Compare commits

...

10 Commits

70 changed files with 4214 additions and 110 deletions

93
.gitignore vendored
View File

@ -1,3 +1,96 @@
*.o
*.a
*.so
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## User settings
xcuserdata/
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
*.xcscmblueprint
*.xccheckout
## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
build/
DerivedData/
*.moved-aside
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
## Obj-C/Swift specific
*.hmap
## App packaging
*.ipa
*.dSYM.zip
*.dSYM
## Playgrounds
timeline.xctimeline
playground.xcworkspace
# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
# Package.pins
# Package.resolved
# *.xcodeproj
#
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
# hence it is not needed unless you have added a package configuration file to your project
# .swiftpm
.build/
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/
#
# Add this line if you want to avoid checking in source code from the Xcode workspace
# *.xcworkspace
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Build/
# Accio dependency management
Dependencies/
.accio/
# fastlane
#
# It is recommended to not store the screenshots in the git repo.
# Instead, use fastlane to re-generate the screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/#source-control
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots/**/*.png
fastlane/test_output
# Code Injection
#
# After new code Injection tools there's a generated folder /iOSInjectionProject
# https://github.com/johnno1962/injectionforxcode
iOSInjectionProject/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
version: 2.1
executors:
my-xcode:
macos:
xcode: 12.0.1
workflows:
version: 2
test-validate-release:
jobs:
# Testing
- test-Mac
- test-iOS
- test-ExampleApp
# Validation
- validate-CocoaPods:
requires:
- test-Mac
- test-iOS
- test-ExampleApp
- validate-Carthage:
requires:
- test-Mac
- test-iOS
- test-ExampleApp
# Release
# - release:
# # Only run for tags
# filters:
# branches:
# ignore: /.*/
# tags:
# only: /.*/
# requires:
# - validate-CocoaPods
# - validate-Carthage
jobs:
test-Mac:
executor: my-xcode
steps:
- checkout
# The CLANG arguments and find command fail the build on analyzer errors
- run: xcodebuild -workspace UnrarKit.xcworkspace -scheme UnrarKit -sdk macosx -configuration Release -quiet analyze test CLANG_ANALYZER_OUTPUT=html CLANG_ANALYZER_OUTPUT_DIR=analyzer-output && [[ -z `find analyzer-output -name "*.html"` ]]
test-iOS:
executor: my-xcode
steps:
- checkout
# The CLANG arguments and find command fail the build on analyzer errors
- run: xcodebuild -workspace UnrarKit.xcworkspace -scheme UnrarKit -destination 'platform=iOS Simulator,name=iPhone 11,OS=latest' -configuration Release analyze test CLANG_ANALYZER_OUTPUT=html CLANG_ANALYZER_OUTPUT_DIR=analyzer-output && [[ -z `find analyzer-output -name "*.html"` ]]
test-ExampleApp:
executor: my-xcode
steps:
- checkout
# The CLANG arguments and find command fail the build on analyzer errors
- run: xcodebuild -workspace UnrarKit.xcworkspace -scheme UnrarExample -sdk iphonesimulator -configuration Release analyze CLANG_ANALYZER_OUTPUT=html CLANG_ANALYZER_OUTPUT_DIR=analyzer-output && [[ -z `find analyzer-output -name "*.html"` ]]
validate-CocoaPods:
executor: my-xcode
steps:
- checkout
- run: ./Scripts/cocoapod-validate.sh
validate-Carthage:
executor: my-xcode
steps:
- checkout
- run: ./Scripts/carthage-validate.sh
# release:
# executor: my-xcode
# steps:
# - checkout
# - run: ./Scripts/push-output.sh

View File

@ -0,0 +1,24 @@
# Contributing to UnrarKit
First of all, if you're reading this, thanks! I love getting feedback from other developers who use this library and welcome any and all feedback. Issues and Pull requests are welcome, with a few guidelines, laid out below.
# Issues
I need the following, at a minimum:
1. The steps to reproduce your issue, detailed enough for me to follow along and see what you're seeing (bonus points for giving me a sample archive that demonstrates the issue)
2. What you expect to happen
3. What actually happened
If what you're reporting is a crash, a crash report is key (or a stack trace, if you don't have a full crash report).
Beyond that, the **quickest way** to get me to address what you're asking for is to provide a unit test (or tests) to demonstrate what you'd like to see (they should probably fail). I have a pretty complete set of tests already in the library that you can use as an example if you'd like.
# Pull Requests
Pull Requests are always greatly appreciated. The general rule of thumb for how quickly something will make it into a future release is the inverse of how much work I'll need to do on it. Creating a PR instead of an issue report takes a huge burden off of me. If you do create a PR, I'll require these things before I merge it:
1. Style needs to mesh with the rest of the repo. I'd love to have some style enforcement checks at some point, but don't yet. Do your best according to what you see in the rest of the source and I'll point out anything you missed. No big deal
2. If you're fixing a bug, I need to see a unit test that reproduces the issue(s) by failing if I comment out your fix. I try to maintain code coverage that's as complete as possible, so more unit tests are always welcome
3. Don't touch the `Libraries/unrar` directory. This is the UnRAR source code, downloaded from [the RARLAB site](https://www.rarlab.com/rar_add.htm), and updated occasionally. You can usually look at the revision history of that folder to see what version it's currently on. This library does cause some compiler warnings, but I ignore them in Xcode and CocoaPods, relying on unit tests to tell me if anything is truly broken, since I don't maintain patches - I expect to be able to drop in newer versions as needed
4. Be patient with the process - I maintain a high attention to detail, and will take however much time is necessary to get the change to where I'd like it. If you'd rather have a more brief back-and-forth, I can always pull into a separate branch to make the changes myself before merging, but enjoy the interaction of collaborating on PRs whenever possible

View File

@ -0,0 +1,28 @@
Thanks for making a contribution to UnrarKit! I greatly value issue reports, which help make the library better, and more useful to more people. To help me address your issue, please follow the steps below.
_Delete from this line up_
- [ ] Provide a brief, descriptive issue title
- [ ] Fill out the template below
- [ ] **Option A** is the easier, more traditional way of reporting a bug
- [ ] **Option B** gets you bonus points (redeemable in the form of me looking at your issue more quickly). Create a failing unit test that would pass if the issue were resolved. When I go to fix your issue, it's one of the first things I would do anyway. There is a pretty complete set already there, so you can use those as a guide to creating new ones.
## Option A
### Steps to reproduce issue (Detailed enough for me to reproduce - attaching a sample archive can be very helpful):
### What you expect to happen:
### What actually happened:
### (_Optional_) A stack trace or crash report, if you have one:
## Option B
### Brief summary of issue:
### Link to your branch where you've created automated tests to demonstrate the issue (and the name of the unit test(s) you created):

View File

