I've developing a Cocoa app that has certain resources (images) which I wish to protect, but still display. Normally one would just place these in the resources folder, but storing there makes it quite easy to grab and use. Is there any way to keep these images hidden, but still access them within the app?
Simple solution:
Merge all files into one big data-file, optionally using 'salts'.
Then retrieve specific files with something like this:
NSData *dataFile = [NSData dataWithContentsOfFile:filePath];
NSData *theFile = [dataFile subdataWithRange: NSMakeRange(startPos,endPos)];
This does not really protect the files,
but prevents people simply dragging out the resources.
At least, the data-file is unusable, certainly with salts.
Another solution:
Create NSData object for every resource.
Add all objects to a NSMutableArray.
Convert the array to one big NSData object.
Write the NSData object to a file.
And add it to the resources folder.
Your app can then read the data-file.
And retrieve the array with the resources.
// Convert array to data
NSData* data=[NSKeyedArchiver archivedDataWithRootObject:theArray];
Use NSKeyedUnarchiver to retrieve the array again.
In order for you to protect the images in one big file, you can just dump the image data to a NSData object sequentially.
If you want, you can use either salts, as previously mentioned, or you can use AES encryption method, as shown here.
Then, you will have to either save the image files structurally (using an NSArray or similar) or record the image offsets so you can retrieve the image data blocks correctly.
This has some drawbacks, specially if your images change over time. That way you will have to monitor those changes and re-structure the file accordingly.
On other option is for you to simply mask the image files by changing name/extension to one of your choice. This will leave some users away from touch.
Finally, you can search for some archiving frameworks using zip like functions and keep the images there (as Blizzard uses in their MPQ format). This will be the best option (since it provides you with encryption methods and it abstracts you of the mechanisms of encryption and archiving) but it may not be easy to find such a framework.
Why do you want to protect the images? It goes without saying that anything you display can be recorded with a screenshot, so if you're trying to protect the images from the person viewing them, there isn't much point.
If you still want to protect them (say, some images should only be available to certain people), encrypting them on disk might be an option. I'm not an Objective-C guy, but this1 seems like a good place to look.
Related
Context
My app's model is a tree of objects where each object represents a filesystem item (a folder or file) on disk beneath a given starting folder.
Periodically, I recursively walk this tree from top-down in order to "sync" it to the actual state of the filesystem. That is, I visit each object in the model and verify that the file/folder it represents still exists in the same location on disk.
If the file/folder has moved, I use an NSURL bookmark to ascertain the new location of the file/folder so that I can update my model's state. (I create an NSURL bookmark when I first create the model object and then store the bookmark data as a property of the object so that I can resolve it later.)
The Problem
NSURL bookmarks simply aren't performant enough. It's not uncommon for my model graph to have 20,000 nested objects. Each one has a bookmark. Here's what I'm seeing when I profile performance:
The recursivelyValidateExistingChildItemsOfParentItem:... method is what walks my model tree. 90% of the time involved is just resolving bookmarks (and, if they are stale, re-creating them as described in Apple's documentation).
The app takes almost 2 minutes to complete the walk thanks to this. So, I need a faster alternative to NSURL bookmarks.
What I've Considered
Extended File Attributes. I could add a UUID attribute to each file on disk. Instead of walking my model graph, I could walk the actual filesystem underneath the starting folder. When I find a new file, I could see if it has a UUID extended attribute. If so, I could then search my model graph for the object with that UUID to handle moved/relocated files. The trouble here is that many things clobber extended file attributes—they aren't guaranteed to stick around.
BDAlias or NDAlias. I used to use BDAlias before I migrated to NSURL bookmarks, but that wasn't exceptionally more performant.
Bottom Line
I need a faster alternative to NSURL's bookmarks. But I still need to be able to track files across launches of my app, so simply keeping file descriptors open or using file id's won't work.
I don't care how low-level I have to get; I just need performance. Thanks!
I know the question is old. But this is my answer:
I only use resolving bookmark as a fallback. I save both file path and URL bookmark data in my model. When I want to open file, first I check if the file still exists in the previously known location. If not, I would try to resolve url's bookmark data. This would narrow calling to URL.init(resolvingBookmarkData) only to a limited subset of items. I would then update model with new path after resolving bookmark to keep performance reasonable.
If you need to assure you are working with exactly the same file, you can check file's date, size or a specific EA as an extra measurement.
Is there a library function to normalize a sound file? I have searched around but could not find any.
I would like to be able to normalize a sound file and setting that into the sound file so it only needs to be done once rather than on the fly.
Can this be done with Core-Audio?
Yes it can be done, but not with a single function call.
The functionality you want is not in fact CoreAudio, but rather in ExtendedAudioFile.h - part of the AudioToolbox framework. This is available for both iOS and MacOSX. I can attest for this being rather hard to find.
Functions of interest in this header are ExtAudioFileOpenURL(), ExtAudioFileRead() and ExtAudioFileWrite().
In outline what you do:
Use ExtAudioFileOpenURL() to open the input file
Use ExtAudioFileGetProperty() with propertyId kExtAudioFileProperty_FileDataFormat to obtain an AudioStreamBasicDescription describing the file.
Possibly set the ASBD to get the format you want. AudioToolBox on MacOSX seems rather more amenable to this than on iOS.
Calculate an allocate a buffer large enough to hold the entire audio file
Read the entire file with ExtAudioFileRead() - NB: this call might not read it all in one go - operating in much the same was as POSIX read()
Perform normalisation
Use ExtAudioFileCreateWithURL() to create the output file
Use ExtAudioFileWrite() to write the normalised samples out.
Dispose of both audio files.
The documentation links to several example projects that can act as donors of working code. You'll find doing normalisation much easier with the samples as floats, but in iOS, I could never get the conversion to work automatically, so you might have to format convert yourself.
Is there any difference between writing an objects(ex array types and NSObject types) to plist and NSFileManager.
if so can i write 1000's of images data and mp3 songs to plist.
As a plist file is an XML (mostly text) file you must archive your data before writing and unarchive after reading (see NSKeyedArchiver here).
NSFileManager, however is a wrapper around generic filesystem operations and there is no need to marshall the data into text in order to store it. The stored data will therefore be much smaller, much quicker to read/write and is the obvious choice.
NSFileManager is used to do things like copy a file, remove a file, and move a file. You wouldn't use NSFileManager to write out a new file. It's only good for working with existing files. It isn't comparable to a plist in the sense of using a plist vs. NSFileManager.
However, if the question you're trying to answer is should I store all my data in a plist or in separate files then that depends. If you're going to store 1000s of images and mp3s, then you definitely do not want to store them all in a single plist. Plists are an inefficient format for storing and updating large amounts of information, both in terms of speed and memory. For example, if you wanted to update a single string in your plist, you have to read the entire plist into memory, update it, and then write the entire plist back to disk. You cannot update just a portion of the plist using the standard plist functions provided by Foundation. If your plist contains all your image and mp3 data, it's going to be really slow.
You may be able to get away with using a plist as a manifest for your images and mp3s which are stored as separate files on disk, but even that can get slow. I'd recommend using SQLite or Core Data instead for the manifest of files and then keeping each image and mp3 as a separate file in the file system. Or, if you don't need to store any metadata with each item, you don't need the manifest at all. If you do end up going with a plist for your manifest, make sure to save the plist as a binary plist using the NSPropertyListBinaryFormat_v1_0 option. This will make the plist take up less space on disk and de-serialize faster when you read it again.
I have been working with base64 encoding. I have successfully encoded images to NSString from NSData, I have also decoded it back to NSData.
So right now I want to store images in Core Data. But would it be best to store an NSString, NSData or the third transformable?
The reason I convert images to NSString is because I want to store it in XML too.
Thanks in advance.
Transformable (as per #timthetoolman) is the easiest way. If your images are large, though, as of iOS 5, the right way to do this is to use the "Binary Data" attribute type and choose "Allows External Storage" so that Core Data can store the large blob of data outside of the database. This can be much more efficient.
Use an NSValueTransformer to convert from your image to an NSData object and then store the data blob in Core Data. You can register your value transformer subclass in the modeling tool. You can check out Apple's PhotoLocations example or this tutorial shows how.
Edit for completeness: as others have pointed out too large a data blob will cause performance issues. As pointed out by #Jesse, iOS5 has an optimization where if the data blob is too large, then Core Data will store it outside of the persistent store. If you have to target pre-iOS5 and the image is too large then you should save the file somewhere in the sandbox and store the URL in the Core Data store. A good discussion in the Apple Dev Forums is here and discusses the limits of storing data blobs in Core Data.
Good Luck
I don't think you should store them in core data, I tried that with images once and found it to be too slow. You should store the locations of the images in core data but just write the images to a file. You can do that as follows:
// JPEG
[UIImageJPEGRepresentation(image, 1.0) writeToFile:jpgPath atomically:YES];
// PNG
[UIImagePNGRepresentation(image) writeToFile:pngPath atomically:YES];
Target iOS5 or later -- Performant Image storage becomes trivial
Newer versions of Xcode and iOS now make storing images both easy and performant. You no longer have to choose to store your images in core data for convenience or in the file system for performance -- Core Data will take care of it for you.
UIImage now conforms to NSCoding in iOS 5. If you're able to target iOS 5 and later, you can just set the the managed object's attribute as Transformable and be done.
if you check the "Allows External Storage" option, Core Data will make the decision whether to store the BLOB in the managed object or as an external file -- all transparently to the developer. to cause larger images to be saved outside of your Core Data store
I noticed that Apple started using zip archives to replace document packages (folders appearing as a single file in Finder) in the iWork applications. I'm considering doing the same as I keep getting support emails related to my document packages getting corrupted when copying them to a windows fileserver.
My questions is what would be the best way to do this in a NSDocument-based application?
I guess the easiest way would be to create a directory file wrapper, create an archive of it and return it in NSDocument's
- (NSFileWrapper *)fileWrapperOfType:(NSString *)typeName error:(NSError **)outError
But I fail to understand how to create a zip archive of the NSFileWrapper.
If you just want to make a zip file your format (ie, "mydoc.myextension" is actually a zip file), there's no convenient, built-in Cocoa mechanism for creating zip archives with code. Take a look at this Google Code project: ziparchive I don't believe a file wrapper will help in that case, though.
Since you cited iWork, I don't own iWork 09, but previous versions use a package format (ie, NSFileWrapper would be ideal) but zip the XML that describes the document's structure, while keeping attachments (like embedded media, images, etc.) in a resource folder, all within the package. I assume they do this because XML can be quite large for large, complicated documents, but compresses very well because it's text. This results in an overall smaller document.
If indeed Apple has moved to making the entire document one big zip archive (which I would find odd), they'd either be extracting necessary resources to a temp folder somewhere or loading the whole thing into memory (a step backward from their package-based approach, IMO). These are considerations you'll need to take into account as well.
You’ll want to take the data from the file wrapper and feed it into something like ziparchive.
Pierre-Olivier Latour has written an extension to NSData that deals with zip compression. You can get it here: http://code.google.com/p/polkit/
I know this is a little late to the party but I thought I'd offer up another link that could help anyone that comes across this post.
Looks like the ZipBrowser sample from Apple would be a good start http://developer.apple.com/library/mac/#samplecode/ZipBrowser/Introduction/Intro.html
HTH