File: programming/cocoa/UKXattrMetadataStore.zip/UKXattrMetadataStore/UKXattrMetadataStore.m


//
//  UKXattrMetadataStore.m
//  BubbleBrowser
//	LICENSE: MIT License
//
//  Created by Uli Kusterer on 12.03.06.
//  Copyright 2006 Uli Kusterer. All rights reserved.
//
 
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
// -----------------------------------------------------------------------------
//	Headers:
// -----------------------------------------------------------------------------
 
#import "UKXattrMetadataStore.h"
#import <sys/xattr.h>
 
 
@implementation UKXattrMetadataStore
 
// -----------------------------------------------------------------------------
//	allKeysAtPath:traverseLink:
//		Return an NSArray of NSStrings containing all xattr names currently set
//		for the file at the specified path.
//		If travLnk == YES, it follows symlinks.
// -----------------------------------------------------------------------------
 
+(NSArray*)		allKeysAtPath: (NSString*)path traverseLink:(BOOL)travLnk
{
	NSMutableArray*	allKeys = [NSMutableArray array];
	size_t dataSize = listxattr( [path fileSystemRepresentation],
								NULL, ULONG_MAX,
								(travLnk ? 0 : XATTR_NOFOLLOW) );
	if( dataSize == ULONG_MAX )
		return allKeys;	// Empty list.
	NSMutableData*	listBuffer = [NSMutableData dataWithLength: dataSize];
	dataSize = listxattr( [path fileSystemRepresentation],
							[listBuffer mutableBytes], [listBuffer length],
							(travLnk ? 0 : XATTR_NOFOLLOW) );
	char*	nameStart = [listBuffer mutableBytes];
	int x;
	for( x = 0; x < dataSize; x++ )
	{
		if( ((char*)[listBuffer mutableBytes])[x] == 0 )	// End of string.
		{
			NSString*	str = [NSString stringWithUTF8String: nameStart];
			nameStart = [listBuffer mutableBytes] +x +1;
			[allKeys addObject: str];
		}
	}
	
	return allKeys;
}
 
 
// -----------------------------------------------------------------------------
//	setData:forKey:atPath:traverseLink:
//		Set the xattr with name key to a block of raw binary data.
//		path is the file whose xattr you want to set.
//		If travLnk == YES, it follows symlinks.
// -----------------------------------------------------------------------------
 
+(void)				setData: (NSData*)data forKey: (NSString*)key atPath: (NSString*)path traverseLink:(BOOL)travLnk
{
	setxattr( [path fileSystemRepresentation], [key UTF8String],
				[data bytes], [data length],
				0, (travLnk ? 0 : XATTR_NOFOLLOW) );
}
 
 
// -----------------------------------------------------------------------------
//	setObject:forKey:atPath:traverseLink:
//		Set the xattr with name key to an XML property list representation of
//		the specified object (or object graph).
//		path is the file whose xattr you want to set.
//		If travLnk == YES, it follows symlinks.
// -----------------------------------------------------------------------------
 
+(void)	setObject: (id)obj forKey: (NSString*)key atPath: (NSString*)path traverseLink:(BOOL)travLnk
{
	// Serialize our objects into a property list XML string:
	NSString*	errMsg = nil;
	NSData*		plistData = [NSPropertyListSerialization dataFromPropertyList: obj
								format: NSPropertyListXMLFormat_v1_0
								errorDescription: &errMsg];
	if( errMsg )
	{
		[errMsg autorelease];
		[NSException raise: @"UKXattrMetastoreCantSerialize" format: @"%@", errMsg];
	}
	else
		[[self class] setData: plistData forKey: key atPath: path traverseLink: travLnk];
}
 
 
// -----------------------------------------------------------------------------
//	setString:forKey:atPath:traverseLink:
//		Set the xattr with name key to an XML property list representation of
//		the specified object (or object graph).
//		path is the file whose xattr you want to set.
//		If travLnk == YES, it follows symlinks.
// -----------------------------------------------------------------------------
 
+(void)	setString: (NSString*)str forKey: (NSString*)key atPath: (NSString*)path traverseLink:(BOOL)travLnk
{
	NSData*		data = [str dataUsingEncoding: NSUTF8StringEncoding];
	
	if( !data )
		[NSException raise: NSCharacterConversionException format: @"Couldn't convert string to UTF8 for xattr storage."];
	
	[[self class] setData: data forKey: key atPath: path traverseLink: travLnk];
}
 
 
// -----------------------------------------------------------------------------
//	dataForKey:atPath:traverseLink:
//		Retrieve the xattr with name key as a raw block of data.
//		path is the file whose xattr you want to set.
//		If travLnk == YES, it follows symlinks.
// -----------------------------------------------------------------------------
 
+(NSMutableData*)	dataForKey: (NSString*)key atPath: (NSString*)path traverseLink:(BOOL)travLnk
{
	size_t		dataSize = getxattr( [path fileSystemRepresentation], [key UTF8String],
										NULL, ULONG_MAX, 0, (travLnk ? 0 : XATTR_NOFOLLOW) );
	if( dataSize == ULONG_MAX )
		return nil;
	NSMutableData*	data = [NSMutableData dataWithLength: dataSize];
	getxattr( [path fileSystemRepresentation], [key UTF8String],
				[data mutableBytes], [data length], 0, (travLnk ? 0 : XATTR_NOFOLLOW) );
	
	return data;
}
 
 
// -----------------------------------------------------------------------------
//	objectForKey:atPath:traverseLink:
//		Retrieve the xattr with name key, which is an XML property list
//		and unserialize it back into an object or object graph.
//		path is the file whose xattr you want to set.
//		If travLnk == YES, it follows symlinks.
// -----------------------------------------------------------------------------
 
+(id)	objectForKey: (NSString*)key atPath: (NSString*)path traverseLink:(BOOL)travLnk
{
	NSString*				errMsg = nil;
	NSMutableData*			data = [[self class] dataForKey: key atPath: path traverseLink: travLnk];
	NSPropertyListFormat	outFormat = NSPropertyListXMLFormat_v1_0;
	id obj = [NSPropertyListSerialization propertyListFromData: data
					mutabilityOption: NSPropertyListImmutable
					format: &outFormat
					errorDescription: &errMsg];
	if( errMsg )
	{
		[errMsg autorelease];
		[NSException raise: @"UKXattrMetastoreCantUnserialize" format: @"%@", errMsg];
	}
	
	return obj;
}
 
 
// -----------------------------------------------------------------------------
//	stringForKey:atPath:traverseLink:
//		Retrieve the xattr with name key, which is an XML property list
//		and unserialize it back into an object or object graph.
//		path is the file whose xattr you want to set.
//		If travLnk == YES, it follows symlinks.
// -----------------------------------------------------------------------------
 
+(id)	stringForKey: (NSString*)key atPath: (NSString*)path traverseLink:(BOOL)travLnk
{
	NSMutableData*			data = [[self class] dataForKey: key atPath: path traverseLink: travLnk];
	
	return [[[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding] autorelease];
}
 
 
@end
 
#endif /*MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4*/

This code uses the PclZip Zip File reading code, which is subject to the GNU LGPL. It also uses the GeSHi syntax highlighter, subject to the GPL. Ask if you want this for your own web site, it's free.