I use this routine to do a binary read from file to memory, which worked fine until now... on iOS at least, in the simulator(...don't have the paid developer program(yet ;) ))
The numbers e.g. fileSize, bytesRead are OK, but it gives gibberish at the end...
I can't have overwritten memory, since I do the output right away...
Then I thought it could be an alignment boundary issue e.g. fileSize % 4 = det. gibberish.
But that would be strange behavior, the function gets a size and a count, the lib should calc a multiple byte read on the background, so that shouldn't cause the problem...
Here's the code I use:
uint8_t *readFileToMemory(FILE *fp)
{
fseek(fp, 0, SEEK_END);
long fileSize = ftell(fp);
rewind(fp);
//
printf("fileSize %lu bytes\n",fileSize);
//
uint8_t *fileData = NULL;
//
fileData = (uint8_t *)requestMemory(fileData, (MEM_TYPE_MEMSIZE)fileSize, BF_MEM_ZERO_NO, "readFileToMemory()");
fread(fileData, 1, (size_t)fileSize, fp);
//
long sizeRead = fread(fileData, 1, (size_t)fileSize, fp);
printf("sizeRead %lu bytes\n",sizeRead);
//
fclose(fp);
//
printf("+\n+\nfileData:\n%s+\n+\n",fileData);
//
return fileData;
}
The reason why I post this question is "WHY the gibberish?" on iOS-sim, I do have a simple workaround btw...
Niels
I am here now, so I might as well provide an answer for closure ;)
I forgot to put an '\0' at the end of the binary file before passing it along as (c/glsl NULL-terminated)string... Oops :)
I thank borrrden for his remarks on the Apple libs binary-read, which I still need to look into... (time time time)
Niels
Related
I'm working on a project with an iPhone connecting to an ESP32 using BLE. I'm trying to write a 528 byte long blob to a characteristic. Since the blob is longer than the max 512 allowed per write I'm trying to do a Write Long.
I'ved tried a couple things
1 - If I just try to write the blob I see the first chunk go through with Prepare Write set but there are no subsequent writes.
Why is it stopping after the first chunk?
2 - If I try to chuck it manually based on the size returned from maximumWriteValueLengthForType I see all the data is sent correctly but Prepare Write is not set so they aren't handled correctly.
How do I specify Prepare Write / Execute Write requests?
Here's a code snippet covering the implementation #2
NSData *blob = [request value];
NSUInteger localLength = 0;
NSUInteger totalLength = [blob length];
NSUInteger chunkSize = [peripheral maximumWriteValueLengthForType:type];
uint8_t localBytes[chunkSize];
NSData *localData;
do
{
if(totalLength > chunkSize) {
NSLog(#"BIGGER THAN CHUNK!!!!!!!!!!!!!!!!!!!!!");
NSLog(#"%tu", chunkSize);
for ( int i = 0; i < chunkSize; i++) {
localBytes[i] = ((uint8_t *)blob.bytes)[localLength + i];
}
localData = [NSMutableData dataWithBytes:localBytes length:chunkSize];
totalLength -= chunkSize;
localLength += chunkSize;
}
else {
NSLog(#"Smaller than chunk");
uint8_t lastBytes[totalLength];
for (int i = 0 ; i < totalLength; i++) {
lastBytes[i] = ((uint8_t *)blob.bytes)[localLength + i];
}
localData = [NSMutableData dataWithBytes:lastBytes length:totalLength];
totalLength = 0;
}
// Write to characteristic
[peripheral writeValue: localData forCharacteristic:characteristic type:type];
} while( totalLength > 0);
Long writes are affected by the same limit of 512 bytes maximum for the characteristic value. Long writes are only useful when MTU is too short to write the full value in one packet. Maybe you're trying to write out of this allowed range or something.
Newer iOS versions communicating with BLE 5 devices use a large enough MTU to fit a characteristic value of 512 in one packet (if the remote device also supports such a big MTU).
If you want to write bigger values than 512 bytes, you will need to split it up into multiple writes, so that the second write "overwrites" the first value sent, rather than appending to it. You can also use L2CAP CoC instead which eliminates this arbitrary 512 byte limit.
You have the right general approach but you can't just send the chunks sequentially. There is a limited buffer for sending Bluetooth data and your loop will write data into that buffer more quickly than the Bluetooth hardware can send it.
The exact approach you need to take depends on whether your characteristic supports write with response or write without response.
If your characteristic uses write with response, you should send a chunk and then wait until you get a call to the didWriteValueFor delegate method. You can then write the next chunk. The advantage of this approach is essentially guaranteed delivery of the data. The disadvantage is it is relatively slow.
If your characteristic uses write without response then you call write repeatedly until you get a call to didWriteValueFor with an error. At this point you have to wait until you get a call to peripheralIsReady. At this point you can start writing again, beginning with the last failed write.
With this approach there is the potential for lost data, but it is faster.
If you have to move large amounts of data, an L2Cap stream might be better, but you need to handle data framing.
I am working on a Bluetooth based application and I am having problems when I try to send data from the iPhone to the other device.
I have no problem when I have to send just one value, using something like this:
- (void)sendData:(NSInteger)mel {
NSData *myData = [NSData dataWithBytes:&mel length:sizeof(mel)];
[self.myDevice writeValue:myData forCharacteristic:self.myCharacteristic type:CBCharacteristicWriteWithoutResponse];
}
But, for some characteristics I need send 2 or more values at the same time (for example in this case, variable mel and another one) but I haven’t been able yet to do it.
Does somebody know how to do this? Thanks in advance.
UPDATE 1
What I tried to send two values is
unsigned char bytes[] = {mel, interval};
NSMutableData *myData = [NSMutableData new];
[myData appendBytes:&bytes length:sizeof(bytes)];
[self.myDevice writeValue:myData forCharacteristic:self.myCharacteristic type:CBCharacteristicWriteWithoutResponse];
But this works like if the second value didn't exist
You can't use sizeof(bytes) to get the number of bytes in the array. It's simply going to return 4 since that is the size of a char *.
One options would be to use sizeof(mel) + sizeof(interval) instead of sizeof(bytes).
the text that caused the crash is the following:
the error occurred at the following line:
let size = CGSize(width: 250, height: DBL_MAX)
let font = UIFont.systemFontOfSize(16.0)
let attributes = [
NSFontAttributeName:font ,
NSParagraphStyleAttributeName: paraStyle
]
var rect = text.boundingRectWithSize(size, options:.UsesLineFragmentOrigin, attributes: attributes, context: nil)
where text variable contains the inputted string
parastyle is declared as follows:
let paraStyle = NSMutableParagraphStyle()
paraStyle.lineBreakMode = NSLineBreakMode.ByWordWrapping
My initial idea is that the system font can't handle these characters and I need to do an NSCharacterSet, but I'm not sure how to either just ban characters that'll crash my app or make it so i can handle this input (ideal). I don't want to ban emojis/emoticons either.
Thanks!
Not an answer but some information and that possibly provids a way code way to avoid it.
Updated to information from The Register:
The problem isn’t with the Arabic characters themselves, but in how the unicode representing them is processed by CoreText, which is a library of software routines to help apps display text on screens.
The bug causes CoreText to access memory that is invalid, which forces the operating system to kill off the currently running program: which could be your text message app, your terminal, or in the case of the notification screen, a core part of the OS.
From Reddit but this may not be completely correct:
It only works when the message has to be abbreviated with ‘…’. This is usually on the lock screen and main menu of Messages.app.
The words effective and power can be anything as long as they’re on two different lines, which forces the Arabic text farther down the message where some of the letters will be replaced with ‘…’
The crash happens when the first dot replaces part of one of the Arabic characters (they require more than one byte to store) Normally there are safety checks to make sure half characters aren’t stored, but this replacement bypasses those checks for whatever reason.
My solution is the next category:
static NSString *const CRASH_STRING = #"\u0963h \u0963 \u0963";
#implementation NSString (CONEffectivePower)
- (BOOL)isDangerousStringForCurrentOS
{
if (IS_IOS_7_OR_LESS || IS_IOS_8_4_OR_HIGHER) {
return NO;
}
return [self containsEffectivePowerText];
}
- (BOOL)containsEffectivePowerText
{
return [self containsString:CRASH_STRING];
}
#end
Filter all characters to have same directionality. Unfortunately, I'm only aware of such API in Java.
Don't even try. This is a bug in the operating system that will be fixed. It's not your problem. If you try to fix it, you are just wasting your time. And you are very likely to introduce bugs - when you say you "sanitise" input that means you cannot handle some perfectly fine input.
The company I work at develops a multiplatform group video chat.
In Crashlytics report we started noticing that some users are "effectively" trolling iOS users using this famous unicode sequence.
We can't just sit and wait for Apple to fix this bug.
So, I've worked on this problem, this is the shortest crashing sequence I got:
// unichar representation
unichar crashChars[8] = {1585, 1611, 32, 2403, 32, 2403, 32, 2403};
// string representation
NSString *crashString = #"\u0631\u064b \u0963 \u0963 \u0963"
So, I decided to filter out all text messages that contains two U+0963 'ॣ' symbols with one symbol between them (hope you are able to decipher this phrase)
My code from NSString+Extensions category.
static const unichar kDangerousSymbol = 2403;
- (BOOL)isDangerousUnicode {
NSUInteger distance = 0;
NSUInteger charactersFound = 0;
for (NSUInteger i = 0; i < self.length; i++) {
unichar character = [self characterAtIndex:i];
if (charactersFound) {
distance++;
}
if (distance > 2) {
charactersFound = 0;
}
if (kDangerousSymbol == character) {
charactersFound++;
}
if (charactersFound > 1 && distance > 0) {
return YES;
}
}
return NO;
}
Lousy Specta test:
SpecBegin(NSStringExtensions)
describe(#"NSString+Extensions", ^{
//....
it(#"should detect dangerous Unicode sequences", ^{
expect([#"\u0963 \u0963" isDangerousUnicode]).to.beTruthy();
expect([#"\u0631\u064b \u0963 \u0963 \u0963" isDangerousUnicode]).to.beTruthy();
expect([#"\u0631\u064b \u0963 \u0963 \u0963" isDangerousUnicode]).to.beFalsy();
});
//....
});
SpecEnd
I'm not sure if it's OK to "discriminate" messages with too many "devanagari vowel sign vocalic ll".
I'm open to corrections, suggestions, criticism :).
I would love to see a better solution to this problem.
Is this the right way?
// convert
const void *buffer = NULL;
size_t size = 0;
dispatch_data_t new_data_file = dispatch_data_create_map(data, &buffer, &size);
if(new_data_file){ /* to avoid warning really - since dispatch_data_create_map demands we care about the return arg */}
NSData *nsdata = [[NSData alloc] initWithBytes:buffer length:size];
// use the nsdata... code removed for general purpose
// clean up
[nsdata release];
free(buffer); // warning: passing const void * to parameter of type void *
It is working fine. My main concern is memory leaks. Leaking data buffers is not fun. So is the NSData, the buffer and the dispatch_data_t new_data_file all fine?
From what I can read on http://opensource.apple.com/source/libdispatch/libdispatch-187.7/dispatch/data.c it seems the buffer is DISPATCH_DATA_DESTRUCTOR_FREE. Does that mean it is my responsibility to free the buffer?
Since iOS 7 and macOS 10.9 (Foundation Release Notes) dispatch_data_t is an NSObject (NSObject <OS_dispatch_data>) in 64 bit apps.
dispatch_data_t can now be freely cast to NSData *, though not vice versa.
For the most part, your code is correct.
+initWithBytes:length: will copy the buffer sent in so, you don't have to worry about freeing the buffer after the data, you can safely free the data first.
According to the documentation, you do NOT free the data after you are done with it:
If you specify non-NULL values for buffer_ptr or size_ptr, the values returned in
those variables are valid only until you release the newly created dispatch data
object. You can use these values as a quick way to access the data of the new
data object.
You simply release the new_data_file variable (ARC will not do this for you).
I am getting a dead store warning when I analyze my project but the project does not crash.
Here is what I am doing
NSString *graphUrl = nil;
if ([graphArray count] == 1)
{
objTrial = [graphArray objectAtIndex:0];
graphUrl = #"http://chart.apis.google.com/chart?cht=s:nda&chf=bg,s,FFFFFF&chs=";
graphUrl = [graphUrl stringByAppendingString:#"&chd=t:"];
graphUrl = [graphUrl stringByAppendingString:objTrial.highValue];// get the dead store error here
}
else
{
//someother operation is done and a value is loaded to aURL
}
I get a dead store warning as mentioned in the code.. How can I prevent this?
It would be great if someone could help me out in this
The warning is telling you that the store that you do in the first line gets thrown away (i.e assigning an empty string to the variable and then reassigning it afterwards without using the original value). Just change the first line to the following and the warning should go away:
NSString *aUrl;
Edit:
you should change the line where you use it also:
aURL = [aValue copy];
"dead store" means something that's not used, or rather something useless.
You get it when you have a variable defined that you never do anything with. So, the Analyzer tells you that you have wasted some storage.
Here you haven't used the aUrl object after assigning it.
It won't cause any problems other than a few bytes of wasted memory. Of course if it's a large object that could be more.
Perhaps someone could chip in with knowledge of compilers, as compiler optimization might take care of dead stores in any case.
Dead Store is a value that is assigned but never used. There is nothing to worry about it. But if you can't control yourself from worrying ;-) you can change your code to,
NSString aUrl = nil;
if ([anArray count] == 1) {
// a value is store in aValue
// then that value is appended to aURL
aURL = [aURL stringByAppendingString:aValue];
} else {
aUrl = #"";
//someother operation is done and a value is loaded to aURL
}