1/* 2 * Copyright (c) 2011 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2011 - 2013 Apple Inc. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#include "baselocl.h" 37 38#include <CoreFoundation/CoreFoundation.h> 39#include <CoreFoundation/CFRuntime.h> 40#include <dispatch/dispatch.h> 41#include <syslog.h> 42 43static void * 44_heim_create_cf_instance(CFTypeID typeID, CFIndex size, char *category) 45{ 46 heim_assert(size >= sizeof(CFRuntimeBase), "cf runtime size too small"); 47 CFTypeRef type = _CFRuntimeCreateInstance(NULL, typeID, size - sizeof(struct heim_base), (unsigned char *)category); 48 if (type) 49 memset(((uint8_t *)type) + sizeof(struct heim_base), 0, size - sizeof(struct heim_base)); 50 return (void *)type; 51} 52/* 53 * 54 */ 55 56const char *__crashreporter_info__ = NULL; 57asm(".desc ___crashreporter_info__, 0x10"); 58 59 60/** 61 * Abort and log the failure (using syslog) 62 */ 63 64void 65heim_abort(const char *fmt, ...) 66 HEIMDAL_NORETURN_ATTRIBUTE 67 HEIMDAL_PRINTF_ATTRIBUTE((printf, 1, 2)) 68{ 69 va_list ap; 70 va_start(ap, fmt); 71 heim_abortv(fmt, ap); 72 va_end(ap); 73} 74 75/** 76 * Abort and log the failure (using syslog) 77 */ 78 79void 80heim_abortv(const char *fmt, va_list ap) 81 HEIMDAL_NORETURN_ATTRIBUTE 82 HEIMDAL_PRINTF_ATTRIBUTE((printf, 1, 0)) 83{ 84 char *str = NULL; 85 int ret; 86 87 ret = vasprintf(&str, fmt, ap); 88 if (ret > 0 && str) { 89 syslog(LOG_ERR, "heim_abort: %s", str); 90 91 __crashreporter_info__ = str; 92 } 93 abort(); 94} 95 96void 97heim_base_once_f(heim_base_once_t *once, void *ctx, void (*func)(void *)) 98{ 99 dispatch_once_f(once, ctx, func); 100} 101 102 103void * 104heim_retain(void *ptr) 105{ 106 if (ptr) 107 CFRetain(ptr); 108 return ptr; 109} 110 111void 112heim_release(void *ptr) 113{ 114 if (ptr) 115 CFRelease(ptr); 116} 117 118heim_tid_t 119heim_get_tid(heim_object_t ptr) 120{ 121 return (heim_tid_t)CFGetTypeID(ptr); 122} 123 124unsigned long 125heim_get_hash(heim_object_t ptr) 126{ 127 return CFHash(ptr); 128} 129 130int 131heim_cmp(heim_object_t a, heim_object_t b) 132{ 133 if (CFEqual(a, b)) 134 return 0; 135 136 uintptr_t ai = (uintptr_t)a; 137 uintptr_t bi = (uintptr_t)b; 138 139 heim_assert(ai != bi, "pointers are the same ?"); 140 141 while (((int)(ai - bi)) == 0) { 142 ai = ai >> 8; 143 bi = bi >> 8; 144 } 145 int diff = (int)(ai - bi); 146 heim_assert(diff != 0, "pointers are the same ?"); 147 148 return diff; 149 150} 151 152heim_array_t 153heim_array_create(void) 154{ 155 return (heim_array_t)CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 156} 157 158heim_tid_t 159heim_array_get_type_id(void) 160{ 161 return (heim_tid_t)CFDictionaryGetTypeID(); 162} 163 164int 165heim_array_append_value(heim_array_t array, heim_object_t object) 166{ 167 CFArrayAppendValue((CFMutableArrayRef)array, object); 168 return 0; 169} 170 171void 172heim_array_iterate_f(heim_array_t array, 173 void *ctx, 174 heim_array_iterator_f_t fn) 175{ 176 CFIndex n, count = CFArrayGetCount((CFArrayRef)array); 177 int stop = 0; 178 for (n = 0; !stop && n < count; n++) 179 fn((heim_array_t)CFArrayGetValueAtIndex((CFArrayRef)array, n), &stop, ctx); 180} 181 182#if __BLOCKS__ 183void 184heim_array_iterate(heim_array_t array, heim_array_iterator_t fn) 185{ 186 CFIndex n, count = CFArrayGetCount((CFArrayRef)array); 187 int stop = 0; 188 for (n = 0; !stop && n < count; n++) 189 fn((heim_array_t)CFArrayGetValueAtIndex((CFArrayRef)array, n), &stop); 190} 191#endif 192 193size_t 194heim_array_get_length(heim_array_t array) 195{ 196 return CFArrayGetCount((CFArrayRef)array); 197} 198 199heim_object_t 200heim_array_copy_value(heim_array_t array, size_t idx) 201{ 202 CFTypeRef value = CFArrayGetValueAtIndex((CFArrayRef)array, idx); 203 if (value) 204 CFRetain(value); 205 return (heim_object_t)value; 206} 207 208void 209heim_array_delete_value(heim_array_t array, size_t idx) 210{ 211 CFArrayRemoveValueAtIndex((CFMutableArrayRef)array, idx); 212} 213 214#if __BLOCKS__ 215void 216heim_array_filter(heim_array_t array, int (^block)(heim_object_t)) 217{ 218 size_t n = 0; 219 220 while (n < CFArrayGetCount((CFArrayRef)array)) { 221 if (block((heim_array_t)CFArrayGetValueAtIndex((CFArrayRef)array, n))) { 222 heim_array_delete_value(array, n); 223 } else { 224 n++; 225 } 226 } 227} 228#endif 229 230int 231heim_array_contains_value(heim_array_t array, heim_object_t value) 232{ 233 return CFArrayContainsValue((CFArrayRef)array, CFRangeMake(0, CFArrayGetCount((CFArrayRef)array)), value); 234} 235 236heim_dict_t 237heim_dict_create(size_t size) 238{ 239 return (heim_dict_t)CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 240} 241 242heim_tid_t 243heim_dict_get_type_id(void) 244{ 245 return (heim_tid_t)CFDictionaryGetTypeID(); 246} 247 248heim_object_t 249heim_dict_copy_value(heim_dict_t dict, heim_object_t key) 250{ 251 heim_object_t obj = (heim_object_t)CFDictionaryGetValue((CFDictionaryRef)dict, key); 252 if (obj) 253 heim_retain(obj); 254 return obj; 255} 256 257int 258heim_dict_add_value(heim_dict_t dict, heim_object_t key, heim_object_t value) 259{ 260 CFDictionarySetValue((CFMutableDictionaryRef)dict, key, value); 261 return 0; 262} 263 264void 265heim_dict_delete_key(heim_dict_t dict, heim_object_t key) 266{ 267 CFDictionaryRemoveValue((CFMutableDictionaryRef)dict, key); 268} 269 270struct dict_iter { 271 heim_dict_t dict; 272 union { 273 heim_dict_iterator_f_t func; 274 void (^block)(heim_object_t, heim_object_t); 275 } u; 276 void *arg; 277}; 278 279static void 280dict_iterate_f(const void *key, const void *value, void *context) 281{ 282 struct dict_iter *ctx = context; 283 ctx->u.func(ctx->dict, (heim_object_t)key, (heim_object_t)value, ctx->arg); 284 285} 286 287void 288heim_dict_iterate_f(heim_dict_t dict, heim_dict_iterator_f_t func, void *arg) 289{ 290 struct dict_iter ctx = { 291 .dict = dict, 292 .u.func = func, 293 .arg = arg 294 }; 295 CFDictionaryApplyFunction((CFDictionaryRef)dict, dict_iterate_f, &ctx); 296} 297 298#ifdef __BLOCKS__ 299 300static void 301dict_iterate_b(const void *key, const void *value, void *context) 302{ 303 struct dict_iter *ctx = context; 304 ctx->u.block((heim_object_t)key, (heim_object_t)value); 305 306} 307 308void 309heim_dict_iterate(heim_dict_t dict, void (^func)(heim_object_t, heim_object_t)) 310{ 311 struct dict_iter ctx = { 312 .u.block = func 313 }; 314 CFDictionaryApplyFunction((CFDictionaryRef)dict, dict_iterate_b, &ctx); 315 316} 317#endif 318 319heim_string_t 320heim_string_create(const char *string) 321{ 322 return (heim_string_t)CFStringCreateWithCString(NULL, string, kCFStringEncodingUTF8); 323} 324 325heim_tid_t 326heim_string_get_type_id(void) 327{ 328 return (heim_tid_t)CFStringGetTypeID(); 329} 330 331char * 332heim_string_copy_utf8(heim_string_t string) 333{ 334 CFIndex len; 335 char *str; 336 337 str = (char *) CFStringGetCStringPtr((CFStringRef)string, kCFStringEncodingUTF8); 338 if (str) 339 return strdup(str); 340 341 len = CFStringGetLength((CFStringRef)string); 342 len = 1 + CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8); 343 str = malloc(len); 344 if (str == NULL) 345 return NULL; 346 347 if (!CFStringGetCString ((CFStringRef)string, str, len, kCFStringEncodingUTF8)) { 348 free (str); 349 return NULL; 350 } 351 return str; 352} 353 354heim_data_t 355heim_data_create(void *indata, size_t len) 356{ 357 return (heim_data_t)CFDataCreate(NULL, indata, len); 358} 359 360heim_tid_t 361heim_data_get_type_id(void) 362{ 363 return (heim_tid_t)CFDataGetTypeID(); 364} 365 366const void * 367heim_data_get_bytes(heim_data_t data) 368{ 369 return CFDataGetBytePtr((CFDataRef)data); 370} 371 372size_t 373heim_data_get_length(heim_data_t data) 374{ 375 return CFDataGetLength((CFDataRef)data); 376} 377 378static void 379heim_alloc_release(CFTypeRef type) 380{ 381 struct heim_base_uniq *mem = (struct heim_base_uniq *)type; 382 if (mem->dealloc) 383 mem->dealloc(mem); 384} 385 386static CFTypeID 387uniq_get_type_id(void) 388{ 389 static CFTypeID haid = _kCFRuntimeNotATypeID; 390 static dispatch_once_t inited; 391 392 dispatch_once(&inited, ^{ 393 static const CFRuntimeClass naclass = { 394 0, 395 "heim-alloc", 396 NULL, 397 NULL, 398 heim_alloc_release, 399 NULL, 400 NULL, 401 NULL, 402 NULL 403 }; 404 haid = _CFRuntimeRegisterClass(&naclass); 405 }); 406 407 return haid; 408} 409 410heim_object_t 411heim_uniq_alloc(size_t size, const char *name, heim_type_dealloc dealloc) 412{ 413 CFTypeID id = uniq_get_type_id(); 414 struct heim_base_uniq *mem; 415 416 heim_assert(size >= sizeof(struct heim_base_uniq), "uniq: size too small"); 417 418 if (id == _kCFRuntimeNotATypeID) 419 return NULL; 420 421 mem = _heim_create_cf_instance(id, size, "base-uniq"); 422 if (mem) { 423 mem->dealloc = dealloc; 424 mem->name = name; 425 } 426 427 return mem; 428} 429 430struct heim_error { 431 struct heim_base base; 432 int error_code; 433 heim_string_t msg; 434 struct heim_error *next; 435}; 436 437static void 438heim_error_release(CFTypeRef ptr) 439{ 440 struct heim_error *p = (struct heim_error *)ptr; 441 heim_release(p->msg); 442 heim_release(p->next); 443} 444 445 446static CFTypeID 447heim_error_get_type_id(void) 448{ 449 static CFTypeID haid = _kCFRuntimeNotATypeID; 450 static dispatch_once_t inited; 451 452 dispatch_once(&inited, ^{ 453 static const CFRuntimeClass naclass = { 454 0, 455 "heim-error", 456 NULL, 457 NULL, 458 heim_error_release, 459 NULL, 460 NULL, 461 NULL, 462 NULL 463 }; 464 haid = _CFRuntimeRegisterClass(&naclass); 465 }); 466 467 return haid; 468} 469 470 471heim_error_t 472heim_error_create(int error_code, const char *fmt, ...) 473{ 474 heim_error_t e; 475 va_list ap; 476 477 va_start(ap, fmt); 478 e = heim_error_createv(error_code, fmt, ap); 479 va_end(ap); 480 481 return e; 482} 483 484heim_error_t 485heim_error_createv(int error_code, const char *fmt, va_list ap) 486{ 487 CFTypeID id = heim_error_get_type_id(); 488 heim_error_t e; 489 char *str; 490 int len; 491 492 if (id == _kCFRuntimeNotATypeID) 493 return NULL; 494 495 str = malloc(1024); 496 if (str == NULL) 497 return NULL; 498 len = vsnprintf(str, 1024, fmt, ap); 499 if (len < 0) { 500 free(str); 501 return NULL; 502 } 503 504 e = _heim_create_cf_instance(id, sizeof(struct heim_error), "heim-error"); 505 if (e) { 506 e->msg = heim_string_create(str); 507 e->error_code = error_code; 508 e->next = NULL; 509 } 510 free(str); 511 512 return e; 513} 514 515heim_string_t 516heim_error_copy_string(heim_error_t error) 517{ 518 /* XXX concat all strings */ 519 return heim_retain(error->msg); 520} 521 522int 523heim_error_get_code(heim_error_t error) 524{ 525 return error->error_code; 526} 527 528heim_error_t 529heim_error_append(heim_error_t top, heim_error_t append) 530{ 531 if (top->next) 532 heim_release(top->next); 533 top->next = heim_retain(append); 534 return top; 535} 536 537heim_number_t 538heim_number_create(int number) 539{ 540 return (heim_number_t)CFNumberCreate(NULL, kCFNumberIntType, &number); 541} 542 543 544heim_tid_t 545heim_number_get_type_id(void) 546{ 547 return (heim_tid_t)CFNumberGetTypeID(); 548} 549 550int 551heim_number_get_int(heim_number_t number) 552{ 553 int num = 0; 554 CFNumberGetValue((CFNumberRef)number, kCFNumberIntType, &num); 555 return num; 556} 557 558heim_queue_t 559heim_queue_create(const char *name, heim_queue_attr_t attr) 560{ 561 return (heim_queue_t)dispatch_queue_create(name, NULL); 562} 563 564void 565heim_async_f(heim_queue_t queue, void *ctx, void (*callback)(void *data)) 566{ 567 dispatch_async_f((dispatch_queue_t)queue, ctx, callback); 568} 569 570heim_sema_t 571heim_sema_create(long count) 572{ 573 return (heim_sema_t)dispatch_semaphore_create(count); 574} 575 576void 577heim_sema_signal(heim_sema_t sema) 578{ 579 dispatch_semaphore_signal((dispatch_semaphore_t)sema); 580} 581 582void 583heim_sema_wait(heim_sema_t sema, time_t t) 584{ 585 dispatch_semaphore_wait((dispatch_semaphore_t)sema, 586 dispatch_time(DISPATCH_TIME_NOW, ((long long)t) * NSEC_PER_SEC)); 587} 588