1/*
2 * Copyright (c) 2005 Apple Computer, 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 *  UtilitiesCFPrettyPrint.c
25 *  DiskImages
26 *
27 *  Created by Shantonu Sen on 8/11/04.
28 *  Copyright 2004 Apple Computer, Inc. All rights reserved.
29 *
30 */
31
32#include "UtilitiesCFPrettyPrint.h"
33
34typedef struct TAOCFDepth_Counter {
35    int depth;
36    int arrayIndex;
37    char *indent;
38    FILE *out;
39} TAOCFDepth_Counter;
40
41static void _TAOCFLabelPrettyPrint(char *label, CFTypeRef value, void *context);
42static void _TAOCFDictionaryPrettyPrint(const void *key, const void *value, void *context);
43static void _TAOCFArrayPrettyPrint(const void *value, void *context);
44static void _TAOCFTreePrettyPrint(const void *value, void *context);
45static void _TAOCFBagPrettyPrint(const void *value, void *context);
46static void _TAOCFScalarPrettyPrint(const void *value, void *context);
47static void _TAOCFPrettyPrint_recurse(CFTypeRef inRef, void *h);
48
49static char *	_TAOCFGetDescriptionAsCString(CFTypeRef typeRef);
50
51static void _TAOCFLabelPrettyPrint(char *label, CFTypeRef value, void *context) {
52    TAOCFDepth_Counter *h = (TAOCFDepth_Counter *)context;
53    int i;
54    char *desc;
55
56    // we're printing at least label, so tab over
57
58    for(i=0; i< h->depth; i++) {
59        fprintf(h->out, h->indent);
60    }
61
62    fprintf(h->out, "%s", label);
63
64    if(value == NULL) {
65	// our job here is done
66	fprintf(h->out, "\n");
67	return;
68    }
69
70    if(label && label[0]) {
71	fprintf(h->out, ":");
72    }
73
74    if(CFGetTypeID(value) == CFDictionaryGetTypeID()
75       || CFGetTypeID(value) == CFArrayGetTypeID()
76       || CFGetTypeID(value) == CFTreeGetTypeID()
77       || CFGetTypeID(value) == CFBagGetTypeID() ) {
78        // go to next line, indent, and recurse
79        TAOCFDepth_Counter newhelper;
80
81	fprintf(h->out, "\n");
82
83        newhelper.depth = h->depth + 1;
84	newhelper.out = h->out;
85	newhelper.arrayIndex = 0;
86	newhelper.indent = h->indent;
87	_TAOCFPrettyPrint_recurse((CFTypeRef) value, &newhelper);
88    } else {
89        // just a regular key value pair. print
90	desc = _TAOCFGetDescriptionAsCString((CFTypeRef)value);
91	if(label && label[0]) {
92	    fprintf(h->out, " ");
93	}
94	if(desc) {
95	    fprintf(h->out, "%s\n", desc);
96	    free(desc);
97	} else {
98	    fprintf(h->out, "(NULL)\n");
99	}
100    }
101}
102
103static void _TAOCFDictionaryPrettyPrint(const void *key, const void *value, void *context) {
104    char *desc;
105
106    desc = _TAOCFGetDescriptionAsCString((CFTypeRef)key);
107
108    _TAOCFLabelPrettyPrint(desc, (CFTypeRef) value, context);
109
110    if(desc) {
111	free(desc);
112    }
113}
114
115static void _TAOCFArrayPrettyPrint(const void *value, void *context) {
116    char desc[256];
117
118    snprintf(desc, 256, "%d", ((TAOCFDepth_Counter *)context)->arrayIndex++);
119
120    _TAOCFLabelPrettyPrint(desc, (CFTypeRef)value, context);
121}
122
123static void _TAOCFBagPrettyPrint(const void *value, void *context) {
124
125    _TAOCFLabelPrettyPrint("", (CFTypeRef)value, context);
126}
127
128static void _TAOCFTreePrettyPrint(const void *value, void *context) {
129    //char desc[256];
130    CFTreeContext treeContext;
131    TAOCFDepth_Counter newhelper;
132
133    newhelper.depth = ((TAOCFDepth_Counter *)context)->depth + 1;
134    newhelper.out = ((TAOCFDepth_Counter *)context)->out;
135    newhelper.indent = ((TAOCFDepth_Counter *)context)->indent;
136    newhelper.arrayIndex = 0;
137
138    //	snprintf(desc, 256, "%d", ((TAOCFDepth_Counter *)context)->arrayIndex++);
139
140    CFTreeGetContext((CFTreeRef)value, &treeContext);
141
142    _TAOCFLabelPrettyPrint("", (CFTypeRef)treeContext.info, context);
143
144    // It's a little non-standard to recurse here, but otherwise
145    // we couldn't print the head of the tree.
146    CFTreeApplyFunctionToChildren((CFTreeRef)value,
147				  _TAOCFTreePrettyPrint, &newhelper);
148}
149
150static void _TAOCFScalarPrettyPrint(const void *value, void *context) {
151    char *desc;
152
153    desc = _TAOCFGetDescriptionAsCString((CFTypeRef)value);
154
155    _TAOCFLabelPrettyPrint(desc, NULL, context);
156
157    if(desc) {
158	free(desc);
159    }
160}
161
162
163// Used to split CFTypes into key:value form
164static void _TAOCFPrettyPrint_recurse(CFTypeRef inRef, void *h) {
165
166    if(inRef == NULL) {
167	_TAOCFScalarPrettyPrint(inRef, h);
168    } else if(CFGetTypeID(inRef) == CFDictionaryGetTypeID()) {
169	// if we have a dictionary, apply the output function
170	CFDictionaryApplyFunction((CFDictionaryRef)inRef,
171				  _TAOCFDictionaryPrettyPrint, h);
172    } else if(CFGetTypeID(inRef) == CFArrayGetTypeID()) {
173	CFArrayApplyFunction((CFArrayRef)inRef,
174			     CFRangeMake(0, CFArrayGetCount((CFArrayRef)inRef)),
175			     _TAOCFArrayPrettyPrint, h);
176    } else if(CFGetTypeID(inRef) == CFTreeGetTypeID()) {
177	_TAOCFTreePrettyPrint(inRef, h);
178    } else if(CFGetTypeID(inRef) == CFBagGetTypeID()) {
179	CFBagApplyFunction(inRef, _TAOCFBagPrettyPrint, h);
180    } else {
181	_TAOCFScalarPrettyPrint(inRef, h);
182    }
183
184}
185
186
187void TAOCFPrettyPrint(CFTypeRef inRef) {
188    TAOCFPrettyPrintToFile(inRef, stdout);
189}
190
191void TAOCFPrettyPrintWithIndenter(CFTypeRef inRef, char *indent) {
192    TAOCFPrettyPrintToFileWithIndenter(inRef, stdout, indent);
193}
194
195void TAOCFPrettyPrintToFile(CFTypeRef inRef, FILE *out) {
196    TAOCFPrettyPrintToFileWithIndenter(inRef, out, "\t");
197}
198
199void TAOCFPrettyPrintToFileWithIndenter(CFTypeRef inRef, FILE *out, char *indent) {
200    TAOCFDepth_Counter helper;
201
202    helper.depth = 0;
203    helper.out = out;
204    helper.arrayIndex = 0;
205    helper.indent = indent;
206
207    _TAOCFPrettyPrint_recurse(inRef, &helper);
208
209}
210
211
212static char *	_TAOCFGetDescriptionAsCString(CFTypeRef typeRef)
213{
214    char	    *str = NULL;
215    CFStringRef	    cfstr = NULL;
216    CFIndex	    len;
217
218//    if(typeRef == NULL) typeRef = kCFNull;
219    cfstr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), typeRef);
220    if(cfstr == NULL && typeRef != NULL) cfstr = CFSTR("<error getting string representation>");
221
222    // add one for the NULL that CFStringGetCString will append
223    len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr), kCFStringEncodingUTF8) + 1;
224    str = malloc(len);
225    if (str) {
226	if (!CFStringGetCString(cfstr, str, len, kCFStringEncodingUTF8)) {
227	    free(str);
228	    str = NULL;
229	}
230    }
231
232    return str;
233}
234