@ -0,0 +1,352 @@
// Return 'true' if we need to exclude the file from processing as result
// of -x switch. If CheckInclList is true, we also check the file against
// the include list created with -n switch.
bool CommandData::ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList)
{
if (CheckArgs(&ExclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
return true;
if (!CheckInclList || InclArgs.ItemsCount()==0)
return false;
if (CheckArgs(&InclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
return false;
return true;
}
bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode)
{
wchar *Name=ConvertPath(CheckName,NULL,0);
wchar FullName[NM];
wchar CurMask[NM];
*FullName=0;
Args->Rewind();
while (Args->GetString(CurMask,ASIZE(CurMask)))
{
wchar *LastMaskChar=PointToLastChar(CurMask);
bool DirMask=IsPathDiv(*LastMaskChar); // Mask for directories only.
if (Dir)
{
// CheckName is a directory.
if (DirMask)
{
// We process the directory and have the directory exclusion mask.
// So let's convert "mask\" to "mask" and process it normally.
*LastMaskChar=0;
}
else
{
// REMOVED, we want -npath\* to match empty folders too.
// If mask has wildcards in name part and does not have the trailing
// '\' character, we cannot use it for directories.
// if (IsWildcard(PointToName(CurMask)))
// continue;
}
}
else
{
// If we process a file inside of directory excluded by "dirmask\".
// we want to exclude such file too. So we convert "dirmask\" to
// "dirmask\*". It is important for operations other than archiving
// with -x. When archiving with -x, directory matched by "dirmask\"
// is excluded from further scanning.
if (DirMask)
wcsncatz(CurMask,L"*",ASIZE(CurMask));
}
#ifndef SFX_MODULE
if (CheckFullPath && IsFullPath(CurMask))
{
// We do not need to do the special "*\" processing here, because
// unlike the "else" part of this "if", now we convert names to full
// format, so they all include the path, which is matched by "*\"
// correctly. Moreover, removing "*\" from mask would break
// the comparison, because now all names have the path.
if (*FullName==0)
ConvertNameToFull(CheckName,FullName,ASIZE(FullName));
if (CmpName(CurMask,FullName,MatchMode))
return true;
}
else
#endif
{
wchar NewName[NM+2],*CurName=Name;
// Important to convert before "*\" check below, so masks like
// d:*\something are processed properly.
wchar *CmpMask=ConvertPath(CurMask,NULL,0);
if (CmpMask[0]=='*' && IsPathDiv(CmpMask[1]))
{
// We want "*\name" to match 'name' not only in subdirectories,
// but also in the current directory. We convert the name
// from 'name' to '.\name' to be matched by "*\" part even if it is
// in current directory.
NewName[0]='.';
NewName[1]=CPATHDIVIDER;
wcsncpyz(NewName+2,Name,ASIZE(NewName)-2);
CurName=NewName;
}
if (CmpName(CmpMask,CurName,MatchMode))
return true;
}
}
return false;
}
#ifndef SFX_MODULE
// Now this function performs only one task and only in Windows version:
// it skips symlinks to directories if -e1024 switch is specified.
// Symlinks are skipped in ScanTree class, so their entire contents
// is skipped too. Without this function we would check the attribute
// only directly before archiving, so we would skip the symlink record,
// but not the contents of symlinked directory.
bool CommandData::ExclDirByAttr(uint FileAttr)
{
#ifdef _WIN_ALL
if ((FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0 &&
(ExclFileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0)
return true;
#endif
return false;
}
#endif
#if !defined(SFX_MODULE)
void CommandData::SetTimeFilters(const wchar *Mod,bool Before,bool Age)
{
bool ModeOR=false,TimeMods=false;
const wchar *S=Mod;
// Check if any 'mca' modifiers are present, set OR mode if 'o' is present,
// skip modifiers and set S to beginning of time string. Be sure to check
// *S!=0, because termination 0 is a part of string for wcschr.
for (;*S!=0 && wcschr(L"MCAOmcao",*S)!=NULL;S++)
if (*S=='o' || *S=='O')
ModeOR=true;
else
TimeMods=true;
if (!TimeMods) // Assume 'm' if no modifiers are specified.
Mod=L"m";
// Set the specified time for every modifier. Be sure to check *Mod!=0,
// because termination 0 is a part of string for wcschr. This check is
// important when we set Mod to "m" above.
for (;*Mod!=0 && wcschr(L"MCAOmcao",*Mod)!=NULL;Mod++)
switch(toupperw(*Mod))
{
case 'M':
if (Before)
{
Age ? FileMtimeBefore.SetAgeText(S):FileMtimeBefore.SetIsoText(S);
FileMtimeBeforeOR=ModeOR;
}
else
{
Age ? FileMtimeAfter.SetAgeText(S):FileMtimeAfter.SetIsoText(S);
FileMtimeAfterOR=ModeOR;
}
break;
case 'C':
if (Before)
{
Age ? FileCtimeBefore.SetAgeText(S):FileCtimeBefore.SetIsoText(S);
FileCtimeBeforeOR=ModeOR;
}
else
{
Age ? FileCtimeAfter.SetAgeText(S):FileCtimeAfter.SetIsoText(S);
FileCtimeAfterOR=ModeOR;
}
break;
case 'A':
if (Before)
{
Age ? FileAtimeBefore.SetAgeText(S):FileAtimeBefore.SetIsoText(S);
FileAtimeBeforeOR=ModeOR;
}
else
{
Age ? FileAtimeAfter.SetAgeText(S):FileAtimeAfter.SetIsoText(S);
FileAtimeAfterOR=ModeOR;
}
break;
}
}
#endif
#ifndef SFX_MODULE
// Return 'true' if we need to exclude the file from processing.
bool CommandData::TimeCheck(RarTime &ftm,RarTime &ftc,RarTime &fta)
{
bool FilterOR=false;
if (FileMtimeBefore.IsSet()) // Filter present.
if (ftm>=FileMtimeBefore) // Condition not matched.
if (FileMtimeBeforeOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileMtimeBeforeOR)
return false; // Include file in OR mode.
if (FileMtimeAfter.IsSet()) // Filter present.
if (ftm<FileMtimeAfter) // Condition not matched.
if (FileMtimeAfterOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileMtimeAfterOR)
return false; // Include file in OR mode.
if (FileCtimeBefore.IsSet()) // Filter present.
if (ftc>=FileCtimeBefore) // Condition not matched.
if (FileCtimeBeforeOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileCtimeBeforeOR)
return false; // Include file in OR mode.
if (FileCtimeAfter.IsSet()) // Filter present.
if (ftc<FileCtimeAfter) // Condition not matched.
if (FileCtimeAfterOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileCtimeAfterOR)
return false; // Include file in OR mode.
if (FileAtimeBefore.IsSet()) // Filter present.
if (fta>=FileAtimeBefore) // Condition not matched.
if (FileAtimeBeforeOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileAtimeBeforeOR)
return false; // Include file in OR mode.
if (FileAtimeAfter.IsSet()) // Filter present.
if (fta<FileAtimeAfter) // Condition not matched.
if (FileAtimeAfterOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileAtimeAfterOR)
return false; // Include file in OR mode.
return FilterOR; // Exclude if all OR filters are not matched.
}
#endif
#ifndef SFX_MODULE
// Return 'true' if we need to exclude the file from processing.
bool CommandData::SizeCheck(int64 Size)
{
if (FileSizeLess!=INT64NDF && Size>=FileSizeLess)
return true;
if (FileSizeMore!=INT64NDF && Size<=FileSizeMore)
return true;
return false;
}
#endif
// Return 0 if file must not be processed or a number of matched parameter otherwise.
int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType,
bool Flags,wchar *MatchedArg,uint MatchedArgSize)
{
if (MatchedArg!=NULL && MatchedArgSize>0)
*MatchedArg=0;
bool Dir=FileHead.Dir;
if (ExclCheck(FileHead.FileName,Dir,false,true))
return 0;
#ifndef SFX_MODULE
if (TimeCheck(FileHead.mtime,FileHead.ctime,FileHead.atime))
return 0;
if ((FileHead.FileAttr & ExclFileAttr)!=0 || FileHead.Dir && ExclDir)
return 0;
if (InclAttrSet && (!FileHead.Dir && (FileHead.FileAttr & InclFileAttr)==0 ||
FileHead.Dir && !InclDir))
return 0;
if (!Dir && SizeCheck(FileHead.UnpSize))
return 0;
#endif
wchar *ArgName;
FileArgs.Rewind();
for (int StringCount=1;(ArgName=FileArgs.GetString())!=NULL;StringCount++)
if (CmpName(ArgName,FileHead.FileName,MatchType))
{
if (ExactMatch!=NULL)
*ExactMatch=wcsicompc(ArgName,FileHead.FileName)==0;
if (MatchedArg!=NULL)
wcsncpyz(MatchedArg,ArgName,MatchedArgSize);
return StringCount;
}
return 0;
}
#if !defined(SFX_MODULE)
void CommandData::SetStoreTimeMode(const wchar *S)
{
if (*S==0 || IsDigit(*S) || *S=='-' || *S=='+')
{
// Apply -ts, -ts1, -ts-, -ts+ to all 3 times.
// Handle obsolete -ts[2,3,4] as ts+.
EXTTIME_MODE Mode=EXTTIME_MAX;
if (*S=='-')
Mode=EXTTIME_NONE;
if (*S=='1')
Mode=EXTTIME_1S;
xmtime=xctime=xatime=Mode;
S++;
}
while (*S!=0)
{
EXTTIME_MODE Mode=EXTTIME_MAX;
if (S[1]=='-')
Mode=EXTTIME_NONE;
if (S[1]=='1')
Mode=EXTTIME_1S;
switch(toupperw(*S))
{
case 'M':
xmtime=Mode;
break;
case 'C':
xctime=Mode;
break;
case 'A':
xatime=Mode;
break;
case 'P':
PreserveAtime=true;
break;
}
S++;
}
}
#endif

View File

@ -0,0 +1,118 @@
void CommandData::OutTitle()
{
if (BareOutput || DisableCopyright)
return;
#if defined(__GNUC__) && defined(SFX_MODULE)
mprintf(St(MCopyrightS));
#else
#ifndef SILENT
static bool TitleShown=false;
if (TitleShown)
return;
TitleShown=true;
wchar Version[80];
if (RARVER_BETA!=0)
swprintf(Version,ASIZE(Version),L"%d.%02d %ls %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA);
else
swprintf(Version,ASIZE(Version),L"%d.%02d",RARVER_MAJOR,RARVER_MINOR);
#if defined(_WIN_32) || defined(_WIN_64)
wcsncatz(Version,L" ",ASIZE(Version));
#endif
#ifdef _WIN_32
wcsncatz(Version,St(Mx86),ASIZE(Version));
#endif
#ifdef _WIN_64
wcsncatz(Version,St(Mx64),ASIZE(Version));
#endif
if (PrintVersion)
{
mprintf(L"%s",Version);
exit(0);
}
mprintf(St(MUCopyright),Version,RARVER_YEAR);
#endif
#endif
}
inline bool CmpMSGID(MSGID i1,MSGID i2)
{
#ifdef MSGID_INT
return i1==i2;
#else
// If MSGID is const char*, we cannot compare pointers only.
// Pointers to different instances of same string can differ,
// so we need to compare complete strings.
return wcscmp(i1,i2)==0;
#endif
}
void CommandData::OutHelp(RAR_EXIT ExitCode)
{
#if !defined(SILENT)
OutTitle();
static MSGID Help[]={
#ifdef SFX_MODULE
// Console SFX switches definition.
MCHelpCmd,MSHelpCmdE,MSHelpCmdT,MSHelpCmdV
#else
// UnRAR switches definition.
MUNRARTitle1,MRARTitle2,MCHelpCmd,MCHelpCmdE,MCHelpCmdL,
MCHelpCmdP,MCHelpCmdT,MCHelpCmdV,MCHelpCmdX,MCHelpSw,MCHelpSwm,
MCHelpSwAT,MCHelpSwAC,MCHelpSwAD,MCHelpSwAG,MCHelpSwAI,MCHelpSwAP,
MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU,
MCHelpSwDH,MCHelpSwEP,MCHelpSwEP3,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR,
MCHelpSwINUL,MCHelpSwIOFF,MCHelpSwKB,MCHelpSwN,MCHelpSwNa,MCHelpSwNal,
MCHelpSwO,MCHelpSwOC,MCHelpSwOL,MCHelpSwOR,MCHelpSwOW,MCHelpSwP,
MCHelpSwPm,MCHelpSwR,MCHelpSwRI,MCHelpSwSC,MCHelpSwSL,MCHelpSwSM,
MCHelpSwTA,MCHelpSwTB,MCHelpSwTN,MCHelpSwTO,MCHelpSwTS,MCHelpSwU,
MCHelpSwVUnr,MCHelpSwVER,MCHelpSwVP,MCHelpSwX,MCHelpSwXa,MCHelpSwXal,
MCHelpSwY
#endif
};
for (uint I=0;I<ASIZE(Help);I++)
{
#ifndef SFX_MODULE
if (CmpMSGID(Help[I],MCHelpSwV))
continue;
#ifndef _WIN_ALL
static MSGID Win32Only[]={
MCHelpSwIEML,MCHelpSwVD,MCHelpSwAO,MCHelpSwOS,MCHelpSwIOFF,
MCHelpSwEP2,MCHelpSwOC,MCHelpSwONI,MCHelpSwDR,MCHelpSwRI
};
bool Found=false;
for (uint J=0;J<ASIZE(Win32Only);J++)
if (CmpMSGID(Help[I],Win32Only[J]))
{
Found=true;
break;
}
if (Found)
continue;
#endif
#if !defined(_UNIX) && !defined(_WIN_ALL)
if (CmpMSGID(Help[I],MCHelpSwOW))
continue;
#endif
#if !defined(_WIN_ALL) && !defined(_EMX)
if (CmpMSGID(Help[I],MCHelpSwAC))
continue;
#endif
#ifndef SAVE_LINKS
if (CmpMSGID(Help[I],MCHelpSwOL))
continue;
#endif
#ifndef RAR_SMP
if (CmpMSGID(Help[I],MCHelpSwMT))
continue;
#endif
#endif
mprintf(St(Help[I]));
}
mprintf(L"\n");
ErrHandler.Exit(ExitCode);
#endif
}

View File

@ -0,0 +1,13 @@
EXPORTS
RAROpenArchive
RAROpenArchiveEx
RARCloseArchive
RARReadHeader
RARReadHeaderEx
RARProcessFile
RARProcessFileW
RARSetCallback
RARSetChangeVolProc
RARSetProcessDataProc
; RARSetPassword
RARGetDllVersion

View File

@ -0,0 +1,18 @@
#!/usr/bin/env bash
# Works around a bug in Xcode 12. See Carthage issue #3019:
# https://github.com/Carthage/Carthage/issues/3019
# Usage example: ./carthage.sh build --platform iOS
set -euo pipefail
xcconfig=$(mktemp /tmp/static.xcconfig.XXXXXX)
trap 'rm -f "$xcconfig"' INT TERM HUP EXIT
# For Xcode 12 make sure EXCLUDED_ARCHS is set to arm architectures otherwise
# the build will fail on lipo due to duplicate architectures.
echo 'EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1200 = arm64 arm64e armv7 armv7s armv6 armv8' >> $xcconfig
echo 'EXCLUDED_ARCHS = $(inherited) $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_$(EFFECTIVE_PLATFORM_SUFFIX)__NATIVE_ARCH_64_BIT_$(NATIVE_ARCH_64_BIT)__XCODE_$(XCODE_VERSION_MAJOR))' >> $xcconfig
export XCODE_XCCONFIG_FILE="$xcconfig"
carthage "$@"

View File

@ -0,0 +1,174 @@
//
// ExtractBufferedDataTests.m
// UnrarKit
//
//
#import "URKArchiveTestCase.h"
@import os.log;
@import os.signpost;
@interface ExtractBufferedDataTests : URKArchiveTestCase @end
@implementation ExtractBufferedDataTests
- (void)testExtractBufferedData
{
NSURL *archiveURL = self.testFileURLs[@"Test Archive.rar"];
NSString *extractedFile = @"Test File B.jpg";
URKArchive *archive = [[URKArchive alloc] initWithURL:archiveURL error:nil];
NSError *error = nil;
NSMutableData *reconstructedFile = [NSMutableData data];
BOOL success = [archive extractBufferedDataFromFile:extractedFile
error:&error
action:
^(NSData *dataChunk, CGFloat percentDecompressed) {
NSLog(@"Decompressed: %f%%", percentDecompressed);
[reconstructedFile appendBytes:dataChunk.bytes
length:dataChunk.length];
}];
XCTAssertTrue(success, @"Failed to read buffered data");
XCTAssertNil(error, @"Error reading buffered data");
XCTAssertGreaterThan(reconstructedFile.length, 0, @"No data returned");
NSData *originalFile = [NSData dataWithContentsOfURL:self.testFileURLs[extractedFile]];
XCTAssertTrue([originalFile isEqualToData:reconstructedFile],
@"File extracted in buffer not returned correctly");
}
- (void)testExtractBufferedData_ModifiedCRC
{
NSURL *archiveURL = self.testFileURLs[@"Modified CRC Archive.rar"];
NSString *extractedFile = @"README.md";
URKArchive *archive = [[URKArchive alloc] initWithURL:archiveURL error:nil];
NSError *error = nil;
NSMutableData *reconstructedFile = [NSMutableData data];
BOOL success = [archive extractBufferedDataFromFile:extractedFile
error:&error
action:
^(NSData *dataChunk, CGFloat percentDecompressed) {
NSLog(@"Decompressed: %f%%", percentDecompressed);
[reconstructedFile appendBytes:dataChunk.bytes
length:dataChunk.length];
}];
XCTAssertFalse(success, @"Failed to read buffered data");
XCTAssertNotNil(error, @"Error reading buffered data");
NSData *originalFile = [NSData dataWithContentsOfURL:self.testFileURLs[extractedFile]];
XCTAssertTrue([originalFile isEqualToData:reconstructedFile],
@"File extracted in buffer not returned correctly");
}
- (void)testExtractBufferedData_ModifiedCRC_IgnoringMismatches
{
NSURL *archiveURL = self.testFileURLs[@"Modified CRC Archive.rar"];
NSString *extractedFile = @"README.md";
URKArchive *archive = [[URKArchive alloc] initWithURL:archiveURL error:nil];
archive.ignoreCRCMismatches = YES;
NSError *error = nil;
NSMutableData *reconstructedFile = [NSMutableData data];
BOOL success = [archive extractBufferedDataFromFile:extractedFile
error:&error
action:
^(NSData *dataChunk, CGFloat percentDecompressed) {
NSLog(@"Decompressed: %f%%", percentDecompressed);
[reconstructedFile appendBytes:dataChunk.bytes
length:dataChunk.length];
}];
XCTAssertTrue(success, @"Failed to read buffered data");
XCTAssertNil(error, @"Error reading buffered data");
XCTAssertGreaterThan(reconstructedFile.length, 0, @"No data returned");
NSData *originalFile = [NSData dataWithContentsOfURL:self.testFileURLs[extractedFile]];
XCTAssertTrue([originalFile isEqualToData:reconstructedFile],
@"File extracted in buffer not returned correctly");
}
#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
- (void)testExtractBufferedData_VeryLarge
{
os_log_t log = os_log_create("UnrarKit-testExtractBufferedData_VeryLarge", OS_LOG_CATEGORY_POINTS_OF_INTEREST);
os_signpost_id_t createTextFileID;
if (@available(macOS 10.14, *)) {
createTextFileID = os_signpost_id_generate(log);
os_signpost_interval_begin(log, createTextFileID, "Create Text File");
}
NSURL *largeTextFile = [self randomTextFileOfLength:1000000]; // Increase for a more dramatic test
if (@available(macOS 10.14, *)) {
XCTAssertNotNil(largeTextFile, @"No large text file URL returned");
os_signpost_interval_end(log, createTextFileID, "Create Text File");
}
os_signpost_id_t archiveDataID;
if (@available(macOS 10.14, *)) {
archiveDataID = os_signpost_id_generate(log);
os_signpost_interval_begin(log, archiveDataID, "Archive Data");
}
NSURL *archiveURL = [self archiveWithFiles:@[largeTextFile]];
XCTAssertNotNil(archiveURL, @"No archived large text file URL returned");
if (@available(macOS 10.14, *)) {
os_signpost_interval_end(log, archiveDataID, "Archive Data");
}
NSURL *deflatedFileURL = [self.tempDirectory URLByAppendingPathComponent:@"DeflatedTextFile.txt"];
BOOL createSuccess = [[NSFileManager defaultManager] createFileAtPath:deflatedFileURL.path
contents:nil
attributes:nil];
XCTAssertTrue(createSuccess, @"Failed to create empty deflate file");
NSError *handleError = nil;
NSFileHandle *deflated = [NSFileHandle fileHandleForWritingToURL:deflatedFileURL
error:&handleError];
XCTAssertNil(handleError, @"Error creating a file handle");
URKArchive *archive = [[URKArchive alloc] initWithURL:archiveURL error:nil];
os_signpost_id_t extractDataID;
if (@available(macOS 10.14, *)) {
extractDataID = os_signpost_id_generate(log);
os_signpost_interval_begin(log, extractDataID, "Extract Data");
}
NSError *error = nil;
BOOL success = [archive extractBufferedDataFromFile:largeTextFile.lastPathComponent
error:&error
action:
^(NSData *dataChunk, CGFloat percentDecompressed) {
NSLog(@"Decompressed: %f%%", percentDecompressed);
[deflated writeData:dataChunk];
}];
if (@available(macOS 10.14, *)) {
os_signpost_interval_end(log, extractDataID, "Extract Data");
}
XCTAssertTrue(success, @"Failed to read buffered data");
XCTAssertNil(error, @"Error reading buffered data");
[deflated closeFile];
NSData *deflatedData = [NSData dataWithContentsOfURL:deflatedFileURL];
NSData *fileData = [NSData dataWithContentsOfURL:largeTextFile];
XCTAssertTrue([fileData isEqualToData:deflatedData], @"Data didn't restore correctly");
}
#endif
@end

View File

@ -0,0 +1,150 @@
//
// ExtractDataTests.m
// UnrarKit
//
//
#import "URKArchiveTestCase.h"
@interface ExtractDataTests : URKArchiveTestCase
@end
@implementation ExtractDataTests
- (void)testExtractData
{
NSArray *testArchives = @[@"Test Archive.rar",
@"Test Archive (Password).rar",
@"Test Archive (Header Password).rar"];
NSSet *expectedFileSet = [self.testFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) {
return ![key hasSuffix:@"rar"] && ![key hasSuffix:@"md"];
}];
NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)];
for (NSString *testArchiveName in testArchives) {
NSURL *testArchiveURL = self.testFileURLs[testArchiveName];
NSString *password = ([testArchiveName rangeOfString:@"Password"].location != NSNotFound
? @"password"
: nil);
URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL password:password error:nil];
NSError *error = nil;
NSArray *fileInfos = [archive listFileInfo:&error];
XCTAssertNil(error, @"Error reading file info");
for (NSInteger i = 0; i < expectedFiles.count; i++) {
NSString *expectedFilename = expectedFiles[i];
NSError *error = nil;
NSData *extractedData = [archive extractDataFromFile:expectedFilename error:&error];
XCTAssertNil(error, @"Error in extractData:error:");
NSData *expectedFileData = [NSData dataWithContentsOfURL:self.testFileURLs[expectedFilename]];
XCTAssertNotNil(extractedData, @"No data extracted");
XCTAssertTrue([expectedFileData isEqualToData:extractedData], @"Extracted data doesn't match original file");
error = nil;
NSData *dataFromFileInfo = [archive extractData:fileInfos[i] error:&error];
XCTAssertNil(error, @"Error extracting data by file info");
XCTAssertTrue([expectedFileData isEqualToData:dataFromFileInfo], @"Extracted data from file info doesn't match original file");
}
}
}
- (void)testExtractData_Unicode
{
NSSet *expectedFileSet = [self.unicodeFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) {
return ![key hasSuffix:@"rar"] && ![key hasSuffix:@"md"];
}];
NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)];
NSURL *testArchiveURL = self.unicodeFileURLs[@"Ⓣest Ⓐrchive.rar"];
URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil];
NSError *error = nil;
NSArray *fileInfos = [archive listFileInfo:&error];
XCTAssertNil(error, @"Error reading file info");
for (NSInteger i = 0; i < expectedFiles.count; i++) {
NSString *expectedFilename = expectedFiles[i];
NSError *error = nil;
NSData *extractedData = [archive extractDataFromFile:expectedFilename error:&error];
XCTAssertNil(error, @"Error in extractData:error:");
NSData *expectedFileData = [NSData dataWithContentsOfURL:self.unicodeFileURLs[expectedFilename]];
XCTAssertNotNil(extractedData, @"No data extracted");
XCTAssertTrue([expectedFileData isEqualToData:extractedData], @"Extracted data doesn't match original file");
error = nil;
NSData *dataFromFileInfo = [archive extractData:fileInfos[i] error:&error];
XCTAssertNil(error, @"Error extracting data by file info");
XCTAssertTrue([expectedFileData isEqualToData:dataFromFileInfo], @"Extracted data from file info doesn't match original file");
}
}
- (void)testExtractData_NoPassword
{
NSArray *testArchives = @[@"Test Archive (Password).rar",
@"Test Archive (Header Password).rar"];
for (NSString *testArchiveName in testArchives) {
URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[testArchiveName] error:nil];
NSError *error = nil;
NSData *data = [archive extractDataFromFile:@"Test File A.txt" error:&error];
XCTAssertNotNil(error, @"Extract data without password succeeded");
XCTAssertNil(data, @"Data returned without password");
XCTAssertEqual(error.code, URKErrorCodeMissingPassword, @"Unexpected error code returned");
}
}
- (void)testExtractData_InvalidArchive
{
URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Test File A.txt"] error:nil];
NSError *error = nil;
NSData *data = [archive extractDataFromFile:@"Any file.txt" error:&error];
XCTAssertNotNil(error, @"Extract data for invalid archive succeeded");
XCTAssertNil(data, @"Data returned for invalid archive");
XCTAssertEqual(error.code, URKErrorCodeBadArchive, @"Unexpected error code returned");
}
- (void)testExtractData_ModifiedCRC
{
URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Modified CRC Archive.rar"] error:nil];
NSError *error = nil;
NSData *data = [archive extractDataFromFile:@"README.md" error:&error];
XCTAssertNotNil(error, @"Extract data for invalid archive succeeded");
XCTAssertNil(data, @"Data returned for invalid archive");
XCTAssertEqual(error.code, URKErrorCodeBadData, @"Unexpected error code returned");
}
- (void)testExtractData_ModifiedCRC_IgnoringMismatches
{
URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Modified CRC Archive.rar"] error:nil];
archive.ignoreCRCMismatches = YES;
NSError *error = nil;
NSData *data = [archive extractDataFromFile:@"README.md" error:&error];
NSData *expectedData = [NSData dataWithContentsOfURL:self.testFileURLs[@"README.md"]];
XCTAssertNil(error, @"Extract data for invalid archive succeeded");
XCTAssertNotNil(data, @"Data returned for invalid archive");
XCTAssertEqualObjects(data, expectedData);
}
@end

