1/*
2 * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 *  BLGetCStringRepresentation.c
25 *  bless
26 *
27 *  Created by Shantonu Sen on 5/30/06.
28 *  Copyright 2006-2007 Apple Inc. All Rights Reserved.
29 *
30 */
31
32#include <stdlib.h>
33#include <stdarg.h>
34#include <stdio.h>
35#include <unistd.h>
36#include <pthread.h>
37
38#include <CoreFoundation/CoreFoundation.h>
39
40#include "bless.h"
41#include "bless_private.h"
42
43/*
44 * For the given CFTypeRef, get a C-string representation, backed
45 * by thread-local storage
46 */
47
48#if !defined(NO_GETCSTRING) || !NO_GETCSTRING
49
50static pthread_once_t	blcstr_once_control = PTHREAD_ONCE_INIT;
51static pthread_key_t	blcstr_key = 0;
52
53static void initkey(void);
54static void releasestorage(void *addr);
55
56struct stringer {
57	size_t		size;
58	char	*	string;
59};
60
61char *BLGetCStringDescription(CFTypeRef typeRef) {
62
63	CFStringRef desc = NULL;
64	int ret;
65	struct stringer	*storage;
66	CFIndex	strsize;
67
68	if(typeRef == NULL)
69		return NULL;
70
71	ret = pthread_once(&blcstr_once_control, initkey);
72	if(ret)
73		return NULL;
74
75	if(CFGetTypeID(typeRef) == CFStringGetTypeID()) {
76		desc = CFRetain(typeRef);
77	} else {
78		desc = CFCopyDescription(typeRef);
79	}
80	if(desc == NULL)
81		return NULL;
82
83	strsize = CFStringGetLength(desc);
84
85	// assume encoding size of 3x as UTF-8
86	strsize = 3*strsize + 1;
87
88	storage = (struct stringer	*)pthread_getspecific(blcstr_key);
89	if(storage == NULL) {
90		storage = malloc(sizeof(*storage));
91		storage->size = (size_t)strsize;
92		storage->string = malloc(storage->size);
93
94		ret = pthread_setspecific(blcstr_key, storage);
95		if(ret) {
96			CFRelease(desc);
97			free(storage->string);
98			free(storage);
99			fprintf(stderr, "pthread_setspecific failed\n");
100			return NULL;
101		}
102
103	} else if(storage->size < strsize) {
104		// need more space
105		storage->size = (size_t)strsize;
106		free(storage->string);
107		storage->string = malloc(storage->size);
108	}
109
110	if(!CFStringGetCString(desc, storage->string, (CFIndex)storage->size, kCFStringEncodingUTF8)) {
111		CFRelease(desc);
112		fprintf(stderr, "CFStringGetCString failed\n");
113		return NULL;
114	}
115
116	CFRelease(desc);
117
118	return storage->string;
119}
120
121static void initkey(void)
122{
123	int ret;
124
125	ret = pthread_key_create(&blcstr_key, releasestorage);
126	if(ret)
127		fprintf(stderr, "pthread_key_create failed\n");
128//	printf("pthread_key_create: %lu\n", blcstr_key);
129}
130
131static void releasestorage(void *addr)
132{
133	// should be non-NULL
134	struct stringer	*storage = (struct stringer	*)addr;
135
136	free(storage->string);
137	free(storage);
138}
139
140#else
141
142char *BLGetCStringDescription(CFTypeRef typeRef) {
143	return NULL;
144}
145#endif
146