Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
MetadataAttributeMO.m
// |
// File: MetadataAttributeMO.m |
// |
// Abstract: The NSManagedObject subclass for the CDMetadataBrowser's metadata objects. |
// Allows for getting string representations of the various types of metadata, |
// creating and editing these objects as well as updating the inspector view. |
// |
// Version: 1.0 |
// Originally introducted at WWDC 2008 at Session: |
// Extending and Integrating Post-Production Applications with Final Cut Pro |
// |
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") |
// in consideration of your agreement to the following terms, and your use, |
// installation, modification or redistribution of this Apple software |
// constitutes acceptance of these terms. If you do not agree with these |
// terms, please do not use, install, modify or redistribute this Apple |
// software. |
// |
// In consideration of your agreement to abide by the following terms, and |
// subject to these terms, Apple grants you a personal, non - exclusive |
// license, under Apple's copyrights in this original Apple software ( the |
// "Apple Software" ), to use, reproduce, modify and redistribute the Apple |
// Software, with or without modifications, in source and / or binary forms; |
// provided that if you redistribute the Apple Software in its entirety and |
// without modifications, you must retain this notice and the following text |
// and disclaimers in all such redistributions of the Apple Software. Neither |
// the name, trademarks, service marks or logos of Apple Inc. may be used to |
// endorse or promote products derived from the Apple Software without specific |
// prior written permission from Apple. Except as expressly stated in this |
// notice, no other rights or licenses, express or implied, are granted by |
// Apple herein, including but not limited to any patent rights that may be |
// infringed by your derivative works or by other works in which the Apple |
// Software may be incorporated. |
// |
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
// WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
// WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A |
// PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION |
// ALONE OR IN COMBINATION WITH YOUR PRODUCTS. |
// |
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
// CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
// INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION |
// AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER |
// UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR |
// OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
// |
// Copyright ( C ) 2008 Apple Inc. All Rights Reserved. |
// |
#import "MetadataAttributeMO.h" |
#import "Quicktime/Movies.h" |
unsigned charTo4Bits(char c); |
@implementation MetadataAttributeMO |
#pragma mark utility functions for HEX view of data |
+ (NSString *)hexStringFromData:(NSData*) dataValue forEdit:(BOOL)forEdit{ |
UInt32 byteLength = [dataValue length], byteCounter = 0; |
UInt32 stringLength = (byteLength*2) + 1, stringCounter = 0; |
UInt32 numSpacesToAdd = (forEdit?0:(stringLength/4)); |
unsigned char dstBuffer[stringLength+numSpacesToAdd]; |
unsigned char srcBuffer[byteLength]; |
unsigned char *srcPtr = srcBuffer; |
[dataValue getBytes:srcBuffer]; |
const unsigned char t[16] = "0123456789ABCDEF"; |
for (;byteCounter < byteLength; byteCounter++){ |
unsigned src = *srcPtr; |
dstBuffer[stringCounter++] = t[src>>4]; |
dstBuffer[stringCounter++] = t[src & 15]; |
if (!forEdit && (byteCounter%2)==1){ |
dstBuffer[stringCounter++] = ' '; |
} |
srcPtr++; |
} |
dstBuffer[stringCounter] = '\0'; |
return [NSString stringWithUTF8String:(char*)dstBuffer]; |
} |
+ (NSData *)dataFromHexString:(NSString*) dataValue{ |
UInt32 stringLength = [dataValue length]; |
UInt32 byteLength = stringLength/2; |
UInt32 byteCounter = 0; |
char srcBuffer[stringLength]; |
[dataValue getCString:srcBuffer maxLength:stringLength encoding:NSASCIIStringEncoding]; |
char *srcPtr = srcBuffer; |
Byte dstBuffer[byteLength]; |
Byte *dst = dstBuffer; |
for(;byteCounter < byteLength;){ |
char c = *srcPtr++; |
char d = *srcPtr++; |
unsigned hi = 0, lo = 0; |
hi = charTo4Bits(c); |
lo = charTo4Bits(d); |
if (hi== 255 || lo == 255){ |
//errorCase |
return nil; |
} |
dstBuffer[byteCounter++] = ((hi << 4) | lo); |
} |
return [NSData dataWithBytes:dst length:byteLength]; |
} |
#pragma mark empty entry support |
+ (id)defaultValueForType:(UInt32)dataType |
{ |
id data = nil; |
switch(dataType){ |
case kQTMetaDataTypeBinary: |
case kQTMetaDataTypeJPEGImage: |
case kQTMetaDataTypePNGImage: |
case kQTMetaDataTypeBMPImage: |
{ |
const Byte dstBuffer[4] = {0xde, 0xad, 0xbe, 0xef}; |
data = [NSData dataWithBytes:dstBuffer length:4]; |
} |
break; |
case kQTMetaDataTypeUTF8: |
case kQTMetaDataTypeUTF16BE: |
case kQTMetaDataTypeMacEncodedText: |
data = [NSString stringWithString:@"your data"]; |
break; |
case kQTMetaDataTypeSignedIntegerBE: |
case kQTMetaDataTypeUnsignedIntegerBE: |
case kQTMetaDataTypeFloat32BE: |
case kQTMetaDataTypeFloat64BE: |
data = [NSNumber numberWithBool:FALSE]; |
break; |
default: |
NSLog(@"unknownKeyType, returning Bin as storage location"); |
data = nil; |
} |
return data; |
} |
- (void)awakeFromInsert |
{ |
//put in some default values |
[self setValue:[NSString stringWithString:@"com.company.data.metadataname"] forKey:@"name"]; |
[self setValue:[NSNumber numberWithLong:(kQTMetaDataTypeUTF8)] forKey:@"type"]; |
[self setValue:[MetadataAttributeMO defaultValueForType:kQTMetaDataTypeUTF8] forKey:@"dataString"]; |
} |
#pragma mark mapping to/from QT data types |
// since we can't put all the various datatypes into 'data' since it needs a specific type, |
// we need to see what we're storing to know where to put it/get it. |
+ (NSString *)dataKeyForType:(UInt32)dataType |
{ |
NSString* dataKey = nil; |
switch(dataType){ |
case kQTMetaDataTypeBinary: |
case kQTMetaDataTypeJPEGImage: |
case kQTMetaDataTypePNGImage: |
case kQTMetaDataTypeBMPImage: |
dataKey = [NSString stringWithString:@"dataBin"]; |
break; |
case kQTMetaDataTypeUTF8: |
case kQTMetaDataTypeUTF16BE: |
case kQTMetaDataTypeMacEncodedText: |
dataKey = [NSString stringWithString:@"dataString"]; |
break; |
case kQTMetaDataTypeSignedIntegerBE: |
case kQTMetaDataTypeUnsignedIntegerBE: |
dataKey = [NSString stringWithString:@"dataInt64"]; |
break; |
case kQTMetaDataTypeFloat32BE: |
dataKey = [NSString stringWithString:@"dataFloat32"]; |
break; |
case kQTMetaDataTypeFloat64BE: |
dataKey = [NSString stringWithString:@"dataFloat64"]; |
break; |
default: |
NSLog(@"unknownKeyType, returning Bin as storage location"); |
dataKey = [NSString stringWithString:@"dataBin"]; |
} |
return dataKey; |
} |
// since we can't put all the various datatypes into 'data' since it needs a specific type, |
// we need to see what we're storing to know where to put it/get it. |
- (void)setDataForString:(NSString*)stringValue |
{ |
id dataValue = nil; |
UInt32 dataType = [[self valueForKey:@"type"] intValue]; |
switch(dataType){ |
case kQTMetaDataTypeBinary: |
case kQTMetaDataTypeJPEGImage: |
case kQTMetaDataTypePNGImage: |
case kQTMetaDataTypeBMPImage: |
dataValue = [MetadataAttributeMO dataFromHexString:stringValue]; |
break; |
case kQTMetaDataTypeUTF8: |
case kQTMetaDataTypeUTF16BE: |
case kQTMetaDataTypeMacEncodedText: |
dataValue = [NSString stringWithString:stringValue]; |
break; |
case kQTMetaDataTypeSignedIntegerBE: |
case kQTMetaDataTypeUnsignedIntegerBE: |
dataValue = [NSNumber numberWithInt:[stringValue intValue]]; |
break; |
case kQTMetaDataTypeFloat32BE: |
case kQTMetaDataTypeFloat64BE: |
dataValue = [NSNumber numberWithInt:[stringValue doubleValue]]; |
break; |
default: |
NSLog(@"unknown key type in setDataForString"); |
} |
if (dataValue != nil) |
[self setValue:dataValue forKey:[MetadataAttributeMO dataKeyForType:dataType]]; |
} |
// map from the QT metadata types to the UI value types. |
- (void)setControlwithData:(NSControl *)myValueInspectorView forEdit:(BOOL)forEdit{ |
id dataValue = [self valueForKey:@"data"]; |
UInt32 dataType = [[self valueForKey:@"type"] intValue]; |
switch(dataType){ |
case kQTMetaDataTypeBinary: |
case kQTMetaDataTypeJPEGImage: |
case kQTMetaDataTypePNGImage: |
case kQTMetaDataTypeBMPImage: |
[myValueInspectorView setStringValue: @" "]; |
[myValueInspectorView setStringValue:[MetadataAttributeMO hexStringFromData:dataValue forEdit:forEdit]]; |
break; |
case kQTMetaDataTypeUTF8: |
case kQTMetaDataTypeUTF16BE: |
case kQTMetaDataTypeMacEncodedText: |
[myValueInspectorView setStringValue:dataValue]; |
break; |
case kQTMetaDataTypeSignedIntegerBE: |
case kQTMetaDataTypeUnsignedIntegerBE: |
[myValueInspectorView setIntValue:[dataValue intValue]]; |
break; |
case kQTMetaDataTypeFloat32BE: |
[myValueInspectorView setFloatValue:[dataValue floatValue]]; |
break; |
case kQTMetaDataTypeFloat64BE: |
[myValueInspectorView setDoubleValue:[dataValue doubleValue]]; |
break; |
default: |
NSLog(@"unknown key type in setControlwithData"); |
} |
} |
- (id)valueForUndefinedKey:(NSString *)key |
{ // KVC - overridden to access generic dictionary storage unless subclasses explicitly provide accessors |
// since we are storing the different data values as 'dataBin' or 'dataString' depending on what type it is (you can't leave it undefined) |
// we need a generic way to retreive and store it, so we let accessors get and set with 'data' and we route that to the right place. |
// Leveraging the 'type' value, we can calculate the name of the key for the data. |
id returnValue = nil; |
if ([key compare:@"data"] == NSOrderedSame){ |
UInt32 dataType = [[self valueForKey:@"type"] intValue]; |
returnValue = [self valueForKey:[MetadataAttributeMO dataKeyForType:dataType]]; |
//EXERCISE: we should probably clear out all the other @"data--" keys rather than just leaving them... |
} |
if (returnValue == nil) |
returnValue = [super valueForUndefinedKey:key]; |
return returnValue; |
} |
- (void)setValue:(id)value forUndefinedKey:(NSString *)key |
{ // KVC - overridden to access generic dictionary storage unless subclasses explicitly provide accessors |
// since we are storing the different data values as 'dataBin' or 'dataString' depending on what type it is (you can't leave it undefined) |
// we need a generic way to retreive and store it, so we let accessors get and set with 'data' and we route that to the right place. |
// Leveraging the 'type' value, we can calculate the name of the key for the data. |
if ([key compare:@"data"] == NSOrderedSame){ |
UInt32 dataType = [[self valueForKey:@"type"] intValue]; |
[self setValue:value forKey:[MetadataAttributeMO dataKeyForType:dataType]]; |
} |
} |
- (void)setValue:(id)value forKey:(NSString *)key |
{ // KVC - overridden to access generic dictionary storage unless subclasses explicitly provide accessors |
// since we are storing the different data values under different keys depending on the type, |
// when the type changes the value also has to change. make sure we set it to a default so the ui doesn't freak out. |
if ([key compare:@"type"] == NSOrderedSame){ |
UInt32 dataType = [value intValue]; |
NSString * dataKey = [MetadataAttributeMO dataKeyForType:dataType]; |
id oldValue = [super valueForKey:dataKey]; |
if (oldValue == nil) |
[self setValue:[MetadataAttributeMO defaultValueForType:dataType] forKey:dataKey]; |
[self didChangeValueForKey:dataKey]; // KVO - change notification |
} |
[super setValue:value forKey:key]; |
} |
#pragma mark copy/paste support |
- (NSArray *)copyKeys { |
static NSArray *copyKeys = nil; |
if (copyKeys == nil) { |
UInt32 dataType = [[self valueForKey:@"type"] intValue]; |
copyKeys = [[NSArray alloc] initWithObjects: |
@"name", @"type", [MetadataAttributeMO dataKeyForType:dataType], nil]; |
} |
return copyKeys; |
} |
- (NSDictionary *)dictionaryRepresentation |
{ |
return [self dictionaryWithValuesForKeys:[self copyKeys]]; |
} |
- (NSString *)stringDescription |
{ |
NSString *stringDescription = [self valueForKey:@"name"]; |
NSString *dataString = @""; |
id data = [self valueForKey:@"data"]; |
if (data != nil) { |
dataString = [data description]; |
} |
stringDescription = [stringDescription stringByAppendingFormat: |
@" = %@", dataString]; |
return stringDescription; |
} |
#pragma mark drag/drop support |
- (BOOL)supportsBinaryFileDrop{ |
UInt32 dataType = [[self valueForKey:@"type"] intValue]; |
switch(dataType){ |
case kQTMetaDataTypeBinary: |
case kQTMetaDataTypeJPEGImage: |
case kQTMetaDataTypePNGImage: |
case kQTMetaDataTypeBMPImage: |
return YES; |
default: |
return NO; |
} |
} |
@end |
unsigned charTo4Bits(char c){ |
unsigned bits = 0; |
if (c > '/' && c<':'){ |
bits = c - '0'; |
} else if (c > '@' && c < 'G'){ |
bits = (c- 'A') + 10; |
} else if (c > '`' && c < 'g'){ |
bits = (c- 'a') + 10; |
} else { |
bits = 255; |
} |
return bits; |
} |
Copyright © 2010 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2010-05-27