Cocoa: basic problem getting string from file - objective-c

Is there some blindingly obvious reason why this is producing a nil string instead of the actual text content of the file?
NSString *fromFile = [NSString stringWithContentsOfFile:
#"file://localhost/Users/username/Desktop/test.txt"];
NSLog(#"%#", fromFile);
PRINTS: "(null)"
The file is a plain ASCII text file saved from TextWrangler with contents ' abc '.
The path comes from dragging the actual file from the desktop into the Xcode editor window.
I've also tried without "file://localhost".
The method documentation says "Returns nil if the file can't be opened". There's nothing unusual about the file (not locked, etc.). It has default Unix permissions and was created by the same user as is running Xcode.
I know this method is deprecated -- trying to get this working first.

You have stringWithContentsOfFile: and stringWithContentsOfURL: mixed up.
If you are passing in a URL e.g.
#"file://localhost/Users/username/Desktop/test.txt"
the you want stringWithContentsOfURL: and make the parameter a NSURL e.g.
[NSURL URLWithString:#"file://localhost/Users/username/Desktop/test.txt"]
If you want to use stringWithContentsOfFile: the the parameter should be
#"/Users/username/Desktop/test.txt"

Have you tried ~/Desktop/test.txt or /Users/username/Desktop/test.txt?

Related

Files Copied to Clipboard are empty and "Missing Sandbox Extension" When Pasted

I have an application that is copying files to the clipboard. Here is the relevant code (arguments is an array of NSStrings containing file paths):
NSMutableArray *filesToCopy = [[NSMutableArray alloc] init];
int i;
for (i=1; i < [arguments count]; i++) {
NSString* pathToFile = [arguments objectAtIndex:i];
NSURL* fileURL = [[NSURL alloc] initFileURLWithPath:pathToFile];
[filesToCopy addObject:fileURL];
}
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
NSInteger changeCount = [pasteboard clearContents];
BOOL OK = [pasteboard writeObjects:filesToCopy];
However, in testing when trying to paste a file copied to the clipboard by the program into an empty email in Mail, often the file shows up as zero bytes and the following error appears on the console:
11/13/13 6:27:12.173 AM Mail[627]: Failed to obtain a valid sandbox extension for item: [789514] of flavor: [public.file-url] from the pasteboard.
11/13/13 6:27:12.174 AM Mail[627]: Failed to get a sandbox extensions for itemIdentifier (789514). The data for the sandbox extension was NULL
and then that is followed by the following error on the console:
11/13/13 8:24:41.947 AM sandboxd[172]: ([627]) Mail(627) deny file-read-xattr [full path of file]
What is strange is that if I copy the file from Finder then it pastes just fine with no errors every time. In other words, somehow Finder copies the file to the clipboard with different information than the way I am doing it. To verify this, I did a simple AppleScript to return clipboard info. After I copy a file to the clipboard that returns the following:
{{«class furl», 115}, {«class utf8», 115}, {«class ut16», 232}, {string, 115}, {Unicode text, 230}}
After I copy the same file to the clipboard using Finder, the Applescript returns the following:
{{«class furl», 33}, {«class icns», 795020}, {«class ut16», 112}, {«class utf8», 55}, {«class 8BPS», 1630436}, {«class BMP », 4194358}, {«class TPIC», 1059291}, {TIFF picture, 4197954}, {«class PNGf», 392648}, {«class jp2 », 213480}, {GIF picture, 121307}, {JPEG picture, 116181}, {Unicode text, 110}, {string, 55}}
So Finder is putting more information about the file on the clipboard and different information. For example, the furl class has a different length. This extra information is obviously what is cause Mail to successfully past a file copied from Finder while it has an error pasting a file copied by my program.
Any clues to what information I'm missing when I put the file on the clipboard or what extra information I should be adding to the paste? I'm guessing that Finder is pasting not just an array of NSURL's, but an array of Dictionary Keys that includes other file information. It also seems to be creating the furl class differently than I am. I've spent time pouring over documentation and I'm stuck on this one.
I believe I found the problem. It seems like when command line applications copy to the pasteboard, there is a permission related to sandboxing that is not transferred. The files copied could be pasted fine into any non-sandboxed app, but not into a sandboxed application. The solution in this case was to just create a regular Cocoa based .app program. I'm still not sure how, but it copies the files in a way that the permissions are properly transferred and the file can be pasted in both non-sandboxed and sandboxed applications.
There is is lot written out there about avoiding triggering the Sandboxing mechanism in Sandboxed Apps.
But all answers lack the most obvious trouble that can trigger Sandboxing.
When you make a copy of a NSURL (which is still based on NSString) into NSPasteboard without properly escaped characters still containing non-valid signs and spaces before transforming into 'NSURL'.
This is one of the ways URLs can become malicious, so it is only a little bit annoying that the Error Message you get while trying to expose the link to pasteboard is not telling you what the obvious reason was in detail. But maybe this is also because, "never give too much informations how to circumvent the safety barriers".
It just says:
[sandbox] CreateSandboxExtensionData failed: urlData: 0x0000000000XYZ length: 0 (-1 means null)
then you have to properly escape the string with
NSString *encodedStringForURL = [yourString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
this will exchange special characters that should not be part of n URL.
After that you can transform to NSURL as usually.
or
Failed to obtain a valid sandbox extension
then you also used a wrong NSPasteboardType that exposes a URL without proper type. In example when you exposed a String that poses as Link because you tried to avoid the [sandbox] trigger by being clever and telling the pasteboard this is only a random string. The Sandbox is still more clever when you prepend the string with file://.
Then the solution is to use NSPasteboardTypeFileURL and/or NSPasteboardTypeURL. This will inform the sandbox that you exposed links on purpose with proper type.
There are more pitfalls, but also remember you have to use YourURL.absoluteString when you paste to Pasteboard.

initWithContentsOfURL what is the encoding?

Hi I saved a URL that has a path to a directory where I will be storing information, Now I want to retrieve the information but I don't know how to receive the items, I am trying to use initWithContentsOfURL but I dont know what the encoding would be?
This is how I saved the URL
//DirectoryPaths has the NSCAcheDirectory
dirPath = [[directoryPaths objectAtIndex:0] URLByAppendingPathComponent:[NSString stringWithFormat:#"photos.jpg"]];
How do I get a path to the URL now? I tried
NSString *pathToFile = [[NSString alloc] initWithContentsOfURL:dirPath
usedEncoding:nil
error:&error];
I have no clue what the encoding would be since I didnt use one to store the file?
I think you've misunderstood; initWithContentsOfURL:usedEncoding:error: loads a string from a URL. So you'd specify the encoding used for the string — UTF-8, ASCII or something like that.
To get a disk path from a URL you probably want [dirPath path]. In practice you can probably just load from the URL rather than hardcoding local disk behaviour.
Use NSUTF8StringEncoding or ASCII. It works for me. :)

NSBundle returning NULL

I have been using pathForResource for a while but suddenly its giving up on me.
I have added an additional file to my resources called untitled.obj and untitled.mtl.
And following two lines of code:
NSString *path = [[NSBundle mainBundle] pathForResource:#"untitled" ofType:#"obj"];
NSLog(#"thePath = %#", path);
All other *.obj files work fine, except untitled.obj.
The output from NSLog is nothing when i use that file, so i assume its unable to find it for some reason.
The resource is also located in the temp. simulation library:
Delete the app from your device and reset contents and settings in the simulator. Also delete Derived Data of the project. After you do that, test again and it should work.
Everything looks correct to me. Have you checked that you haven't accidentally named the file with a trailing space or other invisible character? Try naming it something entirely different (including changing the extension) and then renaming it back.
I think you need the .plist file. There you have the Bundle name and identifier.

NSString writeToFile with URL encoded string

I have a Mac application that keeps it's own log file. It appends info to the file using NSString's writeToFile method. One of the things that it logs are URL's of web services that it is interacting with. To encode the URL, I'm doing this:
searchString = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)searchString, NULL, (CFStringRef)#"!*'();:#&=+$,/?%#[]", kCFStringEncodingUTF8 );
The app then appends searchString to the rest of the URL and writes it to the log file. Now the problem is that after adding that URL encoding line, nothing seems to be getting written to the file. The program functions as expected otherwise however. Removing the line of code above results in all of the correct information being logged to the file (removing that line is not an option because searchString must be URL encoded).
Oh and I am using NSUTF8StringEncoding when writing the NSString to the file.
Thanks for any help.
EDIT: I know there's also a similar function to CFURLCreateStringByAddingPercentEscapes in NSString, but I've read that it doesn't always work. Can anyone shed some light on this if my original question cannot be answered? Thanks! (EDIT: same problem occurs when using stringByAddingPercentEscapesUsingEncoding:)
EDIT 2: Here's the code that I'm using to append messages to the log file.
+(void)logText:(NSString *)theString{
NSString *docsDirectory = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory,NSUserDomainMask,YES) objectAtIndex:0];
NSString *path = [docsDirectory stringByAppendingPathComponent:#"Folder/File.log"];
NSString *fileContents = [[[NSString alloc] initWithContentsOfFile:path] autorelease];
if([fileContents lengthOfBytesUsingEncoding:NSUTF8StringEncoding] >= 204800){
fileContents = #"";
}
NSString *timeStamp = [[NSDate date] description];
timeStamp = [timeStamp stringByAppendingString:#": "];
timeStamp = [timeStamp stringByAppendingString:theString];
fileContents = [fileContents stringByAppendingString:timeStamp];
fileContents = [fileContents stringByAppendingString:#"\n"];
[fileContents writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:NULL];
}
Because after almost a whole day no one else has offered any answers, I'm going to post a wild guess here: you're not accidentally using the string you want to output (with percent characters in it) as a format string are you?
That is, making the mistake of doing:
NSLog(#"In format strings you can use %# as a placeholder for an object, and %i for a plain C integer.")
Instead of:
NSLog(#"%#", #"In format strings you can use %# as a placeholder for an object, and %i for a plain C integer.");
But I'm going to be surprised if this turns out to be the cause of your problem, as it usually causes random-looking output, rather than absolutely no output. And in some cases, Xcode also gives compiler warnings about it (when I tried NSLog(myString), I got "warning: format not a string literal and no format arguments").
So don't shoot me down if this answer doesn't help. It would be easier to answer your question if you could show us more of your logging code. As for the one line you provided, I can't detect anything wrong with it.
Edit: Oops, I kind of missed that you mentioned you're using writeToFile:atomically:encoding:error: to write the string to the file, so it's even more unlikely you're accidentally treating it as a format string somewhere. But I'm going to leave this answer up for now. Again, you should really show us more of your code though ...
Edit: Regarding your question on a method in NSString that has similar percent encoding functionality, that would be stringByAddingPercentEscapesUsingEncoding:. I'm not sure what kind of problems you're thinking of when you say you've heard it doesn't always work. But one thing is that CFURLCreateStringByAddingPercentEscapes allows you to specify extra characters that don't normally have to be escaped but which you still want to be escaped, while the method of NSString doesn't allow you to specify this.

Troubles with NSString writeToFile

I have been working on a simple text editor in Cocoa/Objective-C for a practice project, and I have come across an error that I would never have expected.
I have an NSString for my file's contents as well as an NSString for it's path. When I attempt to write the contents to a file, I use the following method:
[FileContents writeToFile: CurrentFileName
atomically: NO
encoding: NSStringEncoding /* Error occurs on this line */
error: nil];
I've used this method many times without error yet today, I am getting an error:
Expected expression before 'NSStringEncoding'
NSStringEncoding isn't a valid value. You need to decide what text encoding to use. If you don't know anything about text encodings and these files are only used by your program, I would recommend using NSUTF8StringEncoding everywhere.
UTF-8 has many benefits, including that it is plain ASCII if you don't encounter any non-ASCII characters.
NSStringEncoding is a type, not a value. You need to specify which NSStringEncoding you want (e.g. NSUTF8StringEncoding, NSASCIIStringEncoding and so on).