1/* propertyList.m 2 * Functions helping to read and write property lists 3 * 4 * Copyright (C) 2002-2012 by vhf interservice GmbH 5 * Author: Georg Fleischmann 6 * 7 * created: ? 8 * modified: 2009-12-12 (save coordinated with 9 digits precision instead of 6 before) 9 * 2008-01-12 (propertyListFromNSColor() Apple >= 10.4 workaround) 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the vhf Public License as 13 * published by vhf interservice GmbH. Among other things, the 14 * License requires that the copyright notices and this notice 15 * be preserved on all copies. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 * See the vhf Public License for more details. 21 * 22 * You should have received a copy of the vhf Public License along 23 * with this program; see the file LICENSE. If not, write to vhf. 24 * 25 * vhf interservice GmbH, Im Marxle 3, 72119 Altingen, Germany 26 * eMail: info@vhf.de 27 * http://www.vhf.de 28 */ 29 30#include <AppKit/AppKit.h> 31#include <VHFShared/VHFDictionaryAdditions.h> 32#include <VHFShared/vhfCommonFunctions.h> // vhfStringWithFloat() 33#include <VHFShared/vhfCompatibility.h> // CGFloat for OS X 10.4 34#include "propertyList.h" 35 36#ifndef NSAppKitVersionNumber10_4 37# define NSAppKitVersionNumber10_4 824 38#endif 39 40/* we don't always have VGraphic objects, so we declare the used method here */ 41@interface PropertyList 42- (id)initFromPropertyList:(id)plist inDirectory:(NSString*)directory; 43@end 44@implementation PropertyList 45- (id)initFromPropertyList:(id)plist inDirectory:(NSString*)directory { return nil; } 46@end 47 48/* backward compatibility before moving to new classnames 49 */ 50NSString *newClassName(NSString *className) 51{ 52 if ([className isEqual:@"TextGraphic"]) 53 return @"VText"; 54 return [@"V" stringByAppendingString:className]; 55} 56 57id propertyListFromArray(NSArray *array) 58{ id realObject; 59 NSMutableArray *plistArray; 60 NSEnumerator *enumerator; 61 62 plistArray = [NSMutableArray arrayWithCapacity:[array count]]; 63 enumerator = [array objectEnumerator]; 64 while ((realObject = [enumerator nextObject])) 65 { 66 if ([realObject respondsToSelector:@selector(propertyList)]) 67 [plistArray addObject:[realObject propertyList]]; 68 else 69 { 70 /* Should probably raise here. */ 71 } 72 } 73 return plistArray; 74} 75 76id propertyListFromFloat(float f) 77{ 78 return [NSString stringWithFormat:@"%.12g", f]; 79} 80 81id propertyListFromInt(int i) 82{ 83 return [NSString stringWithFormat:@"%d", i]; 84} 85 86/* modified: 2008-01-11 (Apple workaround) 87 */ 88id propertyListFromNSColor(NSColor *color) 89{ NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:5]; 90 91 if ([[color colorSpaceName] isEqualToString:NSCalibratedWhiteColorSpace]) 92 { 93 [dictionary setObject:@"CalWhite" forKey:@"s"]; 94 [dictionary setObject:vhfStringWithFloat([color alphaComponent]) forKey:@"A"]; 95 [dictionary setObject:vhfStringWithFloat([color whiteComponent]) forKey:@"W"]; 96 } 97 else if ( [[color colorSpaceName] isEqualToString:NSCalibratedRGBColorSpace] ) 98 { 99 [dictionary setObject:@"CalRGB" forKey:@"s"]; 100 [dictionary setObject:vhfStringWithFloat([color alphaComponent]) forKey:@"A"]; 101 [dictionary setObject:vhfStringWithFloat([color blueComponent]) forKey:@"B"]; 102 [dictionary setObject:vhfStringWithFloat([color greenComponent]) forKey:@"G"]; 103 [dictionary setObject:vhfStringWithFloat([color redComponent]) forKey:@"R"]; 104 } 105 else if ([[color colorSpaceName] isEqualToString:NSDeviceWhiteColorSpace]) 106 { 107 [dictionary setObject:@"DevWhite" forKey:@"s"]; 108 [dictionary setObject:vhfStringWithFloat([color alphaComponent]) forKey:@"A"]; 109 [dictionary setObject:vhfStringWithFloat([color whiteComponent]) forKey:@"W"]; 110 } 111 else if ([[color colorSpaceName] isEqualToString:NSDeviceRGBColorSpace]) 112 { 113 [dictionary setObject:@"DevRGB" forKey:@"s"]; 114 [dictionary setObject:vhfStringWithFloat([color alphaComponent]) forKey:@"A"]; 115 [dictionary setObject:vhfStringWithFloat([color blueComponent]) forKey:@"B"]; 116 [dictionary setObject:vhfStringWithFloat([color greenComponent]) forKey:@"G"]; 117 [dictionary setObject:vhfStringWithFloat([color redComponent]) forKey:@"R"]; 118 } 119 else if ([[color colorSpaceName] isEqualToString:NSDeviceCMYKColorSpace]) 120 { 121 [dictionary setObject:@"DevCMYK" forKey:@"s"]; 122 [dictionary setObject:vhfStringWithFloat([color alphaComponent]) forKey:@"A"]; 123 [dictionary setObject:vhfStringWithFloat([color cyanComponent]) forKey:@"C"]; 124 [dictionary setObject:vhfStringWithFloat([color magentaComponent]) forKey:@"M"]; 125 [dictionary setObject:vhfStringWithFloat([color yellowComponent]) forKey:@"Y"]; 126 [dictionary setObject:vhfStringWithFloat([color blackComponent]) forKey:@"B"]; 127 } 128 else if ([[color colorSpaceName] isEqualToString:NSNamedColorSpace]) 129 { 130 [dictionary setObject:@"Named" forKey:@"s"]; 131 [dictionary setObject:[color catalogNameComponent] forKey:@"CId"]; 132 [dictionary setObject:[color colorNameComponent] forKey:@"NId"]; 133 [dictionary setObject:[color localizedCatalogNameComponent] forKey:@"Catalog"]; 134 [dictionary setObject:[color localizedColorNameComponent] forKey:@"Name"]; 135 } 136#ifdef __APPLE__ // Fat: a 2nd layer of same functionality added in Mac OS 10.4 137 else if ( NSAppKitVersionNumber >= NSAppKitVersionNumber10_4 && // >= 10.4 138 [[color colorSpaceName] isEqualToString:NSCustomColorSpace] ) 139 { int cnt = [color numberOfComponents]; 140 CGFloat compo[cnt]; 141 142 [color getComponents:compo]; 143 switch ([[color colorSpace] colorSpaceModel]) 144 { 145 case NSGrayColorSpaceModel: // NSCustomColorSpace Generic Gray colorspace 0.5 1 146 [dictionary setObject:@"CalWhite" forKey:@"s"]; 147 [dictionary setObject:vhfStringWithFloat(compo[0]) forKey:@"W"]; 148 [dictionary setObject:vhfStringWithFloat(compo[1]) forKey:@"A"]; 149 break; 150 //return propertyListFromNSColor([color colorUsingColorSpace:[NSColorSpace deviceGrayColorSpace]]); 151 case NSRGBColorSpaceModel: 152 [dictionary setObject:@"DevRGB" forKey:@"s"]; 153 [dictionary setObject:vhfStringWithFloat(compo[0]) forKey:@"R"]; 154 [dictionary setObject:vhfStringWithFloat(compo[1]) forKey:@"G"]; 155 [dictionary setObject:vhfStringWithFloat(compo[2]) forKey:@"B"]; 156 [dictionary setObject:vhfStringWithFloat(compo[3]) forKey:@"A"]; 157 break; 158 case NSCMYKColorSpaceModel: 159 [dictionary setObject:@"DevCMYK" forKey:@"s"]; 160 [dictionary setObject:vhfStringWithFloat(compo[0]) forKey:@"C"]; 161 [dictionary setObject:vhfStringWithFloat(compo[1]) forKey:@"M"]; 162 [dictionary setObject:vhfStringWithFloat(compo[2]) forKey:@"Y"]; 163 [dictionary setObject:vhfStringWithFloat(compo[3]) forKey:@"B"]; 164 [dictionary setObject:vhfStringWithFloat(compo[4]) forKey:@"A"]; 165 break; 166 //case NSLABColorSpaceModel: 167 //case NSDeviceNColorSpaceModel: 168 default: 169 break; 170 } 171 } 172#endif 173 /*else 174 { 175 [dictionary setObject:@"Unknown" forKey:@"s"]; 176 [dictionary setObject:[NSArchiver archivedDataWithRootObject:color] forKey:@"Data"]; 177 }*/ 178 return dictionary; 179} 180 181id propertyListFromNSPrintInfo(NSPrintInfo *printInfo) 182{ NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:5]; 183 184 if (!printInfo) 185 return dictionary; 186 [dictionary setFloat:[printInfo leftMargin] forKey:@"leftMargin"]; 187 [dictionary setFloat:[printInfo rightMargin] forKey:@"rightMargin"]; 188 [dictionary setFloat:[printInfo topMargin] forKey:@"topMargin"]; 189 [dictionary setFloat:[printInfo bottomMargin] forKey:@"bottomMargin"]; 190 [dictionary setObject:propertyListFromNSSize([printInfo paperSize]) forKey:@"paperSize"]; 191 [dictionary setObject:[printInfo paperName] forKey:@"paperName"]; 192 [dictionary setInt:[printInfo orientation] forKey:@"orientation"]; 193 194 return dictionary; 195} 196 197id propertyListFromNSRect(NSRect rect) 198{ 199 return [NSString stringWithFormat:@"%.12g %.12g %.12g %.12g", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height]; 200} 201 202id propertyListFromNSSize(NSSize size) 203{ 204 return [NSString stringWithFormat:@"%.12g %.12g", size.width, size.height]; 205} 206 207id propertyListFromNSPoint(NSPoint point) 208{ //int digX = 9; 209 210 //if ( floor(point.x*1000.0)/1000.0 == point.x ) 211 // digX = 6; 212 return [NSString stringWithFormat:@"%.12g %.12g", point.x, point.y]; 213} 214 215id propertyListFromV3Point(V3Point point) 216{ 217 return [NSString stringWithFormat:@"%.12g %.12g %.12g", point.x, point.y, point.z]; 218} 219 220NSMutableArray *arrayFromPropertyList(id plist, NSString *directory, NSZone *zone) 221{ id realObject; 222 NSMutableArray *realArray; 223 NSDictionary *plistObject; 224 NSEnumerator *enumerator; 225 NSString *className; 226 227 realArray = [[NSMutableArray allocWithZone:zone] initWithCapacity:[plist count]]; 228 enumerator = [plist objectEnumerator]; 229 while ((plistObject = [enumerator nextObject])) 230 { 231 className = [plistObject objectForKey:@"Class"]; 232 if (className) 233 { id obj = [NSClassFromString(className) allocWithZone:zone]; 234 235 if (!obj) // load old projects 236 obj = [NSClassFromString(newClassName(className)) allocWithZone:zone]; 237 realObject = [obj initFromPropertyList:plistObject inDirectory:directory]; 238 [realArray addObject:realObject]; 239 [realObject release]; 240 } 241 else 242 NSLog(@"arrayFromPropertyList(): Class expected !"); 243 } 244 245 return realArray; 246} 247 248NSColor *colorFromPropertyList(id plist, NSZone *zone) 249{ 250 if ([plist isKindOfClass:[NSDictionary class]]) 251 { NSString *colorSpaceName = [plist objectForKey:@"s"]; 252 253 if (!colorSpaceName) 254 colorSpaceName = [plist objectForKey:@"ColorSpace"]; 255 256 if ([colorSpaceName isEqualToString:@"CalWhite"] || [colorSpaceName isEqualToString:@"NSCalibratedWhiteColorSpace"]) 257 { 258 if ([plist objectForKey:@"W"]) 259 return [[NSColor colorWithCalibratedWhite:[[plist objectForKey:@"W"] floatValue] alpha:[[plist objectForKey:@"A"] floatValue]] retain]; 260 else 261 return [[NSColor colorWithCalibratedWhite:[[plist objectForKey:@"White"] floatValue] alpha:[[plist objectForKey:@"Alpha"] floatValue]] retain]; 262 } 263 else if ([colorSpaceName isEqualToString:@"CalRGB"] || [colorSpaceName isEqualToString:@"NSCalibratedRGBColorSpace"]) 264 { 265 if ([plist objectForKey:@"R"]) 266 return [[NSColor colorWithCalibratedRed:[[plist objectForKey:@"R"] floatValue] green:[[plist objectForKey:@"G"] floatValue] blue:[[plist objectForKey:@"B"] floatValue] alpha:[[plist objectForKey:@"A"] floatValue]] retain]; 267 else 268 return [[NSColor colorWithCalibratedRed:[[plist objectForKey:@"Red"] floatValue] green:[[plist objectForKey:@"Green"] floatValue] blue:[[plist objectForKey:@"Blue"] floatValue] alpha:[[plist objectForKey:@"Alpha"] floatValue]] retain]; 269 } 270 else if ([colorSpaceName isEqualToString:@"DevWhite"] || [colorSpaceName isEqualToString:@"NSDeviceWhiteColorSpace"]) 271 { 272 if ([plist objectForKey:@"W"]) 273 return [[NSColor colorWithDeviceWhite:[[plist objectForKey:@"W"] floatValue] alpha:[[plist objectForKey:@"A"] floatValue]] retain]; 274 else 275 return [[NSColor colorWithDeviceWhite:[[plist objectForKey:@"White"] floatValue] alpha:[[plist objectForKey:@"Alpha"] floatValue]] retain]; 276 } 277 else if ([colorSpaceName isEqualToString:@"DevRGB"] || [colorSpaceName isEqualToString:@"NSDeviceRGBColorSpace"]) 278 { 279 if ([plist objectForKey:@"R"]) 280 return [[NSColor colorWithDeviceRed:[[plist objectForKey:@"R"] floatValue] green:[[plist objectForKey:@"G"] floatValue] blue:[[plist objectForKey:@"B"] floatValue] alpha:[[plist objectForKey:@"A"] floatValue]] retain]; 281 else 282 return [[NSColor colorWithDeviceRed:[[plist objectForKey:@"Red"] floatValue] green:[[plist objectForKey:@"Green"] floatValue] blue:[[plist objectForKey:@"Blue"] floatValue] alpha:[[plist objectForKey:@"Alpha"] floatValue]] retain]; 283 } 284 else if ([colorSpaceName isEqualToString:@"DevCMYK"] || [colorSpaceName isEqualToString:@"NSDeviceCMYKColorSpace"]) 285 { 286 if ([plist objectForKey:@"C"]) 287 return [[NSColor colorWithDeviceCyan:[[plist objectForKey:@"C"] floatValue] magenta:[[plist objectForKey:@"M"] floatValue] yellow:[[plist objectForKey:@"Y"] floatValue] black:[[plist objectForKey:@"B"] floatValue] alpha:[[plist objectForKey:@"A"] floatValue]] retain]; 288 else 289 return [[NSColor colorWithDeviceCyan:[[plist objectForKey:@"Cyan"] floatValue] magenta:[[plist objectForKey:@"Magenta"] floatValue] yellow:[[plist objectForKey:@"Yellow"] floatValue] black:[[plist objectForKey:@"Black"] floatValue] alpha:[[plist objectForKey:@"Alpha"] floatValue]] retain]; 290 } 291 else if ([colorSpaceName isEqualToString:@"Named"] || [colorSpaceName isEqualToString:@"NSNamedColorSpace"]) 292 { 293 return [[NSColor colorWithCatalogName:[plist objectForKey:@"CId"] colorName:[plist objectForKey:@"NId"]] retain]; 294 } 295 else if ([colorSpaceName isEqualToString:@"Unknown"]) 296 return [[NSUnarchiver unarchiveObjectWithData:[plist objectForKey:@"Data"]] retain]; 297 else 298 return nil; 299 } 300 else if ([plist isKindOfClass:[NSData class]]) 301 return plist ? [[NSUnarchiver unarchiveObjectWithData:plist] retain] : nil; 302 else // should never happen 303 return nil; 304} 305 306NSPrintInfo *printInfoFromPropertyList(id plist, NSZone *zone) 307{ NSPrintInfo *printInfo = [[NSPrintInfo sharedPrintInfo] copy]; 308 309 //[printInfo setVerticallyCentered:NO]; 310 //[printInfo setHorizontallyCentered:NO]; 311 //[printInfo setHorizontalPagination:NSFitPagination]; 312 313 [printInfo setLeftMargin:[plist floatForKey:@"leftMargin"]]; 314 [printInfo setRightMargin:[plist floatForKey:@"rightMargin"]]; 315 [printInfo setTopMargin:[plist floatForKey:@"topMargin"]]; 316 [printInfo setBottomMargin:[plist floatForKey:@"bottomMargin"]]; 317 318 [printInfo setPaperSize:sizeFromPropertyList([plist objectForKey:@"paperSize"])]; 319 [printInfo setPaperName:[plist objectForKey:@"paperName"]]; 320 [printInfo setOrientation:[plist intForKey:@"orientation"]]; 321 return printInfo; 322} 323 324NSRect rectFromPropertyList(NSString *plist) 325{ NSRect retval; 326 NSArray *components = [plist componentsSeparatedByString:@" "]; 327 328 retval.origin.x = [[components objectAtIndex:0] floatValue]; 329 retval.origin.y = [[components objectAtIndex:1] floatValue]; 330 retval.size.width = [[components objectAtIndex:2] floatValue]; 331 retval.size.height = [[components objectAtIndex:3] floatValue]; 332 return retval; 333} 334 335NSSize sizeFromPropertyList(id plist) 336{ NSSize retval; 337 NSArray *components = [plist componentsSeparatedByString:@" "]; 338 339 retval.width = [[components objectAtIndex:0] floatValue]; 340 retval.height = [[components objectAtIndex:1] floatValue]; 341 return retval; 342} 343 344NSPoint pointFromPropertyList(id plist) 345{ NSPoint retval; 346 NSArray *components = [plist componentsSeparatedByString:@" "]; 347 348 if ([components count] < 2) 349 return NSMakePoint(0.0, 0.0); 350 retval.x = [[components objectAtIndex:0] floatValue]; 351 retval.y = [[components objectAtIndex:1] floatValue]; 352 return retval; 353} 354 355V3Point v3pointFromPropertyList(id plist) 356{ V3Point retval; 357 NSArray *components = [plist componentsSeparatedByString:@" "]; 358 359 if ([components count] < 3) 360 return V3MakePoint(0.0, 0.0, 0.0); 361 retval.x = [[components objectAtIndex:0] floatValue]; 362 retval.y = [[components objectAtIndex:1] floatValue]; 363 retval.z = [[components objectAtIndex:2] floatValue]; 364 return retval; 365} 366