View File

@ -0,0 +1,213 @@
//
// ListFileInfoTests.m
// UnrarKit
//
//
#import "URKArchiveTestCase.h"
@interface ListFileInfoTests : URKArchiveTestCase
@end
@implementation ListFileInfoTests
- (void)testListFileInfo {
URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Test Archive.rar"] error:nil];
NSSet *expectedFileSet = [self.testFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) {
return ![key hasSuffix:@"rar"] && ![key hasSuffix:@"md"];
}];
NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)];
static NSDateFormatter *testFileInfoDateFormatter;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
testFileInfoDateFormatter = [[NSDateFormatter alloc] init];
testFileInfoDateFormatter.dateFormat = @"M/dd/yyyy h:mm a";
testFileInfoDateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US"];
});
NSDictionary *expectedTimestamps = @{@"Test File A.txt": [testFileInfoDateFormatter dateFromString:@"3/13/2014 8:02 PM"],
@"Test File B.jpg": [testFileInfoDateFormatter dateFromString:@"3/13/2014 8:04 PM"],
@"Test File C.m4a": [testFileInfoDateFormatter dateFromString:@"3/13/2014 8:05 PM"],};
NSError *error = nil;
NSArray *filesInArchive = [archive listFileInfo:&error];
XCTAssertNil(error, @"Error returned by listFileInfo");
XCTAssertNotNil(filesInArchive, @"No list of files returned");
XCTAssertEqual(filesInArchive.count, expectedFileSet.count, @"Incorrect number of files listed in archive");
NSFileManager *fm = [NSFileManager defaultManager];
for (NSInteger i = 0; i < filesInArchive.count; i++) {
URKFileInfo *fileInfo = filesInArchive[i];
// Test Archive Name
NSString *expectedArchiveName = archive.filename;
XCTAssertEqualObjects(fileInfo.archiveName, expectedArchiveName, @"Incorrect archive name");
// Test Filename
NSString *expectedFilename = expectedFiles[i];
XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Incorrect filename");
// Test CRC
NSUInteger expectedFileCRC = [self crcOfTestFile:expectedFilename];
XCTAssertEqual(fileInfo.CRC, expectedFileCRC, @"Incorrect CRC checksum");
// Test Last Modify Date
NSTimeInterval archiveFileTimeInterval = [fileInfo.timestamp timeIntervalSinceReferenceDate];
NSTimeInterval expectedFileTimeInterval = [expectedTimestamps[fileInfo.filename] timeIntervalSinceReferenceDate];
XCTAssertEqualWithAccuracy(archiveFileTimeInterval, expectedFileTimeInterval, 60, @"Incorrect file timestamp (more than 60 seconds off)");
// Test Uncompressed Size
NSError *attributesError = nil;
NSString *expectedFilePath = [[self urlOfTestFile:expectedFilename] path];
NSDictionary *expectedFileAttributes = [fm attributesOfItemAtPath:expectedFilePath
error:&attributesError];
XCTAssertNil(attributesError, @"Error getting file attributes of %@", expectedFilename);
long long expectedFileSize = expectedFileAttributes.fileSize;
XCTAssertEqual(fileInfo.uncompressedSize, expectedFileSize, @"Incorrect uncompressed file size");
// Test Compression method
XCTAssertEqual(fileInfo.compressionMethod, URKCompressionMethodNormal, @"Incorrect compression method");
// Test Host OS
XCTAssertEqual(fileInfo.hostOS, URKHostOSUnix, @"Incorrect host OS");
}
}
- (void)testListFileInfo_Unicode
{
NSSet *expectedFileSet = [self.unicodeFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) {
return ![key hasSuffix:@"rar"] && ![key hasSuffix:@"md"];
}];
NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)];
NSURL *testArchiveURL = self.unicodeFileURLs[@"Ⓣest Ⓐrchive.rar"];
URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil];
NSError *error = nil;
NSArray *filesInArchive = [archive listFileInfo:&error];
XCTAssertNil(error, @"Error returned by listFileInfo");
XCTAssertNotNil(filesInArchive, @"No list of files returned");
XCTAssertEqual(filesInArchive.count, expectedFileSet.count,
@"Incorrect number of files listed in archive");
for (NSInteger i = 0; i < filesInArchive.count; i++) {
URKFileInfo *fileInfo = (URKFileInfo *)filesInArchive[i];
XCTAssertEqualObjects(fileInfo.filename, expectedFiles[i], @"Incorrect filename listed");
XCTAssertEqualObjects(fileInfo.archiveName, archive.filename, @"Incorrect archiveName listed");
}
}
#if !TARGET_OS_IPHONE
- (void)testListFileInfo_MultivolumeArchive {
NSArray<NSURL*> *generatedVolumeURLs = [self multiPartArchiveWithName:@"ListFileInfoTests_MultivolumeArchive.rar"];
URKArchive *archive = [[URKArchive alloc] initWithURL:generatedVolumeURLs.firstObject error:nil];
NSError *error = nil;
NSArray *files = [archive listFileInfo:&error];
XCTAssertNil(error, @"Error returned when listing file info for multivolume archive");
XCTAssertEqual(files.count, 1, @"Incorrect number of file info items returned for multivolume archive");
}
#endif
- (void)testListFileInfo_HeaderPassword
{
NSArray *testArchives = @[@"Test Archive (Header Password).rar"];
NSSet *expectedFileSet = [self.testFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) {
return ![key hasSuffix:@"rar"] && ![key hasSuffix:@"md"];
}];
NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)];
for (NSString *testArchiveName in testArchives) {
NSURL *testArchiveURL = self.testFileURLs[testArchiveName];
URKArchive *archiveNoPassword = [[URKArchive alloc] initWithURL:testArchiveURL error:nil];
NSError *error = nil;
NSArray *filesInArchive = [archiveNoPassword listFileInfo:&error];
XCTAssertNotNil(error, @"No error returned by listFileInfo (no password given)");
XCTAssertNil(filesInArchive, @"List of files returned (no password given)");
URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL password:@"password" error:nil];
filesInArchive = nil;
error = nil;
filesInArchive = [archive listFileInfo:&error];
XCTAssertNil(error, @"Error returned by listFileInfo");
XCTAssertEqual(filesInArchive.count, expectedFileSet.count,
@"Incorrect number of files listed in archive");
for (NSInteger i = 0; i < filesInArchive.count; i++) {
URKFileInfo *archiveFileInfo = filesInArchive[i];
NSString *archiveFilename = archiveFileInfo.filename;
NSString *expectedFilename = expectedFiles[i];
XCTAssertEqualObjects(archiveFilename, expectedFilename, @"Incorrect filename listed");
}
}
}
- (void)testListFileInfo_NoHeaderPasswordGiven {
URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Test Archive (Header Password).rar"] error:nil];
NSError *error = nil;
NSArray *files = [archive listFileInfo:&error];
XCTAssertNotNil(error, @"List without password succeeded");
XCTAssertNil(files, @"List returned without password");
XCTAssertEqual(error.code, URKErrorCodeMissingPassword, @"Unexpected error code returned");
}
- (void)testListFileInfo_InvalidArchive
{
URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Test File A.txt"] error:nil];
NSError *error = nil;
NSArray *files = [archive listFileInfo:&error];
XCTAssertNotNil(error, @"List files of invalid archive succeeded");
XCTAssertNil(files, @"List returned for invalid archive");
XCTAssertEqual(error.code, URKErrorCodeBadArchive, @"Unexpected error code returned");
}
- (void)testListFileInfo_ModifiedCRC
{
URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Modified CRC Archive.rar"] error:nil];
NSError *error = nil;
NSArray *files = [archive listFileInfo:&error];
XCTAssertNotNil(error, @"List files of invalid archive succeeded");
XCTAssertNil(files, @"List returned for invalid archive");
XCTAssertEqual(error.code, URKErrorCodeBadData, @"Unexpected error code returned");
}
- (void)testListFileInfo_ModifiedCRC_IgnoringMismatches
{
URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Modified CRC Archive.rar"] error:nil];
archive.ignoreCRCMismatches = YES;
NSError *error = nil;
NSArray<URKFileInfo*> *files = [archive listFileInfo:&error];
XCTAssertNil(error, @"List files of invalid archive succeeded");
XCTAssertNotNil(files, @"List returned for invalid archive");
XCTAssertEqual(files.count, 1);
XCTAssertEqualObjects(files[0].filename, @"README.md");
}
@end

