Unzipping a single file from Archive - ios

I'm trying to port an existing Android application to iOS,
In the Android application i was using a ZipInputStream to extract a single file from the zip archive and store it in as a temporary file.
How could i extract a single file from a Zip Archive without having to extract the whole archive (As it is very large)?

I just found the answer,
I had to modify SSZipArchive to insert a method that will extract a single file from the ZIP archive (Based on its name)
You could find the modified version here, if someone finds this useful i might clean it up, add the delegate, the tests and propose for pull in SSZipArchive.
Usage is straightforward:
NSString *zipEntityToExtract = #"example.aac";
NSString *destinationFilePath = ...; //(Includes filename)
NSString *zipPath = ...;
[SSZipArchive unzipEntityName:zipEntityToExtract fromFilePath:zipPath toDestination:filePath];
//File is now in destinationFilePath

Related

Access any file inside Zip File [duplicate]

I'm trying to port an existing Android application to iOS,
In the Android application i was using a ZipInputStream to extract a single file from the zip archive and store it in as a temporary file.
How could i extract a single file from a Zip Archive without having to extract the whole archive (As it is very large)?
I just found the answer,
I had to modify SSZipArchive to insert a method that will extract a single file from the ZIP archive (Based on its name)
You could find the modified version here, if someone finds this useful i might clean it up, add the delegate, the tests and propose for pull in SSZipArchive.
Usage is straightforward:
NSString *zipEntityToExtract = #"example.aac";
NSString *destinationFilePath = ...; //(Includes filename)
NSString *zipPath = ...;
[SSZipArchive unzipEntityName:zipEntityToExtract fromFilePath:zipPath toDestination:filePath];
//File is now in destinationFilePath

Objective Zip archives aren't opened by ArchiveUtility.app

I'm using ObjectiveZip library (which is a wrapper for MiniZip) in my iOS app. My app sends .zip archives to server, where they are processed manually by moderator. Here's my code for creating an archive:
NSString * zipfile = [Result zipfilePathWithResult:self];
ZipFile * zf = [[ZipFile alloc] initWithFileName:zipfile mode:ZipFileModeCreate];
ZipWriteStream * zws = [zf writeFileInZipWithName:#"report.xml" compressionLevel:ZipCompressionLevelNone];
[zws writeData:[xml dataUsingEncoding:NSUTF8StringEncoding]];
[zws finishedWriting];
for (NSString * name in mediaFiles)
{
ZipWriteStream * zws = [zf writeFileInZipWithName:name compressionLevel:ZipCompressionLevelNone];
[zws writeData:[files objectForKey:name]];
[zws finishedWriting];
}
[zf close];
Unfortunately, these archives aren't correctly processed by default OS X ArchiveUtility: it always unarchives my files into zip.cpgz, regardless of the actual content of archive (usually it's a .xml file and a few .jpg files).
However, some other applications on OS X and also on Windows are able to open my archives correctly, so the archive isn't actually broken.
Is there a way to make ObjectiveZip work with ArchiveUtility? Or maybe you can suggest any other objective-c library for creating .zip files which can do it. Thanks in advance!
Edit zip.c changing the parameters passed into each calls to zipOpenNewFileInZip3_64. The last parameter being passed into each method is a 1. Change it to a 0 and it will work
Changing the last parameter to zipOpenNewFileInZipX_64 function is one way to fix this but changing this parameter to 0 means setting zip64, i.e large file zipping capability, to false.
I was able to fix this by setting second parameter of zip64local_putValue call to (uLong)20(which is currently 45 in one case) inside the function Write_LocalFileHeader regardless of value of zi->ci.zip64.

how to zip empty folders in File manager in iOS?

I am developing a app like file manager. In this i have created zip folder using any existing folder, it works perfectly fine. For this i have used SSZipArchive API. After zip i send it through mail. It's working fine too.
Now when i try to zip any empty folder, it is not working. Means empty folder does not zip.
Yeah looking at the source code, the method + createZipFileAtPath:withContentsOfDirectory: only appears to care about files:
while ((fileName = [dirEnumerator nextObject])) {
BOOL isDir;
NSString *fullFilePath = [directoryPath stringByAppendingPathComponent:fileName];
[fileManager fileExistsAtPath:fullFilePath isDirectory:&isDir];
if (!isDir) {
[zipArchive writeFileAtPath:fullFilePath withFileName:fileName];
}
}
You have two choices:
Fix it yourself and then send a pull request to the author on github and contribute to work you have, yourself, benefited from.
Live with it. It's not clear how an empty folder not appearing in the zip file is an issue anyway.
Isn't a standard thing to have stub files in directories like that. Some file with no contents.

iOS Objective-Zip corruption issues

I am using flyingdolphinstudio's Objective-Zip which is an Objective-C zipping library. I am using this to zip a .txt file following the answer given in this question.
For my case, I do not have an array to cycle through so just for a single file I have the following:
ZipFile *zipFile= [[ZipFile alloc] initWithFileName:zip_file_name mode:ZipFileModeCreate];
NSDictionary *attributes = [[NSFileManager defaultManager]attributesOfItemAtPath:txt_file_name error:&error];
NSDate *Date = [attributes objectForKey:NSFileCreationDate];
NSData *filedata = [NSData dataWithContentsOfFile:txt_file_name];
ZipWriteStream *stream = [zipFile writeFileInZipWithName:txt_file_name fileDate:Date compressionLevel:ZipCompressionLevelBest];
[stream writeData:filedata];
[stream finishedWriting];
[zipFile close];
The zipping process seems to work, I get a .zip file with the correct name and a non-zero size. However, when I try and un-zip this on my mac, it runs into a .cpgz loop. And judging by this article, I presume its because my file is getting corrupted somewhere in there. Also when I upload it to a server and we try to open it on a linux machine, it spits it back out at us with the error:
$ unzip COCR2_100.zip
Archive: COCR2_100.zip
End-of-central-directory signature not found. Either this file is not
a zipfile, or it constitutes one disk of a multi-part archive. In the
latter case the central directory and zipfile comment will be found on
the last disk(s) of this archive.
note: COCR2_100.zip may be a plain executable, not an archive
unzip: cannot find zipfile directory in one of COCR2_100.zip or
COCR2_100.zip.zip, and cannot find COCR2_100.zip.ZIP, period.
Which also suggests it is corrupted.
Does anybody have any ideas as to why it may be getting corrupted?
Thanks!
Solved this by switching to a different Zip client. Moved from Objective-Zip to ZipArchive and that seemed to work just fine.

