# HG changeset patch # User Jens Alfke # Date 1205039081 28800 # Node ID d84d25d6cdbba89cc036fee08038720ddb790133 Initial checkin. diff -r 000000000000 -r d84d25d6cdbb .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,8 @@ +syntax: glob +.DS_Store +build +.svn +*.pbxuser +*.perspectivev3 +*.mpkg +*.framework diff -r 000000000000 -r d84d25d6cdbb Base64.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Base64.h Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,23 @@ +// +// Base64.h +// MYUtilities +// +// Created by Jens Alfke on 1/27/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import + + +@interface NSData (Base64) + +- (NSString *)base64String; +- (NSString *)base64StringWithNewlines:(BOOL)encodeWithNewlines; + +- (NSData *)decodeBase64; +- (NSData *)decodeBase64WithNewLines:(BOOL)encodedWithNewlines; + +- (NSString *)hexString; +- (NSString *)hexDump; + +@end diff -r 000000000000 -r d84d25d6cdbb Base64.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Base64.m Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,165 @@ +// +// Base64.m +// MYUtilities +// +// Created by Jens Alfke on 1/27/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// +// Adapted from SSCrypto.m by Ed Silva; +// Copyright (c) 2003-2006 Septicus Software. All rights reserved. +// + +#import "Base64.h" +#import +#import + + +@implementation NSData (Base64) + + +/** + * Encodes the current data in base64, and creates and returns an NSString from the result. + * This is the same as piping data through "... | openssl enc -base64" on the command line. + * + * Code courtesy of DaveDribin (http://www.dribin.org/dave/) + * Taken from http://www.cocoadev.com/index.pl?BaseSixtyFour + **/ +- (NSString *)base64String +{ + return [self base64StringWithNewlines: YES]; +} + +/** + * Encodes the current data in base64, and creates and returns an NSString from the result. + * This is the same as piping data through "... | openssl enc -base64" on the command line. + * + * Code courtesy of DaveDribin (http://www.dribin.org/dave/) + * Taken from http://www.cocoadev.com/index.pl?BaseSixtyFour + **/ +- (NSString *)base64StringWithNewlines:(BOOL)encodeWithNewlines +{ + // Create a memory buffer which will contain the Base64 encoded string + BIO * mem = BIO_new(BIO_s_mem()); + + // Push on a Base64 filter so that writing to the buffer encodes the data + BIO * b64 = BIO_new(BIO_f_base64()); + if (!encodeWithNewlines) + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + mem = BIO_push(b64, mem); + + // Encode all the data + BIO_write(mem, [self bytes], [self length]); + BIO_flush(mem); + + // Create a new string from the data in the memory buffer + char * base64Pointer; + long base64Length = BIO_get_mem_data(mem, &base64Pointer); + NSString * base64String = [NSString stringWithCString:base64Pointer length:base64Length]; + + // Clean up and go home + BIO_free_all(mem); + return base64String; +} + +- (NSData *)decodeBase64 +{ + return [self decodeBase64WithNewLines:YES]; +} + +- (NSData *)decodeBase64WithNewLines:(BOOL)encodedWithNewlines +{ + // Create a memory buffer containing Base64 encoded string data + BIO * mem = BIO_new_mem_buf((void *) [self bytes], [self length]); + + // Push a Base64 filter so that reading from the buffer decodes it + BIO * b64 = BIO_new(BIO_f_base64()); + if (!encodedWithNewlines) + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + mem = BIO_push(b64, mem); + + // Decode into an NSMutableData + NSMutableData * data = [NSMutableData data]; + char inbuf[512]; + int inlen; + while ((inlen = BIO_read(mem, inbuf, sizeof(inbuf))) > 0) + [data appendBytes: inbuf length: inlen]; + + // Clean up and go home + BIO_free_all(mem); + return data; +} + + +- (NSString *)hexString +{ + const UInt8 *bytes = self.bytes; + NSUInteger length = self.length; + char out[2*length+1]; + char *dst = &out[0]; + for( int i=0; i 0) { + /* print rest of buffer if not empty */ + //printf("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr); + [ret appendString:[NSString stringWithFormat:@"[%4.4s] %-50.50s %s\n", + addrstr, hexstr, charstr]]; + } + return ret; +} + +@end diff -r 000000000000 -r d84d25d6cdbb CollectionUtils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CollectionUtils.h Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,77 @@ +// +// CollectionUtils.h +// MYUtilities +// +// Created by Jens Alfke on 1/5/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import + +// Collection creation conveniences: + +#define $array(OBJS...) ({id objs[]={OBJS}; \ + [NSArray arrayWithObjects: objs count: sizeof(objs)/sizeof(id)];}) +#define $marray(OBJS...) ({id objs[]={OBJS}; \ + [NSMutableArray arrayWithObjects: objs count: sizeof(objs)/sizeof(id)];}) + +#define $dict(PAIRS...) ({struct _dictpair pairs[]={PAIRS}; \ + _dictof(pairs,sizeof(pairs)/sizeof(struct _dictpair));}) +#define $mdict(PAIRS...) ({struct _dictpair pairs[]={PAIRS}; \ + _mdictof(pairs,sizeof(pairs)/sizeof(struct _dictpair));}) + +#define $object(VAL) ({__typeof(VAL) v=(VAL); _box(&v,@encode(__typeof(v)));}) + + +// Object conveniences: + +BOOL $equal(id obj1, id obj2); // Like -isEqual: but works even if either/both are nil + +#define $sprintf(FORMAT, ARGS... ) [NSString stringWithFormat: (FORMAT), ARGS] + +#define $cast(CLASSNAME,OBJ) (CLASSNAME*)(_cast([CLASSNAME class],(OBJ))) +#define $castNotNil(CLASSNAME,OBJ) (CLASSNAME*)(_castNotNil([CLASSNAME class],(OBJ))) +#define $castIf(CLASSNAME,OBJ) (CLASSNAME*)(_castIf([CLASSNAME class],(OBJ))) +#define $castArrayOf(ITEMCLASSNAME,OBJ) _castArrayOf([ITEMCLASSNAME class],(OBJ))) + +void setObj( id *var, id value ); +BOOL ifSetObj( id *var, id value ); +void setString( NSString **var, NSString *value ); +BOOL ifSetString( NSString **var, NSString *value ); + + +@interface NSArray (MYUtils) +- (BOOL) my_containsObjectIdenticalTo: (id)object; +@end + + +#pragma mark - +#pragma mark FOREACH: + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 +#define foreach(VAR,ARR) for(VAR in ARR) + +#else +struct foreachstate {NSArray *array; unsigned n, i;}; +static inline struct foreachstate _initforeach( NSArray *arr ) { + struct foreachstate s; + s.array = arr; + s.n = [arr count]; + s.i = 0; + return s; +} +#define foreach(VAR,ARR) for( struct foreachstate _s = _initforeach((ARR)); \ + _s.i<_s.n && ((VAR)=[_s.array objectAtIndex: _s.i], YES); \ + _s.i++ ) +#endif + + +// Internals (don't use directly) +struct _dictpair { id key; id value; }; +NSDictionary* _dictof(const struct _dictpair*, size_t count); +NSMutableDictionary* _mdictof(const struct _dictpair*, size_t count); +NSValue* _box(const void *value, const char *encoding); +id _cast(Class,id); +id _castNotNil(Class,id); +id _castIf(Class,id); +NSArray* _castArrayOf(Class,NSArray*); diff -r 000000000000 -r d84d25d6cdbb CollectionUtils.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CollectionUtils.m Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,192 @@ +// +// CollectionUtils.m +// MYUtilities +// +// Created by Jens Alfke on 1/5/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import "CollectionUtils.h" +#import "Test.h" + + +NSDictionary* _dictof(const struct _dictpair* pairs, size_t count) +{ + CAssert(count<10000); + id objects[count], keys[count]; + size_t n = 0; + for( size_t i=0; ivalue ) { + objects[n] = pairs->value; + keys[n] = pairs->key; + n++; + } + } + return [NSDictionary dictionaryWithObjects: objects forKeys: keys count: n]; +} + + +NSMutableDictionary* _mdictof(const struct _dictpair* pairs, size_t count) +{ + CAssert(count<10000); + id objects[count], keys[count]; + size_t n = 0; + for( size_t i=0; ivalue ) { + objects[n] = pairs->value; + keys[n] = pairs->key; + n++; + } + } + return [NSMutableDictionary dictionaryWithObjects: objects forKeys: keys count: n]; +} + + +BOOL $equal(id obj1, id obj2) // Like -isEqual: but works even if either/both are nil +{ + if( obj1 ) + return obj2 && [obj1 isEqual: obj2]; + else + return obj2==nil; +} + + +NSValue* _box(const void *value, const char *encoding) +{ + // file:///Developer/Documentation/DocSets/com.apple.ADC_Reference_Library.DeveloperTools.docset/Contents/Resources/Documents/documentation/DeveloperTools/gcc-4.0.1/gcc/Type-encoding.html + char e = encoding[0]; + if( e=='r' ) // ignore 'const' modifier + e = encoding[1]; + switch( e ) { + case 'c': return [NSNumber numberWithChar: *(char*)value]; + case 'C': return [NSNumber numberWithUnsignedChar: *(char*)value]; + case 's': return [NSNumber numberWithShort: *(short*)value]; + case 'S': return [NSNumber numberWithUnsignedShort: *(unsigned short*)value]; + case 'i': return [NSNumber numberWithInt: *(int*)value]; + case 'I': return [NSNumber numberWithUnsignedInt: *(unsigned int*)value]; + case 'l': return [NSNumber numberWithLong: *(long*)value]; + case 'L': return [NSNumber numberWithUnsignedLong: *(unsigned long*)value]; + case 'q': return [NSNumber numberWithLongLong: *(long long*)value]; + case 'Q': return [NSNumber numberWithUnsignedLongLong: *(unsigned long long*)value]; + case 'f': return [NSNumber numberWithFloat: *(float*)value]; + case 'd': return [NSNumber numberWithDouble: *(double*)value]; + case '*': return [NSString stringWithUTF8String: *(char**)value]; + case '@': return *(id*)value; + default: return [NSValue value: value withObjCType: encoding]; + } +} + + +id _cast( Class requiredClass, id object ) +{ + if( object && ! [object isKindOfClass: requiredClass] ) + [NSException raise: NSInvalidArgumentException format: @"%@ required, but got %@ %p", + requiredClass,[object class],object]; + return object; +} + +id _castNotNil( Class requiredClass, id object ) +{ + if( ! [object isKindOfClass: requiredClass] ) + [NSException raise: NSInvalidArgumentException format: @"%@ required, but got %@ %p", + requiredClass,[object class],object]; + return object; +} + +id _castIf( Class requiredClass, id object ) +{ + if( object && ! [object isKindOfClass: requiredClass] ) + object = nil; + return object; +} + +NSArray* _castArrayOf(Class itemClass, NSArray *a) +{ + id item; + foreach( item, $cast(NSArray,a) ) + _cast(itemClass,item); + return a; +} + + +void setObj( id *var, id value ) +{ + if( value != *var ) { + [*var release]; + *var = [value retain]; + } +} + +BOOL ifSetObj( id *var, id value ) +{ + if( value != *var && ![value isEqual: *var] ) { + [*var release]; + *var = [value retain]; + return YES; + } else { + return NO; + } +} + + +void setString( NSString **var, NSString *value ) +{ + if( value != *var ) { + [*var release]; + *var = [value copy]; + } +} + + +BOOL ifSetString( NSString **var, NSString *value ) +{ + if( value != *var && ![value isEqualToString: *var] ) { + [*var release]; + *var = [value copy]; + return YES; + } else { + return NO; + } +} + + +@implementation NSArray (MYUtils) + +- (BOOL) my_containsObjectIdenticalTo: (id)object +{ + return [self indexOfObjectIdenticalTo: object] != NSNotFound; +} + +@end + + +#import "Test.h" + +TestCase(CollectionUtils) { + NSArray *a = $array(@"foo",@"bar",@"baz"); + //Log(@"a = %@",a); + NSArray *aa = [NSArray arrayWithObjects: @"foo",@"bar",@"baz",nil]; + CAssertEqual(a,aa); + + const char *cstr = "a C string"; + id o = $object(cstr); + //Log(@"o = %@",o); + CAssertEqual(o,@"a C string"); + + NSDictionary *d = $dict({@"int", $object(1)}, + {@"double", $object(-1.1)}, + {@"char", $object('x')}, + {@"ulong", $object(1234567UL)}, + {@"longlong",$object(987654321LL)}, + {@"cstr", $object(cstr)}); + //Log(@"d = %@",d); + NSDictionary *dd = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithInt: 1], @"int", + [NSNumber numberWithDouble: -1.1], @"double", + [NSNumber numberWithChar: 'x'], @"char", + [NSNumber numberWithUnsignedLong: 1234567UL], @"ulong", + [NSNumber numberWithDouble: 987654321LL], @"longlong", + @"a C string", @"cstr", + nil]; + CAssertEqual(d,dd); +} diff -r 000000000000 -r d84d25d6cdbb ConcurrentOperation.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ConcurrentOperation.h Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,19 @@ +// +// ConcurrentOperation.h +// MYUtilities +// +// Created by Jens Alfke on 2/5/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import + + +@interface ConcurrentOperation : NSOperation +{ + BOOL _isExecuting, _isFinished; +} + +- (void) finish; + +@end diff -r 000000000000 -r d84d25d6cdbb ConcurrentOperation.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ConcurrentOperation.m Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,67 @@ +// +// ConcurrentOperation.m +// MYUtilities +// +// Created by Jens Alfke on 2/5/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import "ConcurrentOperation.h" + +// See file:///Developer/Documentation/DocSets/com.apple.ADC_Reference_Library.CoreReference.docset/Contents/Resources/Documents/documentation/Cocoa/Reference/NSOperation_class/Reference/Reference.html#//apple_ref/doc/uid/TP40004591-RH2-DontLinkElementID_4 + + +@implementation ConcurrentOperation + + +- (BOOL) isConcurrent {return YES;} + +- (void) main +{ + Assert(NO,@"Shouldn't call -main method of ConcurrentOperation"); +} + +- (BOOL) isExecuting +{ + return _isExecuting; +} + +- (BOOL) isFinished +{ + return _isFinished; +} + +- (void) start +{ + // don't call super! + Log(@"Starting %@",self); + [self willChangeValueForKey: @"isExecuting"]; + _isExecuting = YES; + [self didChangeValueForKey: @"isExecuting"]; +} + +- (void) finish +{ + Log(@"Finished %@",self); + [self willChangeValueForKey: @"isExecuting"]; + [self willChangeValueForKey: @"isFinished"]; + _isExecuting = NO; + _isFinished = YES; + [self didChangeValueForKey: @"isFinished"]; + [self didChangeValueForKey: @"isExecuting"]; +} + + +- (void) cancel +{ + Log(@"Canceling %@",self); + [super cancel]; + if( _isExecuting ) { + [self willChangeValueForKey: @"isExecuting"]; + _isExecuting = NO; + [self didChangeValueForKey: @"isExecuting"]; + } +} + + +@end diff -r 000000000000 -r d84d25d6cdbb FileAlias.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FileAlias.h Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,39 @@ +// +// FileAlias.h +// MYUtilities +// +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import + + +/** A wrapper around an AliasHandle: a persistent reference to a file, which works + even if the file is moved or renamed, or its volume unmounted. */ + +@interface FileAlias : NSObject +{ + AliasHandle _alias; +} + +- (id) initWithFilePath: (NSString*)path + error: (NSError**)error; + +- (id) initWithFilePath: (NSString*)path + relativeToPath: (NSString*)fromPath + error: (NSError**)error; + +- (NSString*) filePath: (NSError**)error; +- (NSString*) filePathRelativeToPath: (NSString*)fromPath error: (NSError**)error; + +- (NSArray*) findMatchesRelativeToPath: (NSString*)fromPath + withRules: (unsigned)rules // rules = kARMSearch etc. + error: (NSError**)error; +- (NSArray*) findMatches: (NSError**)error; + +- (NSString*) originalPath; +- (NSString*) originalFilename; +- (NSString*) originalVolumeName; +- (void) dump; + +@end diff -r 000000000000 -r d84d25d6cdbb FileAlias.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FileAlias.m Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,231 @@ +// +// FileAlias.m +// MYUtilities +// +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import "FileAlias.h" +#import "FileUtils.h" + + +@implementation FileAlias + + +- (id) initWithFilePath: (NSString*)targetPath + relativeToPath: (NSString*)fromPath + error: (NSError**)error +{ + NSParameterAssert(targetPath); + self = [super init]; + if( self ) { + OSStatus err; + FSRef fromRef, targetRef; + err = PathToFSRef(targetPath, &targetRef); + if( ! err ) { + if( fromPath ) { + err = PathToFSRef(fromPath,&fromRef); + if( ! err ) + err = FSNewAlias(&fromRef,&targetRef,&_alias); + } else { + err = FSNewAlias(NULL,&targetRef,&_alias); + } + } + + if( ! CheckOSErr(err,error) ) { + Warn(@"FileAlias init failed with OSStatus %i",err); + [self release]; + return nil; + } + } + return self; +} + +- (id) initWithFilePath: (NSString*)path + error: (NSError**)error +{ + return [self initWithFilePath: path relativeToPath: nil error: error]; +} + + +- (void) dealloc +{ + if( _alias ) + DisposeHandle((Handle)_alias); + [super dealloc]; +} + + +- (void)encodeWithCoder:(NSCoder *)coder +{ + NSParameterAssert([coder allowsKeyedCoding]); + NSKeyedArchiver *arch = (NSKeyedArchiver*)coder; + + [arch encodeBytes: (const uint8_t *) *_alias + length: GetHandleSize((Handle)_alias) + forKey: @"aliasHandle"]; +} + + +- (id)initWithCoder:(NSCoder *)decoder +{ + NSParameterAssert([decoder allowsKeyedCoding]); + NSKeyedUnarchiver *arch = (NSKeyedUnarchiver*)decoder; + + self = [super init]; + if( self ) { + Handle handle; + unsigned length; + const void *bytes = [arch decodeBytesForKey:@"aliasHandle" returnedLength: &length]; + if( bytes ) + PtrToHand(bytes,&handle,length); + if( ! handle ) { + [self release]; + return nil; + } + _alias = (AliasHandle) handle; + } + return self; +} + + +- (NSString*) description +{ + return [NSString stringWithFormat: @"%@['%@']", [self class],[self originalFilename]]; +} + + +- (NSString*) originalPath +{ + CFStringRef path = NULL; + OSStatus err = FSCopyAliasInfo(_alias,NULL,NULL,&path,NULL,NULL); + if( err ) + return nil; + else + return [(id)path autorelease]; +} + +- (NSString*) originalFilename +{ + HFSUniStr255 targetName; + OSStatus err = FSCopyAliasInfo(_alias,&targetName,NULL,NULL,NULL,NULL); + if( err ) + return nil; + else + return [(id)FSCreateStringFromHFSUniStr(NULL,&targetName) autorelease]; +} + +- (NSString*) originalVolumeName +{ + HFSUniStr255 volName; + OSStatus err = FSCopyAliasInfo(_alias,NULL,&volName,NULL,NULL,NULL); + if( err ) + return nil; + else + return [(id)FSCreateStringFromHFSUniStr(NULL,&volName) autorelease]; +} + +- (void) dump +{ + HFSUniStr255 targetName,volName; + CFStringRef path; + FSAliasInfoBitmap whichInfo = 0; + FSAliasInfo info; + OSStatus err = FSCopyAliasInfo(_alias,&targetName,&volName,&path,&whichInfo,&info); + if( err ) { + NSLog(@"FSCopyAliasInfo returned error %i",err); + return; + } + NSString *str = (id)FSCreateStringFromHFSUniStr(NULL,&targetName); + NSLog(@"Target name = '%@'",str); + [str release]; + str = (id)FSCreateStringFromHFSUniStr(NULL,&volName); + NSLog(@"Volume name = '%@'",str); + [str release]; + NSLog(@"Path = %@",path); + if( path ) CFRelease(path); + NSLog(@"Info bitmap = %08X", whichInfo); +} + + +#pragma mark - +#pragma mark RESOLVING: + + +- (NSString*) filePathRelativeToPath: (NSString*)fromPath error: (NSError**)error +{ + FSRef fromRef, targetRef, *fromRefPtr; + if( fromPath ) { + if( ! CheckOSErr( PathToFSRef(fromPath,&fromRef), error ) ) + return NO; + fromRefPtr = &fromRef; + } else { + fromRefPtr = NULL; + } + + Boolean wasChanged; + NSString *targetPath; + if( CheckOSErr( FSResolveAlias(fromRefPtr,_alias,&targetRef,&wasChanged), error) + && CheckOSErr( FSRefToPath(&targetRef,&targetPath), error ) ) + return targetPath; + else { + NSLog(@"%@: Couldn't resolve alias!",self); + [self dump]; + return nil; + } +} + +- (NSString*) filePath: (NSError**)error +{ + return [self filePathRelativeToPath: nil error: error]; +} + + +- (NSArray*) findMatchesRelativeToPath: (NSString*)fromPath + withRules: (unsigned)rules + error: (NSError**)error +{ + FSRef fromRef, *fromRefPtr; + if( fromPath ) { + if( ! CheckOSErr( PathToFSRef(fromPath,&fromRef), error ) ) + return nil; + fromRefPtr = &fromRef; + } else { + fromRefPtr = NULL; + } + + Boolean wasChanged; + short count = 10; + FSRef matches[count]; + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + if( ! FSMatchAliasBulk(fromRefPtr, rules, _alias, &count, matches, &wasChanged, NULL, NULL), error ) { + NSLog(@"%@: FSMatchAliasBulk failed!",self); + return nil; + } +#else + if( ! CheckOSErr( FSMatchAlias(fromRefPtr,rules,_alias,&count,matches,&wasChanged,NULL,NULL), error) ) { + NSLog(@"%@: FSMatchAlias failed!",self); + return nil; + } +#endif + + NSMutableArray *paths = [NSMutableArray arrayWithCapacity: count]; + for( short i=0; i + + +FOUNDATION_EXPORT OSStatus PathToFSRef( NSString *path, FSRef *outFSRef ); +FOUNDATION_EXPORT OSStatus FSRefToPath( const FSRef *fsRef, NSString **outPath ); + +FOUNDATION_EXPORT BOOL CheckOSErr( OSStatus err, NSError **error ); + +FOUNDATION_EXPORT NSString* AppSupportDirectory(void); diff -r 000000000000 -r d84d25d6cdbb FileUtils.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FileUtils.m Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,55 @@ +// +// FileUtils.m +// MYUtilities +// +// Created by Jens Alfke on 1/14/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import "FileUtils.h" + + +OSStatus PathToFSRef( NSString *path, FSRef *fsRef ) +{ + NSCParameterAssert(path); + return FSPathMakeRef((const UInt8 *)[path UTF8String],fsRef,NULL); +} + +OSStatus FSRefToPath( const FSRef *fsRef, NSString **outPath ) +{ + NSURL *url = (id) CFURLCreateFromFSRef(NULL,fsRef); + if( ! url ) + return paramErr; + *outPath = [url path]; + [url release]; + return noErr; +} + + +BOOL CheckOSErr( OSStatus err, NSError **error ) +{ + if( err ) { + if( error ) + *error = [NSError errorWithDomain: NSOSStatusErrorDomain code: err userInfo: nil]; + return NO; + } else { + return YES; + } +} + + +NSString* AppSupportDirectory() +{ + static NSString *sPath; + if( ! sPath ) { + NSString *dir = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, + NSUserDomainMask, YES) + objectAtIndex: 0]; + dir = [dir stringByAppendingPathComponent: [[NSBundle mainBundle] bundleIdentifier]]; + if( ! [[NSFileManager defaultManager] fileExistsAtPath: dir] + && ! [[NSFileManager defaultManager] createDirectoryAtPath: dir attributes: nil] ) + [NSException raise: NSGenericException format: @"Unable to create app support dir %@",dir]; + sPath = [dir copy]; + } + return sPath; +} diff -r 000000000000 -r d84d25d6cdbb GraphicsUtils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GraphicsUtils.h Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,21 @@ +// +// GraphicsUtils.h +// MYUtilities +// +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import + + +@interface NSImage (MYUtilities) +- (NSImage*) my_shrunkToFitIn: (NSSize) maxSize; +- (NSSize) my_sizeOfLargestRep; +- (NSData*) my_JPEGData; +//- (NSData*) my)_PICTData; +@end + + +@interface NSBezierPath (MYUtilities) ++ (NSBezierPath*) my_bezierPathWithRoundRect: (NSRect)rect radius: (float)radius; +@end diff -r 000000000000 -r d84d25d6cdbb GraphicsUtils.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GraphicsUtils.m Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,190 @@ +// +// GraphicsUtils.m +// MYUtilities +// +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import "GraphicsUtils.h" + + +@implementation NSImage (MYUtilities) + + +- (NSSize) my_sizeOfLargestRep +{ + NSArray *reps = [self representations]; + NSSize max = {0,0}; + int i; + for( i=[reps count]-1; i>=0; i-- ) { + NSImageRep *rep = [reps objectAtIndex: i]; + NSSize size = [rep size]; + if( size.width > max.width || size.height > max.height ) { + max = size; + } + } + return max; +} + + +- (NSImage*) my_shrunkToFitIn: (NSSize) maxSize +{ + NSSize size = self.size; + float scale = MIN( size.width/maxSize.width, size.height/maxSize.height ); + if( scale >= 1.0 ) + return self; + + NSSize newSize = {roundf(size.width*scale), roundf(size.height*scale)}; + NSImage *newImage = [[NSImage alloc] initWithSize: newSize]; + [newImage lockFocus]; + NSGraphicsContext *context = [NSGraphicsContext currentContext]; + [context saveGraphicsState]; + [context setImageInterpolation: NSImageInterpolationHigh]; + [self drawInRect: NSMakeRect(0,0,newSize.width,newSize.height) + fromRect: NSMakeRect(0,0,size.width,size.height) + operation: NSCompositeCopy fraction: 1.0f]; + [context restoreGraphicsState]; + [newImage unlockFocus]; + return [newImage autorelease]; +} + + +- (NSData*) my_JPEGData +{ + NSImage *tiffImage = [[NSImage alloc] initWithData:[self TIFFRepresentation]]; + NSBitmapImageRep *rep = [[tiffImage representations] objectAtIndex:0]; + NSDictionary *props = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithFloat: 0.75f], NSImageCompressionFactor, nil]; + NSData *jpeg = [rep representationUsingType: NSJPEGFileType properties: props]; + [tiffImage release]; + return jpeg; +} + + +#if 0 + +// Adapted from Apple's CocoaCreateMovie sample +// +static void CopyNSImageRepToGWorld(NSBitmapImageRep *imageRepresentation, GWorldPtr gWorldPtr) +{ + PixMapHandle pixMapHandle; + unsigned char* pixBaseAddr; + + // Lock the pixels + pixMapHandle = GetGWorldPixMap(gWorldPtr); + LockPixels (pixMapHandle); + pixBaseAddr = (unsigned char*) GetPixBaseAddr(pixMapHandle); + + const unsigned char* bitMapDataPtr = [imageRepresentation bitmapData]; + + if ((bitMapDataPtr != nil) && (pixBaseAddr != nil)) + { + int i,j; + int pixmapRowBytes = GetPixRowBytes(pixMapHandle); + NSSize imageSize = [imageRepresentation size]; + for (i=0; i< imageSize.height; i++) + { + const unsigned char *src = bitMapDataPtr + i * [imageRepresentation bytesPerRow]; + unsigned char *dst = pixBaseAddr + i * pixmapRowBytes; + for (j = 0; j < imageSize.width; j++) + { + *dst++ = 0; // X - our src is 24-bit only + *dst++ = *src++; // Red component + *dst++ = *src++; // Green component + *dst++ = *src++; // Blue component + } + } + } + UnlockPixels(pixMapHandle); +} + + +- (NSData*) my_PICTData +{ + // Locate the bitmap image rep: + NSBitmapImageRep *rep; + NSEnumerator *e = [[self representations] objectEnumerator]; + while( (rep=[e nextObject]) != nil ) { + if( [rep isKindOfClass: [NSBitmapImageRep class]] ) + break; + } + if( ! rep ) { + Warn(@"No bitmap image rep in image"); + return nil; + } + + // Copy the image data into a GWorld: + Rect bounds; + SetRect(&bounds, 0,0,[rep pixelsWide],[rep pixelsHigh]); + GWorldPtr gworld; + OSStatus err = NewGWorld(&gworld, 32, &bounds, NULL, NULL, 0); + if( err ) { + Warn(@"NewGWorld failed with err %i",err); + return nil; + } + CopyNSImageRepToGWorld(rep,gworld); + + // Draw the GWorld into a PicHandle: + CGrafPtr oldPort; + GDHandle oldDevice; + GetGWorld(&oldPort,&oldDevice); + SetGWorld(gworld,NULL); + ClipRect(&bounds); + PicHandle pic = OpenPicture(&bounds); + CopyBits(GetPortBitMapForCopyBits(gworld), + GetPortBitMapForCopyBits(gworld), + &bounds,&bounds,srcCopy,NULL); + ClosePicture(); + err = QDError(); + SetGWorld(oldPort,oldDevice); + DisposeGWorld(gworld); + + if( err ) { + Warn(@"Couldn't convert to PICT: error %i",err); + return nil; + } + + // Copy the PicHandle into an NSData: + HLock((Handle)pic); + //Test to put PICT on clipboard: + /*ScrapRef scrap; + GetCurrentScrap(&scrap); + ClearScrap(&scrap); + PutScrapFlavor(scrap,'PICT',0,GetHandleSize((Handle)pic),*pic);*/ + NSData *data = [NSData dataWithBytes: *pic length: GetHandleSize((Handle)pic)]; + DisposeHandle((Handle)pic); + Log(@"Converted image to %i bytes of PICT data",[data length]); + return data; +} +#endif + + +@end + + + + +@implementation NSBezierPath (MYUtilities) + ++ (NSBezierPath*) my_bezierPathWithRoundRect: (NSRect)rect radius: (float)radius +{ + radius = MIN(radius, floorf(rect.size.width/2)); + float x0 = NSMinX(rect), y0 = NSMinY(rect), + x1 = NSMaxX(rect), y1 = NSMaxY(rect); + NSBezierPath *path = [NSBezierPath bezierPath]; + + [path moveToPoint: NSMakePoint(x0+radius,y0)]; + + [path appendBezierPathWithArcFromPoint: NSMakePoint(x1,y0) + toPoint: NSMakePoint(x1,y1) radius: radius]; + [path appendBezierPathWithArcFromPoint: NSMakePoint(x1,y1) + toPoint: NSMakePoint(x0,y1) radius: radius]; + [path appendBezierPathWithArcFromPoint: NSMakePoint(x0,y1) + toPoint: NSMakePoint(x0,y0) radius: radius]; + [path appendBezierPathWithArcFromPoint: NSMakePoint(x0,y0) + toPoint: NSMakePoint(x1,y0) radius: radius]; + [path closePath]; + return path; +} + +@end diff -r 000000000000 -r d84d25d6cdbb IChatUtils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IChatUtils.h Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,21 @@ +// +// IChatUtils.h +// MYUtilities +// +// Created by Jens Alfke on 3/3/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import +@class SBApplication; + + +@interface IChatUtils : NSObject + ++ (SBApplication*) app; ++ (BOOL) isRunning; ++ (void) activate; ++ (NSString*) activeChatPartner; ++ (BOOL) sendMessage: (NSString*)msg; + +@end diff -r 000000000000 -r d84d25d6cdbb IChatUtils.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IChatUtils.m Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,65 @@ +// +// IChatUtils.m +// MYUtilities +// +// Created by Jens Alfke on 3/3/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import "IChatUtils.h" +#import "iChatBridge.h" + +@implementation IChatUtils + + +static iChatApplication *sIChatApp; + ++ (void) initialize +{ + if( ! sIChatApp ) { + sIChatApp = [SBApplication applicationWithBundleIdentifier: @"com.apple.iChat"]; + sIChatApp.timeout = 5*60; // in ticks + } +} + + ++ (SBApplication*) app {return sIChatApp;} ++ (BOOL) isRunning {return sIChatApp.isRunning;} ++ (void) activate {[sIChatApp activate];} + + ++ (iChatTextChat*) activeChat +{ + if( ! [sIChatApp isRunning] ) + return nil; + SBElementArray *chats = sIChatApp.textChats; + if( chats.count==0 ) + return nil; + iChatTextChat *chat = [chats objectAtIndex: 0]; + if( ! chat.active ) + return nil; + return chat; +} + ++ (NSString*) activeChatPartner +{ + iChatTextChat *chat = [self activeChat]; + if( ! chat ) + return nil; + NSMutableArray *names = $marray(); + for( iChatBuddy *b in [chat participants] ) + [names addObject: (b.fullName ?: b.name)]; + return [names componentsJoinedByString: @", "]; +} + ++ (BOOL) sendMessage: (NSString*)msg +{ + iChatTextChat *chat = [self activeChat]; + if( ! chat ) + return NO; + [sIChatApp send: msg to: chat]; + return YES; +} + + +@end diff -r 000000000000 -r d84d25d6cdbb KVUtils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/KVUtils.h Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,66 @@ +// +// KVUtils.h +// MYUtilities +// +// Created by Jens Alfke on 2/25/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import + + +enum { + MYKeyValueObservingOptionOnce = 1<<31, + MYKeyValueObservingOptionDelayed = 1<<30 +}; + + + +@interface Observance : NSObject +{ + id _target; + id _observed; + NSString *_keyPath; + NSKeyValueObservingOptions _options; + SEL _action; +} + +- (id) initWithTarget: (id)target + action: (SEL)action + observed: (id)observed + keyPath: (NSString*)keyPath + options: (NSKeyValueObservingOptions)options; + +- (void) stopObserving; + +@property (readonly) id observed; +@property (readonly) NSString* keyPath; + +@end + + + +@interface Observer : NSObject +{ + id _target; + NSMutableArray *_observances; +} + +- (id) initWithTarget: (id)target; + +@property (readonly) id target; + +- (void) observe: (id)observed + keyPath: (NSString*)keyPath + options: (NSKeyValueObservingOptions)options + action: (SEL)action; + +- (void) observe: (id)observed + keyPath: (NSString*)keyPath + action: (SEL)action; + +- (void) stopObserving: (id)observedOrNil keyPath: (NSString*)keyPathOrNil; + +- (void) stopObserving; + +@end diff -r 000000000000 -r d84d25d6cdbb KVUtils.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/KVUtils.m Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,163 @@ +// +// KVUtils.m +// MYUtilities +// +// Created by Jens Alfke on 2/25/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import "KVUtils.h" + + +@implementation Observance + +- (id) initWithTarget: (id)target + action: (SEL)action + observed: (id)observed + keyPath: (NSString*)keyPath + options: (NSKeyValueObservingOptions)options +{ + self = [super init]; + if (self != nil) { + _target = target; + _action = action; + _observed = observed; + _keyPath = [keyPath copy]; + _options = options; + + options &= ~(MYKeyValueObservingOptionOnce | MYKeyValueObservingOptionDelayed); + + [_observed addObserver: self forKeyPath: _keyPath options: options context: _action]; + } + return self; +} + +- (void) dealloc +{ + [_observed removeObserver: self forKeyPath: _keyPath]; + [_keyPath release]; + [super dealloc]; +} + + +@synthesize observed=_observed, keyPath=_keyPath; + + +- (void) stopObserving +{ + [_observed removeObserver: self forKeyPath: _keyPath]; + _observed = nil; + _target = nil; + _action = NULL; +} + + +- (void) _callTargetWithChange: (NSDictionary*)change +{ + @try{ + [_target performSelector: _action withObject: _observed withObject: change]; + }@catch( NSException *x ) { + Warn(@"Uncaught exception in -[%@<%p> %s] while observing change of key-path %@ in %@<%p>: %@", + _target,_target, _action, _keyPath, _observed,_observed, x); + } +} + + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context +{ + if( object == _observed ) { + if( _options & MYKeyValueObservingOptionDelayed ) + [self performSelector: @selector(_callTargetWithChange:) withObject: change + afterDelay: 0.0]; + else + [self _callTargetWithChange: change]; + if( _options & MYKeyValueObservingOptionOnce ) + [self stopObserving]; + } +} + + +@end + + + + +@implementation Observer + + +- (id) init +{ + return [self initWithTarget: self]; +} + + + +- (id) initWithTarget: (id)target +{ + Assert(target); + self = [super init]; + if (self != nil) { + _target = target; + _observances = [[NSMutableArray alloc] init]; + } + return self; +} + + +- (void) dealloc +{ + [self stopObserving]; + [_observances release]; + [super dealloc]; +} + + +@synthesize target=_target; + + +- (void) observe: (id)observed + keyPath: (NSString*)keyPath + options: (NSKeyValueObservingOptions)options + action: (SEL)action +{ + Observance *o = [[Observance alloc] initWithTarget: _target + action: action + observed: observed + keyPath: keyPath + options: options]; + [_observances addObject: o]; + [o release]; +} + + +- (void) observe: (id)observed + keyPath: (NSString*)keyPath + action: (SEL)action +{ + [self observe: observed keyPath: keyPath options: 0 action: action]; +} + + +- (void) stopObserving +{ + [_observances makeObjectsPerformSelector: @selector(stopObserving)]; + [_observances removeAllObjects]; +} + + +- (void) stopObserving: (id)observed keyPath: (NSString*)keyPath +{ + // observed or keyPath may be nil + for( int i=_observances.count-1; i>=0; i-- ) { + Observance *o = [_observances objectAtIndex: i]; + if( (observed==nil || observed==o.observed) && (keyPath==nil || [keyPath isEqual: o.keyPath]) ) { + [o stopObserving]; + [_observances removeObjectAtIndex: i]; + } + } +} + +@end diff -r 000000000000 -r d84d25d6cdbb Logging.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Logging.h Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,23 @@ +// +// Logging.h +// MYUtilities +// +// Created by Jens Alfke on 1/5/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import + + +NSString* LOC( NSString *key ); // Localized string lookup + + +#define Log(FMT,ARGS...) do{if(__builtin_expect(gShouldLog,0)) _Log(FMT,##ARGS);}while(0) +#define Warn Warn + +void AlwaysLog( NSString *msg, ... ) __attribute__((format(__NSString__, 1, 2))); + + +extern int gShouldLog; +void _Log( NSString *msg, ... ) __attribute__((format(__NSString__, 1, 2))); +void Warn( NSString *msg, ... ) __attribute__((format(__NSString__, 1, 2))); diff -r 000000000000 -r d84d25d6cdbb Logging.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Logging.m Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,96 @@ +// +// Logging.m +// MYUtilities +// +// Created by Jens Alfke on 1/5/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import "Logging.h" +#import +#include +#include + + +NSString* LOC( NSString *key ) // Localized string lookup +{ + NSString *value = [[NSBundle mainBundle] localizedStringForKey:key value:nil table:nil]; + if( value == key ) { + Warn(@"No localized string for '%@' in Localizable.strings!",key); + value = [key uppercaseString]; + } + return value; +} + + +int gShouldLog = -1; + + +static BOOL isConsole( int fd ) +{ + if( isatty(fd) ) + return YES; + char path[MAXPATHLEN]; + if( fcntl(fd, F_GETPATH, path) == -1 ) + return NO; + return YES; +} + + +static void _Logv( NSString *msg, va_list args ) +{ + if( isConsole(STDERR_FILENO) ) { + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + static NSDateFormatter *sTimestampFormat; + if( ! sTimestampFormat ) { + sTimestampFormat = [[NSDateFormatter alloc] init]; + sTimestampFormat.dateFormat = @"HH:mm:ss.SSS"; + } + NSDate *now = [[NSDate alloc] init]; + NSString *timestamp = [sTimestampFormat stringFromDate: now]; + [now release]; + msg = [[NSString alloc] initWithFormat: msg arguments: args]; + NSString *finalMsg = [[NSString alloc] initWithFormat: @"%@| %@\n", timestamp,msg]; + fputs([finalMsg UTF8String], stderr); + [finalMsg release]; + [msg release]; + [pool drain]; + } else + NSLogv(msg,args); +} + + +void AlwaysLog( NSString *msg, ... ) +{ + va_list args; + va_start(args,msg); + _Logv(msg,args); + va_end(args); +} + + +void _Log( NSString *msg, ... ) +{ + if( gShouldLog == -1 ) + gShouldLog = [[NSUserDefaults standardUserDefaults] boolForKey: @"Log"]; + + if( gShouldLog ) { + va_list args; + va_start(args,msg); + _Logv(msg,args); + va_end(args); + } +} + + +void Warn( NSString *msg, ... ) +{ + msg = [@"WARNING*** " stringByAppendingString: msg]; + + va_list args; + va_start(args,msg); + _Logv(msg,args); + va_end(args); +} + + diff -r 000000000000 -r d84d25d6cdbb Target.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Target.h Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,17 @@ +// +// Target.h +// MYUtilities +// +// Created by Jens Alfke on 2/11/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import + + +#define $target(RCVR,METHOD) _mktarget((RCVR),@selector(METHOD)) + +id $calltarget( NSInvocation *target, id sender ); + + +NSInvocation* _mktarget( id rcvr, SEL action ); diff -r 000000000000 -r d84d25d6cdbb Target.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Target.m Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,53 @@ +// +// Target.m +// MYUtilities +// +// Created by Jens Alfke on 2/11/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import "Target.h" + + +NSInvocation* _mktarget( id rcvr, SEL action ) +{ + NSMethodSignature *sig = [rcvr methodSignatureForSelector: action]; + CAssert(sig,@"%@<%p> does not respond to %@",[rcvr class],rcvr,NSStringFromSelector(action)); + CAssert(sig.numberOfArguments==3, + @"-[%@ %@] can't be used as a target because it takes >1 param", + [rcvr class],NSStringFromSelector(action)); + CAssert(0==strcmp([sig getArgumentTypeAtIndex: 2],"@"), + @"-[%@ %@] can't be used as a target because it takes a non-object param", + [rcvr class],NSStringFromSelector(action)); + NSInvocation *inv = [NSInvocation invocationWithMethodSignature: sig]; + inv.target = rcvr; + inv.selector = action; + return inv; +} + + +id $calltarget( NSInvocation *target, id param ) +{ + if( target && target.target ) { + [target setArgument: ¶m atIndex: 2]; + [target invoke]; + + NSMethodSignature *sig = target.methodSignature; + NSUInteger returnLength = sig.methodReturnLength; + if( returnLength==0 ) + return nil; // void + else { + const char *returnType = sig.methodReturnType; + if( returnType[0]=='@' ) { + id returnObject; + [target getReturnValue: &returnObject]; + return returnObject; + } else { + UInt8 returnBuffer[returnLength]; + [target getReturnValue: &returnBuffer]; + return [NSValue valueWithBytes: &returnBuffer objCType: returnType]; + } + } + } else + return nil; +} diff -r 000000000000 -r d84d25d6cdbb Test.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Test.h Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,96 @@ +// +// Test.h +// MYUtilities +// +// Created by Jens Alfke on 1/5/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import +#import "CollectionUtils.h" + + +/** Call this first thing in main() to run tests. + This function is a no-op if the DEBUG macro is not defined (i.e. in a release build). + At runtime, to cause a particular test "X" to run, add a command-line argument "Test_X". + To run all tests, add the argument "Test_All". + To run only tests without starting the main program, add the argument "Test_Only". */ +#if DEBUG +void RunTestCases( int argc, const char **argv ); +#else +#define RunTestCases(ARGC,ARGV) +#endif + +/** The TestCase() macro declares a test case. + Its argument is a name for the test case (without quotes), and it's followed with a block + of code implementing the test. + The code should raise an exception if anything fails. + The CAssert, CAssertEqual and CAssertEq macros, below, are the most useful way to do this. + A test case can register a dependency on another test case by calling RequireTestCase(). + Example: + TestCase(MyLib) { + RequireTestCase("LibIDependOn"); + CAssertEq( myFunction(), 12345 ); + } + Test cases are disabled if the DEBUG macro is not defined (i.e. in a release build). */ +#if DEBUG +#define TestCase(NAME) void Test_##NAME(void); \ + struct TestCaseLink linkToTest##NAME = {&Test_##NAME,#NAME}; \ + __attribute__((constructor)) static void registerTestCase##NAME() \ + {linkToTest##NAME.next = gAllTestCases; gAllTestCases=&linkToTest##NAME; } \ + void Test_##NAME(void) +#else +#define TestCase(NAME) __attribute__((unused)) static void Test_##NAME(void) +#endif + +/** Can call this in a test case to indicate a prerequisite. + The prerequisite test will be run first, and if it fails, the current test case will be skipped. */ +#define RequireTestCase(NAME) _RequireTestCase(#NAME) +void _RequireTestCase( const char *name ); + + + +/** General-purpose assertions, replacing NSAssert etc.. You can use these outside test cases. */ + +#define Assert(COND,MSG...) do{ if( __builtin_expect(!(COND),NO) ) \ + _AssertFailed(self,(const char*)_cmd, __FILE__, __LINE__,\ + #COND,##MSG,NULL); }while(0) +#define CAssert(COND,MSG...) do{ if( __builtin_expect(!(COND),NO) ) \ + _AssertFailed(nil, __PRETTY_FUNCTION__, __FILE__, __LINE__,\ + #COND,##MSG,NULL); }while(0) + +#define AssertEqual(VAL,EXPECTED) do{ id _val = VAL, _expected = EXPECTED;\ + Assert(_val==_expected || [_val isEqual: _expected], @"Unexpected value for %s: %@ (expected %@)", #VAL,_val,_expected); \ + }while(0) +#define CAssertEqual(VAL,EXPECTED) do{ id _val = (VAL), _expected = (EXPECTED);\ + CAssert(_val==_expected || [_val isEqual: _expected], @"Unexpected value for %s: %@ (expected %@)", #VAL,_val,_expected); \ + }while(0) + +// AssertEq is for scalars (int, float...) +#define AssertEq(VAL,EXPECTED) do{ typeof(VAL) _val = VAL; typeof(EXPECTED) _expected = EXPECTED;\ + Assert(_val==_expected, @"Unexpected value for %s: %@ (expected %@)", #VAL,$object(_val),$object(_expected)); \ + }while(0) +#define CAssertEq(VAL,EXPECTED) do{ typeof(VAL) _val = VAL; typeof(EXPECTED) _expected = EXPECTED;\ + CAssert(_val==_expected, @"Unexpected value for %s: %@ (expected %@)", #VAL,$object(_val),$object(_expected)); \ + }while(0) + + +#pragma mark - +#pragma mark EXCEPTION UTILITIES: + +@interface NSException (MooseyardUtil) +/** Returns a textual, human-readable backtrace of the point where the exception was thrown. */ +- (NSString*) my_callStack; +@end + + + +// Nasty internals ... +#if DEBUG +void _RunTestCase( void (*testptr)(), const char *name ); + +struct TestCaseLink {void (*testptr)(); const char *name; BOOL passed; struct TestCaseLink *next;}; +extern struct TestCaseLink *gAllTestCases; +#endif DEBUG +void _AssertFailed( id rcvr, const char *selOrFn, const char *sourceFile, int sourceLine, + const char *condString, NSString *message, ... ) __attribute__((noreturn)); diff -r 000000000000 -r d84d25d6cdbb Test.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Test.m Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,203 @@ +// +// Test.m +// MYUtilities +// +// Created by Jens Alfke on 1/5/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import "Test.h" +#import + +#if DEBUG + +struct TestCaseLink *gAllTestCases; +static int sPassed, sFailed; + +static BOOL RunTestCase( struct TestCaseLink *test ) +{ + if( test->testptr ) { + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + Log(@"=== Testing %s ...",test->name); + @try{ + test->testptr(); + Log(@"√√√ %s passed\n\n",test->name); + test->passed = YES; + sPassed++; + }@catch( NSException *x ) { + if( [x.name isEqualToString: @"TestCaseSkipped"] ) + Log(@"... skipping test %s since %@\n\n", test->name, x.reason); + else { + Log(@"XXX FAILED test case '%s' due to:\nException: %@\n%@\n\n", + test->name,x,x.my_callStack); + sFailed++; + } + }@finally{ + [pool drain]; + test->testptr = NULL; // prevents test from being run again + } + } + return test->passed; +} + + +static BOOL RunTestCaseNamed( const char *name ) +{ + for( struct TestCaseLink *test = gAllTestCases; test; test=test->next ) + if( strcmp(name,test->name)==0 ) { + return RunTestCase(test); + } + Log(@"... WARNING: Could not find test case named '%s'\n\n",name); + return NO; +} + + +void _RequireTestCase( const char *name ) +{ + if( ! RunTestCaseNamed(name) ) { + [NSException raise: @"TestCaseSkipped" + format: @"prerequisite %s failed", name]; + } +} + + +void RunTestCases( int argc, const char **argv ) +{ + gShouldLog = YES; + sPassed = sFailed = 0; + BOOL stopAfterTests = NO; + for( int i=1; inext ) + RunTestCase(link); + } else { + RunTestCaseNamed(arg); + } + } + } + if( sPassed>0 || sFailed>0 || stopAfterTests ) { + if( sFailed==0 ) + Log(@"√√√√√√ ALL %i TESTS PASSED √√√√√√", sPassed); + else { + Log(@"****** %i TESTS FAILED, %i PASSED ******", sFailed,sPassed); + exit(1); + } + if( stopAfterTests ) { + Log(@"Stopping after tests ('Test_Only' arg detected)"); + exit(0); + } + } +} + + +#endif DEBUG + + +#pragma mark - +#pragma mark ASSERTION FAILURE HANDLER: + + +void _AssertFailed( id rcvr, const char *selOrFn, const char *sourceFile, int sourceLine, + const char *condString, NSString *message, ... ) +{ + if( message ) { + va_list args; + va_start(args,message); + message = [[[NSString alloc] initWithFormat: message arguments: args] autorelease]; + va_end(args); + } else + message = [NSString stringWithUTF8String: condString]; + + if( rcvr ) + [[NSAssertionHandler currentHandler] handleFailureInMethod: (SEL)selOrFn + object: rcvr + file: [NSString stringWithUTF8String: sourceFile] + lineNumber: sourceLine + description: @"%@", message]; + else + [[NSAssertionHandler currentHandler] handleFailureInFunction: [NSString stringWithUTF8String:selOrFn] + file: [NSString stringWithUTF8String: sourceFile] + lineNumber: sourceLine + description: @"%@", message]; + abort(); // unreachable, but appeases compiler +} + + +#pragma mark - +#pragma mark EXCEPTION BACKTRACES: + + +@implementation NSException (MooseyardUtil) + + +- (NSArray*) my_callStackReturnAddresses +{ + // On 10.5 or later, can get the backtrace: + if( [self respondsToSelector: @selector(callStackReturnAddresses)] ) + return [self valueForKey: @"callStackReturnAddresses"]; + else + return nil; +} + +- (NSArray*) my_callStackReturnAddressesSkipping: (unsigned)skip limit: (unsigned)limit +{ + NSArray *addresses = [self my_callStackReturnAddresses]; + if( addresses ) { + unsigned n = [addresses count]; + skip = MIN(skip,n); + limit = MIN(limit,n-skip); + addresses = [addresses subarrayWithRange: NSMakeRange(skip,limit)]; + } + return addresses; +} + + +- (NSString*) my_callStack +{ + NSArray *addresses = [self my_callStackReturnAddressesSkipping: 2 limit: 15]; + if (!addresses) + return nil; + + // We pipe the hex return addresses through the 'atos' tool to get symbolic names: + // Adapted from : + NSMutableString *cmd = [NSMutableString stringWithFormat: @"/usr/bin/atos -p %d", getpid()]; + NSValue *addr; + foreach(addr,addresses) { + [cmd appendFormat: @" %p", [addr pointerValue]]; + } + FILE *file = popen( [cmd UTF8String], "r" ); + if( ! file ) + return nil; + + NSMutableData *output = [NSMutableData data]; + char buffer[512]; + size_t length; + while ((length = fread( buffer, 1, sizeof( buffer ), file ) )) + [output appendBytes: buffer length: length]; + pclose( file ); + NSString *outStr = [[[NSString alloc] initWithData: output encoding: NSUTF8StringEncoding] autorelease]; + + NSMutableString *result = [NSMutableString string]; + NSString *line; + foreach( line, [outStr componentsSeparatedByString: @"\n"] ) { + // Skip frames that are part of the exception/assertion handling itself: + if( [line hasPrefix: @"-[NSAssertionHandler"] || [line hasPrefix: @"+[NSException"] + || [line hasPrefix: @"-[NSException"] || [line hasPrefix: @"_AssertFailed"] ) + continue; + if( result.length ) + [result appendString: @"\n"]; + [result appendString: @"\t"]; + [result appendString: line]; + // Don't show the "__start" frame below "main": + if( [line hasPrefix: @"main "] ) + break; + } + return result; +} + +@end diff -r 000000000000 -r d84d25d6cdbb TimeIntervalFormatter.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TimeIntervalFormatter.h Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,19 @@ +// +// TimeIntervalFormatter.h +// MYUtilities +// +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import + + +@interface TimeIntervalFormatter : NSFormatter +{ + BOOL _showsMinutes, _showsFractionalSeconds; +} + +- (void) setShowsMinutes: (BOOL)showsMinutes; +- (void) setShowsFractionalSeconds: (BOOL)showsFractionalSeconds; + +@end diff -r 000000000000 -r d84d25d6cdbb TimeIntervalFormatter.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TimeIntervalFormatter.m Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,93 @@ +// +// TimeIntervalFormatter.m +// MYUtilities +// +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import "TimeIntervalFormatter.h" + + +@implementation TimeIntervalFormatter + + +- (void) awakeFromNib +{ + _showsMinutes = YES; +} + +- (void) setShowsMinutes: (BOOL)show {_showsMinutes = show;} +- (void) setShowsFractionalSeconds: (BOOL)show {_showsFractionalSeconds = show;} + + +- (NSString*) stringForObjectValue: (id)object +{ + if (![object isKindOfClass:[NSNumber class]]) + return nil; + NSTimeInterval time = [object doubleValue]; + NSString *sign; + if( time==0.0 ) + return nil; + else if( time < 0.0 ) { + sign = @"-"; + time = -time; + } else + sign = @""; + if( ! _showsFractionalSeconds ) + time = floor(time); + int minutes = (int)floor(time / 60.0); + if( _showsMinutes || minutes>0 ) { + double seconds = time - 60.0*minutes; + return [NSString stringWithFormat: (_showsFractionalSeconds ?@"%@%d:%06.3lf" :@"%@%d:%02.0lf"), + sign,minutes,seconds]; + } else { + return [NSString stringWithFormat: (_showsFractionalSeconds ?@"%@%.3lf" :@"%@%.0lf"), + sign,time]; + } +} + + +- (BOOL)getObjectValue:(id *)anObject + forString:(NSString *)string + errorDescription:(NSString **)error +{ + NSScanner *scanner = [NSScanner scannerWithString: string]; + [scanner setCharactersToBeSkipped: [NSCharacterSet whitespaceCharacterSet]]; + double seconds; + if( [scanner isAtEnd] ) { + seconds = 0.0; + } else { + if( ! [scanner scanDouble: &seconds] || seconds<0.0 ) goto error; + if( [scanner scanString: @":" intoString: NULL] ) { + double minutes = seconds; + if( ! [scanner scanDouble: &seconds] || seconds<0.0 ) goto error; + seconds += 60*minutes; + } + if( ! [scanner isAtEnd] ) goto error; + } + *anObject = [NSNumber numberWithDouble: seconds]; + return YES; + +error: + *anObject = nil; + if( error ) + *error = @"Not a valid time interval"; + return NO; +} + + +- (BOOL)isPartialStringValid:(NSString **)partialStringPtr + proposedSelectedRange:(NSRangePointer)proposedSelRangePtr + originalString:(NSString *)origString + originalSelectedRange:(NSRange)origSelRange + errorDescription:(NSString **)error +{ + static NSCharacterSet *sIllegalChars; + if( ! sIllegalChars ) + sIllegalChars = [[[NSCharacterSet characterSetWithCharactersInString: @"0123456789.:"] + invertedSet] retain]; + return [*partialStringPtr rangeOfCharacterFromSet: sIllegalChars].length == 0; +} + + +@end diff -r 000000000000 -r d84d25d6cdbb ValueArray.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ValueArray.h Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,49 @@ +// +// ValueArray.h +// MYUtilities +// +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import + + +@interface ValueArray : NSObject +{ + unsigned _count; + size_t _valueSize; +} + ++ (ValueArray*) valueArrayWithCount: (unsigned)count valueSize: (size_t)valueSize; + +- (unsigned) count; +- (size_t) valueSize; +- (const void*) valueAtIndex: (unsigned)i; +- (void) getValue: (void*)value atIndex: (unsigned)i; +- (void) setValue: (const void*)value atIndex: (unsigned)i; + +@end + + +#define DeclareValueArrayOf(CAPTYPE,TYPE) \ + @interface CAPTYPE##Array : ValueArray \ + + (CAPTYPE##Array*) TYPE##ArrayWithCount: (unsigned)count; \ + - (TYPE) TYPE##AtIndex: (unsigned)index; \ + - (void) set##CAPTYPE: (TYPE)value atIndex: (unsigned)index; \ + @end + +#define ImplementValueArrayOf(CAPTYPE,TYPE) \ + @implementation CAPTYPE##Array \ + + (CAPTYPE##Array*) TYPE##Array##WithCount: (unsigned)count \ + {return (id)[super valueArrayWithCount: count valueSize: sizeof(TYPE)];} \ + - (TYPE) TYPE##AtIndex: (unsigned)i; \ + {NSParameterAssert(i<_count); return ((const TYPE*)object_getIndexedIvars(self))[i];}\ + - (void) set##CAPTYPE: (TYPE)value atIndex: (unsigned)i \ + {NSParameterAssert(i<_count); ((TYPE*)object_getIndexedIvars(self))[i] = value;}\ + @end + + +// Declares IntArray class +DeclareValueArrayOf(Int,int) + +DeclareValueArrayOf(Double,double) diff -r 000000000000 -r d84d25d6cdbb ValueArray.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ValueArray.m Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,93 @@ +// +// ValueArray.m +// MYUtilities +// +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import "ValueArray.h" + + +@implementation ValueArray + + +- (id) initWithCount: (unsigned)count valueSize: (size_t)valueSize +{ + self = [super init]; + if( self ) { + _count = count; + _valueSize = valueSize; + } + return self; +} + ++ (ValueArray*) valueArrayWithCount: (unsigned)count valueSize: (size_t)valueSize +{ + return [[(ValueArray*)NSAllocateObject(self,count*valueSize,nil) + initWithCount: count valueSize: valueSize] + autorelease]; +} + +- (unsigned) count {return _count;} +- (size_t) valueSize {return _valueSize;} + +- (const void*) valueAtIndex: (unsigned)i +{ + NSParameterAssert(i<_count); + return (const char*)object_getIndexedIvars(self) + i*_valueSize; +} + +- (void) getValue: (void*)value atIndex: (unsigned)i +{ + NSParameterAssert(i<_count); + NSParameterAssert(value!=NULL); + memcpy(value, object_getIndexedIvars(self) + i*_valueSize, _valueSize); +} + +- (void) setValue: (const void*)value atIndex: (unsigned)i +{ + NSParameterAssert(i<_count); + NSParameterAssert(value!=NULL); + memcpy(object_getIndexedIvars(self) + i*_valueSize, value, _valueSize); +} + + + +- (id)initWithCoder:(NSCoder *)decoder +{ + NSParameterAssert([decoder allowsKeyedCoding]); + NSKeyedUnarchiver *arch = (NSKeyedUnarchiver*)decoder; + unsigned count = [arch decodeIntForKey: @"count"]; + size_t valueSize = [arch decodeIntForKey: @"valueSize"]; + + [super release]; + self = [[[self class] valueArrayWithCount: count valueSize: valueSize] retain]; + if( self ) { + unsigned nBytes; + const void *bytes = [arch decodeBytesForKey: @"values" returnedLength: &nBytes]; + NSAssert(nBytes==count*valueSize,@"Value size mismatch"); + memcpy( object_getIndexedIvars(self), bytes, nBytes ); + } + return self; +} + + +- (void)encodeWithCoder:(NSCoder *)coder +{ + NSParameterAssert([coder allowsKeyedCoding]); + NSKeyedArchiver *arch = (NSKeyedArchiver*)coder; + + [arch encodeInt: _count forKey: @"count"]; + [arch encodeInt: _valueSize forKey: @"valueSize"]; + [arch encodeBytes: object_getIndexedIvars(self) + length: _count*_valueSize + forKey: @"values"]; +} + + +@end + + +ImplementValueArrayOf(Int,int) + +ImplementValueArrayOf(Double,double) diff -r 000000000000 -r d84d25d6cdbb With.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/With.h Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,21 @@ +// +// With.h +// MYUtilities +// +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import + + +#define WITH(OBJ) id __with=[OBJ beginWith]; @try + +#define ENDWITH @finally{[__with endWith];} +#define CATCHWITH @catch(NSException *x){id w=__with; __with=nil; _catchWith(w,x);} @finally{[__with endWith];} + +void _catchWith( id with, NSException *x ); + +@interface NSAutoreleasePool (With) ++ (NSAutoreleasePool*) beginWith; +- (void) endWith; +@end \ No newline at end of file diff -r 000000000000 -r d84d25d6cdbb With.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/With.m Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,34 @@ +// +// With.m +// MYUtilities +// +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import "With.h" +#import "Logging.h" + + +@interface NSObject (With) +- (BOOL) endWith: (NSException*)x; +@end + + +void _catchWith( id with, NSException *x ) +{ + Warn(@"Exception thrown from WITH(%@) block: %@",[with class],x); + if( [with respondsToSelector: @selector(endWith:)] ) { + if( ! [with endWith: x] ) + @throw x; // propagate the exception if -endWith: returns NO + } else { + [with endWith]; + } +} + + + +@implementation NSAutoreleasePool (With) ++ (NSAutoreleasePool*) beginWith {return [self new];} +- (void) endWith {[self drain];} +- (BOOL) endWith: (NSException*)x {[self drain]; return YES;} +@end \ No newline at end of file diff -r 000000000000 -r d84d25d6cdbb iChatBridge.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iChatBridge.h Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,460 @@ +/* + * iChat.h + */ + +#import +#import + + +@class iChatItem, iChatApplication, iChatColor, iChatDocument, iChatWindow, iChatRichText, iChatCharacter, iChatParagraph, iChatWord, iChatAttributeRun, iChatAttachment, iChatApplication, iChatBuddy, iChatService, iChatChat, iChatTextChat, iChatAudioChat, iChatVideoChat, iChatFileTransfer; + +typedef enum { + iChatSaveOptionsYes = 'yes ' /* Save the file. */, + iChatSaveOptionsNo = 'no ' /* Do not save the file. */, + iChatSaveOptionsAsk = 'ask ' /* Ask the user whether or not to save the file. */ +} iChatSaveOptions; + +typedef enum { + iChatInviteTypeAudioInvitation = 'acon', + iChatInviteTypeTextChatInvitation = 'tcon', + iChatInviteTypeVideoInvitation = 'vcon' +} iChatInviteType; + +typedef enum { + iChatAccountStatusAvailable = 'aval', + iChatAccountStatusAway = 'away', + iChatAccountStatusOffline = 'offl', + iChatAccountStatusInvisible = 'invs', + iChatAccountStatusIdle = 'idle', + iChatAccountStatusUnknown = 'unkn' +} iChatAccountStatus; + +typedef enum { + iChatMyStatusAway = 'away', + iChatMyStatusAvailable = 'aval', + iChatMyStatusOffline = 'offl', + iChatMyStatusInvisible = 'invs' +} iChatMyStatus; + +typedef enum { + iChatConnectionStatusDisconnecting = 'dcng', + iChatConnectionStatusConnected = 'conn', + iChatConnectionStatusConnecting = 'cong', + iChatConnectionStatusDisconnected = 'dcon' +} iChatConnectionStatus; + +typedef enum { + iChatCapabilitiesVideoChat = 'vcon', + iChatCapabilitiesAudioChat = 'acon', + iChatCapabilitiesMultipersonVideo = 'mwvc', + iChatCapabilitiesMultipersonAudio = 'mwac' +} iChatCapabilities; + +typedef enum { + iChatScreenSharingNone = 'ssns', + iChatScreenSharingLocalScreen = 'ssls', + iChatScreenSharingRemoteScreen = 'ssrs' +} iChatScreenSharing; + +typedef enum { + iChatServiceTypeAIM = 'saim', + iChatServiceTypeBonjour = 'ssub', + iChatServiceTypeJabber = 'sjab' +} iChatServiceType; + +typedef enum { + iChatDirectionIncoming = 'FTic', + iChatDirectionOutgoing = 'FTog' +} iChatDirection; + +typedef enum { + iChatTransferStatusPreparing = 'FTsp', + iChatTransferStatusWaiting = 'FTsw', + iChatTransferStatusTransferring = 'FTsg', + iChatTransferStatusFinalizing = 'FTsz', + iChatTransferStatusFinished = 'FTsf', + iChatTransferStatusFailed = 'FTse' +} iChatTransferStatus; + +typedef enum { + iChatAvTypeAudio = 'ICAa', + iChatAvTypeVideo = 'ICAv' +} iChatAvType; + +typedef enum { + iChatChatTypeInstantMessage = 'ICim', + iChatChatTypeDirectInstantMessage = 'ICdi', + iChatChatTypeChatRoom = 'ICcr' +} iChatChatType; + +typedef enum { + iChatJoinStateNotJoined = 'ICJc', + iChatJoinStateJoining = 'ICJg', + iChatJoinStateJoined = 'ICJj' +} iChatJoinState; + +typedef enum { + iChatAvConnectionStatusInvited = 'ICAi', + iChatAvConnectionStatusWaiting = 'ICAw', + iChatAvConnectionStatusConnecting = 'ICAx', + iChatAvConnectionStatusConnected = 'ICAc', + iChatAvConnectionStatusEnded = 'ICAn' +} iChatAvConnectionStatus; + + + +/* + * Standard Suite + */ + +// A scriptable object. +@interface iChatItem : SBObject + +@property (copy) NSDictionary *properties; // All of the object's properties. + +- (void) closeSaving:(iChatSaveOptions)saving savingIn:(NSURL *)savingIn; // Close a document. +- (void) saveIn:(NSURL *)in_ as:(NSString *)as; // Save a document. +- (void) delete; // Delete an object. +- (SBObject *) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties; // Copy object(s) and put the copies at a new location. +- (BOOL) exists; // Verify if an object exists. +- (SBObject *) moveTo:(SBObject *)to; // Move object(s) to a new location. + +@end + +// The application's top-level scripting object. +@interface iChatApplication : SBApplication + +- (SBElementArray *) documents; +- (SBElementArray *) windows; + +@property (copy, readonly) NSString *name; // The name of the application. +@property (readonly) BOOL frontmost; // Is this the frontmost (active) application? +@property (copy, readonly) NSString *version; // The version of the application. + +- (void) open:(NSArray *)x; // Open a document. +- (void) print:(NSURL *)x; // Print an object. +- (void) quitSaving:(iChatSaveOptions)saving; // Quit the application. +- (void) invite:(NSArray *)x to:(id)to withMessage:(NSString *)withMessage; // Invites a buddy to join an existing chat. +- (void) logIn; // Log in to the specified service, or all services if none is specified. If the account password is not in the keychain the user will be prompted to enter one. +- (void) logOut; // Logs out of a service, or all services if none is specified. +- (void) send:(id)x to:(id)to; // Sends a message or file to a buddy or to a chat. +- (void) storeRecentPicture; // Stores the currently set buddy picture into your recent pictures. +- (void) showChatChooserFor:(iChatBuddy *)for_; // displays a dialog in iChat to start a new chat with the specified buddy + +@end + +// A color. +@interface iChatColor : SBObject + +- (void) closeSaving:(iChatSaveOptions)saving savingIn:(NSURL *)savingIn; // Close a document. +- (void) saveIn:(NSURL *)in_ as:(NSString *)as; // Save a document. +- (void) delete; // Delete an object. +- (SBObject *) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties; // Copy object(s) and put the copies at a new location. +- (BOOL) exists; // Verify if an object exists. +- (SBObject *) moveTo:(SBObject *)to; // Move object(s) to a new location. + +@end + +// An iChat document. +@interface iChatDocument : SBObject + +@property (copy, readonly) NSString *name; // The document's name. +@property (readonly) BOOL modified; // Has the document been modified since the last save? +@property (copy, readonly) NSURL *file; // The document's location on disk. + +- (void) closeSaving:(iChatSaveOptions)saving savingIn:(NSURL *)savingIn; // Close a document. +- (void) saveIn:(NSURL *)in_ as:(NSString *)as; // Save a document. +- (void) delete; // Delete an object. +- (SBObject *) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties; // Copy object(s) and put the copies at a new location. +- (BOOL) exists; // Verify if an object exists. +- (SBObject *) moveTo:(SBObject *)to; // Move object(s) to a new location. + +@end + +// A window. +@interface iChatWindow : SBObject + +@property (copy, readonly) NSString *name; // The full title of the window. +- (NSInteger) id; // The unique identifier of the window. +@property NSInteger index; // The index of the window, ordered front to back. +@property NSRect bounds; // The bounding rectangle of the window. +@property (readonly) BOOL closeable; // Whether the window has a close box. +@property (readonly) BOOL minimizable; // Whether the window can be minimized. +@property BOOL minimized; // Whether the window is currently minimized. +@property (readonly) BOOL resizable; // Whether the window can be resized. +@property BOOL visible; // Whether the window is currently visible. +@property (readonly) BOOL zoomable; // Whether the window can be zoomed. +@property BOOL zoomed; // Whether the window is currently zoomed. +@property (copy, readonly) iChatDocument *document; // The document whose contents are being displayed in the window. + +- (void) closeSaving:(iChatSaveOptions)saving savingIn:(NSURL *)savingIn; // Close a document. +- (void) saveIn:(NSURL *)in_ as:(NSString *)as; // Save a document. +- (void) delete; // Delete an object. +- (SBObject *) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties; // Copy object(s) and put the copies at a new location. +- (BOOL) exists; // Verify if an object exists. +- (SBObject *) moveTo:(SBObject *)to; // Move object(s) to a new location. + +@end + + + +/* + * Text Suite + */ + +// Rich (styled) text +@interface iChatRichText : SBObject + +- (SBElementArray *) characters; +- (SBElementArray *) paragraphs; +- (SBElementArray *) words; +- (SBElementArray *) attributeRuns; +- (SBElementArray *) attachments; + +@property (copy) NSColor *color; // The color of the first character. +@property (copy) NSString *font; // The name of the font of the first character. +@property double size; // The size in points of the first character. + +- (void) closeSaving:(iChatSaveOptions)saving savingIn:(NSURL *)savingIn; // Close a document. +- (void) saveIn:(NSURL *)in_ as:(NSString *)as; // Save a document. +- (void) delete; // Delete an object. +- (SBObject *) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties; // Copy object(s) and put the copies at a new location. +- (BOOL) exists; // Verify if an object exists. +- (SBObject *) moveTo:(SBObject *)to; // Move object(s) to a new location. + +@end + +// This subdivides the text into characters. +@interface iChatCharacter : SBObject + +- (SBElementArray *) characters; +- (SBElementArray *) paragraphs; +- (SBElementArray *) words; +- (SBElementArray *) attributeRuns; +- (SBElementArray *) attachments; + +@property (copy) NSColor *color; // The color of the first character. +@property (copy) NSString *font; // The name of the font of the first character. +@property NSInteger size; // The size in points of the first character. + +- (void) closeSaving:(iChatSaveOptions)saving savingIn:(NSURL *)savingIn; // Close a document. +- (void) saveIn:(NSURL *)in_ as:(NSString *)as; // Save a document. +- (void) delete; // Delete an object. +- (SBObject *) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties; // Copy object(s) and put the copies at a new location. +- (BOOL) exists; // Verify if an object exists. +- (SBObject *) moveTo:(SBObject *)to; // Move object(s) to a new location. + +@end + +// This subdivides the text into paragraphs. +@interface iChatParagraph : SBObject + +- (SBElementArray *) characters; +- (SBElementArray *) paragraphs; +- (SBElementArray *) words; +- (SBElementArray *) attributeRuns; +- (SBElementArray *) attachments; + +@property (copy) NSColor *color; // The color of the first character. +@property (copy) NSString *font; // The name of the font of the first character. +@property NSInteger size; // The size in points of the first character. + +- (void) closeSaving:(iChatSaveOptions)saving savingIn:(NSURL *)savingIn; // Close a document. +- (void) saveIn:(NSURL *)in_ as:(NSString *)as; // Save a document. +- (void) delete; // Delete an object. +- (SBObject *) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties; // Copy object(s) and put the copies at a new location. +- (BOOL) exists; // Verify if an object exists. +- (SBObject *) moveTo:(SBObject *)to; // Move object(s) to a new location. + +@end + +// This subdivides the text into words. +@interface iChatWord : SBObject + +- (SBElementArray *) characters; +- (SBElementArray *) paragraphs; +- (SBElementArray *) words; +- (SBElementArray *) attributeRuns; +- (SBElementArray *) attachments; + +@property (copy) NSColor *color; // The color of the first character. +@property (copy) NSString *font; // The name of the font of the first character. +@property NSInteger size; // The size in points of the first character. + +- (void) closeSaving:(iChatSaveOptions)saving savingIn:(NSURL *)savingIn; // Close a document. +- (void) saveIn:(NSURL *)in_ as:(NSString *)as; // Save a document. +- (void) delete; // Delete an object. +- (SBObject *) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties; // Copy object(s) and put the copies at a new location. +- (BOOL) exists; // Verify if an object exists. +- (SBObject *) moveTo:(SBObject *)to; // Move object(s) to a new location. + +@end + +// This subdivides the text into chunks that all have the same attributes. +@interface iChatAttributeRun : SBObject + +- (SBElementArray *) characters; +- (SBElementArray *) paragraphs; +- (SBElementArray *) words; +- (SBElementArray *) attributeRuns; +- (SBElementArray *) attachments; + +@property (copy) NSColor *color; // The color of the first character. +@property (copy) NSString *font; // The name of the font of the first character. +@property NSInteger size; // The size in points of the first character. + +- (void) closeSaving:(iChatSaveOptions)saving savingIn:(NSURL *)savingIn; // Close a document. +- (void) saveIn:(NSURL *)in_ as:(NSString *)as; // Save a document. +- (void) delete; // Delete an object. +- (SBObject *) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties; // Copy object(s) and put the copies at a new location. +- (BOOL) exists; // Verify if an object exists. +- (SBObject *) moveTo:(SBObject *)to; // Move object(s) to a new location. + +@end + +// Represents an inline text attachment. This class is used mainly for make commands. +@interface iChatAttachment : iChatRichText + +@property (copy, readonly) NSURL *file; // The path to the file for the attachment + + +@end + + + +/* + * iChat Suite + */ + +// iChat application. +@interface iChatApplication (IChatSuite) + +- (SBElementArray *) buddies; +- (SBElementArray *) services; +- (SBElementArray *) fileTransfers; +- (SBElementArray *) chats; +- (SBElementArray *) textChats; +- (SBElementArray *) audioChats; +- (SBElementArray *) videoChats; + +@property (readonly) NSInteger idleTime; // Time in seconds that I have been idle. +@property (copy) NSImage *image; // My image as it appears in all services. +@property (copy) NSString *statusMessage; // My status message, visible to other people while I am online. +@property iChatMyStatus status; // My status on all services. +@property (copy) iChatAudioChat *activeAvChat; // The currently active audio or video chat. + +@end + +// A buddy on a service. +@interface iChatBuddy : iChatItem + +- (NSString *) id; // The buddy's service and handle. For example: AIM:JohnDoe007 +@property (copy, readonly) iChatService *service; // The service on which this buddy exists. +@property (copy, readonly) NSString *name; // The buddy's name as it appears in the buddy list. +@property (copy, readonly) NSString *handle; // The buddy's online account name. +@property (readonly) iChatAccountStatus status; // The buddy's current status. +@property (copy, readonly) NSString *statusMessage; // The buddy's current status message. +@property (readonly) NSInteger idleTime; // The time in seconds the buddy has been idle. +@property (copy, readonly) NSArray *capabilities; // The buddy's messaging capabilities. +@property (copy, readonly) NSImage *image; // The buddy's custom image. +@property (copy, readonly) NSString *firstName; // The first name from this buddy's Address Book card, if available +@property (copy, readonly) NSString *lastName; // The last name from this buddy's Address Book card, if available +@property (copy, readonly) NSString *fullName; // The full name from this buddy's Address Book card, if available + + +@end + +// A service that can be logged in from this system +@interface iChatService : iChatItem + +- (SBElementArray *) buddies; +- (SBElementArray *) chats; + +- (NSString *) id; // A guid identifier for this service. +@property (copy) NSString *name; // The name of this service as defined in Account preferences description field +@property BOOL enabled; // Is the service enabled? +@property (readonly) iChatConnectionStatus status; // The connection status for this account. +@property (readonly) iChatServiceType serviceType; // The type of protocol for this service + +- (void) logIn; // Log in to the specified service, or all services if none is specified. If the account password is not in the keychain the user will be prompted to enter one. +- (void) logOut; // Logs out of a service, or all services if none is specified. + +@end + +// An audio, video, or text chat. +@interface iChatChat : SBObject + +- (NSString *) id; // A guid identifier for this chat. +@property (copy, readonly) iChatService *service; // The service which is participating in this chat. +@property (copy, readonly) NSArray *participants; // Other participants of this chat. This property may be specified at time of creation. +@property (readonly) BOOL secure; // Is this chat secure? +@property (readonly) BOOL invitation; // Is this an invitation to a chat? +@property (readonly) BOOL active; // Is this chat currently active? +@property (copy, readonly) NSDate *started; // The date on which this chat started. +@property (copy, readonly) NSDate *updated; // The date when this chat was last updated. + +- (void) closeSaving:(iChatSaveOptions)saving savingIn:(NSURL *)savingIn; // Close a document. +- (void) saveIn:(NSURL *)in_ as:(NSString *)as; // Save a document. +- (void) delete; // Delete an object. +- (SBObject *) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties; // Copy object(s) and put the copies at a new location. +- (BOOL) exists; // Verify if an object exists. +- (SBObject *) moveTo:(SBObject *)to; // Move object(s) to a new location. +- (void) accept; // Accepts an incoming text, audio, or video chat invitation, or file transfer +- (void) decline; // Declines an incoming text, audio, or video chat invitation, or file transfer + +@end + +// A text chat. +@interface iChatTextChat : iChatChat + +@property (copy, readonly) NSString *subject; // The subject of this chat, if available. +@property (copy, readonly) NSString *invitationMessage; // An invitation message. This may only be specified at the time of creation. This message will be sent to chat participants when the chat is created. +@property (readonly) iChatJoinState joinState; // How you are joined to this chat +@property (copy, readonly) NSString *name; // The address or room name of this chat. This property may be specified at time of creation. +@property (readonly) iChatChatType chatType; // The type of this chat. + + +@end + +// An audio or video chat. +@interface iChatAudioChat : iChatChat + +@property (readonly) iChatScreenSharing screenSharing; // Type of screen sharing session taking place within this chat. +@property BOOL muted; // Is the chat muted? +@property (readonly) iChatAvConnectionStatus avConnectionStatus; // The connection state for this av chat. + +- (void) requestRecording; // Sends a recording request to all participants of an audio or video chat. Recording will not start until all participants have agreed to allow recording. +- (void) stopRecording; // Ends recording of an audio or video chat. + +@end + +@interface iChatVideoChat : iChatAudioChat + +@property BOOL paused; // Is the chat paused? +@property BOOL showingFullScreen; // Is the chat being displayed in full screen mode? +@property BOOL showingLocalVideo; // Is the local video preview being displayed? + +- (void) takeSnapshot; // Takes a snapshot of a video chat and saves it to a desktop. + +@end + +// A file being sent or received +@interface iChatFileTransfer : iChatItem + +- (NSString *) id; // The guid for this file transfer +@property (copy, readonly) NSString *name; // The name of this file +@property (copy, readonly) NSURL *file; // The local path to this file transfer +@property (readonly) iChatDirection direction; // The direction in which this file is being sent +@property (copy, readonly) iChatService *service; // The service on which this file transfer is taking place +@property (copy, readonly) iChatBuddy *buddy; // The account participating in this file transfer +@property (readonly) BOOL secure; // Is this file transfer secure? +@property (readonly) NSInteger fileSize; // The total size in bytes of the completed file transfer +@property (readonly) NSInteger fileProgress; // The number of bytes that have been transferred +@property (readonly) iChatTransferStatus transferStatus; // The current status of this file transfer +@property (copy, readonly) NSDate *started; // The date that this file transfer started + +- (void) accept; // Accepts an incoming text, audio, or video chat invitation, or file transfer +- (void) decline; // Declines an incoming text, audio, or video chat invitation, or file transfer + +@end + diff -r 000000000000 -r d84d25d6cdbb mnemonicode-0.73/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mnemonicode-0.73/Makefile Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,12 @@ +sample_programs: mnencode mndecode + +mnencode: mnencode.o mnemonic.o mn_wordlist.o + +mndecode: mndecode.o mnemonic.o mn_wordlist.o + +mn_wordlist.o: mn_wordlist.c mnemonic.h + +mnemonic.o: mnemonic.c mnemonic.h + +clean: + rm -f *.o mnencode mndecode *~ diff -r 000000000000 -r d84d25d6cdbb mnemonicode-0.73/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mnemonicode-0.73/README Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,13 @@ +These routines implement a method for encoding binary data into a sequence +of words which can be spoken over the phone, for example, and converted +back to data on the other side. + +For more information see http://www.tothink.com/mnemonic + +mnemonic.h Header file +mnemonic.c Encoding/decoding and associated routines +mn_wordlist.c The word list itself +mnencode.c Sample program - encode data from stdin to stdout +mndecode.c Sample program - decode data from stdin to stdout + +Oren Tirosh diff -r 000000000000 -r d84d25d6cdbb mnemonicode-0.73/TODO --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mnemonicode-0.73/TODO Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,10 @@ +Improve the wordlist + + I am looking for comments on the wordlist from you. Yes, you :-) + +Soundalike matching + + I have given up on standard soundex techniques for this purpose. + I am working on an ad-hoc solution which is more-or-less tailored to + this specific list. + diff -r 000000000000 -r d84d25d6cdbb mnemonicode-0.73/mn_wordlist.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mnemonicode-0.73/mn_wordlist.c Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,302 @@ +/* mn_wordlist.c + Copyright (c) 2000 Oren Tirosh + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "mnemonic.h" + +const char *mn_wordlist_version = + " Wordlist ver 0.7 - EXPECT INCOMPATIBLE CHANGES"; + +const char *mn_words[MN_WORDS + 1] = { 0, + "academy", "acrobat", "active", "actor", "adam", "admiral", + "adrian", "africa", "agenda", "agent", "airline", "airport", + "aladdin", "alarm", "alaska", "albert", "albino", "album", + "alcohol", "alex", "algebra", "alibi", "alice", "alien", + "alpha", "alpine", "amadeus", "amanda", "amazon", "amber", + "america", "amigo", "analog", "anatomy", "angel", "animal", + "antenna", "antonio", "apollo", "april", "archive", "arctic", + "arizona", "arnold", "aroma", "arthur", "artist", "asia", + "aspect", "aspirin", "athena", "athlete", "atlas", "audio", + "august", "austria", "axiom", "aztec", "balance", "ballad", + "banana", "bandit", "banjo", "barcode", "baron", "basic", + "battery", "belgium", "berlin", "bermuda", "bernard", "bikini", + "binary", "bingo", "biology", "block", "blonde", "bonus", + "boris", "boston", "boxer", "brandy", "bravo", "brazil", + "bronze", "brown", "bruce", "bruno", "burger", "burma", + "cabinet", "cactus", "cafe", "cairo", "cake", "calypso", + "camel", "camera", "campus", "canada", "canal", "cannon", + "canoe", "cantina", "canvas", "canyon", "capital", "caramel", + "caravan", "carbon", "cargo", "carlo", "carol", "carpet", + "cartel", "casino", "castle", "castro", "catalog", "caviar", + "cecilia", "cement", "center", "century", "ceramic", "chamber", + "chance", "change", "chaos", "charlie", "charm", "charter", + "chef", "chemist", "cherry", "chess", "chicago", "chicken", + "chief", "china", "cigar", "cinema", "circus", "citizen", + "city", "clara", "classic", "claudia", "clean", "client", + "climax", "clinic", "clock", "club", "cobra", "coconut", + "cola", "collect", "colombo", "colony", "color", "combat", + "comedy", "comet", "command", "compact", "company", "complex", + "concept", "concert", "connect", "consul", "contact", "context", + "contour", "control", "convert", "copy", "corner", "corona", + "correct", "cosmos", "couple", "courage", "cowboy", "craft", + "crash", "credit", "cricket", "critic", "crown", "crystal", + "cuba", "culture", "dallas", "dance", "daniel", "david", + "decade", "decimal", "deliver", "delta", "deluxe", "demand", + "demo", "denmark", "derby", "design", "detect", "develop", + "diagram", "dialog", "diamond", "diana", "diego", "diesel", + "diet", "digital", "dilemma", "diploma", "direct", "disco", + "disney", "distant", "doctor", "dollar", "dominic", "domino", + "donald", "dragon", "drama", "dublin", "duet", "dynamic", + "east", "ecology", "economy", "edgar", "egypt", "elastic", + "elegant", "element", "elite", "elvis", "email", "energy", + "engine", "english", "episode", "equator", "escort", "ethnic", + "europe", "everest", "evident", "exact", "example", "exit", + "exotic", "export", "express", "extra", "fabric", "factor", + "falcon", "family", "fantasy", "fashion", "fiber", "fiction", + "fidel", "fiesta", "figure", "film", "filter", "final", + "finance", "finish", "finland", "flash", "florida", "flower", + "fluid", "flute", "focus", "ford", "forest", "formal", + "format", "formula", "fortune", "forum", "fragile", "france", + "frank", "friend", "frozen", "future", "gabriel", "galaxy", + "gallery", "gamma", "garage", "garden", "garlic", "gemini", + "general", "genetic", "genius", "germany", "global", "gloria", + "golf", "gondola", "gong", "good", "gordon", "gorilla", + "grand", "granite", "graph", "green", "group", "guide", + "guitar", "guru", "hand", "happy", "harbor", "harmony", + "harvard", "havana", "hawaii", "helena", "hello", "henry", + "hilton", "history", "horizon", "hotel", "human", "humor", + "icon", "idea", "igloo", "igor", "image", "impact", + "import", "index", "india", "indigo", "input", "insect", + "instant", "iris", "italian", "jacket", "jacob", "jaguar", + "janet", "japan", "jargon", "jazz", "jeep", "john", + "joker", "jordan", "jumbo", "june", "jungle", "junior", + "jupiter", "karate", "karma", "kayak", "kermit", "kilo", + "king", "koala", "korea", "labor", "lady", "lagoon", + "laptop", "laser", "latin", "lava", "lecture", "left", + "legal", "lemon", "level", "lexicon", "liberal", "libra", + "limbo", "limit", "linda", "linear", "lion", "liquid", + "liter", "little", "llama", "lobby", "lobster", "local", + "logic", "logo", "lola", "london", "lotus", "lucas", + "lunar", "machine", "macro", "madam", "madonna", "madrid", + "maestro", "magic", "magnet", "magnum", "major", "mama", + "mambo", "manager", "mango", "manila", "marco", "marina", + "market", "mars", "martin", "marvin", "master", "matrix", + "maximum", "media", "medical", "mega", "melody", "melon", + "memo", "mental", "mentor", "menu", "mercury", "message", + "metal", "meteor", "meter", "method", "metro", "mexico", + "miami", "micro", "million", "mineral", "minimum", "minus", + "minute", "miracle", "mirage", "miranda", "mister", "mixer", + "mobile", "model", "modem", "modern", "modular", "moment", + "monaco", "monica", "monitor", "mono", "monster", "montana", + "morgan", "motel", "motif", "motor", "mozart", "multi", + "museum", "music", "mustang", "natural", "neon", "nepal", + "neptune", "nerve", "neutral", "nevada", "news", "ninja", + "nirvana", "normal", "nova", "novel", "nuclear", "numeric", + "nylon", "oasis", "object", "observe", "ocean", "octopus", + "olivia", "olympic", "omega", "opera", "optic", "optimal", + "orange", "orbit", "organic", "orient", "origin", "orlando", + "oscar", "oxford", "oxygen", "ozone", "pablo", "pacific", + "pagoda", "palace", "pamela", "panama", "panda", "panel", + "panic", "paradox", "pardon", "paris", "parker", "parking", + "parody", "partner", "passage", "passive", "pasta", "pastel", + "patent", "patriot", "patrol", "patron", "pegasus", "pelican", + "penguin", "pepper", "percent", "perfect", "perfume", "period", + "permit", "person", "peru", "phone", "photo", "piano", + "picasso", "picnic", "picture", "pigment", "pilgrim", "pilot", + "pirate", "pixel", "pizza", "planet", "plasma", "plaster", + "plastic", "plaza", "pocket", "poem", "poetic", "poker", + "polaris", "police", "politic", "polo", "polygon", "pony", + "popcorn", "popular", "postage", "postal", "precise", "prefix", + "premium", "present", "price", "prince", "printer", "prism", + "private", "product", "profile", "program", "project", "protect", + "proton", "public", "pulse", "puma", "pyramid", "queen", + "radar", "radio", "random", "rapid", "rebel", "record", + "recycle", "reflex", "reform", "regard", "regular", "relax", + "report", "reptile", "reverse", "ricardo", "ringo", "ritual", + "robert", "robot", "rocket", "rodeo", "romeo", "royal", + "russian", "safari", "salad", "salami", "salmon", "salon", + "salute", "samba", "sandra", "santana", "sardine", "school", + "screen", "script", "second", "secret", "section", "segment", + "select", "seminar", "senator", "senior", "sensor", "serial", + "service", "sheriff", "shock", "sierra", "signal", "silicon", + "silver", "similar", "simon", "single", "siren", "slogan", + "social", "soda", "solar", "solid", "solo", "sonic", + "soviet", "special", "speed", "spiral", "spirit", "sport", + "static", "station", "status", "stereo", "stone", "stop", + "street", "strong", "student", "studio", "style", "subject", + "sultan", "super", "susan", "sushi", "suzuki", "switch", + "symbol", "system", "tactic", "tahiti", "talent", "tango", + "tarzan", "taxi", "telex", "tempo", "tennis", "texas", + "textile", "theory", "thermos", "tiger", "titanic", "tokyo", + "tomato", "topic", "tornado", "toronto", "torpedo", "total", + "totem", "tourist", "tractor", "traffic", "transit", "trapeze", + "travel", "tribal", "trick", "trident", "trilogy", "tripod", + "tropic", "trumpet", "tulip", "tuna", "turbo", "twist", + "ultra", "uniform", "union", "uranium", "vacuum", "valid", + "vampire", "vanilla", "vatican", "velvet", "ventura", "venus", + "vertigo", "veteran", "victor", "video", "vienna", "viking", + "village", "vincent", "violet", "violin", "virtual", "virus", + "visa", "vision", "visitor", "visual", "vitamin", "viva", + "vocal", "vodka", "volcano", "voltage", "volume", "voyage", + "water", "weekend", "welcome", "western", "window", "winter", + "wizard", "wolf", "world", "xray", "yankee", "yoga", + "yogurt", "yoyo", "zebra", "zero", "zigzag", "zipper", + "zodiac", "zoom", "abraham", "action", "address", "alabama", + "alfred", "almond", "ammonia", "analyze", "annual", "answer", + "apple", "arena", "armada", "arsenal", "atlanta", "atomic", + "avenue", "average", "bagel", "baker", "ballet", "bambino", + "bamboo", "barbara", "basket", "bazaar", "benefit", "bicycle", + "bishop", "blitz", "bonjour", "bottle", "bridge", "british", + "brother", "brush", "budget", "cabaret", "cadet", "candle", + "capitan", "capsule", "career", "cartoon", "channel", "chapter", + "cheese", "circle", "cobalt", "cockpit", "college", "compass", + "comrade", "condor", "crimson", "cyclone", "darwin", "declare", + "degree", "delete", "delphi", "denver", "desert", "divide", + "dolby", "domain", "domingo", "double", "drink", "driver", + "eagle", "earth", "echo", "eclipse", "editor", "educate", + "edward", "effect", "electra", "emerald", "emotion", "empire", + "empty", "escape", "eternal", "evening", "exhibit", "expand", + "explore", "extreme", "ferrari", "first", "flag", "folio", + "forget", "forward", "freedom", "fresh", "friday", "fuji", + "galileo", "garcia", "genesis", "gold", "gravity", "habitat", + "hamlet", "harlem", "helium", "holiday", "house", "hunter", + "ibiza", "iceberg", "imagine", "infant", "isotope", "jackson", + "jamaica", "jasmine", "java", "jessica", "judo", "kitchen", + "lazarus", "letter", "license", "lithium", "loyal", "lucky", + "magenta", "mailbox", "manual", "marble", "mary", "maxwell", + "mayor", "milk", "monarch", "monday", "money", "morning", + "mother", "mystery", "native", "nectar", "nelson", "network", + "next", "nikita", "nobel", "nobody", "nominal", "norway", + "nothing", "number", "october", "office", "oliver", "opinion", + "option", "order", "outside", "package", "pancake", "pandora", + "panther", "papa", "patient", "pattern", "pedro", "pencil", + "people", "phantom", "philips", "pioneer", "pluto", "podium", + "portal", "potato", "prize", "process", "protein", "proxy", + "pump", "pupil", "python", "quality", "quarter", "quiet", + "rabbit", "radical", "radius", "rainbow", "ralph", "ramirez", + "ravioli", "raymond", "respect", "respond", "result", "resume", + "retro", "richard", "right", "risk", "river", "roger", + "roman", "rondo", "sabrina", "salary", "salsa", "sample", + "samuel", "saturn", "savage", "scarlet", "scoop", "scorpio", + "scratch", "scroll", "sector", "serpent", "shadow", "shampoo", + "sharon", "sharp", "short", "shrink", "silence", "silk", + "simple", "slang", "smart", "smoke", "snake", "society", + "sonar", "sonata", "soprano", "source", "sparta", "sphere", + "spider", "sponsor", "spring", "acid", "adios", "agatha", + "alamo", "alert", "almanac", "aloha", "andrea", "anita", + "arcade", "aurora", "avalon", "baby", "baggage", "balloon", + "bank", "basil", "begin", "biscuit", "blue", "bombay", + "brain", "brenda", "brigade", "cable", "carmen", "cello", + "celtic", "chariot", "chrome", "citrus", "civil", "cloud", + "common", "compare", "cool", "copper", "coral", "crater", + "cubic", "cupid", "cycle", "depend", "door", "dream", + "dynasty", "edison", "edition", "enigma", "equal", "eric", + "event", "evita", "exodus", "extend", "famous", "farmer", + "food", "fossil", "frog", "fruit", "geneva", "gentle", + "george", "giant", "gilbert", "gossip", "gram", "greek", + "grille", "hammer", "harvest", "hazard", "heaven", "herbert", + "heroic", "hexagon", "husband", "immune", "inca", "inch", + "initial", "isabel", "ivory", "jason", "jerome", "joel", + "joshua", "journal", "judge", "juliet", "jump", "justice", + "kimono", "kinetic", "leonid", "lima", "maze", "medusa", + "member", "memphis", "michael", "miguel", "milan", "mile", + "miller", "mimic", "mimosa", "mission", "monkey", "moral", + "moses", "mouse", "nancy", "natasha", "nebula", "nickel", + "nina", "noise", "orchid", "oregano", "origami", "orinoco", + "orion", "othello", "paper", "paprika", "prelude", "prepare", + "pretend", "profit", "promise", "provide", "puzzle", "remote", + "repair", "reply", "rival", "riviera", "robin", "rose", + "rover", "rudolf", "saga", "sahara", "scholar", "shelter", + "ship", "shoe", "sigma", "sister", "sleep", "smile", + "spain", "spark", "split", "spray", "square", "stadium", + "star", "storm", "story", "strange", "stretch", "stuart", + "subway", "sugar", "sulfur", "summer", "survive", "sweet", + "swim", "table", "taboo", "target", "teacher", "telecom", + "temple", "tibet", "ticket", "tina", "today", "toga", + "tommy", "tower", "trivial", "tunnel", "turtle", "twin", + "uncle", "unicorn", "unique", "update", "valery", "vega", + "version", "voodoo", "warning", "william", "wonder", "year", + "yellow", "young", "absent", "absorb", "accent", "alfonso", + "alias", "ambient", "andy", "anvil", "appear", "apropos", + "archer", "ariel", "armor", "arrow", "austin", "avatar", + "axis", "baboon", "bahama", "bali", "balsa", "bazooka", + "beach", "beast", "beatles", "beauty", "before", "benny", + "betty", "between", "beyond", "billy", "bison", "blast", + "bless", "bogart", "bonanza", "book", "border", "brave", + "bread", "break", "broken", "bucket", "buenos", "buffalo", + "bundle", "button", "buzzer", "byte", "caesar", "camilla", + "canary", "candid", "carrot", "cave", "chant", "child", + "choice", "chris", "cipher", "clarion", "clark", "clever", + "cliff", "clone", "conan", "conduct", "congo", "content", + "costume", "cotton", "cover", "crack", "current", "danube", + "data", "decide", "desire", "detail", "dexter", "dinner", + "dispute", "donor", "druid", "drum", "easy", "eddie", + "enjoy", "enrico", "epoxy", "erosion", "except", "exile", + "explain", "fame", "fast", "father", "felix", "field", + "fiona", "fire", "fish", "flame", "flex", "flipper", + "float", "flood", "floor", "forbid", "forever", "fractal", + "frame", "freddie", "front", "fuel", "gallop", "game", + "garbo", "gate", "gibson", "ginger", "giraffe", "gizmo", + "glass", "goblin", "gopher", "grace", "gray", "gregory", + "grid", "griffin", "ground", "guest", "gustav", "gyro", + "hair", "halt", "harris", "heart", "heavy", "herman", + "hippie", "hobby", "honey", "hope", "horse", "hostel", + "hydro", "imitate", "info", "ingrid", "inside", "invent", + "invest", "invite", "iron", "ivan", "james", "jester", + "jimmy", "join", "joseph", "juice", "julius", "july", + "justin", "kansas", "karl", "kevin", "kiwi", "ladder", + "lake", "laura", "learn", "legacy", "legend", "lesson", + "life", "light", "list", "locate", "lopez", "lorenzo", + "love", "lunch", "malta", "mammal", "margo", "marion", + "mask", "match", "mayday", "meaning", "mercy", "middle", + "mike", "mirror", "modest", "morph", "morris", "nadia", + "nato", "navy", "needle", "neuron", "never", "newton", + "nice", "night", "nissan", "nitro", "nixon", "north", + "oberon", "octavia", "ohio", "olga", "open", "opus", + "orca", "oval", "owner", "page", "paint", "palma", + "parade", "parent", "parole", "paul", "peace", "pearl", + "perform", "phoenix", "phrase", "pierre", "pinball", "place", + "plate", "plato", "plume", "pogo", "point", "polite", + "polka", "poncho", "powder", "prague", "press", "presto", + "pretty", "prime", "promo", "quasi", "quest", "quick", + "quiz", "quota", "race", "rachel", "raja", "ranger", + "region", "remark", "rent", "reward", "rhino", "ribbon", + "rider", "road", "rodent", "round", "rubber", "ruby", + "rufus", "sabine", "saddle", "sailor", "saint", "salt", + "satire", "scale", "scuba", "season", "secure", "shake", + "shallow", "shannon", "shave", "shelf", "sherman", "shine", + "shirt", "side", "sinatra", "sincere", "size", "slalom", + "slow", "small", "snow", "sofia", "song", "sound", + "south", "speech", "spell", "spend", "spoon", "stage", + "stamp", "stand", "state", "stella", "stick", "sting", + "stock", "store", "sunday", "sunset", "support", "sweden", + "swing", "tape", "think", "thomas", "tictac", "time", + "toast", "tobacco", "tonight", "torch", "torso", "touch", + "toyota", "trade", "tribune", "trinity", "triton", "truck", + "trust", "type", "under", "unit", "urban", "urgent", + "user", "value", "vendor", "venice", "verona", "vibrate", + "virgo", "visible", "vista", "vital", "voice", "vortex", + "waiter", "watch", "wave", "weather", "wedding", "wheel", + "whiskey", "wisdom", "deal", "null", "nurse", "quebec", + "reserve", "reunion", "roof", "singer", "verbal", "amen", + "ego", "fax", "jet", "job", "rio", "ski", + "yes" +}; diff -r 000000000000 -r d84d25d6cdbb mnemonicode-0.73/mndecode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mnemonicode-0.73/mndecode.c Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,21 @@ +#include +#include "mnemonic.h" + +main () +{ + char buf[0x90000]; + mn_byte outbuf[0x10000]; + int buflen; + int n; + + buflen = fread (buf, 1, sizeof buf - 1, stdin); + buf[buflen] = 0; + + n = mn_decode (buf, outbuf, sizeof outbuf); + if (n < 0) + fprintf (stderr, "mn_decode result %d\n", n); + else + fwrite (outbuf, 1, n, stdout); + + return 0; +} diff -r 000000000000 -r d84d25d6cdbb mnemonicode-0.73/mnemonic.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mnemonicode-0.73/mnemonic.c Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,467 @@ +/* mnemonic.c + + Copyright (c) 2000 Oren Tirosh + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include "mnemonic.h" +#include + + +/* + * mn_words_required + * + * Description: + * Calculate the number of words required to encode data using mnemonic + * encoding. + * + * Parameters: + * size - Size in bytes of data to be encoded + * + * Return value: + * number of words required for the encoding + */ + +int +mn_words_required (int size) +{ + return ((size + 1) * 3) / 4; +} + + +/* + * mn_encode_word_index + * + * Description: + * Perform one step of encoding binary data into words. Returns word index. + * + * Parameters: + * src - Pointer to data buffer to encode + * srcsize - Size in bytes of data to encode + * n - Sequence number of word to encode + * 0 <= n < mn_words_required(srcsize) + * + * Return value: + * 0 - no more words to encode / n is out of range + * 1..MN_WORDS - word index. May be used as index to the mn_words[] array + */ + +mn_index mn_encode_word_index (void *src, int srcsize, int n) +{ + mn_word32 x = 0; /* Temporary for MN_BASE arithmetic */ + int offset; /* Offset into src */ + int remaining; /* Octets remaining to end of src */ + int extra = 0; /* Index 7 extra words for 24 bit data */ + int i; + + if (n < 0 || n >= mn_words_required (srcsize)) + return 0; /* word out of range */ + offset = (n / 3) * 4; /* byte offset into src */ + remaining = srcsize - offset; + if (remaining <= 0) + return 0; + if (remaining >= 4) + remaining = 4; + for (i = 0; i < remaining; i++) + x |= ((mn_byte *) src)[offset + i] << (i * 8); /* endianness-agnostic */ + + switch (n % 3) + { + case 2: /* Third word of group */ + if (remaining == 3) /* special case for 24 bits */ + extra = MN_BASE; /* use one of the 7 3-letter words */ + x /= (MN_BASE * MN_BASE); + break; + case 1: /* Second word of group */ + x /= MN_BASE; + } + return x % MN_BASE + extra + 1; +} + + +/* + * mn_encode_word + * + * Description: + * Perform one step of encoding binary data into words. Returns pointer + * to word. + * + * Parameters: + * src - Pointer to data buffer to encode + * srcsize - Size of data to encode in bytes + * n - Sequence number of word to encode. + * 0 <= n < mn_words_required(srcsize) + * + * Return value: + * NULL - no more words to encode / n is out of range + * valid pointer - pointer to null-terminated lowercase word. length<=7 + */ + +const char * +mn_encode_word (void *src, int srcsize, int n) +{ + return mn_words[mn_encode_word_index (src, srcsize, n)]; +} + + +/* + * isletter + * Utility function - returns nonzero if character c is an ASCII letter. + */ + +static int +isletter (char c) +{ + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); +} + +/* + * mn_next_word_index + * + * Description: + * Perform one step of decoding a null-terminated buffer into word indices. + * A word is defined as a sequence of letter character separated by one + * or more non-letter separator characters. + * + * Parameters: + * ptr - Pointer to a pointer to the next character in the buffer. + * *ptr is modified by the function; see Return Value below. + * + * Return value: + * 0 - If *ptr==0 (points to the null at the end of the buffer) no more + * words were found in the buffer. Otherwise *ptr points to beginning + * of an unrecognized word. + * >0 - index of word found, suitable for decoding with mn_decode_word_index + * or comparison to values returned from mn_encode_index. *ptr points + * to first character of next word or to terminating null. + */ + +mn_index +mn_next_word_index (char **ptr) +{ + char *wordstart; + char wordbuf[MN_WORD_BUFLEN]; + int i = 0; + char c; + mn_index idx; + + while (**ptr && !isletter (**ptr)) /* skip separator chars */ + (*ptr)++; + wordstart = *ptr; /* save for error reporting */ + while (**ptr && isletter (**ptr) && i < MN_WORD_BUFLEN - 1) + { + c = *(*ptr)++; + if (c >= 'A' && c <= 'Z') + c += 'a' - 'A'; /* convert to lowercase */ + wordbuf[i++] = c; + } + wordbuf[i] = '\0'; + while (**ptr && isletter (**ptr)) /* skip tail of long words */ + (*ptr)++; + while (**ptr && !isletter (**ptr)) /* skip separators */ + (*ptr)++; + + if (wordbuf[0] == '\0') + return 0; /* EOF, no word found */ + + for (idx = 1; idx <= MN_WORDS; idx++) + { + if (!strcmp (wordbuf, mn_words[idx])) + return idx; + /* FIXME: some fancy code should go here + to accept misspellings and soundalikes. + (replacing the linear search would also be nice) */ + } + *ptr = wordstart; + return 0; /* not found */ +} + + +/* + * mn_decode_word_index + * + * Description: + * Perform one step of decoding a sequence of words into binary data. + * + * Parameters: + * index - Index of word, e.g. return value of mn_next_word_index. Use + * the value MN_EOF(=0) to signal the end of input. + * dest - Points to buffer to receive decoded binary result. + * destsize - Size of buffer + * offset - Pointer to an integer offset into the destination buffer for + * next data byte. Initialize *offset to 0 before first call to + * function. Modified by function and may be used as an + * indication for the amount of data actually decoded. + * + * Return value: + * The return value indicates the status of the decoding function. It is + * ok to ignore this value on all calls to the function except the last + * one (with index=MN_EOF). Any errors encountered will be reported on. + * the last call. The error code is also returned in *offset (negative + * values indicate error). + * + * MN_OK (==0) + * for index!=MN_EOF a return value of MN_OK means that + * decoding has been successful so far. + * for index==MN_EOF a return value of MN_OK means that decoding + * of the entire buffer has been successful and the decoder is in + * a valid state for the end of the message. A total of *offset + * valid decoded bytes is in the buffer. + * MN_EREM + * returned on MN_EOF when an unaccounted arithmetic remainder is + * in the decoder. Most likely indicates a truncated word sequence. + * MN_EOVERRUN + * Not enough room in buffer for decoded data. + * MN_EOVERRUN24 + * Returned when decoding of data is attempted after decoding one + * of the 7 words reserved for 24 bit remainders at the end of the + * message. Probably indicates a garbled messages. + * MN_EINDEX + * Bad input index. Naturally this should not happen when using + * the result of mn_next_word_index. + * MN_EINDEX24 + * Returned when one of the 7 words reserved for 24 bit remainders + * is received at an offset inappropriate for a 24 bit remainder. + * MN_EENCODING + * Indicates an overflow in MN_BASE arithmetic. Approximately 0.09% + * of the 3 word combinations are unused and will generate this error. + */ + +int +mn_decode_word_index (mn_index index, void *dest, int destsize, int *offset) +{ + mn_word32 x; /* Temporary for MN_BASE arithmetic */ + int groupofs; + int i; + + if (*offset < 0) /* Error from previous call? report it */ + return *offset; + + if (index < 0 || index > MN_WORDS) /* Word index out of range */ + { + *offset = MN_EINDEX; + return *offset; + } + + if (*offset > destsize) /* out of range? */ + { + *offset = MN_EOVERRUN; + return *offset; + } + + if (index > MN_BASE && *offset % 4 != 2) + { /* Unexpected 24 bit remainder word */ + *offset = MN_EINDEX24; + return *offset; + } + + groupofs = *offset & ~3; /* Offset of 4 byte group containing offet */ + x = 0; + for (i = 0; i < 4; i++) + if (groupofs + i < destsize) /* Ignore any bytes outside buffer */ + x |= ((mn_byte *) dest)[groupofs + i] << (i * 8); /* assemble number */ + + if (index == MN_EOF) /* Got EOF signal */ + { + switch (*offset % 4) + { + case 3: /* group was three words and the last */ + return MN_OK; /* word was a 24 bit remainder */ + case 2: /* last group has two words */ + if (x <= 0xFFFF) /* should encode 16 bit data */ + return MN_OK; + else + { + *offset = MN_EREM; + return *offset; + } + case 1: /* last group has just one word */ + if (x <= 0xFF) /* should encode 8 bits */ + return MN_OK; + else + { + *offset = MN_EREM; + return *offset; + } + + case 0: /* last group was full 3 words */ + return MN_OK; + } + } + if (*offset == destsize) /* At EOF but didn't get MN_EOF */ + { + *offset = MN_EOVERRUN; + return *offset; + } + + index--; /* 1 based to 0 based index */ + + switch (*offset % 4) + { + case 3: /* Got data past 24 bit remainder */ + *offset = MN_EOVERRUN24; + return *offset; + case 2: + if (index >= MN_BASE) + { /* 24 bit remainder */ + x += (index - MN_BASE) * MN_BASE * MN_BASE; + (*offset)++; /* *offset%4 == 3 for next time */ + } + else + { /* catch invalid encodings */ + if (index >= 1625 || (index == 1624 && x > 1312671)) + { + *offset = MN_EENCODING; + return *offset; + } + x += index * MN_BASE * MN_BASE; + (*offset) += 2; /* *offset%4 == 0 for next time */ + } + break; + case 1: + x += index * MN_BASE; + (*offset)++; + break; + case 0: + x = index; + (*offset)++; + break; + } + + for (i = 0; i < 4; i++) + if (groupofs + i < destsize) /* Don't step outside the buffer */ + { + ((mn_byte *) dest)[groupofs + i] = (mn_byte) x % 256; + x /= 256; + } + return MN_OK; +} + +/* + * mn_encode + * + * Description: + * Encode a binary data buffer into a null-terminated sequence of words. + * The word separators are taken from the format string. + * + * Parameters: + * src - Pointer to the beginning of the binary data buffer. + * srcsize - Size in bytes of binary data buffer + * dest - Pointer to the beginning of a character buffer + * destsize - Size in characters of character buffer + * format - Null-terminated string describing the output format. + * In the format string any letter or sequence of letters + * acts as a placeholder for the encoded words. The word + * placeholders are separated by one or more non-letter + * characters. When the encoder reaches the end of the + * format string it starts reading it again. + * For sample formats see MN_F* constants in mnemonic.h + * If format is empty or NULL the format MN_FDEFAULT + * is used. + * + * Return value: + * MN_OK(=0) + * Encoding was successful. + * MN_EOVERRUN + * Output size exceeds size of destination buffer + * MN_EFORMAT + * Invalid format string. This function enforces formats which + * will result in a string which can be successfully decoded by + * the mn_decode function. + */ + +int +mn_encode (void *src, int srcsize, char *dest, int destsize, char *format) +{ + int n; + char *fmt; + char *destend = dest + destsize; + const char *word; + + if (format == 0 || format[0] == '\0') + format = MN_FDEFAULT; + fmt = format; + for (n = 0; n < mn_words_required (srcsize); n++) + { + while (dest < destend && *fmt != '\0' && !isletter (*fmt)) + *dest++ = *fmt++; + if (dest >= destend) + return MN_EOVERRUN; + if (*fmt == '\0') + { + if (isletter (fmt[-1]) && isletter (format[0])) + return MN_EFORMAT; + fmt = format; + while (dest < destend && *fmt != '\0' && !isletter (*fmt)) + *dest++ = *fmt++; + if (!isletter (*fmt)) + return MN_EFORMAT; + } + word = mn_encode_word (src, srcsize, n); + if (word == 0) + return MN_EOVERRUN; /* shouldn't happen, actually */ + + while (isletter (*fmt)) + fmt++; + while (dest < destend && *word != '\0') + *dest++ = *word++; + } + if (dest < destend) + *dest++ = '\0'; + else + return MN_EOVERRUN; + return MN_OK; +} + +/* + * mn_decode + * + * Description: + * Decode a text representation in null-terminated character buffer src to + * binary buffer dest. + * + * Parameters: + * src - Pointer to null-terminated character buffer + * dest - Pointer to beginning of destination buffer + * destsize - Size in bytes of destination buffer + * + * Return value: + * This function may return all the value returned by mn_decode_word_index + * plus the following result code: + * + * MN_EWORD - Unrecognized word. + */ + +int +mn_decode (char *src, void *dest, int destsize) +{ + mn_index index; + int offset = 0; + + while ((index = mn_next_word_index (&src)) != 0) + { + if (index == 0 && *src != 0) + return MN_EWORD; + (void) mn_decode_word_index (index, dest, destsize, &offset); + } + (void) mn_decode_word_index (MN_EOF, dest, destsize, &offset); + return offset; +} diff -r 000000000000 -r d84d25d6cdbb mnemonicode-0.73/mnemonic.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mnemonicode-0.73/mnemonic.h Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,68 @@ +/* mnemonic.h + + Copyright (c) 2000 Oren Tirosh + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#define MN_BASE 1626 /* cubic root of 2^32, rounded up */ +#define MN_REMAINDER 7 /* extra words for 24 bit remainders */ +#define MN_WORDS (MN_BASE+MN_REMAINDER) /* total number of words */ +#define MN_WORD_BUFLEN 25 /* size for a word buffer+headroom */ + +#define MN_EOF 0 /* signal end to mn_decode_word_index */ + +/* result codes */ +#define MN_OK 0 /* decoding ok */ +#define MN_EREM -1 /* unexpected arithmetic remainder */ +#define MN_EOVERRUN -2 /* output buffer overrun */ +#define MN_EOVERRUN24 -3 /* data after 24 bit remainder */ +#define MN_EINDEX -4 /* bad word index */ +#define MN_EINDEX24 -5 /* unexpected 24 bit remainder word */ +#define MN_EENCODING -6 /* invalid arithmetic encoding */ +#define MN_EWORD -7 /* unrecognized word */ +#define MN_EFORMAT -8 /* bad format string */ + +/* Sample formats for mn_encode */ +#define MN_FDEFAULT "x-x-x--" +#define MN_F64BITSPERLINE " x-x-x--x-x-x\n" +#define MN_F96BITSPERLINE " x-x-x--x-x-x--x-x-x\n" +#define MN_F128BITSPERLINE " x-x-x--x-x-x--x-x-x--x-x-x\n" +/* Note that the last format does not fit in a standard 80 character line */ + +typedef unsigned char mn_byte; /* 8 bit quantity */ +typedef unsigned long mn_word32; /* temporary value, at least 32 bits */ +typedef unsigned int mn_index; /* index into wordlist */ + +extern const char *mn_words[]; /* the word list itself */ +extern const char *mn_wordlist_version; /* version notice string */ + +int mn_decode (char *src, void *dest, int destsize); +int mn_encode (void *src , int srcsize, + char *dest, int destsize, char *format); + +int mn_words_required (int size); +mn_index mn_encode_word_index (void *src, int srcsize, int n); +const char* mn_encode_word (void *src, int srcsize, int n); +mn_index mn_next_word_index (char **ptr); +int mn_decode_word_index (mn_index index, void *dest, + int destsize, int *offset); + + diff -r 000000000000 -r d84d25d6cdbb mnemonicode-0.73/mnencode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mnemonicode-0.73/mnencode.c Sat Mar 08 21:04:41 2008 -0800 @@ -0,0 +1,22 @@ +#include +#include "mnemonic.h" + +main () +{ + mn_byte buf[0x10000]; + char outbuf[0x90000]; + int buflen; + int n; + + fprintf (stderr, "%s\n", mn_wordlist_version); + + buflen = fread (buf, 1, sizeof (buf), stdin); + n = mn_encode (buf, buflen, outbuf, sizeof outbuf, MN_F64BITSPERLINE); + if (n == 0) + fwrite (outbuf, 1, strlen (outbuf), stdout); + else + fprintf (stderr, "mn_encode error %d\n", n); + putchar ('\n'); + + return 0; +}