View File

@ -0,0 +1,261 @@
//
// PerformOnDataTests.m
// UnrarKit
//
//
#import "URKArchiveTestCase.h"
@interface PerformOnDataTests : URKArchiveTestCase
@end
@implementation PerformOnDataTests
- (void)testPerformOnData
{
NSArray *testArchives = @[@"Test Archive.rar",
@"Test Archive (Password).rar",
@"Test Archive (Header Password).rar"];
NSSet *expectedFileSet = [self.testFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) {
return ![key hasSuffix:@"rar"] && ![key hasSuffix:@"md"];
}];
NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)];
for (NSString *testArchiveName in testArchives) {
NSURL *testArchiveURL = self.testFileURLs[testArchiveName];
NSString *password = ([testArchiveName rangeOfString:@"Password"].location != NSNotFound
? @"password"
: nil);
URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL password:password error:nil];
__block NSUInteger fileIndex = 0;
NSError *error = nil;
[archive performOnDataInArchive:
^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) {
NSString *expectedFilename = expectedFiles[fileIndex++];
XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Unexpected filename encountered");
NSData *expectedFileData = [NSData dataWithContentsOfURL:self.testFileURLs[expectedFilename]];
XCTAssertNotNil(fileData, @"No data extracted");
XCTAssertTrue([expectedFileData isEqualToData:fileData], @"File data doesn't match original file");
} error:&error];
XCTAssertNil(error, @"Error iterating through files");
XCTAssertEqual(fileIndex, expectedFiles.count, @"Incorrect number of files encountered");
}
}
- (void)testPerformOnData_Unicode
{
NSSet *expectedFileSet = [self.unicodeFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) {
return ![key hasSuffix:@"rar"] && ![key hasSuffix:@"md"];
}];
NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)];
NSURL *testArchiveURL = self.unicodeFileURLs[@"Ⓣest Ⓐrchive.rar"];
URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil];
__block NSUInteger fileIndex = 0;
NSError *error = nil;
[archive performOnDataInArchive:
^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) {
NSString *expectedFilename = expectedFiles[fileIndex++];
XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Unexpected filename encountered");
NSData *expectedFileData = [NSData dataWithContentsOfURL:self.unicodeFileURLs[expectedFilename]];
XCTAssertNotNil(fileData, @"No data extracted");
XCTAssertTrue([expectedFileData isEqualToData:fileData], @"File data doesn't match original file");
} error:&error];
XCTAssertNil(error, @"Error iterating through files");
XCTAssertEqual(fileIndex, expectedFiles.count, @"Incorrect number of files encountered");
}
- (void)testPerformOnData_ModifiedCRC
{
NSURL *testArchiveURL = self.testFileURLs[@"Modified CRC Archive.rar"];
URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil];
__block BOOL blockCalled = NO;
NSError *error = nil;
[archive performOnDataInArchive:
^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) {
blockCalled = YES;
} error:&error];
XCTAssertNotNil(error, @"Error iterating through files");
XCTAssertFalse(blockCalled);
}
- (void)testPerformOnData_ModifiedCRC_IgnoringMismatches
{
NSURL *testArchiveURL = self.testFileURLs[@"Modified CRC Archive.rar"];
URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil];
archive.ignoreCRCMismatches = YES;
__block NSUInteger fileIndex = 0;
NSError *error = nil;
[archive performOnDataInArchive:
^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) {
XCTAssertEqual(fileIndex++, 0, @"performOnDataInArchive called too many times");
XCTAssertEqualObjects(fileInfo.filename, @"README.md");
NSData *expectedFileData = [NSData dataWithContentsOfURL:self.testFileURLs[@"README.md"]];
XCTAssertNotNil(fileData, @"No data extracted");
XCTAssertTrue([expectedFileData isEqualToData:fileData], @"File data doesn't match original file");
} error:&error];
XCTAssertNil(error, @"Error iterating through files");
}
#if !TARGET_OS_IPHONE
- (void)testPerformOnData_FileMoved
{
NSURL *largeArchiveURL = [self largeArchiveURL];
URKArchive *archive = [[URKArchive alloc] initWithURL:largeArchiveURL error:nil];
NSError *error = nil;
NSArray *archiveFiles = [archive listFilenames:&error];
XCTAssertNotNil(archiveFiles, @"No filenames listed from test archive");
XCTAssertNil(error, @"Error listing files in test archive: %@", error);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[NSThread sleepForTimeInterval:1];
NSURL *movedURL = [largeArchiveURL URLByAppendingPathExtension:@"FileMoved"];
NSError *renameError = nil;
NSFileManager *fm = [NSFileManager defaultManager];
[fm moveItemAtURL:largeArchiveURL toURL:movedURL error:&renameError];
XCTAssertNil(renameError, @"Error renaming file: %@", renameError);
});
__block NSUInteger fileCount = 0;
error = nil;
BOOL success = [archive performOnDataInArchive:^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) {
XCTAssertNotNil(fileData, @"Extracted file is nil: %@", fileInfo.filename);
if (!fileInfo.isDirectory) {
fileCount++;
XCTAssertGreaterThan(fileData.length, 0, @"Extracted file is empty: %@", fileInfo.filename);
}
} error:&error];
XCTAssertEqual(fileCount, 20, @"Not all files read");
XCTAssertTrue(success, @"Failed to read files");
XCTAssertNil(error, @"Error reading files: %@", error);
}
#endif
#if !TARGET_OS_IPHONE
- (void)testPerformOnData_FileDeleted
{
NSURL *largeArchiveURL = [self largeArchiveURL];
URKArchive *archive = [[URKArchive alloc] initWithURL:largeArchiveURL error:nil];
NSError *error = nil;
NSArray *archiveFiles = [archive listFilenames:&error];
XCTAssertNotNil(archiveFiles, @"No filenames listed from test archive");
XCTAssertNil(error, @"Error listing files in test archive: %@", error);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[NSThread sleepForTimeInterval:1];
NSError *removeError = nil;
NSFileManager *fm = [NSFileManager defaultManager];
[fm removeItemAtURL:largeArchiveURL error:&removeError];
XCTAssertNil(removeError, @"Error removing file: %@", removeError);
});
__block NSUInteger fileCount = 0;
error = nil;
BOOL success = [archive performOnDataInArchive:^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) {
XCTAssertNotNil(fileData, @"Extracted file is nil: %@", fileInfo.filename);
if (!fileInfo.isDirectory) {
fileCount++;
XCTAssertGreaterThan(fileData.length, 0, @"Extracted file is empty: %@", fileInfo.filename);
}
} error:&error];
XCTAssertEqual(fileCount, 20, @"Not all files read");
XCTAssertTrue(success, @"Failed to read files");
XCTAssertNil(error, @"Error reading files: %@", error);
}
#endif
#if !TARGET_OS_IPHONE
- (void)testPerformOnData_FileMovedBeforeBegin
{
NSURL *largeArchiveURL = [self largeArchiveURL];
URKArchive *archive = [[URKArchive alloc] initWithURL:largeArchiveURL error:nil];
NSError *error = nil;
NSArray *archiveFiles = [archive listFilenames:&error];
XCTAssertNotNil(archiveFiles, @"No filenames listed from test archive");
XCTAssertNil(error, @"Error listing files in test archive: %@", error);
NSURL *movedURL = [largeArchiveURL URLByAppendingPathExtension:@"FileMovedBeforeBegin"];
NSError *renameError = nil;
NSFileManager *fm = [NSFileManager defaultManager];
[fm moveItemAtURL:largeArchiveURL toURL:movedURL error:&renameError];
XCTAssertNil(renameError, @"Error renaming file: %@", renameError);
__block NSUInteger fileCount = 0;
error = nil;
BOOL success = [archive performOnDataInArchive:^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) {
XCTAssertNotNil(fileData, @"Extracted file is nil: %@", fileInfo.filename);
if (!fileInfo.isDirectory) {
fileCount++;
XCTAssertGreaterThan(fileData.length, 0, @"Extracted file is empty: %@", fileInfo.filename);
}
} error:&error];
XCTAssertEqual(fileCount, 20, @"Not all files read");
XCTAssertTrue(success, @"Failed to read files");
XCTAssertNil(error, @"Error reading files: %@", error);
}
#endif
- (void)testPerformOnData_Folder
{
NSURL *testArchiveURL = self.testFileURLs[@"Folder Archive.rar"];
URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil];
NSArray *expectedFiles = @[@"G070-Cliff", @"G070-Cliff/image.jpg"];
__block NSUInteger fileIndex = 0;
NSError *error = nil;
[archive performOnDataInArchive:
^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) {
NSString *expectedFilename = expectedFiles[fileIndex++];
XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Unexpected filename encountered");
} error:&error];
XCTAssertNil(error, @"Error iterating through files");
XCTAssertEqual(fileIndex, expectedFiles.count, @"Incorrect number of files encountered");
}
@end

View File

