How to zip a folder using ZipKit? - ios

Id like to zip a folder using ZipKit??
I cant seem to locate a good documentation for the usage of functions in the ZipKit library.
Can some one explain the method for folder zipping?
ZKFileArchive *archive = [ZKFileArchive archiveWithArchivePath:filePath];
[archive deflateDirectory:param1 relativeToPath:param2 usingResourceFork:NO];
What needs to be passed in param1 and param2??I dont understand the function call here?
It would be great if some one could post an example for it?
Thank you!

Looking at the answer in this related question, here's a good example to work with.
Your param1 is the folder (with it's path) to be archived, and the relative path could be the parent folder.
NSString *zipFilePath = #"/Documents/zipped.zip";
ZKFileArchive *archive = [ZKFileArchive archiveWithArchivePath:zipFilePath];
NSInteger result = [archive deflateDirectory:#"/Documents/myfolder" relativeToPath:#"/Documents" usingResourceFork:NO];
It would be nice if ZipKit had better documentation than the limited info it has.

I created the following category method for NSFileManager using ZipKit.
- (BOOL)zipContentsOfDirectoryAtPath:(NSString *)directory toPath:(NSString *)filename recursive:(BOOL)recursive {
// If there is already a file at the destination, delete it
if ([self fileExistsAtPath:filename]) {
[self removeItemAtPath:filename error:nil];
}
#try {
ZKFileArchive *archive = [ZKFileArchive archiveWithArchivePath:filename];
NSInteger result = [archive deflateDirectory:directory relativeToPath:directory usingResourceFork:NO];
return result == zkSucceeded;
}
#catch (NSException *exception) {
if ([self fileExistsAtPath:filename]) {
[self removeItemAtPath:filename error:nil];
}
}
return NO;
}
The directory parameter is a path to the directory (and its contents) that you wish to the zip up. The filename parameter is a path to the resulting zip file you want as a result.

Related

iOS Video Caching - Manual cache deletion

