diff --git a/Frameworks/CoreFoundation/CFArray.mm b/Frameworks/CoreFoundation/CFArray.mm index 2a360661bc..543ae87b0f 100644 --- a/Frameworks/CoreFoundation/CFArray.mm +++ b/Frameworks/CoreFoundation/CFArray.mm @@ -432,6 +432,13 @@ void CFArrayInsertValueAtIndex(CFMutableArrayRef array, CFIndex index, const voi _LazyArrOffset.member(array)->addObjectAtIndex((id)value, index); } +/** + @Status Interoperable +*/ +void CFArraySetValueAtIndex(CFMutableArrayRef self,CFIndex index,const void *value) { + _LazyArrOffset.member(self)->replaceObject((id)value, index); +} + /** @Status Interoperable */ diff --git a/Frameworks/Foundation/NSAssertionHandler.mm b/Frameworks/Foundation/NSAssertionHandler.mm index 1d8c0ce708..0aee3cfada 100644 --- a/Frameworks/Foundation/NSAssertionHandler.mm +++ b/Frameworks/Foundation/NSAssertionHandler.mm @@ -14,7 +14,56 @@ // //****************************************************************************** -#import +#include "Starboard.h" +#import +#import +#import +#import + +const NSString* NSAssertionHandlerKey = @"NSAssertionHandlerKey"; @implementation NSAssertionHandler -@end + ++ (NSAssertionHandler*)currentHandler { + id currentHandlerForThread = [[[NSThread currentThread] threadDictionary] objectForKey:NSAssertionHandlerKey]; + + if (currentHandlerForThread == nil) { + if ((currentHandlerForThread = [[[self alloc] init] autorelease]) != nil) { + [[[NSThread currentThread] threadDictionary] setObject:currentHandlerForThread forKey:NSAssertionHandlerKey]; + } + } + + return currentHandlerForThread; +} + +- (void)handleFailureInMethod:(SEL)selector + object:(id)object + file:(NSString*)fileName + lineNumber:(NSInteger)line + description:(NSString*)format, ... { + NSLog(@"*** Assertion failure in %c[%@ %@], %@:%ld", + (object == [object class]) ? '+' : '-', + NSStringFromClass([object class]), + NSStringFromSelector(selector), + fileName, + (long)line); + + va_list arguments; + va_start(arguments, format); + [NSException raise:NSInternalInconsistencyException format:format arguments:arguments]; + va_end(arguments); +} + +- (void)handleFailureInFunction:(NSString*)functionName + file:(NSString*)fileName + lineNumber:(NSInteger)line + description:(NSString*)format, ... { + NSLog(@"*** Assertion failure in %@, %@:%ld", functionName, fileName, (long)line); + + va_list arguments; + va_start(arguments, format); + [NSException raise:NSInternalInconsistencyException format:format arguments:arguments]; + va_end(arguments); +} + +@end \ No newline at end of file diff --git a/Frameworks/Foundation/NSBundle.mm b/Frameworks/Foundation/NSBundle.mm index 1570decab5..7459fb337f 100644 --- a/Frameworks/Foundation/NSBundle.mm +++ b/Frameworks/Foundation/NSBundle.mm @@ -667,8 +667,6 @@ + (NSBundle*)bundleWithPath:(NSString*)path { } + (NSBundle*)bundleWithURL:(NSURL*)url { - EbrDebugLog("bundleWithURL: %s\n", [[url absoluteString] UTF8String]); - if ([url isFileURL]) { return [[self alloc] initWithPath:[url path]]; } else { @@ -678,6 +676,18 @@ + (NSBundle*)bundleWithURL:(NSURL*)url { } } +/** + @Status Interoperable +*/ +- (instancetype)initWithUrl:(NSURL*)url { + if ([url isFileURL]) { + return [self initwithPath:[url path]]; + } + + EbrDebugLog("bad URL\n"); + return nil; +} + /** @Status Interoperable */ diff --git a/Frameworks/Foundation/NSCondition.mm b/Frameworks/Foundation/NSCondition.mm index e1f54adb2b..0ce9e2373d 100644 --- a/Frameworks/Foundation/NSCondition.mm +++ b/Frameworks/Foundation/NSCondition.mm @@ -205,9 +205,6 @@ - (BOOL)tryLock { return pthread_mutex_trylock(&_mutex) == 0; } -/** - @Status Interoperable -*/ - (void)lockWhenCondition:(NSInteger)condition { int rc; diff --git a/Frameworks/Foundation/NSDictionary.h b/Frameworks/Foundation/NSDictionary.h index bd498c5443..e816c7baae 100644 --- a/Frameworks/Foundation/NSDictionary.h +++ b/Frameworks/Foundation/NSDictionary.h @@ -17,6 +17,11 @@ #ifndef __NSDICTIONARY_H #define __NSDICTIONARY_H +typedef NS_ENUM(NSUInteger, NSEnumerationOptions) { + NSEnumerationConcurrent = 1, + NSEnumerationReverse +}; + class __CFDictionary; #define __CFDICTIONARY_SIZE_BYTES (0x54) @interface NSDictionary : NSObject { @@ -63,6 +68,7 @@ class __CFDictionary; - (NSString*)stringFromQueryComponents; - (void)getObjects:(id*)objects andKeys:(id*)keys; - (void)enumerateKeysAndObjectsUsingBlock:(id)block; +- (void)enumerateKeysAndObjectsWithOptions:(NSEnumerationOptions)options usingBlock:(void (^)(id, id, BOOL*))block; - (NSArray*)objectsForKeys:(NSArray*)keys notFoundMarker:(id)notFoundMarker; + (instancetype)dictionaryWithObjectsAndKeys:(id)firstObj, ...; + (instancetype)dictionaryWithObjects:(id*)vals forKeys:(id*)keys count:(unsigned)count; diff --git a/Frameworks/Foundation/NSDictionary.mm b/Frameworks/Foundation/NSDictionary.mm index f1eda44445..f8f8a14a0d 100644 --- a/Frameworks/Foundation/NSDictionary.mm +++ b/Frameworks/Foundation/NSDictionary.mm @@ -52,7 +52,7 @@ static int _NSDict_SortedKeysHelper(id key1, id key2, void* context) { @implementation NSDictionary : NSObject -+ (BOOL)automaticallyNotifiersObserversForKey:(NSString*)key { ++ (BOOL)automaticallyNotifiesObserversForKey:(NSString*)key { // This class uses setObject:forKey: as a setter, and has no key-specific setters. return NO; } @@ -799,6 +799,14 @@ - (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id, id, BOOL*))block { } } +/** + @Status Caveat + @Notes enumeration options are not implemented. +*/ +- (void)enumerateKeysAndObjectsWithOptions:(NSEnumerationOptions)options usingBlock:(void (^)(id, id, BOOL*))block { + [self enumerateKeysAndObjectsUsingBlock:block]; +} + /** @Status Interoperable */ diff --git a/Frameworks/Foundation/NSFileManager.h b/Frameworks/Foundation/NSFileManager.h deleted file mode 100644 index d1e242c133..0000000000 --- a/Frameworks/Foundation/NSFileManager.h +++ /dev/null @@ -1,53 +0,0 @@ -//****************************************************************************** -// -// Copyright (c) 2015 Microsoft Corporation. All rights reserved. -// -// This code is licensed under the MIT License (MIT). -// -// 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. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// -//****************************************************************************** - -@interface NSFileManager : NSObject { -@public -} -- (unsigned)countByEnumeratingWithState:(NSFastEnumerationState*)state objects:(id*)stackBuf count:(DWORD)maxCount; -- (void)dealloc; -- (BOOL)fileExistsAtPath:(id)pathAddr; -- (BOOL)isReadableFileAtPath:(id)pathAddr; -- (BOOL)isWritableFileAtPath:(id)pathAddr; -- (BOOL)fileExistsAtPath:(id)pathAddr isDirectory:(unsigned char*)isDirectory; -- (BOOL)createDirectoryAtPath:(id)pathAddr attributes:(DWORD)attrs; -- (BOOL)createDirectoryAtPath:(id)pathAddr withIntermediateDirectories:(BOOL)createIntermediates attributes:(id)attrs error:(id*)err; -- (BOOL)createDirectoryAtURL:(id)url withIntermediateDirectories:(BOOL)createIntermediates attributes:(id)attrs error:(id*)err; -- (BOOL)changeCurrentDirectoryPath:(id)pathAddr; -- (BOOL)setAttributes:(id)attribs ofItemAtPath:(id)pathAddr error:(id*)err; -- (BOOL)removeItemAtPath:(id)pathAddr error:(id*)errRet; -- (BOOL)removeItemAtURL:(id)urlAddr error:(id*)errRet; -- (BOOL)createFileAtPath:(id)pathAddr contents:(id)contents attributes:(id)attributes; -- (BOOL)copyItemAtPath:(id)srcPath toPath:(id)destPath error:(id*)error; -- (BOOL)moveItemAtPath:(id)srcPath toPath:(id)destPath error:(id*)error; -- (const char*)fileSystemRepresentationWithPath:(id)pathAddr; -- (BOOL)contentsEqualAtPath:(id)pathObj1 andPath:(id)pathObj2; -- (void)dealloc; -- (id)initWithPath:(const char*)path shallow:(BOOL)shallow; -- (id)enumeratorAtPath:(id)pathAddr; -- (id)directoryContentsAtPath:(id)pathAddr; -- (id)contentsAtPath:(id)pathAddr; -- (id)contentsOfDirectoryAtPath:(id)pathAddr error:(id*)err; -- (id)fileAttributesAtPath:(id)pathAddr traverseLink:(DWORD)traveseLinks; -- (id)stringWithFileSystemRepresentation:(char*)path length:(int)length; -- (id)displayNameAtPath:(id)path; -- (id)attributesOfItemAtPath:(id)pathAddr error:(id*)error; -- (id)fileSystemAttributesAtPath:(id)pathAddr; -- (id)attributesOfFileSystemForPath:(id)pathAddr error:(id*)error; -- (id)destinationOfSymbolicLinkAtPath:(id)path error:(id*)error; -- (id)URLsForDirectory:(DWORD)directory inDomains:(DWORD)domains; -- (id)URLForDirectory:(DWORD)directory inDomain:(DWORD)domains appropriateForURL:(id)forURL create:(BOOL)create error:(id*)error; -@end diff --git a/Frameworks/Foundation/NSFileManager.mm b/Frameworks/Foundation/NSFileManager.mm index e1cf3780d9..4badc21cb2 100644 --- a/Frameworks/Foundation/NSFileManager.mm +++ b/Frameworks/Foundation/NSFileManager.mm @@ -33,25 +33,51 @@ #define _S_IFDIR S_IFDIR #endif -#define DEFN_STR(name) SB_EXPORT NSString* const name = @ #name; - -DEFN_STR(NSFileTypeDirectory) -DEFN_STR(NSFileTypeRegular) -DEFN_STR(NSFileType) -DEFN_STR(NSFileSize) -DEFN_STR(NSFileCreationDate) -DEFN_STR(NSFileModificationDate) -DEFN_STR(NSFileOwnerAccountName) -DEFN_STR(NSFileSystemFreeSize) -DEFN_STR(NSFileSystemSize) -DEFN_STR(NSFilePosixPermissions) -DEFN_STR(NSFileSystemFileNumber) -DEFN_STR(NSFilePathErrorKey) -DEFN_STR(NSFileProtectionKey) -DEFN_STR(NSFileProtectionComplete) -DEFN_STR(NSFileProtectionCompleteUnlessOpen) - -@implementation NSDirectoryEnumerator : NSEnumerator { +// file attribute keys +NSString* const NSFileType = @"NSFileType"; +NSString* const NSFileSize = @"NSFileSize"; +NSString* const NSFileModificationDate = @"NSFileModificationDate"; +NSString* const NSFileReferenceCount = @"NSFileReferenceCount"; +NSString* const NSFileDeviceIdentifier = @"NSFileDeviceIdentifier"; +NSString* const NSFileOwnerAccountName = @"NSFileOwnerAccountName"; +NSString* const NSFileGroupOwnerAccountName = @"NSFileGroupOwnerAccountName"; +NSString* const NSFilePosixPermissions = @"NSFilePosixPermissions"; +NSString* const NSFileSystemNumber = @"NSFileSystemNumber"; +NSString* const NSFileSystemFileNumber = @"NSFileSystemFileNumber"; +NSString* const NSFileExtensionHidden = @"NSFileExtensionHidden"; +NSString* const NSFileHFSCreatorCode = @"NSFileHFSCreatorCode"; +NSString* const NSFileHFSTypeCode = @"NSFileHFSTypeCode"; +NSString* const NSFileImmutable = @"NSFileImmutable"; +NSString* const NSFileAppendOnly = @"NSFileAppendOnly"; +NSString* const NSFileCreationDate = @"NSFileCreationDate"; +NSString* const NSFileOwnerAccountID = @"NSFileOwnerAccountID"; +NSString* const NSFileGroupOwnerAccountID = @"NSFileGroupOwnerAccountID"; +NSString* const NSFileBusy = @"NSFileBusy"; + +NSString* const NSFileProtectionKey = @"NSFileProtectionKey"; + +// NSFileType Attribute Values +NSString* const NSFileTypeDirectory = @"NSFileTypeDirectory"; +NSString* const NSFileTypeRegular = @"NSFileTypeRegular"; +NSString* const NSFileTypeSymbolicLink = @"NSFileTypeSymbolicLink"; +NSString* const NSFileTypeSocket = @"NSFileTypeSocket"; +NSString* const NSFileTypeCharacterSpecial = @"NSFileTypeCharacterSpecial"; +NSString* const NSFileTypeBlockSpecial = @"NSFileTypeBlockSpecial"; +NSString* const NSFileTypeUnknown = @"NSFileTypeUnknown"; + +// File-System attribute Keys +NSString* const NSFileSystemSize = @"NSFileSystemSize"; +NSString* const NSFileSystemFreeSize = @"NSFileSystemFreeSize"; +NSString* const NSFileSystemNodes = @"NSFileSystemNodes"; +NSString* const NSFileSystemFreeNodes = @"NSFileSystemFreeNodes"; + +// File Protection Values +NSString* const NSFileProtectionNone = @"NSFileProtectionNone"; +NSString* const NSFileProtectionComplete = @"NSFileProtectionComplete"; +NSString* const NSFileProtectionCompleteUnlessOpen = @"NSFileProtectionCompleteUnlessOpen"; +NSString* const NSFileProtectionCompleteUntilFirstUserAuthentication = @"NSFileProtectionCompleteUntilFirstUserAuthentication"; + +@implementation NSDirectoryEnumerator { idretain rootFiles; idretain curFile; idretain enumerators; @@ -67,29 +93,30 @@ - (instancetype)init { static void searchRecursive(const char* rootpath, const char* subpath, id objArray, BOOL shallow) { char searchPath[4096]; - strcpy(searchPath, rootpath); + strcpy_s(searchPath, _countof(searchPath), rootpath); if (searchPath[strlen(searchPath) - 1] != '/') { - strcat(searchPath, "/"); + strcat_s(searchPath, _countof(searchPath), "/"); } - strcat(searchPath, subpath); + strcat_s(searchPath, _countof(searchPath), subpath); if (searchPath[strlen(searchPath) - 1] != '/') { - strcat(searchPath, "/"); + strcat_s(searchPath, _countof(searchPath), "/"); } EbrDir* ebrDir = EbrOpenDir(searchPath); if (ebrDir != NULL) { EbrDirEnt dirEnt; while (EbrReadDir(ebrDir, &dirEnt)) { - if (strcmp(dirEnt.fileName, ".") == 0 || strcmp(dirEnt.fileName, "..") == 0) + if (strcmp(dirEnt.fileName, ".") == 0 || strcmp(dirEnt.fileName, "..") == 0) { continue; + } char filename[4096]; - strcpy(filename, subpath); + strcpy_s(filename, _countof(filename), subpath); if (strlen(filename) > 0 && filename[strlen(filename) - 1] != '/') { - strcat(filename, "/"); + strcat_s(filename, _countof(filename), "/"); } - strcat(filename, dirEnt.fileName); + strcat_s(filename, _countof(filename), dirEnt.fileName); id newStr = [NSString stringWithCString:filename]; [objArray addObject:newStr]; @@ -142,7 +169,7 @@ static void addAllFiles(id enumerator, id allFiles) { return ret; } -- (unsigned)countByEnumeratingWithState:(NSFastEnumerationState*)state objects:(id*)stackBuf count:(DWORD)maxCount { +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState*)state objects:(id*)stackBuf count:(NSUInteger)maxCount { if (state->state == 0) { state->mutationsPtr = (unsigned long*)&state->extra[1]; state->extra[0] = *(unsigned long*)&self; @@ -156,8 +183,9 @@ - (unsigned)countByEnumeratingWithState:(NSFastEnumerationState*)state objects:( while (maxCount > 0) { id next = [state->extra[0] nextObject]; - if (next == nil) + if (next == nil) { break; + } *stackBuf = next; stackBuf++; @@ -183,10 +211,15 @@ - (void)dealloc { /** @Status Interoperable */ -- (id) /* use typed version */ skipDescendents { +- (void)skipDescendents { _skipDescendents = true; +} - return self; +/** + @Status Interoperable +*/ +- (void)skipDescendants { + _skipDescendents = true; } - (id) /* use typed version */ nextObject { @@ -222,16 +255,17 @@ - (void)dealloc { @Status Caveat @Notes Only NSFileSize and NSFileCreationDate attributes are supported */ -- (id) /* use typed version */ fileAttributes { +- (NSDictionary*)fileAttributes { const char* rootPath = [searchPath UTF8String]; const char* path = [curFile UTF8String]; char fullPath[4096]; - strcpy(fullPath, rootPath); - if (fullPath[strlen(fullPath) - 1] != '/') - strcat(fullPath, "/"); - strcat(fullPath, path); + strcpy_s(fullPath, _countof(fullPath), rootPath); + if (fullPath[strlen(fullPath) - 1] != '/') { + strcpy_s(fullPath, _countof(fullPath), "/"); + } + strcpy_s(fullPath, _countof(fullPath), path); EbrDebugLog("fileAttributesAtPath: %s\n", fullPath); @@ -244,11 +278,11 @@ - (void)dealloc { id ret = [NSMutableDictionary dictionary]; - [ret setValue:[NSNumber numberWithInt:st.st_size] forKey:@"NSFileSize"]; - [ret setValue:NSFileTypeRegular forKey:@"NSFileType"]; + [ret setValue:[NSNumber numberWithInt:st.st_size] forKey:NSFileSize]; + [ret setValue:NSFileTypeRegular forKey:NSFileType]; id date = [NSDate dateWithTimeIntervalSince1970:(double)st.st_ctime]; - [ret setValue:@"NSFileCreationDate" forKey:date]; + [ret setValue:NSFileCreationDate forKey:date]; return ret; } @@ -259,90 +293,187 @@ - (void)dealloc { @implementation NSFileManager : NSObject +// Creating a File Manager + /** @Status Interoperable */ -- (BOOL)fileExistsAtPath:(id)pathAddr { - if (pathAddr == nil) - return FALSE; - - const char* path = [pathAddr UTF8String]; - - if (strcmp(path, "") == 0) - return FALSE; ++ (NSFileManager*)defaultManager { + static id defaultManager; - if (EbrAccess(path, 0) == 0) { - return TRUE; - } else { - EbrDebugLog("File @ %s doesn't exist\n", path); - return FALSE; + if (defaultManager == nil) { + defaultManager = [self alloc]; } + + return defaultManager; } /** @Status Interoperable */ -- (BOOL)isReadableFileAtPath:(id)pathAddr { - const char* path = [pathAddr UTF8String]; +- (instancetype)init { + return self; +} - if (EbrAccess(path, 6) == 0) { - return TRUE; - } else { - EbrDebugLog("File @ %s isn't writable\n", path); - return FALSE; +// Locating System Directories + +/** + @Status Stub +*/ +- (NSURL*)URLForDirectory:(NSSearchPathDirectory)directory + inDomain:(NSSearchPathDomainMask)domains + appropriateForURL:(NSURL*)forURL + create:(BOOL)create + error:(NSError**)error { + UNIMPLEMENTED(); + assert(forURL == nil); + id paths = NSSearchPathForDirectoriesInDomains(directory, domains, TRUE); + + int count = [paths count]; + + for (int i = 0; i < count; i++) { + id curObj = [paths objectAtIndex:i]; + + id newUrl = [NSURL fileURLWithPath:curObj]; + + return newUrl; } + + assert(0); + + return nil; } /** @Status Interoperable */ -- (BOOL)isWritableFileAtPath:(id)pathAddr { - const char* path = [pathAddr UTF8String]; +- (NSArray*)URLsForDirectory:(NSSearchPathDirectory)directory inDomains:(NSSearchPathDomainMask)domains { + id paths = NSSearchPathForDirectoriesInDomains(directory, domains, TRUE); - if (EbrAccess(path, 4) == 0) { - return TRUE; - } else { - EbrDebugLog("File @ %s isn't readable\n", path); - return FALSE; + int count = [paths count]; + + id ret = [NSMutableArray array]; + + for (int i = 0; i < count; i++) { + id curObj = [paths objectAtIndex:i]; + + id newUrl = [NSURL fileURLWithPath:curObj]; + + [ret addObject:newUrl]; } + + return ret; +} + +// Locating Application Group Container Directories + +/** + @Status Stub +*/ +- (NSURL*)containerURLForSecurityApplicationGroupIdentifier:(NSString*)groupIdentifier { + UNIMPLEMENTED(); + + return nil; +} + +// Discovering Directory Contents + +/** + @Status Stub +*/ +- (NSArray*)contentsOfDirectoryAtURL:(NSURL*)url + includingPropertiesForKeys:(NSArray*)keys + options:(NSDirectoryEnumerationOptions)mask + error:(NSError**)error { + // TODO: this is needed for 1511 + UNIMPLEMENTED(); + return nil; +} + +/** + @Status Caveat + @Notes Path must exist +*/ +- (NSArray*)contentsOfDirectoryAtPath:(id)pathAddr error:(NSError**)err { + EbrDebugLog("contentsOfDirectoryAtPath: %s\n", [pathAddr UTF8String]); + id enumerator = [NSDirectoryEnumerator new]; + [enumerator initWithPath:[pathAddr UTF8String] shallow:TRUE]; + + id ret = [enumerator allObjects]; + [enumerator release]; + return ret; +} + +/** + @Status Stub +*/ +- (NSDirectoryEnumerator*)enumeratorAtURL:(NSURL*)url + includingPropertiesForKeys:(NSArray*)keys + options:(NSDirectoryEnumerationOptions)mask + errorHandler:(BOOL (^)(NSURL* url, NSError* error))handler { + UNIMPLEMENTED(); + return nil; } /** @Status Interoperable */ -- (BOOL)fileExistsAtPath:(id)pathAddr isDirectory:(unsigned char*)isDirectory { +- (id)enumeratorAtPath:(id)pathAddr { const char* path = [pathAddr UTF8String]; - struct stat st; - if (EbrStat(path, &st) == 0) { - if (isDirectory) { - *isDirectory = (st.st_mode & _S_IFDIR) == _S_IFDIR; - } - return TRUE; - } else { - return FALSE; - } + NSDirectoryEnumerator* directoryEnum = [NSDirectoryEnumerator new]; + [directoryEnum initWithPath:path shallow:FALSE]; + + return directoryEnum; +} + +/** + @Status Stub +*/ +- (NSArray**)mountedVolumeURLsIncludingResourceValuesForKeys:(NSArray**)propertyKeys options:(NSVolumeEnumerationOptions)options { + UNIMPLEMENTED(); + return nil; +} + +/** + @Status Stub +*/ +- (NSArray*)subpathsOfDirectoryAtPath:(NSString*)path error:(NSError**)error { + UNIMPLEMENTED(); + return nil; +} + +/** + @Status Stub +*/ +- (NSArray*)subpathsAtPath:(NSString*)path { + UNIMPLEMENTED(); + return nil; } +// Creating and Deleting Items + /** @Status Caveat - @Notes attributes parameter not supported + @Notes attributes parameter not supported. error parameter not supported. */ -- (BOOL)createDirectoryAtPath:(id)pathAddr attributes:(DWORD)attrs { - const char* path = [pathAddr UTF8String]; +- (BOOL)createDirectoryAtURL:(NSURL*)url + withIntermediateDirectories:(BOOL)createIntermediates + attributes:(NSDictionary*)attrs + error:(NSError**)err { + id path = [url path]; - if (EbrMkdir(path)) { - return TRUE; - } else { - return FALSE; - } + return [self createDirectoryAtPath:path withIntermediateDirectories:createIntermediates attributes:attrs error:err]; } /** @Status Caveat @Notes attributes parameter not supported. error parameter is not populated */ -- (BOOL)createDirectoryAtPath:(id)pathAddr withIntermediateDirectories:(BOOL)createIntermediates attributes:(id)attrs error:(id*)err { +- (BOOL)createDirectoryAtPath:(NSString*)pathAddr + withIntermediateDirectories:(BOOL)createIntermediates + attributes:(NSDictionary*)attrs + error:(NSError**)err { if (createIntermediates) { const char* path = [pathAddr UTF8String]; id components = [pathAddr pathComponents]; @@ -354,8 +485,8 @@ - (BOOL)createDirectoryAtPath:(id)pathAddr withIntermediateDirectories:(BOOL)cre const char* pComponent = [curComponent UTF8String]; if (strlen(pComponent) > 0) { - strcat(curPath, pComponent); - strcat(curPath, "/"); + strcat_s(curPath, _countof(curPath), pComponent); + strcat_s(curPath, _countof(curPath), "/"); } if (strlen(curPath) > 0) { @@ -380,34 +511,26 @@ - (BOOL)createDirectoryAtPath:(id)pathAddr withIntermediateDirectories:(BOOL)cre /** @Status Caveat - @Notes attributes parameter not supported. error parameter not supported. + @Notes attributes parameter not supported */ -- (BOOL)createDirectoryAtURL:(id)url withIntermediateDirectories:(BOOL)createIntermediates attributes:(id)attrs error:(id*)err { - id path = [url path]; +- (BOOL)createFileAtPath:(id)pathAddr contents:(id)contents attributes:(id)attributes { + const char* path = [pathAddr UTF8String]; - return [self createDirectoryAtPath:path withIntermediateDirectories:createIntermediates attributes:attrs error:err]; -} + EbrDebugLog("createFileAtPath: %s\n", path); -/** - @Status Interoperable -*/ -- (id)enumeratorAtPath:(id)pathAddr { - const char* path = [pathAddr UTF8String]; + EbrFile* fpOut = EbrFopen(path, "wb"); - NSDirectoryEnumerator* directoryEnum = [NSDirectoryEnumerator new]; - [directoryEnum initWithPath:path shallow:FALSE]; + if (!fpOut) { + EbrDebugLog("failed to createFileAtPath: %s\n", path); + return FALSE; + } - return directoryEnum; -} + char* bytes = (char*)[contents bytes]; + int length = [contents length]; -/** - @Status Interoperable -*/ -- (BOOL)changeCurrentDirectoryPath:(id)pathAddr { - const char* path = [pathAddr UTF8String]; - EbrDebugLog("setting path to %s\n", path); + EbrFwrite(bytes, 1, length, fpOut); - EbrChdir(path); + EbrFclose(fpOut); return TRUE; } @@ -415,279 +538,381 @@ - (BOOL)changeCurrentDirectoryPath:(id)pathAddr { /** @Status Interoperable */ -- (id)directoryContentsAtPath:(id)pathAddr { - id enumerator = [NSDirectoryEnumerator new]; - [enumerator initWithPath:[pathAddr UTF8String] shallow:TRUE]; +- (BOOL)removeItemAtURL:(NSURL*)URL error:(NSError**)error { + id pathAddr = [URL path]; + if (pathAddr == nil) { + EbrDebugLog("removeItemAtURL: nil!\n"); + return YES; + } - id ret = [enumerator allObjects]; - [enumerator release]; - return ret; + return [self removeItemAtPath:pathAddr error:error]; } /** - @Status Interoperable + @Status Stub */ -- (id)contentsAtPath:(id)pathAddr { - return [NSData dataWithContentsOfFile:pathAddr]; +- (BOOL)replaceItemAtURL:(NSURL*)originalItemURL + withItemAtURL:(NSURL*)newItemURL + backupItemName:(NSString*)backupItemName + options:(NSFileManagerItemReplacementOptions)options + resultingItemURL:(NSURL**)resultingURL + error:(NSError**)error { + UNIMPLEMENTED(); + return NO; } /** - @Status Caveat - @Notes Path must exist + @Status Stub */ -- (id)contentsOfDirectoryAtPath:(id)pathAddr error:(id*)err { - EbrDebugLog("contentsOfDirectoryAtPath: %s\n", [pathAddr UTF8String]); - id enumerator = [NSDirectoryEnumerator new]; - [enumerator initWithPath:[pathAddr UTF8String] shallow:TRUE]; - - id ret = [enumerator allObjects]; - [enumerator release]; - return ret; +- (BOOL)trashItemAtURL:(NSURL*)url resultingItemURL:(NSURL**)outResultingURL error:(NSError**)error { + UNIMPLEMENTED(); + return NO; } +// Moving and Copying Items + /** - @Status Caveat - @Notes Only NSFileSize and NSFileType attributes are supported. traverseLink not supported. + @Status Stub */ -- (NSDictionary*)fileAttributesAtPath:(id)pathAddr traverseLink:(DWORD)traveseLinks { - if (pathAddr == nil) { - EbrDebugLog("fileAttributesAtPath nil!"); - - return nil; - } - - struct stat st; +- (BOOL)copyItemAtURL:(NSURL*)srcURL toURL:(NSURL*)dstURL error:(NSError**)error { + UNIMPLEMENTED(); - const char* path = [pathAddr UTF8String]; - EbrDebugLog("fileAttributesAtPath: %s\n", path); + return NO; +} - if (EbrStat(path, &st) == -1) { - return nil; +/** + @Status Interoperable +*/ +- (BOOL)copyItemAtPath:(id)srcPath toPath:(id)destPath error:(NSError**)error { + if (srcPath == nil || destPath == nil) { + EbrDebugLog("copyItemAtPath: nil!\n"); + return FALSE; } - id ret = [NSMutableDictionary dictionary]; - - [ret setValue:[NSNumber numberWithInt:st.st_size] forKey:@"NSFileSize"]; - - // NOTE: st_ctime is file creation time on windows for NTFS - [ret setValue:[NSDate dateWithTimeIntervalSince1970:st.st_ctime] forKey:@"NSFileCreationDate"]; - [ret setValue:[NSDate dateWithTimeIntervalSince1970:st.st_mtime] forKey:@"NSFileModificationDate"]; + const char* src = [srcPath UTF8String]; + const char* dest = [destPath UTF8String]; - if (st.st_mode & _S_IFDIR) { - [ret setValue:NSFileTypeDirectory forKey:@"NSFileType"]; - } else { - [ret setValue:NSFileTypeRegular forKey:@"NSFileType"]; + if (EbrAccess(dest, 0) == 0) { + if (error) { + // TODO: standardize the error code and message + *error = [NSError errorWithDomain:@"Would overwrite destination" code:100 userInfo:nil]; + } + EbrDebugLog("Not copying %s to %s because dest exists\n", src, dest); + return FALSE; } - return ret; -} + EbrDebugLog("Copying %s to %s\n", src, dest); -/** - @Status Stub -*/ -- (id)stringWithFileSystemRepresentation:(char*)path length:(int)length { - UNIMPLEMENTED(); - return [NSString stringWithCString:path length:length]; + EbrFile* fpIn = EbrFopen(src, "rb"); + if (!fpIn) { + EbrDebugLog("Error opening %s\n", src); + return FALSE; + } + + EbrFile* fpOut = EbrFopen(dest, "wb"); + if (!fpOut) { + EbrFclose(fpIn); + EbrDebugLog("Error opening %s\n", dest); + return FALSE; + } + + while (!EbrFeof(fpIn)) { + BYTE in[4096]; + int read = EbrFread(in, 1, 4096, fpIn); + EbrFwrite(in, 1, read, fpOut); + } + + EbrFclose(fpOut); + EbrFclose(fpIn); + + EbrDebugLog("Done copying\n"); + + return TRUE; } /** @Status Stub */ -- (id)displayNameAtPath:(id)path { +- (BOOL)moveItemAtURL:(NSURL*)srcURL toURL:(NSURL*)dstURL error:(NSError**)error { UNIMPLEMENTED(); - return path; + + return NO; } /** @Status Caveat - @Notes Only NSFileSize and NSFileType attributes are supported + @Notes error parameter is not populated */ -- (id)attributesOfItemAtPath:(id)pathAddr error:(id*)error { - if (pathAddr == nil) { - EbrDebugLog("attributesOfItemAtPath nil!"); +- (BOOL)moveItemAtPath:(id)srcPath toPath:(id)destPath error:(NSError**)error { + const char* src = [srcPath UTF8String]; + const char* dest = [destPath UTF8String]; - if (error) { - assert(0); - } + EbrDebugLog("Moving %s to %s\n", src, dest); - return nil; + bool success = EbrRename(src, dest); + if (!success) { + EbrDebugLog("Rename failed.\n"); + return FALSE; + // assert(0); } - struct stat st; + return TRUE; +} - const char* path = [pathAddr UTF8String]; - EbrDebugLog("attributesOfItemAtPath: %s\n", path); +// Managing iCloud-Based Items - if (EbrStat(path, &st) == -1) { - if (error) { - *error = [NSError errorWithDomain:@"File not found" code:100 userInfo:nil]; - } - return nil; - } +/** + @Status Stub +*/ +- (NSURL*)URLForUbiquityContainerIdentifier:(NSString*)containerID { + UNIMPLEMENTED(); - id ret = [NSMutableDictionary dictionary]; + return nil; +} - [ret setValue:[NSNumber numberWithInt:st.st_size] forKey:@"NSFileSize"]; - if (st.st_mode & _S_IFDIR) { - [ret setValue:NSFileTypeDirectory forKey:@"NSFileType"]; - } else { - [ret setValue:NSFileTypeRegular forKey:@"NSFileType"]; - } +/** + @Status Stub +*/ +- (BOOL)isUbiquitousItemAtURL:(NSURL*)url { + UNIMPLEMENTED(); + return NO; +} - return ret; +/** + @Status Stub +*/ +- (BOOL)setUbiquitous:(BOOL)flag itemAtURL:(NSURL*)url destinationURL:(NSURL*)destinationURL error:(NSError**)errorOut { + UNIMPLEMENTED(); + return NO; } /** @Status Stub */ -- (BOOL)setAttributes:(id)attribs ofItemAtPath:(id)pathAddr error:(id*)err { +- (BOOL)startDownloadingUbiquitousItemAtURL:(NSURL*)url error:(NSError**)errorOut { UNIMPLEMENTED(); - EbrDebugLog("setAttributes not implemented\n"); + return NO; +} - return TRUE; +/** + @Status Stub +*/ +- (BOOL)evictUbiquitousItemAtURL:(NSURL*)url error:(NSError**)errorOut { + UNIMPLEMENTED(); + return NO; } /** - @Status Caveat - @Notes error parameter is not populated + @Status Stub */ -- (BOOL)removeItemAtPath:(id)pathAddr error:(id*)errRet { - const char* path = [pathAddr UTF8String]; - EbrDebugLog("removeItemAtPath: %s\n", path); +- (NSURL*)URLForPublishingUbiquitousItemAtURL:(NSURL*)url expirationDate:(NSDate**)outDate error:(NSError**)error { + UNIMPLEMENTED(); + return nil; +} - return EbrRemove(path); +// Creating Symbolic and Hard Links +/** + @Status Stub +*/ +- (BOOL)createSymbolicLinkAtURL:(NSURL*)url withDestinationURL:(NSURL*)destURL error:(NSError**)error { + UNIMPLEMENTED(); + return NO; } -- (BOOL)removeItemAtURL:(id)urlAddr error:(id*)errRet { - id pathAddr = [urlAddr path]; - if (pathAddr == nil) { - EbrDebugLog("removeItemAtURL: nil!\n"); - return FALSE; - } +/** + @Status Stub +*/ +- (BOOL)createSymbolicLinkAtPath:(NSString*)path withDestinationPath:(NSString*)toPath error:(NSError**)error { + UNIMPLEMENTED(); + return NO; +} - return [self removeItemAtPath:pathAddr error:errRet]; +/** + @Status Stub +*/ +- (BOOL)linkItemAtURL:(NSURL*)srcURL toURL:(NSURL*)dstURL error:(NSError**)error { + UNIMPLEMENTED(); + return NO; } /** - @Status Caveat - @Notes attributes parameter not supported + @Status Stub */ -- (BOOL)createFileAtPath:(id)pathAddr contents:(id)contents attributes:(id)attributes { - const char* path = [pathAddr UTF8String]; +- (BOOL)linkItemAtPath:(NSString*)fromPath toPath:(NSString*)toPath error:(NSError**)error { + UNIMPLEMENTED(); + return NO; +} - EbrDebugLog("createFileAtPath: %s\n", path); +/** + @Status Stub +*/ +- (id)destinationOfSymbolicLinkAtPath:(id)path error:(NSError**)error { + UNIMPLEMENTED(); + const char* pPath = [path UTF8String]; + EbrDebugLog("destinationOfSymbolicLinkAtPath: %s\n", pPath); - EbrFile* fpOut = EbrFopen(path, "wb"); + return [path retain]; +} - if (!fpOut) { - EbrDebugLog("failed to createFileAtPath: %s\n", path); +// Determining Access to Files + +/** + @Status Interoperable +*/ +- (BOOL)fileExistsAtPath:(id)pathAddr { + if (pathAddr == nil) { return FALSE; } - char* bytes = (char*)[contents bytes]; - int length = [contents length]; - - EbrFwrite(bytes, 1, length, fpOut); + const char* path = [pathAddr UTF8String]; - EbrFclose(fpOut); + if (strcmp(path, "") == 0) { + return FALSE; + } - return TRUE; + if (EbrAccess(path, 0) == 0) { + return TRUE; + } else { + EbrDebugLog("File @ %s doesn't exist\n", path); + return FALSE; + } } /** @Status Interoperable */ -+ (id) /* use typed version */ defaultManager { - static id defaultManager; +- (BOOL)fileExistsAtPath:(id)pathAddr isDirectory:(BOOL*)isDirectory { + const char* path = [pathAddr UTF8String]; + struct stat st; - if (defaultManager == nil) { - defaultManager = [self alloc]; + if (EbrStat(path, &st) == 0) { + if (isDirectory) { + *isDirectory = (st.st_mode & _S_IFDIR) == _S_IFDIR; + } + return TRUE; + } else { + return FALSE; } - - return defaultManager; } /** @Status Interoperable */ -- (BOOL)copyItemAtPath:(id)srcPath toPath:(id)destPath error:(id*)error { - if (srcPath == nil || destPath == nil) { - EbrDebugLog("copyItemAtPath: nil!\n"); - return FALSE; - } - - const char* src = [srcPath UTF8String]; - const char* dest = [destPath UTF8String]; +- (BOOL)isReadableFileAtPath:(id)pathAddr { + const char* path = [pathAddr UTF8String]; - if (EbrAccess(dest, 0) == 0) { - if (error) - *error = [NSError errorWithDomain:@"Would overwrite destination" code:100 userInfo:nil]; - EbrDebugLog("Not copying %s to %s because dest exists\n", src, dest); + if (EbrAccess(path, 6) == 0) { + return TRUE; + } else { + EbrDebugLog("File @ %s isn't writable\n", path); return FALSE; } +} - EbrDebugLog("Copying %s to %s\n", src, dest); +/** + @Status Interoperable +*/ +- (BOOL)isWritableFileAtPath:(id)pathAddr { + const char* path = [pathAddr UTF8String]; - EbrFile* fpIn = EbrFopen(src, "rb"); - if (!fpIn) { - EbrDebugLog("Error opening %s\n", src); + if (EbrAccess(path, 4) == 0) { + return TRUE; + } else { + EbrDebugLog("File @ %s isn't readable\n", path); return FALSE; } +} - EbrFile* fpOut = EbrFopen(dest, "wb"); - if (!fpOut) { - EbrFclose(fpIn); - EbrDebugLog("Error opening %s\n", dest); - return FALSE; - } +/** + @Status Stub +*/ +- (BOOL)isExecutableFileAtPath:(NSString*)path { + UNIMPLEMENTED(); + return NO; +} - while (!EbrFeof(fpIn)) { - BYTE in[4096]; - int read = EbrFread(in, 1, 4096, fpIn); - EbrFwrite(in, 1, read, fpOut); - } +/** + @Status Stub +*/ +- (BOOL)isDeletableFileAtPath:(NSString*)path { + UNIMPLEMENTED(); + return NO; +} - EbrFclose(fpOut); - EbrFclose(fpIn); +// Getting and Setting Attributes - EbrDebugLog("Done copying\n"); +/** + @Status Stub +*/ +- (NSArray*)componentsToDisplayForPath:(NSString*)path { + UNIMPLEMENTED(); + return nil; +} - return TRUE; +/** + @Status Stub +*/ +- (id)displayNameAtPath:(id)path { + UNIMPLEMENTED(); + return path; } /** @Status Caveat - @Notes error parameter is not populated + @Notes Only NSFileSize and NSFileType attributes are supported */ -- (BOOL)moveItemAtPath:(id)srcPath toPath:(id)destPath error:(id*)error { - const char* src = [srcPath UTF8String]; - const char* dest = [destPath UTF8String]; +- (id)attributesOfItemAtPath:(id)pathAddr error:(NSError**)error { + if (pathAddr == nil) { + EbrDebugLog("attributesOfItemAtPath nil!"); - EbrDebugLog("Moving %s to %s\n", src, dest); + if (error) { + // TODO: standardize the error code and message + *error = [NSError errorWithDomain:@"Empty File Path" code:100 userInfo:nil]; + } - bool success = EbrRename(src, dest); - if (!success) { - EbrDebugLog("Rename failed.\n"); - return FALSE; - // assert(0); + return nil; } - return TRUE; + struct stat st; + + const char* path = [pathAddr UTF8String]; + EbrDebugLog("attributesOfItemAtPath: %s\n", path); + + if (EbrStat(path, &st) == -1) { + if (error) { + // TODO: standardize the error code and message + *error = [NSError errorWithDomain:@"File not found" code:100 userInfo:nil]; + } + return nil; + } + + id ret = [NSMutableDictionary dictionary]; + + [ret setValue:[NSNumber numberWithInt:st.st_size] forKey:NSFileSize]; + if (st.st_mode & _S_IFDIR) { + [ret setValue:NSFileTypeDirectory forKey:NSFileType]; + } else { + [ret setValue:NSFileTypeRegular forKey:NSFileType]; + } + + return ret; } /** @Status Stub */ -- (id)fileSystemAttributesAtPath:(id)pathAddr { +- (id)attributesOfFileSystemForPath:(id)pathAddr error:(NSError**)error { UNIMPLEMENTED(); + if (error) { + *error = nil; + } + const char* path = [pathAddr UTF8String]; EbrDebugLog("fileAttributesAtPath: %s\n", path); id ret = [NSMutableDictionary dictionary]; - - [ret setValue:[NSNumber numberWithInt:32 * 1024 * 1024] forKey:@"NSFileSystemFreeSize"]; - [ret setValue:[NSNumber numberWithInt:64 * 1024 * 1024 * 1024] forKey:@"NSFileSystemSize"]; + [ret setValue:[NSNumber numberWithInt:256 * 1024 * 1024] forKey:NSFileSystemFreeSize]; return ret; } @@ -695,22 +920,89 @@ - (id)fileSystemAttributesAtPath:(id)pathAddr { /** @Status Stub */ -- (id)attributesOfFileSystemForPath:(id)pathAddr error:(id*)error { +- (BOOL)setAttributes:(id)attribs ofItemAtPath:(id)pathAddr error:(NSError**)err { UNIMPLEMENTED(); - const char* path = [pathAddr UTF8String]; + EbrDebugLog("setAttributes not implemented\n"); - EbrDebugLog("fileAttributesAtPath: %s\n", path); + return TRUE; +} - id ret = [NSMutableDictionary dictionary]; +// Getting and Comparing File Contents + +/** + @Status Interoperable +*/ +- (id)contentsAtPath:(id)pathAddr { + return [NSData dataWithContentsOfFile:pathAddr]; +} - [ret setValue:[NSNumber numberWithInt:256 * 1024 * 1024] forKey:@"NSFileSystemFreeSize"]; +/** + @Status Caveat + @Notes Comparing directories not supported +*/ +- (BOOL)contentsEqualAtPath:(id)pathObj1 andPath:(id)pathObj2 { + const char* path1 = [pathObj1 UTF8String]; + const char* path2 = [pathObj2 UTF8String]; - if (error) - *error = nil; + bool dir = EbrIsDir(path1); + if (dir != EbrIsDir(path2)) { + return false; + } - return ret; + if (dir) { + // no good: + assert(0); + } else { + struct stat st1, st2; + if (EbrStat(path1, &st1) != 0 || EbrStat(path2, &st2) != 0) { + return false; + } + + if (st1.st_size != st2.st_size) { + return false; + } + + id d1 = [[NSData alloc] initWithContentsOfFile:pathObj1]; + id d2 = [[NSData alloc] initWithContentsOfFile:pathObj2]; + + bool ret = [d1 isEqualToData:d2] != 0; + + [d1 release]; + [d2 release]; + + return ret; + } + + return FALSE; +} + +// Getting the Relationship Between Items + +/** + @Status Stub +*/ +- (BOOL)getRelationship:(NSURLRelationship*)outRelationship + ofDirectoryAtURL:(NSURL*)directoryURL + toItemAtURL:(NSURL*)otherURL + error:(NSError**)error { + UNIMPLEMENTED(); + return NO; +} + +/** + @Status Stub +*/ +- (BOOL)getRelationship:(NSURLRelationship*)outRelationship + ofDirectory:(NSSearchPathDirectory)directory + inDomain:(NSSearchPathDomainMask)domainMask + toItemAtURL:(NSURL*)url + error:(NSError**)error { + UNIMPLEMENTED(); + return NO; } +// Converting File Paths to Strings + /** @Status Stub */ @@ -722,30 +1014,94 @@ - (const char*)fileSystemRepresentationWithPath:(id)pathAddr { /** @Status Stub */ -- (id)destinationOfSymbolicLinkAtPath:(id)path error:(id*)error { +- (id)stringWithFileSystemRepresentation:(const char*)path length:(NSUInteger)length { UNIMPLEMENTED(); - const char* pPath = [path UTF8String]; - EbrDebugLog("destinationOfSymbolicLinkAtPath: %s\n", pPath); - - return [path retain]; + return [NSString stringWithCString:path length:length]; } +// Managing the Delegate + +// Managing the Current Directory + /** @Status Interoperable */ -- (id)URLsForDirectory:(DWORD)directory inDomains:(DWORD)domains { - id paths = NSSearchPathForDirectoriesInDomains(directory, domains, TRUE); +- (BOOL)changeCurrentDirectoryPath:(id)pathAddr { + const char* path = [pathAddr UTF8String]; + EbrDebugLog("setting path to %s\n", path); - int count = [paths count]; + EbrChdir(path); - id ret = [NSMutableArray array]; + return TRUE; +} - for (int i = 0; i < count; i++) { - id curObj = [paths objectAtIndex:i]; +// Deprecated Methods - id newUrl = [NSURL fileURLWithPath:curObj]; +/** + @Status Stub +*/ +- (BOOL)copyPath:(NSString*)src toPath:(NSString*)dest handler:handler { + UNIMPLEMENTED(); + return NO; +} - [ret addObject:newUrl]; +/** + @Status Stub +*/ +- (BOOL)movePath:(NSString*)src toPath:(NSString*)dest handler:handler { + UNIMPLEMENTED(); + return NO; +} + +/** + @Status Stub +*/ +- (BOOL)removeFileAtPath:(NSString*)path handler:handler { + UNIMPLEMENTED(); + return NO; +} + +/** + @Status Stub +*/ +- (BOOL)changeFileAttributes:(NSDictionary*)attributes atPath:(NSString*)path { + UNIMPLEMENTED(); + return NO; +} + +/** + @Status Caveat + @Notes Only NSFileSize, NSFileType, NSFileCreationDate, NSFileModificationDate attributes are supported. + @traverseLink not supported. +*/ +- (NSDictionary*)fileAttributesAtPath:(NSString*)pathAddr traverseLink:(BOOL)traveseLinks { + if (pathAddr == nil) { + EbrDebugLog("fileAttributesAtPath nil!"); + + return nil; + } + + struct stat st; + + const char* path = [pathAddr UTF8String]; + EbrDebugLog("fileAttributesAtPath: %s\n", path); + + if (EbrStat(path, &st) == -1) { + return nil; + } + + id ret = [NSMutableDictionary dictionary]; + + [ret setValue:[NSNumber numberWithInt:st.st_size] forKey:NSFileSize]; + + // NOTE: st_ctime is file creation time on windows for NTFS + [ret setValue:[NSDate dateWithTimeIntervalSince1970:st.st_ctime] forKey:NSFileCreationDate]; + [ret setValue:[NSDate dateWithTimeIntervalSince1970:st.st_mtime] forKey:NSFileModificationDate]; + + if (st.st_mode & _S_IFDIR) { + [ret setValue:NSFileTypeDirectory forKey:NSFileType]; + } else { + [ret setValue:NSFileTypeRegular forKey:NSFileType]; } return ret; @@ -754,61 +1110,88 @@ - (id)URLsForDirectory:(DWORD)directory inDomains:(DWORD)domains { /** @Status Stub */ -- (id)URLForDirectory:(DWORD)directory inDomain:(DWORD)domains appropriateForURL:(id)forURL create:(BOOL)create error:(id*)error { +- (id)fileSystemAttributesAtPath:(id)pathAddr { UNIMPLEMENTED(); - assert(forURL == nil); - id paths = NSSearchPathForDirectoriesInDomains(directory, domains, TRUE); + const char* path = [pathAddr UTF8String]; - int count = [paths count]; + EbrDebugLog("fileAttributesAtPath: %s\n", path); - for (int i = 0; i < count; i++) { - id curObj = [paths objectAtIndex:i]; + id ret = [NSMutableDictionary dictionary]; - id newUrl = [NSURL fileURLWithPath:curObj]; + [ret setValue:[NSNumber numberWithInt:32 * 1024 * 1024] forKey:NSFileSystemFreeSize]; + [ret setValue:[NSNumber numberWithInt:64 * 1024 * 1024 * 1024] forKey:NSFileSystemSize]; - return newUrl; - } + return ret; +} - assert(0); +/** + @Status Interoperable +*/ +- (id)directoryContentsAtPath:(id)pathAddr { + id enumerator = [NSDirectoryEnumerator new]; + [enumerator initWithPath:[pathAddr UTF8String] shallow:TRUE]; - return nil; + id ret = [enumerator allObjects]; + [enumerator release]; + return ret; } /** @Status Caveat - @Notes Comparing directories not supported + @Notes attributes parameter not supported */ -- (BOOL)contentsEqualAtPath:(id)pathObj1 andPath:(id)pathObj2 { - const char* path1 = [pathObj1 UTF8String]; - const char* path2 = [pathObj2 UTF8String]; - - bool dir = EbrIsDir(path1); - if (dir != EbrIsDir(path2)) - return false; +- (BOOL)createDirectoryAtPath:(id)pathAddr attributes:(NSDictionary*)attrs { + const char* path = [pathAddr UTF8String]; - if (dir) { - // no good: - assert(0); + if (EbrMkdir(path)) { + return TRUE; } else { - struct stat st1, st2; - if (EbrStat(path1, &st1) != 0 || EbrStat(path2, &st2) != 0) - return false; + return FALSE; + } +} - if (st1.st_size != st2.st_size) - return false; +/** + @Status Stub +*/ +- (BOOL)createSymbolicLinkAtPath:(NSString*)path pathContent:(NSString*)destination { + UNIMPLEMENTED(); + return NO; +} - id d1 = [[NSData alloc] initWithContentsOfFile:pathObj1]; - id d2 = [[NSData alloc] initWithContentsOfFile:pathObj2]; +/** + @Status Stub +*/ +- (NSString*)pathContentOfSymbolicLinkAtPath:(NSString*)path { + UNIMPLEMENTED(); + return nil; +} - bool ret = [d1 isEqualToData:d2] != 0; +/** + @Status Stub +*/ +- (BOOL)linkPath:(NSString*)source toPath:(NSString*)destination handler:handler { + UNIMPLEMENTED(); + return NO; +} - [d1 release]; - [d2 release]; +/** + @Status Interoperable +*/ +- (BOOL)removeItemAtPath:(id)pathAddr error:(NSError**)error { + if (error) { + *error = nil; + } - return ret; + const char* path = [pathAddr UTF8String]; + EbrDebugLog("removeItemAtPath: %s\n", path); + + BOOL ret = EbrRemove(path); + if (!ret && error) { + // TODO: standardize the error code and message + *error = [NSError errorWithDomain:@"Failed to delete file" code:100 userInfo:nil]; } - return FALSE; + return ret; } - (void)dealloc { diff --git a/Frameworks/Foundation/NSIndexPath.mm b/Frameworks/Foundation/NSIndexPath.mm index 45a7de8e08..323a70e226 100644 --- a/Frameworks/Foundation/NSIndexPath.mm +++ b/Frameworks/Foundation/NSIndexPath.mm @@ -198,4 +198,12 @@ - (unsigned)section { return [self indexAtPosition:0]; } +/** + @Status Stub +*/ +- (NSIndexPath*)indexPathByRemovingLastIndex { + UNIMPLEMENTED(); + return self; +} + @end diff --git a/Frameworks/Foundation/NSKVOSupport.mm b/Frameworks/Foundation/NSKVOSupport.mm index 9e3855de7b..c8221951a1 100644 --- a/Frameworks/Foundation/NSKVOSupport.mm +++ b/Frameworks/Foundation/NSKVOSupport.mm @@ -298,6 +298,8 @@ void dispatch(bool prior) override { } void NSKVOClass::dealloc(id instance) { + // WE CANNOT USE instance AS AN OBJECT IN HERE. + // It has been deallocated, and we are updating our bookkeeping. std::lock_guard lock(_mutex); for (auto i = _notifiersByInstance.begin(); i != _notifiersByInstance.end();) { if (std::get<0>(i->first) == instance) { @@ -309,10 +311,6 @@ void dispatch(bool prior) override { for (auto i = _keypathNotifiersByInstance.begin(); i != _keypathNotifiersByInstance.end(); ++i) { if (std::get<0>(i->first) == instance && i->second.size() > 0) { - // TODO: We have to be able to throw an exception DURING DEALLOC and have - // the object properly deallocated. - // The FAIL_FAST is a compromise right now because we can't. - FAIL_FAST_MSG("Instance of %s deallocated with observers still registered.", class_getName(originalClass)); [NSException raise:NSInvalidArgumentException format:@"Instance of %s deallocated with observers still registered.", class_getName(originalClass)]; } diff --git a/Frameworks/Foundation/NSKVOSwizzling.mm b/Frameworks/Foundation/NSKVOSwizzling.mm index 68ff4d29c7..9edec05755 100644 --- a/Frameworks/Foundation/NSKVOSwizzling.mm +++ b/Frameworks/Foundation/NSKVOSwizzling.mm @@ -64,8 +64,8 @@ void callOriginalVariadic(id self, SEL _cmd, Args... args) { } void dealloc(id instance) override { - NSKVOClass::dealloc(instance); _deallocInstance(instance); + NSKVOClass::dealloc(instance); } // Two entrypoints into method swizzling: one key-based, one imp-based. diff --git a/Frameworks/Foundation/NSMutableURLRequest.mm b/Frameworks/Foundation/NSMutableURLRequest.mm index 46d51ed3e0..8d752c519b 100644 --- a/Frameworks/Foundation/NSMutableURLRequest.mm +++ b/Frameworks/Foundation/NSMutableURLRequest.mm @@ -130,13 +130,13 @@ - (void)setHTTPShouldUsePipelining:(BOOL)shouldPipeline { } - (id)copyWithZone:(NSZone*)zone { - NSURLRequest* ret = - [[NSMutableURLRequest alloc] initWithURL:(id)_url cachePolicy:0 timeoutInterval:30.0]; /* [BUG: Make it copy all properties] */ + NSURLRequest* ret = [[NSMutableURLRequest alloc] initWithURL:(id)_url + cachePolicy:NSURLRequestUseProtocolCachePolicy + timeoutInterval:30.0]; /* [BUG: Make it copy all properties] */ ret->_headerFields = [_headerFields mutableCopy]; ret->_method.attach([_method copy]); ret->_body.attach([_body copy]); ret->_shouldHandleCookies = _shouldHandleCookies; - ret->_shouldDiscardData = _shouldDiscardData; ret->_cachePolicy = _cachePolicy; ret->_bodyStream = _bodyStream; diff --git a/Frameworks/Foundation/NSNotificationCenter.mm b/Frameworks/Foundation/NSNotificationCenter.mm index ee32d0b625..0db97b4180 100644 --- a/Frameworks/Foundation/NSNotificationCenter.mm +++ b/Frameworks/Foundation/NSNotificationCenter.mm @@ -265,13 +265,15 @@ - (void)removeObserver:(id)observer name:(NSString*)name object:(id)object { } curObserver->valid = false; - CFArrayRemoveValueAtIndex((CFArrayRef)arr, i); if (curObserver->block != nil) { [curObserver->block release]; [curObserver->object release]; curObserver->block = nil; curObserver->object = nil; } + + // Remove the object *after* freeing its block and object + CFArrayRemoveValueAtIndex((CFArrayRef)arr, i); } if (CFArrayGetCount((CFArrayRef)arr) == 0) { diff --git a/Frameworks/Foundation/NSOperation.mm b/Frameworks/Foundation/NSOperation.mm index ca875edac6..cc7059ef93 100644 --- a/Frameworks/Foundation/NSOperation.mm +++ b/Frameworks/Foundation/NSOperation.mm @@ -24,13 +24,16 @@ @implementation NSOperation ++ (BOOL)automaticallyNotifiesObserversForKey:(NSString*)key { + // This class dispatches its own notifications. + return NO; +} + + (id)allocWithZone:(NSZone*)zone { NSOperation* ret = [super allocWithZone:zone]; ret->priv = new NSOperationPriv(); - [ret addObserver:(id)ret forKeyPath:@"isFinished" options:0 context:nil]; - return ret; } @@ -139,15 +142,53 @@ - (void)start { if (execute) { [self willChangeValueForKey:@"isExecuting"]; } - [self willChangeValueForKey:@"isFinished"]; - pthread_mutex_lock(&priv->finishLock); - priv->finished = 1; - [self didChangeValueForKey:@"isFinished"]; - if (execute) { - priv->executing = 0; - [self didChangeValueForKey:@"isExecuting"]; - } - pthread_mutex_unlock(&priv->finishLock); + + [self _setFinished:YES andPerformUnderLock:^{ + if (execute) { + priv->executing = 0; + [self didChangeValueForKey:@"isExecuting"]; + } + }]; + } +} + +/** + @Status Interoperable +*/ +- (void)setFinished:(BOOL)finished { + [self _setFinished:finished andPerformUnderLock:nil]; +} + +- (void)_setFinished:(BOOL)finished andPerformUnderLock:(void(^)())block { + // yes, this is ugly: priv->finished is an int though. + int newValue = finished ? 1 : 0; + pthread_mutex_lock(&priv->finishLock); + + [self willChangeValueForKey:@"isFinished"]; + + if (priv->finished != newValue) { + priv->finished = newValue; + } + + [self didChangeValueForKey:@"isFinished"]; + + if (block) { + block(); + } + + if (newValue == 1) { + pthread_cond_broadcast(&priv->finishCondition); + } + + pthread_mutex_unlock(&priv->finishLock); + + // This may seem unintuitive, but the completion + // block is intended to be called even if the operation + // is cancelled. + if (newValue == 1 && priv->completionBlock != nil) { + priv->completionBlock(); + [priv->completionBlock release]; + priv->completionBlock = nil; } } @@ -188,26 +229,8 @@ - (id)dependencies { return priv->dependencies; } -- (void)observeValueForKeyPath:(id)keyPath ofObject:(id)obj change:(id)changeDictionary context:(void*)context { - pthread_mutex_lock(&priv->finishLock); - int finished = [self isFinished]; - if (finished) { - pthread_cond_broadcast(&priv->finishCondition); - } - pthread_mutex_unlock(&priv->finishLock); - - // Someone might do something stupid like waitUntilFinished in the completion block, - // which would deadlock if these weren't separated. - if (finished && priv->completionBlock != nil) { - priv->completionBlock(); - [priv->completionBlock release]; - priv->completionBlock = nil; - } -} - - (void)dealloc { assert(priv->completionBlock == nil); - [self removeObserver:self forKeyPath:@"isFinished"]; delete priv; [super dealloc]; } diff --git a/Frameworks/Foundation/NSURL.mm b/Frameworks/Foundation/NSURL.mm index 1017d09196..b8c03148b7 100644 --- a/Frameworks/Foundation/NSURL.mm +++ b/Frameworks/Foundation/NSURL.mm @@ -23,6 +23,8 @@ #include "HashFn.h" #include "Etc.h" +#define NSURLMAXLEN SIZE_MAX + NSString* const NSURLFileScheme = @"NSURLFileScheme"; NSString* const NSURLAttributeModificationDateKey = @"NSURLAttributeModificationDateKey"; NSString* const NSURLContentAccessDateKey = @"NSURLContentAccessDateKey"; @@ -63,6 +65,14 @@ NSString* const NSURLTotalFileAllocatedSizeKey = @"NSURLTotalFileAllocatedSizeKey"; NSString* const NSURLFileSizeKey = @"NSURLFileSizeKey"; +static void StripSlashes(char* pPath) { + size_t length = strnlen_s(pPath, NSURLMAXLEN); + while (length > 0 && pPath[length - 1] == '/') { + pPath[length - 1] = '\0'; + length --; + } +} + struct EbrURL { xmlURIPtr uriForAppending() { // Copy our URI @@ -117,22 +127,24 @@ void ProcessURI() { // Remove parameters and any trailing / from the path we report to the app if (_uri->path) { - _path = (char*)malloc(strlen(_uri->path) + 1); - strcpy(_path, _uri->path); + size_t newSize = strnlen_s(_uri->path, NSURLMAXLEN) + 1; + _path = (char*)malloc(newSize); + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(_path, newSize, _uri->path) != 0); char* params = strstr(_path, ";"); if (params != NULL) { *params = 0; params++; - _parameters = (char*)malloc(strlen(params) + 1); - strcpy(_parameters, params); + size_t newParamSize = strnlen_s(params, NSURLMAXLEN) + 1; + _parameters = (char*)malloc(newParamSize); + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(_parameters, newParamSize, params) != 0); } - // Remove trailing / - if (strlen(_path) > 0) { - if (_path[strlen(_path) - 1] == '/') { - _path[strlen(_path) - 1] = 0; + // Remove trailing /, except in "/" case where the path points to root + if (strnlen_s(_path, newSize) > 1) { + if (_path[strnlen_s(_path, newSize) - 1] == '/') { + _path[strnlen_s(_path, newSize) - 1] = '\0'; } } } @@ -152,12 +164,17 @@ void ProcessURI() { } ~EbrURL() { - if (_uri) + if (_uri) { xmlFreeURI(_uri); - if (_parameters) + } + + if (_parameters) { free(_parameters); - if (_path) + } + + if (_path) { free(_path); + } } EbrURL() { @@ -184,24 +201,24 @@ void ProcessURI() { _uri = xmlCreateURI(); if (pScheme) { - _uri->scheme = (char*)xmlMalloc(strlen(pScheme) + 1); - strcpy(_uri->scheme, pScheme); + _uri->scheme = (char*)xmlMalloc(strnlen_s(pScheme, NSURLMAXLEN) + 1); + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(_uri->scheme, NSURLMAXLEN, pScheme) != 0); } if (pHost) { - _uri->server = (char*)xmlMalloc(strlen(pHost) + 1); - strcpy(_uri->server, pHost); + _uri->server = (char*)xmlMalloc(strnlen_s(pHost, NSURLMAXLEN) + 1); + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(_uri->server, NSURLMAXLEN, pHost) != 0); } if (pPath) { - _uri->path = (char*)xmlMalloc(strlen(pPath) + 1); - strcpy(_uri->path, pPath); + _uri->path = (char*)xmlMalloc(strnlen_s(pPath, NSURLMAXLEN) + 1); + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(_uri->path, NSURLMAXLEN, pPath) != 0); } ProcessURI(); } static char* escape(const char* in, const char* escapeChars) { - char* ret = (char*)malloc(strlen(in) * 3 + 1); + char* ret = (char*)malloc(strnlen_s(in, NSURLMAXLEN) * 3 + 1); int retLen = 0; - int inLen = strlen(in); + int inLen = strnlen_s(in, NSURLMAXLEN); const char* hex = "0123456789ABCDEF"; for (int i = 0; i < inLen; i++) { @@ -232,13 +249,16 @@ void ProcessURI() { char* escaped = escape(pStr, "{}\"[]"); _uri = xmlParseURI(escaped); - if (_uri) + if (_uri) { ProcessURI(); + } + if (!_uri) { char* str = (char*)xmlPathToURI((xmlChar*)escaped); _uri = xmlParseURI(str); xmlFree(str); } + free(escaped); if (_uri) { ProcessURI(); @@ -262,7 +282,7 @@ void SetBase(EbrURL* url) { ProcessURI(); } - void SetPath(char* path, char* params) { + void SetPath(const char* path, char* params) { char* oldPath = _path; char* oldParams = _parameters; @@ -272,54 +292,208 @@ void SetPath(char* path, char* params) { int newLen = 16; if (path) { - _path = (char*)malloc(strlen(path) + 1); - strcpy(_path, path); - newLen += strlen(_path); + _path = (char*)malloc(strnlen_s(path, NSURLMAXLEN) + 1); + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(_path, NSURLMAXLEN, path) != 0); + newLen += strnlen_s(_path, NSURLMAXLEN); } if (params) { - _parameters = (char*)malloc(strlen(params) + 1); - strcpy(_parameters, params); - newLen += strlen(params); + _parameters = (char*)malloc(strnlen_s(params, NSURLMAXLEN) + 1); + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(_parameters, NSURLMAXLEN, params) != 0); + newLen += strnlen_s(params, NSURLMAXLEN); } // Strip out parameter char* newPath = (char*)xmlMalloc(newLen); - strcpy(newPath, ""); - if (path) - strcat(newPath, path); + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(newPath, newLen, "") != 0); + if (path) { + FAIL_FAST_HR_IF(E_UNEXPECTED, strcat_s(newPath, newLen, path) != 0); + } + if (params) { - strcat(newPath, ";"); - strcat(newPath, params); + FAIL_FAST_HR_IF(E_UNEXPECTED, strcat_s(newPath, newLen, ";") != 0); + FAIL_FAST_HR_IF(E_UNEXPECTED, strcat_s(newPath, newLen, params) != 0); } xmlFree(_uri->path); _uri->path = newPath; - if (oldPath) + if (oldPath) { free(oldPath); - if (oldParams) + } + + if (oldParams) { free(oldParams); + } } void AppendPath(char* pPath) { int newLen = 16; - if (_path) - newLen += strlen(_path); - if (pPath) - newLen += strlen(pPath); + if (_path) { + newLen += strnlen_s(_path, NSURLMAXLEN); + } + + if (pPath) { + newLen += strnlen_s(pPath, NSURLMAXLEN); + } // Strip out parameter char* newPath = (char*)malloc(newLen); - strcpy(newPath, ""); - if (_path) - strcpy(newPath, _path); - strcat(newPath, "/"); - strcat(newPath, pPath); + auto cleanupTemps = wil::ScopeExit([&]() + { + free(newPath); + }); + + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(newPath, newLen, "") != 0); + if (_path) { + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(newPath, newLen, _path) != 0); + } + + FAIL_FAST_HR_IF(E_UNEXPECTED, strcat_s(newPath, newLen, "/") != 0); + FAIL_FAST_HR_IF(E_UNEXPECTED, strcat_s(newPath, newLen, pPath) != 0); xmlNormalizeURIPath(newPath); SetPath(newPath, _parameters); - free(newPath); + } + + void AppendExtension(const char* pPath) { + int newLen = 2; // size of "."; + + if (_path) { + newLen += strnlen_s(_path, NSURLMAXLEN); + } + + if (pPath) { + newLen += strnlen_s(pPath, NSURLMAXLEN); + } + + char* newPath = (char*)malloc(newLen); + auto cleanupTemps = wil::ScopeExit([&]() + { + free(newPath); + }); + + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(newPath, newLen, "") != 0); + if (_path) { + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(newPath, newLen, _path) != 0); + } + + if (0 != strcmp(newPath, "/")) { + StripSlashes(newPath); + } + + FAIL_FAST_HR_IF(E_UNEXPECTED, strcat_s(newPath, newLen, ".") != 0); + FAIL_FAST_HR_IF(E_UNEXPECTED, strcat_s(newPath, newLen, pPath) != 0); + SetPath(newPath, _parameters); + } + + void DeleteExtension() { + int newLen = 1; // size of "" + if (_path) { + newLen += strnlen_s(_path, NSURLMAXLEN); + } + + char* newPath = (char*)malloc(newLen); + auto cleanupTemps = wil::ScopeExit([&]() + { + free(newPath); + }); + + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(newPath, newLen, "") != 0); + if (_path) { + size_t lastComponentIndex = 0; + size_t extensionIndex = std::string::npos; + char* pLastComponent = strrchr(_path, '/'); + if (pLastComponent) { + lastComponentIndex = static_cast(pLastComponent - _path); + } + + char* pExtension = strrchr(_path, '.'); + if (pExtension) { + extensionIndex = static_cast(pExtension - _path); + } + + if (extensionIndex != std::string::npos && extensionIndex > lastComponentIndex) { + FAIL_FAST_HR_IF(E_UNEXPECTED, strncpy_s(newPath, newLen, _path, extensionIndex) != 0); + newPath[extensionIndex] = '\0'; + } else { + // If no extension exists within the url, simply return without changing _path + return; + } + } + + SetPath(newPath, _parameters); + } + + void DeleteLastPathComponent() { + int newLen = 5; // size of "/../" + if (_path) { + newLen += strnlen_s(_path, NSURLMAXLEN); + } + + char* newPath = (char*)malloc(newLen); + auto cleanupTemps = wil::ScopeExit([&]() + { + free(newPath); + }); + + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(newPath, newLen, "") != 0); + if (_path) { + char* pLastComponent = strrchr(_path, '/'); + size_t lastComponentIndex = std::string::npos; + if (pLastComponent) { + lastComponentIndex = static_cast(pLastComponent - _path); + } + + if (lastComponentIndex == 0) { + if (1 == strnlen_s(_path, NSURLMAXLEN)) { + // iOS behavior conflicts with documentation in this case. + // The documentation claims "/" is the new path, while actually "/../" is returned. + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(newPath, newLen, "/../") != 0); + } else { + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(newPath, newLen, "/") != 0); + } + } + else if (0 == strnlen_s(_path, NSURLMAXLEN)) { + // Edge case for when the path is empty + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(newPath, newLen, "../") != 0); + } + else if (lastComponentIndex != std::string::npos) { + FAIL_FAST_HR_IF(E_UNEXPECTED, strncpy_s(newPath, newLen, _path, lastComponentIndex) != 0); + newPath[lastComponentIndex] = '\0'; + } + } else { + // Edge case for when the path is empty + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(newPath, newLen, "../") != 0); + } + + SetPath(newPath, _parameters); + } + + void StandardizePath() { + NSString* path = [[NSString alloc] initWithUTF8String:_path]; + const char* standardizedPath = [[path stringByStandardizingPath] UTF8String]; + + int newLen = 1; // size of "" + if (_path) { + newLen += strnlen_s(standardizedPath, NSURLMAXLEN); + } + + char* newPath = (char*)malloc(newLen); + auto cleanupTemps = wil::ScopeExit([&]() + { + free(newPath); + }); + + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(newPath, newLen, "") != 0); + + if (standardizedPath) { + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(newPath, newLen, standardizedPath) != 0); + } + + xmlNormalizeURIPath(newPath); + SetPath(newPath, _parameters); + [path release]; } }; @@ -371,8 +545,9 @@ - (instancetype)initWithScheme:(NSString*)scheme host:(NSString*)host path:(NSSt @Status Interoperable */ - (instancetype)initFileURLWithPath:(NSString*)path { - if (path == nil) + if (path == nil) { return nil; + } NSURL* baseURL = nil; char szBasePath[4096] = ""; @@ -381,33 +556,30 @@ - (instancetype)initFileURLWithPath:(NSString*)path { EbrGetcwd(szBasePath, sizeof(szBasePath)); // Add trailing / - if (strlen(szBasePath) > 0 && szBasePath[strlen(szBasePath) - 1] != '/') - strcat(szBasePath, "/"); + if (strnlen_s(szBasePath, NSURLMAXLEN) > 0 && szBasePath[strnlen_s(szBasePath, NSURLMAXLEN) - 1] != '/') { + FAIL_FAST_HR_IF(E_UNEXPECTED, strcat_s(szBasePath, NSURLMAXLEN, "/") != 0); + } } const char* pPath = [path UTF8String]; - char* szPath = (char*)malloc(strlen(pPath) + 16); - strcpy(szPath, pPath); + char* szPath = (char*)malloc(strnlen_s(pPath, NSURLMAXLEN) + 16); + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(szPath, NSURLMAXLEN, pPath) != 0); // Strip trailing /'s - while (strlen(szPath) > 0 && szPath[strlen(szPath) - 1] == '/') { - szPath[strlen(szPath) - 1] = 0; + while (strnlen_s(szPath, NSURLMAXLEN) > 0 && szPath[strnlen_s(szPath, NSURLMAXLEN) - 1] == '/') { + szPath[strnlen_s(szPath, NSURLMAXLEN) - 1] = 0; } BOOL isDirectory = FALSE; - if (EbrAccess(szPath, 0) == -1 || EbrIsDir(szPath)) + if (EbrAccess(szPath, 0) == -1 || EbrIsDir(szPath)) { isDirectory = TRUE; + } + free(szPath); return [self initFileURLWithPath:path isDirectory:isDirectory]; } -static void StripSlashes(char* pPath) { - while (strlen(pPath) > 0 && pPath[strlen(pPath) - 1] == '/') { - pPath[strlen(pPath) - 1] = 0; - } -} - /** @Status Interoperable */ @@ -419,8 +591,9 @@ - (instancetype)initFileURLWithPath:(NSString*)path isDirectory:(BOOL)isDirector EbrGetcwd(szBasePath, sizeof(szBasePath)); // Add trailing / - if (strlen(szBasePath) > 0 && szBasePath[strlen(szBasePath) - 1] != '/') - strcat(szBasePath, "/"); + if (strnlen_s(szBasePath, NSURLMAXLEN) > 0 && szBasePath[strnlen_s(szBasePath, NSURLMAXLEN) - 1] != '/') { + FAIL_FAST_HR_IF(E_UNEXPECTED, strcat_s(szBasePath, NSURLMAXLEN, "/") != 0); + } baseURL = [NSURL alloc]; initPath(baseURL, "file", "localhost", szBasePath); @@ -428,17 +601,18 @@ - (instancetype)initFileURLWithPath:(NSString*)path isDirectory:(BOOL)isDirector } const char* pPath = [path UTF8String]; - char* szPath = (char*)malloc(strlen(pPath) + 16); - strcpy(szPath, pPath); + char* szPath = (char*)malloc(strnlen_s(pPath, NSURLMAXLEN) + 16); + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(szPath, NSURLMAXLEN, pPath) != 0); // Strip trailing /'s - while (strlen(szPath) > 0 && szPath[strlen(szPath) - 1] == '/') { - szPath[strlen(szPath) - 1] = 0; + while (strnlen_s(szPath, NSURLMAXLEN) > 0 && szPath[strnlen_s(szPath, NSURLMAXLEN) - 1] == '/') { + szPath[strnlen_s(szPath, NSURLMAXLEN) - 1] = 0; } if (isDirectory) { // Add trailing / - if (strlen(szPath) > 0 && szPath[strlen(szPath) - 1] != '/') - strcat(szPath, "/"); + if (strnlen_s(szPath, NSURLMAXLEN) > 0 && szPath[strnlen_s(szPath, NSURLMAXLEN) - 1] != '/') { + FAIL_FAST_HR_IF(E_UNEXPECTED, strcat_s(szPath, NSURLMAXLEN, "/") != 0); + } } if (baseURL == nil) { @@ -446,6 +620,7 @@ - (instancetype)initFileURLWithPath:(NSString*)path isDirectory:(BOOL)isDirector } else { initPath(self, NULL, NULL, szPath); } + free(szPath); buildFullURI(self, baseURL); @@ -460,6 +635,14 @@ - (instancetype)initWithString:(NSString*)string { return [self initWithString:string relativeToURL:nil]; } +/** + @Status Stub +*/ +- (NSURL*)fileReferenceURL { + UNIMPLEMENTED(); + return nil; +} + /** @Status Interoperable */ @@ -476,13 +659,14 @@ - (NSURL*)URLByAppendingPathComponent:(id)path isDirectory:(BOOL)isDirectory { return nil; } - NSURL* ret = [[self class] alloc]; + NSURL* ret = [[[self class] alloc] init]; const char* pPath = [path UTF8String]; - char* szPath = (char*)malloc(strlen(pPath) + 16); - strcpy(szPath, pPath); + char* szPath = (char*)malloc(strnlen_s(pPath, NSURLMAXLEN) + 16); + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(szPath, NSURLMAXLEN, pPath) != 0); StripSlashes(szPath); - if (isDirectory) - strcat(szPath, "/"); + if (isDirectory) { + FAIL_FAST_HR_IF(E_UNEXPECTED, strcat_s(szPath, NSURLMAXLEN, "/") != 0); + } ret->_uri = _uri->Clone(); ret->_uri->AppendPath(szPath); @@ -492,12 +676,68 @@ - (NSURL*)URLByAppendingPathComponent:(id)path isDirectory:(BOOL)isDirectory { return [ret autorelease]; } + +/** + @Status Interoperable +*/ +- (NSURL*)URLByAppendingPathExtension:(NSString*)pathExtension { + NSURL* ret = [[[self class] alloc] init]; + + ret->_uri = _uri->Clone(); + ret->_uri->AppendExtension([pathExtension UTF8String]); + buildFullURI(ret, nil); + + return [ret autorelease]; +} + +/** + @Status Interoperable +*/ +- (NSURL*)URLByDeletingLastPathComponent { + NSURL* ret = [[[self class] alloc] init]; + ret->_uri = _uri->Clone(); + ret->_uri->DeleteLastPathComponent(); + return [ret autorelease]; +} + +/** + @Status Interoperable +*/ +- (NSURL*) URLByDeletingPathExtension { + NSURL* ret = [[[self class] alloc] init]; + ret->_uri = _uri->Clone(); + ret->_uri->DeleteExtension(); + return [ret autorelease]; +} + +/** + @Status Stub +*/ +- (NSURL*) URLByResolvingSymlinksInPath { + UNIMPLEMENTED(); + return self; +} + +/** + @Status Caveat + @Notes Does not resolve symlinks in path or check /private + */ +- (NSURL*) URLByStandardizingPath { + NSURL* ret = [[[self class] alloc] init]; + ret->_uri = _uri->Clone(); + if ([[self scheme] isEqualToString:@"file"]) { + ret->_uri->StandardizePath(); + } + return [ret autorelease]; +} + /** @Status Interoperable */ - (instancetype)initWithString:(id)string relativeToURL:(id)parent { - if (string == nil) + if (string == nil) { return nil; + } const char* pURL = [string UTF8String]; buildURIs(self, pURL, parent); @@ -510,15 +750,17 @@ - (instancetype)initWithString:(id)string relativeToURL:(id)parent { } - (id)initWithString:(id)string relativeToURL:(id)parent isDirectory:(DWORD)isDirectory { - if (string == nil) + if (string == nil) { return nil; + } const char* pURL = [string UTF8String]; - char* szPath = (char*)malloc(strlen(pURL) + 16); - strcpy(szPath, pURL); + char* szPath = (char*)malloc(strnlen_s(pURL, NSURLMAXLEN) + 16); + FAIL_FAST_HR_IF(E_UNEXPECTED, strcpy_s(szPath, NSURLMAXLEN, pURL) != 0); StripSlashes(szPath); - if (isDirectory) - strcat(szPath, "/"); + if (isDirectory) { + FAIL_FAST_HR_IF(E_UNEXPECTED, strcat_s(szPath, NSURLMAXLEN, "/") != 0); + } buildURIs(self, szPath, parent); free(szPath); @@ -560,10 +802,14 @@ + (NSURL*)URLWithString:(id)string relativeToURL:(id)parent { - (void)dealloc { [_baseURL release]; - if (_uri) + if (_uri) { delete _uri; - if (_fullUri) + } + + if (_fullUri) { delete _fullUri; + } + _absoluteString = nil; [super dealloc]; @@ -601,7 +847,7 @@ - (void)encodeWithCoder:(NSCoder*)coder { - (unsigned)hash { if (_fullUri->_path) { - return murmurHash3(_fullUri->_path, strlen(_fullUri->_path), 0x834cba12); + return murmurHash3(_fullUri->_path, strnlen_s(_fullUri->_path, NSURLMAXLEN), 0x834cba12); } return 0; } @@ -609,53 +855,15 @@ - (unsigned)hash { - (BOOL)isEqual:(id)other { NSURL* otherURL; - if (self == other) + if (self == other) { return YES; + } - if (![other isKindOfClass:[NSURL class]]) - return NO; - - otherURL = other; - if (otherURL->_fullUri->_scheme && _fullUri->_scheme) { - if (strcmp(otherURL->_fullUri->_scheme, _fullUri->_scheme) != 0) - return NO; - } else if (otherURL->_fullUri->_scheme != _fullUri->_scheme) - return NO; - - if (otherURL->_fullUri->_server && _fullUri->_server) { - if (strcmp(otherURL->_fullUri->_server, _fullUri->_server) != 0) - return NO; - } else if (otherURL->_fullUri->_server != _fullUri->_server) - return NO; - - if (otherURL->_fullUri->_path && _fullUri->_path) { - if (strcmp(otherURL->_fullUri->_path, _fullUri->_path) != 0) - return NO; - } else if (otherURL->_fullUri->_path != _fullUri->_path) - return NO; - - if (otherURL->_fullUri->_parameters && _fullUri->_parameters) { - if (strcmp(otherURL->_fullUri->_parameters, _fullUri->_parameters) != 0) - return NO; - } else if (otherURL->_fullUri->_parameters != _fullUri->_parameters) - return NO; - - if (otherURL->_fullUri->_query && _fullUri->_query) { - if (strcmp(otherURL->_fullUri->_query, _fullUri->_query) != 0) - return NO; - } else if (otherURL->_fullUri->_query != _fullUri->_query) - return NO; - - if (otherURL->_fullUri->_fragment && _fullUri->_fragment) { - if (strcmp(otherURL->_fullUri->_fragment, _fullUri->_fragment) != 0) - return NO; - } else if (otherURL->_fullUri->_fragment != _fullUri->_fragment) - return NO; - - if (otherURL->_fullUri->_port != _fullUri->_port) + if (![other isKindOfClass:[NSURL class]]) { return NO; + } - return YES; + return ([[other absoluteString] isEqual:[self absoluteString]]); } /** @@ -666,8 +874,10 @@ - (NSString*)relativeString { return [self absoluteString]; } else { char* uriStr = (char*)xmlSaveUri(_uri->_uri); - if (uriStr == NULL) + if (uriStr == NULL) { return nil; + } + id ret = [NSString stringWithCString:uriStr]; xmlFree(uriStr); @@ -682,14 +892,18 @@ - (NSString*)absoluteString { if (_absoluteString == nil) { if (_fullUri) { char* uriStr = (char*)xmlSaveUri(_fullUri->_uri); - if (uriStr == NULL) + if (uriStr == NULL) { return nil; + } + _absoluteString = [NSString stringWithCString:uriStr]; xmlFree(uriStr); } else { char* uriStr = (char*)xmlSaveUri(_uri->_uri); - if (uriStr == NULL) + if (uriStr == NULL) { return nil; + } + _absoluteString = [NSString stringWithCString:uriStr]; xmlFree(uriStr); } @@ -703,8 +917,9 @@ - (NSString*)absoluteString { */ - (NSString*)resourceSpecifier { char* uriStr = (char*)xmlSaveUri(_fullUri->_uri); - if (uriStr == NULL) + if (uriStr == NULL) { return nil; + } char* schemeSkipped = uriStr; if (_fullUri->_scheme != NULL) { @@ -725,8 +940,9 @@ - (NSString*)resourceSpecifier { @Status Interoperable */ - (NSString*)parameterString { - if (!_fullUri->_parameters) + if (!_fullUri->_parameters) { return nil; + } id ret = [NSString stringWithCString:(char*)_fullUri->_parameters]; @@ -737,10 +953,13 @@ - (NSString*)parameterString { @Status Interoperable */ - (NSString*)scheme { - if (!_fullUri) + if (!_fullUri) { return nil; - if (!_fullUri->_scheme) + } + + if (!_fullUri->_scheme) { return nil; + } id ret = [NSString stringWithCString:(char*)_fullUri->_scheme]; @@ -751,11 +970,13 @@ - (NSString*)scheme { @Status Interoperable */ - (NSString*)host { - if (!_fullUri) + if (!_fullUri) { return nil; + } - if (!_fullUri->_server) + if (!_fullUri->_server) { return @""; + } id ret = [NSString stringWithCString:(char*)_fullUri->_server]; @@ -766,8 +987,9 @@ - (NSString*)host { @Status Interoperable */ - (NSString*)fragment { - if (!_fullUri->_fragment) + if (!_fullUri->_fragment) { return nil; + } id ret = [NSString stringWithCString:(char*)_fullUri->_fragment]; @@ -778,10 +1000,13 @@ - (NSString*)fragment { @Status Interoperable */ - (id)path { - if (!_fullUri) + if (!_fullUri) { return nil; - if (!_fullUri->_path) + } + + if (!_fullUri->_path) { return nil; + } id ret = [NSString stringWithCString:(char*)_fullUri->_path]; @@ -799,8 +1024,9 @@ - (id)pathComponents { @Status Interoperable */ - (id)port { - if (_fullUri->_port == -1) + if (_fullUri->_port == -1) { return nil; + } return [NSNumber numberWithInt:_fullUri->_port]; } @@ -809,8 +1035,9 @@ - (id)port { @Status Interoperable */ - (id)query { - if (!_fullUri->_query) + if (!_fullUri->_query) { return nil; + } id ret = [NSString stringWithCString:(char*)_fullUri->_query]; @@ -821,8 +1048,9 @@ - (id)query { @Status Interoperable */ - (id)relativePath { - if (!_uri->_path) + if (!_uri->_path) { return nil; + } id ret = [NSString stringWithCString:(char*)_uri->_path]; @@ -851,8 +1079,9 @@ - (id)description { @Status Interoperable */ - (id)absoluteURL { - if (_baseURL == nil) + if (_baseURL == nil) { return self; + } return [NSURL URLWithString:[self absoluteString]]; } @@ -892,8 +1121,9 @@ - (id)baseURL { */ - (BOOL)setResourceValue:(id)value forKey:(id)key error:(NSError**)error { UNIMPLEMENTED(); - if (error) + if (error) { *error = nil; + } EbrDebugLog("NSURL::setResourceValue not supported\n"); return TRUE; } diff --git a/Frameworks/Foundation/NSURLConnection.mm b/Frameworks/Foundation/NSURLConnection.mm index ab8ba70e7b..32058ab59a 100644 --- a/Frameworks/Foundation/NSURLConnection.mm +++ b/Frameworks/Foundation/NSURLConnection.mm @@ -22,7 +22,7 @@ #include "NSURLConnectionState.h" #include "Foundation/NSURLConnection.h" -@implementation NSURLConnection : NSObject +@implementation NSURLConnection /** @Status Interoperable @@ -50,9 +50,9 @@ + (void)sendAsynchronousRequest:(id)request @Status Caveat @Notes NSError returned is not detailed */ -+ (id)sendSynchronousRequest:(id)request returningResponse:(NSURLResponse**)responsep error:(NSError**)errorp { - id state = [[[NSURLConnectionState alloc] init] autorelease]; - id connection = [[self alloc] initWithRequest:request delegate:state startImmediately:FALSE]; ++ (NSData*)sendSynchronousRequest:(id)request returningResponse:(NSURLResponse**)responsep error:(NSError**)errorp { + NSURLConnectionState* state = [[[NSURLConnectionState alloc] init] autorelease]; + NSURLConnection* connection = [[self alloc] initWithRequest:request delegate:state startImmediately:FALSE]; if (connection == nil) { if (errorp != NULL) { @@ -70,16 +70,16 @@ + (id)sendSynchronousRequest:(id)request returningResponse:(NSURLResponse**)resp [state receiveAllDataInMode:mode]; [connection unscheduleFromRunLoop:[NSRunLoop currentRunLoop] forMode:mode]; - id result = [[((NSURLConnection*)connection)->_mutableData retain] autorelease]; + id result = state.receivedData; [connection cancel]; if (errorp != NULL) { - *errorp = [state error]; + *errorp = state.error; } if (responsep != NULL) { - *responsep = [[((NSURLConnection*)connection)->_response retain] autorelease]; + *responsep = state.response; } [connection release]; @@ -132,7 +132,6 @@ - (void)dealloc { [_protocol release]; [_delegate release]; [_response release]; - [_mutableData release]; [super dealloc]; } @@ -190,11 +189,6 @@ - (id)URLProtocol:(id)urlProtocol willSendRequest:(id)request redirectResponse:( - (void)URLProtocol:(id)urlProtocol didReceiveResponse:(id)response cacheStoragePolicy:(NSURLCacheStoragePolicy)policy { EbrDebugLog("URL protocol did receive response\n"); - - if (_mutableData == nil) { - _mutableData = [[NSMutableData alloc] init]; - } - /* if ( [response respondsToSelector:@selector(statusCode)] && [response statusCode] != 200 ) { [_delegate setError:[NSError errorWithDomain:@"Bad response code" code:[response statusCode] userInfo:nil]]; @@ -214,14 +208,6 @@ - (void)URLProtocol:(id)urlProtocol didReceiveResponse:(id)response cacheStorage - (void)URLProtocol:(id)urlProtocol didLoadData:(id)data { EbrDebugLog("URL protocol did load data\n"); - if (_mutableData == nil) { - _mutableData = [[NSMutableData alloc] init]; - } - - if (![_request _shouldDiscardData]) { - [_mutableData appendData:data]; - } - if ([_delegate respondsToSelector:@selector(connection:didReceiveData:)]) { [_delegate connection:self didReceiveData:data]; } diff --git a/Frameworks/Foundation/NSURLConnectionState.h b/Frameworks/Foundation/NSURLConnectionState.h index 42d83fd837..86dd5db85c 100644 --- a/Frameworks/Foundation/NSURLConnectionState.h +++ b/Frameworks/Foundation/NSURLConnectionState.h @@ -19,15 +19,13 @@ BOOL _isRunning; id _error; idretain _wakeUp; + NSMutableData* _receivedData; } -- (BOOL)isRunning; +@property (nonatomic, readonly, retain) NSData* receivedData; +@property (nonatomic, readonly, retain) NSURLResponse* response; +@property (nonatomic, readonly, retain) NSError* error; - (id)init; -- (id)dealloc; -- (id)receiveAllDataInMode:(id)mode; -- (id)connection:(id)connection didReceiveData:(id)data; -- (id)setError:(id)error; -- (id)error; -- (id)_doneWakeup; -- (id)connection:(id)connection didFailWithError:(id)error; -- (id)connectionDidFinishLoading:(id)connection; +- (BOOL)isRunning; +- (void)receiveAllDataInMode:(id)mode; +- (void)_doneWakeup; @end diff --git a/Frameworks/Foundation/NSURLConnectionState.mm b/Frameworks/Foundation/NSURLConnectionState.mm index 28caba5fac..3c5056dc97 100644 --- a/Frameworks/Foundation/NSURLConnectionState.mm +++ b/Frameworks/Foundation/NSURLConnectionState.mm @@ -19,27 +19,39 @@ #include "Foundation/NSDate.h" #include "NSRunLoopSource.h" -@implementation NSURLConnectionState : NSObject +@interface NSURLConnectionState () +@property (nonatomic, readwrite, retain) NSError* error; +@property (nonatomic, readwrite, retain) NSURLResponse* response; +@end + +@implementation NSURLConnectionState - (id)init { - _isRunning = YES; - _error = nil; - _wakeUp.attach([NSRunLoopSource new]); - [_wakeUp setSourceDelegate:(id)self selector:@selector(_doneWakeup)]; + if(self = [super init]) { + _error = nil; + _wakeUp.attach([NSRunLoopSource new]); + [_wakeUp setSourceDelegate:(id)self selector:@selector(_doneWakeup)]; + } return self; } -- (id)dealloc { +- (void)dealloc { [_error release]; _wakeUp = nil; + [_receivedData release]; [super dealloc]; - return self; +} + +- (NSData*)receivedData { + return [[_receivedData retain] autorelease]; } - (BOOL)isRunning { return _isRunning; } -- (id)receiveAllDataInMode:(id)mode { +- (void)receiveAllDataInMode:(id)mode { + _isRunning = YES; + [[NSRunLoop currentRunLoop] addInputSource:(id)_wakeUp forMode:mode]; while ([self isRunning]) { @@ -47,39 +59,32 @@ - (id)receiveAllDataInMode:(id)mode { } [[NSRunLoop currentRunLoop] removeInputSource:(id)_wakeUp forMode:mode]; - - return self; } -- (id)connection:(id)connection didReceiveData:(id)data { - return self; +- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response { + // We get some of these for each redirect. We want explicitly to only capture the final one. + self.response = response; + [_receivedData release]; + _receivedData = [[NSMutableData alloc] init]; } -- (id)setError:(id)error { - _error = [error retain]; - return self; +- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data { + [_receivedData appendData:data]; } -- (id)error { - return _error; -} +- (void)_doneWakeup { -- (id)_doneWakeup { - return self; } -- (id)connection:(id)connection didFailWithError:(id)error { +- (void)connection:(id)connection didFailWithError:(id)error { _isRunning = NO; - _error = [error retain]; + self.error = error; [_wakeUp _trigger]; - - return self; } -- (id)connectionDidFinishLoading:(id)connection { +- (void)connectionDidFinishLoading:(id)connection { _isRunning = NO; [_wakeUp _trigger]; - return self; } @end diff --git a/Frameworks/Foundation/NSURLCredentialStorage.mm b/Frameworks/Foundation/NSURLCredentialStorage.mm new file mode 100644 index 0000000000..e6c51d5e01 --- /dev/null +++ b/Frameworks/Foundation/NSURLCredentialStorage.mm @@ -0,0 +1,31 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#import +#import +#import + +@implementation NSURLCredentialStorage + +- (instancetype)init { + self = [super init]; + return self; +} + ++ (NSURLCredentialStorage*)sharedCredentialStorage { + return [[[NSURLCredentialStorage alloc] init] autorelease]; +} +@end \ No newline at end of file diff --git a/Frameworks/Foundation/NSURLRequest.mm b/Frameworks/Foundation/NSURLRequest.mm index 2244486cc5..01baa530e8 100644 --- a/Frameworks/Foundation/NSURLRequest.mm +++ b/Frameworks/Foundation/NSURLRequest.mm @@ -50,14 +50,14 @@ - (id)init { @Status Interoperable */ - (id)initWithURL:(id)url { - return [self initWithURL:url cachePolicy:nil timeoutInterval:30.0]; + return [self initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30.0]; } /** @Status Interoperable */ + (id)requestWithURL:(id)url { - id ret = [[self alloc] initWithURL:url cachePolicy:nil timeoutInterval:30.0]; + id ret = [[self alloc] initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30.0]; return [ret autorelease]; } @@ -119,12 +119,12 @@ + (id)requestWithURL:(id)url cachePolicy:(NSURLRequestCachePolicy)cachePolicy ti } - (id)mutableCopy { - NSURLRequest* ret = [[NSMutableURLRequest alloc] initWithURL:(id)_url cachePolicy:0 timeoutInterval:30.0]; + NSURLRequest* ret = + [[NSMutableURLRequest alloc] initWithURL:(id)_url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30.0]; ret->_headerFields = [_headerFields mutableCopy]; ret->_method.attach([_method copy]); ret->_body.attach([_body copy]); ret->_shouldHandleCookies = _shouldHandleCookies; - ret->_shouldDiscardData = _shouldDiscardData; ret->_cachePolicy = _cachePolicy; ret->_bodyStream = _bodyStream; @@ -167,16 +167,6 @@ - (id)valueForHTTPHeaderField:(id)field { return nil; } -- (id)_setShouldDiscardData:(BOOL)shouldDiscardData { - _shouldDiscardData = shouldDiscardData != FALSE; - - return 0; -} - -- (BOOL)_shouldDiscardData { - return _shouldDiscardData; -} - /** @Status Interoperable */ diff --git a/Frameworks/Foundation/NSURLSession.mm b/Frameworks/Foundation/NSURLSession.mm index a7c9e0d7ab..60226eac62 100644 --- a/Frameworks/Foundation/NSURLSession.mm +++ b/Frameworks/Foundation/NSURLSession.mm @@ -29,10 +29,6 @@ @implementation NSURLSessionDataTask @end -@implementation NSURLSessionConfiguration - -@end - @implementation NSURLSession @end diff --git a/Frameworks/Foundation/NSURLSessionConfiguration.mm b/Frameworks/Foundation/NSURLSessionConfiguration.mm new file mode 100644 index 0000000000..b0086bfa6b --- /dev/null +++ b/Frameworks/Foundation/NSURLSessionConfiguration.mm @@ -0,0 +1,115 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#import +#import +#import + +@interface NSURLSessionConfiguration () +@property (readwrite, copy) NSString* identifier; +@end + +@implementation NSURLSessionConfiguration + +- (instancetype)_initWithSharedDefaults { + if (self = [super init]) { + _allowsCellularAccess = YES; + _timeoutIntervalForRequest = 60; + _timeoutIntervalForResource = 7; + _HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain; + _HTTPCookieStorage = [[NSHTTPCookieStorage sharedHTTPCookieStorage] retain]; + _HTTPShouldSetCookies = YES; + _networkServiceType = NSURLNetworkServiceTypeDefault; + _requestCachePolicy = NSURLRequestUseProtocolCachePolicy; + _HTTPMaximumConnectionsPerHost = 6; + //_URLCredentialStorage = [[NSURLCredentialStorage sharedCredentialStorage] retain]; + } + + return self; +} + +- (instancetype)_initTLSAndCache { + if (self = [self _initWithSharedDefaults]) { + _TLSMaximumSupportedProtocol = kTLSProtocol12; + _TLSMinimumSupportedProtocol = kTLSProtocol1; + _URLCache = [[NSURLCache sharedURLCache] retain]; + } + return self; +} + +- (instancetype)init { + if (self = [self _initWithSharedDefaults]) { + _TLSMaximumSupportedProtocol = kTLSProtocol12; + _TLSMinimumSupportedProtocol = kSSLProtocol3; + } + return self; +} + +- (instancetype)initEphemeralSession { + self = [self _initTLSAndCache]; + return self; +} + +- (instancetype)initBackgroundSession:(NSString*)identifier { + if (self = [self _initTLSAndCache]) { + _identifier = identifier; + } + return self; +} + +- (id)copyWithZone:(NSZone*)zone { + NSURLSessionConfiguration* copy = [[self class] allocWithZone:zone]; + copy.identifier = _identifier; + copy.networkServiceType = _networkServiceType; + copy.allowsCellularAccess = _allowsCellularAccess; + copy.timeoutIntervalForRequest = _timeoutIntervalForRequest; + copy.timeoutIntervalForResource = _timeoutIntervalForResource; + copy.HTTPCookieAcceptPolicy = _HTTPCookieAcceptPolicy; + copy.HTTPCookieStorage = [[_HTTPCookieStorage copy] autorelease]; + copy.HTTPShouldSetCookies = _HTTPShouldSetCookies; + copy.TLSMaximumSupportedProtocol = _TLSMaximumSupportedProtocol; + copy.TLSMinimumSupportedProtocol = _TLSMinimumSupportedProtocol; + copy.URLCredentialStorage = [[_URLCredentialStorage copy] autorelease]; + copy.URLCache = [[_URLCache copy] autorelease]; + copy.requestCachePolicy = _requestCachePolicy; + copy.HTTPMaximumConnectionsPerHost = _HTTPMaximumConnectionsPerHost; + copy.HTTPAdditionalHeaders = _HTTPAdditionalHeaders; + copy.sharedContainerIdentifier = _sharedContainerIdentifier; + copy.sessionSendsLaunchEvents = _sessionSendsLaunchEvents; + copy.discretionary = _discretionary; + copy.protocolClasses = _protocolClasses; + copy.HTTPShouldUsePipelining = _HTTPShouldUsePipelining; + copy.connectionProxyDictionary = _connectionProxyDictionary; + return copy; +} + ++ (NSURLSessionConfiguration*)defaultSessionConfiguration { + return [[[NSURLSessionConfiguration alloc] init] autorelease]; +} + ++ (NSURLSessionConfiguration*)ephemeralSessionConfiguration { + return [[[NSURLSessionConfiguration alloc] initEphemeralSession] autorelease]; +} + ++ (NSURLSessionConfiguration*)backgroundSessionConfigurationWithIdentifier:(NSString*)identifier { + return [[[NSURLSessionConfiguration alloc] initBackgroundSession:identifier] autorelease]; +} + ++ (NSURLSessionConfiguration*)backgroundSessionConfiguration:(NSString*)identifier { + return [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:identifier]; +} + +@end \ No newline at end of file diff --git a/Frameworks/Foundation/NSUserDefaults.mm b/Frameworks/Foundation/NSUserDefaults.mm index 73b0ac2093..1ea7d03d32 100644 --- a/Frameworks/Foundation/NSUserDefaults.mm +++ b/Frameworks/Foundation/NSUserDefaults.mm @@ -80,7 +80,7 @@ - (instancetype)init { return self; } -+ (BOOL)automaticallyNotifiersObserversForKey:(NSString*)key { ++ (BOOL)automaticallyNotifiesObserversForKey:(NSString*)key { // This class uses setObject:forKey: as a setter, and has no key-specific setters. return NO; } diff --git a/Frameworks/Foundation/NSValueTransformers.h b/Frameworks/Foundation/NSValueTransformers.h index d9151f7879..10f70ac9ff 100644 --- a/Frameworks/Foundation/NSValueTransformers.h +++ b/Frameworks/Foundation/NSValueTransformers.h @@ -76,6 +76,72 @@ id valueFromDataWithType(void* data, const char* objcType) { } return [NSValue valueWithBytes:data objCType:objcType]; } + +bool dataWithTypeFromValue(void* data, const char* objcType, id value) { + switch (objcType[0]) { + case '@': + woc::ValueTransformer::store(value, data); + break; + case '#': + woc::ValueTransformer::store(value, data); + break; + case 'c': + woc::ValueTransformer::store(value, data); + break; + case 'i': + woc::ValueTransformer::store(value, data); + break; + case 's': + woc::ValueTransformer::store(value, data); + break; + case 'l': + woc::ValueTransformer::store(value, data); + break; + case 'q': + woc::ValueTransformer::store(value, data); + break; + case 'C': + woc::ValueTransformer::store(value, data); + break; + case 'I': + woc::ValueTransformer::store(value, data); + break; + case 'S': + woc::ValueTransformer::store(value, data); + break; + case 'L': + woc::ValueTransformer::store(value, data); + break; + case 'Q': + woc::ValueTransformer::store(value, data); + break; + case 'f': + woc::ValueTransformer::store(value, data); + break; + case 'd': + woc::ValueTransformer::store(value, data); + break; + case 'B': + woc::ValueTransformer::store(value, data); + break; + case '*': + case '^': + case '?': + // We cannot box/unbox arbitrary pointers or char*. + return false; + default: + NSValue* nsv = static_cast(value); + if (getArgumentSize(objcType) == getArgumentSize([nsv objCType])) { + [nsv getValue:data]; + } else { + // If the argument types don't match in size, we just say + // that this key can't be coded. + return false; + } + break; + } + return true; +} } template <> diff --git a/Frameworks/QuartzCore/CALayer.mm b/Frameworks/QuartzCore/CALayer.mm index 406b29cd0b..3915d75fc0 100644 --- a/Frameworks/QuartzCore/CALayer.mm +++ b/Frameworks/QuartzCore/CALayer.mm @@ -2349,6 +2349,11 @@ + (CGRect)convertRect:(CGRect)pos fromLayer:(CALayer*)fromLayer toLayer:(CALayer - (NSObject*)presentationValueForKey:(NSString*)key { return GetCACompositor()->getDisplayProperty(priv->_presentationNode, [key UTF8String]); } + +- (void)updateAccessibilityInfo:(const IWAccessibilityInfo*)info { + GetCACompositor()->SetAccessibilityInfo([self _presentationNode], *info); +} + @end void SetCACompositor(CACompositorInterface* compositorInterface) { diff --git a/Frameworks/StarboardXaml/CompositorInterface.h b/Frameworks/StarboardXaml/CompositorInterface.h index af3209b135..deb4be1493 100644 --- a/Frameworks/StarboardXaml/CompositorInterface.h +++ b/Frameworks/StarboardXaml/CompositorInterface.h @@ -150,6 +150,8 @@ class DisplayTextureXamlGlyphs : public DisplayTexture { float _fontSize; float _lineHeight; bool _centerVertically; + bool _isBold = false; + bool _isItalic = false; DisplayTextureXamlGlyphs(); ~DisplayTextureXamlGlyphs(); @@ -163,6 +165,7 @@ class DisplayTextureXamlGlyphs : public DisplayTexture { #include class CAXamlCompositor; +struct IWAccessibilityInfo; class DisplayNode : public RefCountedType { friend class CAXamlCompositor; @@ -191,6 +194,7 @@ class DisplayNode : public RefCountedType { void SetContents(DisplayTexture* tex, float width, float height, float scale); void SetContentsElement(winobjc::Id& elem, float width, float height, float scale); void SetContentsElement(winobjc::Id& elem); + void SetAccessibilityInfo(const IWAccessibilityInfo& info); float GetPresentationPropertyValue(const char* name); void AddToRoot(); diff --git a/Frameworks/StarboardXaml/CompositorInterface.mm b/Frameworks/StarboardXaml/CompositorInterface.mm index 996362fd83..ab6dbb24f8 100644 --- a/Frameworks/StarboardXaml/CompositorInterface.mm +++ b/Frameworks/StarboardXaml/CompositorInterface.mm @@ -338,6 +338,9 @@ void SetParams(UIFont* font, _centerVertically = centerVertically; _lineHeight = [font ascender] - [font descender]; + int mask = [font fontDescriptor].symbolicTraits; + _isBold = (mask & UIFontDescriptorTraitBold) > 0; + _isItalic = (mask & UIFontDescriptorTraitItalic) > 0; ConstructGlyphs([[font fontName] UTF8String], (const wchar_t*)[text rawCharacters], [text length]); } }; @@ -1259,6 +1262,10 @@ void DecrementCounter(const char* name) { GenericControlXaml* genericControlTexture = new GenericControlXaml([(RTObject*)xamlElement internalObject]); return genericControlTexture; } + + virtual void SetAccessibilityInfo(DisplayNode* node, const IWAccessibilityInfo& info) override { + node->SetAccessibilityInfo(info); + } }; void SetUIHandlers(); @@ -1306,4 +1313,4 @@ void IWXamlKeyInput(int key) { void GridSizeChanged(float newWidth, float newHeight) { [[UIApplication displayMode] _setWindowSize:CGSizeMake(newWidth, newHeight)]; [[UIApplication displayMode] _updateDisplaySettings]; -} \ No newline at end of file +} diff --git a/Frameworks/StarboardXaml/XamlCompositor.cpp b/Frameworks/StarboardXaml/XamlCompositor.cpp index 74cb1c655a..b65448856d 100644 --- a/Frameworks/StarboardXaml/XamlCompositor.cpp +++ b/Frameworks/StarboardXaml/XamlCompositor.cpp @@ -24,6 +24,9 @@ #include #include #include + +#include + using namespace Windows::Storage::Streams; using namespace Microsoft::WRL; @@ -323,6 +326,17 @@ void DisplayNode::SetBackgroundColor(float r, float g, float b, float a) { } } +void DisplayNode::SetAccessibilityInfo(const IWAccessibilityInfo& info) { + /* Disabled for now + XamlCompositorCS::Controls::CALayerXaml^ xamlNode = GetCALayer(this); + auto peer = + (XamlCompositorCS::Controls::CALayerXamlAutomationPeer^)Windows::UI::Xaml::Automation::Peers::FrameworkElementAutomationPeer::FromElement(xamlNode); + + assert(xamlNode != nullptr); + assert(peer != nullptr); + */ +} + void UpdateRootNode() { } @@ -544,6 +558,8 @@ DisplayTextureXamlGlyphs::~DisplayTextureXamlGlyphs() { _xamlTextbox.Set(NULL); } +Platform::String ^ charToPlatformString(const char* str); + void DisplayTextureXamlGlyphs::ConstructGlyphs(const char* fontName, const wchar_t* str, int length) { XamlCompositorCS::Controls::CATextLayerXaml ^ textLayer = (XamlCompositorCS::Controls::CATextLayerXaml ^ )(Platform::Object ^ )_xamlTextbox; @@ -556,6 +572,14 @@ void DisplayTextureXamlGlyphs::ConstructGlyphs(const char* fontName, const wchar textColor.B = (unsigned char)(_color[2] * 255.0f); textColor.A = (unsigned char)(_color[3] * 255.0f); textControl->Foreground = ref new Windows::UI::Xaml::Media::SolidColorBrush(textColor); + textControl->FontFamily = ref new Windows::UI::Xaml::Media::FontFamily(charToPlatformString(fontName)); + if (_isBold) { + textControl->FontWeight = Windows::UI::Text::FontWeights::Bold; + } + + if (_isItalic) { + textControl->FontStyle = Windows::UI::Text::FontStyle::Italic; + } switch (_horzAlignment) { case alignLeft: @@ -575,6 +599,15 @@ void DisplayTextureXamlGlyphs::ConstructGlyphs(const char* fontName, const wchar textControl->LineHeight = _lineHeight; } +Platform::String ^ charToPlatformString(const char* str) { + if (!str) { + return nullptr; + } + + std::wstring widStr(str, str + strlen(str)); + return ref new Platform::String(widStr.c_str()); +} + void DisplayTextureXamlGlyphs::Measure(float width, float height) { XamlCompositorCS::Controls::CATextLayerXaml ^ textLayer = (XamlCompositorCS::Controls::CATextLayerXaml ^ )(Platform::Object ^ )_xamlTextbox; diff --git a/Frameworks/UIKit/UIAccessibility.mm b/Frameworks/UIKit/UIAccessibility.mm new file mode 100644 index 0000000000..295ffacc97 --- /dev/null +++ b/Frameworks/UIKit/UIAccessibility.mm @@ -0,0 +1,90 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#include "Starboard.h" +#include "AccessibilityInternal.h" + +#import + +UIAccessibilityTraits UIAccessibilityTraitNone = 0; +UIAccessibilityTraits UIAccessibilityTraitButton = ACC_FLAG_BUTTON; +UIAccessibilityTraits UIAccessibilityTraitLink = ACC_FLAG_LINK; +UIAccessibilityTraits UIAccessibilityTraitSearchField = ACC_FLAG_UNUSED; +UIAccessibilityTraits UIAccessibilityTraitImage = ACC_FLAG_UNUSED; +UIAccessibilityTraits UIAccessibilityTraitSelected = ACC_FLAG_UNUSED; +UIAccessibilityTraits UIAccessibilityTraitPlaysSound = ACC_FLAG_UNUSED; +UIAccessibilityTraits UIAccessibilityTraitKeyboardKey = ACC_FLAG_UNUSED; +UIAccessibilityTraits UIAccessibilityTraitStaticText = ACC_FLAG_STATIC_TEXT; +UIAccessibilityTraits UIAccessibilityTraitSummaryElement = ACC_FLAG_UNUSED; +UIAccessibilityTraits UIAccessibilityTraitNotEnabled = ACC_FLAG_UNUSED; +UIAccessibilityTraits UIAccessibilityTraitUpdatesFrequently = ACC_FLAG_UNUSED; +UIAccessibilityTraits UIAccessibilityTraitStartsMediaSession = ACC_FLAG_UNUSED; +UIAccessibilityTraits UIAccessibilityTraitAdjustable = ACC_FLAG_UNUSED; +UIAccessibilityTraits UIAccessibilityTraitAllowsDirectInteraction = ACC_FLAG_UNUSED; +UIAccessibilityTraits UIAccessibilityTraitCausesPageTurn = ACC_FLAG_UNUSED; +UIAccessibilityTraits UIAccessibilityTraitHeader = ACC_FLAG_UNUSED; + +UIAccessibilityNotifications UIAccessibilityScreenChangedNotification = 0; +UIAccessibilityNotifications UIAccessibilityLayoutChangedNotification = 1; +UIAccessibilityNotifications UIAccessibilityAnnouncementNotification = 2; +UIAccessibilityNotifications UIAccessibilityPageScrolledNotification = 3; + +@implementation UIAccessibilityElement + +- (id)initWithAccessibilityContainer:(UIView*)container { + _accessibilityContainer = container; + [self initAccessibility]; + return self; +} + +/** + @Status Stub +*/ +- (void)initAccessibility { +} + +/** + @Status Stub +*/ +- (void)updateAccessibility { + IWUpdateAccessibility(self.accessibilityContainer.layer, self); +} + +@end + +@implementation UIView (Accessibility) +@end + +/** + @Status Stub +*/ +void UIAccessibilityPostNotification(UIAccessibilityNotifications notification, id argument) { +} + +/** + @Status Stub +*/ +BOOL UIAccessibilityIsVoiceOverRunning(void) { + return FALSE; +} + +void IWUpdateAccessibility(id receiver, NSObject* accessibilityObj) { + IWAccessibilityInfo info; + + // traits are composed of accessibility flags, just copy them. + info.flags = (IWAccessibilityFlags)accessibilityObj.accessibilityTraits; + [receiver updateAccessibilityInfo:&info]; +} diff --git a/Frameworks/UIKit/UIButton.mm b/Frameworks/UIKit/UIButton.mm index 6a60678e4f..7e2cbfe7c8 100644 --- a/Frameworks/UIKit/UIButton.mm +++ b/Frameworks/UIKit/UIButton.mm @@ -337,8 +337,13 @@ static bool validateState(UIControlState state) { return true; } +- (void)initAccessibility { + [super initAccessibility]; + self.accessibilityTraits = UIAccessibilityTraitButton; +} + /** - @Status Interoperable + @Status Interoperable */ - (void)setImage:(UIImage*)image forState:(UIControlState)state { if (!validateState(state)) { @@ -394,6 +399,8 @@ - (void)setTitle:(NSString*)title forState:(UIControlState)state { _states[state].title.attach([title copy]); [self setNeedsLayout]; [self layoutSubviews]; + + self.accessibilityLabel = title; } /** diff --git a/Frameworks/UIKit/UIControl.mm b/Frameworks/UIKit/UIControl.mm index 71f2611ea7..59a93bbdf2 100644 --- a/Frameworks/UIKit/UIControl.mm +++ b/Frameworks/UIKit/UIControl.mm @@ -58,6 +58,11 @@ - (id)initWithCoder:(NSCoder*)coder { return self; } +- (void)initAccessibility { + [super initAccessibility]; + self.isAccessibilityElement = TRUE; +} + - (void)addEventConnection:(UIRuntimeEventConnection*)connection { [_registeredActions addObject:connection]; } @@ -169,6 +174,12 @@ - (void)setEnabled:(BOOL)enabled { [self setNeedsDisplay]; [self setNeedsLayout]; + + if (enabled) { + self.accessibilityTraits &= ~UIAccessibilityTraitNotEnabled; + } else { + self.accessibilityTraits |= UIAccessibilityTraitNotEnabled; + } } /** diff --git a/Frameworks/UIKit/UIFont.mm b/Frameworks/UIKit/UIFont.mm index 23a3d4b37c..90ec4364fc 100644 --- a/Frameworks/UIKit/UIFont.mm +++ b/Frameworks/UIKit/UIFont.mm @@ -22,6 +22,8 @@ #include "Foundation/NSArray.h" #include "Foundation/NSFileManager.h" #include "UIKit/UIFont.h" +#include "UIKit/UIFontDescriptor.h" +#include "UIFontDescriptorInternal.h" extern "C" { #include @@ -42,6 +44,7 @@ @implementation UIFont { @public void *_font, *_sizingFont; idretaintype(NSString) _name; + UIFontDescriptor* _descriptor; idretain _fileName; float _size; float _horizontalScale; @@ -216,6 +219,17 @@ + (UIFont*)fontWithName:(NSString*)name size:(float)size { return [ret autorelease]; } +/** + @Status Interoperable + @Tags Font + @Public Yes +*/ ++ (UIFont*)fontWithDescriptor:(UIFontDescriptor*)descriptor size:(CGFloat)fontSize { + UIFont* font = [UIFont fontWithName:[descriptor _getFontName] size:fontSize]; + font->_descriptor = [descriptor retain]; + return font; +} + + (UIFont*)messageFont { static id mFont; @@ -498,30 +512,52 @@ - (float)leading { /** @Status Interoperable + @Framework Foundation + @Tags Font + @Public Yes +*/ +- (UIFontDescriptor*)fontDescriptor { + return self->_descriptor; +} + +/** + @Status Interoperable + @Framework Foundation + @Tags Font + @Public Yes */ + (float)smallSystemFontSize { - return 12.0f; + return [UIFontDescriptor _getSystemSmallFontSize]; } /** @Status Interoperable + @Framework Foundation + @Tags Font + @Public Yes */ + (float)systemFontSize { - return 14.0f; + return [UIFontDescriptor _getSystemFontSize]; } /** @Status Interoperable + @Framework Foundation + @Tags Font + @Public Yes */ + (float)labelFontSize { - return 17.0f; + return [UIFontDescriptor _getLabelFontSize]; } /** @Status Interoperable + @Framework Foundation + @Tags Font + @Public Yes */ + (float)buttonFontSize { - return 14.0f; + return [UIFontDescriptor _getButtonFontSize]; } - (NSUInteger)hash { @@ -549,7 +585,7 @@ - (NSObject*)copyWithZone:(NSZone*)zone { - (void)dealloc { _fileName = nil; _name = nil; - + _descriptor = nil; [super dealloc]; } diff --git a/Frameworks/UIKit/UIFontDescriptor.mm b/Frameworks/UIKit/UIFontDescriptor.mm index 3654d7055e..8d8b3e755b 100644 --- a/Frameworks/UIKit/UIFontDescriptor.mm +++ b/Frameworks/UIKit/UIFontDescriptor.mm @@ -15,8 +15,137 @@ //****************************************************************************** #include "Starboard.h" - #include "UIKit/UIFontDescriptor.h" -@implementation UIFontDescriptor +NSString* const UIFontTextStyleTitle1 = @"UICTFontTextStyleTitle1"; +NSString* const UIFontTextStyleTitle2 = @"UICTFontTextStyleTitle2"; +NSString* const UIFontTextStyleTitle3 = @"UICTFontTextStyleTitle3"; +NSString* const UIFontTextStyleHeadline = @"UICTFontTextStyleHeadline"; +NSString* const UIFontTextStyleSubheadline = @"UICTFontTextStyleSubheadline"; +NSString* const UIFontTextStyleBody = @"UICTFontTextStyleBody"; +NSString* const UIFontTextStyleFootnote = @"UICTFontTextStyleFootnote"; +NSString* const UIFontTextStyleCaption1 = @"UICTFontTextStyleCaption1"; +NSString* const UIFontTextStyleCaption2 = @"UICTFontTextStyleCaption2"; +NSString* const UIFontTextStyleCallout = @"UICTFontTextStyleCallout"; + +NSString* const UIFontDescriptorFamilyAttribute = @"UIFontDescriptorFamilyAttribute"; +NSString* const UIFontDescriptorTraitsAttribute = @"UIFontDescriptorTraitsAttribute"; + +NSString* const UIFontSymbolicTrait = @"UIFontSymbolicTrait"; + +NSString* const SystemFontName = @"SegoeUI"; + +/** + All these values are fixed number in IOS no matter on iphone* or ipad*. + */ +const float c_smallSystemFontSize = 12.0f; +const float c_systemFontSize = 14.0f; +const float c_labelFontSize = 17.0f; +const float c_buttonFontSize = 14.0f; + +@implementation UIFontDescriptor { +@private + idretaintype(NSString) _name; + float _size; + UIFontDescriptorSymbolicTraits _traits; +} + +/** + @Status Interoperable +*/ ++ (UIFontDescriptor*)fontDescriptorWithName:(NSString*)fontName size:(CGFloat)size { + UIFontDescriptor* fontDescriptor = [[UIFontDescriptor alloc] init]; + fontDescriptor->_name = [UIFontDescriptor _getFallBackFontName:fontName]; + fontDescriptor->_size = [UIFontDescriptor _getFallBackFontSize:size]; + return [fontDescriptor autorelease]; +} + ++ (UIFontDescriptor*)fontDescriptorWithDescriptor:(UIFontDescriptor*)descriptor size:(CGFloat)size { + UIFontDescriptor* fontDescriptor = [[UIFontDescriptor alloc] init]; + fontDescriptor->_name = descriptor->_name; + fontDescriptor->_size = size; + fontDescriptor->_traits = descriptor->_traits; + return [fontDescriptor autorelease]; +} + +/** + @Status Caveat + @Notes Force to use default font name and size. +*/ ++ (UIFontDescriptor*)preferredFontDescriptorWithTextStyle:(NSString*)style { + return [UIFontDescriptor fontDescriptorWithName:nil size:0.0]; +} + +/** + This is a temp solution, we need to implement the fall back logic in 1512. + Here just to check nil, and return default system font as fall back. + */ ++ (NSString*)_getFallBackFontName:(NSString*)fontName { + NSString* ret = [NSString alloc]; + if (fontName == nil || fontName.length == 0) { + ret = [ret initWithString:SystemFontName]; + } else { + ret = [ret initWithString:fontName]; + } + return [ret autorelease]; +} + ++ (float)_getFallBackFontSize:(float)size { + // We need to set the maximun of size, since xaml will crash if it is too big. + float const maxSize = 100; + if (size <= 0 || size > maxSize) { + return c_systemFontSize; + } else { + return size; + } +} + ++ (float)_getSystemSmallFontSize { + return c_smallSystemFontSize; +} + ++ (float)_getSystemFontSize { + return c_systemFontSize; +} + ++ (float)_getLabelFontSize { + return c_labelFontSize; +} + ++ (float)_getButtonFontSize { + return c_buttonFontSize; +} + +/** + @Status Interoperable +*/ +- (UIFontDescriptor*)fontDescriptorWithSymbolicTraits:(UIFontDescriptorSymbolicTraits)symbolicTraits { + UIFontDescriptor* result = [UIFontDescriptor fontDescriptorWithDescriptor:self size:self->_size]; + result->_traits = symbolicTraits; + return result; +} + +/** + @Status Stub +*/ +- (instancetype)initWithFontAttributes:(NSDictionary*)attributes { + // Just to unblock the build. +} + +- (NSString*)_getFontName { + return self->_name; +} + +/** + @Status Interoperable +*/ +- (UIFontDescriptorSymbolicTraits)symbolicTraits { + return self->_traits; +} + +- (void)dealloc { + _name = nil; + [super dealloc]; +} + @end \ No newline at end of file diff --git a/Frameworks/UIKit/UILabel.mm b/Frameworks/UIKit/UILabel.mm index 8cc06a16ce..33bd53584f 100644 --- a/Frameworks/UIKit/UILabel.mm +++ b/Frameworks/UIKit/UILabel.mm @@ -22,6 +22,7 @@ #include "UIKit/UIFont.h" #include "UIKit/UIColor.h" #include "UIKit/UILabel.h" +#include "UIKit/UIAccessibility.h" #include "CGContextInternal.h" @@ -46,6 +47,7 @@ @implementation UILabel { BOOL _isHighlighted; UIBaselineAdjustment _baselineAdjustment; } + - (void)adjustFontSizeToFit { if (_numberOfLines != 1) { [self adjustTextLayerSize]; @@ -177,8 +179,13 @@ - (instancetype)initWithFrame:(CGRect)frame { return self; } +- (void)initAccessibility { + [super initAccessibility]; + self.accessibilityTraits = UIAccessibilityTraitStaticText; +} + /** - @Status Interoperable + @Status Interoperable */ - (void)setFont:(UIFont*)font { if (![_font isEqual:font]) { @@ -212,11 +219,14 @@ - (void)setText:(NSString*)newStr { } if (newStr == nil || ![_text isEqual:newStr]) { _text.attach([newStr copy]); + if (_adjustFontSize) { [self adjustFontSizeToFit]; } else { [self adjustTextLayerSize]; } + + self.accessibilityValue = newStr; } } diff --git a/Frameworks/UIKit/UIPopoverPresentationController.mm b/Frameworks/UIKit/UIPopoverPresentationController.mm new file mode 100644 index 0000000000..fe4db992fb --- /dev/null +++ b/Frameworks/UIKit/UIPopoverPresentationController.mm @@ -0,0 +1,101 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#include "Starboard.h" + +#include "UIKit/UIPopoverPresentationController.h" + +@implementation UIPopoverPresentationController + +/** + @Status Stub +*/ +- (id)initWithPresentedViewController:(UIViewController*)presentedViewController + presentingViewController:(UIViewController*)presentingViewController { + return [super initWithPresentedViewController:presentedViewController presentingViewController:presentingViewController]; +} + +/** + @Status Stub +*/ +- (UIView*)presentedView { + return [super presentedView]; +} + +/** + @Status Stub +*/ +- (CGRect)frameOfPresentedViewInContainerView { + return [super frameOfPresentedViewInContainerView]; +} + +/** + @Status Stub +*/ +- (BOOL)shouldPresentInFullscreen { + return [super shouldPresentInFullscreen]; +} + +/** + @Status Stub +*/ +- (BOOL)shouldRemovePresentersView { + return [super shouldRemovePresentersView]; +} + +/** + @Status Stub +*/ +- (void)containerViewWillLayoutSubviews { + UNIMPLEMENTED(); +} + +/** + @Status Stub +*/ +- (void)containerViewDidLayoutSubviews { + UNIMPLEMENTED(); +} + +/** + @Status Stub +*/ +- (void)presentationTransitionWillBegin { + UNIMPLEMENTED(); +} + +/** + @Status Stub +*/ +- (void)presentationTransitionDidEnd:(BOOL)completed { + UNIMPLEMENTED(); +} + +/** + @Status Stub +*/ +- (void)dismissalTransitionWillBegin { + UNIMPLEMENTED(); +} + +/** + @Status Stub +*/ +- (void)dismissalTransitionDidEnd:(BOOL)completed { + UNIMPLEMENTED(); +} + +@end diff --git a/Frameworks/UIKit/UIPresentationController.mm b/Frameworks/UIKit/UIPresentationController.mm new file mode 100644 index 0000000000..8771e3dca2 --- /dev/null +++ b/Frameworks/UIKit/UIPresentationController.mm @@ -0,0 +1,106 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#include "Starboard.h" + +#include "UIKit/UIPresentationController.h" + +@implementation UIPresentationController + +/** + @Status Interoperable +*/ +- (id)initWithPresentedViewController:(UIViewController*)presentedViewController + presentingViewController:(UIViewController*)presentingViewController { + _presentingViewController = presentingViewController; + _presentedViewController = presentedViewController; + _presentationStyle = _presentedViewController.modalPresentationStyle; + _containerView = _presentingViewController.view; + + return self; +} + +/** + @Status Interoperable +*/ +- (UIView*)presentedView { + return self.presentedViewController.view; +} + +/** + @Status Interoperable +*/ +- (CGRect)frameOfPresentedViewInContainerView { + return _containerView.frame; +} + +/** + @Status Interoperable +*/ +- (BOOL)shouldPresentInFullscreen { + return YES; +} + +/** + @Status Interoperable +*/ +- (BOOL)shouldRemovePresentersView { + return NO; +} + +/** + @Status Stub +*/ +- (void)containerViewWillLayoutSubviews { + UNIMPLEMENTED(); +} + +/** + @Status Stub +*/ +- (void)containerViewDidLayoutSubviews { + UNIMPLEMENTED(); +} + +/** + @Status Stub +*/ +- (void)presentationTransitionWillBegin { + UNIMPLEMENTED(); +} + +/** + @Status Stub +*/ +- (void)presentationTransitionDidEnd:(BOOL)completed { + UNIMPLEMENTED(); +} + +/** + @Status Stub +*/ +- (void)dismissalTransitionWillBegin { + UNIMPLEMENTED(); +} + +/** + @Status Stub +*/ +- (void)dismissalTransitionDidEnd:(BOOL)completed { + UNIMPLEMENTED(); +} + +@end \ No newline at end of file diff --git a/Frameworks/UIKit/UIScreen.mm b/Frameworks/UIKit/UIScreen.mm index a9162ece03..bce2a475ae 100644 --- a/Frameworks/UIKit/UIScreen.mm +++ b/Frameworks/UIKit/UIScreen.mm @@ -72,13 +72,26 @@ + (NSArray*)screens { } /** - @Status Interoperable + @Status Caveat + @Notes Returns the system scale and will dynamcially change unlike iOS. */ -- (float)scale { +- (CGFloat)scale { return GetCACompositor()->screenScale(); } -- (float)brightness { +/** + @Status Caveat + @Notes Returns the host screen scale which will never change. This value may not map 1:1 with iOS. +*/ +- (CGFloat)nativeScale { + return UIApplication.displayMode.hostScreenScale; +} + +/** + @Status Caveat + @Notes Always returns 1.0. +*/ +- (CGFloat)brightness { return 1.0; } @@ -95,6 +108,19 @@ - (CGRect)bounds { return ret; } +/** + @Status Caveat + @Notes returns the host window size width and height. +*/ +- (CGRect)nativeBounds { + CGRect ret; + ret.origin.x = 0.0f; + ret.origin.y = 0.0f; + ret.size = UIApplication.displayMode.hostWindowSize; + + return ret; +} + /** @Status Interoperable */ diff --git a/Frameworks/UIKit/UISearchBar.mm b/Frameworks/UIKit/UISearchBar.mm index f1a3f70dda..9619334add 100644 --- a/Frameworks/UIKit/UISearchBar.mm +++ b/Frameworks/UIKit/UISearchBar.mm @@ -24,9 +24,16 @@ #include "UIKit/UIImage.h" #include "UIKit/UISegmentedControl.h" +static const CGFloat c_marginBottom = 10; +static const CGFloat c_marginLeftAndRight = 10; +static const CGFloat c_defaultTextFieldHeight = 24; +static const CGFloat c_marginTopForPrompt = 10; +static const float c_defaultFontSize = 15.0; +static const CGFloat c_scopeButtonMarginTop = 20; + @implementation UISearchBar { idretaintype(UITextField) _textField; - idretaintype(UILabel) _label; + idretaintype(UILabel) _promptLabel; idretaintype(UISegmentedControl) _scopeButtons; idretaintype(NSString) _placeholder; BOOL _scopeButtonsHidden; @@ -34,33 +41,17 @@ @implementation UISearchBar { } static void initInternal(UISearchBar* self) { - CGRect frame; - - for (int i = 0; i < 5; i++) { - id view = [UIView new]; - [self addSubview:view]; - } - - frame = [self frame]; - frame.origin.x = 20; - frame.size.width -= 20; - + CGRect frame = [self frame]; self->_textField.attach([[UITextField alloc] initWithFrame:frame]); [self->_textField setDelegate:(id)self]; [self->_textField setBorderStyle:UITextBorderStyleRoundedRect]; [self->_textField addTarget:self action:@selector(onTextChanged:) forControlEvents:UIControlEventEditingChanged]; - [self->_textField setFont:[UIFont systemFontOfSize:15.0f]]; + [self->_textField setFont:[UIFont systemFontOfSize:c_defaultFontSize]]; if (self->_placeholder != nil) { [self->_textField setPlaceholder:self->_placeholder]; } [self addSubview:self->_textField]; - self->_label.attach([[UILabel alloc] initWithFrame:frame]); - [self->_label setText:@"Find:"]; - [self->_label setBackgroundColor:nil]; - [self->_label setTextColor:[UIColor darkGrayColor]]; - [self addSubview:self->_label]; - UIImage* navGradient = [[UIImage imageNamed:@"/img/navgradient-default.png"] stretchableImageWithLeftCapWidth:1 topCapHeight:0]; UIImageSetLayerContents([self layer], navGradient); } @@ -69,6 +60,24 @@ - (BOOL)resignFirstResponder { return [_textField resignFirstResponder]; } +/** + @Status Interoperable +*/ +- (void)setPrompt:(NSString*)prompt { + if (_promptLabel == nil) { + CGRect promptFrame = CGRectMake(0, c_marginTopForPrompt, self.frame.size.width, c_defaultTextFieldHeight); + + self->_promptLabel.attach([[UILabel alloc] initWithFrame:promptFrame]); + [self->_promptLabel setTextAlignment:NSTextAlignmentCenter]; + [self->_promptLabel setBackgroundColor:nil]; + [self->_promptLabel setTextColor:[UIColor blackColor]]; + [self addSubview:self->_promptLabel]; + } + + _prompt = prompt; + [self setNeedsDisplay]; +} + - (instancetype)initWithCoder:(NSCoder*)coder { id ret = [super initWithCoder:coder]; @@ -127,7 +136,6 @@ - (void)setKeyboardType:(UIKeyboardType)type { - (instancetype)initWithFrame:(CGRect)frame { [super initWithFrame:frame]; - initInternal(self); return self; @@ -225,32 +233,25 @@ - (void)setScopeBarButtonTitleTextAttributes:(id)attributes forState:(DWORD)forS } - (void)layoutSubviews { - CGRect bounds; + CGRect promptFrame = CGRectMake(0, c_marginTopForPrompt, self.frame.size.width, c_defaultTextFieldHeight); + [_promptLabel setFrame:promptFrame]; + [self->_promptLabel setText:_prompt]; - bounds = [self bounds]; - - CGRect textFrame; - textFrame = bounds; - textFrame.origin.x = 50; - textFrame.size.width -= 60; - textFrame.size.height = 25; - textFrame.origin.y = bounds.size.height / 2.0f - textFrame.size.height / 2.0f; + CGFloat textFieldOriginY = self.frame.size.height - c_defaultTextFieldHeight - c_marginBottom; + CGRect textFrame = { { c_marginLeftAndRight, textFieldOriginY }, + { self.frame.size.width - (2 * c_marginLeftAndRight), c_defaultTextFieldHeight } }; if (!_scopeButtonsHidden) { if (_scopeButtons) { - textFrame.origin.y += 20; - [_scopeButtons setFrame:textFrame]; - textFrame.origin.y -= 40; + CGRect scopeButtonsFrame = textFrame; + scopeButtonsFrame.origin.y = scopeButtonsFrame.origin.y + textFrame.size.height + c_scopeButtonMarginTop; + [_scopeButtons setFrame:scopeButtonsFrame]; } } else { [_scopeButtons setHidden:TRUE]; } [_textField setFrame:textFrame]; - textFrame.origin.x = 10; - textFrame.size.width = 40; - - [_label setFrame:textFrame]; } - (BOOL)textField:(id)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString*)newString { @@ -306,7 +307,7 @@ - (void)setBackgroundImage:(id)image { - (void)dealloc { _textField = nil; - _label = nil; + _promptLabel = nil; _scopeButtons = nil; _placeholder = nil; [super dealloc]; diff --git a/Frameworks/UIKit/UIView.mm b/Frameworks/UIKit/UIView.mm index fd56f4df21..150fe27dd1 100644 --- a/Frameworks/UIKit/UIView.mm +++ b/Frameworks/UIKit/UIView.mm @@ -115,6 +115,16 @@ - (void)initPriv { // EbrDebugLog("%d: Allocing %s (%x)\n", viewCount, object_getClassName(self), (id) self); } +- (void)initAccessibility { + self.isAccessibilityElement = FALSE; + self.accessibilityTraits = UIAccessibilityTraitNone; + [self updateAccessibility]; +} + +- (void)updateAccessibility { + IWUpdateAccessibility(self.layer, self); +} + + (instancetype)allocWithZone:(NSZone*)zone { UIView* ret = [super allocWithZone:zone]; @@ -129,6 +139,7 @@ + (instancetype)allocWithZone:(NSZone*)zone { [self setOpaque:TRUE]; [self setFrame:pos]; [self setNeedsDisplay]; + [self initAccessibility]; return self; } @@ -648,6 +659,8 @@ - (void)setFrame:(CGRect)frame { if (self->priv->translatesAutoresizingMaskIntoConstraints) { [self autoLayoutUpdateConstraints]; } + + self.accessibilityFrame = self.frame; } /** @@ -2431,21 +2444,6 @@ - (BOOL)endEditing:(BOOL)force { - (void)drawRect:(CGRect)pos { } -- (void)setAccessibilityLabel:(NSString*)label { -} - -- (void)setAccessibilityHint:(NSString*)hint { -} - -- (void)setAccessibilityTraits:(UIAccessibilityTraits)traits { -} - -- (void)setAccessibilityViewIsModal:(BOOL)modal { -} - -- (void)setIsAccessibilityElement:(BOOL)enabled { -} - /** @Status Interoperable */ diff --git a/Frameworks/UIKit/UIViewController.mm b/Frameworks/UIKit/UIViewController.mm index 4c7abd256a..c7311640c6 100644 --- a/Frameworks/UIKit/UIViewController.mm +++ b/Frameworks/UIKit/UIViewController.mm @@ -36,6 +36,7 @@ #include "UIViewControllerInternal.h" #include "AutoLayout.h" #include "UIViewControllerInternal.h" +#include "UIKit/UIPopoverPresentationController.h" NSString* const UITransitionContextFromViewControllerKey = (NSString * const) @"UITransitionContextFromViewControllerKey"; NSString* const UITransitionContextToViewControllerKey = (NSString * const) @"UITransitionContextToViewControllerKey"; @@ -889,6 +890,13 @@ - (UIViewController*)modalViewController { return priv->_modalViewController; } +/** + @Status Interoperable +*/ +- (UIPopoverPresentationController*)popoverPresentationController { + return priv->_popoverPresentationController; +} + /** @Status Interoperable */ @@ -1058,7 +1066,10 @@ - (void)presentViewController:(UIViewController*)controller animated:(BOOL)anima [controller view]; controller->priv->_parentViewController = self; controller->priv->_presentingViewController = self; - [controller performSelector:@selector(_addToTop:) withObject:[NSNumber numberWithInt:animated] afterDelay:0.0]; + [controller performSelector:@selector(_addToTop:) + onThread:[NSThread currentThread] + withObject:[NSNumber numberWithInt:animated] + waitUntilDone:YES]; } /* @@ -1283,6 +1294,25 @@ - (void)_addToTop:(NSNumber*)animatedValue { priv->_isRootView = true; if (priv->_parentViewController != nil) { + // TODO: This implementation satisfies the contract that the popoverPresentationController is not nil when presenting a + // UIViewController with modalPresentationType equal to UIModalPresentationPopover. + // The full implementation will need to utilize the UIPresentationController for UIViewController presentations + if (priv->_presentationStyle == UIModalPresentationPopover) { + if (priv->_popoverPresentationController != nil) { + [priv->_popoverPresentationController release]; + } + + priv->_popoverPresentationController = + [[UIPopoverPresentationController alloc] initWithPresentedViewController:self + presentingViewController:priv->_parentViewController]; + + if (priv->_presentationController != nil) { + [priv->_presentationController release]; + } + + priv->_presentationController = priv->_popoverPresentationController; + } + float endY = 0; UIView* view = [self view]; @@ -1898,7 +1928,7 @@ - (void)performSegueWithIdentifier:(NSString*)identifier sender:(id)sender { NSString* controllerName = nil; UIStoryboardSegueTemplate* segueTemplate = nil; - for (UIStoryboardSegueTemplate* cur in (NSArray*)priv->_modalTemplates) { + for (UIStoryboardSegueTemplate* cur in(NSArray*)priv->_modalTemplates) { if ([[cur identifier] isEqualToString:identifier]) { controllerName = [cur destination]; segueTemplate = cur; @@ -1929,7 +1959,7 @@ - (void)performSegueWithDestination:(NSString*)destination sender:(id)sender { NSString* controllerName = nil; UIStoryboardSegueTemplate* segueTemplate = nil; - for (UIStoryboardSegueTemplate* cur in (NSArray*)priv->_modalTemplates) { + for (UIStoryboardSegueTemplate* cur in(NSArray*)priv->_modalTemplates) { if ([[cur destination] isEqualToString:destination]) { controllerName = [cur destination]; segueTemplate = cur; @@ -2049,7 +2079,7 @@ - (void)dealloc { // Remove us from being the parent of our child view controller. // Should we call controller->removeFromParentViewController instead? - for (UIViewController* curController in (NSArray*)priv->_childViewControllers) { + for (UIViewController* curController in(NSArray*)priv->_childViewControllers) { curController->priv->_parentViewController = nil; } diff --git a/Frameworks/XamlCompositorCS/CALayerXaml.cs b/Frameworks/XamlCompositorCS/CALayerXaml.cs index 716f0ca995..a785ef04dc 100644 --- a/Frameworks/XamlCompositorCS/CALayerXaml.cs +++ b/Frameworks/XamlCompositorCS/CALayerXaml.cs @@ -10,6 +10,7 @@ using Windows.Foundation.Collections; using Windows.UI; using Windows.UI.Xaml; +using Windows.UI.Xaml.Automation.Peers; using Windows.UI.Xaml.Media.Animation; using Windows.UI.Xaml.Media.Imaging; using Windows.UI.Xaml.Controls; @@ -28,6 +29,21 @@ namespace XamlCompositorCS { namespace Controls { + [Bindable] + public sealed class CALayerXamlAutomationPeer : FrameworkElementAutomationPeer + { + public CALayerXamlAutomationPeer(CALayerXaml owner) : base(owner) { + } + + protected override string GetClassNameCore() { + return "FakeClassName"; + } + + protected override AutomationControlType GetAutomationControlTypeCore() { + return AutomationControlType.ScrollBar; + } + } + [Bindable] public sealed class CALayerXaml : Panel, CacheableObject { @@ -857,6 +873,12 @@ public bool hidden } } + /* Disable for now + protected override AutomationPeer OnCreateAutomationPeer() + { + return new CALayerXamlAutomationPeer(this); + } + */ public static void SizeChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) { diff --git a/Frameworks/include/AccessibilityInternal.h b/Frameworks/include/AccessibilityInternal.h new file mode 100644 index 0000000000..81cee55d50 --- /dev/null +++ b/Frameworks/include/AccessibilityInternal.h @@ -0,0 +1,37 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#pragma once + +@protocol UIAccessibility; + +typedef uint64_t IWAccessibilityFlags; + +const uint64_t ACC_FLAG_BUTTON = (1 << 1); +const uint64_t ACC_FLAG_LINK = (1 << 2); +const uint64_t ACC_FLAG_SELECTED = (1 << 3); +const uint64_t ACC_FLAG_STATIC_TEXT = (1 << 4); + +const uint64_t ACC_FLAG_UNUSED = 0; + +// TODO: BK: additional accessibility info here. + +struct IWAccessibilityInfo { + IWAccessibilityFlags flags; +}; + +void IWUpdateAccessibility(id receiver, NSObject* accessibilityObj); + diff --git a/Frameworks/include/CACompositor.h b/Frameworks/include/CACompositor.h index a5418aab80..61baaf7520 100644 --- a/Frameworks/include/CACompositor.h +++ b/Frameworks/include/CACompositor.h @@ -28,6 +28,8 @@ struct CAMediaTimingProperties; #define CACompositorRotation180 180.0f #define CACompositorRotation90CounterClockwise 270.0f +struct IWAccessibilityInfo; + class CACompositorInterface { public: virtual void DisplayTreeChanged() = 0; @@ -117,6 +119,8 @@ class CACompositorInterface { virtual void IncrementCounter(const char* name) = 0; virtual void DecrementCounter(const char* name) = 0; + + virtual void SetAccessibilityInfo(DisplayNode* node, const IWAccessibilityInfo& info) = 0; }; extern CACompositorInterface* _globalCompositor; @@ -129,4 +133,4 @@ CA_EXPORT CACompositorInterface* GetCACompositor(); CA_EXPORT void SetCACompositor(CACompositorInterface* compositorInterface); CA_EXPORT bool CASignalDisplayLink(); -#endif \ No newline at end of file +#endif diff --git a/Frameworks/include/CALayerInternal.h b/Frameworks/include/CALayerInternal.h index 4fb7d58177..1597558747 100644 --- a/Frameworks/include/CALayerInternal.h +++ b/Frameworks/include/CALayerInternal.h @@ -18,6 +18,7 @@ #define _CALAYERPRIVATE_H_ #import +#import @class CAAnimation, CALayerContext; diff --git a/Frameworks/include/ErrorHandling.h b/Frameworks/include/ErrorHandling.h new file mode 100644 index 0000000000..06bb53041f --- /dev/null +++ b/Frameworks/include/ErrorHandling.h @@ -0,0 +1,226 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#ifndef __ERRORHANDLING_H +#define __ERRORHANDLING_H + +// We need to do a bit of work to be able to pull in the result.h file and all of its error handling helpers + +#pragma push_macro("PCWSTR") +#undef PCWSTR +#define PCWSTR const wchar_t* + +#pragma push_macro("PWSTR") +#undef PWSTR +#define PWSTR wchar_t* + +#pragma push_macro("PCSTR") +#undef PCSTR +#define PCSTR const char* + +#pragma push_macro("PSTR") +#undef PSTR +#define PSTR char* + +#pragma push_macro("ARRAYSIZE") +#undef ARRAYSIZE +#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) + +#pragma push_macro("FORMAT_MESSAGE_IGNORE_INSERTS") +#undef FORMAT_MESSAGE_IGNORE_INSERTS +#define FORMAT_MESSAGE_IGNORE_INSERTS 0x00000200 + +#pragma push_macro("FORMAT_MESSAGE_FROM_STRING") +#undef FORMAT_MESSAGE_FROM_STRING +#define FORMAT_MESSAGE_FROM_STRING 0x00000400 + +#pragma push_macro("FORMAT_MESSAGE_FROM_HMODULE") +#undef FORMAT_MESSAGE_FROM_HMODULE +#define FORMAT_MESSAGE_FROM_HMODULE 0x00000800 + +#pragma push_macro("FORMAT_MESSAGE_FROM_SYSTEM") +#undef FORMAT_MESSAGE_FROM_SYSTEM +#define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000 + +#pragma push_macro("FORMAT_MESSAGE_ARGUMENT_ARRAY") +#undef FORMAT_MESSAGE_ARGUMENT_ARRAY +#define FORMAT_MESSAGE_ARGUMENT_ARRAY 0x00002000 + +#pragma push_macro("FORMAT_MESSAGE_MAX_WIDTH_MASK") +#undef FORMAT_MESSAGE_MAX_WIDTH_MASK +#define FORMAT_MESSAGE_MAX_WIDTH_MASK 0x000000FF + +#pragma push_macro("LANG_NEUTRAL") +#undef LANG_NEUTRAL +#define LANG_NEUTRAL 0x00 + +#pragma push_macro("SUBLANG_DEFAULT") +#undef SUBLANG_DEFAULT +#define SUBLANG_DEFAULT 0x01 // user default + +#pragma push_macro("MAKELANGID") +#undef MAKELANGID +#define MAKELANGID(p, s) ((((WORD )(s)) << 10) | (WORD )(p)) + +#pragma push_macro("INVALID_HANDLE_VALUE") +#undef INVALID_HANDLE_VALUE +#define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) + +#pragma push_macro("FAST_FAIL_FATAL_APP_EXIT") +#undef FAST_FAIL_FATAL_APP_EXIT +#define FAST_FAIL_FATAL_APP_EXIT 7 + +#pragma push_macro("STATUS_NO_MEMORY") +#undef STATUS_NO_MEMORY +#define STATUS_NO_MEMORY ((unsigned long )0xC0000017L) + +typedef int INT_PTR, *PINT_PTR; +typedef unsigned int UINT_PTR, *PUINT_PTR; + +typedef long LONG; + +typedef long LONG_PTR, *PLONG_PTR; +typedef unsigned long ULONG_PTR, *PULONG_PTR; + +typedef ULONG_PTR SIZE_T, *PSIZE_T; +typedef void *HANDLE; + +typedef int BOOL; +typedef unsigned short WORD; +typedef void* PVOID; + +#ifndef BASETYPES +#define BASETYPES +typedef unsigned long ULONG; +typedef ULONG *PULONG; +typedef unsigned short USHORT; +typedef USHORT *PUSHORT; +typedef unsigned char UCHAR; +typedef UCHAR *PUCHAR; +typedef char *PSZ; +#endif /* !BASETYPES */ + +// Templates are defined here in order to avoid a dependency on C++ header file, +// or on compiler-specific contructs. +extern "C++" { + template + struct OBJC_ENUM_FLAG_INTEGER_FOR_SIZE; + + template <> + struct OBJC_ENUM_FLAG_INTEGER_FOR_SIZE<1> + { + typedef char type; + }; + + template <> + struct OBJC_ENUM_FLAG_INTEGER_FOR_SIZE<2> + { + typedef short type; + }; + + template <> + struct OBJC_ENUM_FLAG_INTEGER_FOR_SIZE<4> + { + typedef int type; + }; + + // used as an approximation of std::underlying_type + template + struct OBJC_ENUM_FLAG_SIZED_INTEGER + { + typedef typename OBJC_ENUM_FLAG_INTEGER_FOR_SIZE::type type; + }; +} + +#pragma push_macro("DEFINE_ENUM_FLAG_OPERATORS") +#undef DEFINE_ENUM_FLAG_OPERATORS +#define DEFINE_ENUM_FLAG_OPERATORS(ENUMTYPE) \ +extern "C++" { \ +inline ENUMTYPE operator | (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((OBJC_ENUM_FLAG_SIZED_INTEGER::type)a) | ((OBJC_ENUM_FLAG_SIZED_INTEGER::type)b)); } \ +inline ENUMTYPE &operator |= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((OBJC_ENUM_FLAG_SIZED_INTEGER::type &)a) |= ((OBJC_ENUM_FLAG_SIZED_INTEGER::type)b)); } \ +inline ENUMTYPE operator & (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((OBJC_ENUM_FLAG_SIZED_INTEGER::type)a) & ((OBJC_ENUM_FLAG_SIZED_INTEGER::type)b)); } \ +inline ENUMTYPE &operator &= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((OBJC_ENUM_FLAG_SIZED_INTEGER::type &)a) &= ((OBJC_ENUM_FLAG_SIZED_INTEGER::type)b)); } \ +inline ENUMTYPE operator ~ (ENUMTYPE a) { return ENUMTYPE(~((OBJC_ENUM_FLAG_SIZED_INTEGER::type)a)); } \ +inline ENUMTYPE operator ^ (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((OBJC_ENUM_FLAG_SIZED_INTEGER::type)a) ^ ((OBJC_ENUM_FLAG_SIZED_INTEGER::type)b)); } \ +inline ENUMTYPE &operator ^= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((OBJC_ENUM_FLAG_SIZED_INTEGER::type &)a) ^= ((OBJC_ENUM_FLAG_SIZED_INTEGER::type)b)); } \ +} + +// Override Win32 function calls +#pragma push_macro("GetCurrentThreadId") +#pragma push_macro("InterlockedIncrementNoFence") +#pragma push_macro("GetLastError") +#pragma push_macro("CopyMemory") +#pragma push_macro("ZeroMemory") +#pragma push_macro("FormatMessageW") +#pragma push_macro("OutputDebugStringW") +#pragma push_macro("InterlockedDecrementRelease") +#pragma push_macro("InterlockedCompareExchangePointer") + +#define GetCurrentThreadId objc_getCurrentThreadId +#define InterlockedIncrementNoFence objc_interlockedIncrementNoFence +#define GetLastError objc_getLastError +#define CopyMemory objc_copyMemory +#define ZeroMemory objc_zeroMemory +#define FormatMessageW objc_formatMessageW +#define OutputDebugStringW objc_outputDebugStringW +#define InterlockedDecrementRelease objc_interlockedDecrementRelease +#define InterlockedCompareExchangePointer objc_interlockedCompareExchangePointer + +#include "../objcrt/error-handling.h" + +// Ignore some warnings in result.h +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winvalid-noreturn" +#pragma clang diagnostic ignored "-Wunused-value" +#endif +#include "wil/result.h" +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +// Pop all the temp Win32 function defines +#pragma pop_macro("GetCurrentThreadId") +#pragma pop_macro("InterlockedIncrementNoFence") +#pragma pop_macro("GetLastError") +#pragma pop_macro("CopyMemory") +#pragma pop_macro("ZeroMemory") +#pragma pop_macro("FormatMessageW") +#pragma pop_macro("OutputDebugStringW") +#pragma pop_macro("InterlockedDecrementRelease") +#pragma pop_macro("InterlockedCompareExchangePointer") + +// Pop all the temp Win32 defines +#pragma pop_macro("PCWSTR") +#pragma pop_macro("PWSTR") +#pragma pop_macro("PCSTR") +#pragma pop_macro("PSTR") +#pragma pop_macro("ARRAYSIZE") +#pragma pop_macro("FORMAT_MESSAGE_IGNORE_INSERTS") +#pragma pop_macro("FORMAT_MESSAGE_FROM_STRING") +#pragma pop_macro("FORMAT_MESSAGE_FROM_HMODULE") +#pragma pop_macro("FORMAT_MESSAGE_FROM_SYSTEM") +#pragma pop_macro("FORMAT_MESSAGE_ARGUMENT_ARRAY") +#pragma pop_macro("FORMAT_MESSAGE_MAX_WIDTH_MASK") +#pragma pop_macro("LANG_NEUTRAL") +#pragma pop_macro("SUBLANG_DEFAULT") +#pragma pop_macro("MAKELANGID") +#pragma pop_macro("INVALID_HANDLE_VALUE") +#pragma pop_macro("FAST_FAIL_FATAL_APP_EXIT") +#pragma pop_macro("STATUS_NO_MEMORY") +#pragma pop_macro("DEFINE_ENUM_FLAG_OPERATORS") + +#endif // __ERRORHANDLING_H diff --git a/Frameworks/include/NSURLRequestInternal.h b/Frameworks/include/NSURLRequestInternal.h index 3e13d33b08..3657eb77f2 100644 --- a/Frameworks/include/NSURLRequestInternal.h +++ b/Frameworks/include/NSURLRequestInternal.h @@ -9,7 +9,6 @@ idretain _bodyStream; id _headerFields; bool _shouldHandleCookies; - bool _shouldDiscardData; NSURLRequestCachePolicy _cachePolicy; } @end \ No newline at end of file diff --git a/Frameworks/include/Starboard.h b/Frameworks/include/Starboard.h index 0679604414..27f1564421 100644 --- a/Frameworks/include/Starboard.h +++ b/Frameworks/include/Starboard.h @@ -17,11 +17,6 @@ #ifndef __STARBOARD_H #define __STARBOARD_H -// Placeholder for unimplemented logging and telemetry -#define UNIMPLEMENTED() -#define FAIL_FAST() -#define FAIL_FAST_MSG(format, ...) - // Interface should not be defined for Objective-C code #ifdef interface #undef interface @@ -31,12 +26,18 @@ #define IWPLATFORM_EXPORT #endif +#include "ErrorHandling.h" + extern "C" void dbg_printf(const char* fmt, ...); #define EbrDebugLog(...) dbg_printf(__VA_ARGS__) #define fatal_printf(...) #define EbrShutdownAV() #define idp(protocol) id +// Placeholder for unimplemented logging and telemetry +#define UNIMPLEMENTED() \ + dbg_printf("*******Stub %s not implemented at %s:%d*******\r\n", __FUNCTION__, __FILE__, __LINE__); + #include #include #ifdef __OBJC__ diff --git a/Frameworks/include/UIFontDescriptorInternal.h b/Frameworks/include/UIFontDescriptorInternal.h new file mode 100644 index 0000000000..f63d4fcbfa --- /dev/null +++ b/Frameworks/include/UIFontDescriptorInternal.h @@ -0,0 +1,34 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#pragma once + +FOUNDATION_EXPORT NSString* const SystemFontName; +FOUNDATION_EXPORT const float c_smallSystemFontSize; +FOUNDATION_EXPORT const float c_systemFontSize; +FOUNDATION_EXPORT const float c_labelFontSize; +FOUNDATION_EXPORT const float c_buttonFontSize; + +@interface UIFontDescriptor () ++ (float)_getSystemSmallFontSize; ++ (float)_getSystemFontSize; ++ (float)_getLabelFontSize; ++ (float)_getButtonFontSize; ++ (NSString*)_getFallBackFontName:(NSString*)fontName; ++ (float)_getFallBackFontSize:(float)size; +- (NSString*)_getFontName; +- (float)_getSize; +@end \ No newline at end of file diff --git a/Frameworks/include/UIViewControllerInternal.h b/Frameworks/include/UIViewControllerInternal.h index 990801eed8..f142812c43 100644 --- a/Frameworks/include/UIViewControllerInternal.h +++ b/Frameworks/include/UIViewControllerInternal.h @@ -35,6 +35,8 @@ struct UIViewControllerPriv { idretaintype(UIViewController) _modalViewController; idretaintype(UISearchDisplayController) _searchDisplayController; __unsafe_unretained id _presentingViewController, _presentedViewController; + __unsafe_unretained id _popoverPresentationController; + __unsafe_unretained id _presentationController; idretaintype(NSDictionary) _externalObjects; __unsafe_unretained id _parentViewController; idretaintype(NSString) nibName; diff --git a/Frameworks/include/wil/Common.h b/Frameworks/include/wil/Common.h new file mode 100644 index 0000000000..aca5ca482a --- /dev/null +++ b/Frameworks/include/wil/Common.h @@ -0,0 +1,579 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** +// Windows Internal Libraries (wil) +//! @file +//! Dependency-free straight c++ helpers, macros and type traits. +//! This file is always included implicitly by all wil headers. It contains helpers that are broadly applicable without +//! requiring any dependencies. Including this file naturally includes wistd_type_traits.h to supply functionality such +//! as `wistd::move()` to exception-free code. + +#pragma once +#ifndef __cplusplus +#error This file is designed for C++ consumers only +#endif +#pragma warning(push) +#pragma warning(disable:4714) // __forceinline not honored + +// DO NOT add *any* further includes to this file -- there should be no dependencies from its usage +#include "wistd_type_traits.h" + + +// Some SAL remapping / decoration to better support Doxygen. Macros that look like function calls can +// confuse Doxygen when they are used to decorate a function or variable. We simplify some of these to +// basic macros without the function for common use cases. +//! @cond +#define _Success_return_ _Success_(return) +#define _Success_true_ _Success_(true) +#define __declspec_noinline_ __declspec(noinline) +#define __declspec_selectany_ __declspec(selectany) +//! @encdond + +#if defined(_CPPUNWIND) && !defined(WIL_SUPPRESS_EXCEPTIONS) +//! This define is automatically set when exceptions are enabled within wil. +//! It is automatically defined when your code is compiled with exceptions enabled (via checking for the built-in +//! _CPPUNWIND flag) unless you explicitly define WIL_SUPPRESS_EXCEPTIONS ahead of including your first wil +//! header. All exception-based WIL methods and classes are included behind: +//! ~~~~ +//! #ifdef WIL_ENABLE_EXCEPTIONS +//! // code +//! #endif +//! ~~~~ +//! This enables exception-free code to directly include WIL headers without worrying about exception-based +//! routines suddenly becoming available. +#define WIL_ENABLE_EXCEPTIONS +#endif + +// block for documentation only +#if defined(WIL_DOXYGEN) +//! This define can be explicitly set to disable exception usage within wil. +//! Normally this define is never needed as the WIL_ENABLE_EXCEPTIONS macro is enabled automatically by looking +//! at _CPPUNWIND. If your code compiles with exceptions enabled, but does not want to enable the exception-based +//! classes and methods from WIL, define this macro ahead of including the first WIL header. +#define WIL_SUPPRESS_EXCEPTIONS +#endif + + +//! @defgroup bitwise Bitwise Inspection and Manipulation +//! Bitwise helpers to improve readability and reduce the error rate of bitwise operations. +//! Several macros have been constructed to assist with bitwise inspection and manipulation. These macros exist +//! for two primary purposes: +//! +//! 1. To improve the readability of bitwise comparisons and manipulation. +//! +//! The macro names are the more concise, readable form of what's being done and do not require that any flags +//! or variables be specified multiple times for the comparisons. +//! +//! 2. To reduce the error rate associated with bitwise operations. +//! +//! The readability improvements naturally lend themselves to this by cutting down the number of concepts. +//! Using `WI_IS_FLAG_SET(var, MyEnum::Flag)` rather than `((var & MyEnum::Flag) == MyEnum::Flag)` removes the comparison +//! operator and repetition in the flag value. +//! +//! Additionally, these macros separate single flag operations (which tend to be the most common) from multi-flag +//! operations so that compile-time errors are generated for bitwise operations which are likely incorrect, +//! such as: `WI_IS_FLAG_SET(var, MyEnum::None)` or `WI_IS_FLAG_SET(var, MyEnum::ValidMask)`. +//! +//! Note that the single flag helpers should be used when a compile-time constant single flag is being manipulated. These +//! helpers provide compile-time errors on misuse and should be preferred over the multi-flag helpers. The multi-flag helpers +//! should be used when multiple flags are being used simultaneously or when the flag values are not compile-time constants. +//! +//! Common example usage (manipulation of flag variables): +//! ~~~~ +//! WI_SET_FLAG(m_flags, MyFlags::Foo); // Set a single flag in the given variable +//! WI_SET_ALL_FLAGS(m_flags, MyFlags::Foo | MyFlags::Bar); // Set one or more flags +//! WI_CLEAR_FLAG_IF(m_flags, MyFlags::Bar, isBarClosed); // Conditionally clear a single flag based upon a bool +//! WI_CLEAR_ALL_FLAGS(m_flags, MyFlags::Foo | MyFlags::Bar); // Clear one or more flags from the given variable +//! WI_TOGGLE_FLAG(m_flags, MyFlags::Foo); // Toggle (change to the opposite value) a single flag +//! WI_UPDATE_FLAG(m_flags, MyFlags::Bar, isBarClosed); // Sets or Clears a single flag from the given variable based upon a bool value +//! WI_UPDATE_FLAGS_IN_MASK(m_flags, flagsMask, newFlagValues); // Sets or Clears the flags in flagsMask to the masked values from newFlagValues +//! ~~~~ +//! Common example usage (inspection of flag variables): +//! ~~~~ +//! if (WI_IS_FLAG_SET(m_flags, MyFlags::Foo)) // Is a single flag set in the given variable? +//! if (WI_IS_ANY_FLAG_SET(m_flags, MyFlags::Foo | MyFlags::Bar)) // Is at least one flag from the given mask set? +//! if (WI_ARE_ALL_FLAGS_CLEAR(m_flags, MyFlags::Foo | MyFlags::Bar)) // Are all flags in the given list clear? +//! if (WI_IS_SINGLE_FLAG_SET(m_flags)) // Is *exactly* one flag set in the given variable? +//! ~~~~ +//! @{ + +// block for documentation only +#ifdef WIL_DOXYGEN + +//! Validates that exactly ONE bit is set in compile-time constant `flag` or a compilation error is produced. +#define WI_STATIC_ASSERT_SINGLE_BIT_SET(flag) + +//! @name Bitwise modification macros +//! @{ + +//! Set multiple bitflags specified by `flags` in the variable `var`. +#define WI_SET_ALL_FLAGS(var, flags) +//! Set a single compile-time constant `flag` in the variable `var`. +#define WI_SET_FLAG(var, flag) +//! Conditionally sets a single compile-time constant `flag` in the variable `var` only if `condition` is true. +#define WI_SET_FLAG_IF(var, flag, condition) +//! Conditionally sets a single compile-time constant `flag` in the variable `var` only if `condition` is false. +#define WI_SET_FLAG_IF_FALSE(var, flag, condition) + +//! Clear multiple bitflags specified by `flags` from the variable `var`. +#define WI_CLEAR_ALL_FLAGS(var, flags) +//! Clear a single compile-time constant `flag` from the variable `var`. +#define WI_CLEAR_FLAG(var, flag) +//! Conditionally clear a single compile-time constant `flag` in the variable `var` only if `condition` is true. +#define WI_CLEAR_FLAG_IF(var, flag, condition) +//! Conditionally clear a single compile-time constant `flag` in the variable `var` only if `condition` is false. +#define WI_CLEAR_FLAG_IF_FALSE(var, flag, condition) + +//! Changes a single compile-time constant `flag` in the variable `var` to be set if `isFlagSet` is true or cleared if `isFlagSet` is false. +#define WI_UPDATE_FLAG(var, flag, isFlagSet) +//! Changes only the flags specified by `flagsMask` in the variable `var` to match the corresponding flags in `newFlags`. +#define WI_UPDATE_FLAGS_IN_MASK(var, flagsMask, newFlags) + +//! Toggles (XOR the value) of multiple bitflags specified by `flags` in the variable `var`. +#define WI_TOGGLE_ALL_FLAGS(var, flags) +//! Toggles (XOR the value) of a single compile-time constant `flag` in the variable `var`. +#define WI_TOGGLE_FLAG(var, flag) +//! @} // bitwise modification helpers + +//! @name Bitwise inspection macros +//! @{ + +//! Evaluates as true if every bitflag specified in `flags` is set within `val`. +#define WI_ARE_ALL_FLAGS_SET(val, flags) +//! Evaluates as true if one or more bitflags specified in `flags` are set within `val`. +#define WI_IS_ANY_FLAG_SET(val, flags) +//! Evaluates as true if a single compile-time constant `flag` is set within `val`. +#define WI_IS_FLAG_SET(val, flag) + +//! Evaluates as true if every bitflag specified in `flags` is clear within `val`. +#define WI_ARE_ALL_FLAGS_CLEAR(val, flags) +//! Evaluates as true if one or more bitflags specified in `flags` are clear within `val`. +#define WI_IS_ANY_FLAG_CLEAR(val, flags) +//! Evaluates as true if a single compile-time constant `flag` is clear within `val`. +#define WI_IS_FLAG_CLEAR(val, flag) + +//! Evaluates as true if exactly one bit (any bit) is set within `val`. +#define WI_IS_SINGLE_FLAG_SET(val) +//! Evaluates as true if exactly one bit from within the specified `mask` is set within `val`. +#define WI_IS_SINGLE_FLAG_SET_IN_MASK(val, mask) +//! Evaluates as true if exactly one bit (any bit) is set within `val` or if there are no bits set within `val`. +#define WI_IS_CLEAR_OR_SINGLE_FLAG_SET(val) +//! Evaluates as true if exactly one bit from within the specified `mask` is set within `val` or if there are no bits from `mask` set within `val`. +#define WI_IS_CLEAR_OR_SINGLE_FLAG_SET_IN_MASK(val, mask) +//! @} + +//! This define can be explicitly set to enable usage of PascalCase() macro names for bitwise operations. +//! Defining WIL_SUPPORT_BITOPERATION_PASCAL_NAMES ahead of including a WIL header will enable the PascalCase name variants +//! for all of the bitwise test and manipulation macros. For example, when this define is set, you can use `SetFlag(var, flag)` +//! in addition to the standard WIL macro name `WI_SET_FLAG(var, flag)`. +//! +//! These names are not enabled by default given the likelihood of a macro name like 'SetFlag' conflicting with existing code. +//! Traditionally shell has enabled these fairly natural names through the cstock header, so they are provided as an option for teams +//! to enable. +#define WIL_SUPPORT_BITOPERATION_PASCAL_NAMES + +//! @name PascalNames for bitwise helper macros +//! These are not enabled by default (see @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES for more information). +//! @{ + +//! Alias for @ref WI_SET_ALL_FLAGS when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define SetAllFlags(var, flags) +//! Alias for @ref WI_SET_FLAG when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define SetFlag(var, flag) +//! Alias for @ref WI_SET_FLAG_IF when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define SetFlagIf(var, flag, condition) +//! Alias for @ref WI_SET_FLAG_IF_FALSE when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define SetFlagIfFalse(var, flag, condition) + +//! Alias for @ref WI_CLEAR_ALL_FLAGS when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define ClearAllFlags(var, flags) +//! Alias for @ref WI_CLEAR_FLAG when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define ClearFlag(var, flag) +//! Alias for @ref WI_CLEAR_FLAG_IF when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define ClearFlagIf(var, flag, condition) +//! Alias for @ref WI_CLEAR_FLAG_IF_FALSE when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define ClearFlagIfFalse(var, flag, condition) + +//! Alias for @ref WI_UPDATE_FLAG when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define UpdateFlag(var, flag, isFlagSet) +//! Alias for @ref WI_UPDATE_FLAGS_IN_MASK when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define UpdateFlagsInMask(var, flagsMask, newFlags) + +//! Alias for @ref WI_TOGGLE_ALL_FLAGS when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define ToggleAllFlags(var, flags) +//! Alias for @ref WI_TOGGLE_FLAG when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define ToggleFlag(var, flag) + +//! Alias for @ref WI_ARE_ALL_FLAGS_SET when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define AreAllFlagsSet(val, flags) +//! Alias for @ref WI_IS_ANY_FLAG_SET when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define IsAnyFlagSet(val, flags) +//! Alias for @ref WI_IS_FLAG_SET when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define IsFlagSet(val, flag) + +//! Alias for @ref WI_ARE_ALL_FLAGS_CLEAR when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define AreAllFlagsClear(val, flags) +//! Alias for @ref WI_IS_ANY_FLAG_CLEAR when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define IsAnyFlagClear(val, flags) +//! Alias for @ref WI_IS_FLAG_CLEAR when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define IsFlagClear(val, flag) + +//! Alias for @ref WI_IS_SINGLE_FLAG_SET when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define IsSingleFlagSet(val) +//! Alias for @ref WI_IS_SINGLE_FLAG_SET_IN_MASK when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define IsSingleFlagSetInMask(val, mask) +//! Alias for @ref WI_IS_CLEAR_OR_SINGLE_FLAG_SET when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define IsClearOrSingleFlagSet(val) +//! Alias for @ref WI_IS_CLEAR_OR_SINGLE_FLAG_SET_IN_MASK when @ref WIL_SUPPORT_BITOPERATION_PASCAL_NAMES is specified. +#define IsClearOrSingleFlagSetInMask(val, mask) +//! @} // Alternate PascalNames for bitwise helpers + +#else // WIL_DOXYGEN + +#define WI_STATIC_ASSERT_SINGLE_BIT_SET(flag) sizeof(wil::details::Single_Bit_Expected_Zero_Or_Multiple_Found<__WI_IS_SINGLE_FLAG_SET(flag) != 0>) + +// Macros to manipulate flag bitmasks + +#define WI_SET_ALL_FLAGS(var, flags) ((var) |= (flags)) +#define WI_SET_FLAG(var, flag) (WI_STATIC_ASSERT_SINGLE_BIT_SET(flag), WI_SET_ALL_FLAGS(var, flag)) +#define WI_SET_FLAG_IF(var, flag, condition) do { if (wil::verify_bool(condition)) { WI_SET_FLAG(var, flag); } } while (0, 0) +#define WI_SET_FLAG_IF_FALSE(var, flag, condition) do { if (!(wil::verify_bool(condition))) { WI_SET_FLAG(var, flag); } } while (0, 0) + +#define WI_CLEAR_ALL_FLAGS(var, flags) ((var) &= ~(flags)) +#define WI_CLEAR_FLAG(var, flag) (WI_STATIC_ASSERT_SINGLE_BIT_SET(flag), WI_CLEAR_ALL_FLAGS(var, flag)) +#define WI_CLEAR_FLAG_IF(var, flag, condition) do { if (wil::verify_bool(condition)) { WI_CLEAR_FLAG(var, flag); } } while (0, 0) +#define WI_CLEAR_FLAG_IF_FALSE(var, flag, condition) do { if (!(wil::verify_bool(condition))) { WI_CLEAR_FLAG(var, flag); } } while (0, 0) + +#define WI_UPDATE_FLAG(var, flag, isFlagSet) (wil::verify_bool(isFlagSet) ? WI_SET_FLAG(var, flag) : WI_CLEAR_FLAG(var, flag)) +#define WI_UPDATE_FLAGS_IN_MASK(var, flagsMask, newFlags) wil::details::UpdateFlagsInMaskHelper(var, flagsMask, newFlags) + +#define WI_TOGGLE_FLAG(var, flag) (WI_STATIC_ASSERT_SINGLE_BIT_SET(flag), WI_TOGGLE_ALL_FLAGS(var, flag)) +#define WI_TOGGLE_ALL_FLAGS(var, flags) ((var) ^= (flags)) + +// Macros to inspect flag bitmasks + +#define WI_ARE_ALL_FLAGS_SET(val, flags) wil::details::AreAllFlagsSetHelper(val, flags) +#define WI_IS_ANY_FLAG_SET(val, flags) wil::details::IsAnyFlagSetHelper(val, flags) +#define WI_IS_FLAG_SET(val, flag) (WI_STATIC_ASSERT_SINGLE_BIT_SET(flag), WI_IS_ANY_FLAG_SET(val, flag)) + +#define WI_ARE_ALL_FLAGS_CLEAR(val, flags) wil::details::AreAllFlagsClearHelper(val, flags) +#define WI_IS_ANY_FLAG_CLEAR(val, flags) (!wil::details::AreAllFlagsSetHelper(val, flags)) +#define WI_IS_FLAG_CLEAR(val, flag) (WI_STATIC_ASSERT_SINGLE_BIT_SET(flag), WI_ARE_ALL_FLAGS_CLEAR(val, flag)) + +#define WI_IS_SINGLE_FLAG_SET(val) wil::details::IsSingleFlagSetHelper(val) +#define WI_IS_SINGLE_FLAG_SET_IN_MASK(val, mask) wil::details::IsSingleFlagSetHelper((val) & (mask)) +#define WI_IS_CLEAR_OR_SINGLE_FLAG_SET(val) wil::details::IsClearOrSingleFlagSetHelper(val) +#define WI_IS_CLEAR_OR_SINGLE_FLAG_SET_IN_MASK(val, mask) wil::details::IsClearOrSingleFlagSetHelper((val) & (mask)) + +#if defined(WIL_SUPPORT_BITOPERATION_PASCAL_NAMES) || defined(SUPPORT_BITOPERATION_PASCAL_NAMES) + +#define SetAllFlags(var, flags) WI_SET_ALL_FLAGS(var, flags) +#define SetFlag(var, flag) WI_SET_FLAG(var, flag) +#define SetFlagIf(var, flag, condition) WI_SET_FLAG_IF(var, flag, condition) +#define SetFlagIfFalse(var, flag, condition) WI_SET_FLAG_IF_FALSE(var, flag, condition) +#define ClearAllFlags(var, flags) WI_CLEAR_ALL_FLAGS(var, flags) +#define ClearFlag(var, flag) WI_CLEAR_FLAG(var, flag) +#define ClearFlagIf(var, flag, condition) WI_CLEAR_FLAG_IF(var, flag, condition) +#define ClearFlagIfFalse(var, flag, condition) WI_CLEAR_FLAG_IF_FALSE(var, flag, condition) +#define UpdateFlag(var, flag, isFlagSet) WI_UPDATE_FLAG(var, flag, isFlagSet) +#define UpdateFlagsInMask(var, flagsMask, newFlags) WI_UPDATE_FLAGS_IN_MASK(var, flagsMask, newFlags) +#define ToggleAllFlags(var, flags) WI_TOGGLE_ALL_FLAGS(var, flags) +#define ToggleFlag(var, flag) WI_TOGGLE_FLAG(var, flag) +#define AreAllFlagsSet(val, flags) WI_ARE_ALL_FLAGS_SET(val, flags) +#define IsAnyFlagSet(val, flags) WI_IS_ANY_FLAG_SET(val, flags) +#define IsFlagSet(val, flag) WI_IS_FLAG_SET(val, flag) +#define AreAllFlagsClear(val, flags) WI_ARE_ALL_FLAGS_CLEAR(val, flags) +#define IsAnyFlagClear(val, flags) WI_IS_ANY_FLAG_CLEAR(val, flags) +#define IsFlagClear(val, flag) WI_IS_FLAG_CLEAR(val, flag) +#define IsSingleFlagSet (val) WI_IS_SINGLE_FLAG_SET(val) +#define IsSingleFlagSetInMask(val, mask) WI_IS_SINGLE_FLAG_SET_IN_MASK(val, mask) +#define IsClearOrSingleFlagSet(val) WI_IS_CLEAR_OR_SINGLE_FLAG_SET(val) +#define IsClearOrSingleFlagSetInMask(val, mask) WI_IS_CLEAR_OR_SINGLE_FLAG_SET_IN_MASK(val, mask) + +#endif // WIL_SUPPORT_BITOPERATION_PASCAL_NAMES +#endif // !WIL_DOXYGEN + +//! @deprecated Will be removed in the future. +#define WI_SET_FLAG_IF_TRUE WI_SET_FLAG_IF + +//! @} // end bitfields group + + +#if defined(WIL_DOXYGEN) +//! This macro provides a C++ header with a guaranteed initialization function. +//! Normally, were a global object's constructor used for this purpose, the optimizer/linker might throw +//! the object away if it's unreferenced (which throws away the side-effects that the initialization function +//! was trying to achieve). Using this macro forces linker inclusion of a variable that's initialized by the +//! provided function to elide that optimization. +//! +//! This functionality is primarily provided as a building block for header-based libraries (such as WIL) +//! to be able to layer additional functionality into other libraries by their mere inclusion. Alternative models +//! of initialization should be used whenever they are available. +//! ~~~~ +//! #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +//! WI_HEADER_INITITALIZATION_FUNCTION(InitializeDesktopFamilyApis, [] +//! { +//! g_pfnGetModuleName = GetCurrentModuleName; +//! g_pfnFailFastInLoaderCallout = FailFastInLoaderCallout; +//! g_pfnRtlNtStatusToDosErrorNoTeb = RtlNtStatusToDosErrorNoTeb; +//! return 1; +//! }); +//! #endif +//! ~~~~ +//! The above example is used within WIL to decide whether or not the library containing WIL is allowed to use +//! desktop APIs. Building this functionality as #IFDEFs within functions would create ODR violations, whereas +//! doing it with global function pointers and header initialization allows a runtime determination. +#define WI_HEADER_INITITALIZATION_FUNCTION(name, fn) +#elif defined(_M_IX86) +#define WI_HEADER_INITITALIZATION_FUNCTION(name, fn) \ + extern "C" { __declspec(selectany) size_t g_header_init_ ## name = fn(); } \ + __pragma(comment(linker, "/INCLUDE:_g_header_init_" #name)) +#elif defined(_M_IA64) || defined(_M_AMD64) || defined(_M_ARM) || defined(_M_ARM64) +#define WI_HEADER_INITITALIZATION_FUNCTION(name, fn) \ + extern "C" { __declspec(selectany) size_t g_header_init_ ## name = fn(); } \ + __pragma(comment(linker, "/INCLUDE:g_header_init_" #name)) +#else + #error linker pragma must include g_header_init variation +#endif + + +//! All Windows Internal Library classes and functions are located within the "wil" namespace. +//! The 'wil' namespace is an intentionally short name as the intent is for code to be able to reference +//! the namespace directly (example: `wil::srwlock lock;`) without a using statement. Resist adding a using +//! statement for wil to avoid introducing potential name collisions between wil and other namespaces. +namespace wil +{ + //! @defgroup outparam Output Parameters + //! Improve the conciseness of assigning values to optional output parameters. + //! @{ + + //! Assign a value-type to an optional output parameter. + //! Functions may have optional output parameters that want to receive a value calculated + //! as part of the function. Using this routine allows removal of many `if (param != nullptr)` blocks when + //! commonly dealing with out parameters in routines. + //! ~~~~ + //! void PerformTask(_Out_opt_ TaskResult* pResult = nullptr) + //! { + //! TaskResult result = TaskResult::None; + //! // calculate result + //! wil::AssignToOptParam(pResult, result); + //! } + //! ~~~~ + //! @param outParam The optional out-pointer + //! @param val The value to set in `outParam` if the out-pointer is non-null + template + inline void AssignToOptParam(_Out_opt_ T *outParam, T val) + { + if (outParam != nullptr) + { + *outParam = val; + } + } + + //! Assign nullptr to an optional output pointer parameter. + //! Functions may have optional output pointer parameters that want to receive an object from + //! a function. Using this routine provides trivial best practice initialization of an optional pointer-based + //! output parameter on routine entry and will typically be combined with use of @ref AssignToOptParam or + //! @ref DetachToOptParam on routine exit. + //! ~~~~ + //! bool HasString(_Out_opt_ PCWSTR* outString = nullptr) + //! { + //! wil::AssignNullToOptParam(outString); + //! wil::unique_cotaskmem_string str = GetStringInternal(); + //! bool hasString = (str != nullptr); + //! wil::DetachToOptParam(outString, str); + //! return hasString; + //! } + //! ~~~~ + //! @param outParam The optional out-pointer + //! @param val The value to set in `outParam` if the out-pointer is non-null + template + inline void AssignNullToOptParam(_Out_opt_ T *outParam) + { + if (outParam != nullptr) + { + *outParam = nullptr; + } + } + + //! @} // end output parameter helpers + + + //! @cond + namespace details + { + template + __forceinline bool verify_bool_helper(T const& t, wistd::true_type) + { + return static_cast(t); + } + + template + __forceinline bool verify_bool_helper(T const& t, wistd::false_type) + { + static_assert((wistd::is_same::value), "Wrong Type: bool/BOOL/BOOLEAN/boolean expected"); + } + + template <> + __forceinline bool verify_bool_helper(bool const& t, wistd::false_type) + { + return t; + } + + template <> + __forceinline bool verify_bool_helper(int const& t, wistd::false_type) // This supports BOOL + { + return (t != 0); + } + + template <> + __forceinline bool verify_bool_helper(unsigned char const& t, wistd::false_type) // This supports BOOLEAN and boolean + { + return !!t; + } + } + //! @endcond + + + //! @defgroup typesafety Type Validation + //! Helpers to validate variable types to prevent accidental, but allowed type conversions. + //! These helpers are most useful when building macros that accept a particular type. Putting these functions around the types accepted + //! prior to pushing that type through to a function (or using it within the macro) allows the macro to add an additional layer of type + //! safety that would ordinarily be stripped away by C++ implicit conversions. This system is extensively used in the error handling helper + //! macros to validate the types given to various macro parameters. + //! @{ + + //! Verify that `val` can be evaluated as a logical bool. + //! Other types will generate an intentional compilation error. Allowed types for a logical bool are bool, BOOL, + //! boolean, BOOLEAN, and classes with an explicit bool cast. + //! @param val The logical bool expression + //! @return A C++ bool representing the evaluation of `val`. + template + __forceinline bool verify_bool(T const& val) + { + return details::verify_bool_helper(val, typename wistd::is_class::type()); + } + + //! Verify that `val` is a Win32 BOOL value. + //! Other types (including other logical bool expressions) will generate an intentional compilation error. Note that this will + //! accept any `int` value as long as that is the underlying typedef behind `BOOL`. + //! @param val The Win32 BOOL returning expression + //! @return A Win32 BOOL representing the evaluation of `val`. + template + __forceinline int verify_BOOL(T const& val) + { + // Note: Written in terms of 'int' as BOOL is actually: typedef int BOOL; + static_assert((wistd::is_same::value), "Wrong Type: BOOL expected"); + return val; + } + + //! Verify that `hr` is an HRESULT value. + //! Other types will generate an intentional compilation error. Note that this will accept any `long` value as that is the + //! underlying typedef behind HRESULT. + //! + //! Note that occasionally you might run into an HRESULT which is directly defined with a #define, such as: + //! ~~~~ + //! #define UIA_E_NOTSUPPORTED 0x80040204 + //! ~~~~ + //! Though this looks like an `HRESULT`, this is actually an `unsigned long` (the hex specification forces this). When + //! these are encountered and they are NOT in the public SDK (have not yet shipped to the public), then you should change + //! their definition to match the manner in which `HRESULT` constants are defined in winerror.h: + //! ~~~~ + //! #define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001L) + //! ~~~~ + //! When these are encountered in the public SDK, their type should not be changed and you should use a static_cast + //! to use this value in a macro that utilizes `verify_hresult`, for example: + //! ~~~~ + //! RETURN_HR_IF_FALSE(static_cast(UIA_E_NOTSUPPORTED), (patternId == UIA_DragPatternId)); + //! ~~~~ + //! @param val The HRESULT returning expression + //! @return An HRESULT representing the evaluation of `val`. + template + _Post_satisfies_(return == hr) + inline long verify_hresult(const T hr) + { + // Note: Written in terms of 'int' as HRESULT is actually: typedef _Return_type_success_(return >= 0) long HRESULT + static_assert(wistd::is_same::value, "Wrong Type: HRESULT expected"); + return hr; + } + //! @} // end type validation routines + + + // Implementation details for macros and helper functions... do not use directly. + //! @cond + namespace details + { + // Use size-specific casts to avoid sign extending numbers -- avoid warning C4310: cast truncates constant value + #define __WI_MAKE_UNSIGNED(val) \ + (__pragma(warning(push)) __pragma(warning(disable: 4310 4309)) (sizeof(val) == 1 ? static_cast(val) : \ + sizeof(val) == 2 ? static_cast(val) : \ + sizeof(val) == 4 ? static_cast(val) : \ + static_cast(val)) __pragma(warning(pop))) + #define __WI_IS_UNSIGNED_SINGLE_FLAG_SET(val) ((val) && !((val) & ((val) - 1))) + #define __WI_IS_SINGLE_FLAG_SET(val) __WI_IS_UNSIGNED_SINGLE_FLAG_SET(__WI_MAKE_UNSIGNED(val)) + + template + class Single_Bit_Expected_Zero_Or_Multiple_Found + { + // If you see an error here (something like): + // wicommon.h(228): error C2118: negative subscript + // helpersuts.cpp(91) : see reference to class template instantiation 'wil::details::Single_Bit_Expected_Zero_Or_Multiple_Found' being compiled + // The cause is likely the incorrect use of a ZERO or MULTI-BIT mask from a macro that requires a single bit be + // set (examples: WI_IS_FLAG_SET, WI_SET_FLAG). + // For non-static data, the corresponding multiple flag macros can be used (WI_ARE_ALL_FLAGS_SET, WI_SET_ALL_FLAGS, etc) + char dummyArray[fSingleStaticFlag ? 1 : -1]; + }; + + template + __forceinline bool AreAllFlagsSetHelper(TVal val, TFlags flags) + { + return ((val & flags) == static_cast(flags)); + } + + template + __forceinline bool IsSingleFlagSetHelper(TVal val) + { + return __WI_IS_SINGLE_FLAG_SET(val); + } + + template + __forceinline bool IsClearOrSingleFlagSetHelper(TVal val) + { + return ((val == static_cast::type>(0)) || IsSingleFlagSetHelper(val)); + } + + template + __forceinline bool IsAnyFlagSetHelper(TVal val, TFlags flags) + { + return ((val & flags) != static_cast(0)); + } + + template + __forceinline bool AreAllFlagsClearHelper(TVal val, TFlags flags) + { + return ((val & flags) == static_cast(0)); + } + + template + __forceinline void UpdateFlagsInMaskHelper(_Inout_ TVal& val, TMask mask, TFlags flags) + { + val = static_cast::type>((val & ~mask) | (flags & mask)); + } + + } // details + +} // wil + +#pragma warning(pop) diff --git a/Frameworks/include/wil/result.h b/Frameworks/include/wil/result.h new file mode 100644 index 0000000000..55e5c5e1db --- /dev/null +++ b/Frameworks/include/wil/result.h @@ -0,0 +1,4729 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** +// Windows Internal Libraries (wil) +//! @file +//! Windows Error Handling Helpers: standard error handling mechanisms across return codes, fail fast, exceptions and logging + +#pragma once + +#include +#include +#include // malloc / free used for internal buffer management +#include // provides the _ReturnAddress() intrinsic +#include "Common.h" +#if defined(WIL_ENABLE_EXCEPTIONS) && !defined(WIL_SUPPRESS_NEW) +#include // provides std::bad_alloc in the windows and public CRT headers +#endif + +#ifndef STATUS_SUCCESS +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +#endif +#if !defined(_NTDEF_) +typedef _Return_type_success_(return >= 0) LONG NTSTATUS; +#endif + +#pragma warning(push) +#pragma warning(disable:4714) // __forceinline not honored + +//***************************************************************************** +// Behavioral setup (error handling macro configuration) +//***************************************************************************** +// Set any of the following macros to the values given below before including Result.h to +// control the error handling macro's trade-offs between diagnostics and performance + +// RESULT_DIAGNOSTICS_LEVEL +// This define controls the level of diagnostic instrumentation that is built into the binary as a +// byproduct of using the macros. The amount of diagnostic instrumentation that is supplied is +// a trade-off between diagnosibility of issues and code size and performance. The modes are: +// 0 - No diagnostics, smallest & fastest (subject to tail-merge) +// 1 - No diagnostics, unique call sites for each macro (defeat's tail-merge) +// 2 - Line number +// 3 - Line number + source filename +// 4 - Line number + source filename + function name +// 5 - Line number + source filename + function name + code within the macro +// By default, mode 3 is used in free builds and mode 5 is used in checked builds. Note that the +// _ReturnAddress() will always be available through all modes when possible. + +// RESULT_INCLUDE_CALLER_RETURNADDRESS +// This controls whether or not the _ReturnAddress() of the function that includes the macro will +// be reported to telemetry. Note that this is in addition to the _ReturnAddress() of the actual +// macro position (which is always reported). The values are: +// 0 - The address is not included +// 1 - The address is included +// The default value is '1'. + +// RESULT_INLINE_ERROR_TESTS +// For conditional macros (other than RETURN_XXX), this controls whether branches will be evaluated +// within the call containing the macro or will be forced into the function called by the macros. +// Pushing branching into the called function reduces code size and the number of unique branches +// evaluated, but increases the instruction count executed per macro. +// 0 - Branching will not happen inline to the macros +// 1 - Branching is pushed into the calling function via __forceinline +// The default value is '1'. Note that XXX_MSG functions are always effectively mode '0' due to the +// compiler's unwillingness to inline var-arg functions. + +// RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST +// RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST +// RESULT_INLINE_ERROR_TESTS_FAIL_FAST +// These defines are identical to those above in form/function, but only applicable to fail fast error +// handling allowing a process to have different diagnostic information and performance characteristics +// for fail fast than for other error handling given the different reporting infrastructure (Watson +// vs Telemetry). + +// RESULT_SUPPRESS_PRERELEASE +// RESULT_FORCE_PRERELEASE +// Set one or the other to always force (or deny) pre-release behavior from within the WIL macros. +// Current pre-release behavioral differences are: +// * RETURN_XXX macros (without _MSG or _LOG suffix) include diagnostic information and report +// telemetry (they will not do so in release) +// * More aggressive use of FailFast in scenarios where failures are uncommon to help find bugs +// (an example is use of ::GetLastError() when the last error is not set). This is elevated +// to fail fast in pre-release to raise visibility. In release it reports a generic error (and +// telemetry) given that its likely the failure has gone undiscovered until then. +// * Default use of FailFast when converting an unknown exception to an HRESULT. If the exception is +// unknown, it's like a bug (or a situation where an exception conversion function should be +// supported). In release it reports a generic error given the possibility that the particular +// exception type has not been seen until that point. +// By default, WIL picks up the PRERELEASE define and changes behavior accordingly. + + +// Setup the debug behavior +#ifndef RESULT_DEBUG +#if (DBG || defined(DEBUG) || defined(_DEBUG)) && !defined(NDEBUG) +#define RESULT_DEBUG +#endif +#endif + +// Set the default diagnostic mode +// Note that RESULT_DEBUG_INFO and RESULT_SUPPRESS_DEBUG_INFO are older deprecated models of controlling mode +#ifndef RESULT_DIAGNOSTICS_LEVEL +#if (defined(DBG) || defined(_DEBUG) || defined(RESULT_DEBUG_INFO)) && !defined(RESULT_SUPPRESS_DEBUG_INFO) +#define RESULT_DIAGNOSTICS_LEVEL 5 +#else +#define RESULT_DIAGNOSTICS_LEVEL 3 +#endif +#endif +#ifndef RESULT_INCLUDE_CALLER_RETURNADDRESS +#define RESULT_INCLUDE_CALLER_RETURNADDRESS 1 +#endif +#ifndef RESULT_INLINE_ERROR_TESTS +#define RESULT_INLINE_ERROR_TESTS 1 +#endif +#ifndef RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST +#define RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST RESULT_DIAGNOSTICS_LEVEL +#endif +#ifndef RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST +#define RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST RESULT_INCLUDE_CALLER_RETURNADDRESS +#endif +#ifndef RESULT_INLINE_ERROR_TESTS_FAIL_FAST +#define RESULT_INLINE_ERROR_TESTS_FAIL_FAST RESULT_INLINE_ERROR_TESTS +#endif + +// Lock to prerelease behavior. This is a short-term fix to avoid ODR violations. +#define RESULT_FORCE_PRERELEASE + +// Setup the default pre-release behavior +#ifndef RESULT_PRERELEASE +#if (defined(RESULT_FORCE_PRERELEASE) || ((defined(DBG) || defined(_DEBUG)) && !defined(RESULT_SUPPRESS_PRERELEASE))) +#define RESULT_PRERELEASE +#endif +#endif + + +//***************************************************************************** +// Win32 specific error macros +//***************************************************************************** + +#define FAILED_WIN32(win32err) ((win32err) != 0) +#define SUCCEEDED_WIN32(win32err) ((win32err) == 0) + + +//***************************************************************************** +// NT_STATUS specific error macros +//***************************************************************************** + +#define FAILED_NTSTATUS(status) (((NTSTATUS)(status)) < 0) +#define SUCCEEDED_NTSTATUS(status) (((NTSTATUS)(status)) >= 0) + + +//***************************************************************************** +// Testing helpers - redefine to run unit tests against fail fast +//***************************************************************************** + +#ifndef RESULT_NORETURN +#define RESULT_NORETURN __declspec(noreturn) +#endif +#ifndef RESULT_NORETURN_NULL +#define RESULT_NORETURN_NULL _Ret_notnull_ +#endif +#ifndef RESULT_RAISE_FAST_FAIL_EXCEPTION +#define RESULT_RAISE_FAST_FAIL_EXCEPTION __fastfail(FAST_FAIL_FATAL_APP_EXIT) +#endif + + +//***************************************************************************** +// Helpers to setup the macros and functions used below... do not directly use. +//***************************************************************************** + +//! @cond +#define __R_FN_PARAMS_FULL _In_opt_ void* callerReturnAddress, unsigned int lineNumber, _In_opt_ PCSTR fileName, _In_opt_ PCSTR functionName, _In_opt_ PCSTR code, void* returnAddress +#define __R_FN_LOCALS_FULL_RA void* callerReturnAddress = nullptr; unsigned int lineNumber = 0; PCSTR fileName = nullptr; PCSTR functionName = nullptr; PCSTR code = nullptr; void* returnAddress = _ReturnAddress(); +#define __R_ENABLE_IF_IS_CLASS(ptrType) typename wistd::enable_if_t::value, void*> = 0 +#define __R_ENABLE_IF_IS_NOT_CLASS(ptrType) typename wistd::enable_if_t::value, void*> = 0 +// NOTE: This BEGINs the common macro handling (__R_ prefix) for non-fail fast handled cases +// This entire section will be repeated below for fail fast (__RFF_ prefix). +#define __R_COMMA , +#define __R_FN_CALL_FULL callerReturnAddress, lineNumber, fileName, functionName, code, returnAddress +#define __R_FN_CALL_FULL_RA callerReturnAddress, lineNumber, fileName, functionName, code, _ReturnAddress() +// The following macros assemble the varying amount of data we want to collect from the macros, treating it uniformly +#if (RESULT_DIAGNOSTICS_LEVEL >= 2) // line number +#define __R_IF_LINE(term) term +#define __R_IF_NOT_LINE(term) +#define __R_IF_COMMA , +#else +#define __R_IF_LINE(term) +#define __R_IF_NOT_LINE(term) term +#define __R_IF_COMMA +#endif +#if (RESULT_DIAGNOSTICS_LEVEL >= 3) // line number + file name +#define __R_IF_FILE(term) term +#define __R_IF_NOT_FILE(term) +#else +#define __R_IF_FILE(term) +#define __R_IF_NOT_FILE(term) term +#endif +#if (RESULT_DIAGNOSTICS_LEVEL >= 4) // line number + file name + function name +#define __R_IF_FUNCTION(term) term +#define __R_IF_NOT_FUNCTION(term) +#else +#define __R_IF_FUNCTION(term) +#define __R_IF_NOT_FUNCTION(term) term +#endif +#if (RESULT_DIAGNOSTICS_LEVEL >= 5) // line number + file name + function name + macro code +#define __R_IF_CODE(term) term +#define __R_IF_NOT_CODE(term) +#else +#define __R_IF_CODE(term) +#define __R_IF_NOT_CODE(term) term +#endif +#if (RESULT_INCLUDE_CALLER_RETURNADDRESS == 1) +#define __R_IF_CALLERADDRESS(term) term +#define __R_IF_NOT_CALLERADDRESS(term) +#else +#define __R_IF_CALLERADDRESS(term) +#define __R_IF_NOT_CALLERADDRESS(term) term +#endif +#if (RESULT_INCLUDE_CALLER_RETURNADDRESS == 1) || (RESULT_DIAGNOSTICS_LEVEL >= 2) +#define __R_IF_TRAIL_COMMA , +#else +#define __R_IF_TRAIL_COMMA +#endif +// Assemble the varying amounts of data into a single macro +#define __R_INFO_ONLY(CODE) __R_IF_CALLERADDRESS(_ReturnAddress() __R_IF_COMMA) __R_IF_LINE(__LINE__) __R_IF_FILE(__R_COMMA __FILE__) __R_IF_FUNCTION(__R_COMMA __FUNCTION__) __R_IF_CODE(__R_COMMA CODE) +#define __R_INFO(CODE) __R_INFO_ONLY(CODE) __R_IF_TRAIL_COMMA +#define __R_FN_PARAMS_ONLY __R_IF_CALLERADDRESS(void* callerReturnAddress __R_IF_COMMA) __R_IF_LINE(unsigned int lineNumber) __R_IF_FILE(__R_COMMA _In_opt_ PCSTR fileName) __R_IF_FUNCTION(__R_COMMA _In_opt_ PCSTR functionName) __R_IF_CODE(__R_COMMA _In_opt_ PCSTR code) +#define __R_FN_PARAMS __R_FN_PARAMS_ONLY __R_IF_TRAIL_COMMA +#define __R_FN_CALL_ONLY __R_IF_CALLERADDRESS(callerReturnAddress __R_IF_COMMA) __R_IF_LINE(lineNumber) __R_IF_FILE(__R_COMMA fileName) __R_IF_FUNCTION(__R_COMMA functionName) __R_IF_CODE(__R_COMMA code) +#define __R_FN_CALL __R_FN_CALL_ONLY __R_IF_TRAIL_COMMA +#define __R_FN_LOCALS __R_IF_NOT_CALLERADDRESS(void* callerReturnAddress = nullptr;) __R_IF_NOT_LINE(unsigned int lineNumber = 0;) __R_IF_NOT_FILE(PCSTR fileName = nullptr;) __R_IF_NOT_FUNCTION(PCSTR functionName = nullptr;) __R_IF_NOT_CODE(PCSTR code = nullptr;) +#define __R_FN_LOCALS_RA __R_IF_NOT_CALLERADDRESS(void* callerReturnAddress = nullptr;) __R_IF_NOT_LINE(unsigned int lineNumber = 0;) __R_IF_NOT_FILE(PCSTR fileName = nullptr;) __R_IF_NOT_FUNCTION(PCSTR functionName = nullptr;) __R_IF_NOT_CODE(PCSTR code = nullptr;) void* returnAddress = _ReturnAddress(); +#define __R_FN_UNREFERENCED __R_IF_CALLERADDRESS(callerReturnAddress;) __R_IF_LINE(lineNumber;) __R_IF_FILE(fileName;) __R_IF_FUNCTION(functionName;) __R_IF_CODE(code;) +// 1) Direct Methods +// * Called Directly by Macros +// * Always noinline +// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL == 1) +#if (RESULT_DIAGNOSTICS_LEVEL == 1) +#define __R_DIRECT_METHOD(RetType, MethodName) template inline __declspec(noinline) RetType MethodName +#define __R_DIRECT_NORET_METHOD(RetType, MethodName) template inline __declspec(noinline) RESULT_NORETURN RetType MethodName +#else +#define __R_DIRECT_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName +#define __R_DIRECT_NORET_METHOD(RetType, MethodName) inline __declspec(noinline) RESULT_NORETURN RetType MethodName +#endif +#define __R_DIRECT_FN_PARAMS __R_FN_PARAMS +#define __R_DIRECT_FN_PARAMS_ONLY __R_FN_PARAMS_ONLY +#define __R_DIRECT_FN_CALL __R_FN_CALL_FULL_RA __R_COMMA +#define __R_DIRECT_FN_CALL_ONLY __R_FN_CALL_FULL_RA +// 2) Internal Methods +// * Only called by Conditional routines +// * 'inline' when (RESULT_INLINE_ERROR_TESTS = 0 and RESULT_DIAGNOSTICS_LEVEL != 1), otherwise noinline (directly called by code when branching is forceinlined) +// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL == 1 and RESULT_INLINE_ERROR_TESTS = 1) +#if (RESULT_DIAGNOSTICS_LEVEL == 1) +#define __R_INTERNAL_NOINLINE_METHOD(MethodName) inline __declspec(noinline) void MethodName +#define __R_INTERNAL_NOINLINE_NORET_METHOD(MethodName) inline __declspec(noinline) RESULT_NORETURN void MethodName +#define __R_INTERNAL_INLINE_METHOD(MethodName) template inline __declspec(noinline) void MethodName +#define __R_INTERNAL_INLINE_NORET_METHOD(MethodName) template inline __declspec(noinline) RESULT_NORETURN void MethodName +#define __R_CALL_INTERNAL_INLINE_METHOD(MethodName) MethodName +#else +#define __R_INTERNAL_NOINLINE_METHOD(MethodName) inline void MethodName +#define __R_INTERNAL_NOINLINE_NORET_METHOD(MethodName) inline RESULT_NORETURN void MethodName +#define __R_INTERNAL_INLINE_METHOD(MethodName) inline __declspec(noinline) void MethodName +#define __R_INTERNAL_INLINE_NORET_METHOD(MethodName) inline __declspec(noinline) RESULT_NORETURN void MethodName +#define __R_CALL_INTERNAL_INLINE_METHOD(MethodName) MethodName +#endif +#define __R_CALL_INTERNAL_NOINLINE_METHOD(MethodName) MethodName +#define __R_INTERNAL_NOINLINE_FN_PARAMS __R_FN_PARAMS void* returnAddress __R_COMMA +#define __R_INTERNAL_NOINLINE_FN_PARAMS_ONLY __R_FN_PARAMS void* returnAddress +#define __R_INTERNAL_NOINLINE_FN_CALL __R_FN_CALL_FULL __R_COMMA +#define __R_INTERNAL_NOINLINE_FN_CALL_ONLY __R_FN_CALL_FULL +#define __R_INTERNAL_INLINE_FN_PARAMS __R_FN_PARAMS +#define __R_INTERNAL_INLINE_FN_PARAMS_ONLY __R_FN_PARAMS_ONLY +#define __R_INTERNAL_INLINE_FN_CALL __R_FN_CALL_FULL_RA __R_COMMA +#define __R_INTERNAL_INLINE_FN_CALL_ONLY __R_FN_CALL_FULL_RA +#if (RESULT_INLINE_ERROR_TESTS == 0) +#define __R_INTERNAL_METHOD __R_INTERNAL_NOINLINE_METHOD +#define __R_INTERNAL_NORET_METHOD __R_INTERNAL_NOINLINE_NORET_METHOD +#define __R_CALL_INTERNAL_METHOD __R_CALL_INTERNAL_NOINLINE_METHOD +#define __R_INTERNAL_FN_PARAMS __R_INTERNAL_NOINLINE_FN_PARAMS +#define __R_INTERNAL_FN_PARAMS_ONLY __R_INTERNAL_NOINLINE_FN_PARAMS_ONLY +#define __R_INTERNAL_FN_CALL __R_INTERNAL_NOINLINE_FN_CALL +#define __R_INTERNAL_FN_CALL_ONLY __R_INTERNAL_NOINLINE_FN_CALL_ONLY +#else +#define __R_INTERNAL_METHOD __R_INTERNAL_INLINE_METHOD +#define __R_INTERNAL_NORET_METHOD __R_INTERNAL_INLINE_NORET_METHOD +#define __R_CALL_INTERNAL_METHOD __R_CALL_INTERNAL_INLINE_METHOD +#define __R_INTERNAL_FN_PARAMS __R_INTERNAL_INLINE_FN_PARAMS +#define __R_INTERNAL_FN_PARAMS_ONLY __R_INTERNAL_INLINE_FN_PARAMS_ONLY +#define __R_INTERNAL_FN_CALL __R_INTERNAL_INLINE_FN_CALL +#define __R_INTERNAL_FN_CALL_ONLY __R_INTERNAL_INLINE_FN_CALL_ONLY +#endif +// 3) Conditional Methods +// * Called Directly by Macros +// * May be noinline or __forceinline depending upon (RESULT_INLINE_ERROR_TESTS) +// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL == 1) +#if (RESULT_DIAGNOSTICS_LEVEL == 1) +#define __R_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName) template inline __declspec(noinline) RetType MethodName +#define __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName +#define __R_CONDITIONAL_INLINE_METHOD(RetType, MethodName) template __forceinline RetType MethodName +#define __R_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName) __forceinline RetType MethodName +#define __R_CONDITIONAL_PARTIAL_TEMPLATE unsigned int optimizerCounter __R_COMMA +#else +#define __R_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName +#define __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName +#define __R_CONDITIONAL_INLINE_METHOD(RetType, MethodName) __forceinline RetType MethodName +#define __R_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName) __forceinline RetType MethodName +#define __R_CONDITIONAL_PARTIAL_TEMPLATE +#endif +#define __R_CONDITIONAL_NOINLINE_FN_CALL __R_FN_CALL _ReturnAddress() __R_COMMA +#define __R_CONDITIONAL_NOINLINE_FN_CALL_ONLY __R_FN_CALL _ReturnAddress() +#define __R_CONDITIONAL_INLINE_FN_CALL __R_FN_CALL +#define __R_CONDITIONAL_INLINE_FN_CALL_ONLY __R_FN_CALL_ONLY +#if (RESULT_INLINE_ERROR_TESTS == 0) +#define __R_CONDITIONAL_METHOD __R_CONDITIONAL_NOINLINE_METHOD +#define __R_CONDITIONAL_TEMPLATE_METHOD __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD +#define __R_CONDITIONAL_FN_CALL __R_CONDITIONAL_NOINLINE_FN_CALL +#define __R_CONDITIONAL_FN_CALL_ONLY __R_CONDITIONAL_NOINLINE_FN_CALL_ONLY +#else +#define __R_CONDITIONAL_METHOD __R_CONDITIONAL_INLINE_METHOD +#define __R_CONDITIONAL_TEMPLATE_METHOD __R_CONDITIONAL_INLINE_TEMPLATE_METHOD +#define __R_CONDITIONAL_FN_CALL __R_CONDITIONAL_INLINE_FN_CALL +#define __R_CONDITIONAL_FN_CALL_ONLY __R_CONDITIONAL_INLINE_FN_CALL_ONLY +#endif +#define __R_CONDITIONAL_FN_PARAMS __R_FN_PARAMS +#define __R_CONDITIONAL_FN_PARAMS_ONLY __R_FN_PARAMS_ONLY +// Macro call-site helpers +#define __R_NS_ASSEMBLE2(ri, rd) in##ri##diag##rd // Differing internal namespaces eliminate ODR violations between modes +#define __R_NS_ASSEMBLE(ri, rd) __R_NS_ASSEMBLE2(ri, rd) +#define __R_NS_NAME __R_NS_ASSEMBLE(RESULT_INLINE_ERROR_TESTS, RESULT_DIAGNOSTICS_LEVEL) +#define __R_NS wil::details::__R_NS_NAME +#if (RESULT_DIAGNOSTICS_LEVEL == 1) +#define __R_FN(MethodName) __R_NS:: MethodName <__COUNTER__> +#else +#define __R_FN(MethodName) __R_NS:: MethodName +#endif +// NOTE: This ENDs the common macro handling (__R_ prefix) for non-fail fast handled cases +// This entire section is repeated below for fail fast (__RFF_ prefix). For ease of editing this section, the +// process is to copy/paste, and search and replace (__R_ -> __RFF_), (RESULT_DIAGNOSTICS_LEVEL -> RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST), +// (RESULT_INLINE_ERROR_TESTS -> RESULT_INLINE_ERROR_TESTS_FAIL_FAST) and (RESULT_INCLUDE_CALLER_RETURNADDRESS -> RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST) +#define __RFF_COMMA , +#define __RFF_FN_CALL_FULL callerReturnAddress, lineNumber, fileName, functionName, code, returnAddress +#define __RFF_FN_CALL_FULL_RA callerReturnAddress, lineNumber, fileName, functionName, code, _ReturnAddress() +// The following macros assemble the varying amount of data we want to collect from the macros, treating it uniformly +#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 2) // line number +#define __RFF_IF_LINE(term) term +#define __RFF_IF_NOT_LINE(term) +#define __RFF_IF_COMMA , +#else +#define __RFF_IF_LINE(term) +#define __RFF_IF_NOT_LINE(term) term +#define __RFF_IF_COMMA +#endif +#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 3) // line number + file name +#define __RFF_IF_FILE(term) term +#define __RFF_IF_NOT_FILE(term) +#else +#define __RFF_IF_FILE(term) +#define __RFF_IF_NOT_FILE(term) term +#endif +#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 4) // line number + file name + function name +#define __RFF_IF_FUNCTION(term) term +#define __RFF_IF_NOT_FUNCTION(term) +#else +#define __RFF_IF_FUNCTION(term) +#define __RFF_IF_NOT_FUNCTION(term) term +#endif +#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 5) // line number + file name + function name + macro code +#define __RFF_IF_CODE(term) term +#define __RFF_IF_NOT_CODE(term) +#else +#define __RFF_IF_CODE(term) +#define __RFF_IF_NOT_CODE(term) term +#endif +#if (RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST == 1) +#define __RFF_IF_CALLERADDRESS(term) term +#define __RFF_IF_NOT_CALLERADDRESS(term) +#else +#define __RFF_IF_CALLERADDRESS(term) +#define __RFF_IF_NOT_CALLERADDRESS(term) term +#endif +#if (RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST == 1) || (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 2) +#define __RFF_IF_TRAIL_COMMA , +#else +#define __RFF_IF_TRAIL_COMMA +#endif +// Assemble the varying amounts of data into a single macro +#define __RFF_INFO_ONLY(CODE) __RFF_IF_CALLERADDRESS(_ReturnAddress() __RFF_IF_COMMA) __RFF_IF_LINE(__LINE__) __RFF_IF_FILE(__RFF_COMMA __FILE__) __RFF_IF_FUNCTION(__RFF_COMMA __FUNCTION__) __RFF_IF_CODE(__RFF_COMMA CODE) +#define __RFF_INFO(CODE) __RFF_INFO_ONLY(CODE) __RFF_IF_TRAIL_COMMA +#define __RFF_FN_PARAMS_ONLY __RFF_IF_CALLERADDRESS(void* callerReturnAddress __RFF_IF_COMMA) __RFF_IF_LINE(unsigned int lineNumber) __RFF_IF_FILE(__RFF_COMMA _In_opt_ PCSTR fileName) __RFF_IF_FUNCTION(__RFF_COMMA _In_opt_ PCSTR functionName) __RFF_IF_CODE(__RFF_COMMA _In_opt_ PCSTR code) +#define __RFF_FN_PARAMS __RFF_FN_PARAMS_ONLY __RFF_IF_TRAIL_COMMA +#define __RFF_FN_CALL_ONLY __RFF_IF_CALLERADDRESS(callerReturnAddress __RFF_IF_COMMA) __RFF_IF_LINE(lineNumber) __RFF_IF_FILE(__RFF_COMMA fileName) __RFF_IF_FUNCTION(__RFF_COMMA functionName) __RFF_IF_CODE(__RFF_COMMA code) +#define __RFF_FN_CALL __RFF_FN_CALL_ONLY __RFF_IF_TRAIL_COMMA +#define __RFF_FN_LOCALS __RFF_IF_NOT_CALLERADDRESS(void* callerReturnAddress = nullptr;) __RFF_IF_NOT_LINE(unsigned int lineNumber = 0;) __RFF_IF_NOT_FILE(PCSTR fileName = nullptr;) __RFF_IF_NOT_FUNCTION(PCSTR functionName = nullptr;) __RFF_IF_NOT_CODE(PCSTR code = nullptr;) +#define __RFF_FN_UNREFERENCED __RFF_IF_CALLERADDRESS(callerReturnAddress;) __RFF_IF_LINE(lineNumber;) __RFF_IF_FILE(fileName;) __RFF_IF_FUNCTION(functionName;) __RFF_IF_CODE(code;) +// 1) Direct Methods +// * Called Directly by Macros +// * Always noinline +// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) +#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) +#define __RFF_DIRECT_METHOD(RetType, MethodName) template inline __declspec(noinline) RetType MethodName +#define __RFF_DIRECT_NORET_METHOD(RetType, MethodName) template inline __declspec(noinline) RESULT_NORETURN RetType MethodName +#else +#define __RFF_DIRECT_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName +#define __RFF_DIRECT_NORET_METHOD(RetType, MethodName) inline __declspec(noinline) RESULT_NORETURN RetType MethodName +#endif +#define __RFF_DIRECT_FN_PARAMS __RFF_FN_PARAMS +#define __RFF_DIRECT_FN_PARAMS_ONLY __RFF_FN_PARAMS_ONLY +#define __RFF_DIRECT_FN_CALL __RFF_FN_CALL_FULL_RA __RFF_COMMA +#define __RFF_DIRECT_FN_CALL_ONLY __RFF_FN_CALL_FULL_RA +// 2) Internal Methods +// * Only called by Conditional routines +// * 'inline' when (RESULT_INLINE_ERROR_TESTS_FAIL_FAST = 0 and RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST != 1), otherwise noinline (directly called by code when branching is forceinlined) +// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1 and RESULT_INLINE_ERROR_TESTS_FAIL_FAST = 1) +#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) +#define __RFF_INTERNAL_NOINLINE_METHOD(MethodName) inline __declspec(noinline) void MethodName +#define __RFF_INTERNAL_NOINLINE_NORET_METHOD(MethodName) inline __declspec(noinline) RESULT_NORETURN void MethodName +#define __RFF_INTERNAL_INLINE_METHOD(MethodName) template inline __declspec(noinline) void MethodName +#define __RFF_INTERNAL_INLINE_NORET_METHOD(MethodName) template inline __declspec(noinline) RESULT_NORETURN void MethodName +#define __RFF_CALL_INTERNAL_INLINE_METHOD(MethodName) MethodName +#else +#define __RFF_INTERNAL_NOINLINE_METHOD(MethodName) inline void MethodName +#define __RFF_INTERNAL_NOINLINE_NORET_METHOD(MethodName) inline RESULT_NORETURN void MethodName +#define __RFF_INTERNAL_INLINE_METHOD(MethodName) inline __declspec(noinline) void MethodName +#define __RFF_INTERNAL_INLINE_NORET_METHOD(MethodName) inline __declspec(noinline) RESULT_NORETURN void MethodName +#define __RFF_CALL_INTERNAL_INLINE_METHOD(MethodName) MethodName +#endif +#define __RFF_CALL_INTERNAL_NOINLINE_METHOD(MethodName) MethodName +#define __RFF_INTERNAL_NOINLINE_FN_PARAMS __RFF_FN_PARAMS void* returnAddress __RFF_COMMA +#define __RFF_INTERNAL_NOINLINE_FN_PARAMS_ONLY __RFF_FN_PARAMS void* returnAddress +#define __RFF_INTERNAL_NOINLINE_FN_CALL __RFF_FN_CALL_FULL __RFF_COMMA +#define __RFF_INTERNAL_NOINLINE_FN_CALL_ONLY __RFF_FN_CALL_FULL +#define __RFF_INTERNAL_INLINE_FN_PARAMS __RFF_FN_PARAMS +#define __RFF_INTERNAL_INLINE_FN_PARAMS_ONLY __RFF_FN_PARAMS_ONLY +#define __RFF_INTERNAL_INLINE_FN_CALL __RFF_FN_CALL_FULL_RA __RFF_COMMA +#define __RFF_INTERNAL_INLINE_FN_CALL_ONLY __RFF_FN_CALL_FULL_RA +#if (RESULT_INLINE_ERROR_TESTS_FAIL_FAST == 0) +#define __RFF_INTERNAL_METHOD __RFF_INTERNAL_NOINLINE_METHOD +#define __RFF_INTERNAL_NORET_METHOD __RFF_INTERNAL_NOINLINE_NORET_METHOD +#define __RFF_CALL_INTERNAL_METHOD __RFF_CALL_INTERNAL_NOINLINE_METHOD +#define __RFF_INTERNAL_FN_PARAMS __RFF_INTERNAL_NOINLINE_FN_PARAMS +#define __RFF_INTERNAL_FN_PARAMS_ONLY __RFF_INTERNAL_NOINLINE_FN_PARAMS_ONLY +#define __RFF_INTERNAL_FN_CALL __RFF_INTERNAL_NOINLINE_FN_CALL +#define __RFF_INTERNAL_FN_CALL_ONLY __RFF_INTERNAL_NOINLINE_FN_CALL_ONLY +#else +#define __RFF_INTERNAL_METHOD __RFF_INTERNAL_INLINE_METHOD +#define __RFF_INTERNAL_NORET_METHOD __RFF_INTERNAL_INLINE_NORET_METHOD +#define __RFF_CALL_INTERNAL_METHOD __RFF_CALL_INTERNAL_INLINE_METHOD +#define __RFF_INTERNAL_FN_PARAMS __RFF_INTERNAL_INLINE_FN_PARAMS +#define __RFF_INTERNAL_FN_PARAMS_ONLY __RFF_INTERNAL_INLINE_FN_PARAMS_ONLY +#define __RFF_INTERNAL_FN_CALL __RFF_INTERNAL_INLINE_FN_CALL +#define __RFF_INTERNAL_FN_CALL_ONLY __RFF_INTERNAL_INLINE_FN_CALL_ONLY +#endif +// 3) Conditional Methods +// * Called Directly by Macros +// * May be noinline or __forceinline depending upon (RESULT_INLINE_ERROR_TESTS_FAIL_FAST) +// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) +#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) +#define __RFF_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName) template inline __declspec(noinline) RetType MethodName +#define __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName +#define __RFF_CONDITIONAL_INLINE_METHOD(RetType, MethodName) template __forceinline RetType MethodName +#define __RFF_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName) __forceinline RetType MethodName +#define __RFF_CONDITIONAL_PARTIAL_TEMPLATE unsigned int optimizerCounter __RFF_COMMA +#else +#define __RFF_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName +#define __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName +#define __RFF_CONDITIONAL_INLINE_METHOD(RetType, MethodName) __forceinline RetType MethodName +#define __RFF_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName) __forceinline RetType MethodName +#define __RFF_CONDITIONAL_PARTIAL_TEMPLATE +#endif +#define __RFF_CONDITIONAL_NOINLINE_FN_CALL __RFF_FN_CALL _ReturnAddress() __RFF_COMMA +#define __RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY __RFF_FN_CALL _ReturnAddress() +#define __RFF_CONDITIONAL_INLINE_FN_CALL __RFF_FN_CALL +#define __RFF_CONDITIONAL_INLINE_FN_CALL_ONLY __RFF_FN_CALL_ONLY +#if (RESULT_INLINE_ERROR_TESTS_FAIL_FAST == 0) +#define __RFF_CONDITIONAL_METHOD __RFF_CONDITIONAL_NOINLINE_METHOD +#define __RFF_CONDITIONAL_TEMPLATE_METHOD __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD +#define __RFF_CONDITIONAL_FN_CALL __RFF_CONDITIONAL_NOINLINE_FN_CALL +#define __RFF_CONDITIONAL_FN_CALL_ONLY __RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY +#else +#define __RFF_CONDITIONAL_METHOD __RFF_CONDITIONAL_INLINE_METHOD +#define __RFF_CONDITIONAL_TEMPLATE_METHOD __RFF_CONDITIONAL_INLINE_TEMPLATE_METHOD +#define __RFF_CONDITIONAL_FN_CALL __RFF_CONDITIONAL_INLINE_FN_CALL +#define __RFF_CONDITIONAL_FN_CALL_ONLY __RFF_CONDITIONAL_INLINE_FN_CALL_ONLY +#endif +#define __RFF_CONDITIONAL_FN_PARAMS __RFF_FN_PARAMS +#define __RFF_CONDITIONAL_FN_PARAMS_ONLY __RFF_FN_PARAMS_ONLY +// Macro call-site helpers +#define __RFF_NS_ASSEMBLE2(ri, rd) in##ri##diag##rd // Differing internal namespaces eliminate ODR violations between modes +#define __RFF_NS_ASSEMBLE(ri, rd) __RFF_NS_ASSEMBLE2(ri, rd) +#define __RFF_NS_NAME __RFF_NS_ASSEMBLE(RESULT_INLINE_ERROR_TESTS_FAIL_FAST, RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST) +#define __RFF_NS wil::details::__RFF_NS_NAME +#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) +#define __RFF_FN(MethodName) __RFF_NS:: MethodName <__COUNTER__> +#else +#define __RFF_FN(MethodName) __RFF_NS:: MethodName +#endif +// end-of-repeated fail-fast handling macros +// Helpers for return macros +#define __RETURN_HR_LOG(hr, str) do { HRESULT __hr = (hr); if (FAILED(__hr)) { __R_FN(Return_Hr)(__R_INFO(str) __hr); } return __hr; } while (0, 0) +#define __RETURN_HR_LOG_FAIL(hr, str) do { HRESULT __hr = (hr); __R_FN(Return_Hr)(__R_INFO(str) __hr); return __hr; } while (0, 0) +#define __RETURN_WIN32_LOG(err, str) do { DWORD __err = (err); if (FAILED_WIN32(__err)) { return __R_FN(Return_Win32)(__R_INFO(str) __err); } return S_OK; } while (0, 0) +#define __RETURN_WIN32_LOG_FAIL(err, str) do { DWORD __err = (err); return __R_FN(Return_Win32)(__R_INFO(str) __err); } while (0, 0) +#define __RETURN_GLE_LOG_FAIL(str) return __R_FN(Return_GetLastError)(__R_INFO_ONLY(str)) +#define __RETURN_NTSTATUS_LOG(status, str) do { NTSTATUS __status = (status); if(FAILED_NTSTATUS(__status)) { return __R_FN(Return_NtStatus)(__R_INFO(str) __status); } return S_OK;} while (0, 0) +#define __RETURN_NTSTATUS_LOG_FAIL(status, str) do { NTSTATUS __status = (status); return __R_FN(Return_NtStatus)(__R_INFO(str) __status); } while (0, 0) +#define __RETURN_HR_MSG(hr, str, fmt, ...) do { HRESULT __hr = (hr); if (FAILED(__hr)) { __R_FN(Return_HrMsg)(__R_INFO(str) __hr, fmt, __VA_ARGS__); } return __hr; } while (0, 0) +#define __RETURN_HR_MSG_FAIL(hr, str, fmt, ...) do { HRESULT __hr = (hr); __R_FN(Return_HrMsg)(__R_INFO(str) __hr, fmt, __VA_ARGS__); return __hr; } while (0, 0) +#define __RETURN_WIN32_MSG(err, str, fmt, ...) do { DWORD __err = (err); if (FAILED_WIN32(__err)) { return __R_FN(Return_Win32Msg)(__R_INFO(str) __err, fmt, __VA_ARGS__); } return S_OK; } while (0, 0) +#define __RETURN_WIN32_MSG_FAIL(err, str, fmt, ...) do { DWORD __err = (err); return __R_FN(Return_Win32Msg)(__R_INFO(str) __err, fmt, __VA_ARGS__); } while (0, 0) +#define __RETURN_GLE_MSG_FAIL(str, fmt, ...) return __R_FN(Return_GetLastErrorMsg)(__R_INFO(str) fmt, __VA_ARGS__) +#define __RETURN_NTSTATUS_MSG(status, str, fmt, ...) do { NTSTATUS __status = (status); if(FAILED_NTSTATUS(__status)) { return __R_FN(Return_NtStatusMsg)(__R_INFO(str) __status, fmt, __VA_ARGS__); } return S_OK; } while (0, 0) +#define __RETURN_NTSTATUS_MSG_FAIL(status, str, fmt, ...) do { NTSTATUS __status = (status); return __R_FN(Return_NtStatusMsg)(__R_INFO(str) __status, fmt, __VA_ARGS__); } while (0, 0) +#ifdef RESULT_PRERELEASE +#define __RETURN_HR(hr, str) do { HRESULT __hr = (hr); if (FAILED(__hr)) { __R_FN(Return_HrPreRelease)(__R_INFO(str) __hr); } return __hr; } while (0, 0) +#define __RETURN_HR_FAIL(hr, str) do { HRESULT __hr = (hr); __R_FN(Return_HrPreRelease)(__R_INFO(str) __hr); return __hr; } while (0, 0) +#define __RETURN_WIN32(err, str) do { DWORD __err = (err); if (FAILED_WIN32(__err)) { return __R_FN(Return_Win32PreRelease)(__R_INFO(str) __err); } return S_OK; } while (0, 0) +#define __RETURN_WIN32_FAIL(err, str) do { DWORD __err = (err); return __R_FN(Return_Win32PreRelease)(__R_INFO(str) __err); } while (0, 0) +#define __RETURN_GLE_FAIL(str) return __R_FN(Return_GetLastErrorPreRelease)(__R_INFO_ONLY(str)) +#define __RETURN_NTSTATUS(status, str) do { NTSTATUS __status = (status); if(FAILED_NTSTATUS(__status)) { return __R_FN(Return_NtStatusPreRelease)(__R_INFO(str) __status); } return S_OK; } while (0, 0) +#define __RETURN_NTSTATUS_FAIL(status, str) do { NTSTATUS __status = (status); return __R_FN(Return_NtStatusPreRelease)(__R_INFO(str) __status); } while (0, 0) +#else +#define __RETURN_HR(hr, str) return (hr) +#define __RETURN_HR_FAIL(hr, str) return (hr) +#define __RETURN_WIN32(err, str) return (HRESULT_FROM_WIN32(err)) +#define __RETURN_WIN32_FAIL(err, str) return (HRESULT_FROM_WIN32(err)) +#define __RETURN_GLE_FAIL(str) return (wil::details::GetLastErrorFailHr()) +#define __RETURN_NTSTATUS(status, str) return (wil::details::NtStatusToHr(status)) +#define __RETURN_NTSTATUS_FAIL(status, str) return (wil::details::NtStatusToHr(status)) +#endif +#if defined(_PREFAST_) +#define __WI_ANALYSIS_ASSUME(_exp) _Analysis_assume_(_exp) +#else +#ifdef RESULT_DEBUG +#define __WI_ANALYSIS_ASSUME(_exp) ((void) 0) +#else +#define __WI_ANALYSIS_ASSUME(_exp) __noop(_exp) +#endif +#endif // _PREFAST_ +//! @endcond + + +//***************************************************************************** +// Pre-release fail fast helpers (for use only internally to WIL) +//***************************************************************************** + +//! @cond +#ifdef RESULT_PRERELEASE +#define __FAIL_FAST_PRERELEASE_ASSERT__(condition) do { if (!(condition)) { __RFF_FN(FailFast_Unexpected)(__RFF_INFO_ONLY(#condition)); } } while (0, 0) +#define __FAIL_FAST_PRERELEASE_ASSUME__(condition) __FAIL_FAST_PRERELEASE_ASSERT__(condition) +#define __FAIL_FAST_IMMEDIATE_PRERELEASE_ASSERT__(condition) do { if (!(condition)) { RESULT_RAISE_FAST_FAIL_EXCEPTION; } } while (0, 0) +#define __FAIL_FAST_IMMEDIATE_PRERELEASE_ASSUME__(condition) __FAIL_FAST_IMMEDIATE_PRERELEASE_ASSERT__(condition) +#else +#define __FAIL_FAST_PRERELEASE_ASSERT__(condition) +#define __FAIL_FAST_PRERELEASE_ASSUME__(condition) (condition) +#define __FAIL_FAST_IMMEDIATE_PRERELEASE_ASSERT__(condition) +#define __FAIL_FAST_IMMEDIATE_PRERELEASE_ASSUME__(condition) (condition) +#endif +//! @endcond + + +//***************************************************************************** +// Macros for returning failures as HRESULTs +//***************************************************************************** + +// Always returns a known result (HRESULT) - logs failures in pre-release +#define RETURN_HR(hr) __RETURN_HR(wil::verify_hresult(hr), #hr) +#define RETURN_LAST_ERROR() __RETURN_GLE_FAIL(nullptr) +#define RETURN_WIN32(win32err) __RETURN_WIN32(win32err, #win32err) +#define RETURN_NTSTATUS(status) __RETURN_NTSTATUS(status, #status) + +// Conditionally returns failures (HRESULT) - logs failures in pre-release +#define RETURN_IF_FAILED(hr) do { HRESULT __hrRet = wil::verify_hresult(hr); if (FAILED(__hrRet)) { __RETURN_HR_FAIL(__hrRet, #hr); }} while (0, 0) +#define RETURN_IF_WIN32_BOOL_FALSE(win32BOOL) do { BOOL __boolRet = wil::verify_BOOL(win32BOOL); if (!__boolRet) { __RETURN_GLE_FAIL(#win32BOOL); }} while (0, 0) +#define RETURN_IF_WIN32_ERROR(win32err) do { DWORD __errRet = (win32err); if (FAILED_WIN32(__errRet)) { __RETURN_WIN32_FAIL(__errRet, #win32err); }} while (0, 0) +#define RETURN_IF_HANDLE_INVALID(handle) do { HANDLE __hRet = (handle); if (__hRet == INVALID_HANDLE_VALUE) { __RETURN_GLE_FAIL(#handle); }} while (0, 0) +#define RETURN_IF_HANDLE_NULL(handle) do { HANDLE __hRet = (handle); if (__hRet == nullptr) { __RETURN_GLE_FAIL(#handle); }} while (0, 0) +#define RETURN_IF_NULL_ALLOC(ptr) do { if ((ptr) == nullptr) { __RETURN_HR_FAIL(E_OUTOFMEMORY, #ptr); }} while (0, 0) +#define RETURN_HR_IF(hr, condition) do { if (wil::verify_bool(condition)) { __RETURN_HR(wil::verify_hresult(hr), #condition); }} while (0, 0) +#define RETURN_HR_IF_FALSE(hr, condition) RETURN_HR_IF(hr, !(wil::verify_bool(condition))) +#define RETURN_HR_IF_NULL(hr, ptr) do { if ((ptr) == nullptr) { __RETURN_HR(wil::verify_hresult(hr), #ptr); }} while (0, 0) +#define RETURN_LAST_ERROR_IF(condition) do { if (wil::verify_bool(condition)) { __RETURN_GLE_FAIL(#condition); }} while (0, 0) +#define RETURN_LAST_ERROR_IF_FALSE(condition) RETURN_LAST_ERROR_IF(!(wil::verify_bool(condition))) +#define RETURN_LAST_ERROR_IF_NULL(ptr) do { if ((ptr) == nullptr) { __RETURN_GLE_FAIL(#ptr); }} while (0, 0) +#define RETURN_IF_NTSTATUS_FAILED(status) do { NTSTATUS __statusRet = (status); if (FAILED_NTSTATUS(__statusRet)) { __RETURN_NTSTATUS_FAIL(__statusRet, #status); }} while (0, 0) + +// Always returns a known result (HRESULT) - always logs failures +#define RETURN_HR_LOG(hr) __RETURN_HR_LOG(wil::verify_hresult(hr), #hr) +#define RETURN_LAST_ERROR_LOG() __RETURN_GLE_LOG_FAIL(nullptr) +#define RETURN_WIN32_LOG(win32err) __RETURN_WIN32_LOG(win32err, #win32err) +#define RETURN_NTSTATUS_LOG(status) __RETURN_NTSTATUS_LOG(status, #status) + +// Conditionally returns failures (HRESULT) - always logs failures +#define RETURN_IF_FAILED_LOG(hr) do { auto __hrRet = wil::verify_hresult(hr); if (FAILED(__hrRet)) { __RETURN_HR_LOG_FAIL(__hrRet, #hr); }} while (0, 0) +#define RETURN_IF_WIN32_BOOL_FALSE_LOG(win32BOOL) do { if (!wil::verify_BOOL(win32BOOL)) { __RETURN_GLE_LOG_FAIL(#win32BOOL); }} while (0, 0) +#define RETURN_IF_WIN32_ERROR_LOG(win32err) do { auto __errRet = (win32err); if (FAILED_WIN32(__errRet)) { __RETURN_WIN32_LOG_FAIL(__errRet, #win32err); }} while (0, 0) +#define RETURN_IF_HANDLE_INVALID_LOG(handle) do { HANDLE __hRet = (handle); if (__hRet == INVALID_HANDLE_VALUE) { __RETURN_GLE_LOG_FAIL(#handle); }} while (0, 0) +#define RETURN_IF_HANDLE_NULL_LOG(handle) do { HANDLE __hRet = (handle); if (__hRet == nullptr) { __RETURN_GLE_LOG_FAIL(#handle); }} while (0, 0) +#define RETURN_IF_NULL_ALLOC_LOG(ptr) do { if ((ptr) == nullptr) { __RETURN_HR_LOG_FAIL(E_OUTOFMEMORY, #ptr); }} while (0, 0) +#define RETURN_HR_IF_LOG(hr, condition) do { if (wil::verify_bool(condition)) { __RETURN_HR_LOG(wil::verify_hresult(hr), #condition); }} while (0, 0) +#define RETURN_HR_IF_FALSE_LOG(hr, condition) RETURN_HR_IF_LOG(hr, !(wil::verify_bool(condition))) +#define RETURN_HR_IF_NULL_LOG(hr, ptr) do { if ((ptr) == nullptr) { __RETURN_HR_LOG(wil::verify_hresult(hr), #ptr); }} while (0, 0) +#define RETURN_LAST_ERROR_IF_LOG(condition) do { if (wil::verify_bool(condition)) { __RETURN_GLE_LOG_FAIL(#condition); }} while (0, 0) +#define RETURN_LAST_ERROR_IF_FALSE_LOG(condition) RETURN_LAST_ERROR_IF_LOG(!(wil::verify_bool(condition))) +#define RETURN_LAST_ERROR_IF_NULL_LOG(ptr) do { if ((ptr) == nullptr) { __RETURN_GLE_LOG_FAIL(#ptr); }} while (0, 0) +#define RETURN_IF_NTSTATUS_FAILED_LOG(status) do { auto __statusRet = (status); if (FAILED_NTSTATUS(__statusRet)) { __RETURN_NTSTATUS_LOG_FAIL(__statusRet, #status); }} while (0, 0) + +// Always returns a known failure (HRESULT) - always logs a var-arg message on failure +#define RETURN_HR_MSG(hr, fmt, ...) __RETURN_HR_MSG(wil::verify_hresult(hr), #hr, fmt, __VA_ARGS__) +#define RETURN_LAST_ERROR_MSG(fmt, ...) __RETURN_GLE_MSG_FAIL(nullptr, fmt, __VA_ARGS__) +#define RETURN_WIN32_MSG(win32err, fmt, ...) __RETURN_WIN32_MSG(win32err, #win32err, fmt, __VA_ARGS__) +#define RETURN_NTSTATUS_MSG(status, fmt, ...) __RETURN_NTSTATUS_MSG(status, #status, fmt, __VA_ARGS__) + +// Conditionally returns failures (HRESULT) - always logs a var-arg message on failure +#define RETURN_IF_FAILED_MSG(hr, fmt, ...) do { auto __hrRet = wil::verify_hresult(hr); if (FAILED(__hrRet)) { __RETURN_HR_MSG_FAIL(__hrRet, #hr, fmt, __VA_ARGS__); }} while (0, 0) +#define RETURN_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) do { if (!wil::verify_BOOL(win32BOOL)) { __RETURN_GLE_MSG_FAIL(#win32BOOL, fmt, __VA_ARGS__); }} while (0, 0) +#define RETURN_IF_WIN32_ERROR_MSG(win32err, fmt, ...) do { auto __errRet = (win32err); if (FAILED_WIN32(__errRet)) { __RETURN_WIN32_MSG_FAIL(__errRet, #win32err, fmt, __VA_ARGS__); }} while (0, 0) +#define RETURN_IF_HANDLE_INVALID_MSG(handle, fmt, ...) do { HANDLE __hRet = (handle); if (__hRet == INVALID_HANDLE_VALUE) { __RETURN_GLE_MSG_FAIL(#handle, fmt, __VA_ARGS__); }} while (0, 0) +#define RETURN_IF_HANDLE_NULL_MSG(handle, fmt, ...) do { HANDLE __hRet = (handle); if (__hRet == nullptr) { __RETURN_GLE_MSG_FAIL(#handle, fmt, __VA_ARGS__); }} while (0, 0) +#define RETURN_IF_NULL_ALLOC_MSG(ptr, fmt, ...) do { if ((ptr) == nullptr) { __RETURN_HR_MSG_FAIL(E_OUTOFMEMORY, #ptr, fmt, __VA_ARGS__); }} while (0, 0) +#define RETURN_HR_IF_MSG(hr, condition, fmt, ...) do { if (wil::verify_bool(condition)) { __RETURN_HR_MSG(wil::verify_hresult(hr), #condition, fmt, __VA_ARGS__); }} while (0, 0) +#define RETURN_HR_IF_FALSE_MSG(hr, condition, fmt, ...) RETURN_HR_IF_MSG(hr, !(wil::verify_bool(condition)), fmt, __VA_ARGS__) +#define RETURN_HR_IF_NULL_MSG(hr, ptr, fmt, ...) do { if ((ptr) == nullptr) { __RETURN_HR_MSG(wil::verify_hresult(hr), #ptr, fmt, __VA_ARGS__); }} while (0, 0) +#define RETURN_LAST_ERROR_IF_MSG(condition, fmt, ...) do { if (wil::verify_bool(condition)) { __RETURN_GLE_MSG_FAIL(#condition, fmt, __VA_ARGS__); }} while (0, 0) +#define RETURN_LAST_ERROR_IF_FALSE_MSG(condition, fmt, ...) RETURN_LAST_ERROR_IF_MSG(!(wil::verify_bool(condition)), fmt, __VA_ARGS__) +#define RETURN_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) do { if ((ptr) == nullptr) { __RETURN_GLE_MSG_FAIL(#ptr, fmt, __VA_ARGS__); }} while (0, 0) +#define RETURN_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) do { NTSTATUS __statusRet = (status); if (FAILED_NTSTATUS(__statusRet)) { __RETURN_NTSTATUS_MSG_FAIL(__statusRet, #status, fmt, __VA_ARGS__); }} while (0, 0) + +// Conditionally returns failures (HRESULT) - use for failures that are expected in common use - failures are not logged - macros are only for control flow pattern +#define RETURN_IF_FAILED_EXPECTED(hr) do { auto __hrRet = wil::verify_hresult(hr); if (FAILED(__hrRet)) { return __hrRet; }} while (0, 0) +#define RETURN_IF_WIN32_BOOL_FALSE_EXPECTED(win32BOOL) do { if (!wil::verify_BOOL(win32BOOL)) { return wil::details::GetLastErrorFailHr(); }} while (0, 0) +#define RETURN_IF_WIN32_ERROR_EXPECTED(win32err) do { auto __errRet = (win32err); if (FAILED_WIN32(__errRet)) { return HRESULT_FROM_WIN32(__errRet); }} while (0, 0) +#define RETURN_IF_HANDLE_INVALID_EXPECTED(handle) do { HANDLE __hRet = (handle); if (__hRet == INVALID_HANDLE_VALUE) { return wil::details::GetLastErrorFailHr(); }} while (0, 0) +#define RETURN_IF_HANDLE_NULL_EXPECTED(handle) do { HANDLE __hRet = (handle); if (__hRet == nullptr) { return wil::details::GetLastErrorFailHr(); }} while (0, 0) +#define RETURN_IF_NULL_ALLOC_EXPECTED(ptr) do { if ((ptr) == nullptr) { return E_OUTOFMEMORY; }} while (0, 0) +#define RETURN_HR_IF_EXPECTED(hr, condition) do { if (wil::verify_bool(condition)) { return wil::verify_hresult(hr); }} while (0, 0) +#define RETURN_HR_IF_FALSE_EXPECTED(hr, condition) RETURN_HR_IF_EXPECTED(hr, !(wil::verify_bool(condition))) +#define RETURN_HR_IF_NULL_EXPECTED(hr, ptr) do { if ((ptr) == nullptr) { return wil::verify_hresult(hr); }} while (0, 0) +#define RETURN_LAST_ERROR_IF_EXPECTED(condition) do { if (wil::verify_bool(condition)) { return wil::details::GetLastErrorFailHr(); }} while (0, 0) +#define RETURN_LAST_ERROR_IF_FALSE_EXPECTED(condition) RETURN_LAST_ERROR_IF_EXPECTED(!(wil::verify_bool(condition))) +#define RETURN_LAST_ERROR_IF_NULL_EXPECTED(ptr) do { if ((ptr) == nullptr) { return wil::details::GetLastErrorFailHr(); }} while (0, 0) +#define RETURN_IF_NTSTATUS_FAILED_EXPECTED(status) do { auto __statusRet = (status); if (FAILED_NTSTATUS(__statusRet)) { return wil::details::NtStatusToHr(__statusRet); }} while (0, 0) + + +//***************************************************************************** +// Macros for logging failures (ignore or pass-through) +//***************************************************************************** + +// Always logs a known failure +#define LOG_HR(hr) __R_FN(Log_Hr)(__R_INFO(#hr) wil::verify_hresult(hr)) +#define LOG_LAST_ERROR() __R_FN(Log_GetLastError)(__R_INFO_ONLY(nullptr)) +#define LOG_WIN32(win32err) __R_FN(Log_Win32)(__R_INFO(#win32err) win32err) +#define LOG_NTSTATUS(status) __R_FN(Log_NtStatus)(__R_INFO(#status) status) + +// Conditionally logs failures - returns parameter value +#define LOG_IF_FAILED(hr) __R_FN(Log_IfFailed)(__R_INFO(#hr) wil::verify_hresult(hr)) +#define LOG_IF_WIN32_BOOL_FALSE(win32BOOL) __R_FN(Log_IfWin32BoolFalse)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL)) +#define LOG_IF_WIN32_ERROR(win32err) __R_FN(Log_IfWin32Error)(__R_INFO(#win32err) win32err) +#define LOG_IF_HANDLE_INVALID(handle) __R_FN(Log_IfHandleInvalid)(__R_INFO(#handle) handle) +#define LOG_IF_HANDLE_NULL(handle) __R_FN(Log_IfHandleNull)(__R_INFO(#handle) handle) +#define LOG_IF_NULL_ALLOC(ptr) __R_FN(Log_IfNullAlloc)(__R_INFO(#ptr) ptr) +#define LOG_HR_IF(hr, condition) __R_FN(Log_HrIf)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition)) +#define LOG_HR_IF_FALSE(hr, condition) __R_FN(Log_HrIfFalse)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition)) +#define LOG_HR_IF_NULL(hr, ptr) __R_FN(Log_HrIfNull)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr) +#define LOG_LAST_ERROR_IF(condition) __R_FN(Log_GetLastErrorIf)(__R_INFO(#condition) wil::verify_bool(condition)) +#define LOG_LAST_ERROR_IF_FALSE(condition) __R_FN(Log_GetLastErrorIfFalse)(__R_INFO(#condition) wil::verify_bool(condition)) +#define LOG_LAST_ERROR_IF_NULL(ptr) __R_FN(Log_GetLastErrorIfNull)(__R_INFO(#ptr) ptr) +#define LOG_IF_NTSTATUS_FAILED(status) __R_FN(Log_IfNtStatusFailed)(__R_INFO(#status) status) + +// Alternatives for SUCCEEDED(hr) and FAILED(hr) that conditionally log failures +#define SUCCEEDED_LOG(hr) SUCCEEDED(LOG_IF_FAILED(hr)) +#define FAILED_LOG(hr) FAILED(LOG_IF_FAILED(hr)) + +// Always logs a known failure - logs a var-arg message on failure +#define LOG_HR_MSG(hr, fmt, ...) __R_FN(Log_HrMsg)(__R_INFO(#hr) wil::verify_hresult(hr), fmt, __VA_ARGS__) +#define LOG_LAST_ERROR_MSG(fmt, ...) __R_FN(Log_GetLastErrorMsg)(__R_INFO(nullptr) fmt, __VA_ARGS__) +#define LOG_WIN32_MSG(win32err, fmt, ...) __R_FN(Log_Win32Msg)(__R_INFO(#win32err) win32err, fmt, __VA_ARGS__) +#define LOG_NTSTATUS_MSG(status, fmt, ...) __R_FN(Log_NtStatusMsg)(__R_INFO(#status) status, fmt, __VA_ARGS__) + +// Conditionally logs failures - returns parameter value - logs a var-arg message on failure +#define LOG_IF_FAILED_MSG(hr, fmt, ...) __R_FN(Log_IfFailedMsg)(__R_INFO(#hr) wil::verify_hresult(hr), fmt, __VA_ARGS__) +#define LOG_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) __R_FN(Log_IfWin32BoolFalseMsg)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), fmt, __VA_ARGS__) +#define LOG_IF_WIN32_ERROR_MSG(win32err, fmt, ...) __R_FN(Log_IfWin32ErrorMsg)(__R_INFO(#win32err) win32err, fmt, __VA_ARGS__) +#define LOG_IF_HANDLE_INVALID_MSG(handle, fmt, ...) __R_FN(Log_IfHandleInvalidMsg)(__R_INFO(#handle) handle, fmt, __VA_ARGS__) +#define LOG_IF_HANDLE_NULL_MSG(handle, fmt, ...) __R_FN(Log_IfHandleNullMsg)(__R_INFO(#handle) handle, fmt, __VA_ARGS__) +#define LOG_IF_NULL_ALLOC_MSG(ptr, fmt, ...) __R_FN(Log_IfNullAllocMsg)(__R_INFO(#ptr) ptr, fmt, __VA_ARGS__) +#define LOG_HR_IF_MSG(hr, condition, fmt, ...) __R_FN(Log_HrIfMsg)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), fmt, __VA_ARGS__) +#define LOG_HR_IF_FALSE_MSG(hr, condition, fmt, ...) __R_FN(Log_HrIfFalseMsg)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), fmt, __VA_ARGS__) +#define LOG_HR_IF_NULL_MSG(hr, ptr, fmt, ...) __R_FN(Log_HrIfNullMsg)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr, fmt, __VA_ARGS__) +#define LOG_LAST_ERROR_IF_MSG(condition, fmt, ...) __R_FN(Log_GetLastErrorIfMsg)(__R_INFO(#condition) wil::verify_bool(condition), fmt, __VA_ARGS__) +#define LOG_LAST_ERROR_IF_FALSE_MSG(condition, fmt, ...) __R_FN(Log_GetLastErrorIfFalseMsg)(__R_INFO(#condition) wil::verify_bool(condition), fmt, __VA_ARGS__) +#define LOG_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) __R_FN(Log_GetLastErrorIfNullMsg)(__R_INFO(#ptr) ptr, fmt, __VA_ARGS__) +#define LOG_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) __R_FN(Log_IfNtStatusFailedMsg)(__R_INFO(#status) status, fmt, __VA_ARGS__) + + +//***************************************************************************** +// Macros to fail fast the process on failures +//***************************************************************************** + +// Always fail fast a known failure +#define FAIL_FAST_HR(hr) __RFF_FN(FailFast_Hr)(__RFF_INFO(#hr) wil::verify_hresult(hr)) +#define FAIL_FAST_LAST_ERROR() __RFF_FN(FailFast_GetLastError)(__RFF_INFO_ONLY(nullptr)) +#define FAIL_FAST_WIN32(win32err) __RFF_FN(FailFast_Win32)(__RFF_INFO(#win32err) win32err) +#define FAIL_FAST_NTSTATUS(status) __RFF_FN(FailFast_NtStatus)(__RFF_INFO(#status) status) + +// Conditionally fail fast failures - returns parameter value +#define FAIL_FAST_IF_FAILED(hr) __RFF_FN(FailFast_IfFailed)(__RFF_INFO(#hr) wil::verify_hresult(hr)) +#define FAIL_FAST_IF_WIN32_BOOL_FALSE(win32BOOL) __RFF_FN(FailFast_IfWin32BoolFalse)(__RFF_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL)) +#define FAIL_FAST_IF_WIN32_ERROR(win32err) __RFF_FN(FailFast_IfWin32Error)(__RFF_INFO(#win32err) win32err) +#define FAIL_FAST_IF_HANDLE_INVALID(handle) __RFF_FN(FailFast_IfHandleInvalid)(__RFF_INFO(#handle) handle) +#define FAIL_FAST_IF_HANDLE_NULL(handle) __RFF_FN(FailFast_IfHandleNull)(__RFF_INFO(#handle) handle) +#define FAIL_FAST_IF_NULL_ALLOC(ptr) __RFF_FN(FailFast_IfNullAlloc)(__RFF_INFO(#ptr) ptr) +#define FAIL_FAST_HR_IF(hr, condition) __RFF_FN(FailFast_HrIf)(__RFF_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition)) +#define FAIL_FAST_HR_IF_FALSE(hr, condition) __RFF_FN(FailFast_HrIfFalse)(__RFF_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition)) +#define FAIL_FAST_HR_IF_NULL(hr, ptr) __RFF_FN(FailFast_HrIfNull)(__RFF_INFO(#ptr) wil::verify_hresult(hr), ptr) +#define FAIL_FAST_LAST_ERROR_IF(condition) __RFF_FN(FailFast_GetLastErrorIf)(__RFF_INFO(#condition) wil::verify_bool(condition)) +#define FAIL_FAST_LAST_ERROR_IF_FALSE(condition) __RFF_FN(FailFast_GetLastErrorIfFalse)(__RFF_INFO(#condition) wil::verify_bool(condition)) +#define FAIL_FAST_LAST_ERROR_IF_NULL(ptr) __RFF_FN(FailFast_GetLastErrorIfNull)(__RFF_INFO(#ptr) ptr) +#define FAIL_FAST_IF_NTSTATUS_FAILED(status) __RFF_FN(FailFast_IfNtStatusFailed)(__RFF_INFO(#status) status) + +// Always fail fast a known failure - fail fast a var-arg message on failure +#define FAIL_FAST_HR_MSG(hr, fmt, ...) __RFF_FN(FailFast_HrMsg)(__RFF_INFO(#hr) wil::verify_hresult(hr), fmt, __VA_ARGS__) +#define FAIL_FAST_LAST_ERROR_MSG(fmt, ...) __RFF_FN(FailFast_GetLastErrorMsg)(__RFF_INFO(nullptr) fmt, __VA_ARGS__) +#define FAIL_FAST_WIN32_MSG(win32err, fmt, ...) __RFF_FN(FailFast_Win32Msg)(__RFF_INFO(#win32err) win32err, fmt, __VA_ARGS__) +#define FAIL_FAST_NTSTATUS_MSG(status, fmt, ...) __RFF_FN(FailFast_NtStatusMsg)(__RFF_INFO(#status) status, fmt, __VA_ARGS__) + +// Conditionally fail fast failures - returns parameter value - fail fast a var-arg message on failure +#define FAIL_FAST_IF_FAILED_MSG(hr, fmt, ...) __RFF_FN(FailFast_IfFailedMsg)(__RFF_INFO(#hr) wil::verify_hresult(hr), fmt, __VA_ARGS__) +#define FAIL_FAST_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) __RFF_FN(FailFast_IfWin32BoolFalseMsg)(__RFF_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), fmt, __VA_ARGS__) +#define FAIL_FAST_IF_WIN32_ERROR_MSG(win32err, fmt, ...) __RFF_FN(FailFast_IfWin32ErrorMsg)(__RFF_INFO(#win32err) win32err, fmt, __VA_ARGS__) +#define FAIL_FAST_IF_HANDLE_INVALID_MSG(handle, fmt, ...) __RFF_FN(FailFast_IfHandleInvalidMsg)(__RFF_INFO(#handle) handle, fmt, __VA_ARGS__) +#define FAIL_FAST_IF_HANDLE_NULL_MSG(handle, fmt, ...) __RFF_FN(FailFast_IfHandleNullMsg)(__RFF_INFO(#handle) handle, fmt, __VA_ARGS__) +#define FAIL_FAST_IF_NULL_ALLOC_MSG(ptr, fmt, ...) __RFF_FN(FailFast_IfNullAllocMsg)(__RFF_INFO(#ptr) ptr, fmt, __VA_ARGS__) +#define FAIL_FAST_HR_IF_MSG(hr, condition, fmt, ...) __RFF_FN(FailFast_HrIfMsg)(__RFF_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), fmt, __VA_ARGS__) +#define FAIL_FAST_HR_IF_FALSE_MSG(hr, condition, fmt, ...) __RFF_FN(FailFast_HrIfFalseMsg)(__RFF_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), fmt, __VA_ARGS__) +#define FAIL_FAST_HR_IF_NULL_MSG(hr, ptr, fmt, ...) __RFF_FN(FailFast_HrIfNullMsg)(__RFF_INFO(#ptr) wil::verify_hresult(hr), ptr, fmt, __VA_ARGS__) +#define FAIL_FAST_LAST_ERROR_IF_MSG(condition, fmt, ...) __RFF_FN(FailFast_GetLastErrorIfMsg)(__RFF_INFO(#condition) wil::verify_bool(condition), fmt, __VA_ARGS__) +#define FAIL_FAST_LAST_ERROR_IF_FALSE_MSG(condition, fmt, ...) __RFF_FN(FailFast_GetLastErrorIfFalseMsg)(__RFF_INFO(#condition) wil::verify_bool(condition), fmt, __VA_ARGS__) +#define FAIL_FAST_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) __RFF_FN(FailFast_GetLastErrorIfNullMsg)(__RFF_INFO(#ptr) ptr, fmt, __VA_ARGS__) +#define FAIL_FAST_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) __RFF_FN(FailFast_IfNtStatusFailedMsg)(__RFF_INFO(#status) status, fmt, __VA_ARGS__) + +// Always fail fast a known failure +#ifndef FAIL_FAST +#define FAIL_FAST() __RFF_FN(FailFast_Unexpected)(__RFF_INFO_ONLY(nullptr)) +#endif + +// Conditionally fail fast failures - returns parameter value +#define FAIL_FAST_IF(condition) __RFF_FN(FailFast_If)(__RFF_INFO(#condition) wil::verify_bool(condition)) +#define FAIL_FAST_IF_FALSE(condition) __RFF_FN(FailFast_IfFalse)(__RFF_INFO(#condition) wil::verify_bool(condition)) +#define FAIL_FAST_IF_NULL(ptr) __RFF_FN(FailFast_IfNull)(__RFF_INFO(#ptr) ptr) + +// Always fail fast a known failure - fail fast a var-arg message on failure +#define FAIL_FAST_MSG(hr, fmt, ...) __RFF_FN(FailFast_UnexpectedMsg)(__RFF_INFO(#hr) wil::verify_hresult(hr), fmt, __VA_ARGS__) + +// Conditionally fail fast failures - returns parameter value - fail fast a var-arg message on failure +#define FAIL_FAST_IF_MSG(hr, condition, fmt, ...) __RFF_FN(FailFast_IfMsg)(__RFF_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), fmt, __VA_ARGS__) +#define FAIL_FAST_IF_FALSE_MSG(hr, condition, fmt, ...) __RFF_FN(FailFast_IfFalseMsg)(__RFF_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), fmt, __VA_ARGS__) +#define FAIL_FAST_IF_NULL_MSG(hr, ptr, fmt, ...) __RFF_FN(FailFast_IfNullMsg)(__RFF_INFO(#ptr) wil::verify_hresult(hr), ptr, fmt, __VA_ARGS__) + +// Immediate fail fast (no telemetry - use rarely / only when *already* in an undefined state) +#define FAIL_FAST_IMMEDIATE() __RFF_FN(FailFastImmediate_Unexpected)() + +// Conditional immediate fail fast (no telemetry - use rarely / only when *already* in an undefined state) +#define FAIL_FAST_IMMEDIATE_IF_FAILED(hr) __RFF_FN(FailFastImmediate_IfFailed)(wil::verify_hresult(hr)) +#define FAIL_FAST_IMMEDIATE_IF(condition) __RFF_FN(FailFastImmediate_If)(wil::verify_bool(condition)) +#define FAIL_FAST_IMMEDIATE_IF_FALSE(condition) __RFF_FN(FailFastImmediate_IfFalse)(wil::verify_bool(condition)) +#define FAIL_FAST_IMMEDIATE_IF_NULL(ptr) __RFF_FN(FailFastImmediate_IfNull)(ptr) +#define FAIL_FAST_IMMEDIATE_IF_NTSTATUS_FAILED(status) __RFF_FN(FailFastImmediate_IfNtStatusFailed)(status) + +// Specializations +#define FAIL_FAST_IMMEDIATE_IF_IN_LOADER_CALLOUT() do { if (wil::details::g_pfnFailFastInLoaderCallout != nullptr) { wil::details::g_pfnFailFastInLoaderCallout(); } } while (0, 0) + + +//***************************************************************************** +// Macros to throw exceptions on failure +//***************************************************************************** + +#ifdef WIL_ENABLE_EXCEPTIONS + +// Always throw a known failure +#define THROW_HR(hr) __R_FN(Throw_Hr)(__R_INFO(#hr) wil::verify_hresult(hr)) +#define THROW_LAST_ERROR() __R_FN(Throw_GetLastError)(__R_INFO_ONLY(nullptr)) +#define THROW_WIN32(win32err) __R_FN(Throw_Win32)(__R_INFO(#win32err) win32err) +#define THROW_EXCEPTION(exception) wil::details::ReportFailure_CustomException(__R_INFO(#exception) exception) +#define THROW_NTSTATUS(status) __R_FN(Throw_NtStatus)(__R_INFO(#status) status) + +// Conditionally throw failures - returns parameter value +#define THROW_IF_FAILED(hr) __R_FN(Throw_IfFailed)(__R_INFO(#hr) wil::verify_hresult(hr)) +#define THROW_IF_WIN32_BOOL_FALSE(win32BOOL) __R_FN(Throw_IfWin32BoolFalse)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL)) +#define THROW_IF_WIN32_ERROR(win32err) __R_FN(Throw_IfWin32Error)(__R_INFO(#win32err) win32err) +#define THROW_IF_HANDLE_INVALID(handle) __R_FN(Throw_IfHandleInvalid)(__R_INFO(#handle) handle) +#define THROW_IF_HANDLE_NULL(handle) __R_FN(Throw_IfHandleNull)(__R_INFO(#handle) handle) +#define THROW_IF_NULL_ALLOC(ptr) __R_FN(Throw_IfNullAlloc)(__R_INFO(#ptr) ptr) +#define THROW_HR_IF(hr, condition) __R_FN(Throw_HrIf)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition)) +#define THROW_HR_IF_FALSE(hr, condition) __R_FN(Throw_HrIfFalse)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition)) +#define THROW_HR_IF_NULL(hr, ptr) __R_FN(Throw_HrIfNull)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr) +#define THROW_LAST_ERROR_IF(condition) __R_FN(Throw_GetLastErrorIf)(__R_INFO(#condition) wil::verify_bool(condition)) +#define THROW_LAST_ERROR_IF_FALSE(condition) __R_FN(Throw_GetLastErrorIfFalse)(__R_INFO(#condition) wil::verify_bool(condition)) +#define THROW_LAST_ERROR_IF_NULL(ptr) __R_FN(Throw_GetLastErrorIfNull)(__R_INFO(#ptr) ptr) +#define THROW_IF_NTSTATUS_FAILED(status) __R_FN(Throw_IfNtStatusFailed)(__R_INFO(#status) status) + +// Always throw a known failure - throw a var-arg message on failure +#define THROW_HR_MSG(hr, fmt, ...) __R_FN(Throw_HrMsg)(__R_INFO(#hr) wil::verify_hresult(hr), fmt, __VA_ARGS__) +#define THROW_LAST_ERROR_MSG(fmt, ...) __R_FN(Throw_GetLastErrorMsg)(__R_INFO(nullptr) fmt, __VA_ARGS__) +#define THROW_WIN32_MSG(win32err, fmt, ...) __R_FN(Throw_Win32Msg)(__R_INFO(#win32err) win32err, fmt, __VA_ARGS__) +#define THROW_EXCEPTION_MSG(exception, fmt, ...) wil::details::ReportFailure_CustomExceptionMsg(__R_INFO(#exception) exception, fmt, __VA_ARGS__) +#define THROW_NTSTATUS_MSG(status, fmt, ...) __R_FN(Throw_NtStatusMsg)(__R_INFO(#status) status, fmt, __VA_ARGS__) + +// Conditionally throw failures - returns parameter value - throw a var-arg message on failure +#define THROW_IF_FAILED_MSG(hr, fmt, ...) __R_FN(Throw_IfFailedMsg)(__R_INFO(#hr) wil::verify_hresult(hr), fmt, __VA_ARGS__) +#define THROW_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) __R_FN(Throw_IfWin32BoolFalseMsg)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), fmt, __VA_ARGS__) +#define THROW_IF_WIN32_ERROR_MSG(win32err, fmt, ...) __R_FN(Throw_IfWin32ErrorMsg)(__R_INFO(#win32err) win32err, fmt, __VA_ARGS__) +#define THROW_IF_HANDLE_INVALID_MSG(handle, fmt, ...) __R_FN(Throw_IfHandleInvalidMsg)(__R_INFO(#handle) handle, fmt, __VA_ARGS__) +#define THROW_IF_HANDLE_NULL_MSG(handle, fmt, ...) __R_FN(Throw_IfHandleNullMsg)(__R_INFO(#handle) handle, fmt, __VA_ARGS__) +#define THROW_IF_NULL_ALLOC_MSG(ptr, fmt, ...) __R_FN(Throw_IfNullAllocMsg)(__R_INFO(#ptr) ptr, fmt, __VA_ARGS__) +#define THROW_HR_IF_MSG(hr, condition, fmt, ...) __R_FN(Throw_HrIfMsg)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), fmt, __VA_ARGS__) +#define THROW_HR_IF_FALSE_MSG(hr, condition, fmt, ...) __R_FN(Throw_HrIfFalseMsg)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), fmt, __VA_ARGS__) +#define THROW_HR_IF_NULL_MSG(hr, ptr, fmt, ...) __R_FN(Throw_HrIfNullMsg)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr, fmt, __VA_ARGS__) +#define THROW_LAST_ERROR_IF_MSG(condition, fmt, ...) __R_FN(Throw_GetLastErrorIfMsg)(__R_INFO(#condition) wil::verify_bool(condition), fmt, __VA_ARGS__) +#define THROW_LAST_ERROR_IF_FALSE_MSG(condition, fmt, ...) __R_FN(Throw_GetLastErrorIfFalseMsg)(__R_INFO(#condition) wil::verify_bool(condition), fmt, __VA_ARGS__) +#define THROW_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) __R_FN(Throw_GetLastErrorIfNullMsg)(__R_INFO(#ptr) ptr, fmt, __VA_ARGS__) +#define THROW_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) __R_FN(Throw_IfNtStatusFailedMsg)(__R_INFO(#status) status, fmt, __VA_ARGS__) + + +//***************************************************************************** +// Macros to catch and convert exceptions on failure +//***************************************************************************** + +// Conditionally returns a known failure (HRESULT) (always place immediately after a try { } block) +#define CATCH_RETURN() catch (...) { __RETURN_HR_LOG_FAIL(wil::ResultFromCaughtException(), nullptr); } +#define CATCH_RETURN_MSG(fmt, ...) catch (...) { __RETURN_HR_MSG_FAIL(wil::ResultFromCaughtException(), nullptr, fmt, __VA_ARGS__); } +#define CATCH_RETURN_EXPECTED() catch (...) { return wil::ResultFromCaughtException(); } + +// Conditionally logs a known failure (always place immediately after a try { } block) +#define CATCH_LOG() catch (...) { __R_FN(Log_Hr)(__R_INFO(nullptr) wil::ResultFromCaughtException()); } +#define CATCH_LOG_MSG(fmt, ...) catch (...) { __R_FN(Log_HrMsg)(__R_INFO(nullptr) wil::ResultFromCaughtException(), fmt, __VA_ARGS__); } + +// Conditionally fail fast (always place immediately after a try { } block) +#define CATCH_FAIL_FAST() catch (...) { __R_FN(FailFast_Hr)(__R_INFO(nullptr) wil::ResultFromCaughtException()); } +#define CATCH_FAIL_FAST_MSG(fmt, ...) catch (...) { __R_FN(FailFast_HrMsg)(__R_INFO(nullptr) wil::ResultFromCaughtException(), fmt, __VA_ARGS__); } + +// Conditionally normalize (rethrow) a caught exception to ResultException or Platform::Exception^ (always place immediately after a try { } block) +#define CATCH_THROW_NORMALIZED() catch (...) { wil::details::RethrowNormalizedCaughtException(__R_INFO_ONLY(nullptr)); } +#define CATCH_THROW_NORMALIZED_MSG(fmt, ...) catch (...) { wil::details::RethrowNormalizedCaughtExceptionMsg(__R_INFO(nullptr) fmt, __VA_ARGS__); } + +#endif // WIL_ENABLE_EXCEPTIONS + + +//***************************************************************************** +// Assert Macros +//***************************************************************************** + +#ifdef RESULT_DEBUG +#define WI_ASSERT(condition) (__WI_ANALYSIS_ASSUME(condition), ((!(condition)) ? (__annotation(L"Debug", L"AssertFail", L#condition), DbgRaiseAssertionFailure(), false) : true)) +#define WI_ASSERT_MSG(condition, msg) (__WI_ANALYSIS_ASSUME(condition), ((!(condition)) ? (__annotation(L"Debug", L"AssertFail", L##msg), DbgRaiseAssertionFailure(), false) : true)) +#define WI_ASSERT_NOASSUME WI_ASSERT +#define WI_ASSERT_MSG_NOASSUME WI_ASSERT_MSG +#define WI_VERIFY WI_ASSERT +#define WI_VERIFY_MSG WI_ASSERT_MSG +#else +#define WI_ASSERT(condition) (__WI_ANALYSIS_ASSUME(condition), 0) +#define WI_ASSERT_MSG(condition, msg) (__WI_ANALYSIS_ASSUME(condition), 0) +#define WI_ASSERT_NOASSUME(condition) ((void) 0) +#define WI_ASSERT_MSG_NOASSUME(condition, msg) ((void) 0) +#define WI_VERIFY(condition) (__WI_ANALYSIS_ASSUME(condition), ((condition) ? true : false)) +#define WI_VERIFY_MSG(condition, msg) (__WI_ANALYSIS_ASSUME(condition), ((condition) ? true : false)) +#endif // RESULT_DEBUG + + +//***************************************************************************** +// Usage Error Macros +//***************************************************************************** + +#ifndef WI_USAGE_ASSERT +#define WI_USAGE_ASSERT(condition) WI_ASSERT(condition) +#endif +// #ifdef RESULT_DEBUG +// #define WI_USAGE_ERROR(msg, ...) do { LOG_HR_MSG(HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE), msg, __VA_ARGS__); WI_USAGE_ASSERT(false); } while (0, 0) +// #define WI_USAGE_ERROR_FORWARD(msg, ...) do { ReportFailure_ReplaceMsg(__R_FN_CALL_FULL, FailureType::Log, HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE), msg, __VA_ARGS__); WI_USAGE_ASSERT(false); } while (0, 0) +// #else +#define WI_USAGE_ERROR(msg, ...) // do { LOG_HR(HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE)); WI_USAGE_ASSERT(false); } while (0, 0) +#define WI_USAGE_ERROR_FORWARD(msg, ...) // do { ReportFailure_Hr(__R_FN_CALL_FULL, FailureType::Log, HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE)); WI_USAGE_ASSERT(false); } while (0, 0) +// #endif +#define WI_USAGE_VERIFY(condition, msg, ...) do { auto __passed = wil::verify_bool(condition); if (!__passed) { WI_USAGE_ERROR(msg, __VA_ARGS__); }} while (0, 0) +#define WI_USAGE_VERIFY_FORWARD(condition, msg, ...) do { auto __passed = wil::verify_bool(condition); if (!__passed) { WI_USAGE_ERROR_FORWARD(msg, __VA_ARGS__); }} while (0, 0) + + +// [deprecated] Old macros names -- to be removed -- do not use +#define RETURN_HR_IF_TRUE RETURN_HR_IF +#define RETURN_LAST_ERROR_IF_TRUE RETURN_LAST_ERROR_IF +#define RETURN_HR_IF_TRUE_LOG RETURN_HR_IF_LOG +#define RETURN_HR_IF_TRUE_MSG RETURN_HR_IF_MSG +#define RETURN_HR_IF_TRUE_EXPECTED RETURN_HR_IF_EXPECTED +#define LOG_HR_IF_TRUE LOG_HR_IF +#define LOG_HR_IF_TRUE_MSG LOG_HR_IF_MSG +#define LOG_LAST_ERROR_IF_TRUE LOG_LAST_ERROR_IF +#define FAIL_FAST_HR_IF_TRUE FAIL_FAST_HR_IF +#ifdef WIL_ENABLE_EXCEPTIONS +#define THROW_HR_IF_TRUE THROW_HR_IF +#define THROW_LAST_ERROR_IF_TRUE THROW_LAST_ERROR_IF +#define THROW_HR_IF_TRUE_MSG THROW_HR_IF_MSG +#endif // WIL_ENABLE_EXCEPTIONS + +namespace wil +{ + // Indicates the kind of message / failure type that was used to produce a given error + enum class FailureType + { + Exception, // THROW_... + Return, // RETURN_..._LOG or RETURN_..._MSG + ReturnPreRelease, // RETURN_... + Log, // LOG_... + FailFast // FAIL_FAST_... + }; + + // Represents the call context information about a given failure + // No constructors, destructors or virtual members should be contained within + struct CallContextInfo + { + long contextId; // incrementing ID for this call context (unique across an individual module load within process) + PCSTR contextName; // the explicit name given to this context + PCWSTR contextMessage; // [optional] Message that can be associated with the call context + }; + + inline void ClearContext(_Out_ CallContextInfo *pContext) WI_NOEXCEPT + { + pContext->contextId = 0; + pContext->contextName = nullptr; + pContext->contextMessage = nullptr; + } + + // Represents all context information about a given failure + // No constructors, destructors or virtual members should be contained within + struct FailureInfo + { + FailureType type; + HRESULT hr; + long failureId; // incrementing ID for this specific failure (unique across an individual module load within process) + PCWSTR pszMessage; // Message is only present for _MSG logging (it's the Sprintf message) + DWORD threadId; // the thread this failure was originally encountered on + PCSTR pszCode; // [debug only] Capture code from the macro + PCSTR pszFunction; // [debug only] The function name + PCSTR pszFile; + unsigned int uLineNumber; + int cFailureCount; // How many failures of 'type' have been reported in this module so far + PCSTR pszCallContext; // General breakdown of the call context stack that generated this failure + CallContextInfo callContextOriginating; // The outermost (first seen) call context + CallContextInfo callContextCurrent; // The most recently seen call context + PCSTR pszModule; // The module where the failure originated + void* returnAddress; // The return address to the point that called the macro + void* callerReturnAddress; // The return address of the function that includes the macro + }; + + // [optionally] Plug in error logging + // Note: This callback is deprecated. Please use SetResultTelemetryFallback for telemetry or + // SetResultLoggingCallback for observation. + __declspec(selectany) void(__stdcall *g_pfnResultLoggingCallback)(_Inout_ wil::FailureInfo *pFailure, _Inout_updates_opt_z_(cchDebugMessage) PWSTR pszDebugMessage, _Pre_satisfies_(cchDebugMessage > 0) size_t cchDebugMessage) WI_NOEXCEPT = nullptr; + + // [optional] + // This can be explicitly set to control whether or not error messages will be output to OutputDebugString. It can also + // be set directly from within the debugger to force console logging for debugging purposes. + #if (defined(DBG) || defined(_DEBUG)) + __declspec(selectany) bool g_fResultOutputDebugString = true; + #else + __declspec(selectany) bool g_fResultOutputDebugString = false; + #endif + + // [optionally] Plug in additional exception-type support (return S_OK when *unable* to remap the exception) + __declspec(selectany) HRESULT(__stdcall *g_pfnResultFromCaughtException)() WI_NOEXCEPT = nullptr; + + // [optionally] Use to configure fast fail of unknown exceptions (turn them off). + __declspec(selectany) bool g_fResultFailFastUnknownExceptions = true; + + // [optionally] Set to false to a configure all THROW_XXX macros in C++/CX to throw ResultException rather than Platform::Exception^ + __declspec(selectany) bool g_fResultThrowPlatformException = true; + + //! @cond + namespace details + { + _Success_(true) _Ret_range_(dest, destEnd) + inline PWSTR LogStringPrintf(_Out_writes_to_ptr_(destEnd) _Always_(_Post_z_) PWSTR dest, _Pre_satisfies_(destEnd >= dest) PCWSTR destEnd, _In_ _Printf_format_string_ PCWSTR format, ...) + { + va_list argList; + va_start(argList, format); + StringCchVPrintfW(dest, (destEnd - dest), format, argList); + return (destEnd == dest) ? dest : (dest + wcslen(dest)); + } + } + //! @endcond + + // This call generates the default logging string that makes its way to OutputDebugString for + // any particular failure. This string is also used to associate a failure with a PlatformException^ which + // only allows a single string to be associated with the exception. + inline HRESULT GetFailureLogString(_Out_writes_(cchDest) _Always_(_Post_z_) PWSTR pszDest, _Pre_satisfies_(cchDest > 0) _In_ size_t cchDest, _In_ FailureInfo const &failure) WI_NOEXCEPT + { + PCSTR pszType = ""; + switch (failure.type) + { + case FailureType::Exception: + pszType = "Exception"; + break; + case FailureType::Return: + pszType = "ReturnHr"; + break; + case FailureType::ReturnPreRelease: + pszType = "ReturnHr[PreRelease]"; + break; + case FailureType::Log: + pszType = "LogHr"; + break; + case FailureType::FailFast: + pszType = "FailFast"; + break; + } + + wchar_t szErrorText[256]; + szErrorText[0] = L'\0'; + FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, failure.hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), szErrorText, ARRAYSIZE(szErrorText), nullptr); + + // %FILENAME(%LINE): %TYPE(%count) tid(%threadid) %HRESULT %SystemMessage + // %Caller_MSG [%CODE(%FUNCTION)] + + PWSTR dest = pszDest; + PCWSTR destEnd = (pszDest + cchDest); + + if (failure.pszFile != nullptr) + { + dest = details::LogStringPrintf(dest, destEnd, L"%hs(%d)\\%hs!%p: ", failure.pszFile, failure.uLineNumber, failure.pszModule, failure.returnAddress); + } + else + { + dest = details::LogStringPrintf(dest, destEnd, L"%hs!%p: ", failure.pszModule, failure.returnAddress); + } + + if (failure.callerReturnAddress != nullptr) + { + dest = details::LogStringPrintf(dest, destEnd, L"(caller: %p) ", failure.callerReturnAddress); + } + + dest = details::LogStringPrintf(dest, destEnd, L"%hs(%d) tid(%x) %08X %ws", pszType, failure.cFailureCount, ::GetCurrentThreadId(), failure.hr, szErrorText); + + if ((failure.pszMessage != nullptr) || (failure.pszCallContext != nullptr) || (failure.pszFunction != nullptr)) + { + dest = details::LogStringPrintf(dest, destEnd, L" "); + if (failure.pszMessage != nullptr) + { + dest = details::LogStringPrintf(dest, destEnd, L"Msg:[%ws] ", failure.pszMessage); + } + if (failure.pszCallContext != nullptr) + { + dest = details::LogStringPrintf(dest, destEnd, L"CallContext:[%hs] ", failure.pszCallContext); + } + + if (failure.pszCode != nullptr) + { + dest = details::LogStringPrintf(dest, destEnd, L"[%hs(%hs)]\n", failure.pszFunction, failure.pszCode); + } + else if (failure.pszFunction != nullptr) + { + dest = details::LogStringPrintf(dest, destEnd, L"[%hs]\n", failure.pszFunction); + } + else + { + dest = details::LogStringPrintf(dest, destEnd, L"\n"); + } + } + + // Explicitly choosing to return success in the event of truncation... Current callers + // depend upon it or it would be eliminated. + return S_OK; + } + + //! @cond + namespace details + { + #ifdef WIL_SUPPRESS_PRIVATE_API_USE + #pragma detect_mismatch("ODR_violation_WIL_SUPPRESS_PRIVATE_API_USE_mismatch", "1") + #else + #pragma detect_mismatch("ODR_violation_WIL_SUPPRESS_PRIVATE_API_USE_mismatch", "0") + #endif + + #ifdef RESULT_PRERELEASE + #pragma detect_mismatch("ODR_violation_WIL_RESULT_PRERELEASE_mismatch", "1") + #else + #pragma detect_mismatch("ODR_violation_WIL_RESULT_PRERELEASE_mismatch", "0") + #endif + + // Fallback telemetry provider callback (set with wil::SetResultTelemetryFallback) + __declspec(selectany) void(__stdcall *g_pfnTelemetryCallback)(bool alreadyReported, wil::FailureInfo const &failure) WI_NOEXCEPT = nullptr; + + // Observe all errors flowing through the system with this callback (set with wil::SetResultLoggingCallback); use with custom logging + __declspec(selectany) void(__stdcall *g_pfnLoggingCallback)(wil::FailureInfo const &failure) WI_NOEXCEPT = nullptr; + + // True if g_pfnResultLoggingCallback is set (allows cutting off backwards compat calls to the function) + __declspec(selectany) bool g_resultMessageCallbackSet = false; + + // Desktop Only: Module fetch function (automatically setup) + __declspec(selectany) PCSTR(__stdcall *g_pfnGetModuleName)() WI_NOEXCEPT = nullptr; + + // Desktop Only: Private module load fail fast function (automatically setup) + __declspec(selectany) void(__stdcall *g_pfnFailFastInLoaderCallout)() WI_NOEXCEPT = nullptr; + + // Desktop Only: Private module load convert NtStatus to HResult (automatically setup) + __declspec(selectany) ULONG(__stdcall *g_pfnRtlNtStatusToDosErrorNoTeb)(NTSTATUS) = nullptr; + + // C++/cx compiled additions + __declspec(selectany) void(__stdcall *g_pfnThrowPlatformException)(FailureInfo const &failure, PCWSTR debugString) = nullptr; + __declspec(selectany) void(__stdcall *g_pfnRethrowNormalizedCaughtException_WinRt)(__R_FN_PARAMS_FULL, _In_opt_ PCWSTR message) = nullptr; + __declspec(selectany) _Always_(_Post_satisfies_(return < 0)) HRESULT(__stdcall *g_pfnResultFromCaughtException_WinRt)() WI_NOEXCEPT = nullptr; + + enum class ReportFailureOptions + { + None = 0x00, + ForcePlatformException = 0x01, + SuppressAction = 0x02 + }; + DEFINE_ENUM_FLAG_OPERATORS(ReportFailureOptions); + + // Forward declarations to enable use of fail fast and reporting internally... + namespace __R_NS_NAME + { + __R_DIRECT_METHOD(HRESULT, Log_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT; + __R_DIRECT_METHOD(HRESULT, Log_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT; + __R_DIRECT_METHOD(DWORD, Log_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT; + } + namespace __RFF_NS_NAME + { + __RFF_DIRECT_NORET_METHOD(void, FailFast_Unexpected)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT; + __RFF_CONDITIONAL_METHOD(bool, FailFast_If)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT; + __RFF_CONDITIONAL_METHOD(bool, FailFast_HrIf)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT; + __RFF_CONDITIONAL_METHOD(bool, FailFast_IfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT; + } + __declspec(noinline) inline void ReportFailure(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, _In_opt_ PCWSTR message = nullptr, ReportFailureOptions options = ReportFailureOptions::None); + inline void ReportFailure_ReplaceMsg(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, _Printf_format_string_ PCSTR formatString, ...); + __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr); + _Always_(_Post_satisfies_(return < 0)) inline HRESULT ResultFromUnknownCaughtException(); + + // A simple ref-counted buffer class. The interface is very similar to shared_ptr<>, only it manages + // an allocated buffer (malloc) and maintains the size. + + class shared_buffer + { + public: + shared_buffer() WI_NOEXCEPT : m_pCopy(nullptr), m_size(0) + { + } + + shared_buffer(shared_buffer const &other) WI_NOEXCEPT : m_pCopy(nullptr), m_size(0) + { + assign(other.m_pCopy, other.m_size); + } + + shared_buffer(shared_buffer &&other) WI_NOEXCEPT : + m_pCopy(other.m_pCopy), + m_size(other.m_size) + { + other.m_pCopy = nullptr; + other.m_size = 0; + } + + ~shared_buffer() WI_NOEXCEPT + { + reset(); + } + + shared_buffer& operator=(shared_buffer const &other) WI_NOEXCEPT + { + assign(other.m_pCopy, other.m_size); + return *this; + } + + shared_buffer& operator=(shared_buffer &&other) WI_NOEXCEPT + { + reset(); + m_pCopy = other.m_pCopy; + m_size = other.m_size; + other.m_pCopy = nullptr; + other.m_size = 0; + return *this; + } + + void reset() WI_NOEXCEPT + { + if (m_pCopy != nullptr) + { + if (0 == ::InterlockedDecrementRelease(m_pCopy)) + { + free(m_pCopy); + } + m_pCopy = nullptr; + m_size = 0; + } + } + + bool create(_In_reads_bytes_opt_(cbData) void const *pData, size_t cbData) WI_NOEXCEPT + { + if (cbData == 0) + { + reset(); + return true; + } + + long *pCopyRefCount = reinterpret_cast(malloc(sizeof(long)+cbData)); + if (pCopyRefCount == nullptr) + { + return false; + } + + *pCopyRefCount = 0; + if (pData != nullptr) + { + CopyMemory(pCopyRefCount + 1, pData, cbData); // +1 to advance past sizeof(long) counter + } + assign(pCopyRefCount, cbData); + return true; + } + + bool create(size_t cbData) WI_NOEXCEPT + { + return create(nullptr, cbData); + } + + void* get(_Out_opt_ size_t *pSize = nullptr) const WI_NOEXCEPT + { + if (pSize != nullptr) + { + *pSize = m_size; + } + return (m_pCopy == nullptr) ? nullptr : (m_pCopy + 1); + } + + size_t size() const WI_NOEXCEPT + { + return m_size; + } + + explicit operator bool() const WI_NOEXCEPT + { + return (m_pCopy != nullptr); + } + + bool unique() const WI_NOEXCEPT + { + return ((m_pCopy != nullptr) && (*m_pCopy == 1)); + } + + private: + long *m_pCopy; // pointer to allocation: refcount + data + size_t m_size; // size of the data from m_pCopy + + void assign(_In_opt_ long *pCopy, size_t cbSize) WI_NOEXCEPT + { + reset(); + if (pCopy != nullptr) + { + m_pCopy = pCopy; + m_size = cbSize; + ::InterlockedIncrementNoFence(m_pCopy); + } + } + }; + + inline shared_buffer make_shared_buffer_nothrow(_In_reads_bytes_opt_(countBytes) void *pData, size_t countBytes) WI_NOEXCEPT + { + shared_buffer buffer; + buffer.create(pData, countBytes); + return buffer; + } + + inline shared_buffer make_shared_buffer_nothrow(size_t countBytes) WI_NOEXCEPT + { + shared_buffer buffer; + buffer.create(countBytes); + return buffer; + } + + // A small mimic of the STL shared_ptr class, but unlike shared_ptr, a pointer is not attached to the class, but is + // always simply contained within (it cannot be attached or detached). + + template + class shared_object + { + public: + shared_object() WI_NOEXCEPT : m_pCopy(nullptr) + { + } + + shared_object(shared_object const &other) WI_NOEXCEPT : + m_pCopy(other.m_pCopy) + { + if (m_pCopy != nullptr) + { + ::InterlockedIncrementNoFence(&m_pCopy->m_refCount); + } + } + + shared_object(shared_object &&other) WI_NOEXCEPT : + m_pCopy(other.m_pCopy) + { + other.m_pCopy = nullptr; + } + + ~shared_object() WI_NOEXCEPT + { + reset(); + } + + shared_object& operator=(shared_object const &other) WI_NOEXCEPT + { + reset(); + m_pCopy = other.m_pCopy; + if (m_pCopy != nullptr) + { + ::InterlockedIncrementNoFence(&m_pCopy->m_refCount); + } + return *this; + } + + shared_object& operator=(shared_object &&other) WI_NOEXCEPT + { + reset(); + m_pCopy = other.m_pCopy; + other.m_pCopy = nullptr; + return *this; + } + + void reset() WI_NOEXCEPT + { + if (m_pCopy != nullptr) + { + if (0 == ::InterlockedDecrementRelease(&m_pCopy->m_refCount)) + { + delete m_pCopy; + } + m_pCopy = nullptr; + } + } + + bool create() + { + RefAndObject *pObject = new(std::nothrow) RefAndObject(); + if (pObject == nullptr) + { + return false; + } + reset(); + m_pCopy = pObject; + return true; + } + + template + bool create(param_t &¶m1) + { + RefAndObject *pObject = new(std::nothrow) RefAndObject(wistd::forward(param1)); + if (pObject == nullptr) + { + return false; + } + reset(); + m_pCopy = pObject; + return true; + } + + object_t* get() const WI_NOEXCEPT + { + return (m_pCopy == nullptr) ? nullptr : &m_pCopy->m_object; + } + + explicit operator bool() const WI_NOEXCEPT + { + return (m_pCopy != nullptr); + } + + bool unique() const WI_NOEXCEPT + { + return ((m_pCopy != nullptr) && (m_pCopy->m_refCount == 1)); + } + + object_t *operator->() const WI_NOEXCEPT + { + return get(); + } + + private: + struct RefAndObject + { + long m_refCount; + object_t m_object; + + RefAndObject() : + m_refCount(1), + m_object() + { + } + + template + RefAndObject(param_t &¶m1) : + m_refCount(1), + m_object(wistd::forward(param1)) + { + } + }; + + RefAndObject *m_pCopy; + }; + + template + inline shared_object make_shared_object_nothrow() + { + shared_object object; + object.create(); + return object; + } + + // Note that this should eventually be switched to variadic template forwarding, but cannot be at the moment due + // to the use of this from Result.h and it's dependence upon an older compiler for the phone build + template + inline shared_object make_shared_object_nothrow(param_t &¶m1) + { + shared_object object; + object.create(wistd::forward(param1)); + return object; + } + + // The following functions are basically the same, but are kept separated to: + // 1) Provide a unique count and last error code per-type + // 2) Avoid merging the types to allow easy debugging (breakpoints, conditional breakpoints based + // upon count of errors from a particular type, etc) + + __declspec(noinline) inline int RecordException(HRESULT hr) WI_NOEXCEPT + { + static HRESULT volatile s_hrErrorLast = S_OK; + static long volatile s_cErrorCount = 0; + s_hrErrorLast = hr; + return ::InterlockedIncrementNoFence(&s_cErrorCount); + } + + __declspec(noinline) inline int RecordReturn(HRESULT hr) WI_NOEXCEPT + { + static HRESULT volatile s_hrErrorLast = S_OK; + static long volatile s_cErrorCount = 0; + s_hrErrorLast = hr; + return ::InterlockedIncrementNoFence(&s_cErrorCount); + } + + __declspec(noinline) inline int RecordReturnPreRelease(HRESULT hr) WI_NOEXCEPT + { + static HRESULT volatile s_hrErrorLast = S_OK; + static long volatile s_cErrorCount = 0; + s_hrErrorLast = hr; + return ::InterlockedIncrementNoFence(&s_cErrorCount); + } + + __declspec(noinline) inline int RecordLog(HRESULT hr) WI_NOEXCEPT + { + static HRESULT volatile s_hrErrorLast = S_OK; + static long volatile s_cErrorCount = 0; + s_hrErrorLast = hr; + return ::InterlockedIncrementNoFence(&s_cErrorCount); + } + + __declspec(noinline) inline int RecordFailFast(HRESULT hr) WI_NOEXCEPT + { + static HRESULT volatile s_hrErrorLast = S_OK; + s_hrErrorLast = hr; + return 1; + } + + __declspec(noinline) inline HRESULT NtStatusToHr(NTSTATUS status) + { + // The following conversions are the only known incorrect mappings in RtlNtStatusToDosErrorNoTeb + if (SUCCEEDED_NTSTATUS(status)) + { + // All successful status codes have only one hresult equivalent, S_OK + return S_OK; + } + if (status == STATUS_NO_MEMORY) + { + // RtlNtStatusToDosErrorNoTeb maps STATUS_NO_MEMORY to the less popular of two Win32 no memory error codes resulting in an unexpected mapping + return E_OUTOFMEMORY; + } + + if (g_pfnRtlNtStatusToDosErrorNoTeb != nullptr) + { + DWORD err = g_pfnRtlNtStatusToDosErrorNoTeb(status); + if (err != 0) + { + return HRESULT_FROM_WIN32(err); + } + } + + return HRESULT_FROM_NT(status); + } + + // The following set of functions all differ only based upon number of arguments. They are unified in their handling + // of data from each of the various error-handling types (fast fail, exceptions, etc.). + + inline DWORD GetLastErrorFail(__R_FN_PARAMS_FULL) WI_NOEXCEPT + { + __R_FN_UNREFERENCED; + auto err = ::GetLastError(); + if (SUCCEEDED_WIN32(err)) + { + // This function should only be called when GetLastError() is set to a FAILURE. + // If you hit this assert (or are reviewing this failure telemetry), then there are one of three issues: + // 1) Your code is using a macro (such as RETURN_IF_WIN32_BOOL_FALSE()) on a function that does not actually + // set the last error (consult MSDN). + // 2) Your macro check against the error is not immediately after the API call. Pushing it later can result + // in another API call between the previous one and the check resetting the last error. + // 3) The API you're calling has a bug in it and does not accurately set the last error (there are a few + // examples here, such as SendMessageTimeout() that don't accurately set the last error). For these, + // please send mail to 'wildisc' when found and work-around with win32errorhelpers. + + WI_USAGE_ERROR_FORWARD("CALLER BUG: Macro usage error detected. GetLastError() does not have an error."); + return ERROR_ASSERTION_FAILURE; + } + return err; + } + + inline HRESULT GetLastErrorFailHr(__R_FN_PARAMS_FULL) WI_NOEXCEPT + { + return HRESULT_FROM_WIN32(GetLastErrorFail(__R_FN_CALL_FULL)); + } + + inline __declspec(noinline) HRESULT GetLastErrorFailHr() WI_NOEXCEPT + { + __R_FN_LOCALS_FULL_RA; + return GetLastErrorFailHr(__R_FN_CALL_FULL); + } + + inline void PrintLoggingMessage(_Out_writes_(cchDest) _Post_z_ PWSTR pszDest, _Pre_satisfies_(cchDest > 0) size_t cchDest, _In_opt_ _Printf_format_string_ PCSTR formatString, _In_ va_list argList) WI_NOEXCEPT + { + if (formatString == nullptr) + { + pszDest[0] = L'\0'; + } + else + { + wchar_t szFormatWide[2048]; + StringCchPrintfW(szFormatWide, ARRAYSIZE(szFormatWide), L"%hs", formatString); + StringCchVPrintfW(pszDest, cchDest, szFormatWide, argList); + } + } + +#pragma warning(push) +#pragma warning(disable:__WARNING_RETURNING_BAD_RESULT) + // NOTE: The following two functions are unfortunate copies of strsafe.h functions that have been copied to reduce the friction associated with using + // Result.h and ResultException.h in a build that does not have WINAPI_PARTITION_DESKTOP defined (where these are conditionally enabled). + + STRSAFEWORKERAPI WilStringLengthWorkerA(_In_reads_or_z_(cchMax) STRSAFE_PCNZCH psz, _In_ _In_range_(<= , STRSAFE_MAX_CCH) size_t cchMax, _Out_opt_ _Deref_out_range_(< , cchMax) _Deref_out_range_(<= , _String_length_(psz)) size_t* pcchLength) + { + HRESULT hr = S_OK; + size_t cchOriginalMax = cchMax; + while (cchMax && (*psz != '\0')) + { + psz++; + cchMax--; + } + if (cchMax == 0) + { + // the string is longer than cchMax + hr = STRSAFE_E_INVALID_PARAMETER; + } + if (pcchLength) + { + if (SUCCEEDED(hr)) + { + *pcchLength = cchOriginalMax - cchMax; + } + else + { + *pcchLength = 0; + } + } + return hr; + } + + _Must_inspect_result_ STRSAFEAPI StringCchLengthA(_In_reads_or_z_(cchMax) STRSAFE_PCNZCH psz, _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchMax, _Out_opt_ _Deref_out_range_(<, cchMax) _Deref_out_range_(<= , _String_length_(psz)) size_t* pcchLength) + { + HRESULT hr; + if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = WilStringLengthWorkerA(psz, cchMax, pcchLength); + } + if (FAILED(hr) && pcchLength) + { + *pcchLength = 0; + } + return hr; + } +#pragma warning(pop) + +#if VS2015_CA_FIXED + + _Ret_range_(sizeof(char), (psz == nullptr) ? sizeof(char) : (_String_length_(psz) + sizeof(char))) + inline size_t ResultStringSize(_In_opt_ PCSTR psz) + { return (psz == nullptr) ? sizeof(char) : (strlen(psz) + sizeof(char)); } + + _Ret_range_(sizeof(wchar_t), (psz == nullptr) ? sizeof(wchar_t) : ((_String_length_(psz) + 1) * sizeof(wchar_t))) + inline size_t ResultStringSize(_In_opt_ PCWSTR psz) + { return (psz == nullptr) ? sizeof(wchar_t) : (wcslen(psz) + 1) * sizeof(wchar_t); } + +#else + + _When_(psz == nullptr, _Post_satisfies_(return == sizeof(char))) + _When_(psz != nullptr, _Post_satisfies_(return == (_String_length_(psz) + 1) * sizeof(char))) + inline size_t ResultStringSize(_In_opt_ PCSTR psz) + { + return (psz ? strlen(psz) : 1) * sizeof(char); + } + + _When_(psz == nullptr, _Post_satisfies_(return == sizeof(wchar_t))) + _When_(psz != nullptr, _Post_satisfies_(return == (_String_length_(psz) + 1) * sizeof(wchar_t))) + inline size_t ResultStringSize(_In_opt_ PCWSTR psz) + { + return (psz ? wcslen(psz) : 1) * sizeof(wchar_t); + } + +#endif + + template + _Ret_range_(pStart, pEnd) inline unsigned char *WriteResultString(_Out_writes_to_ptr_opt_(pEnd) unsigned char *pStart, _In_opt_ unsigned char *pEnd, _In_opt_ TString pszString, _Out_opt_ TString *ppszBufferString = nullptr) + { + decltype(pszString[0]) const cZero = 0; + TString const pszLocal = (pszString == nullptr) ? &cZero : pszString; + __analysis_assume(pszLocal != nullptr); // VS2015.RC CA tools don't understand that pszLocal is forcibly non-null due top + size_t const cchWant = ResultStringSize(pszLocal) / sizeof(cZero); + size_t const cchMax = static_cast(pEnd - pStart) / sizeof(cZero); + size_t const cchCopy = (cchWant < cchMax) ? cchWant : cchMax; + ::CopyMemory(pStart, pszLocal, cchCopy * sizeof(cZero)); + wil::AssignToOptParam(ppszBufferString, (cchCopy > 1) ? reinterpret_cast(pStart) : nullptr); + if ((cchCopy < cchWant) && (cchCopy > 0)) + { + auto pZero = pStart + ((cchCopy - 1) * sizeof(cZero)); + ::ZeroMemory(pZero, sizeof(cZero)); + } +#pragma warning(suppress: 28196) // Filed OSG bug 3026886 to address. + return (pStart + (cchCopy * sizeof(cZero))); + } + + _Ret_range_(0, (cchMax > 0) ? cchMax - 1 : 0) inline size_t UntrustedStringLength(_In_ PCSTR psz, _In_ size_t cchMax) { size_t cbLength; return SUCCEEDED(wil::details::StringCchLengthA(psz, cchMax, &cbLength)) ? cbLength : 0; } + _Ret_range_(0, (cchMax > 0) ? cchMax - 1 : 0) inline size_t UntrustedStringLength(_In_ PCWSTR psz, _In_ size_t cchMax) { size_t cbLength; return SUCCEEDED(::StringCchLengthW(psz, cchMax, &cbLength)) ? cbLength : 0; } + + template + _Ret_range_(pStart, pEnd) inline unsigned char *GetResultString(_In_reads_to_ptr_opt_(pEnd) unsigned char *pStart, _In_opt_ unsigned char *pEnd, _Out_ TString *ppszBufferString) + { + size_t cchLen = UntrustedStringLength(reinterpret_cast(pStart), (pEnd - pStart) / sizeof((*ppszBufferString)[0])); + *ppszBufferString = (cchLen > 0) ? reinterpret_cast(pStart) : nullptr; + auto pReturn = min(pEnd, pStart + ((cchLen + 1) * sizeof((*ppszBufferString)[0]))); + __analysis_assume((pReturn >= pStart) && (pReturn <= pEnd)); + return pReturn; + } + + // A small, no-dependency class meant to enable accessing lock-free thread local storage (roughly + // modeled after ppl::Combinable<>). This is used to service thread-specific failure callbacks + // without requiring any locking when an error is fired. + // Note that *for now*, T must be POD and is ZERO'inited and will not have a constructor/destructor + // ran on it (easy to add, but code including this file does not enable/include placement new. + + template + class ThreadStorage + { + public: + ThreadStorage() WI_NOEXCEPT + { + ::ZeroMemory(const_cast(m_hashArray), sizeof(m_hashArray)); + } + + ~ThreadStorage() WI_NOEXCEPT + { + for (auto &entry : m_hashArray) + { + Node *pNode = entry; + while (pNode != nullptr) + { + auto pCurrent = pNode; + pNode = pNode->pNext; + pCurrent->~Node(); + free(pCurrent); + } + entry = nullptr; + } + } + + // Note: Can return nullptr even when (shouldAllocate == true) upon allocation failure + T* GetLocal(bool shouldAllocate = false) WI_NOEXCEPT + { + DWORD const threadId = ::GetCurrentThreadId(); + size_t const index = (threadId % ARRAYSIZE(m_hashArray)); + for (auto pNode = m_hashArray[index]; pNode != nullptr; pNode = pNode->pNext) + { + if (pNode->threadId == threadId) + { + return &pNode->value; + } + } + if (shouldAllocate) + { + Node *pNew = reinterpret_cast(malloc(sizeof(Node))); + if (pNew != nullptr) + { + // placement new would be preferred, but components include this file that do not enable it + pNew->Construct(threadId); + Node *pFirst; + do + { + pFirst = m_hashArray[index]; + pNew->pNext = pFirst; + } + while (::InterlockedCompareExchangePointer(reinterpret_cast(m_hashArray + index), pNew, pFirst) != pFirst); + return &pNew->value; + } + } + return nullptr; + } + + private: + ThreadStorage(ThreadStorage const &); + ThreadStorage& operator=(ThreadStorage const &); + + struct Node + { + T value; + DWORD threadId; + Node *pNext; + + void Construct(DWORD currentThreadId) + { + ::ZeroMemory(&value, sizeof(value)); + threadId = currentThreadId; + pNext = nullptr; + } + }; + + Node * volatile m_hashArray[threadCountEstimate]; + }; + + struct IFailureCallback + { + virtual bool NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT = 0; + }; + + class ThreadFailureCallbackHolder; +#ifndef RESULT_SUPPRESS_STATIC_INITIALIZERS + __declspec(selectany) ThreadStorage g_threadFailureCallbacks; + __declspec(selectany) ThreadStorage * g_pThreadFailureCallbacks = &g_threadFailureCallbacks; +#else + __declspec(selectany) ThreadStorage * g_pThreadFailureCallbacks = nullptr; +#endif + + class ThreadFailureCallbackHolder + { + public: + ThreadFailureCallbackHolder(_In_ IFailureCallback *pCallbackParam, _In_opt_ CallContextInfo *pCallContext = nullptr, bool watchNow = true) WI_NOEXCEPT : + m_pCallback(pCallbackParam), + m_ppThreadList(nullptr), + m_pNext(nullptr), + m_threadId(0), + m_pCallContext(pCallContext) + { + if (watchNow) + { + StartWatching(); + } + } + + ThreadFailureCallbackHolder(ThreadFailureCallbackHolder &&other) WI_NOEXCEPT : + m_pCallback(other.m_pCallback), + m_ppThreadList(nullptr), + m_pNext(nullptr), + m_threadId(0), + m_pCallContext(other.m_pCallContext) + { + if (other.m_threadId != 0) + { + other.StopWatching(); + StartWatching(); + } + } + + ~ThreadFailureCallbackHolder() WI_NOEXCEPT + { + if (m_threadId != 0) + { + StopWatching(); + } + } + + void SetCallContext(_In_opt_ CallContextInfo *pCallContext) + { + m_pCallContext = pCallContext; + } + + CallContextInfo *CallContextInfo() + { + return m_pCallContext; + } + + void StartWatching() + { + // out-of balance Start/Stop calls? + __FAIL_FAST_PRERELEASE_ASSERT__(m_threadId == 0); + + m_ppThreadList = (g_pThreadFailureCallbacks != nullptr) ? g_pThreadFailureCallbacks->GetLocal(true) : nullptr; // true = allocate thread list if missing + if (m_ppThreadList) + { + m_pNext = *m_ppThreadList; + *m_ppThreadList = this; + m_threadId = ::GetCurrentThreadId(); + } + } + + void StopWatching() + { + if (m_threadId != ::GetCurrentThreadId()) + { + // The thread-specific failure holder cannot be stopped on a different thread than it was started on or the + // internal book-keeping list will be corrupted. To fix this change the telemetry pattern in the calling code + // to match one of the patterns available here: + // https://microsoft.sharepoint.com/teams/osg_development/Shared%20Documents/Windows%20TraceLogging%20Helpers.docx + + WI_USAGE_ERROR("MEMORY CORRUPTION: Calling code is leaking an activity thread-watcher and releasing it on another thread"); + } + + m_threadId = 0; + + while (*m_ppThreadList != nullptr) + { + if (*m_ppThreadList == this) + { + *m_ppThreadList = m_pNext; + break; + } + m_ppThreadList = &((*m_ppThreadList)->m_pNext); + } + m_ppThreadList = nullptr; + } + + bool IsWatching() + { + return (m_threadId != 0); + } + + void SetWatching(bool shouldWatch) + { + if (shouldWatch && !IsWatching()) + { + StartWatching(); + } + else if (!shouldWatch && IsWatching()) + { + StopWatching(); + } + } + + static bool GetThreadContext(_Inout_ FailureInfo *pFailure, _In_opt_ ThreadFailureCallbackHolder *pCallback, _Out_writes_(callContextStringLength) _Post_z_ PSTR callContextString, _Pre_satisfies_(callContextStringLength > 0) size_t callContextStringLength) + { + *callContextString = '\0'; + bool foundContext = false; + if (pCallback != nullptr) + { + foundContext = GetThreadContext(pFailure, pCallback->m_pNext, callContextString, callContextStringLength); + + if (pCallback->m_pCallContext != nullptr) + { + auto &context = *pCallback->m_pCallContext; + + // We generate the next telemetry ID only when we've found an error (avoid always incrementing) + if (context.contextId == 0) + { + context.contextId = ::InterlockedIncrementNoFence(&s_telemetryId); + } + + if (pFailure->callContextOriginating.contextId == 0) + { + pFailure->callContextOriginating = context; + } + + pFailure->callContextCurrent = context; + + auto callContextStringEnd = callContextString + callContextStringLength; + callContextString += strlen(callContextString); + + if ((callContextStringEnd - callContextString) > 2) // room for at least the slash + null + { + *callContextString++ = '\\'; + auto nameSizeBytes = strlen(context.contextName) + 1; + size_t remainingBytes = static_cast(callContextStringEnd - callContextString); + auto copyBytes = (nameSizeBytes < remainingBytes) ? nameSizeBytes : remainingBytes; + memcpy(callContextString, context.contextName, copyBytes); + *(callContextString + (copyBytes - 1)) = '\0'; + } + + return true; + } + } + return foundContext; + } + + static void GetContextAndNotifyFailure(_Inout_ FailureInfo *pFailure, _Out_writes_(callContextStringLength) _Post_z_ PSTR callContextString, _Pre_satisfies_(callContextStringLength > 0) size_t callContextStringLength) WI_NOEXCEPT + { + *callContextString = '\0'; + bool reportedTelemetry = false; + + ThreadFailureCallbackHolder **ppListeners = (g_pThreadFailureCallbacks != nullptr) ? g_pThreadFailureCallbacks->GetLocal() : nullptr; + if ((ppListeners != nullptr) && (*ppListeners != nullptr)) + { + callContextString[0] = '\0'; + if (GetThreadContext(pFailure, *ppListeners, callContextString, callContextStringLength)) + { + pFailure->pszCallContext = callContextString; + } + + auto pNode = *ppListeners; + do + { + reportedTelemetry |= pNode->m_pCallback->NotifyFailure(*pFailure); + pNode = pNode->m_pNext; + } + while (pNode != nullptr); + } + + if (g_pfnTelemetryCallback != nullptr) + { + g_pfnTelemetryCallback(reportedTelemetry, *pFailure); + } + } + + ThreadFailureCallbackHolder(ThreadFailureCallbackHolder const &) = delete; + ThreadFailureCallbackHolder& operator=(ThreadFailureCallbackHolder const &) = delete; + + private: + static long volatile s_telemetryId; + + ThreadFailureCallbackHolder **m_ppThreadList; + IFailureCallback *m_pCallback; + ThreadFailureCallbackHolder *m_pNext; + DWORD m_threadId; + wil::CallContextInfo *m_pCallContext; + }; + + __declspec(selectany) long volatile ThreadFailureCallbackHolder::s_telemetryId = 1; + + // returns true if telemetry was reported for this error + inline void GetContextAndNotifyFailure(_Inout_ FailureInfo *pFailure, _Out_writes_(callContextStringLength) _Post_z_ PSTR callContextString, _Pre_satisfies_(callContextStringLength > 0) size_t callContextStringLength) WI_NOEXCEPT + { + ThreadFailureCallbackHolder::GetContextAndNotifyFailure(pFailure, callContextString, callContextStringLength); + } + + template + class ThreadFailureCallbackFn final : public IFailureCallback + { + public: + explicit ThreadFailureCallbackFn(_In_ CallContextInfo *pContext, _Inout_ TLambda &&errorFunction) WI_NOEXCEPT : + m_errorFunction(wistd::move(errorFunction)), + m_callbackHolder(this, pContext) + { + } + + ThreadFailureCallbackFn(_Inout_ ThreadFailureCallbackFn && other) WI_NOEXCEPT : + m_errorFunction(wistd::move(other.m_errorFunction)), + m_callbackHolder(this, other.m_callbackHolder.CallContextInfo()) + { + } + + bool NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT + { + return m_errorFunction(failure); + } + + private: + ThreadFailureCallbackFn(_In_ ThreadFailureCallbackFn const &); + ThreadFailureCallbackFn & operator=(_In_ ThreadFailureCallbackFn const &); + + TLambda m_errorFunction; + ThreadFailureCallbackHolder m_callbackHolder; + }; + + + template + class ScopeExitFn + { + public: + explicit ScopeExitFn(_Inout_ TLambda &&fnAtExit) WI_NOEXCEPT : + m_fnAtExit(wistd::move(fnAtExit)), + m_fRun(true) + { + static_assert(!wistd::is_lvalue_reference::value && !wistd::is_rvalue_reference::value, + "ScopeExit should only be directly used with R-Value lambdas"); + } + + ScopeExitFn(_Inout_ ScopeExitFn && other) WI_NOEXCEPT : + m_fnAtExit(wistd::move(other.m_fnAtExit)), + m_fRun(other.m_fRun) + { + other.m_fRun = false; + } + + ~ScopeExitFn() WI_NOEXCEPT + { + operator()(); + } + + void operator()() WI_NOEXCEPT + { + if (m_fRun) + { + m_fRun = false; + m_fnAtExit(); + } + } + + void Dismiss() WI_NOEXCEPT + { + m_fRun = false; + } + + private: + ScopeExitFn(_In_ ScopeExitFn const &); + ScopeExitFn & operator=(_In_ ScopeExitFn const &); + + TLambda m_fnAtExit; + bool m_fRun; + }; + +#ifdef WIL_ENABLE_EXCEPTIONS + enum class GuardState + { + Done = 0, + NeedsRunIgnore = 1, + NeedsRunLog = 2, + NeedsRunFailFast = 3 + }; + + template + class ScopeExitFnGuard + { + public: + explicit ScopeExitFnGuard(GuardState state, _Inout_ TLambda && fnAtExit) WI_NOEXCEPT : + m_fnAtExit(wistd::move(fnAtExit)), + m_state(state) + { + static_assert(!wistd::is_lvalue_reference::value && !wistd::is_rvalue_reference::value, + "ScopeExit should only be directly used with R-Value lambdas"); + } + + ScopeExitFnGuard(ScopeExitFnGuard && other) WI_NOEXCEPT : + m_fnAtExit(wistd::move(other.m_fnAtExit)), + m_state(other.m_state) + { + other.m_state = GuardState::Done; + } + + ~ScopeExitFnGuard() WI_NOEXCEPT + { + operator()(); + } + + void operator()() WI_NOEXCEPT + { + if (m_state != GuardState::Done) + { + auto state = m_state; + m_state = GuardState::Done; + try + { + m_fnAtExit(); + } + catch (...) + { + if (state == GuardState::NeedsRunFailFast) + { + FAIL_FAST_HR(wil::ResultFromCaughtException()); + } + else if (state == GuardState::NeedsRunLog) + { + LOG_HR(wil::ResultFromCaughtException()); + } + // GuardState::NeedsRunIgnore explicitly ignored + } + } + } + + void Dismiss() WI_NOEXCEPT + { + m_state = GuardState::Done; + } + + private: + ScopeExitFnGuard(ScopeExitFnGuard const &); + ScopeExitFnGuard & operator=(ScopeExitFnGuard const &); + + TLambda m_fnAtExit; + GuardState m_state; + }; +#endif // WIL_ENABLE_EXCEPTIONS + } // details namespace + //! @endcond + + //***************************************************************************** + // Public Error Handling Helpers + //***************************************************************************** + + // [optionally] Plug in fallback telemetry reporting + // Normally, the callback is owned by including ResultLogging.h in the including module. Alternatively a module + // could re-route fallback telemetry to any ONE specific provider by calling this method. + + inline void SetResultTelemetryFallback(_In_opt_ decltype(details::g_pfnTelemetryCallback) callbackFunction) + { + // Only ONE telemetry provider can own the fallback telemetry callback. + __FAIL_FAST_PRERELEASE_ASSERT__((details::g_pfnTelemetryCallback == nullptr) || (callbackFunction == nullptr)); + details::g_pfnTelemetryCallback = callbackFunction; + } + + + // [optionally] Plug in result logging (do not use for telemetry) + // This provides the ability for a module to hook all failures flowing through the system for inspection + // and/or logging. + + inline void SetResultLoggingCallback(_In_opt_ decltype(details::g_pfnLoggingCallback) callbackFunction) + { + // Only ONE function can own the result logging callback + __FAIL_FAST_PRERELEASE_ASSERT__((details::g_pfnLoggingCallback == nullptr) || (callbackFunction == nullptr)); + details::g_pfnLoggingCallback = callbackFunction; + } + + + // [optionally] Plug in custom result messages + // There are some purposes that require translating the full information that is known about a failure + // into a message to be logged (either through the console for debugging OR as the message attached + // to a Platform::Exception^). This callback allows a module to format the string itself away from the + // default. + + inline void SetResultMessageCallback(_In_opt_ decltype(wil::g_pfnResultLoggingCallback) callbackFunction) + { + // Only ONE function can own the result message callback + __FAIL_FAST_PRERELEASE_ASSERT__((g_pfnResultLoggingCallback == nullptr) || (callbackFunction == nullptr)); + details::g_resultMessageCallbackSet = true; + g_pfnResultLoggingCallback = callbackFunction; + } + + + // [optionally] Plug in exception remapping + // A module can plug a callback in using this function to setup custom exception handling to allow any + // exception type to be converted into an HRESULT from exception barriers. + + inline void SetResultFromCaughtExceptionCallback(_In_opt_ decltype(wil::g_pfnResultFromCaughtException) callbackFunction) + { + // Only ONE function can own the exception conversion + __FAIL_FAST_PRERELEASE_ASSERT__((g_pfnResultFromCaughtException == nullptr) || (callbackFunction == nullptr)); + g_pfnResultFromCaughtException = callbackFunction; + } + + + // A RAII wrapper around the storage of a FailureInfo struct (which is normally meant to be consumed + // on the stack or from the caller). The storage of FailureInfo needs to copy some data internally + // for lifetime purposes. + + class StoredFailureInfo + { + public: + StoredFailureInfo() WI_NOEXCEPT + { + ::ZeroMemory(&m_failureInfo, sizeof(m_failureInfo)); + } + + StoredFailureInfo(FailureInfo const &other) WI_NOEXCEPT + { + SetFailureInfo(other); + } + + FailureInfo const & GetFailureInfo() const WI_NOEXCEPT + { + return m_failureInfo; + } + + void SetFailureInfo(FailureInfo const &failure) WI_NOEXCEPT + { + m_failureInfo = failure; + + size_t const cbNeed = details::ResultStringSize(failure.pszMessage) + + details::ResultStringSize(failure.pszCode) + + details::ResultStringSize(failure.pszFunction) + + details::ResultStringSize(failure.pszFile) + + details::ResultStringSize(failure.pszCallContext) + + details::ResultStringSize(failure.pszModule) + + details::ResultStringSize(failure.callContextCurrent.contextName) + + details::ResultStringSize(failure.callContextCurrent.contextMessage) + + details::ResultStringSize(failure.callContextOriginating.contextName) + + details::ResultStringSize(failure.callContextOriginating.contextMessage); + + if (!m_spStrings.unique() || (m_spStrings.size() < cbNeed)) + { + m_spStrings.reset(); + m_spStrings.create(cbNeed); + } + + size_t cbAlloc; + unsigned char *pBuffer = static_cast(m_spStrings.get(&cbAlloc)); + unsigned char *pBufferEnd = (pBuffer != nullptr) ? pBuffer + cbAlloc : nullptr; + + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszMessage, &m_failureInfo.pszMessage); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszCode, &m_failureInfo.pszCode); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszFunction, &m_failureInfo.pszFunction); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszFile, &m_failureInfo.pszFile); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszCallContext, &m_failureInfo.pszCallContext); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszModule, &m_failureInfo.pszModule); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.callContextCurrent.contextName, &m_failureInfo.callContextCurrent.contextName); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.callContextCurrent.contextMessage, &m_failureInfo.callContextCurrent.contextMessage); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.callContextOriginating.contextName, &m_failureInfo.callContextOriginating.contextName); + details::WriteResultString(pBuffer, pBufferEnd, failure.callContextOriginating.contextMessage, &m_failureInfo.callContextOriginating.contextMessage); + } + + // Relies upon generated copy constructor and assignment operator + + protected: + FailureInfo m_failureInfo; + details::shared_buffer m_spStrings; + }; + + + // This is the default class thrown from all THROW_XXX macros. It stores all of the FailureInfo context that + // is available when the exception is thrown. It's also caught by exception guards for conversion to HRESULT. + + class ResultException + { + public: + ResultException(FailureInfo const &failure) WI_NOEXCEPT : + m_failure(failure) + { + } + + // This constructor should be used only for custom exception types + ResultException(_Pre_satisfies_(hr < 0) HRESULT hr) WI_NOEXCEPT : + m_failure(CustomExceptionFailureInfo(hr)) + { + } + + _Always_(_Post_satisfies_(return < 0)) HRESULT GetErrorCode() const WI_NOEXCEPT + { + HRESULT const hr = m_failure.GetFailureInfo().hr; + __analysis_assume(hr < 0); + return hr; + } + + FailureInfo const & GetFailureInfo() const WI_NOEXCEPT + { + return m_failure.GetFailureInfo(); + } + + void SetFailureInfo(FailureInfo const &failure) WI_NOEXCEPT + { + m_failure.SetFailureInfo(failure); + } + + // Relies upon auto-generated copy constructor and assignment operator + protected: + StoredFailureInfo m_failure; + + static FailureInfo CustomExceptionFailureInfo(HRESULT hr) WI_NOEXCEPT + { + FailureInfo fi = {}; + fi.type = FailureType::Exception; + fi.hr = hr; + return fi; + } + }; + + + // This helper functions much like ScopeExit -- give it a lambda and get back a local object that can be used to + // catch all errors happening in your module through all WIL error handling mechanisms. The lambda will be called + // once for each error throw, error return, or error catch that is handled while the returned object is still in + // scope. Usage: + // + // auto monitor = wil::ThreadFailureCallback([](wil::FailureInfo const &failure) + // { + // // Write your code that logs or cares about failure details here... + // // It has access to HRESULT, filename, line number, etc through the failure param. + // }); + // + // As long as the returned 'monitor' object remains in scope, the lambda will continue to receive callbacks for any + // failures that occur in this module on the calling thread. Note that this will guarantee that the lambda will run + // for any failure that is through any of the WIL macros (THROW_XXX, RETURN_XXX, LOG_XXX, etc). + + template + inline wil::details::ThreadFailureCallbackFn ThreadFailureCallback(_Inout_ TLambda &&fnAtExit) WI_NOEXCEPT + { + return wil::details::ThreadFailureCallbackFn(nullptr, wistd::forward(fnAtExit)); + } + + + // Much like ThreadFailureCallback, this class will receive WIL failure notifications from the time it's instantiated + // until the time that it's destroyed. At any point during that time you can ask for the last failure that was seen + // by any of the WIL macros (RETURN_XXX, THROW_XXX, LOG_XXX, etc) on the current thread. + // + // This class is most useful when utilized as a member of an RAII class that's dedicated to providing logging or + // telemetry. In the destructor of that class, if the operation had not been completed successfully (it goes out of + // scope due to early return or exception unwind before success is acknowledged) then details about the last failure + // can be retrieved and appropriately logged. + // + // Usage: + // + // class MyLogger + // { + // public: + // MyLogger() : m_fComplete(false) {} + // ~MyLogger() + // { + // if (!m_fComplete) + // { + // FailureInfo *pFailure = m_cache.GetFailure(); + // if (pFailure != nullptr) + // { + // // Log information about pFailure (pFileure->hr, pFailure->pszFile, pFailure->uLineNumber, etc) + // } + // else + // { + // // It's possible that you get stack unwind from an exception that did NOT come through WIL + // // like (std::bad_alloc from the STL). Use a reasonable default like: HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION). + // } + // } + // } + // void Complete() { m_fComplete = true; } + // private: + // bool m_fComplete; + // ThreadFailureCache m_cache; + // }; + + class ThreadFailureCache final : + public details::IFailureCallback + { + public: + ThreadFailureCache() : + m_callbackHolder(this) + { + } + + ThreadFailureCache(ThreadFailureCache && rhs) : + m_failure(wistd::move(rhs.m_failure)), + m_callbackHolder(this) + { + } + + ThreadFailureCache& operator=(ThreadFailureCache && rhs) + { + m_failure = wistd::move(rhs.m_failure); + return *this; + } + + void WatchCurrentThread() + { + m_callbackHolder.StartWatching(); + } + + void IgnoreCurrentThread() + { + m_callbackHolder.StopWatching(); + } + + FailureInfo const *GetFailure() + { + return (FAILED(m_failure.GetFailureInfo().hr) ? &(m_failure.GetFailureInfo()) : nullptr); + } + + bool NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT + { + // When we "cache" a failure, we bias towards trying to find the origin of the last HRESULT + // generated, so we ignore subsequent failures on the same error code (assuming propagation). + + if (failure.hr != m_failure.GetFailureInfo().hr) + { + m_failure.SetFailureInfo(failure); + } + return false; + } + + private: + StoredFailureInfo m_failure; + details::ThreadFailureCallbackHolder m_callbackHolder; + }; + + + // The ScopeExit function accepts a lambda and returns an object meant to be captured in + // an auto variable. That lambda will be run when the object goes out of scope. For most + // begin/end pairings RAII techniques should be used instead, but occasionally there are + // uncommon cases where RAII techniques are impractical (ensuring a file is deleted after + // a test routine, etc). Usage involves: + // + // FunctionNeedingCleanup(); // start with a call to establish some state that requires cleanup + // auto fnCleanup = ScopeExit([&] + // { + // // write cleanup code here + // }); + // + // When fnCleanup goes out of scope it will run its lambda. Optionally, if the cleanup is + // no long needed, it can be dismissed (so that it is not run): + // + // fnCleanup.Dismiss(); + // + // If the cleanup is needed ahead of going out of scope it can be explicitly run: + // + // fnCleanup(); + + template + inline wil::details::ScopeExitFn ScopeExit(_Inout_ TLambda && fnAtExit) WI_NOEXCEPT + { + return wil::details::ScopeExitFn(wistd::forward(fnAtExit)); + } + + + //***************************************************************************** + // Public Helpers that catch -- only enabled when exceptions are enabled + //***************************************************************************** + +#ifdef WIL_ENABLE_EXCEPTIONS + // The ScopeExitXXX functions work identically to ScopeExit but add an exception guard for the lambda. The different + // variants control what happens if an exception were actually thrown from the cleanup lambda. + + // The ScopeExitNoExcept version should eventually be removed in favor of the simpler ScopeExit() once noexcept is + // fully implemented to provide fail fast handling of exceptions from the regular scope exit class. + template + inline wil::details::ScopeExitFnGuard ScopeExitNoExcept(TLambda && fnAtExit) WI_NOEXCEPT + { + return wil::details::ScopeExitFnGuard(wil::details::GuardState::NeedsRunFailFast, wistd::forward(fnAtExit)); + } + + template + inline wil::details::ScopeExitFnGuard ScopeExitLog(TLambda && fnAtExit) WI_NOEXCEPT + { + return wil::details::ScopeExitFnGuard(wil::details::GuardState::NeedsRunLog, wistd::forward(fnAtExit)); + } + + template + inline wil::details::ScopeExitFnGuard ScopeExitIgnore(TLambda && fnAtExit) WI_NOEXCEPT + { + return wil::details::ScopeExitFnGuard(wil::details::GuardState::NeedsRunIgnore, wistd::forward(fnAtExit)); + } + + + // ResultFromCaughtException is a function that is meant to be called from within a catch(...) block. Internally + // it re-throws and catches the exception to convert it to an HRESULT. If an exception is of an unrecognized type + // the function will fail fast. + // + // try + // { + // // Code + // } + // catch (...) + // { + // hr = wil::ResultFromCaughtException(); + // } + + _Always_(_Post_satisfies_(return < 0)) + __declspec(noinline) inline HRESULT ResultFromCaughtException() WI_NOEXCEPT + { + if (details::g_pfnResultFromCaughtException_WinRt != nullptr) + { + HRESULT hr = details::g_pfnResultFromCaughtException_WinRt(); + __analysis_assume(hr < 0); + return hr; + } + + try + { + throw; + } + catch (ResultException const &re) + { + return re.GetErrorCode(); + } + catch (std::bad_alloc const &) + { + return E_OUTOFMEMORY; + } + catch (...) + { + return details::ResultFromUnknownCaughtException(); + } + } + + + // ResultFromException serves as an exception guard. Much like try/catch(...), this function accepts a lambda + // where all exceptions generated within will be caught and converted to their corresponding HRESULT. If an + // exception is of an unrecognized type, then the guard will fail fast. + // + // HRESULT ErrorCodeReturningFunction() + // { + // RETURN_HR(wil::ResultFromException([&])() + // { + // // Use of libraries or function calls that may throw + // // exceptions... + // })); + // } + + template + inline HRESULT ResultFromException(_Inout_ Functor && functor) WI_NOEXCEPT + { + try + { + functor(); + } + catch (...) + { + return ResultFromCaughtException(); + } + return S_OK; + } + + + // NormalizeIfExceptionThrown serves as an exception guard built to normalize on one exception type. This allows + // a C++/CX void returning function to normalize all exceptions thrown within to Platform::Exception^, even if + // STL is used within (std::bad_alloc) or a custom ResultException has been thrown within. Thus when that C++/CX + // method is invoked by COM with a cross-apartment call, those exceptions will be caught and mapped correctly to + // an HRESULT. From within straight C++, this normalization works identically, only remapping all known exception + // types to ResultException, rather than Platform::Exception^ + // + // void MyFunction() + // { + // wil::NormalizeIfExceptionThrown([&])() + // { + // // Use of libraries or function calls that may throw diverse + // // exception types... + // })); + // } + + template + inline void NormalizeIfExceptionThrown(_Inout_ Functor && functor) + { + try + { + functor(); + } + catch (...) + { + wil::details::RethrowNormalizedCaughtException(__R_INFO_ONLY(nullptr)); + } + } +#endif // WIL_ENABLE_EXCEPTIONS + + //! @cond + namespace details + { + //***************************************************************************** + // Private helpers to catch and propagate exceptions + //***************************************************************************** + +#ifdef WIL_ENABLE_EXCEPTIONS + _declspec(noreturn) inline void RethrowUnknownCaughtException(__R_FN_PARAMS_FULL, _In_opt_ PCWSTR message) + { + if (g_pfnResultFromCaughtException != nullptr) + { + const HRESULT hr = g_pfnResultFromCaughtException(); + if (FAILED(hr)) + { + ReportFailure(__R_FN_CALL_FULL, FailureType::Exception, hr, message); + } + } + +#ifdef RESULT_PRERELEASE + if (g_fResultFailFastUnknownExceptions) + { + // Caller bug: an unknown exception was thrown + ReportFailure(__R_FN_CALL_FULL, FailureType::FailFast, HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION), message); + } +#endif + ReportFailure(__R_FN_CALL_FULL, FailureType::Exception, HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION), message); + } + +#ifdef __cplusplus_winrt + __declspec(noreturn) inline void __stdcall RethrowNormalizedCaughtException_WinRt(__R_FN_PARAMS_FULL, _In_opt_ PCWSTR message) + { + try + { + throw; + } + catch (ResultException const &re) + { + auto &failure = re.GetFailureInfo(); + ReportFailure(__R_FN_CALL_FULL, FailureType::Exception, failure.hr, message, ReportFailureOptions::SuppressAction); + + // Convert to a Platform::Exception^ by re-throwing with the existing failure information + // to maintain as much context as we can. + ReportFailure(failure.callerReturnAddress, failure.uLineNumber, failure.pszFile, failure.pszFunction, failure.pszCode, failure.returnAddress, FailureType::Exception, failure.hr, failure.pszMessage, ReportFailureOptions::ForcePlatformException); + } + catch (Platform::Exception^ exception) + { + wchar_t messageString[2048]; + if (exception->Message) + { + StringCchCopyW(messageString, ARRAYSIZE(messageString), reinterpret_cast(exception->Message->Data())); + if (message != nullptr) + { + StringCchCatW(messageString, ARRAYSIZE(messageString), L" - "); + } + } + else + { + messageString[0] = L'\0'; + } + if (message != nullptr) + { + StringCchCatW(messageString, ARRAYSIZE(messageString), message); + } + + ReportFailure(__R_FN_CALL_FULL, FailureType::Exception, exception->HResult, messageString, ReportFailureOptions::SuppressAction); + + // In C++/CX, Platform::Exception^ is our normalized exception... we can re-throw it. + throw; + } + catch (std::bad_alloc const &) + { + ReportFailure(__R_FN_CALL_FULL, FailureType::Exception, E_OUTOFMEMORY, message); + } + catch (...) + { + RethrowUnknownCaughtException(__R_FN_CALL_FULL, message); + } + RESULT_RAISE_FAST_FAIL_EXCEPTION; + } +#endif + + __declspec(noreturn) inline void RethrowNormalizedCaughtException_Helper(__R_FN_PARAMS_FULL, _In_opt_ PCWSTR message = nullptr) + { + if (g_pfnRethrowNormalizedCaughtException_WinRt != nullptr) + { + g_pfnRethrowNormalizedCaughtException_WinRt(__R_FN_CALL_FULL, message); + } + + try + { + throw; + } + catch (ResultException const &re) + { + ReportFailure(__R_FN_CALL_FULL, FailureType::Exception, re.GetErrorCode(), message, ReportFailureOptions::SuppressAction); + + // Outside of C++/CX, ResultException is our normalized exception. Because it's our class + // we can be confident that it has already been logged -- just re-throw it. + throw; + } + catch (std::bad_alloc const &) + { + ReportFailure(__R_FN_CALL_FULL, FailureType::Exception, E_OUTOFMEMORY, message); + } + catch (...) + { + RethrowUnknownCaughtException(__R_FN_CALL_FULL, message); + } + } + + __declspec(noinline, noreturn) inline void RethrowNormalizedCaughtException(__R_FN_PARAMS_ONLY) + { + __R_FN_LOCALS; + RethrowNormalizedCaughtException_Helper(__R_FN_CALL_FULL_RA); + } + + __declspec(noinline, noreturn) inline void RethrowNormalizedCaughtExceptionMsg(__R_FN_PARAMS _In_ _Printf_format_string_ PCSTR formatString, ...) + { + va_list argList; + va_start(argList, formatString); + wchar_t message[2048]; + PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); + + __R_FN_LOCALS; + RethrowNormalizedCaughtException_Helper(__R_FN_CALL_FULL_RA, message); + } + + _Always_(_Post_satisfies_(return < 0)) + inline HRESULT ResultFromUnknownCaughtException() + { + if (g_pfnResultFromCaughtException != nullptr) + { + HRESULT hr = g_pfnResultFromCaughtException(); + if (FAILED(hr)) + { + return hr; + } + } + + // Caller bug: an unknown exception was thrown + FAIL_FAST_HR_IF(HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION), g_fResultFailFastUnknownExceptions); + + return HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); + } + +#ifdef __cplusplus_winrt + _Always_(_Post_satisfies_(return < 0)) + inline HRESULT __stdcall ResultFromCaughtException_WinRt() WI_NOEXCEPT + { + try + { + throw; + } + catch (ResultException const &re) + { + return re.GetErrorCode(); + } + catch (Platform::Exception^ exception) + { + return exception->HResult; + } + catch (std::bad_alloc const &) + { + return E_OUTOFMEMORY; + } + catch (...) + { + return ResultFromUnknownCaughtException(); + } + } + +#if !defined(RESULT_SUPPRESS_STATIC_INITIALIZERS) + WI_HEADER_INITITALIZATION_FUNCTION(InitializeWinRtExceptions, [] + { + g_pfnRethrowNormalizedCaughtException_WinRt = RethrowNormalizedCaughtException_WinRt; + g_pfnResultFromCaughtException_WinRt = ResultFromCaughtException_WinRt; + return 1; + }); +#endif +#endif +#endif // WIL_ENABLE_EXCEPTIONS + + + + //***************************************************************************** + // Shared Reporting -- all reporting macros bubble up through this codepath + //***************************************************************************** + + inline void LogFailure(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, _In_opt_ PCWSTR message, + bool fWantDebugString, _Out_writes_(debugStringSizeChars) _Post_z_ PWSTR debugString, _Pre_satisfies_(debugStringSizeChars > 0) size_t debugStringSizeChars, + _Out_writes_(callContextStringSizeChars) _Post_z_ PSTR callContextString, _Pre_satisfies_(callContextStringSizeChars > 0) size_t callContextStringSizeChars, + _Out_ FailureInfo *failure) WI_NOEXCEPT + { + debugString[0] = L'\0'; + callContextString[0] = L'\0'; + + static long volatile s_failureId = 0; + + int failureCount = 0; + switch (type) + { + case FailureType::Exception: + failureCount = RecordException(hr); + break; + case FailureType::Return: + failureCount = RecordReturn(hr); + break; + case FailureType::ReturnPreRelease: + failureCount = RecordReturnPreRelease(hr); + break; + case FailureType::Log: + if (SUCCEEDED(hr)) + { + // If you hit this assert (or are reviewing this failure telemetry), then most likely you are trying to log success + // using one of the WIL macros. Example: + // LOG_HR(S_OK); + // Instead, use one of the forms that conditionally logs based upon the error condition: + // LOG_IF_FAILED(hr); + + WI_USAGE_ERROR_FORWARD("CALLER BUG: Macro usage error detected. Do not LOG_XXX success."); + hr = HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE); + } + failureCount = RecordLog(hr); + break; + case FailureType::FailFast: + failureCount = RecordFailFast(hr); + break; + }; + + failure->type = type; + failure->hr = hr; + failure->failureId = ::InterlockedIncrementNoFence(&s_failureId); + failure->pszMessage = ((message != nullptr) && (message[0] != L'\0')) ? message : nullptr; + failure->threadId = ::GetCurrentThreadId(); + failure->pszFile = fileName; + failure->uLineNumber = lineNumber; + failure->cFailureCount = failureCount; + failure->pszCode = code; + failure->pszFunction = functionName; + failure->returnAddress = returnAddress; + failure->callerReturnAddress = callerReturnAddress; + failure->pszCallContext = nullptr; + ClearContext(&failure->callContextCurrent); + ClearContext(&failure->callContextOriginating); + failure->pszModule = (g_pfnGetModuleName != nullptr) ? g_pfnGetModuleName() : nullptr; + + // Completes filling out failure, notifies thread-based callbacks and the telemetry callback + GetContextAndNotifyFailure(failure, callContextString, callContextStringSizeChars); + + // Allow a hook to inspect the failure before acting upon it + if (details::g_pfnLoggingCallback != nullptr) + { + details::g_pfnLoggingCallback(*failure); + } + + // Caller bug: Leaking a success code into a failure-only function + FAIL_FAST_IF(SUCCEEDED(failure->hr) && (type != FailureType::FailFast)); + + // We log to OutputDebugString if: + // * Someone set g_fResultOutputDebugString to true (by the calling module or in the debugger) + // * OR we're in a PRELEASE build without ANY logging callback set (likely then a tool or test) + bool const fUseOutputDebugString = (g_fResultOutputDebugString +#ifdef RESULT_PRERELEASE + || ((g_pfnTelemetryCallback == nullptr) && (g_pfnResultLoggingCallback == nullptr)) +#endif + ); + + // We need to generate the logging message if: + // * We're logging to OutputDebugString + // * OR the caller asked us to (generally for attaching to a C++/CX exception) + if (fWantDebugString || fUseOutputDebugString) + { + // Call the logging callback (if present) to allow them to generate the debug string that will be pushed to the console + // or the platform exception object if the caller desires it. + if (g_pfnResultLoggingCallback != nullptr) + { + g_pfnResultLoggingCallback(failure, debugString, debugStringSizeChars); + } + + // The callback only optionally needs to supply the debug string -- if the callback didn't populate it, yet we still want + // it for OutputDebugString or exception message, then generate the default string. + if (debugString[0] == L'\0') + { + GetFailureLogString(debugString, debugStringSizeChars, *failure); + } + + if (fUseOutputDebugString) + { + ::OutputDebugStringW(debugString); + } + } + else + { + // [deprecated behavior] + // This callback was at one point *always* called for all failures, so we continue to call it for failures even when we don't + // need to generate the debug string information (when the callback was supplied directly). We can avoid this if the caller + // used the explicit function (through g_resultMessageCallbackSet) + if ((g_pfnResultLoggingCallback != nullptr) && !g_resultMessageCallbackSet) + { + g_pfnResultLoggingCallback(failure, nullptr, 0); + } + } + } + +#ifdef __cplusplus_winrt + inline void __stdcall ThrowPlatformException(FailureInfo const &failure, LPCWSTR debugString) + { + throw Platform::Exception::CreateException(failure.hr, ref new Platform::String(reinterpret_cast<_Null_terminated_ const __wchar_t *>(debugString))); + } + +#if !defined(RESULT_SUPPRESS_STATIC_INITIALIZERS) + WI_HEADER_INITITALIZATION_FUNCTION(InitializeWinRt, [] + { + g_pfnThrowPlatformException = ThrowPlatformException; + return 1; + }); +#endif +#endif + + inline __declspec(noinline) void ReportFailure(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, _In_opt_ PCWSTR message, ReportFailureOptions options) + { + bool needPlatformException = ((type == FailureType::Exception) && + (g_pfnThrowPlatformException != nullptr) && + (g_fResultThrowPlatformException || WI_IS_FLAG_SET(options, ReportFailureOptions::ForcePlatformException))); + + FailureInfo failure; + wchar_t debugString[2048]; + char callContextString[1024]; + + LogFailure(__R_FN_CALL_FULL, type, hr, message, needPlatformException, + debugString, ARRAYSIZE(debugString), callContextString, ARRAYSIZE(callContextString), &failure); + + if (WI_IS_FLAG_CLEAR(options, ReportFailureOptions::SuppressAction)) + { + if (type == FailureType::FailFast) + { + // This is an explicit fail fast - examine the callstack to determine the precise reason for this failure + RESULT_RAISE_FAST_FAIL_EXCEPTION; + } + else if (type == FailureType::Exception) + { + if (needPlatformException) + { + g_pfnThrowPlatformException(failure, debugString); + } + + throw ResultException(failure); + } + } + } + + inline void ReportFailure_Msg(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) + { + wchar_t message[2048]; + PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); + ReportFailure(__R_FN_CALL_FULL, type, hr, message); + } + + inline void ReportFailure_ReplaceMsg(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) + { + va_list argList; + va_start(argList, formatString); + ReportFailure_Msg(__R_FN_CALL_FULL, type, hr, formatString, argList); + } + + __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr) + { + ReportFailure(__R_FN_CALL_FULL, type, hr); + } + + __declspec(noinline) inline HRESULT ReportFailure_Win32(__R_FN_PARAMS_FULL, FailureType type, DWORD err) + { + auto hr = HRESULT_FROM_WIN32(err); + ReportFailure(__R_FN_CALL_FULL, type, hr); + return hr; + } + + __declspec(noinline) inline DWORD ReportFailure_GetLastError(__R_FN_PARAMS_FULL, FailureType type) + { + auto err = GetLastErrorFail(__R_FN_CALL_FULL); + ReportFailure(__R_FN_CALL_FULL, type, HRESULT_FROM_WIN32(err)); + return err; + } + + __declspec(noinline) inline HRESULT ReportFailure_GetLastErrorHr(__R_FN_PARAMS_FULL, FailureType type) + { + auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); + ReportFailure(__R_FN_CALL_FULL, type, hr); + return hr; + } + + __declspec(noinline) inline HRESULT ReportFailure_NtStatus(__R_FN_PARAMS_FULL, FailureType type, NTSTATUS status) + { + auto hr = wil::details::NtStatusToHr(status); + ReportFailure(__R_FN_CALL_FULL, type, hr); + return hr; + } + + __declspec(noinline) inline void ReportFailure_HrMsg(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) + { + ReportFailure_Msg(__R_FN_CALL_FULL, type, hr, formatString, argList); + } + + __declspec(noinline) inline HRESULT ReportFailure_Win32Msg(__R_FN_PARAMS_FULL, FailureType type, DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto hr = HRESULT_FROM_WIN32(err); + ReportFailure_Msg(__R_FN_CALL_FULL, type, HRESULT_FROM_WIN32(err), formatString, argList); + return hr; + } + + __declspec(noinline) inline DWORD ReportFailure_GetLastErrorMsg(__R_FN_PARAMS_FULL, FailureType type, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto err = GetLastErrorFail(__R_FN_CALL_FULL); + ReportFailure_Msg(__R_FN_CALL_FULL, type, HRESULT_FROM_WIN32(err), formatString, argList); + return err; + } + + __declspec(noinline) inline HRESULT ReportFailure_GetLastErrorHrMsg(__R_FN_PARAMS_FULL, FailureType type, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); + ReportFailure_Msg(__R_FN_CALL_FULL, type, hr, formatString, argList); + return hr; + } + + __declspec(noinline) inline HRESULT ReportFailure_NtStatusMsg(__R_FN_PARAMS_FULL, FailureType type, NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto hr = wil::details::NtStatusToHr(status); + ReportFailure_Msg(__R_FN_CALL_FULL, type, hr, formatString, argList); + return hr; + } + + + //***************************************************************************** + // Support for throwing custom exception types + //***************************************************************************** + + inline HRESULT GetErrorCode(_In_ ResultException &exception) WI_NOEXCEPT + { + return exception.GetErrorCode(); + } + + inline void SetFailureInfo(_In_ FailureInfo const &failure, _Inout_ ResultException &exception) WI_NOEXCEPT + { + return exception.SetFailureInfo(failure); + } + +#ifdef __cplusplus_winrt + inline HRESULT GetErrorCode(_In_ Platform::Exception^ exception) WI_NOEXCEPT + { + return exception->HResult; + } + + inline void SetFailureInfo(_In_ FailureInfo const &, _Inout_ Platform::Exception^ exception) WI_NOEXCEPT + { + // no-op -- once a PlatformException^ is created, we can't modify the message, but this function must + // exist to distinguish this from ResultException + } +#endif + + template + __declspec(noreturn) inline void ReportFailure_CustomExceptionHelper(_Inout_ T &exception, __R_FN_PARAMS_FULL, _In_opt_ PCWSTR message = nullptr) + { + // When seeing the error: "cannot convert parameter 1 from 'XXX' to 'wil::ResultException &'" + // Custom exceptions must be based upon either ResultException or Platform::Exception^ to be used with ResultException.h. + // This compilation error indicates an attempt to throw an incompatible exception type. + const HRESULT hr = GetErrorCode(exception); + + FailureInfo failure; + wchar_t debugString[2048]; + char callContextString[1024]; + + LogFailure(__R_FN_CALL_FULL, FailureType::Exception, hr, message, false, // false = does not need debug string + debugString, ARRAYSIZE(debugString), callContextString, ARRAYSIZE(callContextString), &failure); + + // push the failure info context into the custom exception class + SetFailureInfo(failure, exception); + + throw exception; + } + + template + __declspec(noreturn, noinline) inline void ReportFailure_CustomException(__R_FN_PARAMS _In_ T exception) + { + __R_FN_LOCALS_RA; + ReportFailure_CustomExceptionHelper(exception, __R_FN_CALL_FULL); + } + + template + __declspec(noreturn, noinline) inline void ReportFailure_CustomExceptionMsg(__R_FN_PARAMS _In_ T exception, _In_ _Printf_format_string_ PCSTR formatString, ...) + { + va_list argList; + va_start(argList, formatString); + wchar_t message[2048]; + PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); + + __R_FN_LOCALS_RA; + ReportFailure_CustomExceptionHelper(exception, __R_FN_CALL_FULL, message); + } + + namespace __R_NS_NAME + { + //***************************************************************************** + // Return Macros + //***************************************************************************** + + __R_DIRECT_METHOD(void, Return_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_DIRECT_FN_CALL FailureType::Return, hr); + } + + __R_DIRECT_METHOD(HRESULT, Return_Win32)(__R_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT + { + __R_FN_LOCALS; + return wil::details::ReportFailure_Win32(__R_DIRECT_FN_CALL FailureType::Return, err); + } + + __R_DIRECT_METHOD(HRESULT, Return_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __R_FN_LOCALS; + return wil::details::ReportFailure_GetLastErrorHr(__R_DIRECT_FN_CALL FailureType::Return); + } + + __R_DIRECT_METHOD(HRESULT, Return_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT + { + __R_FN_LOCALS; + return wil::details::ReportFailure_NtStatus(__R_DIRECT_FN_CALL FailureType::Return, status); + } + + __R_DIRECT_METHOD(void, Return_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_DIRECT_FN_CALL FailureType::Return, hr, formatString, argList); + } + + __R_DIRECT_METHOD(HRESULT, Return_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + return wil::details::ReportFailure_Win32Msg(__R_DIRECT_FN_CALL FailureType::Return, err, formatString, argList); + } + + __R_DIRECT_METHOD(HRESULT, Return_GetLastErrorMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + return wil::details::ReportFailure_GetLastErrorHrMsg(__R_DIRECT_FN_CALL FailureType::Return, formatString, argList); + } + + __R_DIRECT_METHOD(HRESULT, Return_NtStatusMsg)(__R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + return wil::details::ReportFailure_NtStatusMsg(__R_DIRECT_FN_CALL FailureType::Return, status, formatString, argList); + } + + //***************************************************************************** + // Pre-release Return Macros + //***************************************************************************** + +#ifdef RESULT_PRERELEASE + __R_DIRECT_METHOD(void, Return_HrPreRelease)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_DIRECT_FN_CALL FailureType::ReturnPreRelease, hr); + } + + __R_DIRECT_METHOD(HRESULT, Return_Win32PreRelease)(__R_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT + { + __R_FN_LOCALS; + return wil::details::ReportFailure_Win32(__R_DIRECT_FN_CALL FailureType::ReturnPreRelease, err); + } + + __R_DIRECT_METHOD(HRESULT, Return_GetLastErrorPreRelease)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __R_FN_LOCALS; + return wil::details::ReportFailure_GetLastErrorHr(__R_DIRECT_FN_CALL FailureType::ReturnPreRelease); + } + + __R_DIRECT_METHOD(HRESULT, Return_NtStatusPreRelease)(__R_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT + { + __R_FN_LOCALS; + return wil::details::ReportFailure_NtStatus(__R_DIRECT_FN_CALL FailureType::ReturnPreRelease, status); + } +#endif + + //***************************************************************************** + // Log Macros + //***************************************************************************** + + __R_DIRECT_METHOD(HRESULT, Log_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_DIRECT_FN_CALL FailureType::Log, hr); + return hr; + } + + __R_DIRECT_METHOD(DWORD, Log_Win32)(__R_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_Win32(__R_DIRECT_FN_CALL FailureType::Log, err); + return err; + } + + __R_DIRECT_METHOD(DWORD, Log_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __R_FN_LOCALS; + return wil::details::ReportFailure_GetLastError(__R_DIRECT_FN_CALL FailureType::Log); + } + + __R_DIRECT_METHOD(NTSTATUS, Log_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatus(__R_DIRECT_FN_CALL FailureType::Log, status); + return status; + } + + __R_INTERNAL_METHOD(_Log_Hr)(__R_INTERNAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL FailureType::Log, hr); + } + + __R_INTERNAL_METHOD(_Log_GetLastError)(__R_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_GetLastError(__R_INTERNAL_FN_CALL FailureType::Log); + } + + __R_INTERNAL_METHOD(_Log_Win32)(__R_INTERNAL_FN_PARAMS DWORD err) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_Win32(__R_INTERNAL_FN_CALL FailureType::Log, err); + } + + __R_INTERNAL_METHOD(_Log_NullAlloc)(__R_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL FailureType::Log, E_OUTOFMEMORY); + } + + __R_INTERNAL_METHOD(_Log_NtStatus)(__R_INTERNAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatus(__R_INTERNAL_FN_CALL FailureType::Log, status); + } + + __R_CONDITIONAL_METHOD(HRESULT, Log_IfFailed)(__R_CONDITIONAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT + { + if (FAILED(hr)) + { + __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return hr; + } + + __R_CONDITIONAL_METHOD(BOOL, Log_IfWin32BoolFalse)(__R_CONDITIONAL_FN_PARAMS BOOL ret) WI_NOEXCEPT + { + if (!ret) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return ret; + } + + __R_CONDITIONAL_METHOD(DWORD, Log_IfWin32Error)(__R_CONDITIONAL_FN_PARAMS DWORD err) WI_NOEXCEPT + { + if (FAILED_WIN32(err)) + { + __R_CALL_INTERNAL_METHOD(_Log_Win32)(__R_CONDITIONAL_FN_CALL err); + } + return err; + } + + __R_CONDITIONAL_METHOD(HANDLE, Log_IfHandleInvalid)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) WI_NOEXCEPT + { + if (handle == INVALID_HANDLE_VALUE) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return handle; + } + + __R_CONDITIONAL_METHOD(HANDLE, Log_IfHandleNull)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) WI_NOEXCEPT + { + if (handle == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return handle; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Log_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(void, Log_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Log_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY); + } + } + + __R_CONDITIONAL_METHOD(bool, Log_HrIf)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT + { + if (condition) + { + __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return condition; + } + + __R_CONDITIONAL_METHOD(bool, Log_HrIfFalse)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT + { + if (!condition) + { + __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return condition; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(void, Log_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + } + + __R_CONDITIONAL_METHOD(bool, Log_GetLastErrorIf)(__R_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT + { + if (condition) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } + + __R_CONDITIONAL_METHOD(bool, Log_GetLastErrorIfFalse)(__R_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT + { + if (!condition) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_GetLastErrorIfNull)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(void, Log_GetLastErrorIfNull)(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + } + + __R_CONDITIONAL_METHOD(NTSTATUS, Log_IfNtStatusFailed)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT + { + if (FAILED_NTSTATUS(status)) + { + __R_CALL_INTERNAL_METHOD(_Log_NtStatus)(__R_CONDITIONAL_FN_CALL status); + } + return status; + } + + __R_DIRECT_METHOD(HRESULT, Log_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_DIRECT_FN_CALL FailureType::Log, hr, formatString, argList); + return hr; + } + + __R_DIRECT_METHOD(DWORD, Log_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_Win32Msg(__R_DIRECT_FN_CALL FailureType::Log, err, formatString, argList); + return err; + } + + __R_DIRECT_METHOD(DWORD, Log_GetLastErrorMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + return wil::details::ReportFailure_GetLastErrorMsg(__R_DIRECT_FN_CALL FailureType::Log, formatString, argList); + } + + __R_DIRECT_METHOD(NTSTATUS, Log_NtStatusMsg)(__R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatusMsg(__R_DIRECT_FN_CALL FailureType::Log, status, formatString, argList); + return status; + } + + __R_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL FailureType::Log, hr, formatString, argList); + } + + __R_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_GetLastErrorMsg(__R_INTERNAL_NOINLINE_FN_CALL FailureType::Log, formatString, argList); + } + + __R_INTERNAL_NOINLINE_METHOD(_Log_Win32Msg)(__R_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_Win32Msg(__R_INTERNAL_NOINLINE_FN_CALL FailureType::Log, err, formatString, argList); + } + + __R_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL FailureType::Log, E_OUTOFMEMORY, formatString, argList); + } + + __R_INTERNAL_NOINLINE_METHOD(_Log_NtStatusMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatusMsg(__R_INTERNAL_NOINLINE_FN_CALL FailureType::Log, status, formatString, argList); + } + + __R_CONDITIONAL_NOINLINE_METHOD(HRESULT, Log_IfFailedMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (FAILED(hr)) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return hr; + } + + __R_CONDITIONAL_NOINLINE_METHOD(BOOL, Log_IfWin32BoolFalseMsg)(__R_CONDITIONAL_FN_PARAMS BOOL ret, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (!ret) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return ret; + } + + __R_CONDITIONAL_NOINLINE_METHOD(DWORD, Log_IfWin32ErrorMsg)(__R_CONDITIONAL_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (FAILED_WIN32(err)) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_Win32Msg)(__R_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList); + } + return err; + } + + __R_CONDITIONAL_NOINLINE_METHOD(HANDLE, Log_IfHandleInvalidMsg)(__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (handle == INVALID_HANDLE_VALUE) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return handle; + } + + __R_CONDITIONAL_NOINLINE_METHOD(HANDLE, Log_IfHandleNullMsg)(__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (handle == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return handle; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(PointerT, Log_IfNullAllocMsg)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Log_IfNullAllocMsg)(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + } + } + + __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_HrIfMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return condition; + } + + __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_HrIfFalseMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return condition; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(PointerT, Log_HrIfNullMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Log_HrIfNullMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + } + + __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_GetLastErrorIfMsg)(__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_GetLastErrorIfFalseMsg)(__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(PointerT, Log_GetLastErrorIfNullMsg)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Log_GetLastErrorIfNullMsg)(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + } + + __R_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, Log_IfNtStatusFailedMsg)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (FAILED_NTSTATUS(status)) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NtStatusMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList); + } + return status; + } + } // namespace __R_NS_NAME + + namespace __RFF_NS_NAME + { + //***************************************************************************** + // FailFast Macros + //***************************************************************************** + + __RFF_DIRECT_NORET_METHOD(void, FailFast_Hr)(__RFF_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Hr(__RFF_DIRECT_FN_CALL FailureType::FailFast, hr); + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_Win32)(__RFF_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Win32(__RFF_DIRECT_FN_CALL FailureType::FailFast, err); + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_GetLastError)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_GetLastError(__RFF_DIRECT_FN_CALL FailureType::FailFast); + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_NtStatus)(__RFF_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_NtStatus(__RFF_DIRECT_FN_CALL FailureType::FailFast, status); + } + + __RFF_INTERNAL_NORET_METHOD(_FailFast_Hr)(__RFF_INTERNAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Hr(__RFF_INTERNAL_FN_CALL FailureType::FailFast, hr); + } + + __RFF_INTERNAL_NORET_METHOD(_FailFast_GetLastError)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_GetLastError(__RFF_INTERNAL_FN_CALL FailureType::FailFast); + } + + __RFF_INTERNAL_NORET_METHOD(_FailFast_Win32)(__RFF_INTERNAL_FN_PARAMS DWORD err) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Win32(__RFF_INTERNAL_FN_CALL FailureType::FailFast, err); + } + + __RFF_INTERNAL_NORET_METHOD(_FailFast_NullAlloc)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Hr(__RFF_INTERNAL_FN_CALL FailureType::FailFast, E_OUTOFMEMORY); + } + + __RFF_INTERNAL_NORET_METHOD(_FailFast_NtStatus)(__RFF_INTERNAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_NtStatus(__RFF_INTERNAL_FN_CALL FailureType::FailFast, status); + } + + __RFF_CONDITIONAL_METHOD(HRESULT, FailFast_IfFailed)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT + { + if (FAILED(hr)) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); + } + return hr; + } + + __RFF_CONDITIONAL_METHOD(BOOL, FailFast_IfWin32BoolFalse)(__RFF_CONDITIONAL_FN_PARAMS BOOL ret) WI_NOEXCEPT + { + if (!ret) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return ret; + } + + __RFF_CONDITIONAL_METHOD(DWORD, FailFast_IfWin32Error)(__RFF_CONDITIONAL_FN_PARAMS DWORD err) WI_NOEXCEPT + { + if (FAILED_WIN32(err)) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Win32)(__RFF_CONDITIONAL_FN_CALL err); + } + return err; + } + + __RFF_CONDITIONAL_METHOD(HANDLE, FailFast_IfHandleInvalid)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle) WI_NOEXCEPT + { + if (handle == INVALID_HANDLE_VALUE) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return handle; + } + + __RFF_CONDITIONAL_METHOD(RESULT_NORETURN_NULL HANDLE, FailFast_IfHandleNull)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle) WI_NOEXCEPT + { + if (handle == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return handle; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNullAlloc)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_NullAlloc)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL void, FailFast_IfNullAlloc)(__RFF_CONDITIONAL_FN_PARAMS const PointerT& pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_NullAlloc)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + } + + __RFF_CONDITIONAL_METHOD(bool, FailFast_HrIf)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT + { + if (condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); + } + return condition; + } + + __RFF_CONDITIONAL_METHOD(bool, FailFast_HrIfFalse)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT + { + if (!condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); + } + return condition; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_HrIfNull)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); + } + return pointer; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL void, FailFast_HrIfNull)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); + } + } + + __RFF_CONDITIONAL_METHOD(bool, FailFast_GetLastErrorIf)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT + { + if (condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } + + __RFF_CONDITIONAL_METHOD(bool, FailFast_GetLastErrorIfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT + { + if (!condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_GetLastErrorIfNull)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL void, FailFast_GetLastErrorIfNull)(__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + } + + __RFF_CONDITIONAL_METHOD(NTSTATUS, FailFast_IfNtStatusFailed)(__RFF_CONDITIONAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT + { + if (FAILED_NTSTATUS(status)) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_NtStatus)(__RFF_CONDITIONAL_FN_CALL status); + } + return status; + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_HrMsg)(__RFF_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __RFF_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__RFF_DIRECT_FN_CALL FailureType::FailFast, hr, formatString, argList); + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_Win32Msg)(__RFF_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __RFF_FN_LOCALS; + wil::details::ReportFailure_Win32Msg(__RFF_DIRECT_FN_CALL FailureType::FailFast, err, formatString, argList); + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_GetLastErrorMsg)(__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __RFF_FN_LOCALS; + wil::details::ReportFailure_GetLastErrorMsg(__RFF_DIRECT_FN_CALL FailureType::FailFast, formatString, argList); + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_NtStatusMsg)(__RFF_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __RFF_FN_LOCALS; + wil::details::ReportFailure_NtStatusMsg(__RFF_DIRECT_FN_CALL FailureType::FailFast, status, formatString, argList); + } + + __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_HrMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__RFF_INTERNAL_NOINLINE_FN_CALL FailureType::FailFast, hr, formatString, argList); + } + + __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_GetLastErrorMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_GetLastErrorMsg(__RFF_INTERNAL_NOINLINE_FN_CALL FailureType::FailFast, formatString, argList); + } + + __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_Win32Msg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Win32Msg(__RFF_INTERNAL_NOINLINE_FN_CALL FailureType::FailFast, err, formatString, argList); + } + + __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_NullAllocMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__RFF_INTERNAL_NOINLINE_FN_CALL FailureType::FailFast, E_OUTOFMEMORY, formatString, argList); + } + + __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_NtStatusMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_NtStatusMsg(__RFF_INTERNAL_NOINLINE_FN_CALL FailureType::FailFast, status, formatString, argList); + } + + __RFF_CONDITIONAL_NOINLINE_METHOD(HRESULT, FailFast_IfFailedMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (FAILED(hr)) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return hr; + } + + __RFF_CONDITIONAL_NOINLINE_METHOD(BOOL, FailFast_IfWin32BoolFalseMsg)(__RFF_CONDITIONAL_FN_PARAMS BOOL ret, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (!ret) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return ret; + } + + __RFF_CONDITIONAL_NOINLINE_METHOD(DWORD, FailFast_IfWin32ErrorMsg)(__RFF_CONDITIONAL_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (FAILED_WIN32(err)) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_Win32Msg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList); + } + return err; + } + + __RFF_CONDITIONAL_NOINLINE_METHOD(HANDLE, FailFast_IfHandleInvalidMsg)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (handle == INVALID_HANDLE_VALUE) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return handle; + } + + __RFF_CONDITIONAL_NOINLINE_METHOD(RESULT_NORETURN_NULL HANDLE, FailFast_IfHandleNullMsg)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (handle == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return handle; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNullAllocMsg)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NullAllocMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + } + return pointer; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL void, FailFast_IfNullAllocMsg)(__RFF_CONDITIONAL_FN_PARAMS const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NullAllocMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + } + } + + __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_HrIfMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (condition) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return condition; + } + + __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_HrIfFalseMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return condition; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_HrIfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return pointer; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL void, FailFast_HrIfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + } + + __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_GetLastErrorIfMsg)(__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (condition) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_GetLastErrorIfFalseMsg)(__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_GetLastErrorIfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return pointer; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL void, FailFast_GetLastErrorIfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + } + + __RFF_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, FailFast_IfNtStatusFailedMsg)(__RFF_CONDITIONAL_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (FAILED_NTSTATUS(status)) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NtStatusMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList); + } + return status; + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_Unexpected)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Hr(__RFF_DIRECT_FN_CALL FailureType::FailFast, E_UNEXPECTED); + } + + __RFF_INTERNAL_NORET_METHOD(_FailFast_Unexpected)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Hr(__RFF_INTERNAL_FN_CALL FailureType::FailFast, E_UNEXPECTED); + } + + __RFF_CONDITIONAL_METHOD(bool, FailFast_If)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT + { + if (condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } + + __RFF_CONDITIONAL_METHOD(bool, FailFast_IfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT + { + if (!condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNull)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL void, FailFast_IfNull)(__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_UnexpectedMsg)(__RFF_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __RFF_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__RFF_DIRECT_FN_CALL FailureType::FailFast, E_UNEXPECTED, formatString, argList); + } + + __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_UnexpectedMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__RFF_INTERNAL_NOINLINE_FN_CALL FailureType::FailFast, E_UNEXPECTED, formatString, argList); + } + + __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_IfMsg)(__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (condition) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_IfFalseMsg)(__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return pointer; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL void, FailFast_IfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + } + + //***************************************************************************** + // FailFast Immediate Macros + //***************************************************************************** + + __RFF_DIRECT_NORET_METHOD(void, FailFastImmediate_Unexpected)() WI_NOEXCEPT + { + RESULT_RAISE_FAST_FAIL_EXCEPTION; + } + + __RFF_INTERNAL_NORET_METHOD(_FailFastImmediate_Unexpected)() WI_NOEXCEPT + { + RESULT_RAISE_FAST_FAIL_EXCEPTION; + } + + __RFF_CONDITIONAL_METHOD(HRESULT, FailFastImmediate_IfFailed)(HRESULT hr) WI_NOEXCEPT + { + if (FAILED(hr)) + { + __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); + } + return hr; + } + + __RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_If)(bool condition) WI_NOEXCEPT + { + if (condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); + } + return condition; + } + + __RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_IfFalse)(bool condition) WI_NOEXCEPT + { + if (!condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); + } + return condition; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFastImmediate_IfNull)(_Pre_maybenull_ PointerT pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); + } + return pointer; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL void, FailFastImmediate_IfNull)(_In_opt_ const PointerT& pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); + } + } + + __RFF_CONDITIONAL_METHOD(NTSTATUS, FailFastImmediate_IfNtStatusFailed)(NTSTATUS status) WI_NOEXCEPT + { + if (FAILED_NTSTATUS(status)) + { + __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); + } + return status; + } + } // namespace __RFF_NS_NAME + + namespace __R_NS_NAME + { + //***************************************************************************** + // Exception Macros + //***************************************************************************** + +#ifdef WIL_ENABLE_EXCEPTIONS + __R_DIRECT_NORET_METHOD(void, Throw_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) + { + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_DIRECT_FN_CALL FailureType::Exception, hr); + } + + __R_DIRECT_NORET_METHOD(void, Throw_Win32)(__R_DIRECT_FN_PARAMS DWORD err) + { + __R_FN_LOCALS; + wil::details::ReportFailure_Win32(__R_DIRECT_FN_CALL FailureType::Exception, err); + } + + __R_DIRECT_NORET_METHOD(void, Throw_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) + { + __R_FN_LOCALS; + wil::details::ReportFailure_GetLastError(__R_DIRECT_FN_CALL FailureType::Exception); + } + + __R_DIRECT_NORET_METHOD(void, Throw_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) + { + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatus(__R_DIRECT_FN_CALL FailureType::Exception, status); + } + + __R_INTERNAL_NORET_METHOD(_Throw_Hr)(__R_INTERNAL_FN_PARAMS HRESULT hr) + { + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL FailureType::Exception, hr); + } + + __R_INTERNAL_NORET_METHOD(_Throw_GetLastError)(__R_INTERNAL_FN_PARAMS_ONLY) + { + __R_FN_LOCALS; + wil::details::ReportFailure_GetLastError(__R_INTERNAL_FN_CALL FailureType::Exception); + } + + __R_INTERNAL_NORET_METHOD(_Throw_Win32)(__R_INTERNAL_FN_PARAMS DWORD err) + { + __R_FN_LOCALS; + wil::details::ReportFailure_Win32(__R_INTERNAL_FN_CALL FailureType::Exception, err); + } + + __R_INTERNAL_NORET_METHOD(_Throw_NullAlloc)(__R_INTERNAL_FN_PARAMS_ONLY) + { + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL FailureType::Exception, E_OUTOFMEMORY); + } + + __R_INTERNAL_NORET_METHOD(_Throw_NtStatus)(__R_INTERNAL_FN_PARAMS NTSTATUS status) + { + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatus(__R_INTERNAL_FN_CALL FailureType::Exception, status); + } + + __R_CONDITIONAL_METHOD(HRESULT, Throw_IfFailed)(__R_CONDITIONAL_FN_PARAMS HRESULT hr) + { + if (FAILED(hr)) + { + __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return hr; + } + + __R_CONDITIONAL_METHOD(BOOL, Throw_IfWin32BoolFalse)(__R_CONDITIONAL_FN_PARAMS BOOL ret) + { + if (!ret) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return ret; + } + + __R_CONDITIONAL_METHOD(DWORD, Throw_IfWin32Error)(__R_CONDITIONAL_FN_PARAMS DWORD err) + { + if (FAILED_WIN32(err)) + { + __R_CALL_INTERNAL_METHOD(_Throw_Win32)(__R_CONDITIONAL_FN_CALL err); + } + return err; + } + + __R_CONDITIONAL_METHOD(HANDLE, Throw_IfHandleInvalid)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) + { + if (handle == INVALID_HANDLE_VALUE) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return handle; + } + + __R_CONDITIONAL_METHOD(RESULT_NORETURN_NULL HANDLE, Throw_IfHandleNull)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) + { + if (handle == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return handle; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(void, Throw_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer) + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY); + } + } + + __R_CONDITIONAL_METHOD(bool, Throw_HrIf)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) + { + if (condition) + { + __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return condition; + } + + __R_CONDITIONAL_METHOD(bool, Throw_HrIfFalse)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) + { + if (!condition) + { + __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return condition; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer) + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(void, Throw_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer) + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + } + + __R_CONDITIONAL_METHOD(bool, Throw_GetLastErrorIf)(__R_CONDITIONAL_FN_PARAMS bool condition) + { + if (condition) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } + + __R_CONDITIONAL_METHOD(bool, Throw_GetLastErrorIfFalse)(__R_CONDITIONAL_FN_PARAMS bool condition) + { + if (!condition) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_GetLastErrorIfNull)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL void, Throw_GetLastErrorIfNull)(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer) + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + } + + __R_CONDITIONAL_METHOD(NTSTATUS, Throw_IfNtStatusFailed)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status) + { + if (FAILED_NTSTATUS(status)) + { + __R_CALL_INTERNAL_METHOD(_Throw_NtStatus)(__R_CONDITIONAL_FN_CALL status); + } + return status; + } + + __R_DIRECT_METHOD(void, Throw_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_DIRECT_FN_CALL FailureType::Exception, hr, formatString, argList); + } + + __R_DIRECT_METHOD(void, Throw_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_Win32Msg(__R_DIRECT_FN_CALL FailureType::Exception, err, formatString, argList); + } + + __R_DIRECT_METHOD(void, Throw_GetLastErrorMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_GetLastErrorMsg(__R_DIRECT_FN_CALL FailureType::Exception, formatString, argList); + } + + __R_DIRECT_METHOD(void, Throw_NtStatusMsg)(__R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatusMsg(__R_DIRECT_FN_CALL FailureType::Exception, status, formatString, argList); + } + + __R_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) + { + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL FailureType::Exception, hr, formatString, argList); + } + + __R_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) + { + __R_FN_LOCALS; + wil::details::ReportFailure_GetLastErrorMsg(__R_INTERNAL_NOINLINE_FN_CALL FailureType::Exception, formatString, argList); + } + + __R_INTERNAL_NOINLINE_METHOD(_Throw_Win32Msg)(__R_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) + { + __R_FN_LOCALS; + wil::details::ReportFailure_Win32Msg(__R_INTERNAL_NOINLINE_FN_CALL FailureType::Exception, err, formatString, argList); + } + + __R_INTERNAL_NOINLINE_METHOD(_Throw_NullAllocMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) + { + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL FailureType::Exception, E_OUTOFMEMORY, formatString, argList); + } + + __R_INTERNAL_NOINLINE_METHOD(_Throw_NtStatusMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) + { + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatusMsg(__R_INTERNAL_NOINLINE_FN_CALL FailureType::Exception, status, formatString, argList); + } + + __R_CONDITIONAL_NOINLINE_METHOD(HRESULT, Throw_IfFailedMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) + { + if (FAILED(hr)) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return hr; + } + + __R_CONDITIONAL_NOINLINE_METHOD(BOOL, Throw_IfWin32BoolFalseMsg)(__R_CONDITIONAL_FN_PARAMS BOOL ret, _Printf_format_string_ PCSTR formatString, ...) + { + if (!ret) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return ret; + } + + __R_CONDITIONAL_NOINLINE_METHOD(DWORD, Throw_IfWin32ErrorMsg)(__R_CONDITIONAL_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) + { + if (FAILED_WIN32(err)) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_Win32Msg)(__R_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList); + } + return err; + } + + __R_CONDITIONAL_NOINLINE_METHOD(HANDLE, Throw_IfHandleInvalidMsg)(__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) + { + if (handle == INVALID_HANDLE_VALUE) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return handle; + } + + __R_CONDITIONAL_NOINLINE_METHOD(RESULT_NORETURN_NULL HANDLE, Throw_IfHandleNullMsg)(__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) + { + if (handle == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return handle; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_IfNullAllocMsg)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NullAllocMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL void, Throw_IfNullAllocMsg)(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NullAllocMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + } + } + + __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_HrIfMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) + { + if (condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return condition; + } + + __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_HrIfFalseMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) + { + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return condition; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_HrIfNullMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Throw_HrIfNullMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + } + + __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_GetLastErrorIfMsg)(__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) + { + if (condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_GetLastErrorIfFalseMsg)(__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) + { + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_GetLastErrorIfNullMsg)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL void, Throw_GetLastErrorIfNullMsg)(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + } + + __R_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, Throw_IfNtStatusFailedMsg)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) + { + if (FAILED_NTSTATUS(status)) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NtStatusMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList); + } + return status; + } +#endif // WIL_ENABLE_EXCEPTIONS + + } // __R_NS_NAME namespace + } // details namespace + //! @endcond + + //***************************************************************************** + // Error Handling Policies to switch between error-handling style + //***************************************************************************** + // The following policies are used as template policies for components that can support exception, fail-fast, and + // error-code based modes. + + // Use for classes which should return HRESULTs as their error-handling policy + struct err_returncode_policy + { + typedef HRESULT result; + + __forceinline static HRESULT Win32BOOL(BOOL fReturn) { RETURN_IF_WIN32_BOOL_FALSE(fReturn); return S_OK; } + __forceinline static HRESULT Win32Handle(HANDLE h, _Out_ HANDLE *ph) { *ph = h; RETURN_IF_HANDLE_NULL(h); return S_OK; } + _Post_satisfies_(return == hr) + __forceinline static HRESULT HResult(HRESULT hr) { RETURN_HR(hr); } + __forceinline static HRESULT LastError() { RETURN_LAST_ERROR(); } + __forceinline static HRESULT LastErrorIfFalse(bool condition) { if (!condition) { RETURN_LAST_ERROR(); } return S_OK; } + _Post_satisfies_(return == S_OK) + __forceinline static HRESULT OK() { return S_OK; } + }; + + // Use for classes which fail-fast on errors + struct err_failfast_policy + { + typedef _Return_type_success_(true) void result; + __forceinline static result Win32BOOL(BOOL fReturn) { FAIL_FAST_IF_WIN32_BOOL_FALSE(fReturn); } + __forceinline static result Win32Handle(HANDLE h, _Out_ HANDLE *ph) { *ph = h; FAIL_FAST_IF_HANDLE_NULL(h); } + _When_(FAILED(hr), _Analysis_noreturn_) + __forceinline static result HResult(HRESULT hr) { FAIL_FAST_IF_FAILED(hr); } + __forceinline static result LastError() { FAIL_FAST_LAST_ERROR(); } + __forceinline static result LastErrorIfFalse(bool condition) { if (!condition) { FAIL_FAST_LAST_ERROR(); } } + __forceinline static result OK() {} + }; + +#ifdef WIL_ENABLE_EXCEPTIONS + // Use for classes which should return through exceptions as their error-handling policy + struct err_exception_policy + { + typedef _Return_type_success_(true) void result; + __forceinline static result Win32BOOL(BOOL fReturn) { THROW_IF_WIN32_BOOL_FALSE(fReturn); } + __forceinline static result Win32Handle(HANDLE h, _Out_ HANDLE *ph) { *ph = h; THROW_IF_HANDLE_NULL(h); } + _When_(FAILED(hr), _Analysis_noreturn_) + __forceinline static result HResult(HRESULT hr) { THROW_IF_FAILED(hr); } + __forceinline static result LastError() { THROW_LAST_ERROR(); } + __forceinline static result LastErrorIfFalse(bool condition) { if (!condition) { THROW_LAST_ERROR(); } } + __forceinline static result OK() {} + }; +#endif + +} // namespace wil + +#pragma warning(pop) diff --git a/Frameworks/include/wil/wistd_type_traits.h b/Frameworks/include/wil/wistd_type_traits.h new file mode 100644 index 0000000000..b3c9350583 --- /dev/null +++ b/Frameworks/include/wil/wistd_type_traits.h @@ -0,0 +1,23 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** +#pragma once + +#include + +// Have to use throw() as wil won't yet compile with noexcept +#define WI_NOEXCEPT throw() + +namespace wistd = std; diff --git a/Frameworks/limbo/NSObject_NSFoundation.mm b/Frameworks/limbo/NSObject_NSFoundation.mm index 69c451a2b3..cdcfff1f9b 100644 --- a/Frameworks/limbo/NSObject_NSFoundation.mm +++ b/Frameworks/limbo/NSObject_NSFoundation.mm @@ -214,13 +214,8 @@ static bool trySetViaAccessor(NSObject* self, const char* key, id value) { const char* valueType = [sig getArgumentTypeAtIndex:2]; std::vector data(getArgumentSize(valueType)); - if (valueType[0] == '@') { // Method is expecting an object: give it the object directly - memcpy(data.data(), &value, sizeof(id)); - } else if (valueType[0] == '*' || valueType[0] == '^' || valueType[0] == '?') { - // We can't box or unbox char* or arbitrary pointers. + if (!woc::dataWithTypeFromValue(data.data(), valueType, value)) { return false; - } else if ([value isKindOfClass:[NSValue class]]) { - [static_cast(value) getValue:data.data()]; } [invocation setTarget:self]; @@ -243,68 +238,12 @@ static bool trySetViaIvar(NSObject* self, const char* key, id value) { const char* argType = curIvar->type; void* destination = reinterpret_cast(self) + offset; - switch (argType[0]) { - case '@': - [*reinterpret_cast(destination) release]; - woc::ValueTransformer::store(value, destination); - break; - case '#': - woc::ValueTransformer::store(value, destination); - break; - case 'c': - woc::ValueTransformer::store(value, destination); - break; - case 'i': - woc::ValueTransformer::store(value, destination); - break; - case 's': - woc::ValueTransformer::store(value, destination); - break; - case 'l': - woc::ValueTransformer::store(value, destination); - break; - case 'q': - woc::ValueTransformer::store(value, destination); - break; - case 'C': - woc::ValueTransformer::store(value, destination); - break; - case 'I': - woc::ValueTransformer::store(value, destination); - break; - case 'S': - woc::ValueTransformer::store(value, destination); - break; - case 'L': - woc::ValueTransformer::store(value, destination); - break; - case 'Q': - woc::ValueTransformer::store(value, destination); - break; - case 'f': - woc::ValueTransformer::store(value, destination); - break; - case 'd': - woc::ValueTransformer::store(value, destination); - break; - case 'B': - woc::ValueTransformer::store(value, destination); - break; - case '*': - case '^': - case '?': - // We cannot box/unbox arbitrary pointers or char*. - return false; - default: - NSValue* nsv = static_cast(value); - if (getArgumentSize(argType) == getArgumentSize([nsv objCType])) { - [nsv getValue:destination]; - } else { - // If the argument types don't match in size, we just say - // that this key can't be coded. - return false; - } - break; + if (!woc::dataWithTypeFromValue(destination, argType, value)) { + return false; + } + if (argType[0] == '@') { + // retain object-type ivar, old value is _not_ released (iOS/OS X behavior) + [*reinterpret_cast(destination) retain]; } return true; @@ -343,6 +282,24 @@ - (void)setValue:(id)val forKey:(NSString*)key { [self setValue:val forUndefinedKey:key]; } +/** + @Status Interoperable +*/ +- (void)setValue:(id)value forKeyPath:(NSString*)path { + std::string keyPath([path UTF8String]); + + auto pointPosition = keyPath.find('.'); + if (pointPosition == std::string::npos && keyPath.find('@') == std::string::npos) { + [self setValue:value forKey:path]; + return; + } + + std::string keyComponent(keyPath, 0, pointPosition); + + id subValue = [self valueForKey:[NSString stringWithUTF8String:keyComponent.c_str()]]; + [subValue setValue:value forKeyPath:[NSString stringWithUTF8String:keyPath.c_str() + pointPosition + 1]]; +} + /** @Status Interoperable @Notes These throw exceptions. That's what they're supposed to do. diff --git a/Frameworks/limbo/NSString.mm b/Frameworks/limbo/NSString.mm index b43df707a7..64d5557b3b 100644 --- a/Frameworks/limbo/NSString.mm +++ b/Frameworks/limbo/NSString.mm @@ -2438,7 +2438,7 @@ - (NSString*)stringByExpandingTildeInPath { @Status Interoperable */ - (NSString*)stringByStandardizingPath { - NSArray* components = [self componentsSeparatedByString:@"/"]; + NSMutableArray* components = [NSMutableArray arrayWithArray: [self componentsSeparatedByString:@"/"]]; int componentsCount = [components count]; int lastComponentLen = 0; diff --git a/Frameworks/limbo/PlatformSupport.cpp b/Frameworks/limbo/PlatformSupport.cpp index e1c191bcc2..0441ec874a 100644 --- a/Frameworks/limbo/PlatformSupport.cpp +++ b/Frameworks/limbo/PlatformSupport.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "Platform/EbrPlatform.h" #include "Starboard.h" @@ -849,8 +850,9 @@ bool EbrGetRootMapping(const char* dirName, char* dirOut, uint32_t maxLen) { mkdir(dirOut); return true; } - if (_stricmp(dirName, "C:") == 0) { - sprintf_s(dirOut, maxLen, "C:"); + static std::regex drive("[a-zA-Z]:"); + if (std::regex_match(dirName, drive)) { + sprintf_s(dirOut, maxLen, dirName); return true; } sprintf_s(dirOut, maxLen, FSROOT "\\%s", dirName); @@ -884,7 +886,8 @@ int EbrChdir(const char* path) { return 0; } -extern "C" __declspec(dllexport) void dbg_printf(const char* fmt, ...) { +IWPLATFORM_EXPORT +void dbg_printf(const char* fmt, ...) { #ifdef _DEBUG va_list va; diff --git a/Frameworks/limbo/Stubs.mm b/Frameworks/limbo/Stubs.mm index cbd1fe4c3a..01ec65742a 100644 --- a/Frameworks/limbo/Stubs.mm +++ b/Frameworks/limbo/Stubs.mm @@ -234,29 +234,47 @@ void EbrHideKeyboard(void) { @implementation SLComposeViewController @end +/** +@Status Stub +*/ __declspec(dllexport) extern "C" mach_port_t mach_host_self(void) { + UNIMPLEMENTED(); return (mach_port_t)0xBAADF00D; } +/** +@Status Stub +*/ __declspec(dllexport) extern "C" int host_page_size(mach_port_t port, vm_size_t* sizeOut) { + UNIMPLEMENTED(); return 65536; } int vm_page_size = 65536; +/** +@Status Stub +*/ __declspec(dllexport) extern "C" int host_statistics(mach_port_t port, int type, host_info_t dataOut, mach_msg_type_number_t* dataOutSize) { - assert(type == HOST_VM_INFO); - assert(*dataOutSize >= sizeof(vm_statistics)); - *dataOutSize = sizeof(vm_statistics); + if (type == HOST_VM_INFO && *dataOutSize >= sizeof(vm_statistics)) { + *dataOutSize = sizeof(vm_statistics); - vm_statistics* ret = (vm_statistics*)dataOut; - memset(ret, 0, sizeof(vm_statistics)); + vm_statistics* ret = (vm_statistics*)dataOut; + memset(ret, 0, sizeof(vm_statistics)); + + ret->free_count = 512 * 1024 * 1024 / 65536; + } + else { + UNIMPLEMENTED(); + } - ret->free_count = 512 * 1024 * 1024 / 65536; return 0; } +/** +@Status Stub +*/ __declspec(dllexport) extern "C" const char* strnstr(const char* a, const char* b, int len) { - assert(0); + UNIMPLEMENTED(); return NULL; } diff --git a/Frameworks/objcrt/error-handling.cpp b/Frameworks/objcrt/error-handling.cpp new file mode 100644 index 0000000000..a123bcfcdb --- /dev/null +++ b/Frameworks/objcrt/error-handling.cpp @@ -0,0 +1,64 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#include "error-handling.h" +#include + +OBJCRT_EXPORT extern unsigned long objc_getCurrentThreadId() { + return ::GetCurrentThreadId(); +} + +OBJCRT_EXPORT extern long objc_interlockedIncrementNoFence(long volatile* addend) { + return ::InterlockedIncrementNoFence(addend); +} + +OBJCRT_EXPORT extern unsigned long objc_getLastError() { + return ::GetLastError(); +} + +OBJCRT_EXPORT extern void objc_copyMemory(void* destination, const void* source, size_t length) { + ::CopyMemory(destination, source, length); +} + +OBJCRT_EXPORT extern void objc_zeroMemory(void* destination, size_t length) { + ::ZeroMemory(destination, length); +} + +OBJCRT_EXPORT extern unsigned long objc_formatMessageW(unsigned long flags, const void* source, unsigned long messageId, unsigned long languageId, wchar_t* buffer, unsigned long size, va_list* arguments) { + return ::FormatMessageW(flags, source, messageId, languageId, buffer, size, arguments); +} + +OBJCRT_EXPORT extern void objc_outputDebugStringW(wchar_t* outputString) { + return ::OutputDebugStringW(outputString); +} + +OBJCRT_EXPORT extern long objc_interlockedDecrementRelease(long volatile* addend) { + return ::InterlockedDecrementRelease(addend); +} + +OBJCRT_EXPORT extern void* objc_interlockedCompareExchangePointer(void* volatile* destination, void* exchange, void* comparand) { + return ::InterlockedCompareExchangePointer(destination, exchange, comparand); +} + +// These two are temporary, since they're supposed to be intrinsics. When our compiler supports them correct they will be removed: + +OBJCRT_EXPORT extern "C" void* _ReturnAddress() { + return nullptr; +} + +OBJCRT_EXPORT extern "C" void __fastfail(unsigned) { + RaiseFailFastException(nullptr, nullptr, 0); +} diff --git a/Frameworks/objcrt/error-handling.h b/Frameworks/objcrt/error-handling.h new file mode 100644 index 0000000000..47a5f9617a --- /dev/null +++ b/Frameworks/objcrt/error-handling.h @@ -0,0 +1,31 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** +#include + +#ifndef OBJCRT_EXPORT +#define OBJCRT_EXPORT +#endif + +// Error-handling exports +OBJCRT_EXPORT extern unsigned long objc_getCurrentThreadId(); +OBJCRT_EXPORT extern long objc_interlockedIncrementNoFence(long volatile* addend); +OBJCRT_EXPORT extern unsigned long objc_getLastError(); +OBJCRT_EXPORT extern void objc_copyMemory(void* destination, const void* source, size_t length); +OBJCRT_EXPORT extern void objc_zeroMemory(void* destination, size_t length); +OBJCRT_EXPORT extern unsigned long objc_formatMessageW(unsigned long flags, const void* source, unsigned long messageId, unsigned long languageId, wchar_t* buffer, unsigned long size, va_list* arguments); +OBJCRT_EXPORT extern void objc_outputDebugStringW(wchar_t* outputString); +OBJCRT_EXPORT extern long objc_interlockedDecrementRelease(long volatile* addend); +OBJCRT_EXPORT extern void* objc_interlockedCompareExchangePointer(void* volatile* destination, void* exchange, void* comparand); diff --git a/Frameworks/objcrt/lookup.c b/Frameworks/objcrt/lookup.c index 1e96ece8b3..7a06c36c17 100644 --- a/Frameworks/objcrt/lookup.c +++ b/Frameworks/objcrt/lookup.c @@ -27,6 +27,10 @@ IMP (*objc_forward_handler)(id, SEL) = NULL; +static id nil_method(id self, SEL _cmd) { + return nil; +} + IMP objc_not_found_handler(id obj, SEL sel) { BOOL is_class = object_getClass(obj)->info & OBJC_CLASS_INFO_METACLASS; @@ -57,11 +61,20 @@ IMP objc_not_found_handler(id obj, SEL sel) { if (objc_forward_handler != NULL) return objc_forward_handler(obj, sel); +// TODO: Switch to a runtime-configurable setting +#ifdef OBJC_APP_BRINGUP + char buffer[1024] = { 0 }; + sprintf_s(buffer, sizeof(buffer), "*******Class [%s]: method [%s]: not implemented*******\r\n", object_getClassName(obj), sel_getName(sel)); + OutputDebugStringA(buffer); + + return (IMP)nil_method; +#else OBJC_NOT_IMPLEMENTED_ERROR("Selector %c[%s] is not implemented for class %s on object 0x%x!", (is_class ? '+' : '-'), sel_getName(sel), object_getClassName(obj), obj); +#endif } BOOL class_respondsToSelector(Class cls, SEL sel) { @@ -72,9 +85,6 @@ BOOL class_respondsToSelector(Class cls, SEL sel) { } #ifndef OF_ASM_LOOKUP -static id nil_method(id self, SEL _cmd) { - return nil; -} OBJCRT_EXPORT IMP objc_msg_lookup(id obj, SEL sel) { IMP imp; diff --git a/bin/Xib2Nib.exe b/bin/Xib2Nib.exe index 61147c9502..fd80ade67f 100644 Binary files a/bin/Xib2Nib.exe and b/bin/Xib2Nib.exe differ diff --git a/bin/vsimporter.exe b/bin/vsimporter.exe index ebe31e2132..fd04ba89ec 100644 Binary files a/bin/vsimporter.exe and b/bin/vsimporter.exe differ diff --git a/build/Foundation/Foundation.Shared/Foundation.Shared.vcxitems b/build/Foundation/Foundation.Shared/Foundation.Shared.vcxitems index f8f444ef71..58c4560948 100644 --- a/build/Foundation/Foundation.Shared/Foundation.Shared.vcxitems +++ b/build/Foundation/Foundation.Shared/Foundation.Shared.vcxitems @@ -135,6 +135,8 @@ + + diff --git a/build/Foundation/Foundation.Shared/Foundation.def b/build/Foundation/Foundation.Shared/Foundation.def index ba36ed90bf..6026430e09 100644 --- a/build/Foundation/Foundation.Shared/Foundation.def +++ b/build/Foundation/Foundation.Shared/Foundation.def @@ -180,5 +180,5 @@ LIBRARY Foundation __objc_class_name_CTTelephonyNetworkInfo CONSTANT _OBJC_CLASS_NSManagedObjectContext DATA __objc_class_name_NSManagedObjectContext CONSTANT - - \ No newline at end of file + _OBJC_CLASS_NSAssertionHandler DATA + __objc_class_name_NSAssertionHandler CONSTANT \ No newline at end of file diff --git a/build/GLKit/GLKit.Windows/GLKit.Windows.vcxproj b/build/GLKit/GLKit.Windows/GLKit.Windows.vcxproj index c634d27829..fe64cb8b09 100644 --- a/build/GLKit/GLKit.Windows/GLKit.Windows.vcxproj +++ b/build/GLKit/GLKit.Windows/GLKit.Windows.vcxproj @@ -151,7 +151,7 @@ Console false false - UIKit.lib;Foundation.lib;QuartzCore.lib;CoreFoundation.lib;CoreGraphics.lib;OpenGLES.lib;ObjCUWP.lib;kernel32.lib;%(AdditionalDependencies) + Starboard.lib;UIKit.lib;Foundation.lib;QuartzCore.lib;CoreFoundation.lib;CoreGraphics.lib;OpenGLES.lib;ObjCUWP.lib;kernel32.lib;%(AdditionalDependencies) $(AdditionalLibraryDirectories);$(StarboardLibDirs);$(StarboardPrebuiltLibsDir);$(StarboardSdkRoot)\build\Win32\$(Configuration)\$(TargetOsAndVersion);$(StarboardSdkRoot)\deps\prebuilt\$(TargetOsAndVersion)\$(PlatformTarget) ..\GLKit.Shared\GLKit.def /ignore:4087 @@ -176,7 +176,7 @@ Console false false - UIKit.lib;Foundation.lib;QuartzCore.lib;CoreFoundation.lib;CoreGraphics.lib;OpenGLES.lib;ObjCUWP.lib;kernel32.lib;%(AdditionalDependencies) + Starboard.lib;UIKit.lib;Foundation.lib;QuartzCore.lib;CoreFoundation.lib;CoreGraphics.lib;OpenGLES.lib;ObjCUWP.lib;kernel32.lib;%(AdditionalDependencies) $(AdditionalLibraryDirectories);$(StarboardLibDirs);$(StarboardPrebuiltLibsDir);$(StarboardSdkRoot)\build\Win32\$(Configuration)\$(TargetOsAndVersion);$(StarboardSdkRoot)\deps\prebuilt\$(TargetOsAndVersion)\$(PlatformTarget) ..\GLKit.Shared\GLKit.def /ignore:4087 diff --git a/build/GLKit/GLKit.WindowsPhone/GLKit.WindowsPhone.vcxproj b/build/GLKit/GLKit.WindowsPhone/GLKit.WindowsPhone.vcxproj index 1c7899b17a..e9500b96e2 100644 --- a/build/GLKit/GLKit.WindowsPhone/GLKit.WindowsPhone.vcxproj +++ b/build/GLKit/GLKit.WindowsPhone/GLKit.WindowsPhone.vcxproj @@ -1,4 +1,4 @@ - + @@ -114,7 +114,7 @@ Console false false - UIKit.lib;Foundation.lib;QuartzCore.lib;CoreFoundation.lib;CoreGraphics.lib;OpenGLES.lib;ObjCUWP.lib;%(AdditionalDependencies) + Starboard.lib;UIKit.lib;Foundation.lib;QuartzCore.lib;CoreFoundation.lib;CoreGraphics.lib;OpenGLES.lib;ObjCUWP.lib;%(AdditionalDependencies) $(AdditionalLibraryDirectories);$(StarboardLibDirs);$(StarboardPrebuiltLibsDir);$(StarboardSdkRoot)\build\Win32\$(Configuration)\$(TargetOsAndVersion);$(StarboardSdkRoot)\deps\prebuilt\$(TargetOsAndVersion)\$(PlatformTarget) ..\GLKit.Shared\GLKit.def /ignore:4087 @@ -138,7 +138,7 @@ Console false false - UIKit.lib;Foundation.lib;QuartzCore.lib;CoreFoundation.lib;CoreGraphics.lib;OpenGLES.lib;ObjCUWP.lib;%(AdditionalDependencies) + Starboard.lib;UIKit.lib;Foundation.lib;QuartzCore.lib;CoreFoundation.lib;CoreGraphics.lib;OpenGLES.lib;ObjCUWP.lib;%(AdditionalDependencies) $(AdditionalLibraryDirectories);$(StarboardLibDirs);$(StarboardPrebuiltLibsDir);$(StarboardSdkRoot)\build\Win32\$(Configuration)\$(TargetOsAndVersion);$(StarboardSdkRoot)\deps\prebuilt\$(TargetOsAndVersion)\$(PlatformTarget) /ignore:4087 ..\GLKit.Shared\GLKit.def @@ -191,4 +191,4 @@ - + \ No newline at end of file diff --git a/build/Headers/Headers.Shared/Internal.Shared.vcxitems b/build/Headers/Headers.Shared/Internal.Shared.vcxitems index 79da77a62d..54759b1d7a 100644 --- a/build/Headers/Headers.Shared/Internal.Shared.vcxitems +++ b/build/Headers/Headers.Shared/Internal.Shared.vcxitems @@ -17,4 +17,7 @@ + + + diff --git a/build/UIKit/UIKit.Shared/UIKit.Shared.vcxitems b/build/UIKit/UIKit.Shared/UIKit.Shared.vcxitems index 9879d1048f..aed4adbc93 100644 --- a/build/UIKit/UIKit.Shared/UIKit.Shared.vcxitems +++ b/build/UIKit/UIKit.Shared/UIKit.Shared.vcxitems @@ -33,6 +33,7 @@ + @@ -85,6 +86,8 @@ + + @@ -156,4 +159,4 @@ - \ No newline at end of file + diff --git a/build/UIKit/UIKit.Shared/UIKit.def b/build/UIKit/UIKit.Shared/UIKit.def index 149e6994be..6ec7ef4c1e 100644 --- a/build/UIKit/UIKit.Shared/UIKit.def +++ b/build/UIKit/UIKit.Shared/UIKit.def @@ -168,3 +168,30 @@ LIBRARY UIKit __objc_class_name_UIManagedDocument CONSTANT _OBJC_CLASS_UIDocument DATA __objc_class_name_UIDocument CONSTANT + _OBJC_CLASS_UIAccessibilityElement DATA + __objc_class_name_UIAccessibilityElement CONSTANT + + UIAccessibilityPostNotification + UIAccessibilityIsVoiceOverRunning + + UIAccessibilityTraitNone + UIAccessibilityTraitButton + UIAccessibilityTraitLink + UIAccessibilityTraitSearchField + UIAccessibilityTraitImage + UIAccessibilityTraitSelected + UIAccessibilityTraitPlaysSound + UIAccessibilityTraitKeyboardKey + UIAccessibilityTraitStaticText + UIAccessibilityTraitSummaryElement + UIAccessibilityTraitNotEnabled + UIAccessibilityTraitUpdatesFrequently + UIAccessibilityTraitStartsMediaSession + UIAccessibilityTraitAdjustable + UIAccessibilityTraitAllowsDirectInteraction + UIAccessibilityTraitCausesPageTurn + UIAccessibilityTraitHeader + UIAccessibilityScreenChangedNotification + UIAccessibilityLayoutChangedNotification + UIAccessibilityAnnouncementNotification + UIAccessibilityPageScrolledNotification diff --git a/build/UnitTests/UnitTests.vcxproj b/build/UnitTests/UnitTests.vcxproj index ff541b2745..35e9bc982b 100644 --- a/build/UnitTests/UnitTests.vcxproj +++ b/build/UnitTests/UnitTests.vcxproj @@ -192,10 +192,12 @@ + + @@ -205,6 +207,7 @@ + @@ -226,6 +229,7 @@ + @@ -257,7 +261,7 @@ true true true - Text + Text diff --git a/build/build.sln b/build/build.sln index f3efc76b18..6675fc0738 100644 --- a/build/build.sln +++ b/build/build.sln @@ -241,12 +241,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GLKit.Universal", "GLKit\GL EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GLKit.Windows", "GLKit\GLKit.Windows\GLKit.Windows.vcxproj", "{AA0C8E83-62D3-4E3C-98A5-6A25077474D2}" ProjectSection(ProjectDependencies) = postProject + {D9BBA177-5624-43BF-ACE5-CC68949598E4} = {D9BBA177-5624-43BF-ACE5-CC68949598E4} {D4B2AB87-EC16-4D9C-98D5-2EBB69C72370} = {D4B2AB87-EC16-4D9C-98D5-2EBB69C72370} {B3177BAC-2E11-4EF2-976B-2B8B4632FA4A} = {B3177BAC-2E11-4EF2-976B-2B8B4632FA4A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GLKit.WindowsPhone", "GLKit\GLKit.WindowsPhone\GLKit.WindowsPhone.vcxproj", "{71596D8A-C60B-46A3-953C-E667A5EEB077}" ProjectSection(ProjectDependencies) = postProject + {43E56B50-92CC-46D9-B951-2B51F89BE279} = {43E56B50-92CC-46D9-B951-2B51F89BE279} {124DEDF4-7DC3-4D56-96D8-85D509B73DD0} = {124DEDF4-7DC3-4D56-96D8-85D509B73DD0} {2F8CABF5-55C0-4B80-9050-078EFAD20CB8} = {2F8CABF5-55C0-4B80-9050-078EFAD20CB8} EndProjectSection @@ -264,12 +266,12 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests", "UnitTests\UnitTests.vcxproj", "{2AFE3907-6239-49E0-80B3-56BCFCECE9E1}" ProjectSection(ProjectDependencies) = postProject {ED0F4033-106A-432D-818F-B2AE6A251BE9} = {ED0F4033-106A-432D-818F-B2AE6A251BE9} + {EE65195F-8B43-4B9D-B0C0-DA54166EF6F1} = {EE65195F-8B43-4B9D-B0C0-DA54166EF6F1} {D9BBA177-5624-43BF-ACE5-CC68949598E4} = {D9BBA177-5624-43BF-ACE5-CC68949598E4} {AA0C8E83-62D3-4E3C-98A5-6A25077474D2} = {AA0C8E83-62D3-4E3C-98A5-6A25077474D2} {23350084-036D-41C9-837C-2874B3426D8E} = {23350084-036D-41C9-837C-2874B3426D8E} {B3177BAC-2E11-4EF2-976B-2B8B4632FA4A} = {B3177BAC-2E11-4EF2-976B-2B8B4632FA4A} {6FF5CFD7-3E46-4182-9F76-C315F69B6C13} = {6FF5CFD7-3E46-4182-9F76-C315F69B6C13} - {EE65195F-8B43-4B9D-B0C0-DA54166EF6F1} = {EE65195F-8B43-4B9D-B0C0-DA54166EF6F1} EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Headers", "Headers", "{6A9F9F79-A657-47B0-B41C-A48B6A06308C}" diff --git a/build/objcrt/objcrt.Shared/objcrt.Shared.vcxitems b/build/objcrt/objcrt.Shared/objcrt.Shared.vcxitems index 11da5a68a3..bb3abb965a 100644 --- a/build/objcrt/objcrt.Shared/objcrt.Shared.vcxitems +++ b/build/objcrt/objcrt.Shared/objcrt.Shared.vcxitems @@ -34,6 +34,7 @@ + true diff --git a/include/Foundation/NSArray.h b/include/Foundation/NSArray.h index 225d0617d2..09cad2e677 100644 --- a/include/Foundation/NSArray.h +++ b/include/Foundation/NSArray.h @@ -102,8 +102,6 @@ FOUNDATION_EXPORT_CLASS - (void)enumerateObjectsAtIndexes: (NSIndexSet*)range options: (NSEnumerationOptions)opts usingBlock:(void (^)(id object, NSUInteger index, BOOL *stop))block; - (NSUInteger)indexOfObject:(id)obj inSortedRange:(NSRange)r options:(NSBinarySearchingOptions)opts usingComparator:(NSComparator)cmp; -- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject; -- (void)setObject:(id)anObject atIndexedSubscript:(NSUInteger)index; - (void)sortWithOptions:(NSSortOptions)opts usingComparator:(NSComparator)cmptr; diff --git a/include/Foundation/NSAssertionHandler.h b/include/Foundation/NSAssertionHandler.h index 3d21463e0a..41c25786f5 100644 --- a/include/Foundation/NSAssertionHandler.h +++ b/include/Foundation/NSAssertionHandler.h @@ -1,10 +1,17 @@ /* Copyright (c) 2008 John Engelhart -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, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +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, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -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. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +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. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#pragma once #import @@ -12,41 +19,67 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #define _NSAssertBody(condition, desc, ...) #define _NSCAssertBody(condition, desc, ...) #else // NS_BLOCK_ASSERTIONS not defined -#define _NSAssertBody(condition, desc, ...) do { if (!(condition)) { [[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd object:self file:[NSString stringWithUTF8String:__FILE__] lineNumber:__LINE__ description:(desc), ##__VA_ARGS__]; } } while(0) -#define _NSCAssertBody(condition, desc, ...) do { if (!(condition)) { [[NSAssertionHandler currentHandler] handleFailureInFunction:[NSString stringWithUTF8String:__PRETTY_FUNCTION__] file:[NSString stringWithUTF8String:__FILE__] lineNumber:__LINE__ description:(desc), ##__VA_ARGS__]; } } while(0) +#define _NSAssertBody(condition, desc, ...) \ + do { \ + if (!(condition)) { \ + [[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \ + object:self \ + file:[NSString stringWithUTF8String:__FILE__] \ + lineNumber:__LINE__ \ + description:(desc), ##__VA_ARGS__]; \ + } \ + } while (0) +#define _NSCAssertBody(condition, desc, ...) \ + do { \ + if (!(condition)) { \ + [[NSAssertionHandler currentHandler] handleFailureInFunction:[NSString stringWithUTF8String:__PRETTY_FUNCTION__] \ + file:[NSString stringWithUTF8String:__FILE__] \ + lineNumber:__LINE__ \ + description:(desc), ##__VA_ARGS__]; \ + } \ + } while (0) #endif // NS_BLOCK_ASSERTIONS /* * Asserts to use in Objective-C methods: */ -#define NSAssert(condition, desc, ...) _NSAssertBody((condition), (desc), #condition, ##__VA_ARGS__) -#define NSAssert1(condition, desc, val1) NSAssert(condition, desc, val1) -#define NSAssert2(condition, desc, val1, val2) NSAssert(condition, desc, val1, val2) -#define NSAssert3(condition, desc, val1, val2, val3) NSAssert(condition, desc, val1, val2, val3) -#define NSAssert4(condition, desc, val1, val2, val3, val4) NSAssert(condition, desc, val1, val2, val3, val4) -#define NSAssert5(condition, desc, val1, val2, val3, val4, val5) NSAssert(condition, desc, val1, val2, val3, val4, val5) +#define NSAssert(condition, desc, ...) _NSAssertBody((condition), (desc), #condition, ##__VA_ARGS__) +#define NSAssert1(condition, desc, val1) NSAssert(condition, desc, val1) +#define NSAssert2(condition, desc, val1, val2) NSAssert(condition, desc, val1, val2) +#define NSAssert3(condition, desc, val1, val2, val3) NSAssert(condition, desc, val1, val2, val3) +#define NSAssert4(condition, desc, val1, val2, val3, val4) NSAssert(condition, desc, val1, val2, val3, val4) +#define NSAssert5(condition, desc, val1, val2, val3, val4, val5) NSAssert(condition, desc, val1, val2, val3, val4, val5) -#define NSParameterAssert(condition) _NSAssertBody((condition), @"Invalid parameter not satisfying: %s", #condition) +#define NSParameterAssert(condition) _NSAssertBody((condition), @"Invalid parameter not satisfying: %s", #condition) /* * Asserts to use in C function calls: */ -#define NSCAssert(condition, desc, ...) _NSCAssertBody((condition), (desc), #condition, ##__VA_ARGS__) -#define NSCAssert1(condition, desc, val1) NSCAssert(condition, desc, val1) -#define NSCAssert2(condition, desc, val1, val2) NSCAssert(condition, desc, val1, val2) -#define NSCAssert3(condition, desc, val1, val2, val3) NSCAssert(condition, desc, val1, val2, val3) -#define NSCAssert4(condition, desc, val1, val2, val3, val4) NSCAssert(condition, desc, val1, val2, val3, val4) -#define NSCAssert5(condition, desc, val1, val2, val3, val4, val5) NSCAssert(condition, desc, val1, val2, val3, val4, val5) +#define NSCAssert(condition, desc, ...) _NSCAssertBody((condition), (desc), #condition, ##__VA_ARGS__) +#define NSCAssert1(condition, desc, val1) NSCAssert(condition, desc, val1) +#define NSCAssert2(condition, desc, val1, val2) NSCAssert(condition, desc, val1, val2) +#define NSCAssert3(condition, desc, val1, val2, val3) NSCAssert(condition, desc, val1, val2, val3) +#define NSCAssert4(condition, desc, val1, val2, val3, val4) NSCAssert(condition, desc, val1, val2, val3, val4) +#define NSCAssert5(condition, desc, val1, val2, val3, val4, val5) NSCAssert(condition, desc, val1, val2, val3, val4, val5) -#define NSCParameterAssert(condition) _NSCAssertBody((condition), @"Invalid parameter not satisfying: %s", #condition) +#define NSCParameterAssert(condition) _NSCAssertBody((condition), @"Invalid parameter not satisfying: %s", #condition) + +FOUNDATION_EXPORT const NSString* NSAssertionHandlerKey; FOUNDATION_EXPORT_CLASS @interface NSAssertionHandler : NSObject -+ (NSAssertionHandler *)currentHandler; -- (void)handleFailureInMethod:(SEL)selector object:(id)object file:(NSString *)fileName lineNumber:(NSInteger)line description:(NSString *)format,...; -- (void)handleFailureInFunction:(NSString *)functionName file:(NSString *)fileName lineNumber:(NSInteger)line description:(NSString *)format,...; ++ (NSAssertionHandler*)currentHandler; +- (void)handleFailureInMethod:(SEL)selector + object:(id)object + file:(NSString*)fileName + lineNumber:(NSInteger)line + description:(NSString*)format, ...; +- (void)handleFailureInFunction:(NSString*)functionName + file:(NSString*)fileName + lineNumber:(NSInteger)line + description:(NSString*)format, ...; @end diff --git a/include/Foundation/NSBundle.h b/include/Foundation/NSBundle.h index 838f4b4ac2..e330b56491 100644 --- a/include/Foundation/NSBundle.h +++ b/include/Foundation/NSBundle.h @@ -50,7 +50,7 @@ FOUNDATION_EXPORT_CLASS + (NSArray*)preferredLocalizationsFromArray:(NSArray*)localizations forPreferences:(NSArray*)preferences; - initWithPath:(NSString*)path; - +- initWithUrl:(NSURL*)url; - (NSString*)bundlePath; - (NSString*)resourcePath; - (NSURL*)bundleURL; diff --git a/include/Foundation/NSDirectoryEnumerator.h b/include/Foundation/NSDirectoryEnumerator.h index 2cdae823b5..f1b471a6df 100644 --- a/include/Foundation/NSDirectoryEnumerator.h +++ b/include/Foundation/NSDirectoryEnumerator.h @@ -1,17 +1,30 @@ /* Copyright (c) 2006-2007 Christopher J. W. Lloyd -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, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +Copyright (c) 2015 Microsoft Corporation. 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, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -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. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +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. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #import @class NSDictionary; @interface NSDirectoryEnumerator : NSEnumerator --(void)skipDescendents; --(void)skipDescendants; --(NSDictionary *)directoryAttributes; --(NSDictionary *)fileAttributes; + +@property (readonly, copy) NSDictionary* directoryAttributes; +@property (readonly, copy) NSDictionary* fileAttributes; +@property (readonly) NSUInteger level; + +// only spelling difference for these two messages +- (void)skipDescendents; +- (void)skipDescendants; + @end diff --git a/include/Foundation/NSFileManager.h b/include/Foundation/NSFileManager.h index c85049bd84..c90364e00a 100644 --- a/include/Foundation/NSFileManager.h +++ b/include/Foundation/NSFileManager.h @@ -22,141 +22,249 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #import #import -@class NSData, NSDate, NSError; +@class NSData, NSDate, NSError, NSFileManager; -enum { - NSDirectoryEnumerationSkipsSubdirectoryDescendants = 1L << 0, - NSDirectoryEnumerationSkipsPackageDescendants = 1L << 1, - NSDirectoryEnumerationSkipsHiddenFiles = 1L << 2 -}; -typedef uint32_t NSDirectoryEnumerationOptions; -SB_EXPORT NSString* const NSFileType; -SB_EXPORT NSString* const NSFileTypeRegular; -SB_EXPORT NSString* const NSFileTypeDirectory; -SB_EXPORT NSString* const NSFileTypeSymbolicLink; +@protocol NSFileManagerDelegate +@optional -SB_EXPORT NSString* const NSFileTypeCharacterSpecial; -SB_EXPORT NSString* const NSFileTypeBlockSpecial; -SB_EXPORT NSString* const NSFileTypeFIFO; +// Moving an Item +- (BOOL)fileManager:(NSFileManager*)fileManager shouldMoveItemAtURL:(NSURL*)srcURL toURL:(NSURL*)dstURL; +- (BOOL)fileManager:(NSFileManager*)fileManager shouldMoveItemAtPath:(NSString*)path toPath:(NSString*)toPath; +- (BOOL)fileManager:(NSFileManager*)fileManager shouldProceedAfterError:(NSError*)error movingItemAtURL:(NSURL*)srcURL toURL:(NSURL*)dstURL; +- (BOOL)fileManager:(NSFileManager*)fileManager + shouldProceedAfterError:(NSError*)error + movingItemAtPath:(NSString*)path + toPath:(NSString*)toPath; -SB_EXPORT NSString* const NSFileTypeSocket; +// Copying an Item +- (BOOL)fileManager:(NSFileManager*)fileManager shouldCopyItemAtURL:(NSURL*)srcURL toURL:(NSURL*)dstURL; +- (BOOL)fileManager:(NSFileManager*)fileManager shouldCopyItemAtPath:(NSString*)srcPath toPath:(NSString*)dstPath; +- (BOOL)fileManager:(NSFileManager*)fileManager + shouldProceedAfterError:(NSError*)error + copyingItemAtURL:(NSURL*)srcURL + toURL:(NSURL*)dstURL; +- (BOOL)fileManager:(NSFileManager*)fileManager + shouldProceedAfterError:(NSError*)error + copyingItemAtPath:(NSString*)srcPath + toPath:(NSString*)dstPath; -SB_EXPORT NSString* const NSFileTypeUnknown; +// Removing an Item +- (BOOL)fileManager:(NSFileManager*)fileManager shouldRemoveItemAtURL:(NSURL*)URL; +- (BOOL)fileManager:(NSFileManager*)fileManager shouldRemoveItemAtPath:(NSString*)path; +- (BOOL)fileManager:(NSFileManager*)fileManager shouldProceedAfterError:(NSError*)error removingItemAtURL:(NSURL*)URL; +- (BOOL)fileManager:(NSFileManager*)fileManager shouldProceedAfterError:(NSError*)error removingItemAtPath:(NSString*)path; -SB_EXPORT NSString* const NSFileSize; -SB_EXPORT NSString* const NSFileCreationDate; -SB_EXPORT NSString* const NSFileModificationDate; -SB_EXPORT NSString* const NSFileOwnerAccountName; -SB_EXPORT NSString* const NSFileGroupOwnerAccountName; +// Linking an Item +- (BOOL)fileManager:(NSFileManager*)fileManager shouldLinkItemAtURL:(NSURL*)srcURL toURL:(NSURL*)dstURL; +- (BOOL)fileManager:(NSFileManager*)fileManager shouldLinkItemAtPath:(NSString*)srcPath toPath:(NSString*)dstPath; +- (BOOL)fileManager:(NSFileManager*)fileManager + shouldProceedAfterError:(NSError*)error + linkingItemAtURL:(NSURL*)srcURL + toURL:(NSURL*)dstURL; +- (BOOL)fileManager:(NSFileManager*)fileManager + shouldProceedAfterError:(NSError*)error + linkingItemAtPath:(NSString*)srcPath + toPath:(NSString*)dstPath; +@end -SB_EXPORT NSString* const NSFilePosixPermissions; -SB_EXPORT NSString* const NSFileReferenceCount; -SB_EXPORT NSString* const NSFileIdentifier; -SB_EXPORT NSString* const NSFileDeviceIdentifier; +typedef NS_ENUM(NSUInteger, NSVolumeEnumerationOptions) { + NSVolumeEnumerationSkipHiddenVolumes = 1L << 1, + NSVolumeEnumerationProduceFileReferenceURLs = 1L << 2 +}; -SB_EXPORT NSString* const NSFileSystemNumber; -SB_EXPORT NSString* const NSFileSystemSize; -SB_EXPORT NSString* const NSFileSystemFreeSize; +typedef NS_ENUM(NSUInteger, NSDirectoryEnumerationOptions) { + NSDirectoryEnumerationSkipsSubdirectoryDescendants = 1L << 0, + NSDirectoryEnumerationSkipsPackageDescendants = 1L << 1, + NSDirectoryEnumerationSkipsHiddenFiles = 1L << 2 +}; + +typedef NS_ENUM(NSUInteger, NSFileManagerItemReplacementOptions) { + NSFileManagerItemReplacementUsingNewMetadataOnly = 1UL << 0, + NSFileManagerItemReplacementWithoutDeletingBackupItem = 1UL << 1 +}; + +typedef NS_ENUM(NSInteger, NSURLRelationship) { NSURLRelationshipContains, NSURLRelationshipSame, NSURLRelationshipOther }; + +// file attribute keys +FOUNDATION_EXPORT NSString* const NSFileType; +FOUNDATION_EXPORT NSString* const NSFileSize; +FOUNDATION_EXPORT NSString* const NSFileModificationDate; +FOUNDATION_EXPORT NSString* const NSFileReferenceCount; +FOUNDATION_EXPORT NSString* const NSFileDeviceIdentifier; +FOUNDATION_EXPORT NSString* const NSFileOwnerAccountName; +FOUNDATION_EXPORT NSString* const NSFileGroupOwnerAccountName; +FOUNDATION_EXPORT NSString* const NSFilePosixPermissions; +FOUNDATION_EXPORT NSString* const NSFileSystemNumber; +FOUNDATION_EXPORT NSString* const NSFileSystemFileNumber; +FOUNDATION_EXPORT NSString* const NSFileExtensionHidden; +FOUNDATION_EXPORT NSString* const NSFileHFSCreatorCode; +FOUNDATION_EXPORT NSString* const NSFileHFSTypeCode; +FOUNDATION_EXPORT NSString* const NSFileImmutable; +FOUNDATION_EXPORT NSString* const NSFileAppendOnly; +FOUNDATION_EXPORT NSString* const NSFileCreationDate; +FOUNDATION_EXPORT NSString* const NSFileOwnerAccountID; +FOUNDATION_EXPORT NSString* const NSFileGroupOwnerAccountID; +FOUNDATION_EXPORT NSString* const NSFileBusy; + +FOUNDATION_EXPORT NSString* const NSFileProtectionKey; + +// NSFileType Attribute Values +FOUNDATION_EXPORT NSString* const NSFileTypeDirectory; +FOUNDATION_EXPORT NSString* const NSFileTypeRegular; +FOUNDATION_EXPORT NSString* const NSFileTypeSymbolicLink; +FOUNDATION_EXPORT NSString* const NSFileTypeSocket; +FOUNDATION_EXPORT NSString* const NSFileTypeCharacterSpecial; +FOUNDATION_EXPORT NSString* const NSFileTypeBlockSpecial; +FOUNDATION_EXPORT NSString* const NSFileTypeUnknown; + +// File-System attribute Keys +FOUNDATION_EXPORT NSString* const NSFileSystemSize; +FOUNDATION_EXPORT NSString* const NSFileSystemFreeSize; +FOUNDATION_EXPORT NSString* const NSFileSystemNodes; +FOUNDATION_EXPORT NSString* const NSFileSystemFreeNodes; + +// File Protection Values +FOUNDATION_EXPORT NSString* const NSFileProtectionNone; +FOUNDATION_EXPORT NSString* const NSFileProtectionComplete; +FOUNDATION_EXPORT NSString* const NSFileProtectionCompleteUnlessOpen; +FOUNDATION_EXPORT NSString* const NSFileProtectionCompleteUntilFirstUserAuthentication; FOUNDATION_EXPORT_CLASS @interface NSFileManager : NSObject +// Creating a File Manager + (NSFileManager*)defaultManager; +- (instancetype)init; -- delegate; -- (void)setDelegate:delegate; - -- (NSDictionary*)attributesOfFileSystemForPath:(NSString*)path error:(NSError**)errorp; -- (NSDictionary*)attributesOfItemAtPath:(NSString*)path error:(NSError**)error; -- (BOOL)changeCurrentDirectoryPath:(NSString*)path; -- (NSArray*)componentsToDisplayForPath:(NSString*)path; -- (BOOL)contentsEqualAtPath:(NSString*)path1 andPath:(NSString*)path2; -- (NSArray*)contentsOfDirectoryAtPath:(NSString*)path error:(NSError**)error; -- (BOOL)copyItemAtPath:(NSString*)fromPath toPath:(NSString*)toPath error:(NSError**)error; -- (NSString*)destinationOfSymbolicLinkAtPath:(NSString*)path error:(NSError**)error; - -- (NSString*)displayNameAtPath:(NSString*)path; - -- (NSDictionary*)fileSystemAttributesAtPath:(NSString*)path; - -- (BOOL)isDeletableFileAtPath:(NSString*)path; - -- (BOOL)linkItemAtPath:(NSString*)fromPath toPath:(NSString*)toPath error:(NSError**)error; -- (BOOL)linkPath:(NSString*)source toPath:(NSString*)destination handler:handler; -- (BOOL)moveItemAtPath:(NSString*)fromPath toPath:(NSString*)toPath error:(NSError**)error; -- (BOOL)removeItemAtPath:(NSString*)path error:(NSError**)error; - -- (BOOL)setAttributes:(NSDictionary*)attributes ofItemAtPath:(NSString*)path error:(NSError**)error; - -- (NSString*)stringWithFileSystemRepresentation:(const char*)string length:(NSUInteger)length; - -- (NSArray*)subpathsAtPath:(NSString*)path; -- (NSArray*)subpathsOfDirectoryAtPath:(NSString*)path error:(NSError**)error; - -- (NSData*)contentsAtPath:(NSString*)path; +// Locating System Directories +- (NSURL*)URLForDirectory:(NSSearchPathDirectory)directory + inDomain:(NSSearchPathDomainMask)domain + appropriateForURL:(NSURL*)url + create:(BOOL)shouldCreate + error:(NSError**)error; +- (NSArray*)URLsForDirectory:(NSSearchPathDirectory)directory inDomains:(NSSearchPathDomainMask)domainMask; -- (BOOL)createFileAtPath:(NSString*)path contents:(NSData*)data attributes:(NSDictionary*)attributes; +// Locating Application Group Container Directories +- (NSURL*)containerURLForSecurityApplicationGroupIdentifier:(NSString*)groupIdentifier; -- (NSArray*)directoryContentsAtPath:(NSString*)path; +// Discovering Directory Contents +- (NSArray*)contentsOfDirectoryAtURL:(NSURL*)url + includingPropertiesForKeys:(NSArray*)keys + options:(NSDirectoryEnumerationOptions)mask + error:(NSError**)error; +- (NSArray*)contentsOfDirectoryAtPath:(NSString*)path error:(NSError**)error; +- (NSDirectoryEnumerator*)enumeratorAtURL:(NSURL*)url + includingPropertiesForKeys:(NSArray*)keys + options:(NSDirectoryEnumerationOptions)mask + errorHandler:(BOOL (^)(NSURL* url, NSError* error))handler; - (NSDirectoryEnumerator*)enumeratorAtPath:(NSString*)path; +- (NSArray**)mountedVolumeURLsIncludingResourceValuesForKeys:(NSArray**)propertyKeys options:(NSVolumeEnumerationOptions)options; +- (NSArray*)subpathsOfDirectoryAtPath:(NSString*)path error:(NSError**)error; +- (NSArray*)subpathsAtPath:(NSString*)path; -- (BOOL)createDirectoryAtPath:(NSString*)path attributes:(NSDictionary*)attributes; +// Creating and Deleting Items +- (BOOL)createDirectoryAtURL:(NSURL*)url + withIntermediateDirectories:(BOOL)createIntermediates + attributes:(NSDictionary*)attributes + error:(NSError**)error; - (BOOL)createDirectoryAtPath:(NSString*)path withIntermediateDirectories:(BOOL)intermediates attributes:(NSDictionary*)attributes error:(NSError**)error; +- (BOOL)createFileAtPath:(NSString*)path contents:(NSData*)data attributes:(NSDictionary*)attributes; +- (BOOL)removeItemAtURL:(NSURL*)URL error:(NSError**)error; +- (BOOL)replaceItemAtURL:(NSURL*)originalItemURL + withItemAtURL:(NSURL*)newItemURL + backupItemName:(NSString*)backupItemName + options:(NSFileManagerItemReplacementOptions)options + resultingItemURL:(NSURL**)resultingURL + error:(NSError**)error; +- (BOOL)trashItemAtURL:(NSURL*)url resultingItemURL:(NSURL**)outResultingURL error:(NSError**)error; + +// Moving and Copying Items +- (BOOL)copyItemAtURL:(NSURL*)srcURL toURL:(NSURL*)dstURL error:(NSError**)error; +- (BOOL)copyItemAtPath:(NSString*)fromPath toPath:(NSString*)toPath error:(NSError**)error; +- (BOOL)moveItemAtURL:(NSURL*)srcURL toURL:(NSURL*)dstURL error:(NSError**)error; +- (BOOL)moveItemAtPath:(NSString*)fromPath toPath:(NSString*)toPath error:(NSError**)error; -- (BOOL)createSymbolicLinkAtPath:(NSString*)path pathContent:(NSString*)destination; -- (BOOL)createSymbolicLinkAtPath:(NSString*)path withDestinationPath:(NSString*)toPath error:(NSError**)error; +// Managing iCloud-Based Items +@property (readonly, copy) id ubiquityIdentityToken; -- (NSString*)pathContentOfSymbolicLinkAtPath:(NSString*)path; +- (NSURL*)URLForUbiquityContainerIdentifier:(NSString*)containerID; +- (BOOL)isUbiquitousItemAtURL:(NSURL*)url; +- (BOOL)setUbiquitous:(BOOL)flag itemAtURL:(NSURL*)url destinationURL:(NSURL*)destinationURL error:(NSError**)errorOut; +- (BOOL)setUbiquitous:(BOOL)flag itemAtURL:(NSURL*)url destinationURL:(NSURL*)destinationURL error:(NSError**)errorOut; +- (BOOL)startDownloadingUbiquitousItemAtURL:(NSURL*)url error:(NSError**)errorOut; +- (BOOL)evictUbiquitousItemAtURL:(NSURL*)url error:(NSError**)errorOut; +- (NSURL*)URLForPublishingUbiquitousItemAtURL:(NSURL*)url expirationDate:(NSDate**)outDate error:(NSError**)error; + +// Creating Symbolic and Hard Links +- (BOOL)createSymbolicLinkAtURL:(NSURL*)url withDestinationURL:(NSURL*)destURL error:(NSError**)error; +- (BOOL)createSymbolicLinkAtPath:(NSString*)path withDestinationPath:(NSString*)toPath error:(NSError**)error; +- (BOOL)linkItemAtURL:(NSURL*)srcURL toURL:(NSURL*)dstURL error:(NSError**)error; +- (BOOL)linkItemAtPath:(NSString*)fromPath toPath:(NSString*)toPath error:(NSError**)error; +- (NSString*)destinationOfSymbolicLinkAtPath:(NSString*)path error:(NSError**)error; +// Determining Access to Files - (BOOL)fileExistsAtPath:(NSString*)path; - (BOOL)fileExistsAtPath:(NSString*)path isDirectory:(BOOL*)isDirectory; - -- (BOOL)removeFileAtPath:(NSString*)path handler:handler; - -- (BOOL)movePath:(NSString*)src toPath:(NSString*)dest handler:handler; -- (BOOL)copyPath:(NSString*)src toPath:(NSString*)dest handler:handler; - -- (NSString*)currentDirectoryPath; - -- (NSDictionary*)fileAttributesAtPath:(NSString*)path traverseLink:(BOOL)traverse; - - (BOOL)isReadableFileAtPath:(NSString*)path; - (BOOL)isWritableFileAtPath:(NSString*)path; - (BOOL)isExecutableFileAtPath:(NSString*)path; +- (BOOL)isDeletableFileAtPath:(NSString*)path; -- (BOOL)changeFileAttributes:(NSDictionary*)attributes atPath:(NSString*)path; +// Getting and Setting Attributes +- (NSArray*)componentsToDisplayForPath:(NSString*)path; +- (NSString*)displayNameAtPath:(NSString*)path; +- (NSDictionary*)attributesOfItemAtPath:(NSString*)path error:(NSError**)error; +- (NSDictionary*)attributesOfFileSystemForPath:(NSString*)path error:(NSError**)errorp; +- (BOOL)setAttributes:(NSDictionary*)attributes ofItemAtPath:(NSString*)path error:(NSError**)error; -- (const char*)fileSystemRepresentationWithPath:(NSString*)path; -- (const uint16_t*)fileSystemRepresentationWithPathW:(NSString*)path; +// Getting and Comparing File Contents +- (NSData*)contentsAtPath:(NSString*)path; +- (BOOL)contentsEqualAtPath:(NSString*)path1 andPath:(NSString*)path2; -- (NSArray*)URLsForDirectory:(NSSearchPathDirectory)directory inDomains:(NSSearchPathDomainMask)domainMask; -- (BOOL)createDirectoryAtURL:(NSURL*)url - withIntermediateDirectories:(BOOL)createIntermediates - attributes:(NSDictionary*)attributes - error:(NSError**)error; -- (NSDirectoryEnumerator*)enumeratorAtURL:(NSURL*)url - includingPropertiesForKeys:(NSArray*)keys - options:(NSDirectoryEnumerationOptions)mask - errorHandler:(BOOL (^)(NSURL* url, NSError* error))handler; +// Getting the Relationship Between Items +- (BOOL)getRelationship:(NSURLRelationship*)outRelationship + ofDirectoryAtURL:(NSURL*)directoryURL + toItemAtURL:(NSURL*)otherURL + error:(NSError**)error; -- (NSURL*)URLForUbiquityContainerIdentifier:(NSString*)containerID; -- (NSURL*)URLForDirectory:(NSSearchPathDirectory)directory - inDomain:(NSSearchPathDomainMask)domain - appropriateForURL:(NSURL*)url - create:(BOOL)shouldCreate - error:(NSError**)error; +- (BOOL)getRelationship:(NSURLRelationship*)outRelationship + ofDirectory:(NSSearchPathDirectory)directory + inDomain:(NSSearchPathDomainMask)domainMask + toItemAtURL:(NSURL*)url + error:(NSError**)error; -- (NSArray*)contentsOfDirectoryAtURL:(NSURL*)url - includingPropertiesForKeys:(NSArray*)keys - options:(NSDirectoryEnumerationOptions)mask - error:(NSError**)error; -- (BOOL)moveItemAtURL:(NSURL*)srcURL toURL:(NSURL*)dstURL error:(NSError**)error; -- (BOOL)copyItemAtURL:(NSURL*)srcURL toURL:(NSURL*)dstURL error:(NSError**)error; +// Converting File Paths to Strings +- (const char*)fileSystemRepresentationWithPath:(NSString*)path; +- (NSString*)stringWithFileSystemRepresentation:(const char*)string length:(NSUInteger)length; +// Managing the Delegate +// TODO: using property syntax introudce compiling error +// use existing version for now, will look into this later +// @property (assign) id delegate; +- delegate; +- (void)setDelegate:delegate; + +// Managing the Current Directory +- (BOOL)changeCurrentDirectoryPath:(NSString*)path; +@property (readonly, copy) NSString* currentDirectoryPath; + +// Deprecated Methods +- (BOOL)copyPath:(NSString*)src toPath:(NSString*)dest handler:handler; +- (BOOL)movePath:(NSString*)src toPath:(NSString*)dest handler:handler; +- (BOOL)removeFileAtPath:(NSString*)path handler:handler; +- (BOOL)changeFileAttributes:(NSDictionary*)attributes atPath:(NSString*)path; +- (NSDictionary*)fileAttributesAtPath:(NSString*)path traverseLink:(BOOL)traverse; +- (NSDictionary*)fileSystemAttributesAtPath:(NSString*)path; +- (NSArray*)directoryContentsAtPath:(NSString*)path; +- (BOOL)createDirectoryAtPath:(NSString*)path attributes:(NSDictionary*)attributes; +- (BOOL)createSymbolicLinkAtPath:(NSString*)path pathContent:(NSString*)otherPath; +- (NSString*)pathContentOfSymbolicLinkAtPath:(NSString*)path; +- (BOOL)linkPath:(NSString*)source toPath:(NSString*)destination handler:(id)handler; +- (BOOL)removeItemAtPath:(NSString*)path error:(NSError**)error; @end @interface NSObject (NSFileManager_handler) @@ -164,29 +272,6 @@ FOUNDATION_EXPORT_CLASS - (void)fileManager:(NSFileManager*)fileManager willProcessPath:(NSString*)path; @end -@interface NSObject (NSFileManagerDelegate) -- (BOOL)fileManager:(NSFileManager*)fileManager shouldCopyItemAtPath:(NSString*)path toPath:(NSString*)toPath; -- (BOOL)fileManager:(NSFileManager*)fileManager shouldLinkItemAtPath:(NSString*)path toPath:(NSString*)toPath; -- (BOOL)fileManager:(NSFileManager*)fileManager shouldMoveItemAtPath:(NSString*)path toPath:(NSString*)toPath; -- (BOOL)fileManager:(NSFileManager*)fileManager - shouldProceedAfterError:(NSError*)error - copyingItemAtPath:(NSString*)path - toPath:(NSString*)toPath; -- (BOOL)fileManager:(NSFileManager*)fileManager - shouldProceedAfterError:(NSError*)error - linkingItemAtPath:(NSString*)path - toPath:(NSString*)toPath; -- (BOOL)fileManager:(NSFileManager*)fileManager - shouldProceedAfterError:(NSError*)error - movingItemAtPath:(NSString*)path - toPath:(NSString*)toPath; -- (BOOL)fileManager:(NSFileManager*)fileManager shouldProceedAfterError:(NSError*)error removingItemAtPath:(NSString*)path; - -- (BOOL)fileManager:(NSFileManager*)fileManager shouldRemoveItemAtPath:(NSString*)path; -- (BOOL)removeItemAtURL:(NSURL*)URL error:(NSError**)error; - -@end - @interface NSDictionary (NSFileManager_fileAttributes) - (NSDate*)fileModificationDate; - (NSUInteger)filePosixPermissions; diff --git a/include/Foundation/NSIndexPath.h b/include/Foundation/NSIndexPath.h index 63ee5c1ffc..22e1cd4d01 100644 --- a/include/Foundation/NSIndexPath.h +++ b/include/Foundation/NSIndexPath.h @@ -1,5 +1,8 @@ /* Copyright (c) 2007 Dirk Theisen + Portions Copyright (c) 2015 Microsoft Corporation. All rights reserved. + Portions Copyright (c) 2013 Peter Steinberger. 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, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. @@ -10,25 +13,33 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI FOUNDATION_EXPORT_CLASS @interface NSIndexPath : NSObject { - NSUInteger _length; - NSUInteger *_indexes; + NSUInteger _length; + NSUInteger* _indexes; } -+ (NSIndexPath *)indexPathWithIndex:(NSUInteger)index; -+ (NSIndexPath *)indexPathWithIndexes:(NSUInteger *)indexes length:(NSUInteger)length; ++ (NSIndexPath*)indexPathForRow:(unsigned)row inSection:(unsigned)section; ++ (NSIndexPath*)indexPathForItem:(NSInteger)item inSection:(NSInteger)section; + ++ (NSIndexPath*)indexPathWithIndex:(NSUInteger)index; ++ (NSIndexPath*)indexPathWithIndexes:(NSUInteger*)indexes length:(NSUInteger)length; - (id)initWithIndex:(NSUInteger)index; -- (id)initWithIndexes:(NSUInteger *)indexes length:(NSUInteger)length; // designated initializer +- (id)initWithIndexes:(NSUInteger*)indexes length:(NSUInteger)length; // designated initializer -- (NSIndexPath *)indexPathByAddingIndex:(NSUInteger)index; -- (NSIndexPath *)indexPathByRemovingLastIndex; +- (NSIndexPath*)indexPathByAddingIndex:(NSUInteger)index; +- (NSIndexPath*)indexPathByRemovingLastIndex; - (NSUInteger)indexAtPosition:(NSUInteger)position; - (NSUInteger)length; -- (void)getIndexes:(NSUInteger *)indexes; +- (NSUInteger)row; +- (NSUInteger)item; +- (NSUInteger)section; + +- (void)getIndexes:(NSUInteger*)indexes; - // comparison support -- (NSComparisonResult)compare:(NSIndexPath *)otherObject; // sorting an array of indexPaths using this comparison results in an array representing nodes in depth-first traversal order +// comparison support +- (NSComparisonResult)compare:(NSIndexPath*)otherObject; // sorting an array of indexPaths using this comparison results in an array + // representing nodes in depth-first traversal order @end diff --git a/include/Foundation/NSMutableArray.h b/include/Foundation/NSMutableArray.h index cdebd3e698..a80589550f 100644 --- a/include/Foundation/NSMutableArray.h +++ b/include/Foundation/NSMutableArray.h @@ -47,6 +47,9 @@ FOUNDATION_EXPORT_CLASS -(void)sortUsingComparator:(NSComparator)cmptr; +- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject; +- (void)setObject:(id)anObject atIndexedSubscript:(NSUInteger)index; + @end @interface NSMutableArrayConcrete : NSMutableArray diff --git a/include/Foundation/NSURLConnection.h b/include/Foundation/NSURLConnection.h index 407333bfb3..62cec857cb 100644 --- a/include/Foundation/NSURLConnection.h +++ b/include/Foundation/NSURLConnection.h @@ -39,7 +39,6 @@ FOUNDATION_EXPORT_CLASS id _response; unsigned _storagePolicy; BOOL _didRetain, _didRelease; - id _mutableData; } +(BOOL)canHandleRequest:(NSURLRequest *)request; diff --git a/include/Foundation/NSURLCredentialStorage.h b/include/Foundation/NSURLCredentialStorage.h index 93c632c40d..73c1eed5af 100644 --- a/include/Foundation/NSURLCredentialStorage.h +++ b/include/Foundation/NSURLCredentialStorage.h @@ -1,32 +1,38 @@ /* Copyright (c) 2006-2007 Christopher J. W. Lloyd -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, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +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, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -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. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +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. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _NSURLCREDENTIALSTORAGE_H_ #define _NSURLCREDENTIALSTORAGE_H_ #import -@class NSDictionary,NSURLCredential,NSURLProtectionSpace; +@class NSDictionary, NSURLCredential, NSURLProtectionSpace; -FOUNDATION_EXPORT NSString * const NSURLCredentialStorageChangedNotification; +FOUNDATION_EXPORT NSString* const NSURLCredentialStorageChangedNotification; @interface NSURLCredentialStorage : NSObject { } -+(NSURLCredentialStorage *)sharedCredentialStorage; ++ (NSURLCredentialStorage*)sharedCredentialStorage; --(NSDictionary *)allCredentials; --(NSDictionary *)credentialsForProtectionSpace:(NSURLProtectionSpace *)protectionSpace; --(NSURLCredential *)defaultCredentialForProtectionSpace:(NSURLProtectionSpace *)protectionSpace; +- (NSDictionary*)allCredentials; +- (NSDictionary*)credentialsForProtectionSpace:(NSURLProtectionSpace*)protectionSpace; +- (NSURLCredential*)defaultCredentialForProtectionSpace:(NSURLProtectionSpace*)protectionSpace; --(void)setCredential:(NSURLCredential *)credential forProtectionSpace:(NSURLProtectionSpace *)protectionSpace; --(void)setDefaultCredential:(NSURLCredential *)credential forProtectionSpace:(NSURLProtectionSpace *)protectionSpace; +- (void)setCredential:(NSURLCredential*)credential forProtectionSpace:(NSURLProtectionSpace*)protectionSpace; +- (void)setDefaultCredential:(NSURLCredential*)credential forProtectionSpace:(NSURLProtectionSpace*)protectionSpace; --(void)removeCredential:(NSURLCredential *)credential forProtectionSpace:(NSURLProtectionSpace *)protectionSpace; +- (void)removeCredential:(NSURLCredential*)credential forProtectionSpace:(NSURLProtectionSpace*)protectionSpace; @end diff --git a/include/Foundation/NSURLRequest.h b/include/Foundation/NSURLRequest.h index 34903c54e5..955f0f395b 100644 --- a/include/Foundation/NSURLRequest.h +++ b/include/Foundation/NSURLRequest.h @@ -1,10 +1,16 @@ /* Copyright (c) 2006-2007 Christopher J. W. Lloyd -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, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +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, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -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. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +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. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #import #import @@ -12,7 +18,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI @class NSURL, NSInputStream, NSMutableDictionary; -enum { +typedef NS_ENUM(NSUInteger, NSURLRequestCachePolicy) { NSURLRequestUseProtocolCachePolicy = 0, NSURLRequestReloadIgnoringLocalCacheData = 1, NSURLRequestReloadIgnoringCacheData = 1, @@ -21,33 +27,40 @@ enum { NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4, NSURLRequestReloadRevalidatingCacheData = 5 }; -typedef uint32_t NSURLRequestCachePolicy; + +typedef NS_ENUM(NSUInteger, NSURLRequestNetworkServiceType) { + NSURLNetworkServiceTypeDefault = 0, + NSURLNetworkServiceTypeVoIP = 1, + NSURLNetworkServiceTypeVideo = 2, + NSURLNetworkServiceTypeBackground = 3, + NSURLNetworkServiceTypeVoice = 4 +}; FOUNDATION_EXPORT_CLASS -@interface NSURLRequest : NSObject +@interface NSURLRequest : NSObject --initWithURL:(NSURL *)url; --initWithURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)cachePolicy timeoutInterval:(NSTimeInterval)timeout; +- initWithURL:(NSURL*)url; +- initWithURL:(NSURL*)url cachePolicy:(NSURLRequestCachePolicy)cachePolicy timeoutInterval:(NSTimeInterval)timeout; -+requestWithURL:(NSURL *)url; -+requestWithURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)cachePolicy timeoutInterval:(NSTimeInterval)timeout; ++ requestWithURL:(NSURL*)url; ++ requestWithURL:(NSURL*)url cachePolicy:(NSURLRequestCachePolicy)cachePolicy timeoutInterval:(NSTimeInterval)timeout; --(NSURL *)URL; --(NSURLRequestCachePolicy)cachePolicy; --(NSTimeInterval)timeoutInterval; +- (NSURL*)URL; +- (NSURLRequestCachePolicy)cachePolicy; +- (NSTimeInterval)timeoutInterval; --(NSString *)HTTPMethod; --(NSData *)HTTPBody; --(NSInputStream *)HTTPBodyStream; +- (NSString*)HTTPMethod; +- (NSData*)HTTPBody; +- (NSInputStream*)HTTPBodyStream; --(NSDictionary *)allHTTPHeaderFields; --(NSString *)valueForHTTPHeaderField:(NSString *)field; +- (NSDictionary*)allHTTPHeaderFields; +- (NSString*)valueForHTTPHeaderField:(NSString*)field; --(NSURL *)mainDocumentURL; +- (NSURL*)mainDocumentURL; --(BOOL)HTTPShouldHandleCookies; --(BOOL)HTTPShouldUsePipelining; +- (BOOL)HTTPShouldHandleCookies; +- (BOOL)HTTPShouldUsePipelining; --(BOOL)allowsInvalidSSLCertificate; +- (BOOL)allowsInvalidSSLCertificate; @end diff --git a/include/Foundation/NSURLSession.h b/include/Foundation/NSURLSession.h index 31b5610e39..cac178880e 100644 --- a/include/Foundation/NSURLSession.h +++ b/include/Foundation/NSURLSession.h @@ -19,6 +19,7 @@ #import #import +#import @class NSURLResponse; @class NSURLCache; @@ -63,22 +64,6 @@ FOUNDATION_EXPORT_CLASS @end -FOUNDATION_EXPORT_CLASS -@interface NSURLSessionConfiguration : NSObject - -@property (nonatomic) BOOL allowsCellularAccess; -@property (nonatomic) NSURLCache* URLCache; -@property (nonatomic) NSURLRequestCachePolicy requestCachePolicy; -@property (nonatomic) NSTimeInterval timeoutIntervalForResource; -@property (nonatomic) NSTimeInterval timeoutIntervalForRequest; -@property (nonatomic) NSUInteger HTTPMaximumConnectionsPerHost; - -+ (instancetype)ephemeralSessionConfiguration; -+ (instancetype)defaultSessionConfiguration; -+ (instancetype)backgroundSessionConfiguration:(NSString*)name; - -@end - @class NSURLCredential; @class NSURLAuthenticationChallenge; diff --git a/include/Foundation/NSURLSessionConfiguration.h b/include/Foundation/NSURLSessionConfiguration.h new file mode 100644 index 0000000000..4cc241aec9 --- /dev/null +++ b/include/Foundation/NSURLSessionConfiguration.h @@ -0,0 +1,69 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#import +#import +#import +#import + +@class NSDictionary, NSObject; + +/* SSL Protocol version */ +typedef NS_ENUM(NSUInteger, SSLProtocol) { + kSSLProtocolUnknown = 0, + kSSLProtocol3 = 2, + kTLSProtocol1 = 4, + kTLSProtocol11 = 7, + kTLSProtocol12 = 8, + kDTLSProtocol1 = 9, + + /* DEPRECATED on iOS */ + kSSLProtocol2 = 1, + kSSLProtocol3Only = 3, + kTLSProtocol1Only = 5, + kSSLProtocolAll = 6, +}; + +FOUNDATION_EXPORT_CLASS +@interface NSURLSessionConfiguration : NSObject + ++ (NSURLSessionConfiguration*)defaultSessionConfiguration; ++ (NSURLSessionConfiguration*)ephemeralSessionConfiguration; ++ (NSURLSessionConfiguration*)backgroundSessionConfigurationWithIdentifier:(NSString*)identifier; +// Deprecated, calls into backgroundSessionConfigurationWithIdentifier ++ (NSURLSessionConfiguration *)backgroundSessionConfiguration:(NSString *)identifier; +@property (readonly, copy) NSString* identifier; +@property (copy) NSDictionary* HTTPAdditionalHeaders; +@property NSURLRequestNetworkServiceType networkServiceType; +@property BOOL allowsCellularAccess; +@property NSTimeInterval timeoutIntervalForRequest; +@property NSTimeInterval timeoutIntervalForResource; +@property (copy) NSString* sharedContainerIdentifier; +@property NSHTTPCookieAcceptPolicy HTTPCookieAcceptPolicy; +@property (retain) NSHTTPCookieStorage* HTTPCookieStorage; +@property BOOL HTTPShouldSetCookies; +@property SSLProtocol TLSMaximumSupportedProtocol; +@property SSLProtocol TLSMinimumSupportedProtocol; +@property (retain) NSURLCredentialStorage* URLCredentialStorage; +@property (retain) NSURLCache* URLCache; +@property NSURLRequestCachePolicy requestCachePolicy; +@property BOOL sessionSendsLaunchEvents; +@property (getter=isDiscretionary) BOOL discretionary; +@property (copy) NSArray* protocolClasses; +@property NSInteger HTTPMaximumConnectionsPerHost; +@property BOOL HTTPShouldUsePipelining; +@property (copy) NSDictionary* connectionProxyDictionary; +@end diff --git a/include/QuartzCore/CALayer.h b/include/QuartzCore/CALayer.h index 1c6d03bee3..f8bf27fb1c 100644 --- a/include/QuartzCore/CALayer.h +++ b/include/QuartzCore/CALayer.h @@ -62,8 +62,10 @@ CA_EXPORT NSString* const kCAGravityResizeAspectFill; #if defined(__cplusplus) class CAPrivateInfo; +struct IWAccessibilityInfo; #else typedef void* CAPrivateInfo; +typedef void* IWAccessibilityInfo; #endif CA_EXPORT_CLASS @@ -159,6 +161,12 @@ CA_EXPORT_CLASS + (CGPoint)convertPoint:(CGPoint)point fromLayer:(CALayer*)layer toLayer:(CALayer*)layer; +- (void)updateAccessibilityInfo: (IWAccessibilityInfo*)info; + +- (void)updateAccessibilityInfo: (IWAccessibilityInfo*)info; + +- (void)updateAccessibilityInfo: (IWAccessibilityInfo*)info; + @end @interface NSObject (CALayerDelegate) diff --git a/include/UIKit/UIAccessibility.h b/include/UIKit/UIAccessibility.h index c481687788..aa59693554 100644 --- a/include/UIKit/UIAccessibility.h +++ b/include/UIKit/UIAccessibility.h @@ -30,60 +30,101 @@ */ #import -#import +#import + +@class UIView; +@class UIBezierPath; + +enum _UIAccessibilityNavigationStyle { + UIAccessibilityNavigationStyleAutomatic, + UIAccessibilityNavigationStyleSeparate, + UIAccessibilityNavigationStyleCombined, +}; +typedef NSUInteger UIAccessibilityNavigationStyle; typedef uint64_t UIAccessibilityTraits; -extern UIAccessibilityTraits UIAccessibilityTraitNone; -extern UIAccessibilityTraits UIAccessibilityTraitButton; -extern UIAccessibilityTraits UIAccessibilityTraitLink; -extern UIAccessibilityTraits UIAccessibilityTraitSearchField; -extern UIAccessibilityTraits UIAccessibilityTraitImage; -extern UIAccessibilityTraits UIAccessibilityTraitSelected; -extern UIAccessibilityTraits UIAccessibilityTraitPlaysSound; -extern UIAccessibilityTraits UIAccessibilityTraitKeyboardKey; -extern UIAccessibilityTraits UIAccessibilityTraitStaticText; -extern UIAccessibilityTraits UIAccessibilityTraitSummaryElement; -extern UIAccessibilityTraits UIAccessibilityTraitNotEnabled; -extern UIAccessibilityTraits UIAccessibilityTraitUpdatesFrequently; +UIKIT_EXPORT UIAccessibilityTraits UIAccessibilityTraitNone; +UIKIT_EXPORT UIAccessibilityTraits UIAccessibilityTraitButton; +UIKIT_EXPORT UIAccessibilityTraits UIAccessibilityTraitLink; +UIKIT_EXPORT UIAccessibilityTraits UIAccessibilityTraitSearchField; +UIKIT_EXPORT UIAccessibilityTraits UIAccessibilityTraitImage; +UIKIT_EXPORT UIAccessibilityTraits UIAccessibilityTraitSelected; +UIKIT_EXPORT UIAccessibilityTraits UIAccessibilityTraitPlaysSound; +UIKIT_EXPORT UIAccessibilityTraits UIAccessibilityTraitKeyboardKey; +UIKIT_EXPORT UIAccessibilityTraits UIAccessibilityTraitStaticText; +UIKIT_EXPORT UIAccessibilityTraits UIAccessibilityTraitSummaryElement; +UIKIT_EXPORT UIAccessibilityTraits UIAccessibilityTraitNotEnabled; +UIKIT_EXPORT UIAccessibilityTraits UIAccessibilityTraitUpdatesFrequently; +UIKIT_EXPORT UIAccessibilityTraits UIAccessibilityTraitStartsMediaSession; +UIKIT_EXPORT UIAccessibilityTraits UIAccessibilityTraitAdjustable; +UIKIT_EXPORT UIAccessibilityTraits UIAccessibilityTraitAllowsDirectInteraction; +UIKIT_EXPORT UIAccessibilityTraits UIAccessibilityTraitCausesPageTurn; +UIKIT_EXPORT UIAccessibilityTraits UIAccessibilityTraitHeader; typedef uint32_t UIAccessibilityNotifications; -extern UIAccessibilityNotifications UIAccessibilityScreenChangedNotification; -extern UIAccessibilityNotifications UIAccessibilityLayoutChangedNotification; -extern UIAccessibilityNotifications UIAccessibilityAnnouncementNotification; -extern UIAccessibilityNotifications UIAccessibilityPageScrolledNotification; - -@interface NSObject (UIAccessibility) -- (BOOL)isAccessibilityElement; -- (void)setIsAccessibilityElement:(BOOL)isElement; -- (NSString*)accessibilityLabel; -- (void)setAccessibilityLabel:(NSString*)label; -- (NSString*)accessibilityHint; -- (void)setAccessibilityHint:(NSString*)hint; -- (NSString*)accessibilityValue; -- (void)setAccessibilityValue:(NSString*)value; -- (UIAccessibilityTraits)accessibilityTraits; -- (void)setAccessibilityTraits:(UIAccessibilityTraits)traits; -- (CGRect)accessibilityFrame; -- (void)setAccessibilityFrame:(CGRect)frame; - -@property (nonatomic) BOOL accessibilityElementsHidden; -@property (nonatomic) BOOL shouldGroupAccessibilityChildren; -@property (nonatomic) BOOL accessibilityViewIsModal; +UIKIT_EXPORT UIAccessibilityNotifications UIAccessibilityScreenChangedNotification; +UIKIT_EXPORT UIAccessibilityNotifications UIAccessibilityLayoutChangedNotification; +UIKIT_EXPORT UIAccessibilityNotifications UIAccessibilityAnnouncementNotification; +UIKIT_EXPORT UIAccessibilityNotifications UIAccessibilityPageScrolledNotification; + +// ---------------------------------------- + +@protocol UIAccessibility + +- (void)initAccessibility; +- (void)updateAccessibility; + +@property BOOL isAccessibilityElement; + +@property (copy) NSString* accessibilityLabel; +@property (copy) NSString* accessibilityHint; +@property (copy) NSString* accessibilityValue; + +@property UIAccessibilityTraits accessibilityTraits; +@property UIAccessibilityNavigationStyle accessibilityNavigationStyle; + +@property (nonatomic) CGRect accessibilityFrame; +@property (copy) UIBezierPath* accessibilityPath; +@property CGPoint accessibilityActivationPoint; + +@property (retain) NSString* accessibilityLanguage; + +@property BOOL accessibilityElementsHidden; +@property BOOL shouldGroupAccessibilityChildren; + +@property BOOL accessibilityViewIsModal; @end -@interface NSObject (UIAccessibilityContainer) -- (NSInteger)accessibilityElementCount; +// ---------------------------------------- + +@protocol UIAccessibilityContainer - (id)accessibilityElementAtIndex:(NSInteger)index; - (NSInteger)indexOfAccessibilityElement:(id)element; + +@property (readonly) NSInteger accessibilityElementCount; +@property (readonly) NSArray* accessibilityElements; + @end -@interface NSObject (UIAccessibilityFocus) +// ---------------------------------------- + +@protocol UIAccessibilityFocus + - (void)accessibilityElementDidBecomeFocused; - (void)accessibilityElementDidLoseFocus; - (BOOL)accessibilityElementIsFocused; + +@end + +// ---------------------------------------- + +@protocol UIAccessibilityIdentification + +@property (copy) NSString* accessibilityIdentifier; + @end -extern void UIAccessibilityPostNotification(UIAccessibilityNotifications notification, id argument); -extern BOOL UIAccessibilityIsVoiceOverRunning(void); +UIKIT_EXPORT void UIAccessibilityPostNotification(UIAccessibilityNotifications notification, id argument); +UIKIT_EXPORT BOOL UIAccessibilityIsVoiceOverRunning(void); diff --git a/include/UIKit/UIAccessibilityElement.h b/include/UIKit/UIAccessibilityElement.h index 333b8024e9..4484139205 100644 --- a/include/UIKit/UIAccessibilityElement.h +++ b/include/UIKit/UIAccessibilityElement.h @@ -29,20 +29,30 @@ #import "UIAccessibility.h" -@interface UIAccessibilityElement : NSObject { - NSString *_accessibilityLabel; - NSString *_accessibilityHint; - NSString *_accessibilityValue; - CGRect _accessibilityFrame; - UIAccessibilityTraits _accessibilityTraits; -} +@interface UIAccessibilityElement : NSObject - (id)initWithAccessibilityContainer:(id)container; -@property (nonatomic, retain) NSString *accessibilityLabel; -@property (nonatomic, retain) NSString *accessibilityHint; -@property (nonatomic, retain) NSString *accessibilityValue; -@property (nonatomic, assign) CGRect accessibilityFrame; -@property (nonatomic, assign) UIAccessibilityTraits accessibilityTraits; +@property (assign) UIView* accessibilityContainer; + +@property BOOL isAccessibilityElement; + +@property (copy) NSString* accessibilityLabel; +@property (copy) NSString* accessibilityHint; +@property (copy) NSString* accessibilityValue; + +@property UIAccessibilityTraits accessibilityTraits; +@property UIAccessibilityNavigationStyle accessibilityNavigationStyle; + +@property (nonatomic) CGRect accessibilityFrame; +@property (copy) UIBezierPath* accessibilityPath; +@property CGPoint accessibilityActivationPoint; + +@property (retain) NSString* accessibilityLanguage; + +@property BOOL accessibilityElementsHidden; +@property BOOL shouldGroupAccessibilityChildren; + +@property BOOL accessibilityViewIsModal; @end diff --git a/include/UIKit/UIBarItem.h b/include/UIKit/UIBarItem.h index ca683d8df8..493feeae75 100644 --- a/include/UIKit/UIBarItem.h +++ b/include/UIKit/UIBarItem.h @@ -31,10 +31,11 @@ #import #import #import "UIGeometry.h" +#import @class UIImage; -@interface UIBarItem : NSObject +@interface UIBarItem : NSObject @property (nonatomic, getter=isEnabled) BOOL enabled; @property (nonatomic, retain) UIImage *image; @@ -42,6 +43,22 @@ @property (nonatomic, copy) NSString *title; @property (nonatomic) NSInteger tag; +// UIAccessibility properties. +@property BOOL isAccessibilityElement; +@property (copy) NSString* accessibilityLabel; +@property (copy) NSString* accessibilityHint; +@property (copy) NSString* accessibilityValue; +@property UIAccessibilityTraits accessibilityTraits; +@property UIAccessibilityNavigationStyle accessibilityNavigationStyle; +@property (nonatomic) CGRect accessibilityFrame; +@property (copy) UIBezierPath* accessibilityPath; +@property CGPoint accessibilityActivationPoint; +@property (retain) NSString* accessibilityLanguage; +@property BOOL accessibilityElementsHidden; +@property BOOL shouldGroupAccessibilityChildren; +@property BOOL accessibilityViewIsModal; +@property (copy) NSString* accessibilityIdentifier; + - (void)setTitleTextAttributes:(NSDictionary *)attributes forState:(UIControlState)state; @end diff --git a/include/UIKit/UIFontDescriptor.h b/include/UIKit/UIFontDescriptor.h index 5ad869f16c..82557ee3f4 100644 --- a/include/UIKit/UIFontDescriptor.h +++ b/include/UIKit/UIFontDescriptor.h @@ -21,15 +21,22 @@ #import #import -enum { - UIFontTextStyleBody, -}; +UIKIT_EXPORT NSString* const UIFontTextStyleTitle1; +UIKIT_EXPORT NSString* const UIFontTextStyleTitle2; +UIKIT_EXPORT NSString* const UIFontTextStyleTitle3; +UIKIT_EXPORT NSString* const UIFontTextStyleHeadline; +UIKIT_EXPORT NSString* const UIFontTextStyleSubheadline; +UIKIT_EXPORT NSString* const UIFontTextStyleBody; +UIKIT_EXPORT NSString* const UIFontTextStyleFootnote; +UIKIT_EXPORT NSString* const UIFontTextStyleCaption1; +UIKIT_EXPORT NSString* const UIFontTextStyleCaption2; +UIKIT_EXPORT NSString* const UIFontTextStyleCallout; -extern NSString* UIFontSymbolicTrait; -extern NSString* UIFontDescriptorTraitsAttribute; -extern NSString* UIFontDescriptorFamilyAttribute; +UIKIT_EXPORT NSString* const UIFontSymbolicTrait; +UIKIT_EXPORT NSString* const UIFontDescriptorTraitsAttribute; +UIKIT_EXPORT NSString* const UIFontDescriptorFamilyAttribute; -typedef enum : uint32_t { +typedef NS_ENUM (uint32_t, UIFontDescriptorSymbolicTraits) { /* Typeface info (lower 16 bits of UIFontDescriptorSymbolicTraits ) */ UIFontDescriptorTraitItalic = 1u << 0, UIFontDescriptorTraitBold = 1u << 1, @@ -40,10 +47,8 @@ typedef enum : uint32_t { UIFontDescriptorTraitUIOptimized = 1u << 12, UIFontDescriptorTraitTightLeading = 1u << 15, UIFontDescriptorTraitLooseLeading = 1u << 16, - /* Font appearance info (upper 16 bits of UIFontDescriptorSymbolicTraits */ UIFontDescriptorClassMask = 0xF0000000, - UIFontDescriptorClassUnknown = 0u << 28, UIFontDescriptorClassOldStyleSerifs = 1u << 28, UIFontDescriptorClassTransitionalSerifs = 2u << 28, @@ -55,18 +60,21 @@ typedef enum : uint32_t { UIFontDescriptorClassOrnamentals = 9u << 28, UIFontDescriptorClassScripts = 10u << 28, UIFontDescriptorClassSymbolic = 12u << 28 -} UIFontDescriptorSymbolicTraits; +}; typedef NSUInteger UIFontTextStyle; -UIKIT_EXPORT_CLASS -@interface UIFontDescriptor : NSObject + (UIFontDescriptor*)preferredFontDescriptorWithTextStyle : (NSUInteger)stytle; -+ (UIFontDescriptor*)fontDescriptorWithName:(NSString*)name size:(CGFloat)size; -+ (UIFontDescriptor*)fontDescriptorWithDescriptor:(UIFontDescriptor*)descriptor size:(CGFloat)size; +UIKIT_EXPORT_CLASS + +@interface UIFontDescriptor : NSObject ++ (UIFontDescriptor*)preferredFontDescriptorWithTextStyle:(NSString*)style; ++ (UIFontDescriptor*)fontDescriptorWithName:(NSString*)fontName size:(CGFloat)size; +- (UIFontDescriptor*)fontDescriptorWithSymbolicTraits:(UIFontDescriptorSymbolicTraits)symbolicTraits; - (instancetype)initWithFontAttributes:(NSDictionary*)attributes; +- (id)objectForKey:(NSString*)anAttribute; -@property (nonatomic) UIFontDescriptorSymbolicTraits symbolicTraits; +@property (nonatomic, readonly) UIFontDescriptorSymbolicTraits symbolicTraits; @end diff --git a/include/UIKit/UIKit.h b/include/UIKit/UIKit.h index 9d39a402a6..21292687d3 100644 --- a/include/UIKit/UIKit.h +++ b/include/UIKit/UIKit.h @@ -79,6 +79,7 @@ #import "UISegmentedControl.h" #import "UIActivityIndicatorView.h" #import "UIPopoverController.h" +#import "UIPopoverPresentationController.h" #import "UINavigationBar.h" #import "UITextView.h" #import "UIDataDetectors.h" diff --git a/include/UIKit/UIPopoverController.h b/include/UIKit/UIPopoverController.h index 9119dba235..ddf0fe353f 100644 --- a/include/UIKit/UIPopoverController.h +++ b/include/UIKit/UIPopoverController.h @@ -81,15 +81,4 @@ typedef NSUInteger UIPopoverArrowDirection; @end -@protocol UIPopoverPresentationControllerDelegate -@end - -@interface UIPopoverPresentationController : UIViewController -@property (nonatomic, retain) UIBarButtonItem* barButtonItem; -@property (nonatomic) NSUInteger permittedArrowDirections; -@property (nonatomic, retain) UIView* sourceView; -@property (nonatomic) CGRect sourceRect; -@property (nonatomic) id delegate; -@end - #endif /* _UIPOPOVERCONTROLLER_H_ */ diff --git a/include/UIKit/UIPopoverPresentationController.h b/include/UIKit/UIPopoverPresentationController.h new file mode 100644 index 0000000000..c2f1707361 --- /dev/null +++ b/include/UIKit/UIPopoverPresentationController.h @@ -0,0 +1,53 @@ +/* +* Copyright (c) 2011, The Iconfactory. All rights reserved. +* +* Copyright (c) 2015 Microsoft Corporation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* 3. Neither the name of The Iconfactory nor the names of its contributors may +* be used to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE ICONFACTORY BE LIABLE FOR ANY DIRECT, +* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _UIPOPOVERPRESENTATIONCONTROLLER_H_ +#define _UIPOPOVERPRESENTATIONCONTROLLER_H_ + +#include +#include + +@interface UIPopoverPresentationController : UIPresentationController + +@property (nonatomic, readwrite) UIEdgeInsets popoverLayoutMargins; +@property (nonatomic, copy) UIColor* backgroundColor; +@property (nonatomic, copy) NSArray* passthroughViews; +@property (nonatomic, readwrite, retain) Class popoverBackgroundViewClass; +@property (nonatomic, retain) UIBarButtonItem* barButtonItem; +@property (nonatomic, retain) UIView* sourceView; +@property (nonatomic, assign) CGRect sourceRect; +@property (nonatomic) id delegate; +@property (nonatomic, assign) UIPopoverArrowDirection permittedArrowDirections; +@property (nonatomic, readonly) UIPopoverArrowDirection arrowDirection; + +@end + +#endif /* _UIPOPOVERPRESENTATIONCONTROLLER_H_ */ \ No newline at end of file diff --git a/include/UIKit/UIPopoverPresentationControllerDelegate.h b/include/UIKit/UIPopoverPresentationControllerDelegate.h new file mode 100644 index 0000000000..dae574ea06 --- /dev/null +++ b/include/UIKit/UIPopoverPresentationControllerDelegate.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2011, The Iconfactory. All rights reserved. + * + * Copyright (c) 2015 Microsoft Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of The Iconfactory nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE ICONFACTORY BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _UIPOPOVERPRESENTATIONCONTROLLERDELEGATE_H_ +#define _UIPOPOVERPRESENTATIONCONTROLLERDELEGATE_H_ + +#import + +@class UIPopoverPresentationController, UIView; + +@protocol UIPopoverPresentationControllerDelegate + +@optional +- (void)prepareForPopoverPresentation:(UIPopoverPresentationController*)popoverPresentationController; +- (BOOL)popoverPresentationControllerShouldDismissPopover:(UIPopoverPresentationController*)popoverPresentationController; +- (void)popoverPresentationControllerDidDismissPopover:(UIPopoverPresentationController*)popoverPresentationController; +- (void)popoverPresentationController:(UIPopoverPresentationController*)popoverPresentationController + willRepositionPopoverToRect:(CGRect*)rect + inView:(UIView*)view; +@end + +#endif /* _UIPOPOVERPRESENTATIONCONTROLLERDELEGATE_H_ */ diff --git a/include/UIKit/UIPresentationController.h b/include/UIKit/UIPresentationController.h new file mode 100644 index 0000000000..c62b891cea --- /dev/null +++ b/include/UIKit/UIPresentationController.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011, The Iconfactory. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of The Iconfactory nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE ICONFACTORY BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _UIPRESENTATIONCONTROLLER_H_ +#define _UIPRESENTATIONCONTROLLER_H_ + +#import +#import + +@interface UIPresentationController : NSObject + +- (instancetype)initWithPresentedViewController:(UIViewController*)presentedViewController + presentingViewController:(UIViewController*)presentingViewController; + +- (UIView*)presentedView; +- (CGRect)frameOfPresentedViewInContainerView; + +- (void)containerViewWillLayoutSubviews; +- (void)containerViewDidLayoutSubviews; +- (void)presentationTransitionWillBegin; +- (void)presentationTransitionDidEnd:(BOOL)completed; +- (void)dismissalTransitionWillBegin; +- (void)dismissalTransitionDidEnd:(BOOL)completed; + +- (BOOL)shouldPresentInFullscreen; +- (BOOL)shouldRemovePresentersView; + +@property (nonatomic, readonly, retain) UIViewController* presentingViewController; +@property (nonatomic, readonly, retain) UIViewController* presentedViewController; +@property (nonatomic, readonly, retain) UIView* containerView; +@property (nonatomic, readonly) UIModalPresentationStyle presentationStyle; + +@end + +#endif /* _UIPRESENTATIONCONTROLLER_H_ */ \ No newline at end of file diff --git a/include/UIKit/UIScreen.h b/include/UIKit/UIScreen.h index c79063cb0d..d8a18b76f8 100644 --- a/include/UIKit/UIScreen.h +++ b/include/UIKit/UIScreen.h @@ -49,12 +49,14 @@ UIKIT_EXPORT_CLASS + (NSArray*)screens; @property (nonatomic, readonly) CGRect bounds; +@property (nonatomic, readonly) CGRect nativeBounds; @property (nonatomic, readonly) CGRect applicationFrame; @property (nonatomic, readonly, copy) NSArray* availableModes; // only ever returns the currentMode @property (nonatomic, retain) UIScreenMode* currentMode; // ignores any attempt to set this @property (nonatomic, readonly) CGFloat scale; -@property (nonatomic, readonly, retain) UIScreenMode* preferredMode; @property (nonatomic, readonly) CGFloat nativeScale; +@property (nonatomic, readonly) CGFloat brightness; +@property (nonatomic, readonly, retain) UIScreenMode* preferredMode; @end diff --git a/include/UIKit/UISearchBar.h b/include/UIKit/UISearchBar.h index e08b7fc2b5..7a97ccd77e 100644 --- a/include/UIKit/UISearchBar.h +++ b/include/UIKit/UISearchBar.h @@ -77,7 +77,7 @@ UIKIT_EXPORT_CLASS @property (nonatomic) UIKeyboardType keyboardType; @property (nonatomic) UIOffset searchTextPositionAdjustment; @property (nonatomic) UISearchBarStyle searchBarStyle; -@property (nonatomic) NSString* prompt; +@property (nonatomic, copy) NSString* prompt; - (void)setShowsCancelButton:(BOOL)showsCancelButton animated:(BOOL)animated; - (void)setImage:(UIImage*)iconImage forSearchBarIcon:(UISearchBarIcon)icon state:(UIControlState)state; diff --git a/include/UIKit/UIView.h b/include/UIKit/UIView.h index 71a3f4a9a4..9b3567efc3 100644 --- a/include/UIKit/UIView.h +++ b/include/UIKit/UIView.h @@ -36,6 +36,7 @@ #import "UIGeometry.h" #import "UIAppearance.h" #import "NSLayoutConstraint.h" +#import "UIAccessibility.h" enum { UIViewAutoresizingNone = 0, @@ -115,7 +116,7 @@ UIKIT_EXPORT const CGFloat UIViewNoIntrinsicMetric; @class UIColor, CALayer, UIViewController, UIGestureRecognizer, NSLayoutConstraint, UIMotionEffect, WXFrameworkElement; UIKIT_EXPORT_CLASS -@interface UIView : UIResponder { +@interface UIView : UIResponder { @public id _backButtonDelegate; SEL _backButtonSelector; @@ -259,8 +260,22 @@ UIKIT_EXPORT_CLASS - (void)setNativeElement:(WXFrameworkElement*)nativeElement; -/*** This should be put into the accessibility protocol ***/ -@property (copy, nonatomic) NSString* accessibilityIdentifier; +// UIAccessibility properties. +@property BOOL isAccessibilityElement; +@property (copy) NSString* accessibilityLabel; +@property (copy) NSString* accessibilityHint; +@property (copy) NSString* accessibilityValue; +@property UIAccessibilityTraits accessibilityTraits; +@property UIAccessibilityNavigationStyle accessibilityNavigationStyle; +@property (nonatomic) CGRect accessibilityFrame; +@property (copy) UIBezierPath* accessibilityPath; +@property CGPoint accessibilityActivationPoint; +@property (retain) NSString* accessibilityLanguage; +@property BOOL accessibilityElementsHidden; +@property BOOL shouldGroupAccessibilityChildren; +@property BOOL accessibilityViewIsModal; +@property (copy) NSString* accessibilityIdentifier; + @end @interface UIView (StarboardActions) diff --git a/include/UIKit/UIViewController.h b/include/UIKit/UIViewController.h index 8f2d97afbe..0daa6f2aa4 100644 --- a/include/UIKit/UIViewController.h +++ b/include/UIKit/UIViewController.h @@ -54,6 +54,11 @@ typedef enum { UIModalPresentationPageSheet, UIModalPresentationFormSheet, UIModalPresentationCurrentContext, + UIModalPresentationCustom, + UIModalPresentationOverFullScreen, + UIModalPresentationOverCurrentContext, + UIModalPresentationPopover, + UIModalPresentationNone = -1 } UIModalPresentationStyle; typedef enum { @@ -63,7 +68,8 @@ typedef enum { UIModalTransitionStylePartialCurl, } UIModalTransitionStyle; -@class UINavigationItem, UINavigationController, UIBarButtonItem, UISplitViewController, UIStoryboard; +@class UINavigationItem, UINavigationController, UIBarButtonItem, UISplitViewController, UIStoryboard, UIPresentationController, + UIPopoverPresentationController; UIKIT_EXPORT_CLASS @interface UIViewController : UIResponder @@ -153,6 +159,9 @@ UIKIT_EXPORT_CLASS @property (nonatomic, readonly, retain) UISplitViewController* splitViewController; @property (nonatomic, readonly, retain) UISearchDisplayController* searchDisplayController; // stub +@property (nonatomic, readonly) UIPopoverPresentationController* popoverPresentationController; +@property (nonatomic, readonly) UIPresentationController* presentationController; + // stubs @property (nonatomic, retain) UITabBarItem* tabBarItem; @property (nonatomic, readonly, retain) UITabBarController* tabBarController; @@ -168,6 +177,22 @@ UIKIT_EXPORT_CLASS @property (nonatomic) BOOL automaticallyAdjustsScrollViewInsets; @property (nonatomic) BOOL extendedLayoutIncludesOpaqueBars; +// UIAccessibility properties. +@property BOOL isAccessibilityElement; +@property (copy) NSString* accessibilityLabel; +@property (copy) NSString* accessibilityHint; +@property (copy) NSString* accessibilityValue; +@property UIAccessibilityTraits accessibilityTraits; +@property UIAccessibilityNavigationStyle accessibilityNavigationStyle; +@property (nonatomic) CGRect accessibilityFrame; +@property (copy) UIBezierPath* accessibilityPath; +@property CGPoint accessibilityActivationPoint; +@property (retain) NSString* accessibilityLanguage; +@property BOOL accessibilityElementsHidden; +@property BOOL shouldGroupAccessibilityChildren; +@property BOOL accessibilityViewIsModal; +@property (copy) NSString* accessibilityIdentifier; + @end UIKIT_EXPORT NSString* const UITransitionContextFromViewControllerKey; diff --git a/msvc/sbclang.targets b/msvc/sbclang.targets index bee0c021e1..5b1f16764e 100644 --- a/msvc/sbclang.targets +++ b/msvc/sbclang.targets @@ -45,7 +45,7 @@ true - + diff --git a/msvc/sbresources.props b/msvc/sbresources.props index 67b1483251..82ac29ecaa 100644 --- a/msvc/sbresources.props +++ b/msvc/sbresources.props @@ -5,6 +5,7 @@ AppxPackagePayload takes care of the copying in that case --> $(OutDir) + $(OutDir)\$(TargetName).bundle $(OutDir)\app.zip \ No newline at end of file diff --git a/msvc/sbresources.targets b/msvc/sbresources.targets index 8c38f642eb..88b6ea2ed9 100644 --- a/msvc/sbresources.targets +++ b/msvc/sbresources.targets @@ -32,6 +32,7 @@ _XibCompile;_StoryboardCompile;_DataModelCompile;_DataModelDirCompile;_AssetCatalogCompile;CopyInfoPlist Link + BuildLink ComputeXibCompileOptions;ComputeStoryboardCompileOptions;ComputeDataModelCompileOptions;ComputeDataModelDirCompileOptions;ComputeAssetCatalogCompileOptions;ComputePlistCopyOptions;CopyStarboardDependencies @@ -39,7 +40,7 @@ Name="SBResourceCompile" BeforeTargets="$(SBResourceCompileBeforeTargets)" AfterTargets="$(SBResourceCompileAfterTargets)" - DependsOnTargets="$(SBResourceCompileDependsOn);SBResourceCopy;SBResourcePackage" /> + DependsOnTargets="$(SBResourceCompileDependsOn);_SBResourceCopy;SBResourcePackage" /> - + - + - + + @@ -165,18 +173,22 @@ Inputs="%(DataModelCompileFile.SourceFile);%(DataModelCompileFile.Identity)"> - + - @@ -190,12 +202,17 @@ Inputs="%(DataModelDirCompileFile.SourceFile);%(DataModelDirCompileFile.Identity)"> - + - @@ -209,15 +226,21 @@ Inputs="%(AssetCatalogCompileFile.SourceFile);%(AssetCatalogCompileFile.Identity)"> - - + + + + Condition="'%(AssetCatalogCompileFile.ExcludedFromBuild)' != 'true'" + Command=""$(MSBuildThisFileDirectory)..\bin\acbuilder.exe" --notices --target-device iphone --target-device ipad --compile "%(AssetCatalogCompileFile.OutputDir)" "%(AssetCatalogCompileFile.SourceFile)"" /> @@ -280,9 +303,10 @@ $([System.IO.Path]::Combine('$(IntDir)', '%(DataModelCompile.VariantDir)', '%(DataModelCompile.Filename)')).mom.dummy - + %(DataModelCompile.Identity) %(DataModelCompile.IntermediateFile) + %(DataModelCompile.ExcludedFromBuild) @@ -293,25 +317,27 @@ $([System.IO.Path]::Combine('$(IntDir)', '%(DataModelDirCompile.VariantDir)', '%(DataModelDirCompile.Filename)')).momc.dummy - + %(DataModelDirCompile.Identity) %(DataModelDirCompile.IntermediateFile) + %(DataModelDirCompile.ExcludedFromBuild) - - $([System.IO.Path]::Combine('$(IntDir)', 'AssetCatalog')) - + %(AssetCatalogCompile.Identity) %(AssetCatalogCompile.IntermediateDir) + %(AssetCatalogCompile.ExcludedFromBuild) + + diff --git a/msvc/starboard-cmdline.targets b/msvc/starboard-cmdline.targets index c62077bc62..7904331049 100644 --- a/msvc/starboard-cmdline.targets +++ b/msvc/starboard-cmdline.targets @@ -7,7 +7,7 @@ Application v140 true + true @@ -48,6 +49,7 @@ Designer + diff --git a/msvc/vsimporter-templates/WinStore10-App/Project.vstemplate b/msvc/vsimporter-templates/WinStore10-App/Project.vstemplate index 85f14a50ad..779e27ae69 100644 --- a/msvc/vsimporter-templates/WinStore10-App/Project.vstemplate +++ b/msvc/vsimporter-templates/WinStore10-App/Project.vstemplate @@ -3,6 +3,7 @@ App.vcxproj.filters Package-native.appxmanifest + default.rd.xml LockScreenLogo.scale-200.png SplashScreen.scale-200.png Square44x44Logo.scale-200.png diff --git a/msvc/vsimporter-templates/WinStore10-App/default.rd.xml b/msvc/vsimporter-templates/WinStore10-App/default.rd.xml new file mode 100644 index 0000000000..028964726f --- /dev/null +++ b/msvc/vsimporter-templates/WinStore10-App/default.rd.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/msvc/vsimporter-templates/WinStore10-Bundle/Bundle.vcxproj b/msvc/vsimporter-templates/WinStore10-Bundle/Bundle.vcxproj new file mode 100644 index 0000000000..471a8b9b75 --- /dev/null +++ b/msvc/vsimporter-templates/WinStore10-Bundle/Bundle.vcxproj @@ -0,0 +1,36 @@ + + + + + $projectname$ + $safeprojectname$ + en-US + 14.0 + Windows Store + 10.0 + 10.0.10240.0 + 10.0.10240.0 + + + + Utility + Bundle + v140 + + + + + + + + + + + + + + + + + + diff --git a/msvc/vsimporter-templates/WinStore10-Bundle/Bundle.vcxproj.filters b/msvc/vsimporter-templates/WinStore10-Bundle/Bundle.vcxproj.filters new file mode 100644 index 0000000000..512a653973 --- /dev/null +++ b/msvc/vsimporter-templates/WinStore10-Bundle/Bundle.vcxproj.filters @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/msvc/vsimporter-templates/WinStore10-Bundle/Project.vstemplate b/msvc/vsimporter-templates/WinStore10-Bundle/Project.vstemplate new file mode 100644 index 0000000000..47870a58df --- /dev/null +++ b/msvc/vsimporter-templates/WinStore10-Bundle/Project.vstemplate @@ -0,0 +1,7 @@ + + + + Bundle.vcxproj.filters + + + diff --git a/samples/GLKitComplex/GLKitComplex.vsimporter/GLKitComplex-WinStore10/GLKitComplex.vcxproj b/samples/GLKitComplex/GLKitComplex.vsimporter/GLKitComplex-WinStore10/GLKitComplex.vcxproj index 39693504f7..32d2289e28 100644 --- a/samples/GLKitComplex/GLKitComplex.vsimporter/GLKitComplex-WinStore10/GLKitComplex.vcxproj +++ b/samples/GLKitComplex/GLKitComplex.vsimporter/GLKitComplex-WinStore10/GLKitComplex.vcxproj @@ -35,6 +35,7 @@ v140 GLKitComplex true + true diff --git a/samples/HelloGLKit/HelloGLKit.vsimporter/HelloGLKit-WinStore10/HelloGLKit.vcxproj b/samples/HelloGLKit/HelloGLKit.vsimporter/HelloGLKit-WinStore10/HelloGLKit.vcxproj index 8f886880b8..f05102c05d 100644 --- a/samples/HelloGLKit/HelloGLKit.vsimporter/HelloGLKit-WinStore10/HelloGLKit.vcxproj +++ b/samples/HelloGLKit/HelloGLKit.vsimporter/HelloGLKit-WinStore10/HelloGLKit.vcxproj @@ -35,6 +35,7 @@ v140 HelloGLKit true + true diff --git a/samples/HelloOpenGL/HelloOpenGL.vsimporter/HelloOpenGL-WinStore10/HelloOpenGL.vcxproj b/samples/HelloOpenGL/HelloOpenGL.vsimporter/HelloOpenGL-WinStore10/HelloOpenGL.vcxproj index e7d5aed674..7291b623ec 100644 --- a/samples/HelloOpenGL/HelloOpenGL.vsimporter/HelloOpenGL-WinStore10/HelloOpenGL.vcxproj +++ b/samples/HelloOpenGL/HelloOpenGL.vsimporter/HelloOpenGL-WinStore10/HelloOpenGL.vcxproj @@ -35,6 +35,7 @@ v140 HelloOpenGL true + true diff --git a/samples/HelloUI/HelloUI.vsimporter/HelloUI-WinStore10/HelloUI.vcxproj b/samples/HelloUI/HelloUI.vsimporter/HelloUI-WinStore10/HelloUI.vcxproj index 5da87aca3d..7afe51ba7f 100644 --- a/samples/HelloUI/HelloUI.vsimporter/HelloUI-WinStore10/HelloUI.vcxproj +++ b/samples/HelloUI/HelloUI.vsimporter/HelloUI-WinStore10/HelloUI.vcxproj @@ -35,6 +35,7 @@ v140 HelloUI true + true diff --git a/samples/HelloUI/HelloUI/HelloUI.m b/samples/HelloUI/HelloUI/HelloUI.m index 01c6431f6f..a32cfd7e3e 100644 --- a/samples/HelloUI/HelloUI/HelloUI.m +++ b/samples/HelloUI/HelloUI/HelloUI.m @@ -18,7 +18,7 @@ -(void) applicationDidFinishLaunching: (UIApplication *) app _welcomeLabel = [[UILabel alloc] initWithFrame: bounds]; [_welcomeLabel setBackgroundColor: nil]; - [_welcomeLabel setTextColor: [UIColor whiteColor]]; + [_welcomeLabel setTextColor: [UIColor blueColor]]; [_welcomeLabel setText: @"Hello Islandwood!"]; [_welcomeLabel setFont: [UIFont boldSystemFontOfSize: 48.0f]]; [_welcomeLabel setTextAlignment: UITextAlignmentCenter]; @@ -39,6 +39,7 @@ -(void) applicationDidFinishLaunching: (UIApplication *) app [_draggableButton setTitle: @"Move me!" forState: UIControlStateNormal]; [_draggableButton setTintColor:[UIColor whiteColor]]; _draggableButton.frame = CGRectMake(bounds.size.width / 2.0f - 50.0f, 50.0f, 100.0f, 40.0f); + [_draggableButton addTarget: self action: @selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside]; [_mainWindow addSubview: _draggableButton]; UIPanGestureRecognizer *moveButton = [[UIPanGestureRecognizer alloc] initWithTarget: self action: @selector(buttonPanned:)]; @@ -47,6 +48,11 @@ -(void) applicationDidFinishLaunching: (UIApplication *) app [_mainWindow makeKeyAndVisible]; } +-(void) buttonPressed: (UIButton*)button +{ + [_welcomeLabel setText: @"Got a touch!"]; +} + -(void) buttonPanned: (UIPanGestureRecognizer *) gesture { CGPoint newPosition = _draggableButton.layer.position; @@ -69,4 +75,4 @@ +(void) setStartupDisplayMode: (WOCDisplayMode *) mode { mode.magnification = 1.0; } @end -#endif \ No newline at end of file +#endif diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj index 7e8d7d06ef..9bd54e8cd7 100644 --- a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj +++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj @@ -35,6 +35,7 @@ v140 WOCCatalog true + true diff --git a/samples/WOCCatalog/WOCCatalog/ControlsViewController.m b/samples/WOCCatalog/WOCCatalog/ControlsViewController.m index cce097cd5f..ee2463154d 100644 --- a/samples/WOCCatalog/WOCCatalog/ControlsViewController.m +++ b/samples/WOCCatalog/WOCCatalog/ControlsViewController.m @@ -15,68 +15,67 @@ //****************************************************************************** #import "ControlsViewController.h" +#import "SingleImageViewController.h" + +#define UIPOPOVERCONTROL_ROW 4 @implementation ControlsViewController - (void)viewDidLoad { [super viewDidLoad]; - - [self tableView].allowsSelection = NO; } -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - - return 4; +- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section { + return 5; } -- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath -{ +- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath { return 50; } -- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - - UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MenuCell"]; +- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath { + UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"MenuCell"]; if (nil == cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MenuCell"]; } - + if (indexPath.row == 0) { // switch CGRect frame = CGRectMake(5.0, 12.0, 94.0, 27.0); - UISwitch *switchCtrl = [[UISwitch alloc] initWithFrame:frame]; + UISwitch* switchCtrl = [[UISwitch alloc] initWithFrame:frame]; // in case the parent view draws with a custom color or gradient, use a transparent color switchCtrl.backgroundColor = [UIColor clearColor]; cell.accessoryView = switchCtrl; cell.textLabel.text = @"UISwitch"; + cell.selectionStyle = UITableViewCellSelectionStyleNone; } else if (indexPath.row == 1) { - // slider CGRect frame = CGRectMake(5.0, 12.0, 120.0, 8.0); - UISlider *sliderCtl = [[UISlider alloc] initWithFrame:frame]; - + UISlider* sliderCtl = [[UISlider alloc] initWithFrame:frame]; + // in case the parent view draws with a custom color or gradient, use a transparent color sliderCtl.backgroundColor = [UIColor clearColor]; - + sliderCtl.minimumValue = 0.0; sliderCtl.maximumValue = 100.0; sliderCtl.continuous = YES; sliderCtl.value = 50.0; - + // Add an accessibility label that describes the slider. [sliderCtl setAccessibilityLabel:@"StandardSlider"]; cell.accessoryView = sliderCtl; cell.textLabel.text = @"UISlider"; - } - else if (indexPath.row == 2) { + cell.selectionStyle = UITableViewCellSelectionStyleNone; + } else if (indexPath.row == 2) { // activity indicator CGRect frame = CGRectMake(5.0, 12.0, 40.0, 40.0); - - UIActivityIndicatorView *progressInd = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; - //self.progressIndSavedColor = progressInd.color; + + UIActivityIndicatorView* progressInd = + [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; + // self.progressIndSavedColor = progressInd.color; progressInd.frame = frame; [progressInd startAnimating]; progressInd.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray; @@ -84,23 +83,49 @@ - (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSI cell.accessoryView = progressInd; cell.textLabel.text = @"UIActivityIndicator"; - } - else if (indexPath.row == 3) { + cell.selectionStyle = UITableViewCellSelectionStyleNone; + } else if (indexPath.row == 3) { // progress view - + CGRect frame = CGRectMake(5.0, 20.0, 160, 24); - UIProgressView *progressBar = [[UIProgressView alloc] initWithFrame:frame]; + UIProgressView* progressBar = [[UIProgressView alloc] initWithFrame:frame]; progressBar.progressViewStyle = UIProgressViewStyleDefault; progressBar.progress = 0.5; cell.accessoryView = progressBar; cell.textLabel.text = @"UIProgressView"; - + cell.selectionStyle = UITableViewCellSelectionStyleNone; + + } else if (indexPath.row == UIPOPOVERCONTROL_ROW) { + // UIPopoverPresentationController + + cell.textLabel.text = @"UIPopupPresentationController (press me)"; + cell.selectionStyle = UITableViewCellSelectionStyleBlue; } - + return cell; } -@end +- (NSIndexPath*)tableView:(UITableView*)tableView willSelectRowAtIndexPath:(NSIndexPath*)indexPath { + if (indexPath.row == UIPOPOVERCONTROL_ROW) { + return indexPath; + } + + return nil; +} +- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath { + if (indexPath.row == UIPOPOVERCONTROL_ROW) { + // Note: presenting a UIViewController with the UIModalPresentationStyle of Popover does not yet present the view controller + // as a popover. This work will need to be completed as part of UIPopoverController and UIPresentation controller work. + SingleImageViewController* imvc = [[SingleImageViewController alloc] initWithImage:[UIImage imageNamed:@"photo1.jpg"]]; + assert(imvc.popoverPresentationController == nil); + + imvc.modalPresentationStyle = UIModalPresentationPopover; + [self presentViewController:imvc animated:YES completion:nil]; + assert(imvc.popoverPresentationController != nil); + } +} + +@end diff --git a/samples/WOCCatalog/WOCCatalog/DisplayModeViewController.h b/samples/WOCCatalog/WOCCatalog/DisplayModeViewController.h index ebfbd83b91..2756e30e18 100644 --- a/samples/WOCCatalog/WOCCatalog/DisplayModeViewController.h +++ b/samples/WOCCatalog/WOCCatalog/DisplayModeViewController.h @@ -15,7 +15,8 @@ //****************************************************************************** #import +#import -@interface SBDisplayModeViewController : UITableViewController -@property (nonatomic, retain) NSMutableArray *rows; +@interface SBDisplayModeViewController : UITableViewController +@property (nonatomic, retain) NSMutableArray* rows; @end diff --git a/samples/WOCCatalog/WOCCatalog/DisplayModeViewController.m b/samples/WOCCatalog/WOCCatalog/DisplayModeViewController.m index 57b5639251..7195c0675e 100644 --- a/samples/WOCCatalog/WOCCatalog/DisplayModeViewController.m +++ b/samples/WOCCatalog/WOCCatalog/DisplayModeViewController.m @@ -18,141 +18,171 @@ #import "DisplayModeViewController.h" @implementation SBDisplayModeViewController { - NSArray *_informationLabels; - NSArray *_presetNames; - NSArray *_orientationNames; - UITextField *fixedWidth, *fixedHeight, *magnification, *fixedAspect; + NSArray* _informationLabels; + NSArray* _presetNames; + NSArray* _orientationNames; + UITextField *fixedWidth, *nativeBounds, *fixedHeight, *magnification, *fixedAspect, *scale, *nativeScale, *uiScreenBrightness, + *hostScreenScale; UIPickerView *presets, *orientations; + UIScreen* uiScreen; } --(void) toggleFitToWindow: (UISwitch *) sender -{ +- (void)toggleFitToWindow:(UISwitch*)sender { UIApplication.displayMode.autoMagnification = sender.on; [UIApplication.displayMode updateDisplaySettings]; } --(void) toggleAdjustWindowSize: (UISwitch *) sender -{ +- (void)toggleAdjustWindowSize:(UISwitch*)sender { UIApplication.displayMode.sizeUIWindowToFit = sender.on; [UIApplication.displayMode updateDisplaySettings]; } --(void) setWidth: (UITextField *) sender -{ +- (void)setWidth:(UITextField*)sender { float val = [sender.text floatValue]; - if ( val != val ) val = 0.0f; - if ( val < 0.0f ) val = 0.0f; - if ( val < 200.0f && val > 0.0f ) val = 200.09f; - if ( val > 2048.0f ) val = 2048.0f; + if (val != val) { + val = 0.0f; + } + if (val < 0.0f) { + val = 0.0f; + } + if (val < 200.0f && val > 0.0f) { + val = 200.09f; + } + if (val > 2048.0f) { + val = 2048.0f; + } UIApplication.displayMode.fixedWidth = val; - sender.text = [NSString stringWithFormat: @"%.1f", UIApplication.displayMode.fixedWidth]; + sender.text = [NSString stringWithFormat:@"%.1f", UIApplication.displayMode.fixedWidth]; [UIApplication.displayMode updateDisplaySettings]; - [presets selectRow: 0 inComponent: 0 animated: FALSE]; + [presets selectRow:0 inComponent:0 animated:FALSE]; } --(void) setHeight: (UITextField *) sender -{ +- (void)setHeight:(UITextField*)sender { float val = [sender.text floatValue]; - if ( val != val ) val = 0.0f; - if ( val < 0.0f ) val = 0.0f; - if ( val < 200.0f && val > 0.0f ) val = 200.09f; - if ( val > 2048.0f ) val = 2048.0f; + if (val != val) { + val = 0.0f; + } + if (val < 0.0f) { + val = 0.0f; + } + if (val < 200.0f && val > 0.0f) { + val = 200.09f; + } + if (val > 2048.0f) { + val = 2048.0f; + } UIApplication.displayMode.fixedHeight = val; - sender.text = [NSString stringWithFormat: @"%.1f", UIApplication.displayMode.fixedHeight]; + sender.text = [NSString stringWithFormat:@"%.1f", UIApplication.displayMode.fixedHeight]; [UIApplication.displayMode updateDisplaySettings]; - [presets selectRow: 0 inComponent: 0 animated: FALSE]; + [presets selectRow:0 inComponent:0 animated:FALSE]; } --(void) setMagnification: (UITextField *) sender -{ +- (void)setMagnification:(UITextField*)sender { float val = [sender.text floatValue]; - if ( val != val ) val = 0.0f; - if ( val < 0.25f ) val = 0.25f; - if ( val > 5.0f ) val = 5.0f; + if (val != val) { + val = 0.0f; + } + if (val < 0.25f) { + val = 0.25f; + } + if (val > 5.0f) { + val = 5.0f; + } UIApplication.displayMode.magnification = val; - sender.text = [NSString stringWithFormat: @"%.2f", UIApplication.displayMode.magnification]; + sender.text = [NSString stringWithFormat:@"%.2f", UIApplication.displayMode.magnification]; [UIApplication.displayMode updateDisplaySettings]; - [presets selectRow: 0 inComponent: 0 animated: FALSE]; + [presets selectRow:0 inComponent:0 animated:FALSE]; } --(void) setAspect: (UITextField *) sender -{ +- (void)setAspect:(UITextField*)sender { float val = [sender.text floatValue]; - if ( val != val ) val = 0.0f; - if ( val > 0.0f && val < 0.2f ) val = 0.2f; - if ( val > 5.0f ) val = 5.0f; + if (val != val) { + val = 0.0f; + } + if (val > 0.0f && val < 0.2f) { + val = 0.2f; + } + if (val > 5.0f) { + val = 5.0f; + } UIApplication.displayMode.fixedAspectRatio = val; - sender.text = [NSString stringWithFormat: @"%.2f", UIApplication.displayMode.fixedAspectRatio]; + sender.text = [NSString stringWithFormat:@"%.2f", UIApplication.displayMode.fixedAspectRatio]; [UIApplication.displayMode updateDisplaySettings]; - [presets selectRow: 0 inComponent: 0 animated: FALSE]; + [presets selectRow:0 inComponent:0 animated:FALSE]; } --(void) updateLabels -{ - for ( NSDictionary *curItem in _informationLabels ) { - UITableViewCell *cell = curItem[@"Cell"]; - UILabel *label = (UILabel *) cell.accessoryView; +- (void)updateLabels { + for (NSDictionary* curItem in _informationLabels) { + UITableViewCell* cell = curItem[@"Cell"]; + UILabel* label = (UILabel*)cell.accessoryView; - label.text = [UIApplication.displayMode valueForKey: curItem[@"ValueName"]]; + label.text = [UIApplication.displayMode valueForKey:curItem[@"ValueName"]]; cell.textLabel.text = curItem[@"LabelName"]; cell.detailTextLabel.text = curItem[@"ValueName"]; } - fixedWidth.text = [NSString stringWithFormat: @"%.1f", UIApplication.displayMode.fixedWidth]; - fixedHeight.text = [NSString stringWithFormat: @"%.1f", UIApplication.displayMode.fixedHeight]; - fixedAspect.text = [NSString stringWithFormat: @"%.1f", UIApplication.displayMode.fixedAspectRatio]; - magnification.text = [NSString stringWithFormat: @"%.2f", UIApplication.displayMode.magnification]; + fixedWidth.text = [NSString stringWithFormat:@"%.1f", UIApplication.displayMode.fixedWidth]; + fixedHeight.text = [NSString stringWithFormat:@"%.1f", UIApplication.displayMode.fixedHeight]; + fixedAspect.text = [NSString stringWithFormat:@"%.1f", UIApplication.displayMode.fixedAspectRatio]; + magnification.text = [NSString stringWithFormat:@"%.2f", UIApplication.displayMode.magnification]; + hostScreenScale.text = [NSString stringWithFormat:@"%.2f", UIApplication.displayMode.hostScreenScale]; + scale.text = [NSString stringWithFormat:@"%.2f", [uiScreen scale]]; + nativeScale.text = [NSString stringWithFormat:@"%.2f", [uiScreen nativeScale]]; + CGRect nativeBoundRect = [uiScreen nativeBounds]; + nativeBounds.text = [NSString stringWithFormat:@"%.2f, %.2f", nativeBoundRect.size.width, nativeBoundRect.size.height]; } --(NSInteger) pickerView: (UIPickerView *) view numberOfRowsInComponent: (NSInteger) component -{ - if ( view == presets ) { +- (NSInteger)pickerView:(UIPickerView*)view numberOfRowsInComponent:(NSInteger)component { + if (view == presets) { return [_presetNames count]; - } else if ( view == orientations ) { + } else if (view == orientations) { return [_orientationNames count]; - } else return 0; + } else { + return 0; + } } --(NSString *) pickerView: (UIPickerView *) view titleForRow: (NSInteger) row forComponent: (NSInteger) component -{ - if ( view == presets ) { +- (NSString*)pickerView:(UIPickerView*)view titleForRow:(NSInteger)row forComponent:(NSInteger)component { + if (view == presets) { return _presetNames[row]; - } else if ( view == orientations ) { + } else if (view == orientations) { return _orientationNames[row]; - } else return nil; + } else { + return nil; + } } --(NSInteger) numberOfComponentsInPickerView: (UIPickerView *) view -{ +- (NSInteger)numberOfComponentsInPickerView:(UIPickerView*)view { return 1; } --(void) pickerView: (UIPickerView *) view didSelectRow: (NSInteger) row inComponent: (NSInteger) component -{ - if ( view == presets ) { - if ( row == 0 ) return; +- (void)pickerView:(UIPickerView*)view didSelectRow:(NSInteger)row inComponent:(NSInteger)component { + if (view == presets) { + if (row == 0) { + return; + } - [UIApplication.displayMode setDisplayPreset: (WOCDisplayPreset) (row - 1)]; + [UIApplication.displayMode setDisplayPreset:(WOCDisplayPreset)(row - 1)]; [UIApplication.displayMode updateDisplaySettings]; - } else if ( view == orientations ) { - switch ( row ) { - case 0: + } else if (view == orientations) { + switch (row) { + case 0: UIApplication.displayMode.presentationTransform = UIInterfaceOrientationPortrait; break; - case 1: + case 1: UIApplication.displayMode.presentationTransform = UIInterfaceOrientationLandscapeLeft; break; - - case 2: + + case 2: UIApplication.displayMode.presentationTransform = UIInterfaceOrientationLandscapeRight; break; - - case 3: + + case 3: UIApplication.displayMode.presentationTransform = UIInterfaceOrientationPortraitUpsideDown; break; } @@ -160,17 +190,17 @@ -(void) pickerView: (UIPickerView *) view didSelectRow: (NSInteger) row inCompon } } -- (id) init { +- (id)init { self = [super init]; self.rows = [NSMutableArray new]; - UITableViewCell *cell; - - presets = [[UIPickerView alloc] initWithFrame: CGRectMake(0, 0, 200, 200)]; + UITableViewCell* cell; + uiScreen = [[UIScreen alloc] init]; + presets = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)]; cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MenuCell"]; cell.accessoryView = presets; cell.textLabel.text = @"Preset modes"; - [self.rows addObject: cell]; + [self.rows addObject:cell]; presets.dataSource = self; _presetNames = @[ @@ -183,150 +213,183 @@ - (id) init { @"Native320Fixed", @"Native768Fixed", @"Native4x3Aspect", - @"Native16x9Aspect" ]; + @"Native16x9Aspect" + ]; - [presets selectRow: 4 inComponent: 0 animated: FALSE]; + [presets selectRow:4 inComponent:0 animated:FALSE]; presets.delegate = self; - orientations = [[UIPickerView alloc] initWithFrame: CGRectMake(0, 0, 200, 200)]; + orientations = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)]; cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MenuCell"]; cell.accessoryView = orientations; cell.textLabel.text = @"Presentation Transform"; - [self.rows addObject: cell]; + [self.rows addObject:cell]; orientations.dataSource = self; - _orientationNames = @[ - @"Portrait", - @"LandscapeLeft", - @"LandscapeRight", - @"PortraitUpsideDown" ]; + _orientationNames = @[ @"Portrait", @"LandscapeLeft", @"LandscapeRight", @"PortraitUpsideDown" ]; - [orientations selectRow: 0 inComponent: 0 animated: FALSE]; + [orientations selectRow:0 inComponent:0 animated:FALSE]; orientations.delegate = self; - UISwitch *fitToWindow = [UISwitch new]; + UISwitch* fitToWindow = [UISwitch new]; fitToWindow.on = UIApplication.displayMode.autoMagnification; - [fitToWindow addTarget: self action: @selector(toggleFitToWindow:) forControlEvents: UIControlEventValueChanged]; + [fitToWindow addTarget:self action:@selector(toggleFitToWindow:) forControlEvents:UIControlEventValueChanged]; cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MenuCell"]; cell.accessoryView = fitToWindow; cell.textLabel.text = @"Auto magnification"; - [self.rows addObject: cell]; - - UISwitch *adjustWindowSize = [UISwitch new]; + [self.rows addObject:cell]; + + UISwitch* adjustWindowSize = [UISwitch new]; adjustWindowSize.on = UIApplication.displayMode.sizeUIWindowToFit; - [adjustWindowSize addTarget: self action: @selector(toggleAdjustWindowSize:) forControlEvents: UIControlEventValueChanged]; + [adjustWindowSize addTarget:self action:@selector(toggleAdjustWindowSize:) forControlEvents:UIControlEventValueChanged]; cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MenuCell"]; cell.accessoryView = adjustWindowSize; cell.textLabel.text = @"Size UIWindow to fit"; - [self.rows addObject: cell]; - - fixedWidth = [[UITextField alloc] initWithFrame: CGRectMake(0, 0, 100, 20)]; - fixedWidth.text = [NSString stringWithFormat: @"%.1f", UIApplication.displayMode.fixedWidth]; + [self.rows addObject:cell]; + + fixedWidth = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 20)]; + fixedWidth.text = [NSString stringWithFormat:@"%.1f", UIApplication.displayMode.fixedWidth]; fixedWidth.borderStyle = UITextBorderStyleBezel; - [fixedWidth addTarget: self action: @selector(setWidth:) forControlEvents: UIControlEventEditingDidEnd]; + [fixedWidth addTarget:self action:@selector(setWidth:) forControlEvents:UIControlEventEditingDidEnd]; cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"MenuCell"]; cell.accessoryView = fixedWidth; cell.textLabel.text = @"Fixed width"; cell.detailTextLabel.text = @"0.0 = fit to window"; - [self.rows addObject: cell]; - - fixedHeight = [[UITextField alloc] initWithFrame: CGRectMake(0, 0, 100, 20)]; - fixedHeight.text = [NSString stringWithFormat: @"%.1f", UIApplication.displayMode.fixedHeight]; + [self.rows addObject:cell]; + + fixedHeight = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 20)]; + fixedHeight.text = [NSString stringWithFormat:@"%.1f", UIApplication.displayMode.fixedHeight]; fixedHeight.borderStyle = UITextBorderStyleBezel; - [fixedHeight addTarget: self action: @selector(setHeight:) forControlEvents: UIControlEventEditingDidEnd]; + [fixedHeight addTarget:self action:@selector(setHeight:) forControlEvents:UIControlEventEditingDidEnd]; cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"MenuCell"]; cell.accessoryView = fixedHeight; cell.textLabel.text = @"Fixed height"; cell.detailTextLabel.text = @"0.0 = fit to window"; - [self.rows addObject: cell]; - - fixedAspect = [[UITextField alloc] initWithFrame: CGRectMake(0, 0, 100, 20)]; - fixedAspect.text = [NSString stringWithFormat: @"%.1f", UIApplication.displayMode.fixedAspectRatio]; + [self.rows addObject:cell]; + + fixedAspect = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 20)]; + fixedAspect.text = [NSString stringWithFormat:@"%.1f", UIApplication.displayMode.fixedAspectRatio]; fixedAspect.borderStyle = UITextBorderStyleBezel; - [fixedAspect addTarget: self action: @selector(setAspect:) forControlEvents: UIControlEventEditingDidEnd]; + [fixedAspect addTarget:self action:@selector(setAspect:) forControlEvents:UIControlEventEditingDidEnd]; cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"MenuCell"]; cell.accessoryView = fixedAspect; cell.textLabel.text = @"Fixed aspect ratio"; cell.detailTextLabel.text = @"0.0 = none"; - [self.rows addObject: cell]; - - magnification = [[UITextField alloc] initWithFrame: CGRectMake(0, 0, 100, 20)]; - magnification.text = [NSString stringWithFormat: @"%.2f", UIApplication.displayMode.magnification]; + [self.rows addObject:cell]; + + magnification = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 20)]; + magnification.text = [NSString stringWithFormat:@"%.2f", UIApplication.displayMode.magnification]; magnification.borderStyle = UITextBorderStyleBezel; - [magnification addTarget: self action: @selector(setMagnification:) forControlEvents: UIControlEventEditingDidEnd]; + [magnification addTarget:self action:@selector(setMagnification:) forControlEvents:UIControlEventEditingDidEnd]; cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MenuCell"]; cell.accessoryView = magnification; cell.textLabel.text = @"Magnification"; - [self.rows addObject: cell]; + [self.rows addObject:cell]; + + scale = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 20)]; + scale.text = [NSString stringWithFormat:@"%.2f", [uiScreen scale]]; + scale.borderStyle = UITextBorderStyleBezel; + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MenuCell"]; + cell.accessoryView = scale; + cell.textLabel.text = @"Scale"; + [self.rows addObject:cell]; + + nativeScale = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 20)]; + nativeScale.text = [NSString stringWithFormat:@"%.2f", [uiScreen nativeScale]]; + nativeScale.borderStyle = UITextBorderStyleBezel; + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MenuCell"]; + cell.accessoryView = nativeScale; + cell.textLabel.text = @"Native Scale"; + [self.rows addObject:cell]; + + nativeBounds = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 150, 20)]; + CGRect nativeBoundRect = [uiScreen nativeBounds]; + nativeBounds.text = [NSString stringWithFormat:@"%.2f, %.2f", nativeBoundRect.size.width, nativeBoundRect.size.height]; + nativeBounds.borderStyle = UITextBorderStyleBezel; + nativeBounds.adjustsFontSizeToFitWidth = TRUE; + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MenuCell"]; + cell.accessoryView = nativeBounds; + cell.textLabel.text = @"Native Bounds"; + [self.rows addObject:cell]; + + uiScreenBrightness = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 20)]; + uiScreenBrightness.text = [NSString stringWithFormat:@"%.2f", [uiScreen brightness]]; + uiScreenBrightness.borderStyle = UITextBorderStyleBezel; + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MenuCell"]; + cell.accessoryView = uiScreenBrightness; + cell.textLabel.text = @"Brightness"; + [self.rows addObject:cell]; _informationLabels = @[ [@{ @"LabelName" : @"Current App Size", - @"ValueName" : @"currentSize" } mutableCopy], + @"ValueName" : @"currentSize" } mutableCopy], [@{ @"LabelName" : @"Current App Magnfication", - @"ValueName" : @"currentMagnification" } mutableCopy], + @"ValueName" : @"currentMagnification" } mutableCopy], [@{ @"LabelName" : @"Host Window Size (Points)", - @"ValueName" : @"hostWindowSize" } mutableCopy], + @"ValueName" : @"hostWindowSize" } mutableCopy], [@{ @"LabelName" : @"Host Screen Size (Pixels)", - @"ValueName" : @"hostScreenSizePixels" } mutableCopy], + @"ValueName" : @"hostScreenSizePixels" } mutableCopy], [@{ @"LabelName" : @"Host Screen Scale (pixels per point)", - @"ValueName" : @"hostScreenScale" } mutableCopy], + @"ValueName" : @"hostScreenScale" } mutableCopy], [@{ @"LabelName" : @"Host Screen Size (Points)", - @"ValueName" : @"hostScreenSizePoints" } mutableCopy], + @"ValueName" : @"hostScreenSizePoints" } mutableCopy], [@{ @"LabelName" : @"Host Screen Size (Inches)", - @"ValueName" : @"hostScreenSizeInches" } mutableCopy] + @"ValueName" : @"hostScreenSizeInches" } mutableCopy], + ]; - for ( NSMutableDictionary *curItem in _informationLabels ) { - UILabel *label = [[UILabel alloc] initWithFrame: CGRectMake(0, 0, 100, 20)]; - label.text = [UIApplication.displayMode valueForKey: curItem[@"ValueName"]]; + for (NSMutableDictionary* curItem in _informationLabels) { + UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 20)]; + label.text = [UIApplication.displayMode valueForKey:curItem[@"ValueName"]]; label.adjustsFontSizeToFitWidth = TRUE; cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"MenuCell"]; cell.accessoryView = label; cell.textLabel.text = curItem[@"LabelName"]; cell.detailTextLabel.text = curItem[@"ValueName"]; - [self.rows addObject: cell]; + [self.rows addObject:cell]; curItem[@"Cell"] = cell; } - [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(updateLabels) name: UIApplicationDidChangeDisplayModeNofication object: nil]; - + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(updateLabels) + name:UIApplicationDidChangeDisplayModeNofication + object:nil]; + return self; } -- (void)viewDidLoad -{ +- (void)viewDidLoad { [super viewDidLoad]; - + self.title = @"Display Mode"; - + [self tableView].allowsSelection = NO; } -- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { - if ( indexPath.row == 0 || indexPath.row == 1 ) { +- (float)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath { + if (indexPath.row == 0 || indexPath.row == 1) { // Picker view return 240.0f; } return 50.0f; } -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { +- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section { return [_rows count]; } -- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { +- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath { return [_rows objectAtIndex:indexPath.row]; } - @end #endif \ No newline at end of file diff --git a/samples/WOCCatalog/WOCCatalog/SearchBarViewController.m b/samples/WOCCatalog/WOCCatalog/SearchBarViewController.m index 031f48c6d7..5a8dad9ef5 100644 --- a/samples/WOCCatalog/WOCCatalog/SearchBarViewController.m +++ b/samples/WOCCatalog/WOCCatalog/SearchBarViewController.m @@ -24,36 +24,30 @@ - (void)viewDidLoad { [self tableView].allowsSelection = NO; } -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - +- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section { return 1; } -- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath -{ - return 50; +- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath { + return 100; } -- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - - UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MenuCell"]; +- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath { + UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"MenuCell"]; if (nil == cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MenuCell"]; } - + [super viewDidLoad]; - - self.title = @"SearchBar"; - + + self.title = @"UISearchBar"; self.view.backgroundColor = [UIColor groupTableViewBackgroundColor]; - - UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0.0, 0.0, cell.bounds.size.width, 40.0)]; - //self.searchBar.delegate = self; - searchBar.showsCancelButton = YES; - searchBar.showsBookmarkButton = YES; - [cell addSubview: searchBar]; - [searchBar setAutoresizingMask: UIViewAutoresizingFlexibleWidth]; - + + UISearchBar* searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(10, 10, cell.bounds.size.width, 80)]; + [searchBar setPrompt:@"This is the prompt"]; + [searchBar setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; + [cell addSubview:searchBar]; + return cell; } diff --git a/samples/WOCCatalog/WOCCatalog/TextViewViewController.m b/samples/WOCCatalog/WOCCatalog/TextViewViewController.m index 9643383492..5947fc7d7c 100644 --- a/samples/WOCCatalog/WOCCatalog/TextViewViewController.m +++ b/samples/WOCCatalog/WOCCatalog/TextViewViewController.m @@ -20,22 +20,31 @@ @implementation TextViewViewController - (void)viewDidLoad { [super viewDidLoad]; - + self.textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)]; self.textView.textColor = [UIColor blackColor]; - self.textView.font = [UIFont fontWithName:@"Arial" size:18.0]; + UIFontDescriptor* des = [UIFontDescriptor fontDescriptorWithName:@"Calibri" size:18.0]; + des = [des fontDescriptorWithSymbolicTraits:(UIFontDescriptorTraitBold | UIFontDescriptorTraitItalic)]; + self.textView.font = [UIFont fontWithDescriptor:des size:20.0]; self.textView.backgroundColor = [UIColor whiteColor]; - - self.textView.text = @"Lorem ipsum dolor sit amet lorem a ut massa quam tempus maecenas. Eu consequat ipsum magnis quisque. Etiam luctus dictum natoque ullamcorper dolor quam quisque metus. Dui imperdiet eget ante tellus. Nullam sem aenean. Pede donec lorem ultricies eleifend imperdiet integer phasellus blandit dictum nulla eget. Nulla fringilla sit pulvinar eu vel semper orci. Vel lorem ante ut. Eleifend vulputate rhoncus. Ultricies dolor venenatis amet sit aenean ante magnis imperdiet rhoncus tellus elementum. Etiam amet ante enim. Tellus adipiscing consequat. Dolor justo adipiscing nisi amet. Adipiscing aliquam eleifend lorem ante fringilla integer elementum quis felis libero pretium justo. Veni tellus id. Etiam quam vitae leo aenean et vivamus rhoncus nec. Nulla adipiscing parturient sit porttitor et nec quam ultricies integer nullam. Lorem dui eu vitae ultricies tellus eget quis felis dolor tincidunt aenean semper. Vitae quis dolor natoque eleifend justo phasellus mollis pulvinar venenatis ac pede sem pellentesque. Eget commodo nam quam sem ipsum vici ligula ante."; + + self.textView.text = @"Lorem ipsum dolor sit amet lorem a ut massa quam tempus maecenas. Eu consequat ipsum magnis quisque. Etiam " + @"luctus dictum natoque ullamcorper dolor quam quisque metus. Dui imperdiet eget ante tellus. Nullam sem aenean. " + @"Pede donec lorem ultricies eleifend imperdiet integer phasellus blandit dictum nulla eget. Nulla fringilla sit " + @"pulvinar eu vel semper orci. Vel lorem ante ut. Eleifend vulputate rhoncus. Ultricies dolor venenatis amet sit " + @"aenean ante magnis imperdiet rhoncus tellus elementum. Etiam amet ante enim. Tellus adipiscing consequat. " + @"Dolor justo adipiscing nisi amet. Adipiscing aliquam eleifend lorem ante fringilla integer elementum quis " + @"felis libero pretium justo. Veni tellus id. Etiam quam vitae leo aenean et vivamus rhoncus nec. Nulla " + @"adipiscing parturient sit porttitor et nec quam ultricies integer nullam. Lorem dui eu vitae ultricies tellus " + @"eget quis felis dolor tincidunt aenean semper. Vitae quis dolor natoque eleifend justo phasellus mollis " + @"pulvinar venenatis ac pede sem pellentesque. Eget commodo nam quam sem ipsum vici ligula ante."; self.textView.returnKeyType = UIReturnKeyDefault; self.textView.keyboardType = UIKeyboardTypeDefault; self.textView.scrollEnabled = YES; self.textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - - [self.view addSubview: self.textView]; + + [self.view addSubview:self.textView]; } @end - - diff --git a/tests/unittests/Accessibility.mm b/tests/unittests/Accessibility.mm new file mode 100644 index 0000000000..c3f2479605 --- /dev/null +++ b/tests/unittests/Accessibility.mm @@ -0,0 +1,25 @@ +#include "gtest-api.h" + +#import +#import "Starboard.h" +#import "CALayerInternal.h" +#import "NullCompositor.h" + +TEST(Accessibility, accessors) +{ + SetCACompositor(new NullCompositor); + + auto button = [[UIButton alloc] init]; + button.isAccessibilityElement = TRUE; + button.accessibilityHint = @"TestHint"; + + EXPECT_TRUE_MSG(button.isAccessibilityElement == TRUE, "Bad accessor"); + EXPECT_TRUE_MSG([button.accessibilityHint isEqualToString: @"TestHint"], "Bad accessor"); + + auto item = [[UIBarButtonItem alloc] init]; + item.isAccessibilityElement = TRUE; + item.accessibilityHint = @"TestHint"; + + EXPECT_TRUE_MSG(item.isAccessibilityElement == TRUE, "Bad accessor"); + EXPECT_TRUE_MSG([item.accessibilityHint isEqualToString: @"TestHint"], "Bad accessor"); +} diff --git a/tests/unittests/Foundation/NSOperation.mm b/tests/unittests/Foundation/NSOperation.mm new file mode 100644 index 0000000000..41fef64448 --- /dev/null +++ b/tests/unittests/Foundation/NSOperation.mm @@ -0,0 +1,60 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#include "gtest-api.h" +#import + +TEST(Foundation, NSOperation) { + NSOperationQueue* queue = [[NSOperationQueue alloc] init]; + + NSOperation* operation = [[NSOperation alloc] init]; + __block bool completed = false; + + [operation setCompletionBlock:^{ + [operation waitUntilFinished]; // Should not deadlock, but we cannot test this + completed = [operation isFinished]; + }]; + + [queue addOperation:operation]; + + [operation waitUntilFinished]; + + ASSERT_TRUE(completed); + ASSERT_EQ(completed, [operation isFinished]); + ASSERT_FALSE([operation isExecuting]); +} + +TEST(Foundation, NSOperationCancellation) { + NSOperationQueue* queue = [[NSOperationQueue alloc] init]; + + NSOperation* cancelledOperation = [[NSOperation alloc] init]; + __block bool cancelledOperationCompleted = false; + + [cancelledOperation setCompletionBlock:^{ + [cancelledOperation waitUntilFinished]; // Should not deadlock, but we cannot test this + cancelledOperationCompleted = [cancelledOperation isFinished]; + }]; + + [cancelledOperation cancel]; + + [queue addOperation:cancelledOperation]; + + [cancelledOperation waitUntilFinished]; + + ASSERT_TRUE(cancelledOperationCompleted); + ASSERT_FALSE([cancelledOperation isExecuting]); + ASSERT_TRUE([cancelledOperation isCancelled]); +} diff --git a/tests/unittests/NSLayoutConstraint.mm b/tests/unittests/NSLayoutConstraint.mm index 9c49f8ccee..0559e7f481 100644 --- a/tests/unittests/NSLayoutConstraint.mm +++ b/tests/unittests/NSLayoutConstraint.mm @@ -19,82 +19,10 @@ #import #import "Starboard.h" #import "CALayerInternal.h" +#import "NullCompositor.h" #include -class NullCompositor : public CACompositorInterface -{ -public: - void DisplayTreeChanged() override { } - void ProcessTransactions() override { } - void RequestRedraw() override { } - DisplayNode* CreateDisplayNode() override { return nullptr; } - DisplayTransaction* CreateDisplayTransaction() override { return nullptr; } - void QueueDisplayTransaction(DisplayTransaction* transaction, DisplayTransaction* onTransaction) override { } - - void sortWindowLevels() override { } - - void addNode(DisplayTransaction* transaction, DisplayNode* node, DisplayNode* superNode, DisplayNode* beforeNode, DisplayNode* afterNode) override { } - void moveNode(DisplayTransaction* transaction, DisplayNode* node, DisplayNode* beforeNode, DisplayNode* afterNode) override { } - void removeNode(DisplayTransaction* transaction, DisplayNode* pNode) override { } - - void addAnimation(DisplayTransaction* transaction, id layer, id animation, id forKey) override { } - void addAnimationRaw(DisplayTransaction* transaction, DisplayNode* pNode, DisplayAnimation* pAnimation) override { } - void removeAnimationRaw(DisplayTransaction* transaction, DisplayNode* pNode, DisplayAnimation* pAnimation) override { } - - void setDisplayProperty(DisplayTransaction* transaction, DisplayNode* node, const char* propertyName, NSObject* newValue) override { } - - void setNodeTexture(DisplayTransaction* transaction, DisplayNode* node, DisplayTexture* newTexture, CGSize contentsSize, float contentsScale) override { } - void setNodeMaskNode(DisplayNode* node, DisplayNode* maskNode) override { } - NSObject* getDisplayProperty(DisplayNode* node, const char* propertyName = NULL) override { return nil; } - - void setNodeTopMost(DisplayNode* node, bool topMost) override { } - void setNodeTopWindowLevel(DisplayNode* node, float level) override { } - - DisplayTexture* GetDisplayTextureForCGImage(CGImageRef img, bool create) override { return nullptr; } - DisplayTexture* CreateDisplayTextureForText() override { return nullptr; } - void SetTextDisplayTextureParams(DisplayTexture* texture, id font, id text, id color, UITextAlignment alignment, UILineBreakMode lineBreak, id shadowColor, - const CGSize &shadowOffset, int numLines, UIEdgeInsets edgeInsets, bool centerVertically) override { } - DisplayTexture* CreateDisplayTextureForElement(id xamlElement) override { return nullptr; } - - DisplayAnimation* GetBasicDisplayAnimation(id caanim, NSString* propertyName, NSObject* fromValue, NSObject* toValue, CAMediaTimingProperties* timingProperties) override { return nullptr; } - DisplayAnimation* GetMoveDisplayAnimation(DisplayAnimation** secondAnimRet, id caanim, DisplayNode* animNode, NSString* type, NSString* subtype, CAMediaTimingProperties* timingProperties) override { return nullptr; } - - void RetainAnimation(DisplayAnimation* animation) override { } - void ReleaseAnimation(DisplayAnimation* animation) override { } - - void RetainNode(DisplayNode* node) override { } - void ReleaseNode(DisplayNode* node) override { } - - void RetainDisplayTexture(DisplayTexture* tex) override { } - void ReleaseDisplayTexture(DisplayTexture* tex) override { } - - void SortWindowLevels() override { } - bool isTablet() override { return false; } - float screenWidth() override { return 100.0f; } - float screenHeight() override { return 100.0f; } - float screenScale() override { return 1.0f; } - int deviceWidth() override { return 100; } - int deviceHeight() override { return 100; } - float screenXDpi() override { return 100; } - float screenYDpi() override { return 100; } - - void setScreenSize(float width, float height, float scale, float rotationClockwise) override { } - void setDeviceSize(int width, int height) override { } - void setScreenDpi(int xDpi, int yDpi) override { } - void setTablet(bool isTablet) override { } - - DisplayTexture* CreateWritableBitmapTexture32(int width, int height) override { return nullptr; } - void* LockWritableBitmapTexture(DisplayTexture* tex, int* stride) override { return nullptr; } - void UnlockWritableBitmapTexture(DisplayTexture* tex) override { } - - void EnableDisplaySyncNotification() override { } - void DisableDisplaySyncNotification() override { } - - void IncrementCounter(const char* name) override { } - void DecrementCounter(const char* name) override { } -}; - // We're loading outside the context of a UWP, so LoadPackagedModule in UIView.mm will fail. static void initAutoLayout() { static bool initialized; @@ -293,4 +221,4 @@ static void initAutoLayout() { [topLevelView addConstraints:layoutConstraints]; EXPECT_EQ(numConstraints, [topLevelView.constraints count]) << "Unrelated constraints added to view:\n" << ::testing::PrintToString(layoutConstraints); -} \ No newline at end of file +} diff --git a/tests/unittests/NSURL.m b/tests/unittests/NSURL.m new file mode 100644 index 0000000000..9b8ae16d3c --- /dev/null +++ b/tests/unittests/NSURL.m @@ -0,0 +1,70 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#include "gtest-api.h" +#import + +void testNSURLMethod(SEL selector, NSURL* input, id argument, NSURL* expected) { + NSURL* actual = [input performSelector:selector withObject:argument]; + ASSERT_OBJCEQ_MSG(expected, actual, "FAILED: expected != actual"); +} + +TEST(NSFoundation, NSURLTests) { + NSURL* testURL = [[NSURL alloc] initWithString:@"http://www.test.com/home/index.html?Foo#24"]; + NSURL* testURL2 = [[NSURL alloc] initWithString:@"http://www.test.com/"]; + NSURL* testURL3 = [[NSURL alloc] initWithString:@"http://www.test.com/home/asdf/./index.html?Foo#24"]; + NSURL* testURL4 = [[NSURL alloc] initWithString:@"file://www.test.com/home/../home/./index.html?Foo#24"]; + NSURL* testURL5 = [[NSURL alloc] initWithString:@"http://www.test.com?Foo#24"]; + NSURL* testURL6 = [[NSURL alloc] initWithString:@"http://www.test.com/home.page/asdf"]; + NSURL* testURL7 = [[NSURL alloc] initWithString:@"http://www.test.com/.foo"]; + + // URLByDeletingPathExtension tests + testNSURLMethod(@selector(URLByDeletingPathExtension), testURL, nil, [[NSURL alloc] initWithString:@"http://www.test.com/home/index?Foo#24"]); + testNSURLMethod(@selector(URLByDeletingPathExtension), testURL2, nil, [[NSURL alloc] initWithString:@"http://www.test.com/"]); + testNSURLMethod(@selector(URLByDeletingPathExtension), testURL3, nil, [[NSURL alloc] initWithString:@"http://www.test.com/home/asdf/./index?Foo#24"]); + testNSURLMethod(@selector(URLByDeletingPathExtension), testURL4, nil, [[NSURL alloc] initWithString:@"file://www.test.com/home/../home/./index?Foo#24"]); + testNSURLMethod(@selector(URLByDeletingPathExtension), testURL5, nil, [[NSURL alloc] initWithString:@"http://www.test.com?Foo#24"]); + testNSURLMethod(@selector(URLByDeletingPathExtension), testURL6, nil, [[NSURL alloc] initWithString:@"http://www.test.com/home.page/asdf"]); + testNSURLMethod(@selector(URLByDeletingPathExtension), testURL7, nil, [[NSURL alloc] initWithString:@"http://www.test.com/"]); + + // URLByDeletingLastPathComponent + testNSURLMethod(@selector(URLByDeletingLastPathComponent), testURL, nil, [[NSURL alloc] initWithString:@"http://www.test.com/home?Foo#24"]); + testNSURLMethod(@selector(URLByDeletingLastPathComponent), testURL2, nil, [[NSURL alloc] initWithString:@"http://www.test.com/../"]); + testNSURLMethod(@selector(URLByDeletingLastPathComponent), testURL3, nil, [[NSURL alloc] initWithString:@"http://www.test.com/home/asdf/.?Foo#24"]); + testNSURLMethod(@selector(URLByDeletingLastPathComponent), testURL4, nil, [[NSURL alloc] initWithString:@"file://www.test.com/home/../home/.?Foo#24"]); + testNSURLMethod(@selector(URLByDeletingLastPathComponent), testURL5, nil, [[NSURL alloc] initWithString:@"http://www.test.com../?Foo#24"]); + testNSURLMethod(@selector(URLByDeletingLastPathComponent), testURL6, nil, [[NSURL alloc] initWithString:@"http://www.test.com/home.page"]); + testNSURLMethod(@selector(URLByDeletingLastPathComponent), testURL7, nil, [[NSURL alloc] initWithString:@"http://www.test.com/"]); + + // URLByStandardizingPath + testNSURLMethod(@selector(URLByStandardizingPath), testURL, nil, [[NSURL alloc] initWithString:@"http://www.test.com/home/index.html?Foo#24"]); + testNSURLMethod(@selector(URLByStandardizingPath), testURL2, nil, [[NSURL alloc] initWithString:@"http://www.test.com/"]); + testNSURLMethod(@selector(URLByStandardizingPath), testURL3, nil, [[NSURL alloc] initWithString:@"http://www.test.com/home/asdf/./index.html?Foo#24"]); + testNSURLMethod(@selector(URLByStandardizingPath), testURL4, nil, [[NSURL alloc] initWithString:@"file://www.test.com/home/index.html?Foo#24"]); + testNSURLMethod(@selector(URLByStandardizingPath), testURL5, nil, [[NSURL alloc] initWithString:@"http://www.test.com?Foo#24"]); + testNSURLMethod(@selector(URLByStandardizingPath), testURL6, nil, [[NSURL alloc] initWithString:@"http://www.test.com/home.page/asdf"]); + testNSURLMethod(@selector(URLByStandardizingPath), testURL7, nil, [[NSURL alloc] initWithString:@"http://www.test.com/.foo"]); + + // URLByAppendingPathExtension + NSString* extension = @"txt"; + testNSURLMethod(@selector(URLByAppendingPathExtension:), testURL, extension, [[NSURL alloc] initWithString:@"http://www.test.com/home/index.html.txt?Foo#24"]); + testNSURLMethod(@selector(URLByAppendingPathExtension:), testURL2, extension, [[NSURL alloc] initWithString:@"http://www.test.com/.txt"]); + testNSURLMethod(@selector(URLByAppendingPathExtension:), testURL3, extension, [[NSURL alloc] initWithString:@"http://www.test.com/home/asdf/./index.html.txt?Foo#24"]); + testNSURLMethod(@selector(URLByAppendingPathExtension:), testURL4, extension, [[NSURL alloc] initWithString:@"file://www.test.com/home/../home/./index.html.txt?Foo#24"]); + testNSURLMethod(@selector(URLByAppendingPathExtension:), testURL5, extension, [[NSURL alloc] initWithString:@"http://www.test.com.txt?Foo#24"]); + testNSURLMethod(@selector(URLByAppendingPathExtension:), testURL6, extension, [[NSURL alloc] initWithString:@"http://www.test.com/home.page/asdf.txt"]); + testNSURLMethod(@selector(URLByAppendingPathExtension:), testURL7, extension, [[NSURL alloc] initWithString:@"http://www.test.com/.foo.txt"]); +} \ No newline at end of file diff --git a/tests/unittests/NSURLSessionConfiguration.m b/tests/unittests/NSURLSessionConfiguration.m new file mode 100644 index 0000000000..457f7aba72 --- /dev/null +++ b/tests/unittests/NSURLSessionConfiguration.m @@ -0,0 +1,90 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#include "gtest-api.h" +#import +#import + +TEST(Foundation, NSURLSessionConfiguration_initValues) { + NSURLSessionConfiguration* sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; + ASSERT_TRUE_MSG(sessionConfiguration != NULL, "FAILED: sessionConfiguration should be non-null!"); + + ASSERT_EQ_MSG(YES, sessionConfiguration.allowsCellularAccess, "FAILED: allowsCellularAccess should be YES"); + ASSERT_EQ_MSG(60, sessionConfiguration.timeoutIntervalForRequest, "FAILED: timeoutIntervalForRequest should be %d", 60); + ASSERT_EQ_MSG(7, sessionConfiguration.timeoutIntervalForResource, "FAILED: timeoutIntervalForResource should be %d", 7); + ASSERT_EQ_MSG(NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain, + sessionConfiguration.HTTPCookieAcceptPolicy, + "FAILED: HTTPCookieAcceptPolicy should be %d", + NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain); + ASSERT_EQ_MSG(YES, sessionConfiguration.HTTPShouldSetCookies, "FAILED: HTTPShouldSetCookies should be YES"); + ASSERT_EQ_MSG(NSURLNetworkServiceTypeDefault, + sessionConfiguration.networkServiceType, + "FAILED: networkServiceType should be %d", + NSURLNetworkServiceTypeDefault); + ASSERT_EQ_MSG(NSURLRequestUseProtocolCachePolicy, + sessionConfiguration.requestCachePolicy, + "FAILED: requestCachePolicy should be %d", + NSURLRequestUseProtocolCachePolicy); + ASSERT_EQ_MSG(6, sessionConfiguration.HTTPMaximumConnectionsPerHost, "FAILED: HTTPMaximumConnectionsPerHost should be %d", 6); + ASSERT_TRUE_MSG(sessionConfiguration.HTTPCookieStorage != NULL, "FAILED: HTTPCookieStorage should be non-null"); +} + +TEST(Foundation, NSURLSessionConfiguration_defaultSessionConfiguration) { + NSURLSessionConfiguration* sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; + ASSERT_TRUE_MSG(sessionConfiguration != NULL, "FAILED: sessionConfiguration should be non-null!"); + + ASSERT_EQ_MSG(YES, sessionConfiguration.allowsCellularAccess, "FAILED: allowsCellularAccess should be YES"); + ASSERT_EQ_MSG(kTLSProtocol12, + sessionConfiguration.TLSMaximumSupportedProtocol, + "FAILED: TLSMaximumSupportedProtocol should be %d", + kTLSProtocol12); + ASSERT_EQ_MSG(kSSLProtocol3, + sessionConfiguration.TLSMinimumSupportedProtocol, + "FAILED: TLSMinimumSupportedProtocol should be %d", + kSSLProtocol3); +} + +TEST(Foundation, NSURLSessionConfiguration_ephemeralSessionConfiguration) { + NSURLSessionConfiguration* sessionConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration]; + ASSERT_TRUE_MSG(sessionConfiguration != NULL, "FAILED: sessionConfiguration should be non-null!"); + + ASSERT_EQ_MSG(kTLSProtocol12, + sessionConfiguration.TLSMaximumSupportedProtocol, + "FAILED: TLSMaximumSupportedProtocol should be %d", + kTLSProtocol12); + ASSERT_EQ_MSG(kTLSProtocol1, + sessionConfiguration.TLSMinimumSupportedProtocol, + "FAILED: TLSMinimumSupportedProtocol should be %d", + kTLSProtocol1); + ASSERT_TRUE_MSG(sessionConfiguration.URLCache != NULL, "FAILED: URLCache should be non-null"); +} + +TEST(Foundation, NSURLSessionConfiguration_backgroundSessionConfigurationWithIdentifier) { + NSString* identifier = @"Microsoft"; + NSURLSessionConfiguration* sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:identifier]; + ASSERT_TRUE_MSG(sessionConfiguration != NULL, "FAILED: sessionConfiguration should be non-null!"); + + ASSERT_EQ_MSG(kTLSProtocol12, + sessionConfiguration.TLSMaximumSupportedProtocol, + "FAILED: TLSMaximumSupportedProtocol should be %d", + kTLSProtocol12); + ASSERT_EQ_MSG(kTLSProtocol1, + sessionConfiguration.TLSMinimumSupportedProtocol, + "FAILED: TLSMinimumSupportedProtocol should be %d", + kTLSProtocol1); + ASSERT_OBJCEQ_MSG(identifier, sessionConfiguration.identifier, "FAILED: identifier should be %d", identifier); + ASSERT_TRUE_MSG(sessionConfiguration.URLCache != NULL, "FAILED: URLCache should be non-null"); +} diff --git a/tests/unittests/NullCompositor.h b/tests/unittests/NullCompositor.h new file mode 100644 index 0000000000..bf9cf06e66 --- /dev/null +++ b/tests/unittests/NullCompositor.h @@ -0,0 +1,91 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +class NullCompositor : public CACompositorInterface +{ +public: + void DisplayTreeChanged() override { } + void ProcessTransactions() override { } + void RequestRedraw() override { } + DisplayNode* CreateDisplayNode() override { return nullptr; } + DisplayTransaction* CreateDisplayTransaction() override { return nullptr; } + void QueueDisplayTransaction(DisplayTransaction* transaction, DisplayTransaction* onTransaction) override { } + + void sortWindowLevels() override { } + + void addNode(DisplayTransaction* transaction, DisplayNode* node, DisplayNode* superNode, DisplayNode* beforeNode, DisplayNode* afterNode) override { } + void moveNode(DisplayTransaction* transaction, DisplayNode* node, DisplayNode* beforeNode, DisplayNode* afterNode) override { } + void removeNode(DisplayTransaction* transaction, DisplayNode* pNode) override { } + + void addAnimation(DisplayTransaction* transaction, id layer, id animation, id forKey) override { } + void addAnimationRaw(DisplayTransaction* transaction, DisplayNode* pNode, DisplayAnimation* pAnimation) override { } + void removeAnimationRaw(DisplayTransaction* transaction, DisplayNode* pNode, DisplayAnimation* pAnimation) override { } + + void setDisplayProperty(DisplayTransaction* transaction, DisplayNode* node, const char* propertyName, NSObject* newValue) override { } + + void setNodeTexture(DisplayTransaction* transaction, DisplayNode* node, DisplayTexture* newTexture, CGSize contentsSize, float contentsScale) override { } + void setNodeMaskNode(DisplayNode* node, DisplayNode* maskNode) override { } + NSObject* getDisplayProperty(DisplayNode* node, const char* propertyName = NULL) override { return nil; } + + void setNodeTopMost(DisplayNode* node, bool topMost) override { } + void setNodeTopWindowLevel(DisplayNode* node, float level) override { } + + DisplayTexture* GetDisplayTextureForCGImage(CGImageRef img, bool create) override { return nullptr; } + DisplayTexture* CreateDisplayTextureForText() override { return nullptr; } + void SetTextDisplayTextureParams(DisplayTexture* texture, id font, id text, id color, UITextAlignment alignment, UILineBreakMode lineBreak, id shadowColor, + const CGSize &shadowOffset, int numLines, UIEdgeInsets edgeInsets, bool centerVertically) override { } + DisplayTexture* CreateDisplayTextureForElement(id xamlElement) override { return nullptr; } + + DisplayAnimation* GetBasicDisplayAnimation(id caanim, NSString* propertyName, NSObject* fromValue, NSObject* toValue, CAMediaTimingProperties* timingProperties) override { return nullptr; } + DisplayAnimation* GetMoveDisplayAnimation(DisplayAnimation** secondAnimRet, id caanim, DisplayNode* animNode, NSString* type, NSString* subtype, CAMediaTimingProperties* timingProperties) override { return nullptr; } + + void RetainAnimation(DisplayAnimation* animation) override { } + void ReleaseAnimation(DisplayAnimation* animation) override { } + + void RetainNode(DisplayNode* node) override { } + void ReleaseNode(DisplayNode* node) override { } + + void RetainDisplayTexture(DisplayTexture* tex) override { } + void ReleaseDisplayTexture(DisplayTexture* tex) override { } + + void SortWindowLevels() override { } + bool isTablet() override { return false; } + float screenWidth() override { return 100.0f; } + float screenHeight() override { return 100.0f; } + float screenScale() override { return 1.0f; } + int deviceWidth() override { return 100; } + int deviceHeight() override { return 100; } + float screenXDpi() override { return 100; } + float screenYDpi() override { return 100; } + + void setScreenSize(float width, float height, float scale, float rotationClockwise) override { } + void setDeviceSize(int width, int height) override { } + void setScreenDpi(int xDpi, int yDpi) override { } + void setTablet(bool isTablet) override { } + + DisplayTexture* CreateWritableBitmapTexture32(int width, int height) override { return nullptr; } + void* LockWritableBitmapTexture(DisplayTexture* tex, int* stride) override { return nullptr; } + void UnlockWritableBitmapTexture(DisplayTexture* tex) override { } + + void EnableDisplaySyncNotification() override { } + void DisableDisplaySyncNotification() override { } + + void IncrementCounter(const char* name) override { } + void DecrementCounter(const char* name) override { } + + virtual void SetAccessibilityInfo(DisplayNode* node, const IWAccessibilityInfo& info) override {} +}; + diff --git a/tests/unittests/foundation.m b/tests/unittests/foundation.m index ce14a2f5f5..d614c892bd 100644 --- a/tests/unittests/foundation.m +++ b/tests/unittests/foundation.m @@ -126,6 +126,23 @@ [[uuidShort description] UTF8String]); } +@interface TestKVOSelfObserver : NSObject { + id _dummy; +} +@end +@implementation TestKVOSelfObserver +- (id)init { + if (self = [super init]) { + [self addObserver:self forKeyPath:@"dummy" options:0 context:nullptr]; + } + return self; +} +- (void)dealloc { + [self removeObserver:self forKeyPath:@"dummy"]; + [super dealloc]; +} +@end + @interface TestKVOChange: NSObject @property (nonatomic, copy) NSString* keypath; @property (nonatomic, assign /*weak but no arc*/) id object; @@ -502,12 +519,21 @@ - (void)incrementManualIntegerProperty { NSMutableDictionary* observed = [NSMutableDictionary dictionary]; TestKVOObserver* observer = [[TestKVOObserver alloc] init]; + [observed setObject:[[[TestKVOObject alloc] init] autorelease] forKey:@"subKey"]; + [observed addObserver:observer forKeyPath:@"arbitraryValue" options:NSKeyValueObservingOptionNew context:NULL]; + [observed addObserver:observer forKeyPath:@"subKey.basicObjectProperty" options:NSKeyValueObservingOptionNew context:NULL]; + [observed setObject:@"Whatever" forKey:@"arbitraryValue"]; + [observed setValue:@"Whatever2" forKeyPath:@"arbitraryValue"]; + [observed setValue:@"Whatever2" forKeyPath:@"subKey.basicObjectProperty"]; EXPECT_EQ_MSG([[observer changesForKeypath:@"arbitraryValue"] count], - 1, + 2, "On a NSMutableDictionary, a change notification for arbitraryValue."); + EXPECT_EQ_MSG([[observer changesForKeypath:@"subKey.basicObjectProperty"] count], + 1, + "On a NSMutableDictionary, a change notification for subKey.basicObjectProperty."); } { // Deregistration test TestKVOObject* observed = [[TestKVOObject alloc] init]; @@ -810,4 +836,8 @@ - (void)incrementManualIntegerProperty { EXPECT_ANY_THROW_MSG([observed removeObserver:observer forKeyPath:@"basicObjectProperty" context:reinterpret_cast(1)], "Removing an unregistered observer should throw an exception."); } + { // Test deallocation of an object that is its own observer + TestKVOSelfObserver* observed = [[TestKVOSelfObserver alloc] init]; + EXPECT_NO_THROW([observed release]); + } } diff --git a/tools/vsimporter/include/SBTarget.h b/tools/vsimporter/include/SBTarget.h index 4e490e4c77..2112461f34 100644 --- a/tools/vsimporter/include/SBTarget.h +++ b/tools/vsimporter/include/SBTarget.h @@ -30,7 +30,8 @@ class VSTemplateProject; enum TargetProductType { TargetProductUnknown = 0, TargetApplication = 1, - TargetStaticLib = 2 + TargetStaticLib = 2, + TargetBundle = 3 }; typedef std::map BuildSettingsMap; diff --git a/tools/vsimporter/src/PBX/PBXNativeTarget.cpp b/tools/vsimporter/src/PBX/PBXNativeTarget.cpp index f44e8a72a5..50b6a64b20 100644 --- a/tools/vsimporter/src/PBX/PBXNativeTarget.cpp +++ b/tools/vsimporter/src/PBX/PBXNativeTarget.cpp @@ -98,6 +98,13 @@ void PBXNativeTarget::getBuildSettings(VariableCollection& settings) const else if (productFileType != "wrapper.application") SBLog::warning() << "Unexpected product file type \"" << productFileType << "\" for \"" << getName() << "\" app target." << std::endl; + settings.insert("EXECUTABLE_NAME", productName); + settings.insert("EXECUTABLE_FOLDER_PATH", productNameFull); + } else if (m_productType == "com.apple.product-type.bundle") { + if (productFileType != "wrapper.cfbundle") { + SBLog::warning() << "Unexpected product file type \"" << productFileType << "\" for \"" << getName() << "\" bundle target." << std::endl; + } + settings.insert("EXECUTABLE_NAME", productName); settings.insert("EXECUTABLE_FOLDER_PATH", productNameFull); } diff --git a/tools/vsimporter/src/SBFrameworksBuildPhase.cpp b/tools/vsimporter/src/SBFrameworksBuildPhase.cpp index 5b8c852cd3..127f3f9956 100644 --- a/tools/vsimporter/src/SBFrameworksBuildPhase.cpp +++ b/tools/vsimporter/src/SBFrameworksBuildPhase.cpp @@ -52,7 +52,14 @@ SBFrameworksBuildPhase::SBFrameworksBuildPhase(const PBXFrameworksBuildPhase* ph void SBFrameworksBuildPhase::writeVCProjectFiles(VCProject& proj) const { + // We don't support linking with frameworks when building bundles TargetProductType productType = m_parentTarget.getProductType(); + if (productType == TargetBundle) { + if (!m_phase->getBuildFileList().empty()) { + SBLog::warning() << "Ignoring all frameworkss in \"" << m_parentTarget.getName() << "\" bundle target." << std::endl; + } + return; + } String linkTarget; if (productType == TargetApplication) @@ -97,4 +104,4 @@ void SBFrameworksBuildPhase::writeVCProjectFiles(VCProject& proj) const config->setItemDefinition(linkTarget, "AdditionalDependencies", additionalDeps); } } -} \ No newline at end of file +} diff --git a/tools/vsimporter/src/SBNativeTarget.cpp b/tools/vsimporter/src/SBNativeTarget.cpp index af83c2667b..aff8c1f1b7 100644 --- a/tools/vsimporter/src/SBNativeTarget.cpp +++ b/tools/vsimporter/src/SBNativeTarget.cpp @@ -45,15 +45,18 @@ SBNativeTarget* SBNativeTarget::create(const PBXTarget* target, const StringSet& bool SBNativeTarget::init() { // Verify that target's build type is valid - if (m_target->getProductType() == "com.apple.product-type.library.static") { + String productType = m_target->getProductType(); + if (productType == "com.apple.product-type.library.static") { m_type = TargetStaticLib; - } else if (m_target->getProductType() == "com.apple.product-type.framework") { + } else if (productType == "com.apple.product-type.framework") { m_type = TargetStaticLib; SBLog::warning() << "Treating \"" << getName() << "\" framework target as a static library. This is experimental behaviour." << std::endl; - } else if (m_target->getProductType() == "com.apple.product-type.application") { + } else if (productType == "com.apple.product-type.application") { m_type = TargetApplication; + } else if (productType == "com.apple.product-type.bundle") { + m_type = TargetBundle; } else { - SBLog::warning() << "Ignoring \"" << getName() << "\" target with unsupported product type \"" << m_target->getProductType() << "\"." << std::endl; + SBLog::warning() << "Ignoring \"" << getName() << "\" target with unsupported product type \"" << productType << "\"." << std::endl; return false; } @@ -83,7 +86,7 @@ VCProject* SBNativeTarget::constructVCProject(VSTemplateProject* projTemplate) // Write variables file for App targets for (auto bs : m_buildSettings) { - if (getProductType() == TargetApplication) { + if (getProductType() == TargetApplication || getProductType() == TargetBundle) { String configName = bs.first; BuildSettings* configBS = bs.second; diff --git a/tools/vsimporter/src/SBProject.cpp b/tools/vsimporter/src/SBProject.cpp index 01033b7934..7cc703388f 100644 --- a/tools/vsimporter/src/SBProject.cpp +++ b/tools/vsimporter/src/SBProject.cpp @@ -355,10 +355,13 @@ void SBProject::constructVCProjects(VSSolution& sln, const StringSet& slnConfigs for (auto target : m_existingTargets) { // Construct template name String templateName; - if (target.second->getProductType() == TargetApplication) { + TargetProductType productType = target.second->getProductType(); + if (productType == TargetApplication) { templateName = outputFormat + "-" + "App"; - } else if (target.second->getProductType() == TargetStaticLib) { + } else if (productType == TargetStaticLib) { templateName = outputFormat + "-" + "StaticLib"; + } else if (productType == TargetBundle) { + templateName = outputFormat + "-" + "Bundle"; } else if (target.first->getType() == "PBXAggregateTarget") { templateName = outputFormat + "-" + "Aggregate"; } else { @@ -389,8 +392,11 @@ void SBProject::constructVCProjects(VSSolution& sln, const StringSet& slnConfigs sln.addPlatform(platformName); } - // Add a referenced to the shared headers project - proj->addSharedProject(headerProj); + // Add a referenced to the shared headers project to targets that compile things + if (productType == TargetApplication || productType == TargetStaticLib) + { + proj->addSharedProject(headerProj); + } // Add the project to the solution VSBuildableSolutionProject* slnProj = sln.addProject(proj, projFolder); diff --git a/tools/vsimporter/src/SBResourcesBuildPhase.cpp b/tools/vsimporter/src/SBResourcesBuildPhase.cpp index ce723c0184..ac7421ecd2 100644 --- a/tools/vsimporter/src/SBResourcesBuildPhase.cpp +++ b/tools/vsimporter/src/SBResourcesBuildPhase.cpp @@ -39,8 +39,10 @@ SBResourcesBuildPhase::SBResourcesBuildPhase(const PBXResourcesBuildPhase* phase void SBResourcesBuildPhase::writeVCProjectFiles(VCProject& proj) const { - if (m_parentTarget.getProductType() != TargetApplication) + TargetProductType productType = m_parentTarget.getProductType(); + if (productType != TargetApplication && productType != TargetBundle) { return; + } SBBuildPhase::writeVSFileDescriptions(proj, "SBResourceCopy"); @@ -69,4 +71,4 @@ void SBResourcesBuildPhase::writeVCProjectFiles(VCProject& proj) const String varsFile = m_parentTarget.getName() + "-" + bs.first + "-xcvars.txt"; infoPlistMap[plistPath]->setDefinition("VariableFile", varsFile, condition); } -} \ No newline at end of file +} diff --git a/tools/vsimporter/src/SBSourcesBuildPhase.cpp b/tools/vsimporter/src/SBSourcesBuildPhase.cpp index b921f162d2..7db2358e2a 100644 --- a/tools/vsimporter/src/SBSourcesBuildPhase.cpp +++ b/tools/vsimporter/src/SBSourcesBuildPhase.cpp @@ -41,6 +41,16 @@ SBSourcesBuildPhase::SBSourcesBuildPhase(const PBXSourcesBuildPhase* phase, cons void SBSourcesBuildPhase::writeVCProjectFiles(VCProject& proj) const { + // We don't support source compilation when building bundles + TargetProductType productType = m_parentTarget.getProductType(); + if (productType == TargetBundle) + { + if (!m_phase->getBuildFileList().empty()) { + SBLog::warning() << "Ignoring all source files in \"" << m_parentTarget.getName() << "\" bundle target." << std::endl; + } + return; + } + SBBuildPhase::writeVSFileDescriptions(proj, "Text"); String xcProjectDir = m_parentTarget.getProject().getProjectDir(); diff --git a/tools/vsimporter/src/SBTarget.cpp b/tools/vsimporter/src/SBTarget.cpp index 50680c8696..f2d70c28fc 100644 --- a/tools/vsimporter/src/SBTarget.cpp +++ b/tools/vsimporter/src/SBTarget.cpp @@ -192,7 +192,7 @@ String SBTarget::makeRelativePath(const String& path, const String& absRoot) con SBTarget* SBTarget::getPossibleTarget(const PBXBuildFile* buildFile) { - static const char* const _productWildcards[] = {"lib*.a", "*.app", "*.framework"}; + static const char* const _productWildcards[] = {"lib*.a", "*.app", "*.framework", "*.bundle"}; static StringVec productWildcards(_productWildcards, _productWildcards + sizeof(_productWildcards) / sizeof(char*)); sbAssert(buildFile); @@ -274,6 +274,7 @@ VCProject* SBTarget::constructVCProject(VSTemplateProject* projTemplate) String execName = configBS.second->getValue("EXECUTABLE_NAME"); if (getProductType() == TargetStaticLib) execName = sb_fname(execName); + if (!execName.empty()) projConfig->setProperty("TargetName", execName); } diff --git a/tools/vsimporter/xib2nib/ObjectConverter.cpp b/tools/vsimporter/xib2nib/ObjectConverter.cpp index 7040d45d67..dea8054f56 100644 --- a/tools/vsimporter/xib2nib/ObjectConverter.cpp +++ b/tools/vsimporter/xib2nib/ObjectConverter.cpp @@ -35,6 +35,7 @@ #include "UILabel.h" #include "UIRuntimeAccessibilityConfiguration.h" #include "UITableViewCell.h" +#include "UITableViewCellContentView.h" #include "UITextField.h" #include "UITextView.h" #include "UITabBarController.h" @@ -56,6 +57,9 @@ #include "MKMapView.h" #include "UISlider.h" #include "NSLayoutConstraint.h" +#include "UICollectionViewCell.h" +#include "UICollectionView.h" +#include "UIStepper.h" #include "_UILayoutGuide.h" #include @@ -150,6 +154,8 @@ XIBObject *ObjectConverter::ConverterForStoryObject(const char *className, pugi: IS_CONVERTER(ret, className, "fontDescription", UIFont) IS_CONVERTER(ret, className, "tableViewController", UITableViewController) IS_CONVERTER(ret, className, "tableView", UITableView) + IS_CONVERTER(ret, className, "tableViewCell", UITableViewCell) + IS_CONVERTER(ret, className, "tableViewCellContentView", UITableViewCellContentView) IS_CONVERTER(ret, className, "textField", UITextField) IS_CONVERTER(ret, className, "textView", UITextView) IS_CONVERTER(ret, className, "button", UIButton) @@ -165,6 +171,12 @@ XIBObject *ObjectConverter::ConverterForStoryObject(const char *className, pugi: IS_CONVERTER(ret, className, "viewControllerLayoutGuide", _UILayoutGuide) IS_CONVERTER(ret, className, "datePicker", UIDatePicker) IS_CONVERTER(ret, className, "slider", UISlider) + IS_CONVERTER(ret, className, "collectionReusableView", UICollectionReusableView) + IS_CONVERTER(ret, className, "collectionViewCell", UICollectionViewCell) + IS_CONVERTER(ret, className, "collectionView", UICollectionView) + IS_CONVERTER(ret, className, "pickerView", UIPickerView) + IS_CONVERTER(ret, className, "segmentedControl", UISegmentedControl) + IS_CONVERTER(ret, className, "stepper", UIStepper) if ( ret == NULL ) { #ifdef _DEBUG diff --git a/tools/vsimporter/xib2nib/UICollectionView.cpp b/tools/vsimporter/xib2nib/UICollectionView.cpp new file mode 100644 index 0000000000..eb0e58eb9c --- /dev/null +++ b/tools/vsimporter/xib2nib/UICollectionView.cpp @@ -0,0 +1,46 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#include "UICollectionView.h" + +UICollectionView::UICollectionView() +{ +} + +void UICollectionView::InitFromXIB(XIBObject *obj) +{ + UIView::InitFromXIB(obj); + + obj->_outputClassName = "UICollectionView"; +} + +void UICollectionView::InitFromStory(XIBObject *obj) +{ + UIView::InitFromStory(obj); + + obj->_outputClassName = "UICollectionView"; +} + +void UICollectionView::ConvertStaticMappings(NIBWriter *writer, XIBObject *obj) +{ + writer->_allUIObjects->AddMember(NULL, this); + UIView::ConvertStaticMappings(writer, obj); +} + +ObjectConverter *UICollectionView::Clone() +{ + return new UICollectionView(); +} diff --git a/tools/vsimporter/xib2nib/UICollectionView.h b/tools/vsimporter/xib2nib/UICollectionView.h new file mode 100644 index 0000000000..0c6305ffc5 --- /dev/null +++ b/tools/vsimporter/xib2nib/UICollectionView.h @@ -0,0 +1,16 @@ +#pragma once +#include "UIView.h" +class UICollectionView : + public UIView +{ +private: + +public: + UICollectionView(); + virtual void InitFromXIB(XIBObject *obj); + virtual void InitFromStory(XIBObject *obj); + virtual void ConvertStaticMappings(NIBWriter *writer, XIBObject *obj); + + ObjectConverter *Clone(); +}; + diff --git a/tools/vsimporter/xib2nib/UICollectionViewCell.cpp b/tools/vsimporter/xib2nib/UICollectionViewCell.cpp new file mode 100644 index 0000000000..9b94edf59d --- /dev/null +++ b/tools/vsimporter/xib2nib/UICollectionViewCell.cpp @@ -0,0 +1,111 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#include "UICollectionViewCell.h" + +UICollectionReusableView::UICollectionReusableView() +{ +} + +void UICollectionReusableView::InitFromXIB(XIBObject *obj) +{ + UIView::InitFromXIB(obj); + + obj->_outputClassName = "UICollectionReusableView"; +} + +void UICollectionReusableView::InitFromStory(XIBObject *obj) +{ + UIView::InitFromStory(obj); + + obj->_outputClassName = "UICollectionReusableView"; +} + +void UICollectionReusableView::Awaken() +{ + UIView::Awaken(); +} + +void UICollectionReusableView::ConvertStaticMappings(NIBWriter *writer, XIBObject *obj) +{ + writer->_allUIObjects->AddMember(NULL, this); + + UIView::ConvertStaticMappings(writer, obj); +} + +ObjectConverter *UICollectionReusableView::Clone() +{ + return new UICollectionReusableView(); +} + +UICollectionViewCell::UICollectionViewCell() +{ +} + +void UICollectionViewCell::InitFromXIB(XIBObject *obj) +{ + UICollectionReusableView::InitFromXIB(obj); + + obj->_outputClassName = "UICollectionViewCell"; + _contentView = (UIView *)obj->FindMember("IBUIContentView"); +} + +void UICollectionViewCell::InitFromStory(XIBObject *obj) +{ + UICollectionReusableView::InitFromStory(obj); + + obj->_outputClassName = "UICollectionViewCell"; + _contentView = (UIView *)obj->FindMember("contentView"); +} + +void UICollectionViewCell::Awaken() +{ + UICollectionReusableView::Awaken(); + if (_contentView) { + _contentView->_clipsToBounds = false; + _contentView->_backgroundColor = NULL; + _contentView->_contentMode = 0; + _contentView->_multipleTouchEnabled = false; + } +} + +void UICollectionViewCell::ConvertStaticMappings(NIBWriter *writer, XIBObject *obj) +{ + writer->_allUIObjects->AddMember(NULL, this); + if (_contentView) { + _contentView->setFrame(getFrame()); + _contentView->_opaque = true; + int count = _contentView->_subviews->count(); + for (int i = 0; i < count; i++) { + UIView *curObj = (UIView *)_contentView->_subviews->objectAtIndex(i); + //curObj->_bounds.height = _contentView->_bounds.height; + writer->_allUIObjects->AddMember(NULL, curObj); + } + _contentView->_ignoreUIObject = true; + } + + UICollectionReusableView::ConvertStaticMappings(writer, obj); + + if (_contentView) { + _contentView->_outputClassName = "UICollectionViewCellContentView"; + obj->AddOutputMember(writer, "UIContentView", _contentView); + } +} + +ObjectConverter *UICollectionViewCell::Clone() +{ + return new UICollectionViewCell(); +} diff --git a/tools/vsimporter/xib2nib/UICollectionViewCell.h b/tools/vsimporter/xib2nib/UICollectionViewCell.h new file mode 100644 index 0000000000..fec53c4d58 --- /dev/null +++ b/tools/vsimporter/xib2nib/UICollectionViewCell.h @@ -0,0 +1,32 @@ +#pragma once +#include "UIView.h" + +class UICollectionReusableView : + public UIView +{ +public: + UICollectionReusableView(); + virtual void Awaken(); + virtual void InitFromXIB(XIBObject *obj); + virtual void InitFromStory(XIBObject *obj); + virtual void ConvertStaticMappings(NIBWriter *writer, XIBObject *obj); + + ObjectConverter *Clone(); +}; + +class UICollectionViewCell : + public UICollectionReusableView +{ +private: + UIView *_contentView; + +public: + UICollectionViewCell(); + virtual void Awaken(); + virtual void InitFromXIB(XIBObject *obj); + virtual void InitFromStory(XIBObject *obj); + virtual void ConvertStaticMappings(NIBWriter *writer, XIBObject *obj); + + ObjectConverter *Clone(); +}; + diff --git a/tools/vsimporter/xib2nib/UIColor.cpp b/tools/vsimporter/xib2nib/UIColor.cpp index 1503106553..f868d19b09 100644 --- a/tools/vsimporter/xib2nib/UIColor.cpp +++ b/tools/vsimporter/xib2nib/UIColor.cpp @@ -104,6 +104,16 @@ void UIColor::InitFromStory(XIBObject *obj) _systemName = sysColor; _white = 0.6f; _a = 0.6f; + } else if (strcmp(sysColor, "groupTableViewBackgroundColor") == 0) { + _colorSpaceOut = colorSpaceWhite; + _systemName = sysColor; + _white = 1.0f; + _a = 0.6f; + } else if (strcmp(sysColor, "tableCellGroupedBackgroundColor") == 0) { + _colorSpaceOut = colorSpaceWhite; + _systemName = sysColor; + _white = 1.0f; + _a = 0.6f; } else { assert(0); } diff --git a/tools/vsimporter/xib2nib/UIFont.cpp b/tools/vsimporter/xib2nib/UIFont.cpp index e4e8bd4f23..22aec0ac68 100644 --- a/tools/vsimporter/xib2nib/UIFont.cpp +++ b/tools/vsimporter/xib2nib/UIFont.cpp @@ -56,12 +56,19 @@ void UIFont::InitFromStory(XIBObject *obj) const char *fontType = getAttrib("type"); - if ( strcmp(fontType, "system") == 0 ) { - _fontName = "Helvetica"; - } else if ( strcmp(fontType, "boldSystem") == 0 ) { - _fontName = "Helvetica-Bold"; - } else { - assert(0); + if (fontType) { + if (strcmp(fontType, "system") == 0) { + _fontName = "Helvetica"; + } + else if (strcmp(fontType, "boldSystem") == 0) { + _fontName = "Helvetica-Bold"; + } + else { + assert(0); + } + } + else { + _fontName = getAttrib("name"); } obj->_outputClassName = "UIFont"; diff --git a/tools/vsimporter/xib2nib/UIStepper.cpp b/tools/vsimporter/xib2nib/UIStepper.cpp new file mode 100644 index 0000000000..54c596b902 --- /dev/null +++ b/tools/vsimporter/xib2nib/UIStepper.cpp @@ -0,0 +1,40 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#include "UIStepper.h" + +UIStepper::UIStepper() +{ +} + +void UIStepper::InitFromXIB(XIBObject *obj) +{ + UIView::InitFromXIB(obj); + + _outputClassName = "UIStepper"; +} + +void UIStepper::InitFromStory(XIBObject *obj) +{ + UIView::InitFromStory(obj); + + _outputClassName = "UIStepper"; +} + +void UIStepper::ConvertStaticMappings(NIBWriter *writer, XIBObject *obj) +{ + UIView::ConvertStaticMappings(writer, obj); +} diff --git a/tools/vsimporter/xib2nib/UIStepper.h b/tools/vsimporter/xib2nib/UIStepper.h new file mode 100644 index 0000000000..409522df8e --- /dev/null +++ b/tools/vsimporter/xib2nib/UIStepper.h @@ -0,0 +1,28 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#pragma once +#include "UIView.h" +class UIStepper : + public UIView +{ +public: + UIStepper(); + virtual void InitFromXIB(XIBObject *obj); + virtual void InitFromStory(XIBObject *obj); + virtual void ConvertStaticMappings(NIBWriter *writer, XIBObject *obj); +}; + diff --git a/tools/vsimporter/xib2nib/UITableViewCell.cpp b/tools/vsimporter/xib2nib/UITableViewCell.cpp index ee0ecbef2f..efc34a33d6 100644 --- a/tools/vsimporter/xib2nib/UITableViewCell.cpp +++ b/tools/vsimporter/xib2nib/UITableViewCell.cpp @@ -20,6 +20,11 @@ UITableViewCell::UITableViewCell() { _indentationLevel = 0; _indentationWidth = 0; + _selectionStyle = 0; + _reuseIdentifier = NULL; + _detailTextLabel = NULL; + _imageView = NULL; + _textLabel = NULL; } void UITableViewCell::InitFromXIB(XIBObject *obj) @@ -38,6 +43,15 @@ void UITableViewCell::InitFromXIB(XIBObject *obj) if ( obj->FindMember("IBUIIndentationWidth") ) _indentationWidth = obj->FindMember("IBUIIndentationWidth")->floatValue(); } +void UITableViewCell::InitFromStory(XIBObject *obj) +{ + UIView::InitFromStory(obj); + + obj->_outputClassName = "UITableViewCell"; + + _contentView = (UIView *)obj->FindMember("contentView"); +} + void UITableViewCell::Awaken() { UIView::Awaken(); diff --git a/tools/vsimporter/xib2nib/UITableViewCell.h b/tools/vsimporter/xib2nib/UITableViewCell.h index d8319b9dae..940fb6c70b 100644 --- a/tools/vsimporter/xib2nib/UITableViewCell.h +++ b/tools/vsimporter/xib2nib/UITableViewCell.h @@ -32,6 +32,7 @@ class UITableViewCell : UITableViewCell(); virtual void Awaken(); virtual void InitFromXIB(XIBObject *obj); + virtual void InitFromStory(XIBObject *obj); virtual void ConvertStaticMappings(NIBWriter *writer, XIBObject *obj); ObjectConverter *Clone(); diff --git a/tools/vsimporter/xib2nib/UITableViewCellContentView.cpp b/tools/vsimporter/xib2nib/UITableViewCellContentView.cpp new file mode 100644 index 0000000000..ca422745d5 --- /dev/null +++ b/tools/vsimporter/xib2nib/UITableViewCellContentView.cpp @@ -0,0 +1,52 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#include "UITableViewCellContentView.h" + +UITableViewCellContentView::UITableViewCellContentView() +{ +} + +void UITableViewCellContentView::InitFromXIB(XIBObject *obj) +{ + UIView::InitFromXIB(obj); + + obj->_outputClassName = "UITableViewCellContentView"; +} + +void UITableViewCellContentView::InitFromStory(XIBObject *obj) +{ + UIView::InitFromStory(obj); + + obj->_outputClassName = "UITableViewCellContentView"; +} + +void UITableViewCellContentView::Awaken() +{ + UIView::Awaken(); +} + +void UITableViewCellContentView::ConvertStaticMappings(NIBWriter *writer, XIBObject *obj) +{ + writer->_allUIObjects->AddMember(NULL, this); + + UIView::ConvertStaticMappings(writer, obj); +} + +ObjectConverter *UITableViewCellContentView::Clone() +{ + return new UITableViewCellContentView(); +} diff --git a/tools/vsimporter/xib2nib/UITableViewCellContentView.h b/tools/vsimporter/xib2nib/UITableViewCellContentView.h new file mode 100644 index 0000000000..18bda42c51 --- /dev/null +++ b/tools/vsimporter/xib2nib/UITableViewCellContentView.h @@ -0,0 +1,33 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#pragma once +#include "UIView.h" +class UITableViewCellContentView : + public UIView +{ +private: + +public: + UITableViewCellContentView(); + virtual void Awaken(); + virtual void InitFromXIB(XIBObject *obj); + virtual void InitFromStory(XIBObject *obj); + virtual void ConvertStaticMappings(NIBWriter *writer, XIBObject *obj); + + ObjectConverter *Clone(); +}; + diff --git a/tools/vsimporter/xib2nib/UIView.cpp b/tools/vsimporter/xib2nib/UIView.cpp index 0167c65b30..b47f4c1891 100644 --- a/tools/vsimporter/xib2nib/UIView.cpp +++ b/tools/vsimporter/xib2nib/UIView.cpp @@ -164,6 +164,16 @@ void UIView::InitFromStory(XIBObject *obj) _contentMode = UIViewContentModeScaleAspectFill; } else if ( strcmp(mode, "scaleAspectFit") == 0 ) { _contentMode = UIViewContentModeScaleAspectFit; + } else if ( strcmp(mode, "TopLeft") == 0 ) { + _contentMode = UIViewContentModeTopLeft; + } else if ( strcmp(mode, "bottomLeft") == 0 ) { + _contentMode = UIViewContentModeBottomLeft; + } else if (strcmp(mode, "right") == 0) { + _contentMode = UIViewContentModeRight; + } else if (strcmp(mode, "top") == 0) { + _contentMode = UIViewContentModeTop; + } else if (strcmp(mode, "bottom") == 0) { + _contentMode = UIViewContentModeBottom; } else { assert(0); } diff --git a/tools/vsimporter/xib2nib/XIBObjectTypes.cpp b/tools/vsimporter/xib2nib/XIBObjectTypes.cpp index 756522cf27..312fd71e32 100644 --- a/tools/vsimporter/xib2nib/XIBObjectTypes.cpp +++ b/tools/vsimporter/xib2nib/XIBObjectTypes.cpp @@ -55,6 +55,10 @@ const char *XIBObjectString::stringValue() { return _strVal; } +int XIBObjectString::intValue() { + return atoi(_strVal); +} + bool XIBObjectString::EqualToString(const char *str) { if ( strcmp(_strVal, str) == 0 ) { @@ -287,6 +291,10 @@ void XIBArray::InitFromStory(XIBObject *obj) void XIBArray::EmitObject(NIBWriter *writer) { + if (!_className) { + _className = "NSArray"; + } + if ( (_members.size() == 0 || _members[0]->_name == NULL || strcmp(_members[0]->_name, "EncodedWithXMLCoder") != 0) && @@ -298,7 +306,6 @@ void XIBArray::EmitObject(NIBWriter *writer) _members.insert(_members.begin(), newMember); } - if ( !_className ) _className = "NSArray"; this->_outputClassName = _className; //printf("NSArray\n"); for ( int i = 0; i < _members.size(); i ++ ) { diff --git a/tools/vsimporter/xib2nib/XIBObjectTypes.h b/tools/vsimporter/xib2nib/XIBObjectTypes.h index 3253bb2adc..4326b67f8d 100644 --- a/tools/vsimporter/xib2nib/XIBObjectTypes.h +++ b/tools/vsimporter/xib2nib/XIBObjectTypes.h @@ -31,6 +31,7 @@ class XIBObjectString : public XIBObject XIBObjectString(const char *str); XIBObjectString(); const char *stringValue(); + int intValue(); bool EqualToString(const char *str);; void EmitObject(NIBWriter *writer); void InitFromStory(XIBObject *obj); diff --git a/tools/vsimporter/xib2nib/xib2nib.cpp b/tools/vsimporter/xib2nib/xib2nib.cpp index 3e96545313..850482b9e9 100644 --- a/tools/vsimporter/xib2nib/xib2nib.cpp +++ b/tools/vsimporter/xib2nib/xib2nib.cpp @@ -118,6 +118,9 @@ void ConvertXIBToNib(FILE *fpOut, pugi::xml_document& doc) if ( obj ) { XIBObject *objectId = curObject->FindMember("objectID"); + if (!objectId) { + objectId = curObject->FindMember("id"); + } int objId = objectId->intValue(); // Attempt to find any associated custom class name