@ -0,0 +1,194 @@
//
// PerformOnFilesTests.m
// UnrarKit
//
//
#import "URKArchiveTestCase.h"
@interface PerformOnFilesTests : URKArchiveTestCase
@end
@implementation PerformOnFilesTests
- (void)testPerformOnFiles
{
NSArray *testArchives = @[@"Test Archive.rar",
@"Test Archive (Password).rar",
@"Test Archive (Header Password).rar"];
NSSet *expectedFileSet = [self.testFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) {
return ![key hasSuffix:@"rar"] && ![key hasSuffix:@"md"];
}];
NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)];
for (NSString *testArchiveName in testArchives) {
NSURL *testArchiveURL = self.testFileURLs[testArchiveName];
NSString *password = ([testArchiveName rangeOfString:@"Password"].location != NSNotFound
? @"password"
: nil);
URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL password:password error:nil];
__block NSUInteger fileIndex = 0;
NSError *error = nil;
[archive performOnFilesInArchive:
^(URKFileInfo *fileInfo, BOOL *stop) {
NSString *expectedFilename = expectedFiles[fileIndex++];
XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Unexpected filename encountered");
} error:&error];
XCTAssertNil(error, @"Error iterating through files");
XCTAssertEqual(fileIndex, expectedFiles.count, @"Incorrect number of files encountered");
}
}
- (void)testPerformOnFiles_ModifiedCRC
{
NSURL *testArchiveURL = self.testFileURLs[@"Modified CRC Archive.rar"];
NSString *password = nil;
URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL password:password error:nil];
__block BOOL blockCalled = NO;
NSError *error = nil;
[archive performOnFilesInArchive:
^(URKFileInfo *fileInfo, BOOL *stop) {
blockCalled = YES;
} error:&error];
XCTAssertNotNil(error, @"Error iterating through files");
XCTAssertFalse(blockCalled);
}
- (void)testPerformOnFiles_ModifiedCRC_MismatchesIgnored
{
NSURL *testArchiveURL = self.testFileURLs[@"Modified CRC Archive.rar"];
NSString *password = nil;
URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL password:password error:nil];
archive.ignoreCRCMismatches = YES;
__block NSUInteger fileIndex = 0;
NSError *error = nil;
[archive performOnFilesInArchive:
^(URKFileInfo *fileInfo, BOOL *stop) {
XCTAssertEqual(fileIndex++, 0, @"performOnFilesInArchive called too many times");
XCTAssertEqualObjects(fileInfo.filename, @"README.md");
} error:&error];
XCTAssertNil(error, @"Error iterating through files");
}
- (void)testPerformOnFiles_Unicode
{
NSSet *expectedFileSet = [self.unicodeFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) {
return ![key hasSuffix:@"rar"] && ![key hasSuffix:@"md"];
}];
NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)];
NSURL *testArchiveURL = self.unicodeFileURLs[@"Ⓣest Ⓐrchive.rar"];
URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil];
__block NSUInteger fileIndex = 0;
NSError *error = nil;
[archive performOnFilesInArchive:
^(URKFileInfo *fileInfo, BOOL *stop) {
NSString *expectedFilename = expectedFiles[fileIndex++];
XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Unexpected filename encountered");
} error:&error];
XCTAssertNil(error, @"Error iterating through files");
XCTAssertEqual(fileIndex, expectedFiles.count, @"Incorrect number of files encountered");
}
- (void)testPerformOnFiles_Nested_ExtractData
{
URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Test Archive.rar"]
password:@""
error:nil];
NSError *archiveError = nil;
[archive performOnFilesInArchive:^(URKFileInfo *fileInfo, BOOL *stop) {
NSError *extractError = nil;
NSData *data = [archive extractData:fileInfo error:&extractError];
if (data == nil) {
*stop = YES;
XCTFail();
}
} error:&archiveError];
}
- (void)testPerformOnFiles_Nested_ExtractFiles
{
URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Test Archive.rar"]
password:@""
error:nil];
NSError *archiveError = nil;
[archive performOnFilesInArchive:^(URKFileInfo *fileInfo, BOOL *stop) {
#if !TARGET_OS_IPHONE
NSURL *extractRootDirectory = self.tempDirectory;
#else
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *extractRootDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] firstObject];
extractRootDirectory = [extractRootDirectory URLByAppendingPathComponent:@"testPerformOnFiles_Nested_ExtractFiles"];
NSLog(@"Documents directory: %@", extractRootDirectory.path);
if ([fm fileExistsAtPath:extractRootDirectory.path]) {
NSError *clearDirError = nil;
XCTAssertTrue([fm removeItemAtURL:extractRootDirectory error:&clearDirError], @"Failed to clear out documents directory");
XCTAssertNil(clearDirError, @"Error while clearing out documents directory");
}
#endif
NSError *extractError = nil;
BOOL success = [archive extractFilesTo:extractRootDirectory.path
overwrite:NO
error:&extractError];
XCTAssertTrue(success);
} error:&archiveError];
}
#if !TARGET_OS_IPHONE
- (void)testPerformOnFiles_Ordering
{
NSArray *testFilenames = @[@"AAA.txt",
@"BBB.txt",
@"CCC.txt"];
NSFileManager *fm = [NSFileManager defaultManager];
NSMutableArray *testFileURLs = [NSMutableArray array];
// Touch test files
[testFilenames enumerateObjectsUsingBlock:^(NSString *filename, NSUInteger idx, BOOL *stop) {
NSURL *outputURL = [self.tempDirectory URLByAppendingPathComponent:filename];
XCTAssertTrue([fm createFileAtPath:outputURL.path contents:nil attributes:nil], @"Failed to create test file: %@", filename);
[testFileURLs addObject:outputURL];
}];
// Create RAR archive with test files, reversed
NSURL *reversedArchiveURL = [self archiveWithFiles:testFileURLs.reverseObjectEnumerator.allObjects];
NSError *error = nil;
__block NSUInteger index = 0;
URKArchive *archive = [[URKArchive alloc] initWithURL:reversedArchiveURL error:nil];
[archive performOnFilesInArchive:^(URKFileInfo *fileInfo, BOOL *stop) {
NSString *expectedFilename = testFilenames[index++];
XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Archive files not iterated through in correct order");
} error:&error];
}
#endif
@end

View File

@ -0,0 +1,275 @@
[![Build Status](https://travis-ci.org/abbeycode/UnrarKit.svg?branch=master)](https://travis-ci.org/abbeycode/UnrarKit)
[![Documentation Coverage](https://img.shields.io/cocoapods/metrics/doc-percent/UnrarKit.svg)](http://cocoadocs.org/docsets/UnrarKit)
# About
UnrarKit is here to enable Mac and iOS apps to easily work with RAR files for read-only operations. It is currently based on version 5.2.1 of the [UnRAR library](http://www.rarlab.com/rar/unrarsrc-5.2.1.tar.gz).
There is a main project, with unit tests, and a basic iOS example project, which demonstrates how to use the library. To see all of these, open the main workspace file.
I'm always open to improvements, so please submit your pull requests, or [create issues](https://github.com/abbeycode/UnrarKit/issues) for someone else to implement.
# Installation
UnrarKit supports both [CocoaPods](https://cocoapods.org/) and [Carthage](https://github.com/Carthage/Carthage). CocoaPods does not support dynamic framework targets (as of v0.39.0), so in that case, please use Carthage.
Cartfile:
github "abbeycode/UnrarKit"
Podfile:
pod "UnrarKit"
# Example Usage
```Objective-C
NSError *archiveError = nil;
URKArchive *archive = [[URKArchive alloc] initWithPath:@"An Archive.rar" error:&archiveError];
NSError *error = nil;
```
## Listing the file names in an archive
```Objective-C
NSArray<String*> *filesInArchive = [archive listFilenames:&error];
for (NSString *name in filesInArchive) {
NSLog(@"Archived file: %@", name);
}
```
## Listing the file details in an archive
```Objective-C
NSArray<URKFileInfo*> *fileInfosInArchive = [archive listFileInfo:&error];
for (URKFileInfo *info in fileInfosInArchive) {
NSLog(@"Archive name: %@ | File name: %@ | Size: %lld", info.archiveName, info.filename, info.uncompressedSize);
}
```
## Working with passwords
```Objective-C
NSArray<URKFileInfo*> *fileInfosInArchive = [archive listFileInfo:&error];
if (archive.isPasswordProtected) {
NSString *givenPassword = // prompt user
archive.password = givenPassword
}
// You can now extract the files
```
## Extracting files to a directory
```Objective-C
BOOL extractFilesSuccessful = [archive extractFilesTo:@"some/directory"
overWrite:NO
progress:
^(URKFileInfo *currentFile, CGFloat percentArchiveDecompressed) {
NSLog(@"Extracting %@: %f%% complete", currentFile.filename, percentArchiveDecompressed);
}
error:&error];
```
## Extracting a file into memory
```Objective-C
NSData *extractedData = [archive extractDataFromFile:@"a file in the archive.jpg"
progress:^(CGFloat percentDecompressed) {
NSLog(@"Extracting, %f%% complete", percentDecompressed);
}
error:&error];
```
## Streaming a file
For large files, you may not want the whole contents in memory at once. You can handle it one "chunk" at a time, like so:
```Objective-C
BOOL success = [archive extractBufferedDataFromFile:@"a file in the archive.jpg"
error:&error
action:
^(NSData *dataChunk, CGFloat percentDecompressed) {
NSLog(@"Decompressed: %f%%", percentDecompressed);
// Do something with the NSData chunk
}];
```
# Progress Reporting
The following methods support `NSProgress` and `NSProgressReporting`:
* `extractFilesTo:overwrite:error:`
* `extractData:error:`
* `extractDataFromFile:error:`
* `performOnFilesInArchive:error:`
* `performOnDataInArchive:error:`
* `extractBufferedDataFromFile:error:action:`
## Using implicit `NSProgress` hierarchy
You can create your own instance of `NSProgress` and observe its `fractionCompleted` property with KVO to monitor progress like so:
```Objective-C
static void *ExtractDataContext = &ExtractDataContext;
URKArchive *archive = [[URKArchive alloc] initWithURL:aFileURL error:nil];
NSProgress *extractDataProgress = [NSProgress progressWithTotalUnitCount:1];
[extractDataProgress becomeCurrentWithPendingUnitCount:1];
NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted));
[extractDataProgress addObserver:self
forKeyPath:observedSelector
options:NSKeyValueObservingOptionInitial
context:ExtractDataContext];
NSError *extractError = nil;
NSData *data = [archive extractDataFromFile:firstFile error:&extractError];
[extractDataProgress resignCurrent];
[extractDataProgress removeObserver:self forKeyPath:observedSelector];
```
## Using your own explicit `NSProgress` instance
If you don't have a hierarchy of `NSProgress` instances, or if you want to observe more details during progress updates in `extractFilesTo:overwrite:error:`, you can create your own instance of `NSProgress` and set the `URKArchive` instance's `progress` property, like so:
```Objective-C
static void *ExtractFilesContext = &ExtractFilesContext;
URKArchive *archive = [[URKArchive alloc] initWithURL:aFileURL error:nil];
NSProgress *extractFilesProgress = [NSProgress progressWithTotalUnitCount:1];
archive.progress = extractFilesProgress;
NSString *observedSelector = NSStringFromSelector(@selector(localizedDescription));
[self.descriptionsReported removeAllObjects];
[extractFilesProgress addObserver:self
forKeyPath:observedSelector
options:NSKeyValueObservingOptionInitial
context:ExtractFilesContext];
NSError *extractError = nil;
BOOL success = [archive extractFilesTo:extractURL.path
overwrite:NO
error:&extractError];
[extractFilesProgress removeObserver:self forKeyPath:observedSelector];
```
## Cancellation with `NSProgress`
Using either method above, you can call `[progress cancel]` to stop the operation in progress. It will cause the operation to fail, returning `nil` or `NO` (depending on the return type, and give an error with error code `URKErrorCodeUserCancelled`.
# Notes
To open in Xcode, use the [UnrarKit.xcworkspace](UnrarKit.xcworkspace) file, which includes the other projects.
# Documentation
Full documentation for the project is available on [CocoaDocs](http://cocoadocs.org/docsets/UnrarKit).
# Logging
For all OS versions from 2016 onward (macOS 10.12, iOS 10, tvOS 10, watchOS 3), UnzipKit uses the new [Unified Logging framework](https://developer.apple.com/documentation/os/logging) for logging and Activity Tracing. You can view messages at the Info or Debug level to view more details of how UnzipKit is working, and use Activity Tracing to help pinpoint the code path that's causing a particular error.
As a fallback, regular `NSLog` is used on older OSes, with all messages logged at the same level.
When debugging your own code, if you'd like to decrease the verbosity of the UnrarKit framework, you can run the following command:
sudo log config --mode "level:default" --subsystem com.abbey-code.UnrarKit
The available levels, in order of increasing verbosity, are `default`, `info`, `debug`, with `debug` being the default.
## Logging guidelines
These are the general rules governing the particulars of how activities and log messages are classified and written. They were written after the initial round of log messages were, so there may be some inconsistencies (such as an incorrect log level). If you think you spot one, open an issue or a pull request!
### Logging
Log messages should follow these conventions.
1. Log messages don't have final punctuation (like these list items)
1. Messages that note a C function is about to be called, rather than a higher level UnrarKit or Cocoa method, end with "...", since it's not expected for them to log any details of their own
#### Default log level
There should be no messages at this level, so that it's possible for a consumer of the API to turn off _all_ diagnostic logging from it, as detailed above. It's only possible to `log config --mode "level:off"` for a process, not a subsystem.
#### Info log level
Info level log statements serve the following specific purposes.
1. Major action is taken, such as initializing an archive object, or deleting a file from an archive
1. Noting each public method has been called, and the arguments with which it was called
1. Signposting the major actions a public method takes
1. Notifying that an atypical condition has occurred (such as an action causing an early stop in a block or a NO return value)
1. Noting that a loop is about to occur, which will contain debug-level messages for each iteration
#### Debug log level
Most messages fall into this category, making it extremely verbose. All non-error messages that don't fall into either of the other two categories should be debug-level, with some examples of specific cases below.
1. Any log message in a private method
1. Noting variable and argument values in a method
1. Indicating that everything is working as expected
1. Indicating what happens during each iteration of a loop (or documenting that an iteration has happened at all)
#### Error log level
1. Every `NSError` generated should get logged with the same detail message as the `NSError` object itself
1. `NSError` log messages should contain the string of the error code's enumeration value (e.g. `"URKErrorCodeArchiveNotFound"`) when it is known at design time
1. Errors should reported everywhere they're encountered, making it easier to trace their flows through the call stack
1. Early exits that result in desired work not being performed
#### Fault log level
So far, there is only one case that gets logged at Fault-level: when a Cocoa framework methods that come back with an error
### Activities
1. Public methods have an English activity names with spaces, and are title-case
1. Private methods each have an activity with the method's name
1. Sub-activities are created for significant scope changes, such as when inside an action block, but not if no significant work is done before entering that action
1. Top-level activities within a method have variables named `activity`, with more specific labels given to sub-activities
1. If a method is strictly an overload that calls out to another overload without doing anything else, it should not define its own activity
# Pushing a new CocoaPods version
New tagged builds (in any branch) get pushed to CocoaPods automatically, provided they meet the following criteria:
1. All builds and tests succeed
2. The library builds successfully for CocoaPods and for Carthage
3. The build is tagged with something resembling a version number (`#.#.#(-beta#)`, e.g. **2.9** or **2.9-beta5**)
4. `pod spec lint` passes, making sure the CocoaPod is 100% valid
Before pushing a build, you must:
1. Add the release notes to the [CHANGELOG.md](CHANGELOG.md), and commit
2. Run [set-version](Scripts/set-version.sh), like so:
`./Scripts/set-version.sh <version number>`
This does the following:
1. Updates the [UnrarKit-Info.plist](Resources/UnrarKit-Info.plist) file to indicate the new version number, and commits it
2. Makes an annotated tag whose message contains the release notes entered in Step 1
Once that's done, you can call `git push --follow-tags` [<sup id=a1>1</sup>](#f1), and let [Travis CI](https://travis-ci.org/abbeycode/UnrarKit/builds) take care of the rest.
# Credits
* Dov Frankel (dov@abbey-code.com)
* Rogerio Pereira Araujo (rogerio.araujo@gmail.com)
* Vicent Scott (vkan388@gmail.com)
<hr>
<span id="f1">1</span>: Or set `followTags = true` in your git config to always get this behavior:
git config --global push.followTags true
[](#a1)

View File

@ -0,0 +1,127 @@
END USER LICENSE AGREEMENT
The following agreement regarding RAR (and its Windows version - WinRAR)
archiver - referred to as "software" - is made between win.rar GmbH -
referred to as "licensor" - and anyone who is installing, accessing
or in any other way using the software - referred to as "user".
1. The author and holder of the copyright of the software is
Alexander L. Roshal. The licensor and as such issuer of the license
and bearer of the worldwide exclusive usage rights including the rights
to reproduce, distribute and make the software available to the public
in any form is win.rar GmbH, Marienstr. 12, 10117 Berlin, Germany.
2. The software is distributed as try before you buy. This means that
anyone may use the software during a test period of a maximum of 40 days
at no charge. Following this test period, the user must purchase
a license to continue using the software.
3. The software's trial version may be freely distributed, with exceptions
noted below, provided the distribution package is not modified in any way.
a. Nobody may distribute separate parts of the package, with the exception
of the UnRAR components, without written permission.
b. The software's unlicensed trial version may not be distributed
inside of any other software package without written permission.
The software must remain in the original unmodified installation
file for download without any barrier and conditions to the user
such as collecting fees for the download or making the download
conditional on the user giving his contact data.
c. The unmodified installation file of WinRAR must be provided pure
and unpaired. Any bundling is interdicted. In particular the use
of any install or download software which is providing any kind
of download bundles is prohibited unless granted by win.rar GmbH
in written form.
d. Hacks/cracks, keys or key generators may not be included, pointed to
or referred to by the distributor of the trial version.
e. In case of violation of the precedent conditions the allowance
lapses immediately and automatically.
4. The trial version of the software can display a registration reminder
dialog. Depending on the software version and configuration such dialog
can contain either a predefined text and links loaded locally
or a web page loaded from the internet. Such web page can contain
licensing instructions or other materials according to the licensor's
choice, including advertisement. When opening a web page, the software
transfers only those parameters which are technically required
by HTTP protocol to successfully open a web page in a browser.
5. The software is distributed "as is". No warranty of any kind is expressed
or implied. You use at your own risk. Neither the author, the licensor
nor the agents of the licensor will be liable for data loss, damages,
loss of profits or any other kind of loss while using or misusing
this software.
6. There are 2 basic types of licenses issued for the software. These are:
a. A single computer usage license. The user purchases one license to
use the software on one computer.
Home users may use their single computer usage license on all
computers and mobile devices (USB drive, external hard drive, etc.)
which are property of the license owner.
Business users require one license per computer or mobile device
on which the software is installed.
b. A multiple usage license. The user purchases a number of usage
licenses for use, by the purchaser or the purchaser's employees
on the same number of computers.
In a network (server/client) environment the user must purchase
a license copy for each separate client (workstation) on which
the software is installed, used or accessed. A separate license copy
for each client (workstation) is needed regardless of whether
the clients (workstations) will use the software simultaneously
or at different times. If for example you wish to have 9 different
clients (workstations) in your network with access to RAR,
you must purchase 9 license copies.
A user who purchased a license, is granted a non-exclusive right to use
the software on as many computers as defined by the licensing terms above
according to the number of licenses purchased, for any legal purpose.
7. There are no additional license fees, apart from the cost of the license,
associated with the creation and distribution of RAR archives,
volumes, self-extracting archives or self-extracting volumes.
Owners of a license may use their copies of the software to produce
archives and self-extracting archives and to distribute those archives
free of any additional royalties.
8. The licensed software may not be rented or leased but may be permanently
transferred, in its entirety, if the recipient agrees to the terms of
this license.
9. To buy a license, please read the file order.htm provided with
the software for details.
10. You may not use, copy, emulate, clone, rent, lease, sell, modify,
decompile, disassemble, otherwise reverse engineer, or transfer
the licensed software, or any subset of the licensed software,
except as provided for in this agreement. Any such unauthorized use
shall result in immediate and automatic termination of this license
and may result in criminal and/or civil prosecution.
Neither RAR binary code, WinRAR binary code, UnRAR source
or UnRAR binary code may be used or reverse engineered to re-create
the RAR compression algorithm, which is proprietary, without written
permission.
The software may be using components developed and/or copyrighted
by third parties. Please read "Acknowledgments" help file topic
for WinRAR or acknow.txt text file for other RAR versions for details.
11. This License Agreement is construed solely and exclusively under
German law. If you are a merchant, the courts at the registered office
of win.rar GmbH in Berlin/Germany shall have exclusive jurisdiction
for any and all disputes arising in connection with this License
Agreement or its validity.
12. Installing and using the software signifies acceptance of these terms
and conditions of the license. If you do not agree with the terms of this
license, you must remove all software files from your storage devices
and cease to use the software.

View File

@ -43,6 +43,6 @@
@property (nonatomic, strong, readonly) NSUserDefaults *userDefaults;
+ (instancetype)sharedInstance;
- (instancetype)initWithSuiteName:(NSString *)suiteName;
- (instancetype)initWithSuiteName:(NSString *)suiteName NS_DESIGNATED_INITIALIZER;
@end

View File

@ -127,8 +127,6 @@
</array>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
@ -138,11 +136,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>0.1</string>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSMinimumSystemVersion</key>

View File

@ -0,0 +1,68 @@
{
"images" : [
{
"filename" : "icon_16x16.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
"filename" : "icon_16x16@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
"filename" : "icon_32x32.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"filename" : "icon_32x32@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"filename" : "icon_128x128.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"filename" : "icon_128x128@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"filename" : "icon_256x256.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"filename" : "icon_256x256@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"filename" : "icon_512x512.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"filename" : "icon_512x512@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,58 @@
{
"images" : [
{
"idiom" : "mac",
"scale" : "1x",
"size" : "7x7"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "7x7"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "11x11"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "11x11"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "24x24"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "24x24"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "50x50"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "50x50"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "100x100"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "100x100"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

View File

@ -0,0 +1,56 @@
{
"images" : [
{
"filename" : "icon_16x16.png",
"idiom" : "universal",
"scale" : "1x",
"size" : "16x16"
},
{
"filename" : "icon_16x16@2x.png",
"idiom" : "universal",
"scale" : "2x",
"size" : "16x16"
},
{
"filename" : "icon_18x18.png",
"idiom" : "universal",
"scale" : "1x",
"size" : "18x18"
},
{
"filename" : "icon_18x18@2x.png",
"idiom" : "universal",
"scale" : "2x",
"size" : "18x18"
},
{
"filename" : "icon_24x24.png",
"idiom" : "universal",
"scale" : "1x",
"size" : "24x24"
},
{
"filename" : "icon_24x24@2x.png",
"idiom" : "universal",
"scale" : "2x",
"size" : "24x24"
},
{
"filename" : "icon_32x32.png",
"idiom" : "universal",
"scale" : "1x",
"size" : "32x32"
},
{
"filename" : "icon_32x32@2x.png",
"idiom" : "universal",
"scale" : "2x",
"size" : "32x32"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 975 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 605 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "icon - menu bar 22x22.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 B

View File

@ -9,13 +9,11 @@
/* Begin PBXBuildFile section */
256AC3DA0F4B6AC300CF3369 /* QuietUnrarAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 256AC3D90F4B6AC300CF3369 /* QuietUnrarAppDelegate.m */; };
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
D488BC6810AF437B00B3451C /* libunrar.so in Frameworks */ = {isa = PBXBuildFile; fileRef = D488BC6710AF437B00B3451C /* libunrar.so */; };
D488BCC110AF49C700B3451C /* libunrar.so in CopyFiles */ = {isa = PBXBuildFile; fileRef = D488BC6710AF437B00B3451C /* libunrar.so */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
D488BE5510B05F3800B3451C /* PasswordView.xib in Resources */ = {isa = PBXBuildFile; fileRef = D488BE5410B05F3800B3451C /* PasswordView.xib */; };
D4A49691105435BE00BE38AE /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
D4A49692105435C100BE38AE /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD58140DA1D0A300B32029 /* MainMenu.xib */; };
D4A96E2110545E9A0091ECB4 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4A96E2010545E9A0091ECB4 /* Carbon.framework */; };
E2A3B83D265EA8B900A6C0A3 /* UnrarKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E2A3B83B265EA8B800A6C0A3 /* UnrarKit.framework */; };
E2A3B83E265EA8B900A6C0A3 /* UnrarKit.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = E2A3B83B265EA8B800A6C0A3 /* UnrarKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
E2A3B83F265EA8B900A6C0A3 /* UnzipKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E2A3B83C265EA8B800A6C0A3 /* UnzipKit.framework */; };
@ -23,7 +21,6 @@
E2A3B843265F199A00A6C0A3 /* Cartfile in Resources */ = {isa = PBXBuildFile; fileRef = E2A3B842265F199A00A6C0A3 /* Cartfile */; };
E2A3B845265F1AA900A6C0A3 /* DockProgress.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E2A3B844265F1AA800A6C0A3 /* DockProgress.framework */; };
E2A3B846265F1AA900A6C0A3 /* DockProgress.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = E2A3B844265F1AA800A6C0A3 /* DockProgress.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
E2A3B848265F267900A6C0A3 /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E2A3B847265F267900A6C0A3 /* UserNotifications.framework */; };
E2A3B8862663C1FB00A6C0A3 /* PreferencesWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = E2A3B8852663C1FB00A6C0A3 /* PreferencesWindow.xib */; };
E2A3B8892663C60200A6C0A3 /* TDNPreferencesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A3B8882663C60200A6C0A3 /* TDNPreferencesWindowController.m */; };
E2A3B8902664DE8900A6C0A3 /* TDNUnarchiver.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A3B88F2664DE8900A6C0A3 /* TDNUnarchiver.m */; };
@ -36,12 +33,9 @@
E2E2F602280CFEC900C783F6 /* TDNUnarchiver.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A3B88F2664DE8900A6C0A3 /* TDNUnarchiver.m */; };
E2E2F603280CFEC900C783F6 /* QuietUnrarAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 256AC3D90F4B6AC300CF3369 /* QuietUnrarAppDelegate.m */; };
E2E2F604280CFEC900C783F6 /* TDNUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A3B8992665225A00A6C0A3 /* TDNUserDefaults.m */; };
E2E2F607280CFEC900C783F6 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
E2E2F608280CFEC900C783F6 /* DockProgress.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E2A3B844265F1AA800A6C0A3 /* DockProgress.framework */; };
E2E2F609280CFEC900C783F6 /* UnrarKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E2A3B83B265EA8B800A6C0A3 /* UnrarKit.framework */; };
E2E2F60A280CFEC900C783F6 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4A96E2010545E9A0091ECB4 /* Carbon.framework */; };
E2E2F60B280CFEC900C783F6 /* UnzipKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E2A3B83C265EA8B800A6C0A3 /* UnzipKit.framework */; };
E2E2F60C280CFEC900C783F6 /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E2A3B847265F267900A6C0A3 /* UserNotifications.framework */; };
E2E2F60E280CFEC900C783F6 /* DockProgress.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = E2A3B844265F1AA800A6C0A3 /* DockProgress.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
E2E2F60F280CFEC900C783F6 /* UnrarKit.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = E2A3B83B265EA8B800A6C0A3 /* UnrarKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
E2E2F611280CFEC900C783F6 /* UnzipKit.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = E2A3B83C265EA8B800A6C0A3 /* UnzipKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@ -50,6 +44,7 @@
E2E2F615280CFEC900C783F6 /* PreferencesWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = E2A3B8852663C1FB00A6C0A3 /* PreferencesWindow.xib */; };
E2E2F616280CFEC900C783F6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
E2E2F618280CFEC900C783F6 /* PasswordView.xib in Resources */ = {isa = PBXBuildFile; fileRef = D488BE5410B05F3800B3451C /* PasswordView.xib */; };
E2E2F64128102BB100C783F6 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E2E2F64028102BB100C783F6 /* Images.xcassets */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -91,14 +86,9 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
256AC3D80F4B6AC300CF3369 /* QuietUnrarAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QuietUnrarAppDelegate.h; sourceTree = "<group>"; };
256AC3D90F4B6AC300CF3369 /* QuietUnrarAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QuietUnrarAppDelegate.m; sourceTree = "<group>"; };
256AC3F00F4B6AF500CF3369 /* QuietUnrar_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QuietUnrar_Prefix.pch; sourceTree = "<group>"; };
29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
8D1107310486CEB800E47090 /* QuietUnrar-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "QuietUnrar-Info.plist"; sourceTree = "<group>"; };
8D1107320486CEB800E47090 /* QuietUnrar.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = QuietUnrar.app; sourceTree = BUILT_PRODUCTS_DIR; };
D488BC6710AF437B00B3451C /* libunrar.so */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libunrar.so; path = libunrar/libunrar.so; sourceTree = "<group>"; };
@ -209,14 +199,12 @@
D4A495E31054177300BE38AE /* volume.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = volume.hpp; path = libunrar/volume.hpp; sourceTree = "<group>"; };
D4A495E41054177300BE38AE /* win32acl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = win32acl.cpp; path = libunrar/win32acl.cpp; sourceTree = "<group>"; };
D4A495E51054177300BE38AE /* win32stm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = win32stm.cpp; path = libunrar/win32stm.cpp; sourceTree = "<group>"; };
D4A96E2010545E9A0091ECB4 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
E296811D24BE4BCD00974229 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
E296811E24BE4BCD00974229 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = "<group>"; };
E2A3B83B265EA8B800A6C0A3 /* UnrarKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UnrarKit.framework; path = Carthage/Build/Mac/UnrarKit.framework; sourceTree = "<group>"; };
E2A3B83C265EA8B800A6C0A3 /* UnzipKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UnzipKit.framework; path = Carthage/Build/Mac/UnzipKit.framework; sourceTree = "<group>"; };
E2A3B842265F199A00A6C0A3 /* Cartfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Cartfile; sourceTree = "<group>"; };
E2A3B844265F1AA800A6C0A3 /* DockProgress.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DockProgress.framework; path = Carthage/Build/Mac/DockProgress.framework; sourceTree = "<group>"; };
E2A3B847265F267900A6C0A3 /* UserNotifications.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotifications.framework; path = System/Library/Frameworks/UserNotifications.framework; sourceTree = SDKROOT; };
E2A3B849266009B000A6C0A3 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
E2A3B8852663C1FB00A6C0A3 /* PreferencesWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = PreferencesWindow.xib; path = Resources/PreferencesWindow.xib; sourceTree = "<group>"; };
E2A3B8872663C60200A6C0A3 /* TDNPreferencesWindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDNPreferencesWindowController.h; sourceTree = "<group>"; };
@ -229,7 +217,8 @@
E2A3B8982665225A00A6C0A3 /* TDNUserDefaults.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDNUserDefaults.h; sourceTree = "<group>"; };
E2A3B8992665225A00A6C0A3 /* TDNUserDefaults.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDNUserDefaults.m; sourceTree = "<group>"; };
E2E2F61E280CFEC900C783F6 /* QuietUnarchiver.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = QuietUnarchiver.app; sourceTree = BUILT_PRODUCTS_DIR; };
E2E2F61F280CFEC900C783F6 /* QuietUnrar copy-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "QuietUnrar copy-Info.plist"; path = "/Users/tarasis/Programming/Projects/QuietUnrar/QuietUnrar copy-Info.plist"; sourceTree = "<absolute>"; };
E2E2F61F280CFEC900C783F6 /* QuietUnarchiver-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "QuietUnarchiver-Info.plist"; path = "/Users/tarasis/Programming/Projects/QuietUnrar/QuietUnarchiver-Info.plist"; sourceTree = "<absolute>"; };
E2E2F64028102BB100C783F6 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = QuietUnarchiver/Images.xcassets; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -238,12 +227,9 @@
buildActionMask = 2147483647;
files = (
D488BC6810AF437B00B3451C /* libunrar.so in Frameworks */,
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
E2A3B845265F1AA900A6C0A3 /* DockProgress.framework in Frameworks */,
E2A3B83D265EA8B900A6C0A3 /* UnrarKit.framework in Frameworks */,
D4A96E2110545E9A0091ECB4 /* Carbon.framework in Frameworks */,
E2A3B83F265EA8B900A6C0A3 /* UnzipKit.framework in Frameworks */,
E2A3B848265F267900A6C0A3 /* UserNotifications.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -251,12 +237,9 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
E2E2F607280CFEC900C783F6 /* Cocoa.framework in Frameworks */,
E2E2F608280CFEC900C783F6 /* DockProgress.framework in Frameworks */,
E2E2F609280CFEC900C783F6 /* UnrarKit.framework in Frameworks */,
E2E2F60A280CFEC900C783F6 /* Carbon.framework in Frameworks */,
E2E2F60B280CFEC900C783F6 /* UnzipKit.framework in Frameworks */,
E2E2F60C280CFEC900C783F6 /* UserNotifications.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -279,25 +262,6 @@
name = Classes;
sourceTree = "<group>";
};
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
isa = PBXGroup;
children = (
D4A96E2010545E9A0091ECB4 /* Carbon.framework */,
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
);
name = "Linked Frameworks";
sourceTree = "<group>";
};
1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = {
isa = PBXGroup;
children = (
29B97324FDCFA39411CA2CEA /* AppKit.framework */,
13E42FB307B3F0F600E4EEF1 /* CoreData.framework */,
29B97325FDCFA39411CA2CEA /* Foundation.framework */,
);
name = "Other Frameworks";
sourceTree = "<group>";
};
19C28FACFE9D520D11CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
@ -315,7 +279,6 @@
29B97317FDCFA39411CA2CEA /* Resources */,
29B97323FDCFA39411CA2CEA /* Frameworks */,
19C28FACFE9D520D11CA2CBB /* Products */,
E2E2F61F280CFEC900C783F6 /* QuietUnrar copy-Info.plist */,
);
name = QuietUnrar;
sourceTree = "<group>";
@ -324,7 +287,6 @@
isa = PBXGroup;
children = (
D4A494191054167B00BE38AE /* libunrar */,
256AC3F00F4B6AF500CF3369 /* QuietUnrar_Prefix.pch */,
29B97316FDCFA39411CA2CEA /* main.m */,
);
name = "Other Sources";
@ -333,6 +295,8 @@
29B97317FDCFA39411CA2CEA /* Resources */ = {
isa = PBXGroup;
children = (
E2E2F64028102BB100C783F6 /* Images.xcassets */,
E2E2F61F280CFEC900C783F6 /* QuietUnarchiver-Info.plist */,
E2A3B842265F199A00A6C0A3 /* Cartfile */,
D488BE5410B05F3800B3451C /* PasswordView.xib */,
8D1107310486CEB800E47090 /* QuietUnrar-Info.plist */,
@ -347,13 +311,10 @@
29B97323FDCFA39411CA2CEA /* Frameworks */ = {
isa = PBXGroup;
children = (
E2A3B847265F267900A6C0A3 /* UserNotifications.framework */,
E2A3B844265F1AA800A6C0A3 /* DockProgress.framework */,
E2A3B83B265EA8B800A6C0A3 /* UnrarKit.framework */,
E2A3B83C265EA8B800A6C0A3 /* UnzipKit.framework */,
D488BC6710AF437B00B3451C /* libunrar.so */,
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */,
1058C7A2FEA54F0111CA2CBB /* Other Frameworks */,
);
name = Frameworks;
sourceTree = "<group>";
@ -549,7 +510,13 @@
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1200;
LastUpgradeCheck = 1330;
TargetAttributes = {
E2E2F5FB280CFEC900C783F6 = {
DevelopmentTeam = VE7YM5VVJB;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "QuietUnrar" */;
compatibilityVersion = "Xcode 3.2";
@ -591,6 +558,7 @@
E2E2F613280CFEC900C783F6 /* LICENSE.txt in Resources */,
E2E2F614280CFEC900C783F6 /* MainMenu.xib in Resources */,
E2E2F615280CFEC900C783F6 /* PreferencesWindow.xib in Resources */,
E2E2F64128102BB100C783F6 /* Images.xcassets in Resources */,
E2E2F616280CFEC900C783F6 /* InfoPlist.strings in Resources */,
E2E2F618280CFEC900C783F6 /* PasswordView.xib in Resources */,
);
@ -780,6 +748,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ENABLE_MODULES = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
@ -812,7 +781,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
ONLY_ACTIVE_ARCH = NO;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
};
name = Debug;
@ -821,6 +790,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ENABLE_MODULES = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
@ -884,10 +854,16 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.2;
DEVELOPMENT_TEAM = VE7YM5VVJB;
EXCLUDED_ARCHS = arm64;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@ -899,15 +875,16 @@
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = QuietUnrar_Prefix.pch;
GCC_PREPROCESSOR_DEFINITIONS = _UNIX;
INFOPLIST_FILE = "QuietUnrar copy-Info.plist";
INFOPLIST_FILE = "QuietUnarchiver-Info.plist";
INSTALL_PATH = "$(HOME)/Applications";
LD_DYLIB_INSTALL_NAME = "";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
MARKETING_VERSION = 2.0;
ONLY_ACTIVE_ARCH = NO;
PRODUCT_BUNDLE_IDENTIFIER = net.tarasis.mac.QuietUnarchiver;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
};
name = Debug;
};
@ -915,10 +892,16 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 0.2;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = VE7YM5VVJB;
EXCLUDED_ARCHS = arm64;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@ -928,14 +911,15 @@
);
GCC_MODEL_TUNING = G5;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = QuietUnrar_Prefix.pch;
GCC_PREPROCESSOR_DEFINITIONS = _UNIX;
INFOPLIST_FILE = "QuietUnrar copy-Info.plist";
INFOPLIST_FILE = "QuietUnarchiver-Info.plist";
INSTALL_PATH = "$(HOME)/Applications";
LD_DYLIB_INSTALL_NAME = "";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
MARKETING_VERSION = 2.0;
PRODUCT_BUNDLE_IDENTIFIER = net.tarasis.mac.QuietUnarchiver;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
};
name = Release;
};