I have a React Native application which uses React Native Video with iOS caching. I have been working on a method inside RCTVideoCache.m which would manually delete the data of a particular cache key. According to the documentation of SPTPersistentCache, which the video library uses for caching, data can be deleted either by locking/unlocking a file and invoking a wipe or after inspecting the source code of SPTPersistentCache.h with a method named removeDataForKeys.
I have tried both ways, however, unsuccessfully.
In my first try, I am using wipeLockedFiles. I have created a deleteFromCache() method inside RCTVideoCache.m. Since all my video files are unlocked by default, in this method I am trying to lock the file corresponding to my cacheKey and invoke a wipe on all locked files (which would consist of only my target cacheKey file) as it is demonstrated in the documentation. This method looks like:
- (void)deleteFromCache:(NSString *)cacheKey withCallback:(void(^)(BOOL))handler;
{
[self.videoCache lockDataForKeys:#[cacheKey] callback:nil queue:nil];
[self.videoCache wipeLockedFiles];
NSLog(#"Size = %#", #(self.videoCache.totalUsedSizeInBytes));
handler(YES);
}
The following results in two errors during compilation:
/Users/.../MyApp/node_modules/react-native-video/ios/VideoCaching/RCTVideoCache.m:79:20: error: no visible #interface for 'SPTPersistentCache' declares the selector 'lockDataForKeys:callback:queue:'
[self.videoCache lockDataForKeys:#[cacheKey] callback:nil queue:nil];
~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/.../MyApp/node_modules/react-native-video/ios/VideoCaching/RCTVideoCache.m:80:20: error: no visible #interface for 'SPTPersistentCache' declares the selector 'wipeLockedFiles'
[self.videoCache wipeLockedFiles];
~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~
I really have no idea why these selectors are not visible from SPTPersistentCache.
In my second try, I am using removeDataForKeys(). Again, I have created a deleteFromCache() method inside RCTVideoCache.m which looks like this:
- (void)deleteFromCache:(NSString *)cacheKey withCallback:(void(^)(BOOL))handler;
{
[self.videoCache removeDataForKeys:#[cacheKey] callback:^(SPTPersistentCacheResponse * _Nonnull response) {
NSLog(#"Result output: %#", response.output);
NSLog(#"Error output: %#", [response.error localizedDescription]);
} onQueue:dispatch_get_main_queue()];
NSLog(#"Size = %#", #(self.videoCache.totalUsedSizeInBytes));
handler(YES);
}
In this second way, there are no errors, however, the data of the key is never deleted. Also, both NSLogs for the response output null inside the terminal.
I am 100% sure that the cacheKey I am providing to my deleteFromCache() method is correct and data corresponding to it exists. However, in both methods NSLog(#"Size = %#", #(self.videoCache.totalUsedSizeInBytes)); does not change and I can also manually verify that the file has not been deleted.
I am really stuck and do not know what is wrong with the code I've written in both cases and why neither of them works. I would appreciate any help on this!
You can delete all sub-folder's files (tmp/rct.video.cache), iterating each one:
+ (void)deleteFromCache
{
NSArray* tmpDirectory = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.temporaryCachePath error:NULL];
for (NSString *file in tmpDirectory) {
[[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:#"%#%#", self.temporaryCachePath, file] error:NULL];
}
}
I ran your example and discovered that you are using incorrect method signatures. These methods simply don't exist in the caching library, their signatures are different.
Try something like this:
- (void)deleteFromCache:(NSString *)cacheKey withCallback:(void(^)(BOOL))handler;
{
NSLog(#"Size before = %#", #(self.videoCache.totalUsedSizeInBytes));
[self.videoCache lockDataForKeys:#[cacheKey] callback:nil onQueue:nil];
[self.videoCache wipeLockedFilesWithCallback:^(SPTPersistentCacheResponse * _Nonnull response) {
NSLog(#"Size after = %#, response = %#", #(self.videoCache.totalUsedSizeInBytes), response);
// Call handler after the files are wiped
handler(YES);
} onQueue:nil];
}
I have no idea why the second approach doesn't work, but NSLog(#"Size = %#", #(self.videoCache.totalUsedSizeInBytes)); is for sure called before the actual deletion happens. In the example I posted above, I have moved the logging statement into the callback closure, so that it reports the size before and after the deletion takes place.

How to trim a video using FFmpeg in Objective-C for iOS application

I am trying to implement a sample iOS application that can trim a bundled video (.mp4) using FFmpeg library in Objective-C environment.
I used this script to compile and build the FFmpeg for iOS. Those libraries was added to the project but now I'm not sure how to continue it. How can I find which function do the trim behaviour and what are the supportive codecs and etc.
I am interesting do achieve this with out any wrapper but directly accessing the library functions. How can I do this?
Update : 1
I believe following code snippet will contain the input video file details in a stream
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"KeseMase" ofType:#".mp4"];
AVInputFormat *inputFormat = av_find_input_format([#"mp4" UTF8String]);
const char *utf8FilePath = [filePath UTF8String];
avformat_open_input(&pFormatCtx, utf8FilePath, inputFormat, nil);
Or does it contain only the header information of the video file?
Update : 2
With following code, I was able to convert input video to a stream of AVPacket and store them in a NSMutableArray
- (BOOL)readFrameIntoPacket:(AVPacket *)packet error:(NSError *__autoreleasing *)error
{
BOOL continueReading = YES;
int frameReadValue = av_read_frame(pFormatCtx, packet);
if (frameReadValue == 0)
{
NSLog(#"%s - %d # Read next frame", __PRETTY_FUNCTION__, __LINE__);
continueReading = YES;
NSValue *value = [NSValue valueWithBytes:&packet objCType:#encode(AVPacket)];
[srcPktArr addObject:value];
}
else
{
continueReading = NO;
av_free_packet(packet);
}
return continueReading;
}
Tasks remain to solve the question are:
1.) How to use those AVPackets to and write a Video file
2.) How to give a start time and end time and write only that part to a video file
Update : 3
Okay... then I try to write those packets to an out put file like below
- (BOOL)writePacket:(AVPacket *)packet error:(NSError *__autoreleasing *)error
{
int writeValue = av_write_frame(outputContext, packet);
if (writeValue == 0)
{
return YES;
}
else if (writeValue == 1)
{
return YES;
}
else
{
return NO;
}
}
and ended up with following error
[mp4 # 0x1c04a200] Invalid packet stream index: 17467852
Update : 4
Okay guys, I get this far.

Xcode - Dropbox - NSMutabledictionary

I'm iterating through the user's Dropbox content (using the loadedMetaData delegate) in order to get information about all files and folder names present in the user's dropbox (I need this so that I cab download all necessary data to the Documents folder of the app for offline use). The information shall be stored in an NSMutabledirectionary where "key = folder-name" and the object is always an array containing all files inside the folder. I'm doing this:
-(void)restClient:(DBRestClient *)client loadedMetadata:(DBMetadata *)metadata
{
if (metadata.isDirectory) {
//subfolders are loaded into array
for (DBMetadata *directory in metadata.contents) {
if (directory.isDirectory)
{
[directoryList addObject:directory.filename];
//
}
}
//files are loaded according loadmeta-folder (first run is root folder)
[fileList removeAllObjects];
for (DBMetadata *file in metadata.contents) {
if (!file.isDirectory)
{
NSLog(#"Directy is called %#", metadata.path);
//NSLog(#"%# was last changed %#", file.filename, file.lastModifiedDate);
[fileList addObject:file.filename];
[fileRevisionDates addObject:file.lastModifiedDate];
}
}
NSLog(#"Key is called %#", metadata.path);
//This is where I store the information in the dictionary
[subFolderContent setValue:fileList forKey:metadata.path];
//loadmetadata for all sub-folders
for (int i = 0; i < directoryList.count; i++) {
[restClient loadMetadata:[NSString stringWithFormat:#"/TestFolder/%#/", [directoryList objectAtIndex:i]]];
}
}
}
Now this basically works, but of course, every time the array "fileList" is updated, all values for each key in the dictionary are updated accordingly... What am I missing? Or is there a better way to achieve this?
Thanks for your help!
Tom
Here's some rough code that might work. (I haven't tested it at all.) To answer your direct question, note that I'm initializing a new fileList in this method instead of having a global one somewhere else. This is what the commenters above were getting at.
I also did a little cleanup:
There's no need to keep the list of directories in an array and then call loadMetadata on each later. You can just call loadMetadata on each directory as you see it.
I deleted fileRevisionDates since it didn't seem usable in its current state. (I guess it was literally an array of dates? You probably need an NSMutableDictionary instead.)
I fixed the path construction on the recursive call to loadMetadata. If a user's Dropbox contained a directory like /foo/bar/baz, it looked like your code would try to get metadata on a path like /TestFolder/baz. I think the change I made will take care of that.
Again, I haven't tested this code at all (and my Objective-C is not very good), so there may be bugs/typos. Others should feel free to suggest edits:
-(void)restClient:(DBRestClient *)client loadedMetadata:(DBMetadata *)metadata {
if (metadata.isDirectory) {
NSMutableArray *fileList = [[NSMutableArray alloc] init];
for (DBMetadata *entry in metadata.contents) {
if (entry.isDirectory) {
[restClient loadMetadata:[NSString stringWithFormat:#"%#/%#", metadata.path, entry.filename]];
}
else {
[fileList addObject:entry.filename];
}
}
[subFolderContent setValue:fileList forKey:metadata.path];
}
}
Finally, please note that this is not a great way to enumerate the contents of a user's Dropbox. See https://blogs.dropbox.com/developers/2013/12/efficiently-enumerating-dropbox-with-delta/ for the preferred approach, which is to use the /delta endpoint.

BlackRaccoon and WhiteRaccon server timeout error

I have use White Raccoon and Black Raccoon both to upload zip file on FTP server.
In White Raccoon I was not able to upload zip file, I always get serverTimeout error. So I tried to upload normal xml file with white raccoon, File is uploaded without any data(0 byte size). Here is the code
-(void)upload:(NSData*)data{
//the upload request needs the input data to be NSData
NSData * ourImageData = data;
//we create the upload request
//we don't autorelease the object so that it will be around when the callback gets called
//this is not a good practice, in real life development you should use a retain property to store a reference to the request
WRRequestUpload * uploadImage = [[WRRequestUpload alloc] init];
uploadImage.delegate = self;
//for anonymous login just leave the username and password nil
uploadImage.hostname = #"hostname";
uploadImage.username = #"username";
uploadImage.password = #"password";
//we set our data
uploadImage.sentData = ourImageData;
//the path needs to be absolute to the FTP root folder.
//full URL would be ftp://xxx.xxx.xxx.xxx/space.jpg
uploadImage.path = #"huge_test.zip";
//we start the request
[uploadImage start];
}
I am using this https://github.com/valentinradu/WhiteRaccoon
-As WhiteRaccoon is not working for me I have tried BlackRaccoon but it is not helping me to even upload a normal xml file, it just give me "Stream timed out with no response from server" error.
here is the code
- (IBAction) uploadFile :(NSData *)datas{
self.uploadData = [NSData dataWithData:datas];
//Here I am just Checking that DATA come from another method is proper or not. I got All thedata which I have passed from method
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/test12121.xml"];
// Write the data to file
[datas writeToFile:path atomically:YES];
self.uploadFile = [[BRRequestUpload alloc] initWithDelegate: self];
//----- for anonymous login just leave the username and password nil
self.uploadFile.path = #"/test.xml";
self.uploadFile.hostname = #"hostname";
self.uploadFile.username = #"username";
self.uploadFile.password = #"password";
//we start the request
[self.uploadFile start];
}
- (long) requestDataSendSize: (BRRequestUpload *) request{
//----- user returns the total size of data to send. Used ONLY for percentComplete
return [self.uploadData length];
}
- (NSData *) requestDataToSend: (BRRequestUpload *) request{
//----- returns data object or nil when complete
//----- basically, first time we return the pointer to the NSData.
//----- and BR will upload the data.
//----- Second time we return nil which means no more data to send
NSData *temp = self.uploadData; // this is a shallow copy of the pointer
self.uploadData = nil; // next time around, return nil...
return temp;
}
-(void) requestFailed:(BRRequest *) request{
if (request == uploadFile)
{
NSLog(#"%#", request.error.message);
uploadFile = nil;
}
NSLog(#"%#", request.error.message);
}
-(BOOL) shouldOverwriteFileWithRequest: (BRRequest *) request
{
//----- set this as appropriate if you want the file to be overwritten
if (request == uploadFile)
{
//----- if uploading a file, we set it to YES
return YES;
}
//----- anything else (directories, etc) we set to NO
return NO;
}
- (void) percentCompleted: (BRRequest *) request
{
NSLog(#"%f completed...", request.percentCompleted);
}
-(void) requestCompleted: (BRRequest *) request
{
//----- handle Create Directory
if (request == uploadFile)
{
NSLog(#"%# completed!", request);
uploadFile = nil;
}
}
I am using https://github.com/lloydsargent/BlackRaccoon.
I have even changed the timeout limit upto 60 but its not working for me. Please anyone can help me?Anyone knows another way to upload zip file to FTP server, then please let me know.
Thanks in advance.

mocking a class - iOS

Im new to unit testing and OCMock so this might be an obvious answer, just didn't find answer on google.
I am trying to test a model object's method.
the method has the following code:
//takes a filepath and a pk, sets the filepath to the
BoxAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
NSNumber *ifExistIndexInJson = [BoxJsonDataHelper pkExistInCurrentJson:[[[self.downloadQueue objectAtIndex:0] objectForKey:#"pk"] integerValue]];
if (ifExistIndexInJson)
{
[[[self.downloadQueue objectAtIndex:0] objectForKey:#"fields"] setObject:path forKey:#"content"];
NSError *error = nil;
[[NSFileManager defaultManager] removeItemAtPath:[[[delegate.currentJsonData objectAtIndex:[ifExistIndexInJson integerValue]] objectForKey:#"fields"] objectForKey:#"content"] error:&error];
[delegate.currentJsonData removeObjectAtIndex:[ifExistIndexInJson integerValue]];
[delegate.currentJsonData addObject:[self.downloadQueue objectAtIndex:0]];
[self.downloadQueue removeObjectAtIndex:0];
if ([self.downloadQueue count] > 0)
{
[BoxServerRequestsObject downloadFileForPK:[[[self.downloadQueue objectAtIndex:0] objectForKey:#"pk"] integerValue]sender:self];
}
else
{
//end the progress or whatever
}
}
else
{
[[[self.downloadQueue objectAtIndex:0] objectForKey:#"fields"] setObject:path forKey:#"content"];
[delegate.currentJsonData addObject:[self.downloadQueue objectAtIndex:0]];
[self.downloadQueue removeObjectAtIndex:0];
if ([self.downloadQueue count] > 0)
{
[BoxServerRequestsObject downloadFileForPK:[[[self.downloadQueue objectAtIndex:0] objectForKey:#"pk"] integerValue]sender:self];
}
else
{
//end the progress or whatever
}
}
I need help with a couple of things:
when I call [BoxJsonDataHelper pkExistInCurrentJson:...]. BoxJsonDataHelper is actually self, only it's a class method not an instance, so I call it by name, How can I fake the results of the return value so theres no dependency?
How to fake a file at a path for the program to remove? than how do I check that it was removed?
how do I mock BoxServerRequestObject to make the method call the mock object instead of the real one? and than how do I check if it has been called(also a class method)
My knowledge in unit testing is limited, and I have just started with OCMock and read some examples so I would appreciate full answers :)
You can mock class methods just like instance methods. They stay mocked until the mock is dealloc'ed.
id boxJsonDataHelperMock = [OCMockObject mockForClass:BoxJsonDataHelper.class];
[[[boxJsonDataHelperMock stub] andReturn:#(1)] pkExistInCurrentJson:OCMOCK_ANY]
Are you just testing whether NSFileManager works at that point? With data objects, I prefer to do the actual writing. Why not just assert that the file doesn't exist after it is removed? If you wanted to mock, you should mock "defaultManager" on NSFileManager and return a mock object that expects removeItemAtPath:error:
Place a mock object in your download queue at index 0.

Resources