#ifndef CoreEntitlements_V2_Kernel_h
#define CoreEntitlements_V2_Kernel_h

/* Default to __single indexable pointers for Firebloom */
__ptrcheck_abi_assume_single();

#include <stdint.h>
#include <sys/cdefs.h>
#include <CoreEntitlements/V2/Return.h>
#include <CoreEntitlements/V2/Context.h>

__BEGIN_DECLS

typedef struct _CEKernelAPI {
    typeof(CEContextInitWithType) *contextInitWithType;
    typeof(CEContextInitWithTypeLegacy) *contextInitWithTypeLegacy;
    typeof(CEContextGetLegacyContext) *contextGetLegacyContext;
    typeof(CEContextCreateAsLegacyContext) *contextCreateAsLegacyContext;
    typeof(CEContextGetDictionary) *contextGetDictionary;
    typeof(CEContextValueForKey) *contextValueForKey;
    typeof(CEContextValueForKeyAsCEString) *contextValueForKeyAsCEString;
    typeof(CEContextCheckSubset) *contextCheckSubset;
    typeof(CEElementIterate) *elementIterate;
    typeof(CEDictionaryIterate) *dictionaryIterate;
    typeof(CEElementGetIndexCount) *elementGetIndexCount;
    typeof(CESequenceValueForIndex) *sequenceValueForIndex;
    typeof(CEDictionaryValueForIndex) *dictionaryValueForIndex;
    typeof(CEDictionaryValueForKey) *dictionaryValueForKey;
    typeof(CEDictionaryValueForKeyAsCEString) *dictionaryValueForKeyAsCEString;
    typeof(CEElementGetType) *elementGetType;
    typeof(CEElementGetCEBuffer) *elementGetCEBuffer;
    typeof(CEElementGetValueAsCEBuffer) *elementGetValueAsCEBuffer;
    typeof(CEElementGetBool) *elementGetBool;
    typeof(CEElementGetInteger) *elementGetInteger;
    typeof(CEElementGetString) *elementGetString;
    typeof(CEElementGetData) *elementGetData;
    typeof(CEElementMatchBool) *elementMatchBool;
    typeof(CEElementMatchInteger) *elementMatchInteger;
    typeof(CEElementMatchString) *elementMatchString;
    typeof(CEElementMatchStringWithCEString) *elementMatchStringWithCEString;
    typeof(CEElementMatchStringWithWildcard) *elementMatchStringWithWildcard;
    typeof(CEElementMatchStringWithCEStringAndWildcard) *elementMatchStringWithCEStringAndWildcard;
    typeof(CEElementMatchData) *elementMatchData;
    typeof(CEElementContainsInteger) *elementContainsInteger;
    typeof(CEElementContainsString) *elementContainsString;
    typeof(CEElementContainsStringWithCEString) *elementContainsStringWithCEString;
    typeof(CEElementContainsStringWithWildcard) *elementContainsStringWithWildcard;
    typeof(CEElementContainsStringWithCEStringAndWildcard) *elementContainsStringWithCEStringAndWildcard;
    typeof(CEElementContainsData) *elementContainsData;
    typeof(CEStringCompare) *stringCompare;
    typeof(CEStringCompareWithCEString) *stringCompareWithCEString;
    typeof(CEStringComparePrefix) *stringComparePrefix;
    typeof(CEStringComparePrefixWithCEString) *stringComparePrefixWithCEString;
    typeof(CEDictionaryIterateWithClosure) *dictionaryIterateWithClosure;
    typeof(CEElementIterateWithClosure) *elementIterateWithClosure;
    typeof(CEContextEvaluateAcceleration) *contextEvaluateAcceleration;
    typeof(CEContextCheckAcceleration) *contextCheckAcceleration;
    typeof(CEContextAccelerate) *contextAccelerate;
    typeof(CEContextDecelerate) *contextDecelerate;
} CEKernelAPI_t;

/* Exported by AMFI for XNU (to be used by PPL) */
extern const CEKernelAPI_t ceKernelImplementation;

/**
 * In some cases, the kernel must be able to modify the context with a custom instance of the
 * legacy context. We do not want the kernel to manually perform this mutation as it requires the
 * kernel to dereference what is otherwise an opaque object (`CEContext_t`).
 *
 * To maintain the opacity of `CEContext_t`, we provide an API which the kernel can use.
 * We can hopefully deprecate this ugly business soon.
 */
CEReturn_t
CEContextSetLegacyContext(CEContext_t *context,
                          const void *legacyContext);

__END_DECLS

#ifdef __cplusplus

#include <libkern/c++/OSBoolean.h>
#include <libkern/c++/OSNumber.h>
#include <libkern/c++/OSString.h>
#include <libkern/c++/OSSymbol.h>
#include <libkern/c++/OSArray.h>
#include <libkern/c++/OSDictionary.h>
#include <libkern/c++/OSData.h>

/**
 * Convert a `CEElement_t` object to an `OSObject`. The `OSObject` hierarchy (both
 * individual elements types and container types) needed for the conversion is allocated by
 * this function.
 *
 * The following elements types can be converted:
 *  `kCETypeBool`
 *  `kCETypeInteger`
 *  `kCETypeString`
 *  `kCETypeSequence`
 *  `kCETypeDictionary`
 *  `kCETypeData`
 *
 * The function returns `kCEReturnNotSupported` for unsupported element types. For any
 * allocation errors, the function will return `kCSReturnOutOfMemory`.
 */
CEReturn_t
CEElementCreateAsOSObject(const CEElement_t *derElement,
                          const OSObject **objectRet);

/**
 * Convert a `CEContext_t` object to an `OSDictionary`. This function is a thin wrapper
 * over the `CEElementCreateAsOSObject` function -- the top-level dictionary from the
 * context is extracted and converted. All constraints from `CEElementCreateAsOSObject`
 * apply.
 */
CEReturn_t
CEContextCreateAsOSDictionary(const CEContext_t *context,
                              const OSDictionary **dictRet);

#endif /* __cplusplus */
#endif /* CoreEntitlements_V2_Kernel_h */
