1/*
2 * Copyright (c) 2010-2012,2014 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
25#include "misc.h"
26
27
28// NOTE: the return may or allocate a fair bit more space then it needs.
29// Use it for short lived conversions (or strdup the result).
30char *utf8(CFStringRef s) {
31	CFIndex sz = CFStringGetMaximumSizeForEncoding(CFStringGetLength(s), kCFStringEncodingUTF8) + 1;
32	CFIndex used = 0;
33	UInt8 *buf = (UInt8 *)malloc(sz);
34	if (!buf) {
35		return NULL;
36	}
37	CFStringGetBytes(s, CFRangeMake(0, CFStringGetLength(s)), kCFStringEncodingUTF8, '?', FALSE, buf, sz, &used);
38	buf[used] = 0;
39
40	return (char*)buf;
41}
42
43void CFfprintf(FILE *f, const char *format, ...) {
44	va_list ap;
45	va_start(ap, format);
46
47	CFStringRef fmt = CFStringCreateWithCString(NULL, format, kCFStringEncodingUTF8);
48	CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, fmt, ap);
49	va_end(ap);
50	CFRelease(fmt);
51
52	CFIndex sz = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8);
53	sz += 1;
54	CFIndex used = 0;
55	unsigned char *buf;
56	bool needs_free = false;
57	if (sz < 1024) {
58		buf = alloca(sz);
59	} else {
60		buf = malloc(sz);
61		needs_free = true;
62	}
63	if (buf) {
64		CFStringGetBytes(str, CFRangeMake(0, CFStringGetLength(str)), kCFStringEncodingUTF8, '?', FALSE, buf, sz, &used);
65	} else {
66		buf = (unsigned char *)"malloc failue during CFfprintf\n";
67	}
68
69	fwrite(buf, 1, used, f);
70	if (needs_free) {
71		free(buf);
72	}
73
74	CFRelease(str);
75}
76
77CFErrorRef fancy_error(CFStringRef domain, CFIndex code, CFStringRef description) {
78	const void *v_ekey = kCFErrorDescriptionKey;
79	const void *v_description = description;
80	CFErrorRef err = CFErrorCreateWithUserInfoKeysAndValues(NULL, domain, code, &v_ekey, &v_description, 1);
81
82	return err;
83}
84
85static
86void add_t2ca(CFMutableDictionaryRef t2ca, CFStringRef t, CFStringRef a) {
87	CFMutableSetRef ca = (CFMutableSetRef)CFDictionaryGetValue(t2ca, t);
88	if (!ca) {
89		ca = CFSetCreateMutable(NULL, 0, &kCFCopyStringSetCallBacks);
90		CFDictionarySetValue(t2ca, t, ca);
91	}
92	CFSetAddValue(ca, a);
93}
94
95void CFSafeRelease(CFTypeRef object) {
96	if (object) {
97		CFRelease(object);
98	}
99}
100
101void graphviz(FILE *f, SecTransformRef tr) {
102	CFDictionaryRef d = SecTransformCopyExternalRepresentation(tr);
103
104	CFfprintf(f, "digraph TR {\n\tnode [shape=plaintext];\n\n");
105	CFIndex i, j;
106	CFArrayRef transforms = CFDictionaryGetValue(d, CFSTR("TRANSFORMS"));
107	CFArrayRef connections = CFDictionaryGetValue(d, CFSTR("ARRAY"));
108
109
110	// map transforms to connected attributes
111	CFMutableDictionaryRef t2ca = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
112	for(i = 0; i < CFArrayGetCount(connections); i++) {
113		CFDictionaryRef c = CFArrayGetValueAtIndex(connections, i);
114
115		CFStringRef t_from = CFDictionaryGetValue(c, CFSTR("FROM_NAME"));
116		CFStringRef t_to = CFDictionaryGetValue(c, CFSTR("TO_NAME"));
117		CFStringRef a_from = CFDictionaryGetValue(c, CFSTR("FROM_ATTRIBUTE"));
118		CFStringRef a_to = CFDictionaryGetValue(c, CFSTR("TO_ATTRIBUTE"));
119
120		add_t2ca(t2ca, t_from, a_from);
121		add_t2ca(t2ca, t_to, a_to);
122	}
123
124
125	for(i = 0; i < CFArrayGetCount(transforms); i++) {
126		CFDictionaryRef t = CFArrayGetValueAtIndex(transforms, i);
127		// NAME STATE(dict) TYPE
128		CFStringRef name = CFDictionaryGetValue(t, CFSTR("NAME"));
129
130		CFfprintf(f, "\tsubgraph \"cluster_%@\"{\n", name);
131
132		CFMutableSetRef ca = (CFMutableSetRef)CFDictionaryGetValue(t2ca, name);
133		if (ca) {
134			CFIndex cnt = CFSetGetCount(ca);
135			CFStringRef *attrs = malloc(cnt * sizeof(CFStringRef));
136			CFSetGetValues(ca, (const void **)attrs);
137
138			for(j = 0; j < cnt; j++) {
139				CFfprintf(f, "\t\t\"%@#%@\" [label=\"%@\"];\n", name, attrs[j], attrs[j]);
140			}
141			CFfprintf(f, "\t\t\"%@\" [fontcolor=blue, fontsize=20];\n\t}\n");
142		}
143	}
144
145	CFfprintf(f, "\n");
146
147	for(i = 0; i < CFArrayGetCount(connections); i++) {
148		CFDictionaryRef c = CFArrayGetValueAtIndex(connections, i);
149
150		CFStringRef t_from = CFDictionaryGetValue(c, CFSTR("FROM_NAME"));
151		CFStringRef t_to = CFDictionaryGetValue(c, CFSTR("TO_NAME"));
152		CFStringRef a_from = CFDictionaryGetValue(c, CFSTR("FROM_ATTRIBUTE"));
153		CFStringRef a_to = CFDictionaryGetValue(c, CFSTR("TO_ATTRIBUTE"));
154
155		CFfprintf(f, "\t\"%@#%@\" -> \"%@#%@\";\n", t_from, a_from, t_to, a_to);
156	}
157
158	CFfprintf(f, "}\n");
159
160	CFfprintf(f, "\n/*\n%@\n/*\n", d);
161}
162