Very basic Objective-C/C Problem - objective-c

Here's my code:
#import <Foundation/Foundation.h>
void PrintPathInfo() {
const char *path = [#"~" fileSystemRepresentation];
NSLog(#"My home folder is at '%#'", path);
}
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
PrintPathInfo();
[pool drain];
return 0;
}
And here's my problem:
Program received signal: “EXC_BAD_ACCESS”.
I really think the problem is my NSLog but I don't know how to solve it.
Could someone help me please? Thanks!

path is not an NSString, which is why that crashes. %# in a formatting string expects an object, and asks it for a description to get a string to print... because you are using a C style string, you need to use the standard C string formatters OR convert the const char * back to an NSString using the initWithCString:encoding: class method of NSString.
Staying with a const char *, you can use:
NSLog(#"My home folder is at '%s'", path);
which would work.

%# is for objects. (Like NSString). for const char* you will want the good old %s from the c's printf format codes.
See http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html
For the format specifies and their meanings

Related

How can I read the "attributedBody" column in macOS' iMessage database?

Apple changed the Messages database schema in the latest macOS Ventura update, and sent messages seem to no longer store their body/content in the text column. The attributedBody column has the content, but it's stored as an encoded blob.
Has anyone had any luck getting plaintext out of this?
The attributedBody column is a serialized NSMutableAttributedString — packed using NSArchiver. It can be unpacked and read using NSUnarchiver but must first be extracted from the Messages sqlite database without losing any of its non-printable characters.
To preserve the column's content when performing a query, you can use sqlite3's HEX() function. The resulting bytes can then be read back into their original state by iterating over them and building a new NSString.
In the example below, NSData is extended with two helper methods to handle reading a file with hex-encoded data. Using dataWithContentsOfHexEncodedFile, a message record's attributedBody can be passed to NSUnarchiver, which will handle decoding the serialized NSAttributedString. This can then be converted to a normal NSString by accessing the string property.
#import <Foundation/Foundation.h>
#implementation NSData (NSDataExtended)
+ (NSData *)dataWithContentsOfHexEncodedString:(NSString *) string {
const char * chars = [string UTF8String];
int i = 0;
NSMutableData *data = [NSMutableData dataWithCapacity: string.length / 2];
char byteChars[3] = {'\0', '\0', '\0'};
unsigned long wholeByte;
while (i < string.length) {
byteChars[0] = chars[i++];
byteChars[1] = chars[i++];
wholeByte = strtoul(byteChars, NULL, 16);
[data appendBytes:&wholeByte length:1];
}
return data;
}
+ (NSData *)dataWithContentsOfHexEncodedFile:(NSString *) filePath {
return [self dataWithContentsOfHexEncodedString:[NSString
stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:nil]];
}
#end
int main(int argc, const char * argv[]) {
system([[[NSString alloc] initWithFormat:#"%s %s > %s",
"/usr/bin/sqlite3 ~/Library/Messages/chat.db",
"'SELECT HEX(attributedBody) FROM message ORDER BY ROWID DESC LIMIT 1'",
"/private/tmp/msgbody"] UTF8String]);
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
NSMutableAttributedString *msg = [[[NSUnarchiver alloc]
initForReadingWithData:[NSData dataWithContentsOfHexEncodedFile:#"/private/tmp/msgbody"]
] decodeTopLevelObjectAndReturnError:nil];
NSLog(#"%#", [msg string]);
return 0;
}

objective-c right padding

hello all hope someone can help with that. I was browsing the net and nothing really seems to make sense :S
so I have a string lets say:
"123" and I would like to use a function like:
padr("123", 5, 'x')
and the result should be:
"123xx"
Sorry but Objective-C is a nightmare when dealing with strings :S
You could create your own method to take the initial string, desired length, and padding character (as I was starting to do & also described in a few similar questions)
Or you could use the NSString method Apple already provides ;)
NSString *paddedString = [#"123"
stringByPaddingToLength: 5
withString: #"x" startingAtIndex:0];
See NSString Class Reference for this method.
What about the NSString method stringByPaddingToLength:withString:startingAtIndex:.
NSString* padr(NSString* string, NSUInteger length, NSString *repl)
{
return [string stringByPaddingToLength:length withString:repl startingAtIndex:0];
}
NSMutableString* padString(NSString *str, int padAmt, char padVal)
{
NSMutableString *lol = [NSMutableString stringWithString:str];
while (lol.length < padAmt) {
[lol appendFormat:#"%c", padVal];
}
return lol;
}
And the Call
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSLog(#"%#", padString(#"123", 5, 'x'));
}
return 0;
}

Ask user for information and return that information

I am trying to ask the user to enter their name and then return; "Hello and their name". I know its something simple that I am missing, but I just dont know what it is.
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSString * name = #"";
NSLog(#"What is your name?");
scanf("%#", &name);
NSLog(#"Hello %#",name);
}
}
You're trying to mix Objective-C and C here. This is somewhat tricky to do, but let me see if I can help point you the right direction.
First, change:
NSString * name = #"";
scanf("%#", &name);
to:
char name[64];
scanf("%s", &name);
and see if that works better.
scanf is a C function that works with c types, and NSString is an objective C object which doesn't really work with "scanf".
(The "64" means that there's enough buffer space for 64 characters and if you blow past that, the app will likely crash).
Also, change:
NSLog(#"Hello %#",name);
to this:
NSLog(#"Hello %s",name);
As "%s" in the format tells NSLog that you're passing a C-style string and not a NSString object.
You're using an NSString object in C, which doesn't work. scanf expects a C string. Here's an example:
NSLog(#"What is your name?");
char name[40];
scanf("%s", name);
NSLog(#"Hello %#",[NSString stringWithCString:name encoding:NSUTF8StringEncoding]);
Or you can stay 100% in C:
printf("What is your name?");
char name[40];
scanf("%s", name);
printf("Hello %s", name);

How to read input in Objective-C?

I am trying to write some simple code that searches two dictionaries for a string and prints to the console if the string appears in both dictionaries. I want the user to be able to input the string via the console, and then pass the string as a variable into a message. I was wondering how I could go about getting a string from the console and using it as the argument in the following method call.
[x rangeOfString:"the string goes here" options:NSCaseInsensitiveSearch];
I am unsure as to how to get the string from the user. Do I use scanf(), or fgets(), into a char and then convert it into a NSSstring, or simply scan into an NSString itself. I am then wondering how to pass that string as an argument. Please help:
Here is the code I have so far. I know it is not succinct, but I just want to get the job done:
#import <Foundation/Foundation.h>
#include <stdio.h>
#include "stdlib.h"
int main(int argc, const char* argv[]){
#autoreleasepool {
char *name[100];
printf("Please enter the name you wish to search for");
scanf("%s", *name);
NSString *name2 = [NSString stringWithFormat:#"%s" , *name];
NSString *nameString = [NSString stringWithContentsOfFile:#"/usr/share/dict/propernames" encoding:NSUTF8StringEncoding error:NULL];
NSString *dictionary = [NSString stringWithContentsOfFile:#"/usr/share/dict/words" encoding:NSUTF8StringEncoding error:NULL];
NSArray *nameString2 = [nameString componentsSeparatedByString:#"\n"];
NSArray *dictionary2 = [dictionary componentsSeparatedByString:#"\n"];
int nsYES = 0;
int dictYES = 0;
for (NSString *n in nameString2) {
NSRange r = [n rangeOfString:name2 options:NSCaseInsensitiveSearch];
if (r.location != NSNotFound){
nsYES = 1;
}
}
for (NSString *x in dictionary2) {
NSRange l = [x rangeOfString:name2 options:NSCaseInsensitiveSearch];
if (l.location != NSNotFound){
dictYES = 1;
}
}
if (dictYES && nsYES){
NSLog(#"glen appears in both dictionaries");
}
}
}
Thanks.
Safely reading from standard input in an interactive manner in C is kind of involved. The standard functions require a fixed-size buffer, which means either some input will be too long (and corrupt your memory!) or you'll have to read in a loop. And unfortunately, Cocoa doesn't offer us a whole lot of help.
For reading standard input entirely (as in, if you're expecting an input file over standard input), there is NSFileHandle, which makes it pretty succinct. But for interactively reading and writing like you want to do here, you pretty much have to go with the linked answer for reading.
Once you have read some input into a C string, you can easily turn it into an NSString with, for example, +[NSString stringWithUTF8String:].

CFArrayGetValueAtIndex not returning aything

I have an extremely simple code snippet to get the application support directory of a use. Problem is, it doesn't work! I get the values in a CFArrayRef (because I want to use C code since I will use this snippet in a C++ application later) and try to get the first string in there using CFArrayGetValueAtIndex(). I convert the returned void* to a char* using a C-style cast and attempt to output it using printf(), but nothing gets outputted! Can anyone explain why? I've looked online through the documentation for CFArray and tried to google the issue, but came up with nothing. Any help would be really appreciated!
Code:
#include <Foundation/Foundation.h>
#include <typeinfo>
int main (int argc, const char * argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
CFArrayRef array = \
(CFArrayRef)NSSearchPathForDirectoriesInDomains(
NSApplicationSupportDirectory,
NSUserDirectory,
YES);
char* string = (char*)CFArrayGetValueAtIndex(array, 0);
printf("string: %s\n", string);
[pool drain];
}
Why are you converting it to a char*? The resulting array from NSSearchPathForDirectoriesInDomains() contains CFStringRefs, not char*s.
Try using CFShow((CFTypeRef)CFArrayGetValueAtIndex(array, 0));