1/* 2 * Copyright (c) 2008 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28#include <libc.h> 29#include "printPList_new.h" 30#include "misc_util.h" 31 32static void _indent(CFMutableStringRef string, unsigned indentLevel) 33{ 34 unsigned int i; 35 36 for (i = 0; i < indentLevel; i++) { 37 CFStringAppendCString(string, " ", kCFStringEncodingUTF8); 38 } 39 return; 40} 41 42static void _appendCFString( 43 CFMutableStringRef string, 44 CFStringRef aString, 45 Boolean withQuotes) 46{ 47 char * quote = ""; 48 49 if (withQuotes) quote = "\""; 50 CFStringAppendFormat(string, NULL, CFSTR("%s%@%s"), quote, aString, quote); 51 return; 52} 53 54static void _appendCFURL(CFMutableStringRef string, 55 CFURLRef anURL) 56{ 57 CFURLRef absURL = NULL; // must release 58 CFStringRef absPath = NULL; // must release 59 char pathBuffer[PATH_MAX]; 60 61 absURL = CFURLCopyAbsoluteURL(anURL); 62 if (!absURL) { 63 goto finish; 64 } 65 66 absPath = CFURLCopyFileSystemPath(anURL, kCFURLPOSIXPathStyle); 67 if (!absPath) { 68 goto finish; 69 } 70 CFURLGetFileSystemRepresentation(anURL, true, (UInt8 *)pathBuffer, 71 PATH_MAX); 72 CFStringAppendCString(string, pathBuffer, kCFStringEncodingUTF8); 73 74finish: 75 if (absURL) CFRelease(absURL); 76 if (absPath) CFRelease(absPath); 77 return; 78} 79 80static void _appendPlist( 81 CFMutableStringRef string, 82 CFTypeRef plist, 83 CFTypeRef plistRoot, 84 PListStyle style, 85 unsigned indentLevel) 86{ 87 CFTypeID typeID = 0; 88 unsigned int indentIncrement = 4; 89 90 if (!plist) { 91 return; 92 } 93 94 /* Don't indent the top-level keys/indices of the plist. 95 */ 96 if (plist == plistRoot) { 97 indentIncrement = 0; 98 } 99 100 typeID = CFGetTypeID(plist); 101 102 if (typeID == CFDictionaryGetTypeID()) { 103 CFDictionaryRef dict = (CFDictionaryRef)plist; 104 CFIndex count, i; 105 CFStringRef * keys = NULL; // must free 106 CFTypeRef * values = NULL; // must free 107 count = CFDictionaryGetCount(dict); 108 keys = (CFStringRef *)malloc(count * sizeof(CFStringRef)); 109 values = (CFTypeRef *)malloc(count * sizeof(CFTypeRef)); 110 111 CFDictionaryGetKeysAndValues(dict, (const void **)keys, 112 (const void **)values); 113 114 if (style == kPListStyleDiagnostics) { 115 // no newline at beginning of diagnostics printout 116 if (plist != plistRoot) { 117 CFStringAppendCString(string, "\n", kCFStringEncodingUTF8); 118 } 119 } else { 120 // no indent before first brace, it's on the end of the line 121 CFStringAppendCString(string, "{\n", kCFStringEncodingUTF8); 122 } 123 for (i = 0; i < count; i++) { 124 125 _indent(string, indentLevel + indentIncrement); 126 _appendCFString(string, keys[i], 127 /* quotes */ (style != kPListStyleDiagnostics)); 128 129 if ( (CFBooleanGetTypeID() == CFGetTypeID(values[i])) && 130 (style == kPListStyleDiagnostics) ) { 131 132 CFStringAppendFormat(string, NULL, CFSTR("\n")); 133 continue; // diagnostics doesn't print bools! 134 } 135 136 if (style == kPListStyleDiagnostics) { 137 CFStringAppendCString(string, ": ", kCFStringEncodingUTF8); 138 } else { 139 CFStringAppendCString(string, " = ", kCFStringEncodingUTF8); 140 } 141 if (CFGetTypeID(values[i]) == CFStringGetTypeID()) { 142 CFIndex keyLength = CFStringGetLength(keys[i]); 143 CFIndex valueLength = CFStringGetLength(values[i]); 144 145 /* drop value for a really long key+string combo down a line */ 146 if (indentLevel + indentIncrement + keyLength + valueLength > 72) { 147 CFStringAppendCString(string, "\n", kCFStringEncodingUTF8); 148 _indent(string, indentLevel + (4 + indentIncrement)); 149 } 150 } 151 _appendPlist(string, values[i], plistRoot, style, indentLevel + 152 indentIncrement); 153 154 /* Put newlines bewteen top-level dict properties for diagnostics. 155 */ 156 if (style == kPListStyleDiagnostics && (i + 1 < count)) { 157 if (plist == plistRoot) { 158 CFStringAppendCString(string, "\n", kCFStringEncodingUTF8); 159 } 160 } 161 } 162 if (style != kPListStyleDiagnostics) { 163 _indent(string, indentLevel); 164 CFStringAppendCString(string, "}\n", kCFStringEncodingUTF8); 165 } 166 free(keys); 167 free(values); 168 } else if (typeID == CFArrayGetTypeID()) { 169 CFArrayRef array = (CFArrayRef)plist; 170 CFIndex count, i; 171 count = CFArrayGetCount(array); 172 173 // no indent before first parenthesis 174 // no newline at beginning of diagnostics printout 175 if (style == kPListStyleDiagnostics && (plist != plistRoot)) { 176 // no newline at beginning of diagnostics printout 177 if (plist != plistRoot) { 178 CFStringAppendCString(string, "\n", kCFStringEncodingUTF8); 179 } 180 } else { 181 CFStringAppendCString(string, "(\n", kCFStringEncodingUTF8); 182 } 183 for (i = 0; i < count; i++) { 184 _indent(string, indentLevel + indentIncrement); 185 _appendPlist(string, CFArrayGetValueAtIndex(array, i), plistRoot, 186 style, indentLevel + indentIncrement); 187 } 188 if (style != kPListStyleDiagnostics) { 189 _indent(string, indentLevel); 190 CFStringAppendCString(string, ")\n", kCFStringEncodingUTF8); 191 } 192 } else if (typeID == CFStringGetTypeID()) { 193 _appendCFString(string, (CFStringRef)plist, 194 /* quotes */ ((indentLevel > 0) && (style != kPListStyleDiagnostics))); 195 CFStringAppendCString(string, "\n", kCFStringEncodingUTF8); 196 } else if (typeID == CFURLGetTypeID()) { 197 _appendCFURL(string, (CFURLRef)plist); 198 CFStringAppendCString(string, "\n", kCFStringEncodingUTF8); 199 } else if (typeID == CFDataGetTypeID()) { 200 // only show a little bit of the data up front 201 CFStringRef dataString = createCFStringForData((CFDataRef)plist, 16); 202 if (dataString) { 203 CFStringAppend(string, dataString); 204 CFStringAppendCString(string, "\n", kCFStringEncodingUTF8); 205 SAFE_RELEASE(dataString); 206 } else { 207 CFStringAppendCString(string, "(data object)\n", kCFStringEncodingUTF8); 208 } 209 } else if (typeID == CFNumberGetTypeID()) { 210 CFStringAppendFormat(string, NULL, CFSTR("%@"), (CFNumberRef)plist); 211 CFStringAppendCString(string, "\n", kCFStringEncodingUTF8); 212 } else if (typeID == CFBooleanGetTypeID()) { 213 CFBooleanRef booleanValue = (CFBooleanRef)plist; 214 CFStringAppendFormat(string, NULL, CFSTR("%s\n"), 215 CFBooleanGetValue(booleanValue) ? "true" : "false"); 216 } else if (typeID == CFDateGetTypeID()) { 217 CFStringAppendCString(string, "(date object)\n", kCFStringEncodingUTF8); 218 } else { 219 CFStringAppendCString(string, "(unknown object)\n", kCFStringEncodingUTF8); 220 } 221 222 return; 223} 224 225void printPList_new(FILE * stream, CFTypeRef plist, PListStyle style) 226{ 227 CFMutableStringRef string = NULL; // must release 228 CFIndex bufSize; 229 char * c_string = NULL; // must free 230 231 string = createCFStringForPlist_new(plist, style); 232 if (!string) { 233 goto finish; 234 } 235 236 bufSize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(string), 237 kCFStringEncodingUTF8) + sizeof('\0'); 238 c_string = (char *)malloc(bufSize); 239 if (!c_string) { 240 goto finish; 241 } 242 243 if (CFStringGetCString(string, c_string, bufSize, kCFStringEncodingUTF8)) { 244 fprintf(stream, "%s", c_string); 245 } 246 247finish: 248 if (string) CFRelease(string); 249 if (c_string) free(c_string); 250 return; 251} 252 253// use in GDB 254void showPList_new(CFPropertyListRef plist, PListStyle style) 255{ 256 printPList_new(stdout, plist, style); 257 return; 258} 259 260CFMutableStringRef createCFStringForPlist_new(CFTypeRef plist, PListStyle style) 261{ 262 CFMutableStringRef string = NULL; // must release 263 264 string = CFStringCreateMutable(kCFAllocatorDefault, 0); 265 if (!string) { 266 goto finish; 267 } 268 269 _appendPlist(string, plist, plist, style, 0); 270 271finish: 272 return string; 273} 274