#include "SOSGenCount.h"
#include <utilities/SecCFWrappers.h>
#include <CoreFoundation/CFLocale.h>
#include <utilities/der_plist.h>
#include <utilities/der_plist_internal.h>
static CFAbsoluteTime SOSGenerationCountGetDateBits(int64_t genValue) {
return (uint32_t) ((((uint64_t) genValue) >> 32) << 1);
}
void SOSGenerationCountWithDescription(SOSGenCountRef gen, void (^operation)(CFStringRef description)) {
CFStringRef description = SOSGenerationCountCopyDescription(gen);
operation(description);
CFReleaseSafe(description);
}
CFStringRef SOSGenerationCountCopyDescription(SOSGenCountRef gen) {
int64_t value = SOSGetGenerationSint(gen);
CFMutableStringRef gcDecsription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("["));
withStringOfAbsoluteTime(SOSGenerationCountGetDateBits(value), ^(CFStringRef decription) {
CFStringAppend(gcDecsription, decription);
});
CFStringAppendFormat(gcDecsription, NULL, CFSTR(" %u]"), (uint32_t)(value & 0xFFFFFFFF));
return gcDecsription;
}
int64_t SOSGetGenerationSint(SOSGenCountRef gen) {
int64_t value;
if(!gen) return 0;
CFNumberGetValue(gen, kCFNumberSInt64Type, &value);
return value;
}
static int64_t sosGenerationSetHighBits(int64_t value, int32_t high_31)
{
value &= 0xFFFFFFFF; value |= ((int64_t) high_31) << 32;
return value;
}
static SOSGenCountRef sosGenerationCreateOrIncrement(SOSGenCountRef gen) {
int64_t value = 0;
if(gen) {
value = SOSGetGenerationSint(gen);
}
if((value >> 32) == 0) {
uint32_t seconds = CFAbsoluteTimeGetCurrent(); value = sosGenerationSetHighBits(value, (seconds >> 1));
}
value++;
return CFNumberCreate(NULL, kCFNumberSInt64Type, &value);
}
SOSGenCountRef SOSGenerationCreate() {
return sosGenerationCreateOrIncrement(NULL);
}
SOSGenCountRef SOSGenerationCreateWithValue(int64_t value) {
return CFNumberCreate(NULL, kCFNumberSInt64Type, &value);
}
SOSGenCountRef SOSGenerationIncrementAndCreate(SOSGenCountRef gen) {
return sosGenerationCreateOrIncrement(gen);
}
SOSGenCountRef SOSGenerationCopy(SOSGenCountRef gen) {
if(!gen) return NULL;
int64_t value = SOSGetGenerationSint(gen);
return CFNumberCreate(NULL, kCFNumberSInt64Type, &value);
}
bool SOSGenerationIsOlder(SOSGenCountRef older, SOSGenCountRef newer) {
switch(CFNumberCompare(older, newer, NULL)) {
case kCFCompareLessThan: return true;
case kCFCompareEqualTo: return false;
case kCFCompareGreaterThan: return false;
}
return false;
}
static bool SOSGenerationIsOlderOrEqual(SOSGenCountRef older, SOSGenCountRef newer) {
switch(CFNumberCompare(older, newer, NULL)) {
case kCFCompareLessThan: return true;
case kCFCompareEqualTo: return true;
case kCFCompareGreaterThan: return false;
}
return false;
}
SOSGenCountRef SOSGenerationCreateWithBaseline(SOSGenCountRef reference) {
SOSGenCountRef retval = SOSGenerationCreate();
if(SOSGenerationIsOlderOrEqual(retval, reference)) {
CFReleaseNull(retval);
retval = SOSGenerationIncrementAndCreate(reference);
}
return retval;
}
SOSGenCountRef SOSGenCountCreateFromDER(CFAllocatorRef allocator, CFErrorRef* error,
const uint8_t** der_p, const uint8_t *der_end) {
SOSGenCountRef retval = NULL;
*der_p = der_decode_number(allocator, 0, &retval, error, *der_p, der_end);
if(retval == NULL)
retval = SOSGenerationCreate();
return retval;
}
size_t SOSGenCountGetDEREncodedSize(SOSGenCountRef gencount, CFErrorRef *error) {
return der_sizeof_number(gencount, error);
}
uint8_t *SOSGenCountEncodeToDER(SOSGenCountRef gencount, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) {
return der_encode_number(gencount, error, der, der_end);
}