Install iOS application( ipa file) inside another app?

I try to write an app, it can download an application from web server ( ipa file) and install it. Does anyone know how to install this ipa file ? Can i do it using OTA inside app or use command line to install it ?
So here's an instant solution for jailbroken devices, which makes it possible to directly install any .ipa file from within your application. The steps you have to take is:
I. Gain root access. You can achieve this by calling setuid(0); from your main() function. You'll need to set the sticky permission bit on your executable and use a startup script too.
II. Unzip the .ipa file. Yes, that's right - IPAs are just disguised ZIP files. You can use the opensource libzip library for this.
III. There'll be a directory called Payload inside. The actual app bundle (let's call it MyApp.app) will reside in that folder.
IV. Create a directory in the /var/mobile/Applications directory on the filesystem. This will be the container sandbox of the app to be installed. By convention, the name of this directory should be an UUID. For example, you can use the following code snippet for this:
CFUUIDRef uuidObj = CFUUIDCreate(NULL);
CFStringRef uuid = CFUUIDCreateString(NULL, uuidObj);
CFRelease(uuidObj);
NSString *appPath = [#"/var/mobile/Applications" stringByAppendingPathComponent:(id)uuid];
[fmgr createDirectoryAtPath:appPath withIntermediateDirectories:YES attributes:nil error:NULL];
CFRelease(uuid);
V. Find the app bundle by looping through the contents of the Payload directory (obtained in step II). Copy it over to the newly created sandbox (of which the name is the UUID string). Also copy the iTunesMetadata.plist and iTunesArtwork files in order iTunes to display a nice icon for the app and to notify you of updates. Fix the permissions of the executable of the application as well to make it executable:
NSString *execName = [appInfoPlist objectForKey:#"CFBundleExecutable"];
NSString *execPath = [bundle stringByAppendingPathComponent:execName];
chmod(execPath.UTF8String, 0755);
VI. You'll need to tell SpringBoard to locate your app and then to reload its installed app cache to make the icon of the freshly installed appear on the home screen. For this, you first update the list of the applications in the MobileInstallation property list file. Here the bundle variable refers to the filesystem location of the app bundle, something like /var/mobile/applications/LONG_UUID_STRING/MyApp.app.
#define kMobileInstallationPlistPath #"/var/mobile/Library/Caches/com.apple.mobile.installation.plist"
NSMutableDictionary *appInfoPlist = [NSMutableDictionary dictionaryWithContentsOfFile:[bundle stringByAppendingPathComponent:#"Info.plist"]];
[appInfoPlist setObject:#"User" forKey:#"ApplicationType"];
[appInfoPlist setObject:bundle forKey:#"Path"];
[appInfoPlist setObject:#{
#"CFFIXED_USER_HOME" : appPath,
#"HOME" : appPath,
#"TMPDIR" : [appPath stringByAppendingPathComponent:#"tmp"]
} forKey:#"EnvironmentVariables"];
[appInfoPlist setObject:appPath forKey:#"Container"];
NSData *data = [NSData dataWithContentsOfFile:kMobileInstallationPlistPath];
NSMutableDictionary *mobileInstallation = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListMutableContainersAndLeaves format:NULL error:NULL];
NSString *bundleID = [appInfoPlist objectForKey:#"CFBundleIdentifier"];
[[mobileInstallation objectForKey:#"User"] setObject:appInfoPlist forKey:bundleID];
[mobileInstallation writeToFile:kMobileInstallationPlistPath atomically:NO];
Then remove the cached app information SpringBoard stores:
remove("/var/mobile/Library/Caches/com.apple.mobile.installation.plist");
remove("/var/mobile/Library/Caches/com.apple.springboard-imagecache-icons");
remove("/var/mobile/Library/Caches/com.apple.springboard-imagecache-icons.plist");
remove("/var/mobile/Library/Caches/com.apple.springboard-imagecache-smallicons");
remove("/var/mobile/Library/Caches/com.apple.springboard-imagecache-smallicons.plist");
remove("/var/mobile/Library/Caches/SpringBoardIconCache");
remove("/var/mobile/Library/Caches/SpringBoardIconCache-small");
remove("/var/mobile/Library/Caches/com.apple.IconsCache");
Then notify SpringBoard to reload the list of all applications:
Class __LSApplicationWorkspace = objc_getClass("LSApplicationWorkspace");
[(LSApplicationWorkspace *)[__LSApplicationWorkspace defaultWorkspace] invalidateIconCache:nil];
[(LSApplicationWorkspace *)[__LSApplicationWorkspace defaultWorkspace] registerApplication:[NSURL fileURLWithPath:bundle]];
notify_post("com.apple.mobile.application_installed");
You can do this via OTA distribution, see
http://help.apple.com/iosdeployment-apps/mac/1.1/#app43ad871e
An example plist can be found here:
https://gist.github.com/hramos/774468
Note that you either need the Enterprise Developer Program or collect the UDIDs of your users and include them in your ad-hoc provisioning profile.

Resources