2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 Copyright 1999-2002, Apple, Inc. All rights reserved.
27 Responsibility: Becky Willrich
31 CFData read/write routines
34 #include "CFInternal.h"
35 #include <CoreFoundation/CFBase.h>
36 #include <CoreFoundation/CFURL.h>
37 #include <CoreFoundation/CFDictionary.h>
38 #include <CoreFoundation/CFURLAccess.h>
39 #include <CoreFoundation/CFDate.h>
40 #include <CoreFoundation/CFNumber.h>
43 #if defined(__WIN32__)
47 #include <sys/types.h>
50 #define timeval xxx_timeval
51 #define BOOLEAN xxx_BOOLEAN
59 #include <sys/types.h>
66 #include <mach-o/dyld.h>
68 extern char *getenv(const char *name
);
70 static void *__CFLoadCFNetwork(void) {
71 static const void *image
= NULL
;
73 // OS 10.3 change to NSAddImage options here:
74 // a) Use NSADDIMAGE_OPTION_WITH_SEARCHING to support setting common DYLD_ environment variables
75 // including DYLD_IMAGE_SUFFIX and DYLD_LIBRARY_PATH.
76 // b) Use NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME to fix a nasty problem where two copies of
77 // a given framework are loaded into the same address space (See bug # 3060641).
78 image
= ((void*)NSAddImage("/System/Library/Frameworks/CoreServices.framework/Frameworks/CFNetwork.framework/CFNetwork", NSADDIMAGE_OPTION_WITH_SEARCHING
| NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME
));
83 static Boolean
__CFURLCreateDataAndPropertiesFromResource(CFAllocatorRef A
, CFURLRef B
, CFDataRef
*C
, CFDictionaryRef
*D
, CFArrayRef E
, SInt32
*F
) {
84 static Boolean (*dyfunc
)(CFAllocatorRef
, CFURLRef
, CFDataRef
*, CFDictionaryRef
*, CFArrayRef
, SInt32
*) = NULL
;
86 void *image
= __CFLoadCFNetwork();
87 dyfunc
= NSAddressOfSymbol(NSLookupSymbolInImage(image
, "__CFURLCreateDataAndPropertiesFromResource", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
));
90 return dyfunc(A
, B
, C
, D
, E
, F
);
94 if (F
) *F
= kCFURLUnknownSchemeError
;
99 static Boolean
__CFURLWriteDataAndPropertiesToResource(CFURLRef A
, CFDataRef B
, CFDictionaryRef C
, SInt32
*D
) {
100 static Boolean (*dyfunc
)(CFURLRef
, CFDataRef
, CFDictionaryRef
, SInt32
*) = NULL
;
101 if (NULL
== dyfunc
) {
102 void *image
= __CFLoadCFNetwork();
103 dyfunc
= NSAddressOfSymbol(NSLookupSymbolInImage(image
, "__CFURLWriteDataAndPropertiesToResource", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
));
106 return dyfunc(A
, B
, C
, D
);
108 if (D
) *D
= kCFURLUnknownSchemeError
;
113 static Boolean
__CFURLDestroyResource(CFURLRef A
, SInt32
*B
) {
114 static Boolean (*dyfunc
)(CFURLRef
, SInt32
*) = NULL
;
115 if (NULL
== dyfunc
) {
116 void *image
= __CFLoadCFNetwork();
117 dyfunc
= NSAddressOfSymbol(NSLookupSymbolInImage(image
, "__CFURLDestroyResource", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
));
122 if (B
) *B
= kCFURLUnknownSchemeError
;
130 CONST_STRING_DECL(kCFURLFileExists
, "kCFURLFileExists")
131 CONST_STRING_DECL(kCFURLFilePOSIXMode
, "kCFURLFilePOSIXMode")
132 CONST_STRING_DECL(kCFURLFileDirectoryContents
, "kCFURLFileDirectoryContents")
133 CONST_STRING_DECL(kCFURLFileLength
, "kCFURLFileLength")
134 CONST_STRING_DECL(kCFURLFileLastModificationTime
, "kCFURLFileLastModificationTime")
135 CONST_STRING_DECL(kCFURLFileOwnerID
, "kCFURLFileOwnerID")
136 CONST_STRING_DECL(kCFURLHTTPStatusCode
, "kCFURLHTTPStatusCode")
137 CONST_STRING_DECL(kCFURLHTTPStatusLine
, "kCFURLHTTPStatusLine")
139 // Compatibility property strings -- we obsoleted these names pre-DP4. REW, 5/22/2000
140 CONST_STRING_DECL(kCFFileURLExists
, "kCFURLFileExists")
141 CONST_STRING_DECL(kCFFileURLPOSIXMode
, "kCFURLFilePOSIXMode")
142 CONST_STRING_DECL(kCFFileURLDirectoryContents
, "kCFURLFileDirectoryContents")
143 CONST_STRING_DECL(kCFFileURLSize
, "kCFURLFileLength")
144 CONST_STRING_DECL(kCFFileURLLastModificationTime
, "kCFURLFileLastModificationTime")
145 CONST_STRING_DECL(kCFHTTPURLStatusCode
, "kCFURLHTTPStatusCode")
146 CONST_STRING_DECL(kCFHTTPURLStatusLine
, "kCFURLHTTPStatusLine")
148 // 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
150 /*************************/
151 /* file: access routines */
152 /*************************/
154 //#warning CF:For the moment file access failures are ill defined and set the error code to kCFURLUnknownError
156 static CFDictionaryRef
_CFFileURLCreatePropertiesFromResource(CFAllocatorRef alloc
, CFURLRef url
, CFArrayRef desiredProperties
, SInt32
*errorCode
) {
157 // MF:!!! This could/should be changed to use _CFGetFileProperties() to do the actual figuring.
158 static CFArrayRef _allProps
= NULL
;
161 CFMutableDictionaryRef propertyDict
= NULL
;
166 CFDateRef modTime
= NULL
, *modTimePtr
= NULL
;
167 CFArrayRef contents
= NULL
, *contentsPtr
= NULL
;
170 if (errorCode
) *errorCode
= 0;
171 if (!desiredProperties
) {
172 // 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
174 const void *values
[9];
175 values
[0] = kCFURLFileExists
;
176 values
[1] = kCFURLFilePOSIXMode
;
177 values
[2] = kCFURLFileDirectoryContents
;
178 values
[3] = kCFURLFileLength
;
179 values
[4] = kCFURLFileLastModificationTime
;
180 values
[5] = kCFURLFileOwnerID
;
181 _allProps
= CFArrayCreate(NULL
, values
, 6, &kCFTypeArrayCallBacks
);
183 desiredProperties
= _allProps
;
186 arrayRange
.location
= 0;
187 arrayRange
.length
= CFArrayGetCount(desiredProperties
);
188 propertyDict
= CFDictionaryCreateMutable(alloc
, 0, & kCFTypeDictionaryKeyCallBacks
, & kCFTypeDictionaryValueCallBacks
);
189 if (arrayRange
.length
== 0) return propertyDict
;
191 if (CFArrayContainsValue(desiredProperties
, arrayRange
, kCFURLFileDirectoryContents
)) {
192 contentsPtr
= &contents
;
194 if (CFArrayContainsValue(desiredProperties
, arrayRange
, kCFURLFileLastModificationTime
)) {
195 modTimePtr
= &modTime
;
198 if (_CFGetFileProperties(alloc
, url
, &exists
, &posixMode
, &size
, modTimePtr
, &ownerID
, contentsPtr
) != 0) {
200 *errorCode
= kCFURLUnknownError
;
205 for (idx
= 0; idx
< arrayRange
.length
; idx
++) {
206 CFStringRef key
= (CFMutableStringRef
)CFArrayGetValueAtIndex(desiredProperties
, idx
);
207 if (key
== kCFURLFilePOSIXMode
|| CFEqual(kCFURLFilePOSIXMode
, key
)) {
209 CFNumberRef num
= CFNumberCreate(alloc
, kCFNumberSInt32Type
, &posixMode
);
210 CFDictionarySetValue(propertyDict
, kCFURLFilePOSIXMode
, num
);
212 } else if (errorCode
) {
213 *errorCode
= kCFURLUnknownError
;
215 } else if (key
== kCFURLFileDirectoryContents
|| CFEqual(kCFURLFileDirectoryContents
, key
)) {
216 if (exists
&& (posixMode
& S_IFMT
) == S_IFDIR
&& contents
) {
217 CFDictionarySetValue(propertyDict
, kCFURLFileDirectoryContents
, contents
);
218 } else if (errorCode
) {
219 *errorCode
= kCFURLUnknownError
;
221 } else if (key
== kCFURLFileLength
|| CFEqual(kCFURLFileLength
, key
)) {
223 CFNumberRef num
= CFNumberCreate(alloc
, kCFNumberSInt64Type
, &size
);
224 CFDictionarySetValue(propertyDict
, kCFURLFileLength
, num
);
226 } else if (errorCode
) {
227 *errorCode
= kCFURLUnknownError
;
229 } else if (key
== kCFURLFileLastModificationTime
|| CFEqual(kCFURLFileLastModificationTime
, key
)) {
230 if (exists
&& modTime
) {
231 CFDictionarySetValue(propertyDict
, kCFURLFileLastModificationTime
, modTime
);
232 } else if (errorCode
) {
233 *errorCode
= kCFURLUnknownError
;
235 } else if (key
== kCFURLFileExists
|| CFEqual(kCFURLFileExists
, key
)) {
237 CFDictionarySetValue(propertyDict
, kCFURLFileExists
, kCFBooleanTrue
);
239 CFDictionarySetValue(propertyDict
, kCFURLFileExists
, kCFBooleanFalse
);
241 } else if (key
== kCFURLFileOwnerID
|| CFEqual(kCFURLFileOwnerID
, key
)) {
243 CFNumberRef num
= CFNumberCreate(alloc
, kCFNumberSInt32Type
, &ownerID
);
244 CFDictionarySetValue(propertyDict
, kCFURLFileOwnerID
, num
);
246 } else if (errorCode
) {
247 *errorCode
= kCFURLUnknownError
;
249 // Add more properties here
250 } else if (errorCode
) {
251 *errorCode
= kCFURLUnknownPropertyKeyError
;
254 if (modTime
) CFRelease(modTime
);
255 if (contents
) CFRelease(contents
);
259 static Boolean
_CFFileURLWritePropertiesToResource(CFURLRef url
, CFDictionaryRef propertyDict
, SInt32
*errorCode
) {
260 #if defined(__MACOS8__)
261 return false; // No properties are writable on OS 8
263 CFTypeRef buffer
[16];
266 Boolean result
= true;
268 char cPath
[CFMaxPathSize
];
270 if (!CFURLGetFileSystemRepresentation(url
, true, cPath
, CFMaxPathSize
)) {
271 if (errorCode
) *errorCode
= kCFURLImproperArgumentsError
;
275 count
= CFDictionaryGetCount(propertyDict
);
277 (CFTypeRef
)keys
= buffer
;
278 (CFTypeRef
)values
= buffer
+8;
280 keys
= CFAllocatorAllocate(CFGetAllocator(url
), sizeof(void *) * count
* 2, 0);
281 values
= keys
+ count
;
283 CFDictionaryGetKeysAndValues(propertyDict
, keys
, values
);
285 for (idx
= 0; idx
< count
; idx
++) {
286 CFStringRef key
= keys
[idx
];
287 CFTypeRef value
= values
[idx
];
288 if (key
== kCFURLFilePOSIXMode
|| CFEqual(kCFURLFilePOSIXMode
, key
)) {
291 if (CFNumberGetTypeID() == CFGetTypeID(value
)) {
292 CFNumberRef modeNum
= (CFNumberRef
)value
;
293 CFNumberGetValue(modeNum
, kCFNumberSInt32Type
, &mode
);
295 #if defined(__WIN32__)
296 const unsigned short *modePtr
= (const unsigned short *)CFDataGetBytePtr((CFDataRef
)value
);
298 const mode_t
*modePtr
= (const mode_t
*)CFDataGetBytePtr((CFDataRef
)value
);
302 err
= chmod(cPath
, mode
);
303 if (err
!= 0) result
= false;
309 if ((CFTypeRef
)keys
!= buffer
) CFAllocatorDeallocate(CFGetAllocator(url
), keys
);
311 if (errorCode
) *errorCode
= result
? 0 : kCFURLUnknownError
;
316 static Boolean
_CFFileURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc
, CFURLRef url
, CFDataRef
*fetchedData
, CFArrayRef desiredProperties
, CFDictionaryRef
*fetchedProperties
, SInt32
*errorCode
) {
317 Boolean success
= true;
319 if (errorCode
) *errorCode
= 0;
323 Boolean releaseAlloc
= false;
326 // We need a real allocator to pass to _CFReadBytesFromFile
327 alloc
= CFRetain(__CFGetDefaultAllocator());
330 if (!_CFReadBytesFromFile(alloc
, url
, &bytes
, &length
, 0)) {
331 if (errorCode
) *errorCode
= kCFURLUnknownError
;
335 *fetchedData
= CFDataCreateWithBytesNoCopy(alloc
, bytes
, length
, alloc
);
338 // Now the CFData should be hanging on to it.
343 if (fetchedProperties
) {
344 *fetchedProperties
= _CFFileURLCreatePropertiesFromResource(alloc
, url
, desiredProperties
, errorCode
);
345 if (!*fetchedProperties
) success
= false;
350 /*************************/
351 /* Public routines */
352 /*************************/
354 Boolean
CFURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc
, CFURLRef url
, CFDataRef
*fetchedData
, CFDictionaryRef
*fetchedProperties
, CFArrayRef desiredProperties
, SInt32
*errorCode
) {
355 CFStringRef scheme
= CFURLCopyScheme(url
);
358 if (errorCode
) *errorCode
= kCFURLImproperArgumentsError
;
359 if (fetchedData
) *fetchedData
= NULL
;
360 if (fetchedProperties
) *fetchedProperties
= NULL
;
364 if (CFStringCompare(scheme
, CFSTR("file"), 0) == kCFCompareEqualTo
) {
365 result
= _CFFileURLCreateDataAndPropertiesFromResource(alloc
, url
, fetchedData
, desiredProperties
, fetchedProperties
, errorCode
);
367 #if defined(__MACH__)
368 result
= __CFURLCreateDataAndPropertiesFromResource(alloc
, url
, fetchedData
, fetchedProperties
, desiredProperties
, errorCode
);
370 if (fetchedData
) *fetchedData
= NULL
;
371 if (fetchedProperties
) *fetchedProperties
= NULL
;
372 if (errorCode
) *errorCode
= kCFURLUnknownSchemeError
;
381 CFTypeRef
CFURLCreatePropertyFromResource(CFAllocatorRef alloc
, CFURLRef url
, CFStringRef property
, SInt32
*errorCode
) {
382 CFArrayRef array
= CFArrayCreate(alloc
, (const void **)&property
, 1, &kCFTypeArrayCallBacks
);
383 CFDictionaryRef dict
;
385 if (CFURLCreateDataAndPropertiesFromResource(alloc
, url
, NULL
, &dict
, array
, errorCode
)) {
386 CFTypeRef result
= CFDictionaryGetValue(dict
, property
);
387 if (result
) CFRetain(result
);
392 if (dict
) CFRelease(dict
);
398 Boolean
CFURLWriteDataAndPropertiesToResource(CFURLRef url
, CFDataRef data
, CFDictionaryRef propertyDict
, SInt32
*errorCode
) {
399 CFStringRef scheme
= CFURLCopyScheme(url
);
401 if (errorCode
) *errorCode
= kCFURLImproperArgumentsError
;
403 } else if (CFStringCompare(scheme
, CFSTR("file"), 0) == kCFCompareEqualTo
) {
404 Boolean success
= true;
406 if (errorCode
) *errorCode
= 0;
408 if (CFURLHasDirectoryPath(url
)) {
409 // Create a directory
410 char cPath
[CFMaxPathSize
];
411 if (!CFURLGetFileSystemRepresentation(url
, true, cPath
, CFMaxPathSize
)) {
412 if (errorCode
) *errorCode
= kCFURLImproperArgumentsError
;
415 success
= _CFCreateDirectory(cPath
);
416 if (!success
&& errorCode
) *errorCode
= kCFURLUnknownError
;
420 SInt32 length
= CFDataGetLength(data
);
421 const void *bytes
= (0 == length
) ? (const void *)"" : CFDataGetBytePtr(data
);
422 success
= _CFWriteBytesToFile(url
, bytes
, length
);
423 if (!success
&& errorCode
) *errorCode
= kCFURLUnknownError
;
427 if (!_CFFileURLWritePropertiesToResource(url
, propertyDict
, errorCode
))
433 #if defined(__MACH__)
434 return __CFURLWriteDataAndPropertiesToResource(url
, data
, propertyDict
, errorCode
);
436 if (errorCode
) *errorCode
= kCFURLUnknownSchemeError
;
442 Boolean
CFURLDestroyResource(CFURLRef url
, SInt32
*errorCode
) {
443 CFStringRef scheme
= CFURLCopyScheme(url
);
444 char cPath
[CFMaxPathSize
];
447 if (errorCode
) *errorCode
= kCFURLImproperArgumentsError
;
449 } else if (CFStringCompare(scheme
, CFSTR("file"), 0) == kCFCompareEqualTo
) {
451 if (!CFURLGetFileSystemRepresentation(url
, true, cPath
, CFMaxPathSize
)) {
452 if (errorCode
) *errorCode
= kCFURLImproperArgumentsError
;
456 if (CFURLHasDirectoryPath(url
)) {
457 if (_CFRemoveDirectory(cPath
)) {
458 if (errorCode
) *errorCode
= 0;
461 if (errorCode
) *errorCode
= kCFURLUnknownError
;
465 if (_CFDeleteFile(cPath
)) {
466 if (errorCode
) *errorCode
= 0;
469 if (errorCode
) *errorCode
= kCFURLUnknownError
;
475 #if defined(__MACH__)
476 return __CFURLDestroyResource(url
, errorCode
);
478 if (errorCode
) *errorCode
= kCFURLUnknownSchemeError
;