1/*
2 * Copyright (c) 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// Mac OS X: llvm-gcc -F<path-to-CFLite-framework> -framework CoreFoundation Examples/plconvert.c -o plconvert
25
26// Linux: clang -I/usr/local/include -L/usr/local/lib -lCoreFoundation plconvert.c -o plconvert
27
28/*
29 This example shows usage of CFString, CFData, and other CFPropertyList types. It takes two arguments:
30    1. A property list file to read, in either binary or XML property list format.
31    2. A file name to write a converted property list file to.
32 If the first input is binary, the output is XML and vice-versa.
33*/
34
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <fcntl.h>
38#include <string.h>
39#include <stdio.h>
40#include <unistd.h>
41
42#include <CoreFoundation/CoreFoundation.h>
43
44static void logIt(CFStringRef format, ...) {
45    va_list args;
46    va_start(args, format);
47    CFStringRef str = CFStringCreateWithFormatAndArguments(kCFAllocatorSystemDefault, NULL, format, args);
48    if (!str) return;
49
50    CFIndex blen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8);
51    char *buf = str ? (char *)malloc(blen + 1) : 0;
52    if (buf) {
53        Boolean converted = CFStringGetCString(str, buf, blen, kCFStringEncodingUTF8);
54        if (converted) {
55            // null-terminate
56            buf[blen] = 0;
57            printf("%s\n", buf);
58        }
59    }
60    if (buf) free(buf);
61    if (str) CFRelease(str);      va_end(args);
62}
63
64static CFMutableDataRef createDataFromFile(const char *fname) {
65    int fd = open(fname, O_RDONLY);
66    CFMutableDataRef res = CFDataCreateMutable(kCFAllocatorSystemDefault, 0);
67    char buf[4096];
68
69    ssize_t amountRead;
70    while ((amountRead = read(fd, buf, 4096)) > 0) {
71        CFDataAppendBytes(res, (const UInt8 *)buf, amountRead);
72    }
73
74    close(fd);
75    return res;
76}
77
78static bool writeDataToFile(CFDataRef data, const char *fname) {
79    int fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0666);
80    if (fd < 0) {
81        printf("There was an error creating the file: %d", errno);
82        return false;
83    }
84    int dataLen = CFDataGetLength(data);
85    int w = write(fd, CFDataGetBytePtr(data), dataLen);
86    fsync(fd);
87    close(fd);
88    if (w != dataLen) return false;
89    return true;
90}
91
92int main(int argc, char **argv) {
93
94    if (argc != 3) {
95        printf("Usage: plconvert <in file> <out file>\nIf the in file is an XML property list, convert to binary property list in out file. If the in file is a binary property list, convert to XML property list in out file.\n");
96    } else {
97        CFMutableDataRef plistData = createDataFromFile(argv[1]);
98        if (!plistData) {
99            printf("Unable to create data from file name: %s", argv[1]);
100        } else {
101            CFPropertyListFormat fmt;
102            CFErrorRef err;
103            CFPropertyListRef plist = CFPropertyListCreateWithData(kCFAllocatorSystemDefault, (CFDataRef)plistData, 0, &fmt, &err);
104            if (!plist) {
105                logIt(CFSTR("Unable to create property list from data: %@"), err);
106            } else {
107                logIt(CFSTR("Property list contents:\n%@"), plist);
108                if (fmt == kCFPropertyListBinaryFormat_v1_0) {
109                    logIt(CFSTR("Converting to XML property list at: %s"), argv[2]);
110                    fmt = kCFPropertyListXMLFormat_v1_0;
111                } else if (fmt == kCFPropertyListXMLFormat_v1_0) {
112                    logIt(CFSTR("Converting to binary property list at: %s"), argv[2]);
113                    fmt = kCFPropertyListBinaryFormat_v1_0;
114                } else {
115                    logIt(CFSTR("Unknown property list format! Not converting output format."));
116                }
117
118                CFDataRef outputData = CFPropertyListCreateData(kCFAllocatorSystemDefault, plist, fmt, 0, &err);
119                if (!outputData) {
120                    logIt(CFSTR("Unable to write property list to data: %@"), err);
121                } else {
122                    bool success = writeDataToFile(outputData, argv[2]);
123                    if (!success) {
124                        logIt(CFSTR("Unable to write data to file"));
125                    }
126                    CFRelease(outputData);
127                }
128                CFRelease(plist);
129            }
130            CFRelease(plistData);
131        }
132    }
133}
134