View File

@ -6,7 +6,8 @@
// Copyright 2009 Tarasis. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@import Cocoa;
@import Carbon;
enum
{
@ -41,6 +42,6 @@ enum
- (BOOL) shouldFileBeReplaced:(NSString *) filename;
- (void) alertUserOfMissing:(const char *) volume;
- (void) hideDockIcon: (BOOL) hide;
- (NSString *) requestArchivePassword;
@property (NS_NONATOMIC_IOSONLY, readonly, copy) NSString *requestArchivePassword;
@end

View File

@ -6,9 +6,7 @@
// Copyright 2009 Tarasis. All rights reserved.
//
#import <Carbon/Carbon.h>
#import <Cocoa/Cocoa.h>
#import <UserNotifications/UserNotifications.h>
@import UserNotifications;
#import "QuietUnrarAppDelegate.h"
#import "TDNUnarchiver.h"
@ -59,6 +57,8 @@ BOOL appRunning = NO;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self->preferencesWindowController.window makeKeyAndOrderFront:self];
// temp set to YES for testing preferences
// my preference is not to have the app become front and central when run.
[NSApp activateIgnoringOtherApps:YES];
});
@ -139,7 +139,7 @@ BOOL appRunning = NO;
- (void)applicationWillBecomeActive:(NSNotification *)notification {
//no use, if app is already running when I try and openfile it is my apps bundle id
NSLog(@"%@", [[NSWorkspace sharedWorkspace] frontmostApplication].bundleIdentifier);
NSLog(@"%@", [NSWorkspace sharedWorkspace].frontmostApplication.bundleIdentifier);
}
- (BOOL)application:(id)sender openFileWithoutUI:(NSString *)filename {
@ -168,10 +168,10 @@ BOOL appRunning = NO;
NSAlert *alert = [[NSAlert alloc] init];
[alert addButtonWithTitle:@"Overwrite"];
NSButton * skipButton = [alert addButtonWithTitle:@"Skip"];
[skipButton setKeyEquivalent:@"\e"];
[alert setMessageText:[NSString stringWithFormat:@"Overwrite %@?", filename]];
[alert setInformativeText:[NSString stringWithFormat:@"The file %@ already exists. Do you wish to extract it again, overwriting the original file?", filename]];
[alert setAlertStyle:NSAlertStyleWarning];
skipButton.keyEquivalent = @"\e";
alert.messageText = [NSString stringWithFormat:@"Overwrite %@?", filename];
alert.informativeText = [NSString stringWithFormat:@"The file %@ already exists. Do you wish to extract it again, overwriting the original file?", filename];
alert.alertStyle = NSAlertStyleWarning;
if ([alert runModal] == NSAlertFirstButtonReturn) {
result = YES;
@ -185,9 +185,9 @@ BOOL appRunning = NO;
- (void) alertUserOfMissing:(const char *) volume {
NSAlert *alert = [[NSAlert alloc] init];
[alert addButtonWithTitle:@"OK"];
[alert setMessageText:[NSString stringWithFormat:@"Archive part %s is missing.", volume]];
[alert setInformativeText:@"Unable to extract all files from RAR archive as part of it is missing"];
[alert setAlertStyle:NSAlertStyleCritical];
alert.messageText = [NSString stringWithFormat:@"Archive part %s is missing.", volume];
alert.informativeText = @"Unable to extract all files from RAR archive as part of it is missing";
alert.alertStyle = NSAlertStyleCritical;
[alert runModal];
@ -202,7 +202,7 @@ BOOL appRunning = NO;
[bundle loadNibNamed:@"PasswordView" owner:self topLevelObjects: nil];
} else {
[passwordField setStringValue:@""];
passwordField.stringValue = @"";
}
NSString * password = nil;
@ -210,13 +210,13 @@ BOOL appRunning = NO;
NSAlert *alert = [[NSAlert alloc] init];
[alert addButtonWithTitle:@"OK"];
[alert addButtonWithTitle:@"Cancel"];
[alert setMessageText:@"Archive Requires a password"];
[alert setInformativeText:@"To extract the contents of this archive a password is required."];
[alert setAccessoryView:passwordView];
[alert setAlertStyle:NSAlertStyleWarning];
alert.messageText = @"Archive Requires a password";
alert.informativeText = @"To extract the contents of this archive a password is required.";
alert.accessoryView = passwordView;
alert.alertStyle = NSAlertStyleWarning;
if ([alert runModal] == NSAlertFirstButtonReturn) {
password = [passwordField stringValue];
password = passwordField.stringValue;
}
return password;
@ -241,7 +241,7 @@ BOOL appRunning = NO;
if (show) {
statusBarItem = [NSStatusBar.systemStatusBar statusItemWithLength:NSVariableStatusItemLength];
statusBarItem.button.title = @"🎫"; //RMCG change to something more appropriate
[statusBarItem setMenu:[self makeStatusBarMenu]];
statusBarItem.menu = [self makeStatusBarMenu];
} else {
[NSStatusBar.systemStatusBar removeStatusItem:statusBarItem];
}
@ -249,7 +249,7 @@ BOOL appRunning = NO;
- (NSMenu *) makeStatusBarMenu {
NSMenu * statusBarMenu = [[NSMenu alloc] init];
[statusBarMenu setTitle:@"QuietUnarchiver Menu"];
statusBarMenu.title = @"QuietUnarchiver Menu";
NSMenuItem * preferencesMenuItem = [[NSMenuItem alloc] initWithTitle:@"Show Preferences" action:@selector(showPreferencesWindow) keyEquivalent:@""];
[statusBarMenu addItem:preferencesMenuItem];

View File

@ -1,9 +0,0 @@
//
// Prefix header for all source files of the 'QuietUnrar' target in the 'QuietUnrar' project
//
#ifdef __OBJC__
#import <Cocoa/Cocoa.h>
#endif
#import "QuietUnrarAppDelegate.h"

View File

@ -3,8 +3,10 @@
Small app for quietly unarchiving rar, zip and lzma files. No windows on the screen unless there is an issue (bad CRC, requires password, missing volume)
Optionally show progress on Dock Icon or Status Bar (for larger files)
Optionally show a notification on completion (with action button to open finder in that folder)
Optionally play sound when decompression finished
Original was written in 2009 as a little thing for me, and now its getting some TLC and updates. Mostly to play with Objective-C again.
Might see if I can compile libunrar for Apple Silicon rather than having to use Rosetta.
## TO DO
@ -20,6 +22,9 @@ Original was written in 2009 as a little thing for me, and now its getting some
* about box with thanks & liecense info
* post notification on finishing
* what to do if app open and user unarchives a file? (apart from not make the preferences window front and central)
* investigate why memory keeps increasing if QuietUnarchiver is kept open but decompresses more files. Ran intruments but nothing listed as leaking or zombied.
* Compiler Warning: Lexical or Preprocessor issue "_UNIX macro redefined"
### Metal Warning
@ -28,3 +33,39 @@ Original was written in 2009 as a little thing for me, and now its getting some
2021-05-30 15:17:28.124992+0100 QuietUnrar[91513:2457432] +[MTLIOAccelDevice registerDevices]: Zero Metal services found
A new mac project doesn't report these warnings.
### Compiler Warning
/Users/tarasis/Programming/Projects/QuietUnrar/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/raros.hpp:28:11: '_UNIX' macro redefined
/Users/tarasis/Programming/Projects/QuietUnrar/TDNUnarchiver.m:12:9: In file included from /Users/tarasis/Programming/Projects/QuietUnrar/TDNUnarchiver.m:12:
/Users/tarasis/Programming/Projects/QuietUnrar/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/UnrarKit.h:18:9: In file included from /Users/tarasis/Programming/Projects/QuietUnrar/Carthage/Build/Mac/UnrarKit.framework/Headers/UnrarKit.h:18:
/Users/tarasis/Programming/Projects/QuietUnrar/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/URKArchive.h:12:9: In file included from /Users/tarasis/Programming/Projects/QuietUnrar/Carthage/Build/Mac/UnrarKit.framework/Headers/URKArchive.h:12:
## Libraries I'm using or intend to use
* RAR either ...
* UnrarKit - https://github.com/abbeycode/UnrarKit
* libunrar -
* ZIP - either ...
* UnzipKit - https://github.com/abbeycode/UnzipKit
* SSZipArchive - https://github.com/ZipArchive/ZipArchive
* ZipZap - https://github.com/pixelglow/ZipZap
* 7Z - either ...
* un7z - https://github.com/isRyven/un7z
* SevenZip - https://github.com/lvsti/SevenZip
* LzmaSDKObjC - https://github.com/OlehKulykov/LzmaSDKObjC
* PlzmaSDK - https://github.com/OlehKulykov/PLzmaSDK
* DockProgress - https://github.com/sindresorhus/DockProgress (need to check out the whole Swift / Objective-C briding thing, don't remember any of that now)
* FSUserDefaults - https://github.com/cfloisand/FSUserDefaults (gist at https://gist.github.com/cfloisand/ba9eb5b661a7dda494bb45f28cdb7e0a and https://christianfloisand.wordpress.com/2018/03/25/improving-userdefaults-in-swift-with-key-value-observing/)
## Other things
In the off chance I forget how to readd / redo a pre-compiled header (I shouldn't but 🤷‍♂️) https://stackoverflow.com/questions/24158648/why-isnt-projectname-prefix-pch-created-automatically-in-xcode-6
```
1) Add new PCH file to the project: New file > Other > PCH file.
2) At the Target's Build Settings option, set the value of Prefix Header to your PCH file name, with the project name as prefix (i.e. for project named TestProject and PCH file named MyPrefixHeaderFile, add the value TestProject/MyPrefixHeaderFile.pch to the plist).
TIP: You can use things like $(SRCROOT) or $(PROJECT_DIR) to get to the path of where you put the .pch in the project.
3) At the Target's Build Settings option, set the value of Precompile Prefix Header to YES
```

View File

@ -8,7 +8,8 @@
#ifndef TDNPreferencesWindowController_h
#define TDNPreferencesWindowController_h
#import <Cocoa/Cocoa.h>
@import Cocoa;
#import "QuietUnrarAppDelegate.h"
NS_ASSUME_NONNULL_BEGIN

View File

@ -24,7 +24,7 @@
@synthesize userDefaults, showNotificationsSwitch, playSoundSwitch, hideDockIconSwitch;
@synthesize quietUnrar;
- (id) init {
- (instancetype) init {
return [super initWithWindowNibName:@"PreferencesWindow"];
}
@ -34,31 +34,31 @@
userDefaults = [TDNUserDefaults sharedInstance];
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
[self.window setTitle:@"QuietUnarchiver Preferences"];
(self.window).title = @"QuietUnarchiver Preferences";
if (userDefaults.hideDock) {
[hideDockIconSwitch setState:NSControlStateValueOn];
hideDockIconSwitch.state = NSControlStateValueOn;
}
if (userDefaults.showNotification) {
[showNotificationsSwitch setState:NSControlStateValueOn];
showNotificationsSwitch.state = NSControlStateValueOn;
}
if (userDefaults.playSounds) {
[playSoundSwitch setState:NSControlStateValueOn];
playSoundSwitch.state = NSControlStateValueOn;
}
}
- (IBAction)showNotificationsSwitchToggled:(id)sender {
userDefaults.showNotification = [showNotificationsSwitch state];
userDefaults.showNotification = showNotificationsSwitch.state;
}
- (IBAction)playSoundSwitchToggled:(id)sender {
userDefaults.playSounds = [playSoundSwitch state];
userDefaults.playSounds = playSoundSwitch.state;
}
- (IBAction)hideDockIconSwitchToggled:(id)sender {
userDefaults.hideDock = [hideDockIconSwitch state];
userDefaults.hideDock = hideDockIconSwitch.state;
[quietUnrar hideDockIcon: userDefaults.hideDock];
}

View File

@ -8,6 +8,8 @@
#ifndef Unarchiver_h
#define Unarchiver_h
#import "QuietUnrarAppDelegate.h"
@interface TDNUnarchiver : NSObject
@property QuietUnrarAppDelegate * quietUnrar;

View File

@ -5,19 +5,18 @@
// Created by Robert McGovern on 2021/05/31.
//
#import <Foundation/Foundation.h>
@import Foundation;
#import <wchar.h>
#import "TDNUnarchiver.h"
#import "QuietUnrarAppDelegate.h"
#import <UnrarKit/UnrarKit.h>
@import UnrarKit;
//#import <UnrarKit/UnrarKit.h>
#import "libunrar/dll.hpp"
#import "libunrar/rardefs.hpp"
#import <wchar.h>
//@interface TDNUnarchiver ()
//
//@end
@interface TDNUnarchiver ()
@end;
@implementation TDNUnarchiver
@ -117,7 +116,7 @@ int CALLBACK generalCallbackFunction(UINT message, LPARAM userData, LPARAM param
//Determine the folder we should extract the archive to. This by default
//is the <folderContainingTheArchive>/<archiveNameWithPathExtension>
NSString * folderToExtractTo = [filename stringByDeletingPathExtension];
NSString * folderToExtractTo = filename.stringByDeletingPathExtension;
// Open the Archive for extraction, we set the open result to 3 so we can see it has changed
char * filenameCString = (char *)[filename cStringUsingEncoding:NSISOLatin1StringEncoding];
@ -203,7 +202,7 @@ int CALLBACK generalCallbackFunction(UINT message, LPARAM userData, LPARAM param
}
}
NSString * folderToExtractTo = [filename stringByDeletingPathExtension];
NSString * folderToExtractTo = filename.stringByDeletingPathExtension;
BOOL extractFilesSuccessful = [archive extractFilesTo: folderToExtractTo
overwrite:NO

View File

@ -5,7 +5,6 @@
// Created by Robert McGovern on 2021/05/31.
//
#import <Foundation/Foundation.h>
#import "FSUserDefaults.h"
NS_ASSUME_NONNULL_BEGIN

View File

@ -463,7 +463,7 @@ void PASCAL RARSetPassword(HANDLE hArcData,char *Password)
}
int PASCAL RARGetDllVersion()
int PASCAL RARGetDllVersion(void)
{
return RAR_DLL_VERSION;
}

View File

@ -178,7 +178,7 @@ void PASCAL RARSetCallback(HANDLE hArcData,UNRARCALLBACK Callback,LPARAM UserD
void PASCAL RARSetChangeVolProc(HANDLE hArcData,CHANGEVOLPROC ChangeVolProc);
void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataProc);
void PASCAL RARSetPassword(HANDLE hArcData,char *Password);
int PASCAL RARGetDllVersion();
int PASCAL RARGetDllVersion(void);
#ifdef __cplusplus
}

2
main.m
View File

@ -6,7 +6,7 @@
// Copyright 2009 Tarasis. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@import Cocoa;
int main(int argc, const char * argv[]) {
@autoreleasepool {