2 * Copyright (c) 2008 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 Copyright 1999-2002, Apple, Inc. All rights reserved.
25 Responsibility: Becky Willrich
29 CFData read/write routines
32 #include "CFInternal.h"
33 #include <CoreFoundation/CFBase.h>
34 #include <CoreFoundation/CFURL.h>
35 #include <CoreFoundation/CFDictionary.h>
36 #include <CoreFoundation/CFURLAccess.h>
37 #include <CoreFoundation/CFDate.h>
38 #include <CoreFoundation/CFNumber.h>
40 #if DEPLOYMENT_TARGET_MACOSX
45 #include <sys/types.h>
52 #if DEPLOYMENT_TARGET_MACOSX
54 DEFINE_WEAK_CFNETWORK_FUNC(Boolean
, _CFURLCreateDataAndPropertiesFromResource
, (CFAllocatorRef A
, CFURLRef B
, CFDataRef
*C
, CFDictionaryRef
*D
, CFArrayRef E
, SInt32
*F
), (A
, B
, C
, D
, E
, F
), false)
55 DEFINE_WEAK_CFNETWORK_FUNC(Boolean
, _CFURLWriteDataAndPropertiesToResource
, (CFURLRef A
, CFDataRef B
, CFDictionaryRef C
, SInt32
*D
), (A
, B
, C
, D
), false)
56 DEFINE_WEAK_CFNETWORK_FUNC(Boolean
, _CFURLDestroyResource
, (CFURLRef A
, SInt32
*B
), (A
, B
), false)
61 CONST_STRING_DECL(kCFURLFileExists
, "kCFURLFileExists")
62 CONST_STRING_DECL(kCFURLFilePOSIXMode
, "kCFURLFilePOSIXMode")
63 CONST_STRING_DECL(kCFURLFileDirectoryContents
, "kCFURLFileDirectoryContents")
64 CONST_STRING_DECL(kCFURLFileLength
, "kCFURLFileLength")
65 CONST_STRING_DECL(kCFURLFileLastModificationTime
, "kCFURLFileLastModificationTime")
66 CONST_STRING_DECL(kCFURLFileOwnerID
, "kCFURLFileOwnerID")
67 CONST_STRING_DECL(kCFURLHTTPStatusCode
, "kCFURLHTTPStatusCode")
68 CONST_STRING_DECL(kCFURLHTTPStatusLine
, "kCFURLHTTPStatusLine")
70 CONST_STRING_DECL(kCFDataURLDataLength
, "kCFDataURLDataLength")
71 CONST_STRING_DECL(kCFDataURLMimeType
, "kCFDataURLMimeType")
72 CONST_STRING_DECL(kCFDataURLTextEncodingName
, "kCFDataURLTextEncodingName")
74 // Compatibility property strings -- we obsoleted these names pre-DP4. REW, 5/22/2000
75 CONST_STRING_DECL(kCFFileURLExists
, "kCFURLFileExists")
76 CONST_STRING_DECL(kCFFileURLPOSIXMode
, "kCFURLFilePOSIXMode")
77 CONST_STRING_DECL(kCFFileURLDirectoryContents
, "kCFURLFileDirectoryContents")
78 CONST_STRING_DECL(kCFFileURLSize
, "kCFURLFileLength")
79 CONST_STRING_DECL(kCFFileURLLastModificationTime
, "kCFURLFileLastModificationTime")
80 CONST_STRING_DECL(kCFHTTPURLStatusCode
, "kCFURLHTTPStatusCode")
81 CONST_STRING_DECL(kCFHTTPURLStatusLine
, "kCFURLHTTPStatusLine")
83 // Copied pretty much verbatim from NSData; note that files are still special cased in this code. Ultimately, we probably want to treat file URLs the same way as any other URL (go through the URL Access layer). -- REW, 10/21/98
85 /*************************/
86 /* file: access routines */
87 /*************************/
89 //#warning CF:For the moment file access failures are ill defined and set the error code to kCFURLUnknownError
91 static CFDictionaryRef
_CFFileURLCreatePropertiesFromResource(CFAllocatorRef alloc
, CFURLRef url
, CFArrayRef desiredProperties
, SInt32
*errorCode
) {
92 // MF:!!! This could/should be changed to use _CFGetFileProperties() to do the actual figuring.
93 static CFArrayRef _allProps
= NULL
;
96 CFMutableDictionaryRef propertyDict
= NULL
;
101 CFDateRef modTime
= NULL
, *modTimePtr
= NULL
;
102 CFArrayRef contents
= NULL
, *contentsPtr
= NULL
;
105 if (errorCode
) *errorCode
= 0;
106 if (!desiredProperties
) {
107 // Cheap and dirty hack to make this work for the moment; ultimately we need to do something more sophisticated. This will result in an error return whenever a property key is defined which isn't applicable to all file URLs. REW, 3/2/99
109 const void *values
[9];
110 values
[0] = kCFURLFileExists
;
111 values
[1] = kCFURLFilePOSIXMode
;
112 values
[2] = kCFURLFileDirectoryContents
;
113 values
[3] = kCFURLFileLength
;
114 values
[4] = kCFURLFileLastModificationTime
;
115 values
[5] = kCFURLFileOwnerID
;
116 _allProps
= CFArrayCreate(kCFAllocatorSystemDefault
, values
, 6, &kCFTypeArrayCallBacks
);
118 desiredProperties
= _allProps
;
121 arrayRange
.location
= 0;
122 arrayRange
.length
= CFArrayGetCount(desiredProperties
);
123 propertyDict
= CFDictionaryCreateMutable(alloc
, 0, & kCFTypeDictionaryKeyCallBacks
, & kCFTypeDictionaryValueCallBacks
);
124 if (arrayRange
.length
== 0) return propertyDict
;
126 if (CFArrayContainsValue(desiredProperties
, arrayRange
, kCFURLFileDirectoryContents
)) {
127 contentsPtr
= &contents
;
129 if (CFArrayContainsValue(desiredProperties
, arrayRange
, kCFURLFileLastModificationTime
)) {
130 modTimePtr
= &modTime
;
133 if (_CFGetFileProperties(alloc
, url
, &exists
, &posixMode
, &size
, modTimePtr
, &ownerID
, contentsPtr
) != 0) {
135 *errorCode
= kCFURLUnknownError
;
140 for (idx
= 0; idx
< arrayRange
.length
; idx
++) {
141 CFStringRef key
= (CFMutableStringRef
)CFArrayGetValueAtIndex(desiredProperties
, idx
);
142 if (key
== kCFURLFilePOSIXMode
|| CFEqual(kCFURLFilePOSIXMode
, key
)) {
144 CFNumberRef num
= CFNumberCreate(alloc
, kCFNumberSInt32Type
, &posixMode
);
145 CFDictionarySetValue(propertyDict
, kCFURLFilePOSIXMode
, num
);
147 } else if (errorCode
) {
148 *errorCode
= kCFURLUnknownError
;
150 } else if (key
== kCFURLFileDirectoryContents
|| CFEqual(kCFURLFileDirectoryContents
, key
)) {
151 if (exists
&& (posixMode
& S_IFMT
) == S_IFDIR
&& contents
) {
152 CFDictionarySetValue(propertyDict
, kCFURLFileDirectoryContents
, contents
);
153 } else if (errorCode
) {
154 *errorCode
= kCFURLUnknownError
;
156 } else if (key
== kCFURLFileLength
|| CFEqual(kCFURLFileLength
, key
)) {
158 CFNumberRef num
= CFNumberCreate(alloc
, kCFNumberSInt64Type
, &size
);
159 CFDictionarySetValue(propertyDict
, kCFURLFileLength
, num
);
161 } else if (errorCode
) {
162 *errorCode
= kCFURLUnknownError
;
164 } else if (key
== kCFURLFileLastModificationTime
|| CFEqual(kCFURLFileLastModificationTime
, key
)) {
165 if (exists
&& modTime
) {
166 CFDictionarySetValue(propertyDict
, kCFURLFileLastModificationTime
, modTime
);
167 } else if (errorCode
) {
168 *errorCode
= kCFURLUnknownError
;
170 } else if (key
== kCFURLFileExists
|| CFEqual(kCFURLFileExists
, key
)) {
172 CFDictionarySetValue(propertyDict
, kCFURLFileExists
, kCFBooleanTrue
);
174 CFDictionarySetValue(propertyDict
, kCFURLFileExists
, kCFBooleanFalse
);
176 } else if (key
== kCFURLFileOwnerID
|| CFEqual(kCFURLFileOwnerID
, key
)) {
178 CFNumberRef num
= CFNumberCreate(alloc
, kCFNumberSInt32Type
, &ownerID
);
179 CFDictionarySetValue(propertyDict
, kCFURLFileOwnerID
, num
);
181 } else if (errorCode
) {
182 *errorCode
= kCFURLUnknownError
;
184 // Add more properties here
185 } else if (errorCode
) {
186 *errorCode
= kCFURLUnknownPropertyKeyError
;
189 if (modTime
) CFRelease(modTime
);
190 if (contents
) CFRelease(contents
);
194 static Boolean
_CFFileURLWritePropertiesToResource(CFURLRef url
, CFDictionaryRef propertyDict
, SInt32
*errorCode
) {
195 CFTypeRef buffer
[16];
198 Boolean result
= true;
200 char cPath
[CFMaxPathSize
];
202 if (!CFURLGetFileSystemRepresentation(url
, true, (unsigned char *)cPath
, CFMaxPathSize
)) {
203 if (errorCode
) *errorCode
= kCFURLImproperArgumentsError
;
207 count
= CFDictionaryGetCount(propertyDict
);
212 keys
= (CFTypeRef
*)CFAllocatorAllocate(CFGetAllocator(url
), sizeof(void *) * count
* 2, 0);
213 values
= keys
+ count
;
215 CFDictionaryGetKeysAndValues(propertyDict
, keys
, values
);
217 for (idx
= 0; idx
< count
; idx
++) {
218 CFStringRef key
= (CFStringRef
)keys
[idx
];
219 CFTypeRef value
= values
[idx
];
220 if (key
== kCFURLFilePOSIXMode
|| CFEqual(kCFURLFilePOSIXMode
, key
)) {
223 if (CFNumberGetTypeID() == CFGetTypeID(value
)) {
224 CFNumberRef modeNum
= (CFNumberRef
)value
;
225 CFNumberGetValue(modeNum
, kCFNumberSInt32Type
, &mode
);
227 #if DEPLOYMENT_TARGET_MACOSX
228 #define MODE_TYPE mode_t
230 const MODE_TYPE
*modePtr
= (const MODE_TYPE
*)CFDataGetBytePtr((CFDataRef
)value
);
233 err
= chmod(cPath
, mode
);
234 if (err
!= 0) result
= false;
240 if ((CFTypeRef
)keys
!= buffer
) CFAllocatorDeallocate(CFGetAllocator(url
), keys
);
242 if (errorCode
) *errorCode
= result
? 0 : kCFURLUnknownError
;
246 static Boolean
_CFFileURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc
, CFURLRef url
, CFDataRef
*fetchedData
, CFArrayRef desiredProperties
, CFDictionaryRef
*fetchedProperties
, SInt32
*errorCode
) {
247 Boolean success
= true;
249 if (errorCode
) *errorCode
= 0;
253 Boolean releaseAlloc
= false;
256 // We need a real allocator to pass to _CFReadBytesFromFile so that the CFDataRef we create with
257 // CFDataCreateWithBytesNoCopy() can free up the object _CFReadBytesFromFile() returns.
258 alloc
= (CFAllocatorRef
)CFRetain(__CFGetDefaultAllocator());
261 if (!_CFReadBytesFromFile(alloc
, url
, &bytes
, &length
, 0)) {
262 if (errorCode
) *errorCode
= kCFURLUnknownError
;
266 *fetchedData
= CFDataCreateWithBytesNoCopy(alloc
, (const UInt8
*)bytes
, length
, alloc
);
269 // Now the CFData should be hanging on to it.
274 if (fetchedProperties
) {
275 *fetchedProperties
= _CFFileURLCreatePropertiesFromResource(alloc
, url
, desiredProperties
, errorCode
);
276 if (!*fetchedProperties
) success
= false;
283 * Support for data: URLs - RFC 2397
284 * Currently this is spi for CFNetwork, to make it API, just put these constants in CFURLAccess.h
289 const CFStringRef kCFDataURLDataLength;
291 const CFStringRef kCFDataURLMimeType;
293 const CFStringRef kCFDataURLTextEncodingName;
296 /* Properties for the data: scheme. */
297 /* kCFDataURLDataLength is a CFNumber giving the data's length in bytes. */
298 /* kCFDataURLMimeType is a CFString. */
299 /* kCFDataURLTextEncodingName is a CFString. */
301 /* REMINDSMZ: From CFURLResponse.c */
302 static CFStringRef
mimeTypeFromContentTypeComponent(CFStringRef component
) {
303 CFIndex compLen
= CFStringGetLength(component
);
304 CFStringInlineBuffer buf
;
306 CFIndex firstChar
= -1, lastChar
= -1;
307 CFCharacterSetRef whitespaceSet
= CFCharacterSetGetPredefined(kCFCharacterSetWhitespace
);
308 CFStringInitInlineBuffer(component
, &buf
, CFRangeMake(0, compLen
));
310 for (idx
= 0; idx
< compLen
; idx
++) {
311 UniChar ch
= CFStringGetCharacterFromInlineBuffer(&buf
, idx
);
313 // Delimits the charset
315 } else if (firstChar
== -1) {
316 if (!CFCharacterSetIsCharacterMember(whitespaceSet
, ch
)) {
319 } else if (!CFCharacterSetIsCharacterMember(whitespaceSet
, ch
)) {
323 if (firstChar
!= -1 && lastChar
!= -1) {
324 CFMutableStringRef newContentType
= CFStringCreateMutableCopy(CFGetAllocator(component
), compLen
, component
);
325 if (lastChar
!= compLen
- 1) {
326 CFStringDelete(newContentType
, CFRangeMake(lastChar
+ 1, compLen
- lastChar
- 1));
329 CFStringDelete(newContentType
, CFRangeMake(0, firstChar
));
331 CFStringLowercase(newContentType
, NULL
);
332 return newContentType
;
337 /* REMINDSMZ: From CFURLResponse.c */
338 static CFStringRef
charsetFromContentTypeHeader(CFStringRef contentType
) {
339 // FIXME: Should this use KeyValuePair parsing to handle quoting properly?
341 CFIndex compLen
= CFStringGetLength(contentType
);
342 CFIndex start
, end
, idx
;
343 CFCharacterSetRef whitespaceSet
;
344 CFMutableStringRef result
;
346 CFStringRef kCFURLResponseCharsetPrefix
= CFSTR("charset=");
348 if (!CFStringFindWithOptions(contentType
, kCFURLResponseCharsetPrefix
, CFRangeMake(0, compLen
), kCFCompareCaseInsensitive
, &range
) || range
.length
== 0) return NULL
;
350 whitespaceSet
= CFCharacterSetGetPredefined(kCFCharacterSetWhitespace
);
353 for (idx
= range
.location
+ range
.length
; idx
< compLen
; idx
++) {
354 UniChar ch
= CFStringGetCharacterAtIndex(contentType
, idx
);
355 if (ch
== ';' || ch
== ',') break;
357 if (!CFCharacterSetIsCharacterMember(whitespaceSet
, ch
)) {
361 } else if (!CFCharacterSetIsCharacterMember(whitespaceSet
,ch
)) {
366 if (start
== -1) return NULL
;
368 result
= CFStringCreateMutableCopy(CFGetAllocator(contentType
), compLen
,contentType
);
369 if (end
!= compLen
) {
370 CFStringDelete(result
, CFRangeMake(end
+1, compLen
-end
-1));
372 CFStringDelete(result
, CFRangeMake(0, start
));
373 CFStringLowercase(result
, NULL
);
377 #define STATIC_BUFFER_SIZE 1024
379 static BOOL
isHexDigit(char c
)
381 return (c
>= '0' && c
<= '9') || (c
>= 'A' && c
<= 'F') || (c
>= 'a' && c
<= 'f');
384 static UInt8
hexDigitValue(char c
)
386 if (c
>= '0' && c
<= '9') {
389 if (c
>= 'A' && c
<= 'F') {
392 if (c
>= 'a' && c
<= 'f') {
395 // NSURL_ERROR("illegal hex digit");
399 static CFDataRef
percentEscapeDecodeBuffer(CFAllocatorRef alloc
, const UInt8
* srcBuffer
, CFRange range
, Boolean stripWhitespace
)
402 UInt8 staticDstBuffer
[STATIC_BUFFER_SIZE
];
404 if (range
.length
> STATIC_BUFFER_SIZE
) {
405 dstBuffer
= (UInt8
*) malloc(range
.length
);
407 dstBuffer
= staticDstBuffer
;
410 CFIndex end
= range
.location
+ range
.length
;
414 for (i
= range
.location
, j
= 0; i
< end
; ++i
) {
417 if (srcBuffer
[i
] == '%' && end
> i
+ 2 && isHexDigit(srcBuffer
[i
+1]) && isHexDigit(srcBuffer
[i
+2])) {
418 value
= hexDigitValue(srcBuffer
[i
+1]) * 16 + hexDigitValue(srcBuffer
[i
+2]);
421 value
= srcBuffer
[i
];
424 if (!stripWhitespace
|| !isspace(value
)) {
425 dstBuffer
[j
++] = value
;
429 CFDataRef result
= CFDataCreate(alloc
, dstBuffer
, j
);
431 if (dstBuffer
!= staticDstBuffer
) {
439 // base 64 digits: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
441 static BOOL
isBase64Digit(char c
)
443 return (c
>= 'A' && c
<= 'Z') || (c
>= 'a' && c
<= 'z') || (c
>= '0' && c
<= '9') || (c
== '+') || (c
== '/');
446 static BOOL
isBase64DigitOrEqualSign(char c
)
448 return isBase64Digit(c
) || c
== '=';
451 static UInt8
base64DigitValue(char c
)
453 if (c
>= 'A' && c
<= 'Z') {
455 } else if (c
>= 'a' && c
<= 'z') {
457 } else if (c
>= '0' && c
<= '9') {
459 } else if (c
== '+') {
461 } else if (c
== '/') {
468 static CFDataRef
base64DecodeData(CFAllocatorRef alloc
, CFDataRef data
)
470 const UInt8
*srcBuffer
= CFDataGetBytePtr(data
);
471 CFIndex length
= CFDataGetLength(data
);
472 UInt8
*dstBuffer
= NULL
;
473 UInt8 staticDstBuffer
[STATIC_BUFFER_SIZE
];
474 CFDataRef result
= NULL
;
476 // base64 encoded data length must be multiple of 4
477 if (length
% 4 != 0) {
481 if (length
> STATIC_BUFFER_SIZE
) {
482 dstBuffer
= (UInt8
*) malloc(length
);
484 dstBuffer
= staticDstBuffer
;
489 for (i
= 0, j
= 0; i
< length
; i
+=4) {
490 if (!(isBase64Digit(srcBuffer
[i
]) &&
491 isBase64Digit(srcBuffer
[i
+1]) &&
492 isBase64DigitOrEqualSign(srcBuffer
[i
+2]) &&
493 isBase64DigitOrEqualSign(srcBuffer
[i
+3]))) {
494 if (dstBuffer
!= staticDstBuffer
) {
500 dstBuffer
[j
++] = (base64DigitValue(srcBuffer
[i
]) << 2) + (base64DigitValue(srcBuffer
[i
+1]) >> 4);
501 if (srcBuffer
[i
+2] != '=') {
502 dstBuffer
[j
++] = ((base64DigitValue(srcBuffer
[i
+1]) & 0xf) << 4) + (base64DigitValue(srcBuffer
[i
+2]) >> 2);
504 if (srcBuffer
[i
+3] != '=') {
505 dstBuffer
[j
++] = ((base64DigitValue(srcBuffer
[i
+2]) & 0x3) << 6) + (base64DigitValue(srcBuffer
[i
+3]));
509 result
= CFDataCreate(alloc
, dstBuffer
, j
);
512 if (dstBuffer
!= staticDstBuffer
) {
519 static inline CFStringRef
percentExpandAndTrimContentType(CFAllocatorRef alloc
, CFStringRef str
, CFRange range
)
521 CFStringRef contentTypeUnexpanded
= CFStringCreateWithSubstring(alloc
, str
, range
);
522 CFStringRef contentTypeExpanded
= CFURLCreateStringByReplacingPercentEscapes(alloc
, contentTypeUnexpanded
, CFSTR(""));
523 CFRelease(contentTypeUnexpanded
);
525 CFMutableStringRef contentTypeHeader
= CFStringCreateMutableCopy(alloc
, 0, contentTypeExpanded
);
526 CFRelease(contentTypeExpanded
);
527 CFStringTrimWhitespace(contentTypeHeader
);
529 return contentTypeHeader
;
532 static Boolean
parseDataRequestURL(CFURLRef url
, CFDataRef
* outData
, CFStringRef
* outMimeType
, CFStringRef
* outTextEncodingName
)
534 Boolean result
= FALSE
;
535 CFAllocatorRef alloc
= CFGetAllocator(url
);
536 CFStringRef str
= CFURLCopyResourceSpecifier(url
);
538 CFRange commaRange
= CFStringFind(str
, CFSTR(","), 0);
540 if (commaRange
.location
!= kCFNotFound
) {
541 CFStringRef contentTypeHeader
= percentExpandAndTrimContentType(alloc
, str
, CFRangeMake(0, commaRange
.location
));
542 CFStringRef mimeType
= mimeTypeFromContentTypeComponent(contentTypeHeader
);
543 CFStringRef textEncodingName
= charsetFromContentTypeHeader(contentTypeHeader
);
545 Boolean base64
= CFStringFind(contentTypeHeader
, CFSTR(";base64"), kCFCompareCaseInsensitive
).location
!= kCFNotFound
;
547 if (mimeType
== NULL
) {
548 mimeType
= (CFStringRef
) CFRetain(CFSTR("text/plain"));
551 if (textEncodingName
== NULL
) {
552 textEncodingName
= (CFStringRef
) CFRetain(CFSTR("us-ascii"));
555 CFIndex bufferSize
= CFURLGetBytes(url
, NULL
, 0);
556 UInt8
* srcBuffer
= (UInt8
*) malloc(bufferSize
);
557 CFURLGetBytes(url
, srcBuffer
, bufferSize
);
559 CFRange dataRange
= CFURLGetByteRangeForComponent(url
, kCFURLComponentResourceSpecifier
, NULL
);
560 while (srcBuffer
[dataRange
.location
] != ',') {
561 dataRange
.location
++;
564 dataRange
.location
++;
567 CFDataRef dataRef
= NULL
;
570 dataRef
= percentEscapeDecodeBuffer(alloc
, srcBuffer
, dataRange
, false);
572 CFDataRef unescapedAndStripped
= percentEscapeDecodeBuffer(alloc
, srcBuffer
, dataRange
, true);
573 if (unescapedAndStripped
) {
574 dataRef
= base64DecodeData(alloc
, unescapedAndStripped
);
575 CFRelease(unescapedAndStripped
);
579 if (dataRef
!= NULL
) {
581 *outMimeType
= (CFStringRef
) mimeType
== NULL
? NULL
: CFStringCreateCopy(alloc
, mimeType
);
582 *outTextEncodingName
= (CFStringRef
) textEncodingName
== NULL
? NULL
: CFStringCreateCopy(alloc
, textEncodingName
);
588 if (contentTypeHeader
) CFRelease(contentTypeHeader
);
589 if (mimeType
) CFRelease(mimeType
);
590 if (textEncodingName
) CFRelease(textEncodingName
);
599 static Boolean
_CFDataURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc
, CFURLRef url
, CFDataRef
*fetchedData
, CFArrayRef desiredProperties
, CFDictionaryRef
*fetchedProperties
, SInt32
*errorCode
) {
600 Boolean success
= true;
602 if (errorCode
) *errorCode
= 0;
604 // We always need to fetch the data...
605 CFDataRef data
= NULL
;
606 CFStringRef mimeType
= NULL
;
607 CFStringRef textEncodingName
= NULL
;
609 if (! parseDataRequestURL(url
, &data
, &mimeType
, &textEncodingName
)) {
611 *errorCode
= kCFURLUnknownError
;
616 *fetchedData
= CFDataCreateCopy(alloc
, data
);
619 if (fetchedProperties
) {
620 const void* propKeys
[] = {
621 kCFDataURLDataLength
,
623 kCFDataURLTextEncodingName
,
625 const CFIndex propKeysCount
= sizeof(propKeys
) / sizeof(propKeys
[0]);
627 if (desiredProperties
== NULL
) {
628 static CFArrayRef sAllProps
= NULL
;
629 if (sAllProps
== NULL
) {
630 sAllProps
= CFArrayCreate(kCFAllocatorSystemDefault
, propKeys
, propKeysCount
, &kCFTypeArrayCallBacks
);
632 desiredProperties
= sAllProps
;
635 const void* vals
[propKeysCount
];
636 const void* keys
[propKeysCount
];
639 CFIndex count
= CFArrayGetCount(desiredProperties
);
640 for (CFIndex i
= 0; i
< count
; i
++) {
641 CFStringRef key
= (CFStringRef
) CFArrayGetValueAtIndex(desiredProperties
, i
);
643 if (CFEqual(key
, kCFDataURLDataLength
)) {
644 CFIndex len
= CFDataGetLength(data
);
646 vals
[ixVal
++] = CFNumberCreate(alloc
, kCFNumberCFIndexType
, &len
);
647 } else if (CFEqual(key
, kCFDataURLMimeType
)) {
648 if (mimeType
!= NULL
) {
650 vals
[ixVal
++] = CFStringCreateCopy(alloc
, mimeType
);
652 } else if (CFEqual(key
, kCFDataURLTextEncodingName
)) {
653 if (textEncodingName
!= NULL
) {
655 vals
[ixVal
++] = CFStringCreateCopy(alloc
, textEncodingName
);
660 *fetchedProperties
= CFDictionaryCreate(alloc
, keys
, vals
, ixVal
, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
661 for (CFIndex i
= 0; i
< ixVal
; i
++)
663 if (*fetchedProperties
== NULL
)
667 if (data
) CFRelease(data
);
668 if (mimeType
) CFRelease(mimeType
);
669 if (textEncodingName
) CFRelease(textEncodingName
);
676 /*************************/
677 /* Public routines */
678 /*************************/
680 Boolean
CFURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc
, CFURLRef url
, CFDataRef
*fetchedData
, CFDictionaryRef
*fetchedProperties
, CFArrayRef desiredProperties
, SInt32
*errorCode
) {
681 CFStringRef scheme
= CFURLCopyScheme(url
);
684 if (errorCode
) *errorCode
= kCFURLImproperArgumentsError
;
685 if (fetchedData
) *fetchedData
= NULL
;
686 if (fetchedProperties
) *fetchedProperties
= NULL
;
690 if (CFStringCompare(scheme
, CFSTR("file"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
) {
691 result
= _CFFileURLCreateDataAndPropertiesFromResource(alloc
, url
, fetchedData
, desiredProperties
, fetchedProperties
, errorCode
);
692 } else if (CFStringCompare(scheme
, CFSTR("data"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
) {
693 result
= _CFDataURLCreateDataAndPropertiesFromResource(alloc
, url
, fetchedData
, desiredProperties
, fetchedProperties
, errorCode
);
695 #if DEPLOYMENT_TARGET_MACOSX
696 result
= __CFNetwork__CFURLCreateDataAndPropertiesFromResource(alloc
, url
, fetchedData
, fetchedProperties
, desiredProperties
, errorCode
);
698 if (fetchedData
) *fetchedData
= NULL
;
699 if (fetchedProperties
) *fetchedProperties
= NULL
;
700 if (errorCode
) *errorCode
= kCFURLUnknownSchemeError
;
709 CFTypeRef
CFURLCreatePropertyFromResource(CFAllocatorRef alloc
, CFURLRef url
, CFStringRef property
, SInt32
*errorCode
) {
710 CFArrayRef array
= CFArrayCreate(alloc
, (const void **)&property
, 1, &kCFTypeArrayCallBacks
);
711 CFDictionaryRef dict
;
713 if (CFURLCreateDataAndPropertiesFromResource(alloc
, url
, NULL
, &dict
, array
, errorCode
)) {
714 CFTypeRef result
= CFDictionaryGetValue(dict
, property
);
715 if (result
) CFRetain(result
);
720 if (dict
) CFRelease(dict
);
726 Boolean
CFURLWriteDataAndPropertiesToResource(CFURLRef url
, CFDataRef data
, CFDictionaryRef propertyDict
, SInt32
*errorCode
) {
727 CFStringRef scheme
= CFURLCopyScheme(url
);
729 if (errorCode
) *errorCode
= kCFURLImproperArgumentsError
;
731 } else if (CFStringCompare(scheme
, CFSTR("file"), 0) == kCFCompareEqualTo
) {
732 Boolean success
= true;
734 if (errorCode
) *errorCode
= 0;
736 if (CFURLHasDirectoryPath(url
)) {
737 // Create a directory
738 char cPath
[CFMaxPathSize
];
739 if (!CFURLGetFileSystemRepresentation(url
, true, (unsigned char *)cPath
, CFMaxPathSize
)) {
740 if (errorCode
) *errorCode
= kCFURLImproperArgumentsError
;
743 success
= _CFCreateDirectory(cPath
);
744 if (!success
&& errorCode
) *errorCode
= kCFURLUnknownError
;
748 SInt32 length
= CFDataGetLength(data
);
749 const void *bytes
= (0 == length
) ? (const void *)"" : CFDataGetBytePtr(data
);
750 success
= _CFWriteBytesToFile(url
, bytes
, length
);
751 if (!success
&& errorCode
) *errorCode
= kCFURLUnknownError
;
755 if (!_CFFileURLWritePropertiesToResource(url
, propertyDict
, errorCode
))
761 #if DEPLOYMENT_TARGET_MACOSX
762 Boolean result
= __CFNetwork__CFURLWriteDataAndPropertiesToResource(url
, data
, propertyDict
, errorCode
);
764 if (errorCode
) *errorCode
= kCFURLUnknownSchemeError
;
771 Boolean
CFURLDestroyResource(CFURLRef url
, SInt32
*errorCode
) {
772 CFStringRef scheme
= CFURLCopyScheme(url
);
773 char cPath
[CFMaxPathSize
];
776 if (errorCode
) *errorCode
= kCFURLImproperArgumentsError
;
778 } else if (CFStringCompare(scheme
, CFSTR("file"), 0) == kCFCompareEqualTo
) {
780 if (!CFURLGetFileSystemRepresentation(url
, true, (unsigned char *)cPath
, CFMaxPathSize
)) {
781 if (errorCode
) *errorCode
= kCFURLImproperArgumentsError
;
785 if (CFURLHasDirectoryPath(url
)) {
786 if (_CFRemoveDirectory(cPath
)) {
787 if (errorCode
) *errorCode
= 0;
790 if (errorCode
) *errorCode
= kCFURLUnknownError
;
794 if (_CFDeleteFile(cPath
)) {
795 if (errorCode
) *errorCode
= 0;
798 if (errorCode
) *errorCode
= kCFURLUnknownError
;
804 #if DEPLOYMENT_TARGET_MACOSX
805 Boolean result
= __CFNetwork__CFURLDestroyResource(url
, errorCode
);
807 if (errorCode
) *errorCode
= kCFURLUnknownSchemeError
;