1 // 2 // QueryHelpers.h 3 // CoreEntitlements 4 // 5 6 #pragma once 7 8 9 /*! 10 * @function CESelectIndex 11 * Returns an operation that when executed will modify the context such that any subsequent operation is performed on the entitlement object at the specified index 12 * 13 * @param index 14 * The index of the object within a container 15 * 16 * @discussion 17 * Using an index that is past the container's size will result in an invalid context 18 */ 19 #define CESelectIndex(index) (CEQueryOperation_t){.opcode = kCEOpSelectIndex, .parameters = {.numericParameter = index}} 20 21 /*! 22 * @function CESelectKey 23 * Returns an operation that when executed will modify the context such that any subsequent operation is performed on the key of the dictionary pair 24 * @discussion 25 * Selecting a key on a non-dictionary-pair object is undefined behavior (i..e. it is implementation defined) 26 */ 27 #define CESelectKey() CESelectIndex(0) 28 29 /*! 30 * @function CESelectValue 31 * Returns an operation that when executed will modify the context such that any subsequent operation is performed on the value of the dictionary pair 32 * @discussion 33 * Selecting a value on a non-dictionary-pair object is undefined behavior (i..e. it is implementation defined) 34 */ 35 #define CESelectValue() CESelectIndex(1) 36 37 /*! 38 * @function CESelectDictValue 39 * Returns an operation that when executed will modify the context such that any subsequent operation is performed on the object that corresponds 40 * to the value pointed to by the specified key 41 * 42 * @param key 43 * The key of the object within a container 44 * 45 * @discussion 46 * Using a key that is not found in the container will result in an invalid context 47 */ 48 #define CESelectDictValue(key) (CEQueryOperation_t){.opcode = kCEOpSelectKey, .parameters = {.stringParameter = {.data = key, .length = sizeof(key) - 1}}} 49 #define CESelectDictValueDynamic(key, len) (CEQueryOperation_t){.opcode = (CEQueryOpOpcode_t)(kCEOpSelectKey | kCEOpDynamic), .parameters = {.dynamicParameter = {.data = key, .length = len}}} 50 51 /*! 52 * @function CEMatchString 53 * Returns an operation that will return a valid context if and only if the context corresponds to a valid string and matches the string exactly 54 * 55 * @param string 56 * The string to match against (MUST BE A STRING LITERAL) 57 * 58 * @discussion 59 * If a valid context is returned it will be in the same state as the execution context 60 */ 61 #define CEMatchString(string) (CEQueryOperation_t){.opcode = kCEOpMatchString, .parameters = {.stringParameter = {.data = string, .length = sizeof(string) - 1}}} 62 #define CEMatchDynamicString(string, len) (CEQueryOperation_t){.opcode = kCEOpMatchString | kCEOpDynamic, .parameters = {.dynamicParameter = {.data = string, .length = len}}} 63 64 /*! 65 * @function CEMatchPrefix 66 * Returns an operation that will return a valid context if and only if the context corresponds to a valid string and it's prefix matched the passed in prefix 67 * 68 * @param prefix 69 * The prefix to match against (MUST BE A STRING LITERAL) 70 * 71 * @discussion 72 * If a valid context is returned it will be in the same state as the execution context 73 */ 74 #define CEMatchPrefix(prefix) (CEQueryOperation_t){.opcode = kCEOpMatchStringPrefix, .parameters = {.stringParameter = {.data = prefix, .length = sizeof(prefix) - 1}}} 75 #define CEMatchDynamicPrefix(prefix, len) (CEQueryOperation_t){.opcode = kCEOpMatchStringPrefix | kCEOpDynamic, .parameters = {.dynamicParameter = {.data = prefix, .length = len}}} 76 77 78 /*! 79 * @function CEMatchBool 80 * Returns an operation that will return a valid context if and only if the context corresponds to a valid boolean and matches the boolean exactly 81 * 82 * @param val 83 * The bool to match against 84 * 85 * @discussion 86 * If a valid context is returned it will be in the same state as the execution context 87 */ 88 #define CEMatchBool(val) (CEQueryOperation_t){.opcode = kCEOpMatchBool, .parameters = {.numericParameter = !!val}} 89 90 /*! 91 * @function CEMatchInteger 92 * Returns an operation that will return a valid context if and only if the context corresponds to a valid integer and matches the integer exactly 93 * 94 * @param val 95 * The integer to match against 96 * 97 * @discussion 98 * If a valid context is returned it will be in the same state as the execution context 99 */ 100 #define CEMatchInteger(val) (CEQueryOperation_t){.opcode = kCEOpMatchInteger, .parameters = {.numericParameter = val}} 101 102 /*! 103 * @function CEIsStringAllowed 104 * Returns an operation that will return a valid context if 1) the current context is a string and allows the string via wildcard rules, or 2) the context is an array of strings that allows the string 105 * 106 * @param string 107 * The string to match against (MUST BE A STRING LITERAL) 108 * 109 * @discussion 110 * If a valid context is returned it will be in the same state as the execution context 111 */ 112 #define CEIsStringAllowed(string) (CEQueryOperation_t){.opcode = kCEOpStringValueAllowed, .parameters = {.stringParameter = {.data = string, .length = sizeof(string) - 1}}} 113 #define CEIsDynamicStringAllowed(string, len) (CEQueryOperation_t){.opcode = kCEOpStringValueAllowed | kCEOpDynamic, .parameters = {.dynamicParameter = {.data = string, .length = len}}} 114 115 /*! 116 * @function CEIsStringPrefixAllowed 117 * Returns an operation that will return a valid context if 1) the current context is a string and matches the prefix or 2) has an array that has the matches the prefix 118 * 119 * @param string 120 * The string to match against (MUST BE A STRING LITERAL) 121 * 122 * @discussion 123 * If a valid context is returned it will be in the same state as the execution context 124 */ 125 #define CEIsStringPrefixAllowed(string) (CEQueryOperation_t){.opcode = kCEOpStringPrefixValueAllowed, .parameters = {.stringParameter = {.data = string, .length = sizeof(string) - 1}}} 126 #define CEIsDynamicStringPrefixAllowed(string, len) (CEQueryOperation_t){.opcode = kCEOpStringPrefixValueAllowed | kCEOpDynamic, .parameters = {.dynamicParameter = {.data = string, .length = len}}} 127 128 129 #pragma mark Helpers 130 /* 131 Macro magic 132 */ 133 #define _SELECT_NTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, N, ...) N 134 135 #define _mc_1(_call, x) _call(x), 136 #define _mc_2(_call, x, ...) _call(x), _mc_1(_call, __VA_ARGS__) 137 #define _mc_3(_call, x, ...) _call(x), _mc_2(_call, __VA_ARGS__) 138 #define _mc_4(_call, x, ...) _call(x), _mc_3(_call, __VA_ARGS__) 139 #define _mc_5(_call, x, ...) _call(x), _mc_4(_call, __VA_ARGS__) 140 #define _mc_6(_call, x, ...) _call(x), _mc_5(_call, __VA_ARGS__) 141 #define _mc_7(_call, x, ...) _call(x), _mc_6(_call, __VA_ARGS__) 142 #define _mc_8(_call, x, ...) _call(x), _mc_7(_call, __VA_ARGS__) 143 #define _mc_9(_call, x, ...) _call(x), _mc_8(_call, __VA_ARGS__) 144 #define _mc_10(_call, x, ...) _call(x), _mc_9(_call, __VA_ARGS__) 145 146 #define _MACRO_ITER(macro, ...) _SELECT_NTH_ARG(__VA_ARGS__, _mc_10, _mc_9, _mc_8 _mc_7, _mc_6, _mc_5, _mc_4, _mc_3, _mc_2, _mc_1)(macro, __VA_ARGS__) 147 148 /*! 149 Macro to automatically generate a query path from a list of string sub components 150 So 151 @code 152 CE_SELECT_PATH("hello, "world") will select a key "hello" and then look up "world" in the dictionary stored in the value of "hello" 153 @endcode 154 */ 155 #define CE_SELECT_PATH(...) _MACRO_ITER(CESelectDictValue, __VA_ARGS__) 156 157 // Macro for string equals 158 #define CE_STRING_EQUALS(str) CEMatchString(str) 159 160 /* 161 A macro that checks if the passed in context grants (via an explicit true boolean) the entitlement at the passed in path. 162 */ 163 #define CE_CONTEXT_GRANTS_ENTITLEMENT(ctx, ...) (CEContextQuery(ctx, (CEQuery_t){CE_SELECT_PATH(__VA_ARGS__) CEMatchBool(true)}, sizeof((CEQuery_t){CE_SELECT_PATH(__VA_ARGS__) CEMatchBool(true)}) / sizeof(CEQueryOperation_t)) == kCENoError) 164