diff --git a/stepmania/PBProject/Patcher/CopyFiles.h b/stepmania/PBProject/Patcher/CopyFiles.h new file mode 100644 index 0000000000..79b11dd728 --- /dev/null +++ b/stepmania/PBProject/Patcher/CopyFiles.h @@ -0,0 +1,30 @@ +#import + +BOOL NeedsPrivs( NSString *path ); +NSString *CopyWithPrivs( NSString *src, NSString *dest ); +NSString *Copy( NSString *src, NSString *dest ); + +/* + * (c) 2006 Steve Checkoway + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/stepmania/PBProject/Patcher/CopyFiles.m b/stepmania/PBProject/Patcher/CopyFiles.m new file mode 100644 index 0000000000..356b36bd47 --- /dev/null +++ b/stepmania/PBProject/Patcher/CopyFiles.m @@ -0,0 +1,163 @@ +#import "CopyFiles.h" +#include +#include +#include +#include +#include +#include +#include + +static NSString *COPY_FAILED; +static NSString *EXECUTE_FAILED; +static NSString *AUTH_FAILED; + +static void LoadStrings() +{ + static bool bLoaded = false; + if( bLoaded ) + return; + COPY_FAILED = NSLocalizedString( @"Copy failed.", nil ); + EXECUTE_FAILED = NSLocalizedString( @"Execute failed.", nil ); + AUTH_FAILED = NSLocalizedString( @"Authentication failed. File not patched.", nil ); + bLoaded = true; +} + +static BOOL CheckDir( const char *path ) +{ + DIR *dir = opendir( path ); + int fd = dirfd( dir ); + struct dirent entry, *ep; + int err; + + fchdir( fd ); + for( err = readdir_r(dir, &entry, &ep); ep && !err; err = readdir_r(dir, &entry, &ep) ) + { + if( !strcmp(".", entry.d_name) || !strcmp("..", entry.d_name) ) + continue; + if( access(entry.d_name, W_OK|R_OK) ) + { + closedir( dir ); + return YES; + } + if( entry.d_type == DT_DIR ) + { + if( CheckDir(entry.d_name) ) + { + closedir( dir ); + return YES; + } + fchdir( fd ); + } + } + closedir( dir ); + return err; +} + +BOOL NeedsPrivs( NSString *path ) +{ + const char *p = [path UTF8String]; + struct stat sb; + + if( stat(p, &sb) ) + return YES; + if( access(p, W_OK|R_OK) ) // I don't care to parse stat output. + return YES; + if( (sb.st_mode & S_IFDIR) && CheckDir(p) ) + return YES; + + return NO; +} + +NSString *CopyWithPrivs( NSString *src, NSString *dest ) +{ + LoadStrings(); + OSStatus error; + static AuthorizationRef authRef; + static BOOL bCreated = false; + + if( !bCreated ) + { + AuthorizationFlags flags = kAuthorizationFlagDefaults; + AuthorizationItem item = { kAuthorizationRightExecute, 0, NULL, 0 }; + AuthorizationRights rights = { 1, &item }; + + error = AuthorizationCreate( NULL, kAuthorizationEmptyEnvironment, flags, &authRef ); + + if (error != errAuthorizationSuccess) + return @"Failed to create authorization."; + + + flags = kAuthorizationFlagDefaults | + kAuthorizationFlagInteractionAllowed | + kAuthorizationFlagPreAuthorize | + kAuthorizationFlagExtendRights; + + error = AuthorizationCopyRights( authRef, &rights, NULL, flags, NULL ); + + if (error != errAuthorizationSuccess) + return AUTH_FAILED; + bCreated = YES; + } + + + // Don't pass path as the first argument. AuthorizationExecuteWithPrivileges must do it. + char path[] = "/bin/cp"; + const char *argv[] = { "-Rf", [src UTF8String], [dest UTF8String], NULL }; + NSString *result = nil; + + error = AuthorizationExecuteWithPrivileges( authRef, path, kAuthorizationFlagDefaults, (char **)argv, NULL ); + + if (error == errAuthorizationSuccess) + { + int status = 0; + pid_t pid = wait( &status ); + + if( pid == -1 ) + result = [NSString stringWithUTF8String:strerror(errno)]; + else if( !WIFEXITED(status) || WEXITSTATUS(status) ) + result = COPY_FAILED; + } + else + { + result = EXECUTE_FAILED; + } + + + return result; +} + +NSString *Copy( NSString *src, NSString *dest ) +{ + LoadStrings(); + // Again, don't pass the path. + NSArray *argv = [NSArray arrayWithObjects:@"-Rf", src, dest, nil]; + NSTask *task = [NSTask launchedTaskWithLaunchPath:@"/bin/cp" arguments:argv]; + + [task waitUntilExit]; + return [task terminationStatus] ? COPY_FAILED : nil; +} + +/* + * (c) 2006 Steve Checkoway + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/stepmania/PBProject/Patcher/Identification.txt b/stepmania/PBProject/Patcher/Identification.txt new file mode 100644 index 0000000000..6b0ede8d25 --- /dev/null +++ b/stepmania/PBProject/Patcher/Identification.txt @@ -0,0 +1,11 @@ +# The format of this file is: +# Application name +# Bundle ID +# version1 +# version2 +# ... +# The version key -ALL- or no version keys matches all versions. + +StepMania +com.StepMania +-ALL- diff --git a/stepmania/PBProject/Patcher/Info.plist b/stepmania/PBProject/Patcher/Info.plist new file mode 100644 index 0000000000..c80d835021 --- /dev/null +++ b/stepmania/PBProject/Patcher/Info.plist @@ -0,0 +1,28 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + smicon + CFBundleIdentifier + com.StepMania.Patcher + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleSignature + ITGp + CFBundleVersion + 1.0 + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/stepmania/PBProject/Patcher/Patcher.xcodeproj/project.pbxproj b/stepmania/PBProject/Patcher/Patcher.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..fe9714d1a1 --- /dev/null +++ b/stepmania/PBProject/Patcher/Patcher.xcodeproj/project.pbxproj @@ -0,0 +1,337 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 42; + objects = { + +/* Begin PBXBuildFile section */ + 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; + 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; + AA2BF5C30A4F6E1B00A21643 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = AA2BF5C10A4F6E1B00A21643 /* Localizable.strings */; }; + AAD7D8740A36C53E0073BAC6 /* Identification.txt in Resources */ = {isa = PBXBuildFile; fileRef = AAD7D8730A36C53E0073BAC6 /* Identification.txt */; }; + AAD7D8BF0A36CC020073BAC6 /* smicon.icns in Resources */ = {isa = PBXBuildFile; fileRef = AAD7D8BE0A36CC020073BAC6 /* smicon.icns */; }; + AAF586BC0A27D9300046D33E /* CopyFiles.m in Sources */ = {isa = PBXBuildFile; fileRef = AAF586BB0A27D9300046D33E /* CopyFiles.m */; }; + AAF586BF0A27D9410046D33E /* Upgrader.m in Sources */ = {isa = PBXBuildFile; fileRef = AAF586BE0A27D9410046D33E /* Upgrader.m */; }; + AAF586CC0A27DA7F0046D33E /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = AAF586CA0A27DA7F0046D33E /* MainMenu.nib */; }; + AAF586CF0A27DA900046D33E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = AAF586CD0A27DA900046D33E /* InfoPlist.strings */; }; + AAF587560A2826240046D33E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AAF587550A2826240046D33E /* Security.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; + 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; + 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; + 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + 32CA4F630368D1EE00C91783 /* Patcher_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Patcher_Prefix.pch; sourceTree = ""; }; + 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 8D1107320486CEB800E47090 /* Patcher.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Patcher.app; sourceTree = BUILT_PRODUCTS_DIR; }; + AA2BF5C20A4F6E1B00A21643 /* en */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; + AAD7D8730A36C53E0073BAC6 /* Identification.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Identification.txt; sourceTree = ""; }; + AAD7D8BE0A36CC020073BAC6 /* smicon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = smicon.icns; path = ../smicon.icns; sourceTree = SOURCE_ROOT; }; + AAF586BA0A27D9300046D33E /* CopyFiles.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; path = CopyFiles.h; sourceTree = ""; }; + AAF586BB0A27D9300046D33E /* CopyFiles.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = CopyFiles.m; sourceTree = ""; }; + AAF586BD0A27D9410046D33E /* Upgrader.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Upgrader.h; sourceTree = ""; }; + AAF586BE0A27D9410046D33E /* Upgrader.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = Upgrader.m; sourceTree = ""; }; + AAF586CB0A27DA7F0046D33E /* en */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = en; path = en.lproj/MainMenu.nib; sourceTree = ""; }; + AAF586CE0A27DA900046D33E /* en */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + AAF587550A2826240046D33E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8D11072E0486CEB800E47090 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, + AAF587560A2826240046D33E /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 080E96DDFE201D6D7F000001 /* Classes */ = { + isa = PBXGroup; + children = ( + AAF586BD0A27D9410046D33E /* Upgrader.h */, + AAF586BE0A27D9410046D33E /* Upgrader.m */, + ); + name = Classes; + sourceTree = ""; + }; + 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { + isa = PBXGroup; + children = ( + 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, + ); + name = "Linked Frameworks"; + sourceTree = ""; + }; + 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + 29B97324FDCFA39411CA2CEA /* AppKit.framework */, + 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */, + 29B97325FDCFA39411CA2CEA /* Foundation.framework */, + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8D1107320486CEB800E47090 /* Patcher.app */, + ); + name = Products; + sourceTree = ""; + }; + 29B97314FDCFA39411CA2CEA /* Patcher */ = { + isa = PBXGroup; + children = ( + 080E96DDFE201D6D7F000001 /* Classes */, + 29B97315FDCFA39411CA2CEA /* Other Sources */, + 29B97317FDCFA39411CA2CEA /* Resources */, + 29B97323FDCFA39411CA2CEA /* Frameworks */, + 19C28FACFE9D520D11CA2CBB /* Products */, + ); + name = Patcher; + sourceTree = ""; + }; + 29B97315FDCFA39411CA2CEA /* Other Sources */ = { + isa = PBXGroup; + children = ( + AAF586BA0A27D9300046D33E /* CopyFiles.h */, + AAF586BB0A27D9300046D33E /* CopyFiles.m */, + 32CA4F630368D1EE00C91783 /* Patcher_Prefix.pch */, + 29B97316FDCFA39411CA2CEA /* main.m */, + ); + name = "Other Sources"; + sourceTree = ""; + }; + 29B97317FDCFA39411CA2CEA /* Resources */ = { + isa = PBXGroup; + children = ( + AA2BF5C10A4F6E1B00A21643 /* Localizable.strings */, + AAD7D8BE0A36CC020073BAC6 /* smicon.icns */, + AAD7D8730A36C53E0073BAC6 /* Identification.txt */, + 8D1107310486CEB800E47090 /* Info.plist */, + AAF586CD0A27DA900046D33E /* InfoPlist.strings */, + AAF586CA0A27DA7F0046D33E /* MainMenu.nib */, + ); + name = Resources; + sourceTree = ""; + }; + 29B97323FDCFA39411CA2CEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + AAF587550A2826240046D33E /* Security.framework */, + 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, + 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8D1107260486CEB800E47090 /* Patcher */ = { + isa = PBXNativeTarget; + buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Patcher" */; + buildPhases = ( + 8D1107290486CEB800E47090 /* Resources */, + 8D11072C0486CEB800E47090 /* Sources */, + 8D11072E0486CEB800E47090 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Patcher; + productInstallPath = "$(HOME)/Applications"; + productName = Patcher; + productReference = 8D1107320486CEB800E47090 /* Patcher.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + isa = PBXProject; + buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Patcher" */; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + en, + ); + mainGroup = 29B97314FDCFA39411CA2CEA /* Patcher */; + projectDirPath = ""; + targets = ( + 8D1107260486CEB800E47090 /* Patcher */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D1107290486CEB800E47090 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + AAF586CC0A27DA7F0046D33E /* MainMenu.nib in Resources */, + AAF586CF0A27DA900046D33E /* InfoPlist.strings in Resources */, + AAD7D8740A36C53E0073BAC6 /* Identification.txt in Resources */, + AAD7D8BF0A36CC020073BAC6 /* smicon.icns in Resources */, + AA2BF5C30A4F6E1B00A21643 /* Localizable.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8D11072C0486CEB800E47090 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D11072D0486CEB800E47090 /* main.m in Sources */, + AAF586BC0A27D9300046D33E /* CopyFiles.m in Sources */, + AAF586BF0A27D9410046D33E /* Upgrader.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + AA2BF5C10A4F6E1B00A21643 /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + AA2BF5C20A4F6E1B00A21643 /* en */, + ); + name = Localizable.strings; + sourceTree = SOURCE_ROOT; + }; + AAF586CA0A27DA7F0046D33E /* MainMenu.nib */ = { + isa = PBXVariantGroup; + children = ( + AAF586CB0A27DA7F0046D33E /* en */, + ); + name = MainMenu.nib; + sourceTree = ""; + }; + AAF586CD0A27DA900046D33E /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + AAF586CE0A27DA900046D33E /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + C01FCF4B08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_CPP_EXCEPTIONS = NO; + GCC_ENABLE_CPP_RTTI = NO; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_MODEL_TUNING = G4; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Applications"; + PRODUCT_NAME = Patcher; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + C01FCF4C08A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = ( + ppc, + i386, + ); + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_CPP_EXCEPTIONS = NO; + GCC_ENABLE_CPP_RTTI = NO; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_MODEL_TUNING = G4; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Applications"; + PRODUCT_NAME = Patcher; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; + C01FCF4F08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/.."; + GCC_VERSION = 3.3; + GCC_VERSION_i386 = 4.0; + GCC_VERSION_ppc = 3.3; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET_i386 = 10.4; + MACOSX_DEPLOYMENT_TARGET_ppc = 10.2; + PREBINDING = NO; + SDKROOT = /Developer/SDKs/MacOSX10.2.8.sdk; + SDKROOT_i386 = /Developer/SDKs/MacOSX10.4u.sdk; + SDKROOT_ppc = /Developer/SDKs/MacOSX10.2.8.sdk; + ZERO_LINK = NO; + }; + name = Debug; + }; + C01FCF5008A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/.."; + GCC_VERSION = 3.3; + GCC_VERSION_i386 = 4.0; + GCC_VERSION_ppc = 3.3; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET_i386 = 10.4; + MACOSX_DEPLOYMENT_TARGET_ppc = 10.2; + PREBINDING = NO; + SDKROOT = /Developer/SDKs/MacOSX10.2.8.sdk; + SDKROOT_i386 = /Developer/SDKs/MacOSX10.4u.sdk; + SDKROOT_ppc = /Developer/SDKs/MacOSX10.2.8.sdk; + ZERO_LINK = NO; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Patcher" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4B08A954540054247B /* Debug */, + C01FCF4C08A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Patcher" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4F08A954540054247B /* Debug */, + C01FCF5008A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; +} diff --git a/stepmania/PBProject/Patcher/Patcher_Prefix.pch b/stepmania/PBProject/Patcher/Patcher_Prefix.pch new file mode 100644 index 0000000000..59fd7194f0 --- /dev/null +++ b/stepmania/PBProject/Patcher/Patcher_Prefix.pch @@ -0,0 +1,28 @@ +#ifdef __OBJC__ + #import +#endif + +/* + * (c) 2006 Steve Checkoway + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/stepmania/PBProject/Patcher/Upgrader.h b/stepmania/PBProject/Patcher/Upgrader.h new file mode 100644 index 0000000000..785a531d16 --- /dev/null +++ b/stepmania/PBProject/Patcher/Upgrader.h @@ -0,0 +1,56 @@ +/* Upgrader */ + +#import + +@interface Upgrader : NSObject +{ + IBOutlet NSButton *m_Choose; + IBOutlet NSButton *m_Okay; + IBOutlet NSPanel *m_Panel; + IBOutlet NSProgressIndicator *m_ProgressBar; + IBOutlet NSProgressIndicator *m_Searching; + IBOutlet NSTextField *m_StatusText; + IBOutlet NSTextField *m_SelectionText; + IBOutlet NSTextField *m_PatchingText; + IBOutlet NSWindow *m_Window; + NSString *m_sAppID; + NSArray *m_vVersions; + NSString *m_sName; + NSString *m_sError; + NSString *m_sPath; +} +- (IBAction) chooseFile:(id)sender; +- (IBAction) upgrade:(id)sender; +- (void) findApp:(id)obj; +- (void) foundApp:(id)obj; +- (void) upgradeFile:(id)path; +- (void) sheetEnded:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo; +- (BOOL) panel:(id)sender isValidFilename:(NSString *)filename; +- (BOOL) panel:(id)sender shouldShowFilename:(NSString *)filename; +- (BOOL) checkPath:(NSString *)path; +@end + +/* + * (c) 2006 Steve Checkoway + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/stepmania/PBProject/Patcher/Upgrader.m b/stepmania/PBProject/Patcher/Upgrader.m new file mode 100644 index 0000000000..7d8fcecaec --- /dev/null +++ b/stepmania/PBProject/Patcher/Upgrader.m @@ -0,0 +1,364 @@ +#import "Upgrader.h" +#import "CopyFiles.h" +#include +#include +#include + +@implementation Upgrader + +// Generate English strings using: genstring -o en.lproj Upgrader.m + +static NSString *CHOOSE_FILE; +static NSString *PATCH_FILE; +static NSString *PATCH_COMPLETE; +static NSString *QUIT; +static NSString *ERROR; +static NSString *ERROR_MESSAGE; +static NSString *PATCH_FILES_MISSING; +static NSString *PATCHER_CORRUPTED; +static NSString *CORRUPT_TITLE; +static NSString *PATCHING; +static NSString *SEARCHING; +static NSString *SELECTION; +static NSString *WINDOW_TITLE; + +static NSOpenPanel *panel = nil; + +- (void)awakeFromNib +{ + NSString *path = [[NSBundle mainBundle] pathForResource:@"Identification" ofType:@"txt"]; + NSData *data = [NSData dataWithContentsOfFile:path]; + NSString *stringData = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; + + CHOOSE_FILE = NSLocalizedString( @"Choose file to patch.", nil ); + PATCH_FILE = NSLocalizedString( @"Patch file.", nil ); + PATCH_COMPLETE = NSLocalizedString( @"Patch complete.", nil ); + QUIT = NSLocalizedString( @"Quit", nil ); + ERROR = NSLocalizedString( @"Error", nil ); + ERROR_MESSAGE = NSLocalizedString( @"Patching failed:\n%@", nil ); + PATCH_FILES_MISSING = NSLocalizedString( @"Patch files missing.", nil ); + PATCHER_CORRUPTED = NSLocalizedString( @"This patcher has become corrupted.", nil ); + CORRUPT_TITLE = NSLocalizedString( @"Corrupt Patcher", nil ); + PATCHING = NSLocalizedString( @"Patching", nil ); + SEARCHING = NSLocalizedString( @"Searching for %@...", nil ); + SELECTION = NSLocalizedString( @"You have chosen to patch \"%@\" in the folder:\n%@", nil ); + WINDOW_TITLE = NSLocalizedString( @"StepMania Patcher", nil ); + + if( !data ) + { + NSRunCriticalAlertPanel( CORRUPT_TITLE, PATCHER_CORRUPTED, @"OK", nil, nil ); + [NSApp terminate:self]; + } + + m_sName = nil; + m_sAppID = nil; + m_vVersions = nil; + + NSArray *lines = [stringData componentsSeparatedByString:@"\n"]; + NSEnumerator *iter = [lines objectEnumerator]; + NSString *line; + NSMutableArray *versions = [NSMutableArray array]; + + while( (line = [iter nextObject]) ) + { + line = [line stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if( [line length] == 0 || [line characterAtIndex:0] == '#' ) + continue; + if( m_sName == nil ) + { + m_sName = [line retain]; + } + else if( m_sAppID == nil ) + { + m_sAppID = [line retain]; + } + else if( [line isEqualToString:@"-ALL-"] ) + { + versions = nil; + break; + } + else + { + [versions addObject:line]; + } + } + + if( !m_sName || !m_sAppID ) + { + NSRunCriticalAlertPanel( CORRUPT_TITLE, PATCHER_CORRUPTED, @"OK", nil, nil ); + [NSApp terminate:self]; + } + + if( versions && [versions count] ) + m_vVersions = [versions retain]; + + // Set strings. + [m_StatusText setStringValue:[NSString stringWithFormat:SEARCHING, m_sName]]; + [m_SelectionText setStringValue:@""]; + [m_PatchingText setStringValue:PATCHING]; + + [m_Searching setUsesThreadedAnimation:YES]; + [m_ProgressBar setUsesThreadedAnimation:YES]; + [m_Window setTitle:WINDOW_TITLE]; + + [NSThread detachNewThreadSelector:@selector(findApp:) toTarget:self withObject:nil]; + [m_Choose setEnabled:YES]; +} + +- (void) dealloc +{ + [m_sName release]; + [m_sAppID release]; + [m_vVersions release]; + [super dealloc]; +} + +- (IBAction) chooseFile:(id)sender +{ + if( !panel ) + { + panel = [[NSOpenPanel openPanel] retain]; + [panel setCanChooseDirectories:YES]; + [panel setAllowsMultipleSelection:NO]; + [panel setDelegate:self]; + [panel setDirectory:@"/Applications"]; + } + + if( [panel runModal] == NSFileHandlingPanelOKButton ) + { + NSString *dir, *app; + + [m_StatusText setStringValue:PATCH_FILE]; + [m_Okay setEnabled:YES]; + [m_sPath release]; + m_sPath = [[panel filename] retain]; + dir = [m_sPath stringByDeletingLastPathComponent]; + app = [[m_sPath lastPathComponent] stringByDeletingPathExtension]; + [m_SelectionText setStringValue:[NSString stringWithFormat:SELECTION, app, dir]]; + [m_Okay setTitle:@"OK"]; + [m_Okay setAction:@selector(upgrade:)]; + [m_Okay setTarget:self]; + } +} + +- (IBAction) upgrade:(id)sender +{ + [NSApp beginSheet:m_Panel + modalForWindow:[sender window] + modalDelegate:self + didEndSelector:@selector(sheetEnded:returnCode:contextInfo:) + contextInfo:NULL]; + [NSThread detachNewThreadSelector:@selector(upgradeFile:) toTarget:self withObject:m_sPath]; +} + +- (void) findApp:(id)obj +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + [m_Searching startAnimation:self]; + + // Find ITG + CFStringRef key = CFSTR( "ApplicationBundlePath" ); + CFPropertyListRef list = CFPreferencesCopyAppValue( key, (CFStringRef)m_sAppID ); + + NSString *sPath = nil; + + if( list && CFGetTypeID(list) != CFDictionaryGetTypeID() ) + { + CFRelease( list ); + list = NULL; + } + if( list ) + { + CFTypeRef value; + CFDictionaryRef dict = (CFDictionaryRef)list; + + if( m_vVersions ) + { + NSEnumerator *iter = [m_vVersions objectEnumerator]; + id version; + + while( (version = [iter nextObject]) ) + { + if( CFDictionaryGetValueIfPresent(dict, (CFStringRef)version, &value) && + CFGetTypeID(value) == CFStringGetTypeID() && + [self checkPath:(NSString *)value] ) + { + sPath = (NSString *)CFRetain( value ); + [sPath autorelease]; + } + } + } + else + { + NSDictionary *dict = (NSDictionary *)list; + NSEnumerator *iter = [dict objectEnumerator]; + id path; + + while( (path = [iter nextObject]) ) + { + if( ![path isKindOfClass:[NSString class]] || ![self checkPath:path] ) + continue; + sPath = [[path retain] autorelease]; + break; + } + } + CFRelease( list ); + } + if( !sPath ) + { + NSWorkspace *ws = [NSWorkspace sharedWorkspace]; + + [ws findApplications]; + sPath = [ws fullPathForApplication:m_sName]; + + if( ![self checkPath:sPath] ) + sPath = nil; + } + [self performSelectorOnMainThread:@selector(foundApp:) withObject:sPath waitUntilDone:YES]; + [m_Searching stopAnimation:self]; + [pool release]; +} + +- (void) foundApp:(id)obj +{ + NSString *path = (NSString *)obj; + + if( path ) // found + { + NSString *dir = [path stringByDeletingLastPathComponent]; + NSString *app = [[path lastPathComponent] stringByDeletingPathExtension]; + + [m_sPath release]; + m_sPath = [path retain]; + [m_Okay setEnabled:YES]; + [m_StatusText setStringValue:PATCH_FILE]; + [m_SelectionText setStringValue:[NSString stringWithFormat:SELECTION, app, dir]]; + } + else + { + m_sPath = @""; + [m_StatusText setStringValue:CHOOSE_FILE]; + } + [m_Choose setEnabled:YES]; + [m_Choose setNeedsDisplay:YES]; + [m_Okay setNeedsDisplay:YES]; + [m_StatusText setNeedsDisplay:YES]; + [m_SelectionText setNeedsDisplay:YES]; +} + +- (void) upgradeFile:(id)path +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSBundle *bundle = [NSBundle mainBundle]; + NSString *patch = [bundle pathForResource:@"Contents" ofType:@"" inDirectory:@"Patch"]; + NSArray *parentFiles = [bundle pathsForResourcesOfType:@"" inDirectory:@"Patch/ParentContents"]; + + if( patch && parentFiles) + { + [m_ProgressBar startAnimation:self]; + + if( NeedsPrivs(path) ) + m_sError = CopyWithPrivs( patch, path ); + else + m_sError = Copy( patch, path ); + + path = [path stringByDeletingLastPathComponent]; + NSEnumerator *enumerator = [parentFiles objectEnumerator]; + while( !m_sError && (patch = [enumerator nextObject]) ) + { + if( NeedsPrivs(path) ) + m_sError = CopyWithPrivs( patch, path ); + else + m_sError = Copy( patch, path ); + } + + [m_ProgressBar stopAnimation:self]; + } + else + { + m_sError = PATCH_FILES_MISSING; + } + [NSApp performSelectorOnMainThread:@selector(endSheet:) withObject:m_Panel waitUntilDone:YES]; + [pool release]; +} + +- (void) sheetEnded:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo +{ + [m_Panel orderOut:self]; + if( m_sError ) + { + NSRunCriticalAlertPanel( ERROR, ERROR_MESSAGE, @"OK", nil, nil, m_sError ); + return; + } + [m_StatusText setStringValue:PATCH_COMPLETE]; + [m_Okay setTitle:QUIT]; + [m_Okay setAction:@selector(terminate:)]; + [m_Okay setTarget:NSApp]; +} + +- (BOOL) panel:(id)sender isValidFilename:(NSString *)filename +{ + return [filename hasSuffix:@".app"] && [self checkPath:filename]; +} + +- (BOOL) panel:(id)sender shouldShowFilename:(NSString *)filename +{ + if( [filename hasSuffix:@".app"] ) + return [self checkPath:filename]; + + struct stat sb; + + if( stat([filename UTF8String], &sb) ) + return NO; + return (sb.st_mode & S_IFDIR) == S_IFDIR; +} + +- (BOOL) checkPath:(NSString *)path +{ + NSBundle *b = [NSBundle bundleWithPath:path]; + + if( !b ) + return NO; + if( ![[b objectForInfoDictionaryKey:@"CFBundleIdentifier"] isEqualToString:m_sAppID] ) + return NO; + if( m_vVersions == nil ) + return YES; + + NSString *bundleVersion = [b objectForInfoDictionaryKey:@"CFBundleVersion"]; + NSEnumerator *iter = [m_vVersions objectEnumerator]; + NSString *version; + + while( (version = [iter nextObject]) ) + if( [bundleVersion isEqualToString:version] ) + return YES; + return NO; +} + +@end + +/* + * (c) 2006 Steve Checkoway + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + diff --git a/stepmania/PBProject/Patcher/en.lproj/InfoPlist.strings b/stepmania/PBProject/Patcher/en.lproj/InfoPlist.strings new file mode 100644 index 0000000000..4e6d64404c Binary files /dev/null and b/stepmania/PBProject/Patcher/en.lproj/InfoPlist.strings differ diff --git a/stepmania/PBProject/Patcher/en.lproj/Localizable.strings b/stepmania/PBProject/Patcher/en.lproj/Localizable.strings new file mode 100644 index 0000000000..a00d916b31 Binary files /dev/null and b/stepmania/PBProject/Patcher/en.lproj/Localizable.strings differ diff --git a/stepmania/PBProject/Patcher/en.lproj/MainMenu.nib/classes.nib b/stepmania/PBProject/Patcher/en.lproj/MainMenu.nib/classes.nib new file mode 100644 index 0000000000..78453481bf --- /dev/null +++ b/stepmania/PBProject/Patcher/en.lproj/MainMenu.nib/classes.nib @@ -0,0 +1,23 @@ +{ + IBClasses = ( + {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + { + ACTIONS = {chooseFile = id; upgrade = id; }; + CLASS = Upgrader; + LANGUAGE = ObjC; + OUTLETS = { + "m_Choose" = NSButton; + "m_Okay" = NSButton; + "m_Panel" = NSPanel; + "m_PatchingText" = NSTextField; + "m_ProgressBar" = NSProgressIndicator; + "m_Searching" = NSProgressIndicator; + "m_SelectionText" = NSTextField; + "m_StatusText" = NSTextField; + "m_Window" = NSWindow; + }; + SUPERCLASS = NSObject; + } + ); + IBVersion = 1; +} \ No newline at end of file diff --git a/stepmania/PBProject/Patcher/en.lproj/MainMenu.nib/info.nib b/stepmania/PBProject/Patcher/en.lproj/MainMenu.nib/info.nib new file mode 100644 index 0000000000..7e364a0c29 --- /dev/null +++ b/stepmania/PBProject/Patcher/en.lproj/MainMenu.nib/info.nib @@ -0,0 +1,34 @@ + + + + + IBDocumentLocation + 39 98 356 240 0 0 1920 1178 + IBEditorPositions + + 29 + 207 529 151 44 0 0 1920 1178 + + IBFramework Version + 446.1 + IBOpenObjects + + 29 + 217 + + IBSystem Version + 8J135 + IBUserGuides + + 21 + + guideLocations + + Horizontal:180.000000 + + guidesLocked + + + + + diff --git a/stepmania/PBProject/Patcher/en.lproj/MainMenu.nib/keyedobjects.nib b/stepmania/PBProject/Patcher/en.lproj/MainMenu.nib/keyedobjects.nib new file mode 100644 index 0000000000..e8c4bb6372 Binary files /dev/null and b/stepmania/PBProject/Patcher/en.lproj/MainMenu.nib/keyedobjects.nib differ diff --git a/stepmania/PBProject/Patcher/main.m b/stepmania/PBProject/Patcher/main.m new file mode 100644 index 0000000000..692105e5d2 --- /dev/null +++ b/stepmania/PBProject/Patcher/main.m @@ -0,0 +1,29 @@ +int main( int argc, const char *argv[] ) +{ + return NSApplicationMain( argc, argv ); +} + +/* + * (c) 2006 Steve Checkoway + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */