Initial checkin.
authorJens Alfke <jens@mooseyard.com>
Sat Mar 08 21:04:41 2008 -0800 (2008-03-08)
changeset 0d84d25d6cdbb
child 1 e55a17cdabd2
Initial checkin.
.hgignore
Base64.h
Base64.m
CollectionUtils.h
CollectionUtils.m
ConcurrentOperation.h
ConcurrentOperation.m
FileAlias.h
FileAlias.m
FileUtils.h
FileUtils.m
GraphicsUtils.h
GraphicsUtils.m
IChatUtils.h
IChatUtils.m
KVUtils.h
KVUtils.m
Logging.h
Logging.m
Target.h
Target.m
Test.h
Test.m
TimeIntervalFormatter.h
TimeIntervalFormatter.m
ValueArray.h
ValueArray.m
With.h
With.m
iChatBridge.h
mnemonicode-0.73/Makefile
mnemonicode-0.73/README
mnemonicode-0.73/TODO
mnemonicode-0.73/mn_wordlist.c
mnemonicode-0.73/mndecode.c
mnemonicode-0.73/mnemonic.c
mnemonicode-0.73/mnemonic.h
mnemonicode-0.73/mnencode.c
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Sat Mar 08 21:04:41 2008 -0800
     1.3 @@ -0,0 +1,8 @@
     1.4 +syntax: glob
     1.5 +.DS_Store
     1.6 +build
     1.7 +.svn
     1.8 +*.pbxuser
     1.9 +*.perspectivev3
    1.10 +*.mpkg
    1.11 +*.framework
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/Base64.h	Sat Mar 08 21:04:41 2008 -0800
     2.3 @@ -0,0 +1,23 @@
     2.4 +//
     2.5 +//  Base64.h
     2.6 +//  MYUtilities
     2.7 +//
     2.8 +//  Created by Jens Alfke on 1/27/08.
     2.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
    2.10 +//
    2.11 +
    2.12 +#import <Cocoa/Cocoa.h>
    2.13 +
    2.14 +
    2.15 +@interface NSData (Base64)
    2.16 +
    2.17 +- (NSString *)base64String;
    2.18 +- (NSString *)base64StringWithNewlines:(BOOL)encodeWithNewlines;
    2.19 +
    2.20 +- (NSData *)decodeBase64;
    2.21 +- (NSData *)decodeBase64WithNewLines:(BOOL)encodedWithNewlines;
    2.22 +
    2.23 +- (NSString *)hexString;
    2.24 +- (NSString *)hexDump;
    2.25 +
    2.26 +@end
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/Base64.m	Sat Mar 08 21:04:41 2008 -0800
     3.3 @@ -0,0 +1,165 @@
     3.4 +//
     3.5 +//  Base64.m
     3.6 +//  MYUtilities
     3.7 +//
     3.8 +//  Created by Jens Alfke on 1/27/08.
     3.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
    3.10 +//
    3.11 +//  Adapted from SSCrypto.m by Ed Silva;
    3.12 +//  Copyright (c) 2003-2006 Septicus Software. All rights reserved.
    3.13 +//
    3.14 +
    3.15 +#import "Base64.h"
    3.16 +#import <openssl/bio.h>
    3.17 +#import <openssl/evp.h>
    3.18 +
    3.19 +
    3.20 +@implementation NSData (Base64)
    3.21 +
    3.22 +
    3.23 +/**
    3.24 + * Encodes the current data in base64, and creates and returns an NSString from the result.
    3.25 + * This is the same as piping data through "... | openssl enc -base64" on the command line.
    3.26 + *
    3.27 + * Code courtesy of DaveDribin (http://www.dribin.org/dave/)
    3.28 + * Taken from http://www.cocoadev.com/index.pl?BaseSixtyFour
    3.29 + **/
    3.30 +- (NSString *)base64String
    3.31 +{
    3.32 +    return [self base64StringWithNewlines: YES];
    3.33 +}
    3.34 +
    3.35 +/**
    3.36 + * Encodes the current data in base64, and creates and returns an NSString from the result.
    3.37 + * This is the same as piping data through "... | openssl enc -base64" on the command line.
    3.38 + *
    3.39 + * Code courtesy of DaveDribin (http://www.dribin.org/dave/)
    3.40 + * Taken from http://www.cocoadev.com/index.pl?BaseSixtyFour
    3.41 + **/
    3.42 +- (NSString *)base64StringWithNewlines:(BOOL)encodeWithNewlines
    3.43 +{
    3.44 +    // Create a memory buffer which will contain the Base64 encoded string
    3.45 +    BIO * mem = BIO_new(BIO_s_mem());
    3.46 +    
    3.47 +    // Push on a Base64 filter so that writing to the buffer encodes the data
    3.48 +    BIO * b64 = BIO_new(BIO_f_base64());
    3.49 +    if (!encodeWithNewlines)
    3.50 +        BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
    3.51 +    mem = BIO_push(b64, mem);
    3.52 +    
    3.53 +    // Encode all the data
    3.54 +    BIO_write(mem, [self bytes], [self length]);
    3.55 +    BIO_flush(mem);
    3.56 +    
    3.57 +    // Create a new string from the data in the memory buffer
    3.58 +    char * base64Pointer;
    3.59 +    long base64Length = BIO_get_mem_data(mem, &base64Pointer);
    3.60 +    NSString * base64String = [NSString stringWithCString:base64Pointer length:base64Length];
    3.61 +    
    3.62 +    // Clean up and go home
    3.63 +    BIO_free_all(mem);
    3.64 +    return base64String;
    3.65 +}
    3.66 +
    3.67 +- (NSData *)decodeBase64
    3.68 +{
    3.69 +    return [self decodeBase64WithNewLines:YES];
    3.70 +}
    3.71 +
    3.72 +- (NSData *)decodeBase64WithNewLines:(BOOL)encodedWithNewlines
    3.73 +{
    3.74 +    // Create a memory buffer containing Base64 encoded string data
    3.75 +    BIO * mem = BIO_new_mem_buf((void *) [self bytes], [self length]);
    3.76 +    
    3.77 +    // Push a Base64 filter so that reading from the buffer decodes it
    3.78 +    BIO * b64 = BIO_new(BIO_f_base64());
    3.79 +    if (!encodedWithNewlines)
    3.80 +        BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
    3.81 +    mem = BIO_push(b64, mem);
    3.82 +    
    3.83 +    // Decode into an NSMutableData
    3.84 +    NSMutableData * data = [NSMutableData data];
    3.85 +    char inbuf[512];
    3.86 +    int inlen;
    3.87 +    while ((inlen = BIO_read(mem, inbuf, sizeof(inbuf))) > 0)
    3.88 +        [data appendBytes: inbuf length: inlen];
    3.89 +    
    3.90 +    // Clean up and go home
    3.91 +    BIO_free_all(mem);
    3.92 +    return data;
    3.93 +}
    3.94 +
    3.95 +
    3.96 +- (NSString *)hexString
    3.97 +{
    3.98 +    const UInt8 *bytes = self.bytes;
    3.99 +    NSUInteger length = self.length;
   3.100 +    char out[2*length+1];
   3.101 +    char *dst = &out[0];
   3.102 +    for( int i=0; i<length; i+=1 )
   3.103 +        dst += sprintf(dst,"%02X",*(bytes++));
   3.104 +    return [[[NSString alloc] initWithBytes: out length: 2*length encoding: NSASCIIStringEncoding]
   3.105 +            autorelease];
   3.106 +}
   3.107 +
   3.108 +- (NSString *)hexDump
   3.109 +{
   3.110 +    NSMutableString *ret=[NSMutableString stringWithCapacity:[self length]*2];
   3.111 +    /* dumps size bytes of *data to string. Looks like:
   3.112 +     * [0000] 75 6E 6B 6E 6F 77 6E 20
   3.113 +     *                  30 FF 00 00 00 00 39 00 unknown 0.....9.
   3.114 +     * (in a single line of course)
   3.115 +     */
   3.116 +    unsigned int size= [self length];
   3.117 +    const unsigned char *p = [self bytes];
   3.118 +    unsigned char c;
   3.119 +    int n;
   3.120 +    char bytestr[4] = {0};
   3.121 +    char addrstr[10] = {0};
   3.122 +    char hexstr[ 16*3 + 5] = {0};
   3.123 +    char charstr[16*1 + 5] = {0};
   3.124 +    for(n=1;n<=size;n++) {
   3.125 +        if (n%16 == 1) {
   3.126 +            /* store address for this line */
   3.127 +            snprintf(addrstr, sizeof(addrstr), "%.4x",
   3.128 +                     ((unsigned int)p-(unsigned int)self) );
   3.129 +        }
   3.130 +        
   3.131 +        c = *p;
   3.132 +        if (isalnum(c) == 0) {
   3.133 +            c = '.';
   3.134 +        }
   3.135 +        
   3.136 +        /* store hex str (for left side) */
   3.137 +        snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
   3.138 +        strncat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1);
   3.139 +        
   3.140 +        /* store char str (for right side) */
   3.141 +        snprintf(bytestr, sizeof(bytestr), "%c", c);
   3.142 +        strncat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1);
   3.143 +        
   3.144 +        if(n%16 == 0) {
   3.145 +            /* line completed */
   3.146 +            //printf("[%4.4s]   %-50.50s  %s\n", addrstr, hexstr, charstr);
   3.147 +            [ret appendString:[NSString stringWithFormat:@"[%4.4s]   %-50.50s  %s\n",
   3.148 +                               addrstr, hexstr, charstr]];
   3.149 +            hexstr[0] = 0;
   3.150 +            charstr[0] = 0;
   3.151 +        } else if(n%8 == 0) {
   3.152 +            /* half line: add whitespaces */
   3.153 +            strncat(hexstr, "  ", sizeof(hexstr)-strlen(hexstr)-1);
   3.154 +            strncat(charstr, " ", sizeof(charstr)-strlen(charstr)-1);
   3.155 +        }
   3.156 +        p++; /* next byte */
   3.157 +    }
   3.158 +    
   3.159 +    if (strlen(hexstr) > 0) {
   3.160 +        /* print rest of buffer if not empty */
   3.161 +        //printf("[%4.4s]   %-50.50s  %s\n", addrstr, hexstr, charstr);
   3.162 +        [ret appendString:[NSString stringWithFormat:@"[%4.4s]   %-50.50s  %s\n",
   3.163 +                           addrstr, hexstr, charstr]];
   3.164 +    }
   3.165 +    return ret;
   3.166 +}
   3.167 +
   3.168 +@end
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/CollectionUtils.h	Sat Mar 08 21:04:41 2008 -0800
     4.3 @@ -0,0 +1,77 @@
     4.4 +//
     4.5 +//  CollectionUtils.h
     4.6 +//  MYUtilities
     4.7 +//
     4.8 +//  Created by Jens Alfke on 1/5/08.
     4.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
    4.10 +//
    4.11 +
    4.12 +#import <Cocoa/Cocoa.h>
    4.13 +
    4.14 +// Collection creation conveniences:
    4.15 +
    4.16 +#define $array(OBJS...)     ({id objs[]={OBJS}; \
    4.17 +                              [NSArray arrayWithObjects: objs count: sizeof(objs)/sizeof(id)];})
    4.18 +#define $marray(OBJS...)    ({id objs[]={OBJS}; \
    4.19 +                              [NSMutableArray arrayWithObjects: objs count: sizeof(objs)/sizeof(id)];})
    4.20 +
    4.21 +#define $dict(PAIRS...)     ({struct _dictpair pairs[]={PAIRS}; \
    4.22 +                              _dictof(pairs,sizeof(pairs)/sizeof(struct _dictpair));})
    4.23 +#define $mdict(PAIRS...)    ({struct _dictpair pairs[]={PAIRS}; \
    4.24 +                              _mdictof(pairs,sizeof(pairs)/sizeof(struct _dictpair));})
    4.25 +
    4.26 +#define $object(VAL)        ({__typeof(VAL) v=(VAL); _box(&v,@encode(__typeof(v)));})
    4.27 +
    4.28 +
    4.29 +// Object conveniences:
    4.30 +
    4.31 +BOOL $equal(id obj1, id obj2);      // Like -isEqual: but works even if either/both are nil
    4.32 +
    4.33 +#define $sprintf(FORMAT, ARGS... )  [NSString stringWithFormat: (FORMAT), ARGS]
    4.34 +
    4.35 +#define $cast(CLASSNAME,OBJ)        (CLASSNAME*)(_cast([CLASSNAME class],(OBJ)))
    4.36 +#define $castNotNil(CLASSNAME,OBJ)  (CLASSNAME*)(_castNotNil([CLASSNAME class],(OBJ)))
    4.37 +#define $castIf(CLASSNAME,OBJ)      (CLASSNAME*)(_castIf([CLASSNAME class],(OBJ)))
    4.38 +#define $castArrayOf(ITEMCLASSNAME,OBJ) _castArrayOf([ITEMCLASSNAME class],(OBJ)))
    4.39 +
    4.40 +void setObj( id *var, id value );
    4.41 +BOOL ifSetObj( id *var, id value );
    4.42 +void setString( NSString **var, NSString *value );
    4.43 +BOOL ifSetString( NSString **var, NSString *value );
    4.44 +
    4.45 +
    4.46 +@interface NSArray (MYUtils)
    4.47 +- (BOOL) my_containsObjectIdenticalTo: (id)object;
    4.48 +@end
    4.49 +
    4.50 +
    4.51 +#pragma mark -
    4.52 +#pragma mark FOREACH:
    4.53 +    
    4.54 +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
    4.55 +#define foreach(VAR,ARR) for(VAR in ARR)
    4.56 +
    4.57 +#else
    4.58 +struct foreachstate {NSArray *array; unsigned n, i;};
    4.59 +static inline struct foreachstate _initforeach( NSArray *arr ) {
    4.60 +    struct foreachstate s;
    4.61 +    s.array = arr;
    4.62 +    s.n = [arr count];
    4.63 +    s.i = 0;
    4.64 +    return s;
    4.65 +}
    4.66 +#define foreach(VAR,ARR) for( struct foreachstate _s = _initforeach((ARR)); \
    4.67 +                                   _s.i<_s.n && ((VAR)=[_s.array objectAtIndex: _s.i], YES); \
    4.68 +                                   _s.i++ )
    4.69 +#endif
    4.70 +
    4.71 +
    4.72 +// Internals (don't use directly)
    4.73 +struct _dictpair { id key; id value; };
    4.74 +NSDictionary* _dictof(const struct _dictpair*, size_t count);
    4.75 +NSMutableDictionary* _mdictof(const struct _dictpair*, size_t count);
    4.76 +NSValue* _box(const void *value, const char *encoding);
    4.77 +id _cast(Class,id);
    4.78 +id _castNotNil(Class,id);
    4.79 +id _castIf(Class,id);
    4.80 +NSArray* _castArrayOf(Class,NSArray*);
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/CollectionUtils.m	Sat Mar 08 21:04:41 2008 -0800
     5.3 @@ -0,0 +1,192 @@
     5.4 +//
     5.5 +//  CollectionUtils.m
     5.6 +//  MYUtilities
     5.7 +//
     5.8 +//  Created by Jens Alfke on 1/5/08.
     5.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
    5.10 +//
    5.11 +
    5.12 +#import "CollectionUtils.h"
    5.13 +#import "Test.h"
    5.14 +
    5.15 +
    5.16 +NSDictionary* _dictof(const struct _dictpair* pairs, size_t count)
    5.17 +{
    5.18 +    CAssert(count<10000);
    5.19 +    id objects[count], keys[count];
    5.20 +    size_t n = 0;
    5.21 +    for( size_t i=0; i<count; i++,pairs++ ) {
    5.22 +        if( pairs->value ) {
    5.23 +            objects[n] = pairs->value;
    5.24 +            keys[n] = pairs->key;
    5.25 +            n++;
    5.26 +        }
    5.27 +    }
    5.28 +    return [NSDictionary dictionaryWithObjects: objects forKeys: keys count: n];
    5.29 +}
    5.30 +
    5.31 +
    5.32 +NSMutableDictionary* _mdictof(const struct _dictpair* pairs, size_t count)
    5.33 +{
    5.34 +    CAssert(count<10000);
    5.35 +    id objects[count], keys[count];
    5.36 +    size_t n = 0;
    5.37 +    for( size_t i=0; i<count; i++,pairs++ ) {
    5.38 +        if( pairs->value ) {
    5.39 +            objects[n] = pairs->value;
    5.40 +            keys[n] = pairs->key;
    5.41 +            n++;
    5.42 +        }
    5.43 +    }
    5.44 +    return [NSMutableDictionary dictionaryWithObjects: objects forKeys: keys count: n];
    5.45 +}
    5.46 +
    5.47 +
    5.48 +BOOL $equal(id obj1, id obj2)      // Like -isEqual: but works even if either/both are nil
    5.49 +{
    5.50 +    if( obj1 )
    5.51 +        return obj2 && [obj1 isEqual: obj2];
    5.52 +    else
    5.53 +        return obj2==nil;
    5.54 +}
    5.55 +
    5.56 +
    5.57 +NSValue* _box(const void *value, const char *encoding)
    5.58 +{
    5.59 +    // file:///Developer/Documentation/DocSets/com.apple.ADC_Reference_Library.DeveloperTools.docset/Contents/Resources/Documents/documentation/DeveloperTools/gcc-4.0.1/gcc/Type-encoding.html
    5.60 +    char e = encoding[0];
    5.61 +    if( e=='r' )                // ignore 'const' modifier
    5.62 +        e = encoding[1];
    5.63 +    switch( e ) {
    5.64 +        case 'c':   return [NSNumber numberWithChar: *(char*)value];
    5.65 +        case 'C':   return [NSNumber numberWithUnsignedChar: *(char*)value];
    5.66 +        case 's':   return [NSNumber numberWithShort: *(short*)value];
    5.67 +        case 'S':   return [NSNumber numberWithUnsignedShort: *(unsigned short*)value];
    5.68 +        case 'i':   return [NSNumber numberWithInt: *(int*)value];
    5.69 +        case 'I':   return [NSNumber numberWithUnsignedInt: *(unsigned int*)value];
    5.70 +        case 'l':   return [NSNumber numberWithLong: *(long*)value];
    5.71 +        case 'L':   return [NSNumber numberWithUnsignedLong: *(unsigned long*)value];
    5.72 +        case 'q':   return [NSNumber numberWithLongLong: *(long long*)value];
    5.73 +        case 'Q':   return [NSNumber numberWithUnsignedLongLong: *(unsigned long long*)value];
    5.74 +        case 'f':   return [NSNumber numberWithFloat: *(float*)value];
    5.75 +        case 'd':   return [NSNumber numberWithDouble: *(double*)value];
    5.76 +        case '*':   return [NSString stringWithUTF8String: *(char**)value];
    5.77 +        case '@':   return *(id*)value;
    5.78 +        default:    return [NSValue value: value withObjCType: encoding];
    5.79 +    }
    5.80 +}
    5.81 +
    5.82 +
    5.83 +id _cast( Class requiredClass, id object )
    5.84 +{
    5.85 +    if( object && ! [object isKindOfClass: requiredClass] )
    5.86 +        [NSException raise: NSInvalidArgumentException format: @"%@ required, but got %@ %p",
    5.87 +         requiredClass,[object class],object];
    5.88 +    return object;
    5.89 +}
    5.90 +
    5.91 +id _castNotNil( Class requiredClass, id object )
    5.92 +{
    5.93 +    if( ! [object isKindOfClass: requiredClass] )
    5.94 +        [NSException raise: NSInvalidArgumentException format: @"%@ required, but got %@ %p",
    5.95 +         requiredClass,[object class],object];
    5.96 +    return object;
    5.97 +}
    5.98 +
    5.99 +id _castIf( Class requiredClass, id object )
   5.100 +{
   5.101 +    if( object && ! [object isKindOfClass: requiredClass] )
   5.102 +        object = nil;
   5.103 +    return object;
   5.104 +}
   5.105 +
   5.106 +NSArray* _castArrayOf(Class itemClass, NSArray *a)
   5.107 +{
   5.108 +    id item;
   5.109 +    foreach( item, $cast(NSArray,a) )
   5.110 +        _cast(itemClass,item);
   5.111 +    return a;
   5.112 +}
   5.113 +
   5.114 +
   5.115 +void setObj( id *var, id value )
   5.116 +{
   5.117 +    if( value != *var ) {
   5.118 +        [*var release];
   5.119 +        *var = [value retain];
   5.120 +    }
   5.121 +}
   5.122 +
   5.123 +BOOL ifSetObj( id *var, id value )
   5.124 +{
   5.125 +    if( value != *var && ![value isEqual: *var] ) {
   5.126 +        [*var release];
   5.127 +        *var = [value retain];
   5.128 +        return YES;
   5.129 +    } else {
   5.130 +        return NO;
   5.131 +    }
   5.132 +}
   5.133 +
   5.134 +
   5.135 +void setString( NSString **var, NSString *value )
   5.136 +{
   5.137 +    if( value != *var ) {
   5.138 +        [*var release];
   5.139 +        *var = [value copy];
   5.140 +    }
   5.141 +}
   5.142 +
   5.143 +
   5.144 +BOOL ifSetString( NSString **var, NSString *value )
   5.145 +{
   5.146 +    if( value != *var && ![value isEqualToString: *var] ) {
   5.147 +        [*var release];
   5.148 +        *var = [value copy];
   5.149 +        return YES;
   5.150 +    } else {
   5.151 +        return NO;
   5.152 +    }
   5.153 +}
   5.154 +
   5.155 +
   5.156 +@implementation NSArray (MYUtils)
   5.157 +
   5.158 +- (BOOL) my_containsObjectIdenticalTo: (id)object
   5.159 +{
   5.160 +    return [self indexOfObjectIdenticalTo: object] != NSNotFound;
   5.161 +}
   5.162 +
   5.163 +@end
   5.164 +
   5.165 +
   5.166 +#import "Test.h"
   5.167 +
   5.168 +TestCase(CollectionUtils) {
   5.169 +    NSArray *a = $array(@"foo",@"bar",@"baz");
   5.170 +    //Log(@"a = %@",a);
   5.171 +    NSArray *aa = [NSArray arrayWithObjects: @"foo",@"bar",@"baz",nil];
   5.172 +    CAssertEqual(a,aa);
   5.173 +    
   5.174 +    const char *cstr = "a C string";
   5.175 +    id o = $object(cstr);
   5.176 +    //Log(@"o = %@",o);
   5.177 +    CAssertEqual(o,@"a C string");
   5.178 +    
   5.179 +    NSDictionary *d = $dict({@"int",    $object(1)},
   5.180 +                            {@"double", $object(-1.1)},
   5.181 +                            {@"char",   $object('x')},
   5.182 +                            {@"ulong",  $object(1234567UL)},
   5.183 +                            {@"longlong",$object(987654321LL)},
   5.184 +                            {@"cstr",   $object(cstr)});
   5.185 +    //Log(@"d = %@",d);
   5.186 +    NSDictionary *dd = [NSDictionary dictionaryWithObjectsAndKeys:
   5.187 +                        [NSNumber numberWithInt: 1],                    @"int",
   5.188 +                        [NSNumber numberWithDouble: -1.1],              @"double",
   5.189 +                        [NSNumber numberWithChar: 'x'],                 @"char",
   5.190 +                        [NSNumber numberWithUnsignedLong: 1234567UL],   @"ulong",
   5.191 +                        [NSNumber numberWithDouble: 987654321LL],       @"longlong",
   5.192 +                        @"a C string",                                  @"cstr",
   5.193 +                        nil];
   5.194 +    CAssertEqual(d,dd);
   5.195 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/ConcurrentOperation.h	Sat Mar 08 21:04:41 2008 -0800
     6.3 @@ -0,0 +1,19 @@
     6.4 +//
     6.5 +//  ConcurrentOperation.h
     6.6 +//  MYUtilities
     6.7 +//
     6.8 +//  Created by Jens Alfke on 2/5/08.
     6.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
    6.10 +//
    6.11 +
    6.12 +#import <Foundation/Foundation.h>
    6.13 +
    6.14 +
    6.15 +@interface ConcurrentOperation : NSOperation 
    6.16 +{
    6.17 +    BOOL _isExecuting, _isFinished;
    6.18 +}
    6.19 +
    6.20 +- (void) finish;
    6.21 +
    6.22 +@end
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/ConcurrentOperation.m	Sat Mar 08 21:04:41 2008 -0800
     7.3 @@ -0,0 +1,67 @@
     7.4 +//
     7.5 +//  ConcurrentOperation.m
     7.6 +//  MYUtilities
     7.7 +//
     7.8 +//  Created by Jens Alfke on 2/5/08.
     7.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
    7.10 +//
    7.11 +
    7.12 +#import "ConcurrentOperation.h"
    7.13 +
    7.14 +// 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
    7.15 +
    7.16 +
    7.17 +@implementation ConcurrentOperation
    7.18 +
    7.19 +
    7.20 +- (BOOL) isConcurrent {return YES;}
    7.21 +
    7.22 +- (void) main
    7.23 +{
    7.24 +    Assert(NO,@"Shouldn't call -main method of ConcurrentOperation");
    7.25 +}
    7.26 +
    7.27 +- (BOOL) isExecuting
    7.28 +{
    7.29 +    return _isExecuting;
    7.30 +}
    7.31 +
    7.32 +- (BOOL) isFinished
    7.33 +{
    7.34 +    return _isFinished;
    7.35 +}
    7.36 +
    7.37 +- (void) start
    7.38 +{
    7.39 +    // don't call super!
    7.40 +    Log(@"Starting %@",self);
    7.41 +    [self willChangeValueForKey: @"isExecuting"];
    7.42 +    _isExecuting = YES;
    7.43 +    [self didChangeValueForKey: @"isExecuting"];
    7.44 +}
    7.45 +
    7.46 +- (void) finish
    7.47 +{
    7.48 +    Log(@"Finished %@",self);
    7.49 +    [self willChangeValueForKey: @"isExecuting"];
    7.50 +    [self willChangeValueForKey: @"isFinished"];
    7.51 +    _isExecuting = NO;
    7.52 +    _isFinished = YES;
    7.53 +    [self didChangeValueForKey: @"isFinished"];
    7.54 +    [self didChangeValueForKey: @"isExecuting"];
    7.55 +}
    7.56 +
    7.57 +
    7.58 +- (void) cancel
    7.59 +{
    7.60 +    Log(@"Canceling %@",self);
    7.61 +    [super cancel];
    7.62 +    if( _isExecuting ) {
    7.63 +        [self willChangeValueForKey: @"isExecuting"];
    7.64 +        _isExecuting = NO;
    7.65 +        [self didChangeValueForKey: @"isExecuting"];
    7.66 +    }
    7.67 +}
    7.68 +
    7.69 +
    7.70 +@end
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/FileAlias.h	Sat Mar 08 21:04:41 2008 -0800
     8.3 @@ -0,0 +1,39 @@
     8.4 +//
     8.5 +//  FileAlias.h
     8.6 +//  MYUtilities
     8.7 +//
     8.8 +//  Copyright 2008 Jens Alfke. All rights reserved.
     8.9 +//
    8.10 +
    8.11 +#import <Foundation/Foundation.h>
    8.12 +
    8.13 +
    8.14 +/** A wrapper around an AliasHandle: a persistent reference to a file, which works
    8.15 +    even if the file is moved or renamed, or its volume unmounted. */
    8.16 +
    8.17 +@interface FileAlias : NSObject <NSCoding>
    8.18 +{
    8.19 +    AliasHandle _alias;
    8.20 +}
    8.21 +
    8.22 +- (id) initWithFilePath: (NSString*)path
    8.23 +                  error: (NSError**)error;
    8.24 +
    8.25 +- (id) initWithFilePath: (NSString*)path 
    8.26 +         relativeToPath: (NSString*)fromPath
    8.27 +                  error: (NSError**)error;
    8.28 +
    8.29 +- (NSString*) filePath: (NSError**)error;
    8.30 +- (NSString*) filePathRelativeToPath: (NSString*)fromPath error: (NSError**)error;
    8.31 +
    8.32 +- (NSArray*) findMatchesRelativeToPath: (NSString*)fromPath 
    8.33 +                             withRules: (unsigned)rules      // rules = kARMSearch etc.
    8.34 +                                 error: (NSError**)error;
    8.35 +- (NSArray*) findMatches: (NSError**)error;
    8.36 +
    8.37 +- (NSString*) originalPath;
    8.38 +- (NSString*) originalFilename;
    8.39 +- (NSString*) originalVolumeName;
    8.40 +- (void) dump;
    8.41 +
    8.42 +@end
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/FileAlias.m	Sat Mar 08 21:04:41 2008 -0800
     9.3 @@ -0,0 +1,231 @@
     9.4 +//
     9.5 +//  FileAlias.m
     9.6 +//  MYUtilities
     9.7 +//
     9.8 +//  Copyright 2008 Jens Alfke. All rights reserved.
     9.9 +//
    9.10 +
    9.11 +#import "FileAlias.h"
    9.12 +#import "FileUtils.h"
    9.13 +
    9.14 +
    9.15 +@implementation FileAlias
    9.16 +
    9.17 +
    9.18 +- (id) initWithFilePath: (NSString*)targetPath 
    9.19 +         relativeToPath: (NSString*)fromPath
    9.20 +                  error: (NSError**)error
    9.21 +{
    9.22 +    NSParameterAssert(targetPath);
    9.23 +    self = [super init];
    9.24 +    if( self ) {
    9.25 +        OSStatus err;
    9.26 +        FSRef fromRef, targetRef;
    9.27 +        err = PathToFSRef(targetPath, &targetRef);
    9.28 +        if( ! err ) {
    9.29 +            if( fromPath ) {
    9.30 +                err = PathToFSRef(fromPath,&fromRef);
    9.31 +                if( ! err )
    9.32 +                    err = FSNewAlias(&fromRef,&targetRef,&_alias);
    9.33 +            } else {
    9.34 +                err = FSNewAlias(NULL,&targetRef,&_alias);
    9.35 +            }
    9.36 +        }
    9.37 +        
    9.38 +        if( ! CheckOSErr(err,error) ) {
    9.39 +            Warn(@"FileAlias init failed with OSStatus %i",err);
    9.40 +            [self release];
    9.41 +            return nil;
    9.42 +        }
    9.43 +    }
    9.44 +    return self;
    9.45 +}
    9.46 +
    9.47 +- (id) initWithFilePath: (NSString*)path
    9.48 +                  error: (NSError**)error
    9.49 +{
    9.50 +    return [self initWithFilePath: path relativeToPath: nil error: error];
    9.51 +}
    9.52 +
    9.53 +
    9.54 +- (void) dealloc
    9.55 +{
    9.56 +    if( _alias )
    9.57 +        DisposeHandle((Handle)_alias);
    9.58 +    [super dealloc];
    9.59 +}
    9.60 +
    9.61 +
    9.62 +- (void)encodeWithCoder:(NSCoder *)coder
    9.63 +{
    9.64 +    NSParameterAssert([coder allowsKeyedCoding]);
    9.65 +    NSKeyedArchiver *arch = (NSKeyedArchiver*)coder;
    9.66 +
    9.67 +    [arch encodeBytes: (const uint8_t *) *_alias 
    9.68 +               length: GetHandleSize((Handle)_alias)
    9.69 +               forKey: @"aliasHandle"];
    9.70 +}
    9.71 +
    9.72 +
    9.73 +- (id)initWithCoder:(NSCoder *)decoder
    9.74 +{
    9.75 +    NSParameterAssert([decoder allowsKeyedCoding]);
    9.76 +    NSKeyedUnarchiver *arch = (NSKeyedUnarchiver*)decoder;
    9.77 +
    9.78 +    self = [super init];
    9.79 +    if( self ) {
    9.80 +        Handle handle;
    9.81 +        unsigned length;
    9.82 +        const void *bytes = [arch decodeBytesForKey:@"aliasHandle" returnedLength: &length];
    9.83 +        if( bytes )
    9.84 +            PtrToHand(bytes,&handle,length);
    9.85 +        if( ! handle ) {
    9.86 +            [self release];
    9.87 +            return nil;
    9.88 +        }
    9.89 +        _alias = (AliasHandle) handle;
    9.90 +    }
    9.91 +    return self;
    9.92 +}
    9.93 +
    9.94 +
    9.95 +- (NSString*) description
    9.96 +{
    9.97 +    return [NSString stringWithFormat: @"%@['%@']", [self class],[self originalFilename]];
    9.98 +}
    9.99 +
   9.100 +
   9.101 +- (NSString*) originalPath
   9.102 +{
   9.103 +    CFStringRef path = NULL;
   9.104 +    OSStatus err = FSCopyAliasInfo(_alias,NULL,NULL,&path,NULL,NULL);
   9.105 +    if( err )
   9.106 +        return nil;
   9.107 +    else
   9.108 +        return [(id)path autorelease];
   9.109 +}
   9.110 +
   9.111 +- (NSString*) originalFilename
   9.112 +{
   9.113 +    HFSUniStr255 targetName;
   9.114 +    OSStatus err = FSCopyAliasInfo(_alias,&targetName,NULL,NULL,NULL,NULL);
   9.115 +    if( err )
   9.116 +        return nil;
   9.117 +    else
   9.118 +        return [(id)FSCreateStringFromHFSUniStr(NULL,&targetName) autorelease];
   9.119 +}
   9.120 +
   9.121 +- (NSString*) originalVolumeName
   9.122 +{
   9.123 +    HFSUniStr255 volName;
   9.124 +    OSStatus err = FSCopyAliasInfo(_alias,NULL,&volName,NULL,NULL,NULL);
   9.125 +    if( err )
   9.126 +        return nil;
   9.127 +    else
   9.128 +        return [(id)FSCreateStringFromHFSUniStr(NULL,&volName) autorelease];
   9.129 +}
   9.130 +
   9.131 +- (void) dump
   9.132 +{
   9.133 +    HFSUniStr255 targetName,volName;
   9.134 +    CFStringRef path;
   9.135 +    FSAliasInfoBitmap whichInfo = 0;
   9.136 +    FSAliasInfo info;
   9.137 +    OSStatus err = FSCopyAliasInfo(_alias,&targetName,&volName,&path,&whichInfo,&info);
   9.138 +    if( err ) {
   9.139 +        NSLog(@"FSCopyAliasInfo returned error %i",err);
   9.140 +        return;
   9.141 +    }
   9.142 +    NSString *str = (id)FSCreateStringFromHFSUniStr(NULL,&targetName);
   9.143 +    NSLog(@"Target name = '%@'",str);
   9.144 +    [str release];
   9.145 +    str = (id)FSCreateStringFromHFSUniStr(NULL,&volName);
   9.146 +    NSLog(@"Volume name = '%@'",str);
   9.147 +    [str release];
   9.148 +    NSLog(@"Path        = %@",path);
   9.149 +    if( path ) CFRelease(path);
   9.150 +    NSLog(@"Info bitmap = %08X", whichInfo);
   9.151 +}    
   9.152 +
   9.153 +
   9.154 +#pragma mark -
   9.155 +#pragma mark RESOLVING:
   9.156 +
   9.157 +
   9.158 +- (NSString*) filePathRelativeToPath: (NSString*)fromPath error: (NSError**)error
   9.159 +{
   9.160 +    FSRef fromRef, targetRef, *fromRefPtr;
   9.161 +    if( fromPath ) {
   9.162 +        if( ! CheckOSErr( PathToFSRef(fromPath,&fromRef), error ) )
   9.163 +            return NO;
   9.164 +        fromRefPtr = &fromRef;
   9.165 +    } else {
   9.166 +        fromRefPtr = NULL;
   9.167 +    }
   9.168 +    
   9.169 +    Boolean wasChanged;
   9.170 +    NSString *targetPath;
   9.171 +    if( CheckOSErr( FSResolveAlias(fromRefPtr,_alias,&targetRef,&wasChanged), error)
   9.172 +            && CheckOSErr( FSRefToPath(&targetRef,&targetPath), error ) )
   9.173 +        return targetPath;
   9.174 +    else {
   9.175 +        NSLog(@"%@: Couldn't resolve alias!",self);
   9.176 +        [self dump];
   9.177 +        return nil;
   9.178 +    }
   9.179 +}
   9.180 +
   9.181 +- (NSString*) filePath: (NSError**)error
   9.182 +{
   9.183 +    return [self filePathRelativeToPath: nil error: error];
   9.184 +}
   9.185 +
   9.186 +
   9.187 +- (NSArray*) findMatchesRelativeToPath: (NSString*)fromPath 
   9.188 +                             withRules: (unsigned)rules
   9.189 +                                 error: (NSError**)error
   9.190 +{
   9.191 +    FSRef fromRef, *fromRefPtr;
   9.192 +    if( fromPath ) {
   9.193 +        if( ! CheckOSErr( PathToFSRef(fromPath,&fromRef), error ) )
   9.194 +            return nil;
   9.195 +        fromRefPtr = &fromRef;
   9.196 +    } else {
   9.197 +        fromRefPtr = NULL;
   9.198 +    }
   9.199 +    
   9.200 +    Boolean wasChanged;
   9.201 +    short count = 10;
   9.202 +    FSRef matches[count];
   9.203 +    
   9.204 +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
   9.205 +    if( ! FSMatchAliasBulk(fromRefPtr, rules, _alias, &count, matches, &wasChanged, NULL, NULL), error ) {
   9.206 +        NSLog(@"%@: FSMatchAliasBulk failed!",self);
   9.207 +        return nil;
   9.208 +    }
   9.209 +#else
   9.210 +    if( ! CheckOSErr( FSMatchAlias(fromRefPtr,rules,_alias,&count,matches,&wasChanged,NULL,NULL), error) ) {
   9.211 +        NSLog(@"%@: FSMatchAlias failed!",self);
   9.212 +        return nil;
   9.213 +    }
   9.214 +#endif
   9.215 +    
   9.216 +    NSMutableArray *paths = [NSMutableArray arrayWithCapacity: count];
   9.217 +    for( short i=0; i<count; i++ ) {
   9.218 +        NSString *path;
   9.219 +        if( FSRefToPath(&matches[i],&path) == noErr )
   9.220 +            [paths addObject: path];
   9.221 +    }
   9.222 +    return paths;
   9.223 +}
   9.224 +
   9.225 +
   9.226 +- (NSArray*) findMatches: (NSError**)error
   9.227 +{
   9.228 +    return [self findMatchesRelativeToPath: nil
   9.229 +                                 withRules: kARMMultVols | kARMSearch | kARMSearchMore | kARMTryFileIDFirst
   9.230 +                                     error: error];
   9.231 +}
   9.232 +
   9.233 +
   9.234 +@end
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/FileUtils.h	Sat Mar 08 21:04:41 2008 -0800
    10.3 @@ -0,0 +1,17 @@
    10.4 +//
    10.5 +//  FileUtils.h
    10.6 +//  MYUtilities
    10.7 +//
    10.8 +//  Created by Jens Alfke on 1/14/08.
    10.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
   10.10 +//
   10.11 +
   10.12 +#import <Foundation/Foundation.h>
   10.13 +
   10.14 +
   10.15 +FOUNDATION_EXPORT OSStatus PathToFSRef( NSString *path, FSRef *outFSRef );
   10.16 +FOUNDATION_EXPORT OSStatus FSRefToPath( const FSRef *fsRef, NSString **outPath );
   10.17 +
   10.18 +FOUNDATION_EXPORT BOOL CheckOSErr( OSStatus err, NSError **error );
   10.19 +
   10.20 +FOUNDATION_EXPORT NSString* AppSupportDirectory(void);
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/FileUtils.m	Sat Mar 08 21:04:41 2008 -0800
    11.3 @@ -0,0 +1,55 @@
    11.4 +//
    11.5 +//  FileUtils.m
    11.6 +//  MYUtilities
    11.7 +//
    11.8 +//  Created by Jens Alfke on 1/14/08.
    11.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
   11.10 +//
   11.11 +
   11.12 +#import "FileUtils.h"
   11.13 +
   11.14 +
   11.15 +OSStatus PathToFSRef( NSString *path, FSRef *fsRef )
   11.16 +{
   11.17 +    NSCParameterAssert(path);
   11.18 +    return FSPathMakeRef((const UInt8 *)[path UTF8String],fsRef,NULL);
   11.19 +}
   11.20 +
   11.21 +OSStatus FSRefToPath( const FSRef *fsRef, NSString **outPath )
   11.22 +{
   11.23 +    NSURL *url = (id) CFURLCreateFromFSRef(NULL,fsRef);
   11.24 +    if( ! url )
   11.25 +        return paramErr;
   11.26 +    *outPath = [url path];
   11.27 +    [url release];
   11.28 +    return noErr;
   11.29 +}
   11.30 +
   11.31 +
   11.32 +BOOL CheckOSErr( OSStatus err, NSError **error )
   11.33 +{
   11.34 +    if( err ) {
   11.35 +        if( error )
   11.36 +            *error = [NSError errorWithDomain: NSOSStatusErrorDomain code: err userInfo: nil];
   11.37 +        return NO;
   11.38 +    } else {
   11.39 +        return YES;
   11.40 +    }
   11.41 +}
   11.42 +
   11.43 +
   11.44 +NSString* AppSupportDirectory()
   11.45 +{
   11.46 +    static NSString *sPath;
   11.47 +    if( ! sPath ) {
   11.48 +        NSString *dir = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory,
   11.49 +                                                             NSUserDomainMask, YES)
   11.50 +                         objectAtIndex: 0];
   11.51 +        dir = [dir stringByAppendingPathComponent: [[NSBundle mainBundle] bundleIdentifier]];
   11.52 +        if( ! [[NSFileManager defaultManager] fileExistsAtPath: dir]
   11.53 +                && ! [[NSFileManager defaultManager] createDirectoryAtPath: dir attributes: nil] )
   11.54 +            [NSException raise: NSGenericException format: @"Unable to create app support dir %@",dir];
   11.55 +        sPath = [dir copy];
   11.56 +    }
   11.57 +    return sPath;
   11.58 +}
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/GraphicsUtils.h	Sat Mar 08 21:04:41 2008 -0800
    12.3 @@ -0,0 +1,21 @@
    12.4 +//
    12.5 +//  GraphicsUtils.h
    12.6 +//  MYUtilities
    12.7 +//
    12.8 +//  Copyright 2008 Jens Alfke. All rights reserved.
    12.9 +//
   12.10 +
   12.11 +#import <Cocoa/Cocoa.h>
   12.12 +
   12.13 +
   12.14 +@interface NSImage (MYUtilities)
   12.15 +- (NSImage*) my_shrunkToFitIn: (NSSize) maxSize;
   12.16 +- (NSSize) my_sizeOfLargestRep;
   12.17 +- (NSData*) my_JPEGData;
   12.18 +//- (NSData*) my)_PICTData;
   12.19 +@end
   12.20 +
   12.21 +
   12.22 +@interface NSBezierPath (MYUtilities)
   12.23 ++ (NSBezierPath*) my_bezierPathWithRoundRect: (NSRect)rect radius: (float)radius;
   12.24 +@end
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/GraphicsUtils.m	Sat Mar 08 21:04:41 2008 -0800
    13.3 @@ -0,0 +1,190 @@
    13.4 +//
    13.5 +//  GraphicsUtils.m
    13.6 +//  MYUtilities
    13.7 +//
    13.8 +//  Copyright 2008 Jens Alfke. All rights reserved.
    13.9 +//
   13.10 +
   13.11 +#import "GraphicsUtils.h"
   13.12 +
   13.13 +
   13.14 +@implementation NSImage (MYUtilities)
   13.15 +
   13.16 +
   13.17 +- (NSSize) my_sizeOfLargestRep
   13.18 +{
   13.19 +    NSArray *reps = [self representations];
   13.20 +    NSSize max = {0,0};
   13.21 +    int i;
   13.22 +    for( i=[reps count]-1; i>=0; i-- ) {
   13.23 +        NSImageRep *rep = [reps objectAtIndex: i];
   13.24 +        NSSize size = [rep size];
   13.25 +        if( size.width > max.width || size.height > max.height ) {
   13.26 +            max = size;
   13.27 +        }
   13.28 +    }
   13.29 +    return max;
   13.30 +}
   13.31 +
   13.32 +
   13.33 +- (NSImage*) my_shrunkToFitIn: (NSSize) maxSize
   13.34 +{
   13.35 +    NSSize size = self.size;
   13.36 +    float scale = MIN( size.width/maxSize.width, size.height/maxSize.height );
   13.37 +    if( scale >= 1.0 )
   13.38 +        return self;
   13.39 +    
   13.40 +    NSSize newSize = {roundf(size.width*scale), roundf(size.height*scale)};
   13.41 +    NSImage *newImage = [[NSImage alloc] initWithSize: newSize];
   13.42 +    [newImage lockFocus];
   13.43 +    NSGraphicsContext *context = [NSGraphicsContext currentContext];
   13.44 +    [context saveGraphicsState];
   13.45 +    [context setImageInterpolation: NSImageInterpolationHigh];
   13.46 +    [self drawInRect: NSMakeRect(0,0,newSize.width,newSize.height)
   13.47 +            fromRect: NSMakeRect(0,0,size.width,size.height)
   13.48 +           operation: NSCompositeCopy fraction: 1.0f];
   13.49 +    [context restoreGraphicsState];
   13.50 +    [newImage unlockFocus];
   13.51 +    return [newImage autorelease];
   13.52 +}
   13.53 +
   13.54 +
   13.55 +- (NSData*) my_JPEGData
   13.56 +{
   13.57 +    NSImage *tiffImage = [[NSImage alloc] initWithData:[self TIFFRepresentation]];
   13.58 +    NSBitmapImageRep *rep = [[tiffImage representations] objectAtIndex:0];
   13.59 +    NSDictionary *props = [NSDictionary dictionaryWithObjectsAndKeys:
   13.60 +        [NSNumber numberWithFloat: 0.75f], NSImageCompressionFactor, nil];
   13.61 +    NSData *jpeg = [rep representationUsingType: NSJPEGFileType properties: props];
   13.62 +    [tiffImage release];
   13.63 +    return jpeg;
   13.64 +}
   13.65 +
   13.66 +
   13.67 +#if 0
   13.68 +
   13.69 +// Adapted from Apple's CocoaCreateMovie sample
   13.70 +// <http://developer.apple.com/samplecode/Sample_Code/QuickTime/Basics/CocoaCreateMovie/MyController.m.htm>
   13.71 +static void CopyNSImageRepToGWorld(NSBitmapImageRep *imageRepresentation, GWorldPtr gWorldPtr)
   13.72 +{
   13.73 +    PixMapHandle  pixMapHandle;
   13.74 +    unsigned char*   pixBaseAddr;
   13.75 +
   13.76 +    // Lock the pixels
   13.77 +    pixMapHandle = GetGWorldPixMap(gWorldPtr);
   13.78 +    LockPixels (pixMapHandle);
   13.79 +    pixBaseAddr = (unsigned char*) GetPixBaseAddr(pixMapHandle);
   13.80 +
   13.81 +    const unsigned char* bitMapDataPtr = [imageRepresentation bitmapData];
   13.82 +
   13.83 +    if ((bitMapDataPtr != nil) && (pixBaseAddr != nil))
   13.84 +    {
   13.85 +        int i,j;
   13.86 +        int pixmapRowBytes = GetPixRowBytes(pixMapHandle);
   13.87 +        NSSize imageSize = [imageRepresentation size];
   13.88 +        for (i=0; i< imageSize.height; i++)
   13.89 +        {
   13.90 +            const unsigned char *src = bitMapDataPtr + i * [imageRepresentation bytesPerRow];
   13.91 +            unsigned char *dst = pixBaseAddr + i * pixmapRowBytes;
   13.92 +            for (j = 0; j < imageSize.width; j++)
   13.93 +            {
   13.94 +                *dst++ = 0;  // X - our src is 24-bit only
   13.95 +                *dst++ = *src++; // Red component
   13.96 +                *dst++ = *src++; // Green component
   13.97 +                *dst++ = *src++; // Blue component
   13.98 +            }
   13.99 +        }
  13.100 +    }
  13.101 +    UnlockPixels(pixMapHandle);
  13.102 +}
  13.103 +
  13.104 +
  13.105 +- (NSData*) my_PICTData
  13.106 +{
  13.107 +    // Locate the bitmap image rep:
  13.108 +    NSBitmapImageRep *rep;
  13.109 +    NSEnumerator *e = [[self representations] objectEnumerator];
  13.110 +    while( (rep=[e nextObject]) != nil ) {
  13.111 +        if( [rep isKindOfClass: [NSBitmapImageRep class]] )
  13.112 +            break;
  13.113 +    }
  13.114 +    if( ! rep ) {
  13.115 +        Warn(@"No bitmap image rep in image");
  13.116 +        return nil;
  13.117 +    }
  13.118 +
  13.119 +    // Copy the image data into a GWorld:
  13.120 +    Rect bounds;
  13.121 +    SetRect(&bounds, 0,0,[rep pixelsWide],[rep pixelsHigh]);    
  13.122 +    GWorldPtr gworld;
  13.123 +    OSStatus err = NewGWorld(&gworld, 32, &bounds, NULL, NULL, 0);
  13.124 +    if( err ) {
  13.125 +        Warn(@"NewGWorld failed with err %i",err);
  13.126 +        return nil;
  13.127 +    }
  13.128 +    CopyNSImageRepToGWorld(rep,gworld);
  13.129 +
  13.130 +    // Draw the GWorld into a PicHandle:
  13.131 +    CGrafPtr oldPort;
  13.132 +    GDHandle oldDevice;
  13.133 +    GetGWorld(&oldPort,&oldDevice);
  13.134 +    SetGWorld(gworld,NULL);
  13.135 +    ClipRect(&bounds);
  13.136 +    PicHandle pic = OpenPicture(&bounds);
  13.137 +    CopyBits(GetPortBitMapForCopyBits(gworld),
  13.138 +             GetPortBitMapForCopyBits(gworld),
  13.139 +             &bounds,&bounds,srcCopy,NULL);
  13.140 +    ClosePicture();
  13.141 +    err = QDError();
  13.142 +    SetGWorld(oldPort,oldDevice);
  13.143 +    DisposeGWorld(gworld);
  13.144 +    
  13.145 +    if( err ) {
  13.146 +        Warn(@"Couldn't convert to PICT: error %i",err);
  13.147 +        return nil;
  13.148 +    }
  13.149 +
  13.150 +    // Copy the PicHandle into an NSData:
  13.151 +    HLock((Handle)pic);
  13.152 +    //Test to put PICT on clipboard:
  13.153 +    /*ScrapRef scrap;
  13.154 +    GetCurrentScrap(&scrap);
  13.155 +    ClearScrap(&scrap);
  13.156 +    PutScrapFlavor(scrap,'PICT',0,GetHandleSize((Handle)pic),*pic);*/
  13.157 +    NSData *data = [NSData dataWithBytes: *pic length: GetHandleSize((Handle)pic)];
  13.158 +    DisposeHandle((Handle)pic);
  13.159 +    Log(@"Converted image to %i bytes of PICT data",[data length]);
  13.160 +    return data;
  13.161 +}
  13.162 +#endif
  13.163 +
  13.164 +
  13.165 +@end
  13.166 +
  13.167 +
  13.168 +
  13.169 +
  13.170 +@implementation NSBezierPath (MYUtilities)
  13.171 +
  13.172 ++ (NSBezierPath*) my_bezierPathWithRoundRect: (NSRect)rect radius: (float)radius
  13.173 +{
  13.174 +    radius = MIN(radius, floorf(rect.size.width/2));
  13.175 +    float x0 = NSMinX(rect), y0 = NSMinY(rect),
  13.176 +          x1 = NSMaxX(rect), y1 = NSMaxY(rect);
  13.177 +    NSBezierPath *path = [NSBezierPath bezierPath];
  13.178 +    
  13.179 +    [path moveToPoint: NSMakePoint(x0+radius,y0)];
  13.180 +    
  13.181 +    [path appendBezierPathWithArcFromPoint: NSMakePoint(x1,y0)
  13.182 +                                   toPoint: NSMakePoint(x1,y1) radius: radius];
  13.183 +    [path appendBezierPathWithArcFromPoint: NSMakePoint(x1,y1)
  13.184 +                                   toPoint: NSMakePoint(x0,y1) radius: radius];
  13.185 +    [path appendBezierPathWithArcFromPoint: NSMakePoint(x0,y1)
  13.186 +                                   toPoint: NSMakePoint(x0,y0) radius: radius];
  13.187 +    [path appendBezierPathWithArcFromPoint: NSMakePoint(x0,y0)
  13.188 +                                   toPoint: NSMakePoint(x1,y0) radius: radius];
  13.189 +    [path closePath];
  13.190 +    return path;
  13.191 +}
  13.192 +
  13.193 +@end
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/IChatUtils.h	Sat Mar 08 21:04:41 2008 -0800
    14.3 @@ -0,0 +1,21 @@
    14.4 +//
    14.5 +//  IChatUtils.h
    14.6 +//  MYUtilities
    14.7 +//
    14.8 +//  Created by Jens Alfke on 3/3/08.
    14.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
   14.10 +//
   14.11 +
   14.12 +#import <Cocoa/Cocoa.h>
   14.13 +@class SBApplication;
   14.14 +
   14.15 +
   14.16 +@interface IChatUtils : NSObject 
   14.17 +
   14.18 ++ (SBApplication*) app;
   14.19 ++ (BOOL) isRunning;
   14.20 ++ (void) activate;
   14.21 ++ (NSString*) activeChatPartner;
   14.22 ++ (BOOL) sendMessage: (NSString*)msg;
   14.23 +
   14.24 +@end
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/IChatUtils.m	Sat Mar 08 21:04:41 2008 -0800
    15.3 @@ -0,0 +1,65 @@
    15.4 +//
    15.5 +//  IChatUtils.m
    15.6 +//  MYUtilities
    15.7 +//
    15.8 +//  Created by Jens Alfke on 3/3/08.
    15.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
   15.10 +//
   15.11 +
   15.12 +#import "IChatUtils.h"
   15.13 +#import "iChatBridge.h"
   15.14 +
   15.15 +@implementation IChatUtils
   15.16 +
   15.17 +
   15.18 +static iChatApplication *sIChatApp;
   15.19 +
   15.20 ++ (void) initialize
   15.21 +{
   15.22 +    if( ! sIChatApp ) {
   15.23 +        sIChatApp = [SBApplication applicationWithBundleIdentifier: @"com.apple.iChat"];
   15.24 +        sIChatApp.timeout = 5*60; // in ticks
   15.25 +    }
   15.26 +}
   15.27 +
   15.28 +
   15.29 ++ (SBApplication*) app  {return sIChatApp;}
   15.30 ++ (BOOL) isRunning      {return sIChatApp.isRunning;}
   15.31 ++ (void) activate       {[sIChatApp activate];}
   15.32 +
   15.33 +
   15.34 ++ (iChatTextChat*) activeChat
   15.35 +{
   15.36 +    if( ! [sIChatApp isRunning] )
   15.37 +        return nil;
   15.38 +    SBElementArray *chats = sIChatApp.textChats;
   15.39 +    if( chats.count==0 )
   15.40 +        return nil;
   15.41 +    iChatTextChat *chat = [chats objectAtIndex: 0];
   15.42 +    if( ! chat.active )
   15.43 +        return nil;
   15.44 +    return chat;
   15.45 +}    
   15.46 +
   15.47 ++ (NSString*) activeChatPartner
   15.48 +{
   15.49 +    iChatTextChat *chat = [self activeChat];
   15.50 +    if( ! chat )
   15.51 +        return nil;
   15.52 +    NSMutableArray *names = $marray();
   15.53 +    for( iChatBuddy *b in [chat participants] )
   15.54 +        [names addObject: (b.fullName ?: b.name)];
   15.55 +    return [names componentsJoinedByString: @", "];
   15.56 +}
   15.57 +
   15.58 ++ (BOOL) sendMessage: (NSString*)msg
   15.59 +{
   15.60 +    iChatTextChat *chat = [self activeChat];
   15.61 +    if( ! chat )
   15.62 +        return NO;
   15.63 +    [sIChatApp send: msg to: chat];
   15.64 +    return YES;
   15.65 +}
   15.66 +
   15.67 +
   15.68 +@end
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/KVUtils.h	Sat Mar 08 21:04:41 2008 -0800
    16.3 @@ -0,0 +1,66 @@
    16.4 +//
    16.5 +//  KVUtils.h
    16.6 +//  MYUtilities
    16.7 +//
    16.8 +//  Created by Jens Alfke on 2/25/08.
    16.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
   16.10 +//
   16.11 +
   16.12 +#import <Cocoa/Cocoa.h>
   16.13 +
   16.14 +
   16.15 +enum {
   16.16 +    MYKeyValueObservingOptionOnce = 1<<31,
   16.17 +    MYKeyValueObservingOptionDelayed = 1<<30
   16.18 +};
   16.19 +
   16.20 +
   16.21 +
   16.22 +@interface Observance : NSObject
   16.23 +{
   16.24 +    id _target;
   16.25 +    id _observed;
   16.26 +    NSString *_keyPath;
   16.27 +    NSKeyValueObservingOptions _options;
   16.28 +    SEL _action;
   16.29 +}
   16.30 +
   16.31 +- (id) initWithTarget: (id)target 
   16.32 +               action: (SEL)action
   16.33 +             observed: (id)observed
   16.34 +              keyPath: (NSString*)keyPath 
   16.35 +              options: (NSKeyValueObservingOptions)options;
   16.36 +
   16.37 +- (void) stopObserving;
   16.38 +
   16.39 +@property (readonly) id observed;
   16.40 +@property (readonly) NSString* keyPath;
   16.41 +
   16.42 +@end
   16.43 +
   16.44 +
   16.45 +
   16.46 +@interface Observer : NSObject
   16.47 +{
   16.48 +    id _target;
   16.49 +    NSMutableArray *_observances;
   16.50 +}
   16.51 +
   16.52 +- (id) initWithTarget: (id)target;
   16.53 +
   16.54 +@property (readonly) id target;
   16.55 +
   16.56 +- (void) observe: (id)observed 
   16.57 +         keyPath: (NSString*)keyPath 
   16.58 +         options: (NSKeyValueObservingOptions)options
   16.59 +          action: (SEL)action;
   16.60 +
   16.61 +- (void) observe: (id)observed 
   16.62 +         keyPath: (NSString*)keyPath 
   16.63 +          action: (SEL)action;
   16.64 +
   16.65 +- (void) stopObserving: (id)observedOrNil keyPath: (NSString*)keyPathOrNil;
   16.66 +
   16.67 +- (void) stopObserving;
   16.68 +
   16.69 +@end
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/KVUtils.m	Sat Mar 08 21:04:41 2008 -0800
    17.3 @@ -0,0 +1,163 @@
    17.4 +//
    17.5 +//  KVUtils.m
    17.6 +//  MYUtilities
    17.7 +//
    17.8 +//  Created by Jens Alfke on 2/25/08.
    17.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
   17.10 +//
   17.11 +
   17.12 +#import "KVUtils.h"
   17.13 +
   17.14 +
   17.15 +@implementation Observance
   17.16 +
   17.17 +- (id) initWithTarget: (id)target 
   17.18 +               action: (SEL)action
   17.19 +             observed: (id)observed
   17.20 +              keyPath: (NSString*)keyPath 
   17.21 +              options: (NSKeyValueObservingOptions)options
   17.22 +{
   17.23 +    self = [super init];
   17.24 +    if (self != nil) {
   17.25 +        _target = target;
   17.26 +        _action = action;
   17.27 +        _observed = observed;
   17.28 +        _keyPath = [keyPath copy];
   17.29 +        _options = options;
   17.30 +        
   17.31 +        options &= ~(MYKeyValueObservingOptionOnce | MYKeyValueObservingOptionDelayed);
   17.32 +        
   17.33 +        [_observed addObserver: self forKeyPath: _keyPath options: options context: _action];
   17.34 +    }
   17.35 +    return self;
   17.36 +}
   17.37 +
   17.38 +- (void) dealloc
   17.39 +{
   17.40 +    [_observed removeObserver: self forKeyPath: _keyPath];
   17.41 +    [_keyPath release];
   17.42 +    [super dealloc];
   17.43 +}
   17.44 +
   17.45 +
   17.46 +@synthesize observed=_observed, keyPath=_keyPath;
   17.47 +
   17.48 +
   17.49 +- (void) stopObserving
   17.50 +{
   17.51 +    [_observed removeObserver: self forKeyPath: _keyPath];
   17.52 +    _observed = nil;
   17.53 +    _target = nil;
   17.54 +    _action = NULL;
   17.55 +}
   17.56 +
   17.57 +
   17.58 +- (void) _callTargetWithChange: (NSDictionary*)change
   17.59 +{
   17.60 +    @try{
   17.61 +        [_target performSelector: _action withObject: _observed withObject: change];
   17.62 +    }@catch( NSException *x ) {
   17.63 +        Warn(@"Uncaught exception in -[%@<%p> %s] while observing change of key-path %@ in %@<%p>: %@",
   17.64 +             _target,_target, _action, _keyPath, _observed,_observed, x);
   17.65 +    }
   17.66 +}
   17.67 +
   17.68 +
   17.69 +- (void)observeValueForKeyPath:(NSString *)keyPath 
   17.70 +                      ofObject:(id)object 
   17.71 +                        change:(NSDictionary *)change 
   17.72 +                       context:(void *)context
   17.73 +{
   17.74 +    if( object == _observed ) {
   17.75 +        if( _options & MYKeyValueObservingOptionDelayed )
   17.76 +            [self performSelector: @selector(_callTargetWithChange:) withObject: change
   17.77 +                       afterDelay: 0.0];
   17.78 +        else
   17.79 +            [self _callTargetWithChange: change];
   17.80 +        if( _options & MYKeyValueObservingOptionOnce )
   17.81 +            [self stopObserving];
   17.82 +    }
   17.83 +}
   17.84 +
   17.85 +
   17.86 +@end
   17.87 +
   17.88 +
   17.89 +
   17.90 +
   17.91 +@implementation Observer
   17.92 +
   17.93 +
   17.94 +- (id) init
   17.95 +{
   17.96 +    return [self initWithTarget: self];
   17.97 +}
   17.98 +
   17.99 +
  17.100 +
  17.101 +- (id) initWithTarget: (id)target
  17.102 +{
  17.103 +    Assert(target);
  17.104 +    self = [super init];
  17.105 +    if (self != nil) {
  17.106 +        _target = target;
  17.107 +        _observances = [[NSMutableArray alloc] init];
  17.108 +    }
  17.109 +    return self;
  17.110 +}
  17.111 +
  17.112 +
  17.113 +- (void) dealloc
  17.114 +{
  17.115 +    [self stopObserving];
  17.116 +    [_observances release];
  17.117 +    [super dealloc];
  17.118 +}
  17.119 +
  17.120 +
  17.121 +@synthesize target=_target;
  17.122 +
  17.123 +
  17.124 +- (void) observe: (id)observed 
  17.125 +         keyPath: (NSString*)keyPath 
  17.126 +         options: (NSKeyValueObservingOptions)options
  17.127 +          action: (SEL)action
  17.128 +{
  17.129 +    Observance *o = [[Observance alloc] initWithTarget: _target
  17.130 +                                                action: action
  17.131 +                                              observed: observed
  17.132 +                                               keyPath: keyPath
  17.133 +                                               options: options];
  17.134 +    [_observances addObject: o];
  17.135 +    [o release];
  17.136 +}
  17.137 +
  17.138 +
  17.139 +- (void) observe: (id)observed 
  17.140 +         keyPath: (NSString*)keyPath 
  17.141 +          action: (SEL)action
  17.142 +{
  17.143 +    [self observe: observed keyPath: keyPath options: 0 action: action];
  17.144 +}
  17.145 +
  17.146 +
  17.147 +- (void) stopObserving
  17.148 +{
  17.149 +    [_observances makeObjectsPerformSelector: @selector(stopObserving)];
  17.150 +    [_observances removeAllObjects];
  17.151 +}
  17.152 +
  17.153 +
  17.154 +- (void) stopObserving: (id)observed keyPath: (NSString*)keyPath
  17.155 +{
  17.156 +    // observed or keyPath may be nil
  17.157 +    for( int i=_observances.count-1; i>=0; i-- ) {
  17.158 +        Observance *o = [_observances objectAtIndex: i];
  17.159 +        if( (observed==nil || observed==o.observed) && (keyPath==nil || [keyPath isEqual: o.keyPath]) ) {
  17.160 +            [o stopObserving];
  17.161 +            [_observances removeObjectAtIndex: i];
  17.162 +        }
  17.163 +    }
  17.164 +}
  17.165 +
  17.166 +@end
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/Logging.h	Sat Mar 08 21:04:41 2008 -0800
    18.3 @@ -0,0 +1,23 @@
    18.4 +//
    18.5 +//  Logging.h
    18.6 +//  MYUtilities
    18.7 +//
    18.8 +//  Created by Jens Alfke on 1/5/08.
    18.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
   18.10 +//
   18.11 +
   18.12 +#import <Cocoa/Cocoa.h>
   18.13 +
   18.14 +
   18.15 +NSString* LOC( NSString *key );     // Localized string lookup
   18.16 +
   18.17 +
   18.18 +#define Log(FMT,ARGS...) do{if(__builtin_expect(gShouldLog,0)) _Log(FMT,##ARGS);}while(0)
   18.19 +#define Warn Warn
   18.20 +
   18.21 +void AlwaysLog( NSString *msg, ... ) __attribute__((format(__NSString__, 1, 2)));
   18.22 +
   18.23 +
   18.24 +extern int gShouldLog;
   18.25 +void _Log( NSString *msg, ... ) __attribute__((format(__NSString__, 1, 2)));
   18.26 +void Warn( NSString *msg, ... ) __attribute__((format(__NSString__, 1, 2)));
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/Logging.m	Sat Mar 08 21:04:41 2008 -0800
    19.3 @@ -0,0 +1,96 @@
    19.4 +//
    19.5 +//  Logging.m
    19.6 +//  MYUtilities
    19.7 +//
    19.8 +//  Created by Jens Alfke on 1/5/08.
    19.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
   19.10 +//
   19.11 +
   19.12 +#import "Logging.h"
   19.13 +#import <unistd.h>
   19.14 +#include <fcntl.h>
   19.15 +#include <sys/param.h>
   19.16 +
   19.17 +
   19.18 +NSString* LOC( NSString *key )     // Localized string lookup
   19.19 +{
   19.20 +    NSString *value = [[NSBundle mainBundle] localizedStringForKey:key value:nil table:nil];
   19.21 +    if( value == key ) {
   19.22 +        Warn(@"No localized string for '%@' in Localizable.strings!",key);
   19.23 +        value = [key uppercaseString];
   19.24 +    }
   19.25 +    return value;
   19.26 +}
   19.27 +
   19.28 +
   19.29 +int gShouldLog = -1;
   19.30 +
   19.31 +
   19.32 +static BOOL isConsole( int fd )
   19.33 +{
   19.34 +    if( isatty(fd) )
   19.35 +        return YES;
   19.36 +    char path[MAXPATHLEN];
   19.37 +    if( fcntl(fd, F_GETPATH, path) == -1 )
   19.38 +        return NO;
   19.39 +    return YES;
   19.40 +}
   19.41 +
   19.42 +
   19.43 +static void _Logv( NSString *msg, va_list args )
   19.44 +{
   19.45 +    if( isConsole(STDERR_FILENO) ) {
   19.46 +        NSAutoreleasePool *pool = [NSAutoreleasePool new];
   19.47 +        static NSDateFormatter *sTimestampFormat;
   19.48 +        if( ! sTimestampFormat ) {
   19.49 +            sTimestampFormat = [[NSDateFormatter alloc] init];
   19.50 +            sTimestampFormat.dateFormat = @"HH:mm:ss.SSS";
   19.51 +        }
   19.52 +        NSDate *now = [[NSDate alloc] init];
   19.53 +        NSString *timestamp = [sTimestampFormat stringFromDate: now];
   19.54 +        [now release];
   19.55 +        msg = [[NSString alloc] initWithFormat: msg arguments: args];
   19.56 +        NSString *finalMsg = [[NSString alloc] initWithFormat: @"%@| %@\n", timestamp,msg];
   19.57 +        fputs([finalMsg UTF8String], stderr);
   19.58 +        [finalMsg release];
   19.59 +        [msg release];
   19.60 +        [pool drain];
   19.61 +    } else
   19.62 +        NSLogv(msg,args);
   19.63 +}
   19.64 +
   19.65 +
   19.66 +void AlwaysLog( NSString *msg, ... )
   19.67 +{
   19.68 +    va_list args;
   19.69 +    va_start(args,msg);
   19.70 +    _Logv(msg,args);
   19.71 +    va_end(args);
   19.72 +}
   19.73 +
   19.74 +
   19.75 +void _Log( NSString *msg, ... )
   19.76 +{
   19.77 +    if( gShouldLog == -1 )
   19.78 +        gShouldLog = [[NSUserDefaults standardUserDefaults] boolForKey: @"Log"];
   19.79 +    
   19.80 +    if( gShouldLog ) {
   19.81 +        va_list args;
   19.82 +        va_start(args,msg);
   19.83 +        _Logv(msg,args);
   19.84 +        va_end(args);
   19.85 +    }
   19.86 +}
   19.87 +
   19.88 +
   19.89 +void Warn( NSString *msg, ... )
   19.90 +{
   19.91 +    msg = [@"WARNING*** " stringByAppendingString: msg];
   19.92 +    
   19.93 +    va_list args;
   19.94 +    va_start(args,msg);
   19.95 +    _Logv(msg,args);
   19.96 +    va_end(args);
   19.97 +}
   19.98 +
   19.99 +
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/Target.h	Sat Mar 08 21:04:41 2008 -0800
    20.3 @@ -0,0 +1,17 @@
    20.4 +//
    20.5 +//  Target.h
    20.6 +//  MYUtilities
    20.7 +//
    20.8 +//  Created by Jens Alfke on 2/11/08.
    20.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
   20.10 +//
   20.11 +
   20.12 +#import <Cocoa/Cocoa.h>
   20.13 +
   20.14 +
   20.15 +#define $target(RCVR,METHOD)    _mktarget((RCVR),@selector(METHOD))
   20.16 +
   20.17 +id $calltarget( NSInvocation *target, id sender );
   20.18 +
   20.19 +
   20.20 +NSInvocation* _mktarget( id rcvr, SEL action );
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/Target.m	Sat Mar 08 21:04:41 2008 -0800
    21.3 @@ -0,0 +1,53 @@
    21.4 +//
    21.5 +//  Target.m
    21.6 +//  MYUtilities
    21.7 +//
    21.8 +//  Created by Jens Alfke on 2/11/08.
    21.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
   21.10 +//
   21.11 +
   21.12 +#import "Target.h"
   21.13 +
   21.14 +
   21.15 +NSInvocation* _mktarget( id rcvr, SEL action )
   21.16 +{
   21.17 +    NSMethodSignature *sig = [rcvr methodSignatureForSelector: action];
   21.18 +    CAssert(sig,@"%@<%p> does not respond to %@",[rcvr class],rcvr,NSStringFromSelector(action));
   21.19 +    CAssert(sig.numberOfArguments==3,
   21.20 +           @"-[%@ %@] can't be used as a target because it takes >1 param",
   21.21 +           [rcvr class],NSStringFromSelector(action));
   21.22 +    CAssert(0==strcmp([sig getArgumentTypeAtIndex: 2],"@"),
   21.23 +           @"-[%@ %@] can't be used as a target because it takes a non-object param",
   21.24 +           [rcvr class],NSStringFromSelector(action));
   21.25 +    NSInvocation *inv = [NSInvocation invocationWithMethodSignature: sig];
   21.26 +    inv.target = rcvr;
   21.27 +    inv.selector = action;
   21.28 +    return inv;
   21.29 +}
   21.30 +
   21.31 +
   21.32 +id $calltarget( NSInvocation *target, id param )
   21.33 +{
   21.34 +    if( target && target.target ) {
   21.35 +        [target setArgument: &param atIndex: 2];
   21.36 +        [target invoke];
   21.37 +        
   21.38 +        NSMethodSignature *sig = target.methodSignature;
   21.39 +        NSUInteger returnLength = sig.methodReturnLength;
   21.40 +        if( returnLength==0 )
   21.41 +            return nil; // void
   21.42 +        else {
   21.43 +            const char *returnType = sig.methodReturnType;
   21.44 +            if( returnType[0]=='@' ) {
   21.45 +                id returnObject;
   21.46 +                [target getReturnValue: &returnObject];
   21.47 +                return returnObject;
   21.48 +            } else {
   21.49 +                UInt8 returnBuffer[returnLength];
   21.50 +                [target getReturnValue: &returnBuffer];
   21.51 +                return [NSValue valueWithBytes: &returnBuffer objCType: returnType];
   21.52 +            }
   21.53 +        }
   21.54 +    } else
   21.55 +        return nil;
   21.56 +}
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/Test.h	Sat Mar 08 21:04:41 2008 -0800
    22.3 @@ -0,0 +1,96 @@
    22.4 +//
    22.5 +//  Test.h
    22.6 +//  MYUtilities
    22.7 +//
    22.8 +//  Created by Jens Alfke on 1/5/08.
    22.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
   22.10 +//
   22.11 +
   22.12 +#import <Foundation/Foundation.h>
   22.13 +#import "CollectionUtils.h"
   22.14 +
   22.15 +
   22.16 +/** Call this first thing in main() to run tests.
   22.17 +    This function is a no-op if the DEBUG macro is not defined (i.e. in a release build).
   22.18 +    At runtime, to cause a particular test "X" to run, add a command-line argument "Test_X".
   22.19 +    To run all tests, add the argument "Test_All".
   22.20 +    To run only tests without starting the main program, add the argument "Test_Only". */
   22.21 +#if DEBUG
   22.22 +void RunTestCases( int argc, const char **argv );
   22.23 +#else
   22.24 +#define RunTestCases(ARGC,ARGV)
   22.25 +#endif
   22.26 +
   22.27 +/** The TestCase() macro declares a test case.
   22.28 +    Its argument is a name for the test case (without quotes), and it's followed with a block
   22.29 +    of code implementing the test.
   22.30 +    The code should raise an exception if anything fails.
   22.31 +    The CAssert, CAssertEqual and CAssertEq macros, below, are the most useful way to do this.
   22.32 +    A test case can register a dependency on another test case by calling RequireTestCase().
   22.33 +    Example:
   22.34 +        TestCase(MyLib) {
   22.35 +            RequireTestCase("LibIDependOn");
   22.36 +            CAssertEq( myFunction(), 12345 );
   22.37 +        }
   22.38 +    Test cases are disabled if the DEBUG macro is not defined (i.e. in a release build). */
   22.39 +#if DEBUG
   22.40 +#define TestCase(NAME)      void Test_##NAME(void); \
   22.41 +                            struct TestCaseLink linkToTest##NAME = {&Test_##NAME,#NAME}; \
   22.42 +                            __attribute__((constructor)) static void registerTestCase##NAME() \
   22.43 +                                {linkToTest##NAME.next = gAllTestCases; gAllTestCases=&linkToTest##NAME; } \
   22.44 +                            void Test_##NAME(void)
   22.45 +#else
   22.46 +#define TestCase(NAME)      __attribute__((unused)) static void Test_##NAME(void)
   22.47 +#endif
   22.48 +
   22.49 +/** Can call this in a test case to indicate a prerequisite.
   22.50 +    The prerequisite test will be run first, and if it fails, the current test case will be skipped. */
   22.51 +#define RequireTestCase(NAME)   _RequireTestCase(#NAME)
   22.52 +void _RequireTestCase( const char *name );
   22.53 +
   22.54 +
   22.55 +
   22.56 +/** General-purpose assertions, replacing NSAssert etc.. You can use these outside test cases. */
   22.57 +
   22.58 +#define Assert(COND,MSG...)    do{ if( __builtin_expect(!(COND),NO) ) \
   22.59 +                                    _AssertFailed(self,(const char*)_cmd, __FILE__, __LINE__,\
   22.60 +                                                  #COND,##MSG,NULL); }while(0)
   22.61 +#define CAssert(COND,MSG...)    do{ if( __builtin_expect(!(COND),NO) ) \
   22.62 +                                    _AssertFailed(nil, __PRETTY_FUNCTION__, __FILE__, __LINE__,\
   22.63 +                                                  #COND,##MSG,NULL); }while(0)
   22.64 +
   22.65 +#define AssertEqual(VAL,EXPECTED)   do{ id _val = VAL, _expected = EXPECTED;\
   22.66 +                                        Assert(_val==_expected || [_val isEqual: _expected], @"Unexpected value for %s: %@ (expected %@)", #VAL,_val,_expected); \
   22.67 +                                    }while(0)
   22.68 +#define CAssertEqual(VAL,EXPECTED)  do{ id _val = (VAL), _expected = (EXPECTED);\
   22.69 +                                        CAssert(_val==_expected || [_val isEqual: _expected], @"Unexpected value for %s: %@ (expected %@)", #VAL,_val,_expected); \
   22.70 +                                    }while(0)
   22.71 +
   22.72 +// AssertEq is for scalars (int, float...)
   22.73 +#define AssertEq(VAL,EXPECTED)  do{ typeof(VAL) _val = VAL; typeof(EXPECTED) _expected = EXPECTED;\
   22.74 +                                    Assert(_val==_expected, @"Unexpected value for %s: %@ (expected %@)", #VAL,$object(_val),$object(_expected)); \
   22.75 +                                }while(0)
   22.76 +#define CAssertEq(VAL,EXPECTED) do{ typeof(VAL) _val = VAL; typeof(EXPECTED) _expected = EXPECTED;\
   22.77 +                                    CAssert(_val==_expected, @"Unexpected value for %s: %@ (expected %@)", #VAL,$object(_val),$object(_expected)); \
   22.78 +                                }while(0)
   22.79 +
   22.80 +
   22.81 +#pragma mark -
   22.82 +#pragma mark EXCEPTION UTILITIES:
   22.83 +
   22.84 +@interface NSException (MooseyardUtil)
   22.85 +/** Returns a textual, human-readable backtrace of the point where the exception was thrown. */
   22.86 +- (NSString*) my_callStack;
   22.87 +@end
   22.88 +
   22.89 +
   22.90 +
   22.91 +// Nasty internals ...
   22.92 +#if DEBUG
   22.93 +void _RunTestCase( void (*testptr)(), const char *name );
   22.94 +
   22.95 +struct TestCaseLink {void (*testptr)(); const char *name; BOOL passed; struct TestCaseLink *next;};
   22.96 +extern struct TestCaseLink *gAllTestCases;
   22.97 +#endif DEBUG
   22.98 +void _AssertFailed( id rcvr, const char *selOrFn, const char *sourceFile, int sourceLine,
   22.99 +                   const char *condString, NSString *message, ... ) __attribute__((noreturn));
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/Test.m	Sat Mar 08 21:04:41 2008 -0800
    23.3 @@ -0,0 +1,203 @@
    23.4 +//
    23.5 +//  Test.m
    23.6 +//  MYUtilities
    23.7 +//
    23.8 +//  Created by Jens Alfke on 1/5/08.
    23.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
   23.10 +//
   23.11 +
   23.12 +#import "Test.h"
   23.13 +#import <unistd.h>
   23.14 +
   23.15 +#if DEBUG
   23.16 +
   23.17 +struct TestCaseLink *gAllTestCases;
   23.18 +static int sPassed, sFailed;
   23.19 +
   23.20 +static BOOL RunTestCase( struct TestCaseLink *test )
   23.21 +{
   23.22 +    if( test->testptr ) {
   23.23 +        NSAutoreleasePool *pool = [NSAutoreleasePool new];
   23.24 +        Log(@"=== Testing %s ...",test->name);
   23.25 +        @try{
   23.26 +            test->testptr();
   23.27 +            Log(@"√√√ %s passed\n\n",test->name);
   23.28 +            test->passed = YES;
   23.29 +            sPassed++;
   23.30 +        }@catch( NSException *x ) {
   23.31 +            if( [x.name isEqualToString: @"TestCaseSkipped"] )
   23.32 +                Log(@"... skipping test %s since %@\n\n", test->name, x.reason);
   23.33 +            else {
   23.34 +                Log(@"XXX FAILED test case '%s' due to:\nException: %@\n%@\n\n", 
   23.35 +                      test->name,x,x.my_callStack);
   23.36 +                sFailed++;
   23.37 +            }
   23.38 +        }@finally{
   23.39 +            [pool drain];
   23.40 +            test->testptr = NULL;       // prevents test from being run again
   23.41 +        }
   23.42 +    }
   23.43 +    return test->passed;
   23.44 +}
   23.45 +
   23.46 +
   23.47 +static BOOL RunTestCaseNamed( const char *name )
   23.48 +{
   23.49 +    for( struct TestCaseLink *test = gAllTestCases; test; test=test->next )
   23.50 +        if( strcmp(name,test->name)==0 ) {
   23.51 +            return RunTestCase(test);
   23.52 +        }
   23.53 +    Log(@"... WARNING: Could not find test case named '%s'\n\n",name);
   23.54 +    return NO;
   23.55 +}
   23.56 +
   23.57 +
   23.58 +void _RequireTestCase( const char *name )
   23.59 +{
   23.60 +    if( ! RunTestCaseNamed(name) ) {
   23.61 +        [NSException raise: @"TestCaseSkipped" 
   23.62 +                    format: @"prerequisite %s failed", name];
   23.63 +    }
   23.64 +}
   23.65 +
   23.66 +
   23.67 +void RunTestCases( int argc, const char **argv )
   23.68 +{
   23.69 +    gShouldLog = YES;
   23.70 +    sPassed = sFailed = 0;
   23.71 +    BOOL stopAfterTests = NO;
   23.72 +    for( int i=1; i<argc; i++ ) {
   23.73 +        const char *arg = argv[i];
   23.74 +        if( strncmp(arg,"Test_",5)==0 ) {
   23.75 +            arg += 5;
   23.76 +            if( strcmp(arg,"Only")==0 )
   23.77 +                stopAfterTests = YES;
   23.78 +            else if( strcmp(arg,"All") == 0 ) {
   23.79 +                for( struct TestCaseLink *link = gAllTestCases; link; link=link->next )
   23.80 +                    RunTestCase(link);
   23.81 +            } else {
   23.82 +                RunTestCaseNamed(arg);
   23.83 +            }
   23.84 +        }
   23.85 +    }
   23.86 +    if( sPassed>0 || sFailed>0 || stopAfterTests ) {
   23.87 +        if( sFailed==0 )
   23.88 +            Log(@"√√√√√√ ALL %i TESTS PASSED √√√√√√", sPassed);
   23.89 +        else {
   23.90 +            Log(@"****** %i TESTS FAILED, %i PASSED ******", sFailed,sPassed);
   23.91 +            exit(1);
   23.92 +        }
   23.93 +        if( stopAfterTests ) {
   23.94 +            Log(@"Stopping after tests ('Test_Only' arg detected)");
   23.95 +            exit(0);
   23.96 +        }
   23.97 +    }
   23.98 +}
   23.99 +
  23.100 +
  23.101 +#endif DEBUG
  23.102 +
  23.103 +
  23.104 +#pragma mark -
  23.105 +#pragma mark ASSERTION FAILURE HANDLER:
  23.106 +
  23.107 +
  23.108 +void _AssertFailed( id rcvr, const char *selOrFn, const char *sourceFile, int sourceLine,
  23.109 +                    const char *condString, NSString *message, ... )
  23.110 +{
  23.111 +    if( message ) {
  23.112 +        va_list args;
  23.113 +        va_start(args,message);
  23.114 +        message = [[[NSString alloc] initWithFormat: message arguments: args] autorelease];
  23.115 +        va_end(args);
  23.116 +    } else
  23.117 +        message = [NSString stringWithUTF8String: condString];
  23.118 +    
  23.119 +    if( rcvr )
  23.120 +        [[NSAssertionHandler currentHandler] handleFailureInMethod: (SEL)selOrFn
  23.121 +                                                            object: rcvr 
  23.122 +                                                              file: [NSString stringWithUTF8String: sourceFile]
  23.123 +                                                        lineNumber: sourceLine 
  23.124 +                                                       description: @"%@", message];
  23.125 +    else
  23.126 +        [[NSAssertionHandler currentHandler] handleFailureInFunction: [NSString stringWithUTF8String:selOrFn]
  23.127 +                                                                file: [NSString stringWithUTF8String: sourceFile]
  23.128 +                                                          lineNumber: sourceLine 
  23.129 +                                                         description: @"%@", message];
  23.130 +    abort(); // unreachable, but appeases compiler
  23.131 +}
  23.132 +
  23.133 +
  23.134 +#pragma mark -
  23.135 +#pragma mark EXCEPTION BACKTRACES:
  23.136 +
  23.137 +
  23.138 +@implementation NSException (MooseyardUtil)
  23.139 +
  23.140 +
  23.141 +- (NSArray*) my_callStackReturnAddresses
  23.142 +{
  23.143 +    // On 10.5 or later, can get the backtrace:
  23.144 +    if( [self respondsToSelector: @selector(callStackReturnAddresses)] )
  23.145 +        return [self valueForKey: @"callStackReturnAddresses"];
  23.146 +    else
  23.147 +        return nil;
  23.148 +}
  23.149 +
  23.150 +- (NSArray*) my_callStackReturnAddressesSkipping: (unsigned)skip limit: (unsigned)limit
  23.151 +{
  23.152 +    NSArray *addresses = [self my_callStackReturnAddresses];
  23.153 +    if( addresses ) {
  23.154 +        unsigned n = [addresses count];
  23.155 +        skip = MIN(skip,n);
  23.156 +        limit = MIN(limit,n-skip);
  23.157 +        addresses = [addresses subarrayWithRange: NSMakeRange(skip,limit)];
  23.158 +    }
  23.159 +    return addresses;
  23.160 +}
  23.161 +
  23.162 +
  23.163 +- (NSString*) my_callStack
  23.164 +{
  23.165 +    NSArray *addresses = [self my_callStackReturnAddressesSkipping: 2 limit: 15];
  23.166 +    if (!addresses)
  23.167 +        return nil;
  23.168 +    
  23.169 +    // We pipe the hex return addresses through the 'atos' tool to get symbolic names:
  23.170 +    // Adapted from <http://paste.lisp.org/display/47196>:
  23.171 +    NSMutableString *cmd = [NSMutableString stringWithFormat: @"/usr/bin/atos -p %d", getpid()];
  23.172 +    NSValue *addr;
  23.173 +    foreach(addr,addresses) {
  23.174 +        [cmd appendFormat: @" %p", [addr pointerValue]];
  23.175 +    }
  23.176 +    FILE *file = popen( [cmd UTF8String], "r" );
  23.177 +    if( ! file )
  23.178 +        return nil;
  23.179 +    
  23.180 +    NSMutableData *output = [NSMutableData data];
  23.181 +    char buffer[512];
  23.182 +    size_t length;
  23.183 +    while ((length = fread( buffer, 1, sizeof( buffer ), file ) ))
  23.184 +        [output appendBytes: buffer length: length];
  23.185 +    pclose( file );
  23.186 +    NSString *outStr = [[[NSString alloc] initWithData: output encoding: NSUTF8StringEncoding] autorelease];
  23.187 +    
  23.188 +    NSMutableString *result = [NSMutableString string];
  23.189 +    NSString *line;
  23.190 +    foreach( line, [outStr componentsSeparatedByString: @"\n"] ) {
  23.191 +        // Skip  frames that are part of the exception/assertion handling itself:
  23.192 +        if( [line hasPrefix: @"-[NSAssertionHandler"] || [line hasPrefix: @"+[NSException"] 
  23.193 +                || [line hasPrefix: @"-[NSException"] || [line hasPrefix: @"_AssertFailed"] )
  23.194 +            continue;
  23.195 +        if( result.length )
  23.196 +            [result appendString: @"\n"];
  23.197 +        [result appendString: @"\t"];
  23.198 +        [result appendString: line];
  23.199 +        // Don't show the "__start" frame below "main":
  23.200 +        if( [line hasPrefix: @"main "] )
  23.201 +            break;
  23.202 +    }
  23.203 +    return result;
  23.204 +}
  23.205 +
  23.206 +@end
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/TimeIntervalFormatter.h	Sat Mar 08 21:04:41 2008 -0800
    24.3 @@ -0,0 +1,19 @@
    24.4 +//
    24.5 +//  TimeIntervalFormatter.h
    24.6 +//  MYUtilities
    24.7 +//
    24.8 +//  Copyright 2008 Jens Alfke. All rights reserved.
    24.9 +//
   24.10 +
   24.11 +#import <Cocoa/Cocoa.h>
   24.12 +
   24.13 +
   24.14 +@interface TimeIntervalFormatter : NSFormatter
   24.15 +{
   24.16 +    BOOL _showsMinutes, _showsFractionalSeconds;
   24.17 +}
   24.18 +
   24.19 +- (void) setShowsMinutes: (BOOL)showsMinutes;
   24.20 +- (void) setShowsFractionalSeconds: (BOOL)showsFractionalSeconds;
   24.21 +
   24.22 +@end
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/TimeIntervalFormatter.m	Sat Mar 08 21:04:41 2008 -0800
    25.3 @@ -0,0 +1,93 @@
    25.4 +//
    25.5 +//  TimeIntervalFormatter.m
    25.6 +//  MYUtilities
    25.7 +//
    25.8 +//  Copyright 2008 Jens Alfke. All rights reserved.
    25.9 +//
   25.10 +
   25.11 +#import "TimeIntervalFormatter.h"
   25.12 +
   25.13 +
   25.14 +@implementation TimeIntervalFormatter
   25.15 +
   25.16 +
   25.17 +- (void) awakeFromNib
   25.18 +{
   25.19 +    _showsMinutes = YES;
   25.20 +}
   25.21 +
   25.22 +- (void) setShowsMinutes: (BOOL)show                {_showsMinutes = show;}
   25.23 +- (void) setShowsFractionalSeconds: (BOOL)show      {_showsFractionalSeconds = show;}
   25.24 +
   25.25 +
   25.26 +- (NSString*) stringForObjectValue: (id)object
   25.27 +{
   25.28 +    if (![object isKindOfClass:[NSNumber class]])
   25.29 +        return nil;
   25.30 +    NSTimeInterval time = [object doubleValue];
   25.31 +    NSString *sign;
   25.32 +    if( time==0.0 )
   25.33 +        return nil;
   25.34 +    else if( time < 0.0 ) {
   25.35 +        sign = @"-";
   25.36 +        time = -time;
   25.37 +    } else
   25.38 +        sign = @"";
   25.39 +    if( ! _showsFractionalSeconds )
   25.40 +        time = floor(time);
   25.41 +    int minutes = (int)floor(time / 60.0);
   25.42 +    if( _showsMinutes || minutes>0 ) {
   25.43 +        double seconds = time - 60.0*minutes;
   25.44 +        return [NSString stringWithFormat: (_showsFractionalSeconds ?@"%@%d:%06.3lf" :@"%@%d:%02.0lf"),
   25.45 +                                           sign,minutes,seconds];
   25.46 +    } else {
   25.47 +        return [NSString stringWithFormat: (_showsFractionalSeconds ?@"%@%.3lf" :@"%@%.0lf"),
   25.48 +                                           sign,time];
   25.49 +    }
   25.50 +}
   25.51 +
   25.52 +
   25.53 +- (BOOL)getObjectValue:(id *)anObject
   25.54 +             forString:(NSString *)string 
   25.55 +      errorDescription:(NSString **)error
   25.56 +{
   25.57 +    NSScanner *scanner = [NSScanner scannerWithString: string];
   25.58 +    [scanner setCharactersToBeSkipped: [NSCharacterSet whitespaceCharacterSet]];
   25.59 +    double seconds;
   25.60 +    if( [scanner isAtEnd] ) {
   25.61 +        seconds = 0.0;
   25.62 +    } else {
   25.63 +        if( ! [scanner scanDouble: &seconds] || seconds<0.0 ) goto error;
   25.64 +        if( [scanner scanString: @":" intoString: NULL] ) {
   25.65 +            double minutes = seconds;
   25.66 +            if( ! [scanner scanDouble: &seconds] || seconds<0.0 ) goto error;
   25.67 +            seconds += 60*minutes;
   25.68 +        }
   25.69 +        if( ! [scanner isAtEnd] ) goto error;
   25.70 +    }
   25.71 +    *anObject = [NSNumber numberWithDouble: seconds];
   25.72 +    return YES;
   25.73 +    
   25.74 +error:
   25.75 +    *anObject = nil;
   25.76 +    if( error )
   25.77 +        *error = @"Not a valid time interval";
   25.78 +    return NO;
   25.79 +}
   25.80 +
   25.81 +
   25.82 +- (BOOL)isPartialStringValid:(NSString **)partialStringPtr 
   25.83 +       proposedSelectedRange:(NSRangePointer)proposedSelRangePtr
   25.84 +              originalString:(NSString *)origString 
   25.85 +       originalSelectedRange:(NSRange)origSelRange 
   25.86 +            errorDescription:(NSString **)error
   25.87 +{
   25.88 +    static NSCharacterSet *sIllegalChars;
   25.89 +    if( ! sIllegalChars )
   25.90 +        sIllegalChars = [[[NSCharacterSet characterSetWithCharactersInString: @"0123456789.:"] 
   25.91 +                                invertedSet] retain];
   25.92 +    return [*partialStringPtr rangeOfCharacterFromSet: sIllegalChars].length == 0;
   25.93 +}
   25.94 +
   25.95 +
   25.96 +@end
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/ValueArray.h	Sat Mar 08 21:04:41 2008 -0800
    26.3 @@ -0,0 +1,49 @@
    26.4 +//
    26.5 +//  ValueArray.h
    26.6 +//  MYUtilities
    26.7 +//
    26.8 +//  Copyright 2008 Jens Alfke. All rights reserved.
    26.9 +//
   26.10 +
   26.11 +#import <Cocoa/Cocoa.h>
   26.12 +
   26.13 +
   26.14 +@interface ValueArray : NSObject <NSCoding>
   26.15 +{
   26.16 +    unsigned _count;
   26.17 +    size_t _valueSize;
   26.18 +}
   26.19 +
   26.20 ++ (ValueArray*) valueArrayWithCount: (unsigned)count valueSize: (size_t)valueSize;
   26.21 +
   26.22 +- (unsigned) count;
   26.23 +- (size_t) valueSize;
   26.24 +- (const void*) valueAtIndex: (unsigned)i;
   26.25 +- (void) getValue: (void*)value atIndex: (unsigned)i;
   26.26 +- (void) setValue: (const void*)value atIndex: (unsigned)i;
   26.27 +
   26.28 +@end
   26.29 +
   26.30 +
   26.31 +#define DeclareValueArrayOf(CAPTYPE,TYPE) \
   26.32 +            @interface CAPTYPE##Array : ValueArray \
   26.33 +            + (CAPTYPE##Array*) TYPE##ArrayWithCount: (unsigned)count; \
   26.34 +            - (TYPE) TYPE##AtIndex: (unsigned)index; \
   26.35 +            - (void) set##CAPTYPE: (TYPE)value atIndex: (unsigned)index; \
   26.36 +            @end
   26.37 +
   26.38 +#define ImplementValueArrayOf(CAPTYPE,TYPE) \
   26.39 +            @implementation CAPTYPE##Array \
   26.40 +            + (CAPTYPE##Array*) TYPE##Array##WithCount: (unsigned)count \
   26.41 +                {return (id)[super valueArrayWithCount: count valueSize: sizeof(TYPE)];} \
   26.42 +            - (TYPE) TYPE##AtIndex: (unsigned)i; \
   26.43 +                {NSParameterAssert(i<_count); return ((const TYPE*)object_getIndexedIvars(self))[i];}\
   26.44 +            - (void) set##CAPTYPE: (TYPE)value atIndex: (unsigned)i \
   26.45 +                {NSParameterAssert(i<_count); ((TYPE*)object_getIndexedIvars(self))[i] = value;}\
   26.46 +            @end
   26.47 +
   26.48 +
   26.49 +// Declares IntArray class
   26.50 +DeclareValueArrayOf(Int,int)
   26.51 +
   26.52 +DeclareValueArrayOf(Double,double)
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/ValueArray.m	Sat Mar 08 21:04:41 2008 -0800
    27.3 @@ -0,0 +1,93 @@
    27.4 +//
    27.5 +//  ValueArray.m
    27.6 +//  MYUtilities
    27.7 +//
    27.8 +//  Copyright 2008 Jens Alfke. All rights reserved.
    27.9 +//
   27.10 +
   27.11 +#import "ValueArray.h"
   27.12 +
   27.13 +
   27.14 +@implementation ValueArray
   27.15 +
   27.16 +
   27.17 +- (id) initWithCount: (unsigned)count valueSize: (size_t)valueSize
   27.18 +{
   27.19 +    self = [super init];
   27.20 +    if( self ) {
   27.21 +        _count = count;
   27.22 +        _valueSize = valueSize;
   27.23 +    }
   27.24 +    return self;
   27.25 +}
   27.26 +
   27.27 ++ (ValueArray*) valueArrayWithCount: (unsigned)count valueSize: (size_t)valueSize
   27.28 +{
   27.29 +    return [[(ValueArray*)NSAllocateObject(self,count*valueSize,nil)
   27.30 +                            initWithCount: count valueSize: valueSize] 
   27.31 +                                autorelease];
   27.32 +}
   27.33 +
   27.34 +- (unsigned) count      {return _count;}
   27.35 +- (size_t) valueSize    {return _valueSize;}
   27.36 +
   27.37 +- (const void*) valueAtIndex: (unsigned)i
   27.38 +{
   27.39 +    NSParameterAssert(i<_count);
   27.40 +    return (const char*)object_getIndexedIvars(self) + i*_valueSize;
   27.41 +}
   27.42 +
   27.43 +- (void) getValue: (void*)value atIndex: (unsigned)i
   27.44 +{
   27.45 +    NSParameterAssert(i<_count);
   27.46 +    NSParameterAssert(value!=NULL);
   27.47 +    memcpy(value, object_getIndexedIvars(self) + i*_valueSize, _valueSize);
   27.48 +}
   27.49 +
   27.50 +- (void) setValue: (const void*)value atIndex: (unsigned)i
   27.51 +{
   27.52 +    NSParameterAssert(i<_count);
   27.53 +    NSParameterAssert(value!=NULL);
   27.54 +    memcpy(object_getIndexedIvars(self) + i*_valueSize, value, _valueSize);
   27.55 +}
   27.56 +
   27.57 +
   27.58 +
   27.59 +- (id)initWithCoder:(NSCoder *)decoder
   27.60 +{
   27.61 +    NSParameterAssert([decoder allowsKeyedCoding]);
   27.62 +    NSKeyedUnarchiver *arch = (NSKeyedUnarchiver*)decoder;
   27.63 +    unsigned count = [arch decodeIntForKey: @"count"];
   27.64 +    size_t valueSize = [arch decodeIntForKey: @"valueSize"];
   27.65 +    
   27.66 +    [super release];
   27.67 +    self = [[[self class] valueArrayWithCount: count valueSize: valueSize] retain];
   27.68 +    if( self ) {
   27.69 +        unsigned nBytes;
   27.70 +        const void *bytes = [arch decodeBytesForKey: @"values" returnedLength: &nBytes];
   27.71 +        NSAssert(nBytes==count*valueSize,@"Value size mismatch");
   27.72 +        memcpy( object_getIndexedIvars(self), bytes, nBytes );
   27.73 +    }
   27.74 +    return self;
   27.75 +}
   27.76 +
   27.77 +
   27.78 +- (void)encodeWithCoder:(NSCoder *)coder
   27.79 +{
   27.80 +    NSParameterAssert([coder allowsKeyedCoding]);
   27.81 +    NSKeyedArchiver *arch = (NSKeyedArchiver*)coder;
   27.82 +    
   27.83 +    [arch encodeInt: _count forKey: @"count"];
   27.84 +    [arch encodeInt: _valueSize forKey: @"valueSize"];
   27.85 +    [arch encodeBytes: object_getIndexedIvars(self)
   27.86 +               length: _count*_valueSize
   27.87 +               forKey: @"values"];
   27.88 +}    
   27.89 +
   27.90 +
   27.91 +@end
   27.92 +
   27.93 +
   27.94 +ImplementValueArrayOf(Int,int)
   27.95 +
   27.96 +ImplementValueArrayOf(Double,double)
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/With.h	Sat Mar 08 21:04:41 2008 -0800
    28.3 @@ -0,0 +1,21 @@
    28.4 +//
    28.5 +//  With.h
    28.6 +//  MYUtilities
    28.7 +//
    28.8 +//  Copyright 2008 Jens Alfke. All rights reserved.
    28.9 +//
   28.10 +
   28.11 +#import <Cocoa/Cocoa.h>
   28.12 +
   28.13 +
   28.14 +#define WITH(OBJ)       id __with=[OBJ beginWith]; @try
   28.15 +
   28.16 +#define ENDWITH         @finally{[__with endWith];}
   28.17 +#define CATCHWITH       @catch(NSException *x){id w=__with; __with=nil; _catchWith(w,x);} @finally{[__with endWith];}
   28.18 +
   28.19 +void _catchWith( id with, NSException *x );
   28.20 +
   28.21 +@interface NSAutoreleasePool (With)
   28.22 ++ (NSAutoreleasePool*) beginWith;
   28.23 +- (void) endWith;
   28.24 +@end
   28.25 \ No newline at end of file
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/With.m	Sat Mar 08 21:04:41 2008 -0800
    29.3 @@ -0,0 +1,34 @@
    29.4 +//
    29.5 +//  With.m
    29.6 +//  MYUtilities
    29.7 +//
    29.8 +//  Copyright 2008 Jens Alfke. All rights reserved.
    29.9 +//
   29.10 +
   29.11 +#import "With.h"
   29.12 +#import "Logging.h"
   29.13 +
   29.14 +
   29.15 +@interface NSObject (With)
   29.16 +- (BOOL) endWith: (NSException*)x;
   29.17 +@end
   29.18 +
   29.19 +
   29.20 +void _catchWith( id with, NSException *x )
   29.21 +{
   29.22 +    Warn(@"Exception thrown from WITH(%@) block: %@",[with class],x);
   29.23 +    if( [with respondsToSelector: @selector(endWith:)] ) {
   29.24 +        if( ! [with endWith: x] )
   29.25 +            @throw x;                           // propagate the exception if -endWith: returns NO
   29.26 +    } else {
   29.27 +        [with endWith];
   29.28 +    }
   29.29 +}
   29.30 +
   29.31 +
   29.32 +
   29.33 +@implementation NSAutoreleasePool (With)
   29.34 ++ (NSAutoreleasePool*) beginWith    {return [self new];}
   29.35 +- (void) endWith                    {[self drain];}
   29.36 +- (BOOL) endWith: (NSException*)x   {[self drain]; return YES;}
   29.37 +@end
   29.38 \ No newline at end of file
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/iChatBridge.h	Sat Mar 08 21:04:41 2008 -0800
    30.3 @@ -0,0 +1,460 @@
    30.4 +/*
    30.5 + * iChat.h
    30.6 + */
    30.7 +
    30.8 +#import <AppKit/AppKit.h>
    30.9 +#import <ScriptingBridge/ScriptingBridge.h>
   30.10 +
   30.11 +
   30.12 +@class iChatItem, iChatApplication, iChatColor, iChatDocument, iChatWindow, iChatRichText, iChatCharacter, iChatParagraph, iChatWord, iChatAttributeRun, iChatAttachment, iChatApplication, iChatBuddy, iChatService, iChatChat, iChatTextChat, iChatAudioChat, iChatVideoChat, iChatFileTransfer;
   30.13 +
   30.14 +typedef enum {
   30.15 +	iChatSaveOptionsYes = 'yes ' /* Save the file. */,
   30.16 +	iChatSaveOptionsNo = 'no  ' /* Do not save the file. */,
   30.17 +	iChatSaveOptionsAsk = 'ask ' /* Ask the user whether or not to save the file. */
   30.18 +} iChatSaveOptions;
   30.19 +
   30.20 +typedef enum {
   30.21 +	iChatInviteTypeAudioInvitation = 'acon',
   30.22 +	iChatInviteTypeTextChatInvitation = 'tcon',
   30.23 +	iChatInviteTypeVideoInvitation = 'vcon'
   30.24 +} iChatInviteType;
   30.25 +
   30.26 +typedef enum {
   30.27 +	iChatAccountStatusAvailable = 'aval',
   30.28 +	iChatAccountStatusAway = 'away',
   30.29 +	iChatAccountStatusOffline = 'offl',
   30.30 +	iChatAccountStatusInvisible = 'invs',
   30.31 +	iChatAccountStatusIdle = 'idle',
   30.32 +	iChatAccountStatusUnknown = 'unkn'
   30.33 +} iChatAccountStatus;
   30.34 +
   30.35 +typedef enum {
   30.36 +	iChatMyStatusAway = 'away',
   30.37 +	iChatMyStatusAvailable = 'aval',
   30.38 +	iChatMyStatusOffline = 'offl',
   30.39 +	iChatMyStatusInvisible = 'invs'
   30.40 +} iChatMyStatus;
   30.41 +
   30.42 +typedef enum {
   30.43 +	iChatConnectionStatusDisconnecting = 'dcng',
   30.44 +	iChatConnectionStatusConnected = 'conn',
   30.45 +	iChatConnectionStatusConnecting = 'cong',
   30.46 +	iChatConnectionStatusDisconnected = 'dcon'
   30.47 +} iChatConnectionStatus;
   30.48 +
   30.49 +typedef enum {
   30.50 +	iChatCapabilitiesVideoChat = 'vcon',
   30.51 +	iChatCapabilitiesAudioChat = 'acon',
   30.52 +	iChatCapabilitiesMultipersonVideo = 'mwvc',
   30.53 +	iChatCapabilitiesMultipersonAudio = 'mwac'
   30.54 +} iChatCapabilities;
   30.55 +
   30.56 +typedef enum {
   30.57 +	iChatScreenSharingNone = 'ssns',
   30.58 +	iChatScreenSharingLocalScreen = 'ssls',
   30.59 +	iChatScreenSharingRemoteScreen = 'ssrs'
   30.60 +} iChatScreenSharing;
   30.61 +
   30.62 +typedef enum {
   30.63 +	iChatServiceTypeAIM = 'saim',
   30.64 +	iChatServiceTypeBonjour = 'ssub',
   30.65 +	iChatServiceTypeJabber = 'sjab'
   30.66 +} iChatServiceType;
   30.67 +
   30.68 +typedef enum {
   30.69 +	iChatDirectionIncoming = 'FTic',
   30.70 +	iChatDirectionOutgoing = 'FTog'
   30.71 +} iChatDirection;
   30.72 +
   30.73 +typedef enum {
   30.74 +	iChatTransferStatusPreparing = 'FTsp',
   30.75 +	iChatTransferStatusWaiting = 'FTsw',
   30.76 +	iChatTransferStatusTransferring = 'FTsg',
   30.77 +	iChatTransferStatusFinalizing = 'FTsz',
   30.78 +	iChatTransferStatusFinished = 'FTsf',
   30.79 +	iChatTransferStatusFailed = 'FTse'
   30.80 +} iChatTransferStatus;
   30.81 +
   30.82 +typedef enum {
   30.83 +	iChatAvTypeAudio = 'ICAa',
   30.84 +	iChatAvTypeVideo = 'ICAv'
   30.85 +} iChatAvType;
   30.86 +
   30.87 +typedef enum {
   30.88 +	iChatChatTypeInstantMessage = 'ICim',
   30.89 +	iChatChatTypeDirectInstantMessage = 'ICdi',
   30.90 +	iChatChatTypeChatRoom = 'ICcr'
   30.91 +} iChatChatType;
   30.92 +
   30.93 +typedef enum {
   30.94 +	iChatJoinStateNotJoined = 'ICJc',
   30.95 +	iChatJoinStateJoining = 'ICJg',
   30.96 +	iChatJoinStateJoined = 'ICJj'
   30.97 +} iChatJoinState;
   30.98 +
   30.99 +typedef enum {
  30.100 +	iChatAvConnectionStatusInvited = 'ICAi',
  30.101 +	iChatAvConnectionStatusWaiting = 'ICAw',
  30.102 +	iChatAvConnectionStatusConnecting = 'ICAx',
  30.103 +	iChatAvConnectionStatusConnected = 'ICAc',
  30.104 +	iChatAvConnectionStatusEnded = 'ICAn'
  30.105 +} iChatAvConnectionStatus;
  30.106 +
  30.107 +
  30.108 +
  30.109 +/*
  30.110 + * Standard Suite
  30.111 + */
  30.112 +
  30.113 +// A scriptable object.
  30.114 +@interface iChatItem : SBObject
  30.115 +
  30.116 +@property (copy) NSDictionary *properties;  // All of the object's properties.
  30.117 +
  30.118 +- (void) closeSaving:(iChatSaveOptions)saving savingIn:(NSURL *)savingIn;  // Close a document.
  30.119 +- (void) saveIn:(NSURL *)in_ as:(NSString *)as;  // Save a document.
  30.120 +- (void) delete;  // Delete an object.
  30.121 +- (SBObject *) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties;  // Copy object(s) and put the copies at a new location.
  30.122 +- (BOOL) exists;  // Verify if an object exists.
  30.123 +- (SBObject *) moveTo:(SBObject *)to;  // Move object(s) to a new location.
  30.124 +
  30.125 +@end
  30.126 +
  30.127 +// The application's top-level scripting object.
  30.128 +@interface iChatApplication : SBApplication
  30.129 +
  30.130 +- (SBElementArray *) documents;
  30.131 +- (SBElementArray *) windows;
  30.132 +
  30.133 +@property (copy, readonly) NSString *name;  // The name of the application.
  30.134 +@property (readonly) BOOL frontmost;  // Is this the frontmost (active) application?
  30.135 +@property (copy, readonly) NSString *version;  // The version of the application.
  30.136 +
  30.137 +- (void) open:(NSArray *)x;  // Open a document.
  30.138 +- (void) print:(NSURL *)x;  // Print an object.
  30.139 +- (void) quitSaving:(iChatSaveOptions)saving;  // Quit the application.
  30.140 +- (void) invite:(NSArray *)x to:(id)to withMessage:(NSString *)withMessage;  // Invites a buddy to join an existing chat.
  30.141 +- (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.
  30.142 +- (void) logOut;  // Logs out of a service, or all services if none is specified.
  30.143 +- (void) send:(id)x to:(id)to;  // Sends a message or file to a buddy or to a chat.
  30.144 +- (void) storeRecentPicture;  // Stores the currently set buddy picture into your recent pictures.
  30.145 +- (void) showChatChooserFor:(iChatBuddy *)for_;  // displays a dialog in iChat to start a new chat with the specified buddy
  30.146 +
  30.147 +@end
  30.148 +
  30.149 +// A color.
  30.150 +@interface iChatColor : SBObject
  30.151 +
  30.152 +- (void) closeSaving:(iChatSaveOptions)saving savingIn:(NSURL *)savingIn;  // Close a document.
  30.153 +- (void) saveIn:(NSURL *)in_ as:(NSString *)as;  // Save a document.
  30.154 +- (void) delete;  // Delete an object.
  30.155 +- (SBObject *) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties;  // Copy object(s) and put the copies at a new location.
  30.156 +- (BOOL) exists;  // Verify if an object exists.
  30.157 +- (SBObject *) moveTo:(SBObject *)to;  // Move object(s) to a new location.
  30.158 +
  30.159 +@end
  30.160 +
  30.161 +// An iChat document.
  30.162 +@interface iChatDocument : SBObject
  30.163 +
  30.164 +@property (copy, readonly) NSString *name;  // The document's name.
  30.165 +@property (readonly) BOOL modified;  // Has the document been modified since the last save?
  30.166 +@property (copy, readonly) NSURL *file;  // The document's location on disk.
  30.167 +
  30.168 +- (void) closeSaving:(iChatSaveOptions)saving savingIn:(NSURL *)savingIn;  // Close a document.
  30.169 +- (void) saveIn:(NSURL *)in_ as:(NSString *)as;  // Save a document.
  30.170 +- (void) delete;  // Delete an object.
  30.171 +- (SBObject *) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties;  // Copy object(s) and put the copies at a new location.
  30.172 +- (BOOL) exists;  // Verify if an object exists.
  30.173 +- (SBObject *) moveTo:(SBObject *)to;  // Move object(s) to a new location.
  30.174 +
  30.175 +@end
  30.176 +
  30.177 +// A window.
  30.178 +@interface iChatWindow : SBObject
  30.179 +
  30.180 +@property (copy, readonly) NSString *name;  // The full title of the window.
  30.181 +- (NSInteger) id;  // The unique identifier of the window.
  30.182 +@property NSInteger index;  // The index of the window, ordered front to back.
  30.183 +@property NSRect bounds;  // The bounding rectangle of the window.
  30.184 +@property (readonly) BOOL closeable;  // Whether the window has a close box.
  30.185 +@property (readonly) BOOL minimizable;  // Whether the window can be minimized.
  30.186 +@property BOOL minimized;  // Whether the window is currently minimized.
  30.187 +@property (readonly) BOOL resizable;  // Whether the window can be resized.
  30.188 +@property BOOL visible;  // Whether the window is currently visible.
  30.189 +@property (readonly) BOOL zoomable;  // Whether the window can be zoomed.
  30.190 +@property BOOL zoomed;  // Whether the window is currently zoomed.
  30.191 +@property (copy, readonly) iChatDocument *document;  // The document whose contents are being displayed in the window.
  30.192 +
  30.193 +- (void) closeSaving:(iChatSaveOptions)saving savingIn:(NSURL *)savingIn;  // Close a document.
  30.194 +- (void) saveIn:(NSURL *)in_ as:(NSString *)as;  // Save a document.
  30.195 +- (void) delete;  // Delete an object.
  30.196 +- (SBObject *) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties;  // Copy object(s) and put the copies at a new location.
  30.197 +- (BOOL) exists;  // Verify if an object exists.
  30.198 +- (SBObject *) moveTo:(SBObject *)to;  // Move object(s) to a new location.
  30.199 +
  30.200 +@end
  30.201 +
  30.202 +
  30.203 +
  30.204 +/*
  30.205 + * Text Suite
  30.206 + */
  30.207 +
  30.208 +// Rich (styled) text
  30.209 +@interface iChatRichText : SBObject
  30.210 +
  30.211 +- (SBElementArray *) characters;
  30.212 +- (SBElementArray *) paragraphs;
  30.213 +- (SBElementArray *) words;
  30.214 +- (SBElementArray *) attributeRuns;
  30.215 +- (SBElementArray *) attachments;
  30.216 +
  30.217 +@property (copy) NSColor *color;  // The color of the first character.
  30.218 +@property (copy) NSString *font;  // The name of the font of the first character.
  30.219 +@property double size;  // The size in points of the first character.
  30.220 +
  30.221 +- (void) closeSaving:(iChatSaveOptions)saving savingIn:(NSURL *)savingIn;  // Close a document.
  30.222 +- (void) saveIn:(NSURL *)in_ as:(NSString *)as;  // Save a document.
  30.223 +- (void) delete;  // Delete an object.
  30.224 +- (SBObject *) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties;  // Copy object(s) and put the copies at a new location.
  30.225 +- (BOOL) exists;  // Verify if an object exists.
  30.226 +- (SBObject *) moveTo:(SBObject *)to;  // Move object(s) to a new location.
  30.227 +
  30.228 +@end
  30.229 +
  30.230 +// This subdivides the text into characters.
  30.231 +@interface iChatCharacter : SBObject
  30.232 +
  30.233 +- (SBElementArray *) characters;
  30.234 +- (SBElementArray *) paragraphs;
  30.235 +- (SBElementArray *) words;
  30.236 +- (SBElementArray *) attributeRuns;
  30.237 +- (SBElementArray *) attachments;
  30.238 +
  30.239 +@property (copy) NSColor *color;  // The color of the first character.
  30.240 +@property (copy) NSString *font;  // The name of the font of the first character.
  30.241 +@property NSInteger size;  // The size in points of the first character.
  30.242 +
  30.243 +- (void) closeSaving:(iChatSaveOptions)saving savingIn:(NSURL *)savingIn;  // Close a document.
  30.244 +- (void) saveIn:(NSURL *)in_ as:(NSString *)as;  // Save a document.
  30.245 +- (void) delete;  // Delete an object.
  30.246 +- (SBObject *) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties;  // Copy object(s) and put the copies at a new location.
  30.247 +- (BOOL) exists;  // Verify if an object exists.
  30.248 +- (SBObject *) moveTo:(SBObject *)to;  // Move object(s) to a new location.
  30.249 +
  30.250 +@end
  30.251 +
  30.252 +// This subdivides the text into paragraphs.
  30.253 +@interface iChatParagraph : SBObject
  30.254 +
  30.255 +- (SBElementArray *) characters;
  30.256 +- (SBElementArray *) paragraphs;
  30.257 +- (SBElementArray *) words;
  30.258 +- (SBElementArray *) attributeRuns;
  30.259 +- (SBElementArray *) attachments;
  30.260 +
  30.261 +@property (copy) NSColor *color;  // The color of the first character.
  30.262 +@property (copy) NSString *font;  // The name of the font of the first character.
  30.263 +@property NSInteger size;  // The size in points of the first character.
  30.264 +
  30.265 +- (void) closeSaving:(iChatSaveOptions)saving savingIn:(NSURL *)savingIn;  // Close a document.
  30.266 +- (void) saveIn:(NSURL *)in_ as:(NSString *)as;  // Save a document.
  30.267 +- (void) delete;  // Delete an object.
  30.268 +- (SBObject *) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties;  // Copy object(s) and put the copies at a new location.
  30.269 +- (BOOL) exists;  // Verify if an object exists.
  30.270 +- (SBObject *) moveTo:(SBObject *)to;  // Move object(s) to a new location.
  30.271 +
  30.272 +@end
  30.273 +
  30.274 +// This subdivides the text into words.
  30.275 +@interface iChatWord : SBObject
  30.276 +
  30.277 +- (SBElementArray *) characters;
  30.278 +- (SBElementArray *) paragraphs;
  30.279 +- (SBElementArray *) words;
  30.280 +- (SBElementArray *) attributeRuns;
  30.281 +- (SBElementArray *) attachments;
  30.282 +
  30.283 +@property (copy) NSColor *color;  // The color of the first character.
  30.284 +@property (copy) NSString *font;  // The name of the font of the first character.
  30.285 +@property NSInteger size;  // The size in points of the first character.
  30.286 +
  30.287 +- (void) closeSaving:(iChatSaveOptions)saving savingIn:(NSURL *)savingIn;  // Close a document.
  30.288 +- (void) saveIn:(NSURL *)in_ as:(NSString *)as;  // Save a document.
  30.289 +- (void) delete;  // Delete an object.
  30.290 +- (SBObject *) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties;  // Copy object(s) and put the copies at a new location.
  30.291 +- (BOOL) exists;  // Verify if an object exists.
  30.292 +- (SBObject *) moveTo:(SBObject *)to;  // Move object(s) to a new location.
  30.293 +
  30.294 +@end
  30.295 +
  30.296 +// This subdivides the text into chunks that all have the same attributes.
  30.297 +@interface iChatAttributeRun : SBObject
  30.298 +
  30.299 +- (SBElementArray *) characters;
  30.300 +- (SBElementArray *) paragraphs;
  30.301 +- (SBElementArray *) words;
  30.302 +- (SBElementArray *) attributeRuns;
  30.303 +- (SBElementArray *) attachments;
  30.304 +
  30.305 +@property (copy) NSColor *color;  // The color of the first character.
  30.306 +@property (copy) NSString *font;  // The name of the font of the first character.
  30.307 +@property NSInteger size;  // The size in points of the first character.
  30.308 +
  30.309 +- (void) closeSaving:(iChatSaveOptions)saving savingIn:(NSURL *)savingIn;  // Close a document.
  30.310 +- (void) saveIn:(NSURL *)in_ as:(NSString *)as;  // Save a document.
  30.311 +- (void) delete;  // Delete an object.
  30.312 +- (SBObject *) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties;  // Copy object(s) and put the copies at a new location.
  30.313 +- (BOOL) exists;  // Verify if an object exists.
  30.314 +- (SBObject *) moveTo:(SBObject *)to;  // Move object(s) to a new location.
  30.315 +
  30.316 +@end
  30.317 +
  30.318 +// Represents an inline text attachment. This class is used mainly for make commands.
  30.319 +@interface iChatAttachment : iChatRichText
  30.320 +
  30.321 +@property (copy, readonly) NSURL *file;  // The path to the file for the attachment
  30.322 +
  30.323 +
  30.324 +@end
  30.325 +
  30.326 +
  30.327 +
  30.328 +/*
  30.329 + * iChat Suite
  30.330 + */
  30.331 +
  30.332 +// iChat application.
  30.333 +@interface iChatApplication (IChatSuite)
  30.334 +
  30.335 +- (SBElementArray *) buddies;
  30.336 +- (SBElementArray *) services;
  30.337 +- (SBElementArray *) fileTransfers;
  30.338 +- (SBElementArray *) chats;
  30.339 +- (SBElementArray *) textChats;
  30.340 +- (SBElementArray *) audioChats;
  30.341 +- (SBElementArray *) videoChats;
  30.342 +
  30.343 +@property (readonly) NSInteger idleTime;  // Time in seconds that I have been idle.
  30.344 +@property (copy) NSImage *image;  // My image as it appears in all services.
  30.345 +@property (copy) NSString *statusMessage;  // My status message, visible to other people while I am online.
  30.346 +@property iChatMyStatus status;  // My status on all services.
  30.347 +@property (copy) iChatAudioChat *activeAvChat;  // The currently active audio or video chat.
  30.348 +
  30.349 +@end
  30.350 +
  30.351 +// A buddy on a service.
  30.352 +@interface iChatBuddy : iChatItem
  30.353 +
  30.354 +- (NSString *) id;  // The buddy's service and handle. For example: AIM:JohnDoe007
  30.355 +@property (copy, readonly) iChatService *service;  // The service on which this buddy exists.
  30.356 +@property (copy, readonly) NSString *name;  // The buddy's name as it appears in the buddy list.
  30.357 +@property (copy, readonly) NSString *handle;  // The buddy's online account name.
  30.358 +@property (readonly) iChatAccountStatus status;  // The buddy's current status.
  30.359 +@property (copy, readonly) NSString *statusMessage;  // The buddy's current status message.
  30.360 +@property (readonly) NSInteger idleTime;  // The time in seconds the buddy has been idle.
  30.361 +@property (copy, readonly) NSArray *capabilities;  // The buddy's messaging capabilities.
  30.362 +@property (copy, readonly) NSImage *image;  // The buddy's custom image.
  30.363 +@property (copy, readonly) NSString *firstName;  // The first name from this buddy's Address Book card, if available
  30.364 +@property (copy, readonly) NSString *lastName;  // The last name from this buddy's Address Book card, if available
  30.365 +@property (copy, readonly) NSString *fullName;  // The full name from this buddy's Address Book card, if available
  30.366 +
  30.367 +
  30.368 +@end
  30.369 +
  30.370 +// A service that can be logged in from this system
  30.371 +@interface iChatService : iChatItem
  30.372 +
  30.373 +- (SBElementArray *) buddies;
  30.374 +- (SBElementArray *) chats;
  30.375 +
  30.376 +- (NSString *) id;  // A guid identifier for this service.
  30.377 +@property (copy) NSString *name;  // The name of this service as defined in Account preferences description field
  30.378 +@property BOOL enabled;  // Is the service enabled?
  30.379 +@property (readonly) iChatConnectionStatus status;  // The connection status for this account.
  30.380 +@property (readonly) iChatServiceType serviceType;  // The type of protocol for this service
  30.381 +
  30.382 +- (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.
  30.383 +- (void) logOut;  // Logs out of a service, or all services if none is specified.
  30.384 +
  30.385 +@end
  30.386 +
  30.387 +// An audio, video, or text chat.
  30.388 +@interface iChatChat : SBObject
  30.389 +
  30.390 +- (NSString *) id;  // A guid identifier for this chat.
  30.391 +@property (copy, readonly) iChatService *service;  // The service which is participating in this chat.
  30.392 +@property (copy, readonly) NSArray *participants;  // Other participants of this chat. This property may be specified at time of creation.
  30.393 +@property (readonly) BOOL secure;  // Is this chat secure?
  30.394 +@property (readonly) BOOL invitation;  // Is this an invitation to a chat?
  30.395 +@property (readonly) BOOL active;  // Is this chat currently active?
  30.396 +@property (copy, readonly) NSDate *started;  // The date on which this chat started.
  30.397 +@property (copy, readonly) NSDate *updated;  // The date when this chat was last updated.
  30.398 +
  30.399 +- (void) closeSaving:(iChatSaveOptions)saving savingIn:(NSURL *)savingIn;  // Close a document.
  30.400 +- (void) saveIn:(NSURL *)in_ as:(NSString *)as;  // Save a document.
  30.401 +- (void) delete;  // Delete an object.
  30.402 +- (SBObject *) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties;  // Copy object(s) and put the copies at a new location.
  30.403 +- (BOOL) exists;  // Verify if an object exists.
  30.404 +- (SBObject *) moveTo:(SBObject *)to;  // Move object(s) to a new location.
  30.405 +- (void) accept;  // Accepts an incoming text, audio, or video chat invitation, or file transfer
  30.406 +- (void) decline;  // Declines an incoming text, audio, or video chat invitation, or file transfer
  30.407 +
  30.408 +@end
  30.409 +
  30.410 +// A text chat.
  30.411 +@interface iChatTextChat : iChatChat
  30.412 +
  30.413 +@property (copy, readonly) NSString *subject;  // The subject of this chat, if available.
  30.414 +@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.
  30.415 +@property (readonly) iChatJoinState joinState;  // How you are joined to this chat
  30.416 +@property (copy, readonly) NSString *name;  // The address or room name of this chat. This property may be specified at time of creation.
  30.417 +@property (readonly) iChatChatType chatType;  // The type of this chat.
  30.418 +
  30.419 +
  30.420 +@end
  30.421 +
  30.422 +// An audio or video chat.
  30.423 +@interface iChatAudioChat : iChatChat
  30.424 +
  30.425 +@property (readonly) iChatScreenSharing screenSharing;  // Type of screen sharing session taking place within this chat.
  30.426 +@property BOOL muted;  // Is the chat muted?
  30.427 +@property (readonly) iChatAvConnectionStatus avConnectionStatus;  // The connection state for this av chat.
  30.428 +
  30.429 +- (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.
  30.430 +- (void) stopRecording;  // Ends recording of an audio or video chat.
  30.431 +
  30.432 +@end
  30.433 +
  30.434 +@interface iChatVideoChat : iChatAudioChat
  30.435 +
  30.436 +@property BOOL paused;  // Is the chat paused?
  30.437 +@property BOOL showingFullScreen;  // Is the chat being displayed in full screen mode?
  30.438 +@property BOOL showingLocalVideo;  // Is the local video preview being displayed?
  30.439 +
  30.440 +- (void) takeSnapshot;  // Takes a snapshot of a video chat and saves it to a desktop.
  30.441 +
  30.442 +@end
  30.443 +
  30.444 +// A file being sent or received
  30.445 +@interface iChatFileTransfer : iChatItem
  30.446 +
  30.447 +- (NSString *) id;  // The guid for this file transfer
  30.448 +@property (copy, readonly) NSString *name;  // The name of this file
  30.449 +@property (copy, readonly) NSURL *file;  // The local path to this file transfer
  30.450 +@property (readonly) iChatDirection direction;  // The direction in which this file is being sent
  30.451 +@property (copy, readonly) iChatService *service;  // The service on which this file transfer is taking place
  30.452 +@property (copy, readonly) iChatBuddy *buddy;  // The account participating in this file transfer
  30.453 +@property (readonly) BOOL secure;  // Is this file transfer secure?
  30.454 +@property (readonly) NSInteger fileSize;  // The total size in bytes of the completed file transfer
  30.455 +@property (readonly) NSInteger fileProgress;  // The number of bytes that have been transferred
  30.456 +@property (readonly) iChatTransferStatus transferStatus;  // The current status of this file transfer
  30.457 +@property (copy, readonly) NSDate *started;  // The date that this file transfer started
  30.458 +
  30.459 +- (void) accept;  // Accepts an incoming text, audio, or video chat invitation, or file transfer
  30.460 +- (void) decline;  // Declines an incoming text, audio, or video chat invitation, or file transfer
  30.461 +
  30.462 +@end
  30.463 +
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/mnemonicode-0.73/Makefile	Sat Mar 08 21:04:41 2008 -0800
    31.3 @@ -0,0 +1,12 @@
    31.4 +sample_programs: mnencode mndecode
    31.5 +
    31.6 +mnencode: mnencode.o mnemonic.o mn_wordlist.o
    31.7 +
    31.8 +mndecode: mndecode.o mnemonic.o mn_wordlist.o
    31.9 +
   31.10 +mn_wordlist.o: mn_wordlist.c mnemonic.h
   31.11 +
   31.12 +mnemonic.o: mnemonic.c mnemonic.h
   31.13 +
   31.14 +clean: 
   31.15 +	rm -f *.o mnencode mndecode *~
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/mnemonicode-0.73/README	Sat Mar 08 21:04:41 2008 -0800
    32.3 @@ -0,0 +1,13 @@
    32.4 +These routines implement a method for encoding binary data into a sequence
    32.5 +of words which can be spoken over the phone, for example, and converted
    32.6 +back to data on the other side.
    32.7 +
    32.8 +For more information see http://www.tothink.com/mnemonic
    32.9 +
   32.10 +mnemonic.h	Header file
   32.11 +mnemonic.c	Encoding/decoding and associated routines
   32.12 +mn_wordlist.c	The word list itself
   32.13 +mnencode.c	Sample program - encode data from stdin to stdout
   32.14 +mndecode.c	Sample program - decode data from stdin to stdout
   32.15 +
   32.16 +Oren Tirosh <oren@hishome.net>
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/mnemonicode-0.73/TODO	Sat Mar 08 21:04:41 2008 -0800
    33.3 @@ -0,0 +1,10 @@
    33.4 +Improve the wordlist 
    33.5 +
    33.6 +  I am looking for comments on the wordlist from you.  Yes, you :-)
    33.7 +
    33.8 +Soundalike matching
    33.9 +
   33.10 +  I have given up on standard soundex techniques for this purpose.  
   33.11 +  I am working on an ad-hoc solution which is more-or-less tailored to
   33.12 +  this specific list.
   33.13 +
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/mnemonicode-0.73/mn_wordlist.c	Sat Mar 08 21:04:41 2008 -0800
    34.3 @@ -0,0 +1,302 @@
    34.4 +/* mn_wordlist.c
    34.5 + Copyright (c) 2000  Oren Tirosh <oren@hishome.net>
    34.6 + 
    34.7 + Permission is hereby granted, free of charge, to any person obtaining a copy
    34.8 + of this software and associated documentation files (the "Software"), to deal
    34.9 + in the Software without restriction, including without limitation the rights
   34.10 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   34.11 + copies of the Software, and to permit persons to whom the Software is
   34.12 + furnished to do so, subject to the following conditions:
   34.13 + 
   34.14 + The above copyright notice and this permission notice shall be included in
   34.15 + all copies or substantial portions of the Software.
   34.16 + 
   34.17 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   34.18 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   34.19 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
   34.20 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   34.21 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   34.22 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   34.23 + THE SOFTWARE.
   34.24 +*/
   34.25 +
   34.26 +#include "mnemonic.h"
   34.27 +
   34.28 +const char *mn_wordlist_version =
   34.29 +  " Wordlist ver 0.7 - EXPECT INCOMPATIBLE CHANGES";
   34.30 +
   34.31 +const char *mn_words[MN_WORDS + 1] = { 0,
   34.32 +  "academy",  "acrobat",  "active",   "actor",    "adam",     "admiral",  
   34.33 +  "adrian",   "africa",   "agenda",   "agent",    "airline",  "airport",  
   34.34 +  "aladdin",  "alarm",    "alaska",   "albert",   "albino",   "album",    
   34.35 +  "alcohol",  "alex",     "algebra",  "alibi",    "alice",    "alien",    
   34.36 +  "alpha",    "alpine",   "amadeus",  "amanda",   "amazon",   "amber",    
   34.37 +  "america",  "amigo",    "analog",   "anatomy",  "angel",    "animal",   
   34.38 +  "antenna",  "antonio",  "apollo",   "april",    "archive",  "arctic",   
   34.39 +  "arizona",  "arnold",   "aroma",    "arthur",   "artist",   "asia",     
   34.40 +  "aspect",   "aspirin",  "athena",   "athlete",  "atlas",    "audio",    
   34.41 +  "august",   "austria",  "axiom",    "aztec",    "balance",  "ballad",   
   34.42 +  "banana",   "bandit",   "banjo",    "barcode",  "baron",    "basic",    
   34.43 +  "battery",  "belgium",  "berlin",   "bermuda",  "bernard",  "bikini",   
   34.44 +  "binary",   "bingo",    "biology",  "block",    "blonde",   "bonus",    
   34.45 +  "boris",    "boston",   "boxer",    "brandy",   "bravo",    "brazil",   
   34.46 +  "bronze",   "brown",    "bruce",    "bruno",    "burger",   "burma",    
   34.47 +  "cabinet",  "cactus",   "cafe",     "cairo",    "cake",     "calypso",  
   34.48 +  "camel",    "camera",   "campus",   "canada",   "canal",    "cannon",   
   34.49 +  "canoe",    "cantina",  "canvas",   "canyon",   "capital",  "caramel",  
   34.50 +  "caravan",  "carbon",   "cargo",    "carlo",    "carol",    "carpet",   
   34.51 +  "cartel",   "casino",   "castle",   "castro",   "catalog",  "caviar",   
   34.52 +  "cecilia",  "cement",   "center",   "century",  "ceramic",  "chamber",  
   34.53 +  "chance",   "change",   "chaos",    "charlie",  "charm",    "charter",  
   34.54 +  "chef",     "chemist",  "cherry",   "chess",    "chicago",  "chicken",  
   34.55 +  "chief",    "china",    "cigar",    "cinema",   "circus",   "citizen",  
   34.56 +  "city",     "clara",    "classic",  "claudia",  "clean",    "client",   
   34.57 +  "climax",   "clinic",   "clock",    "club",     "cobra",    "coconut",  
   34.58 +  "cola",     "collect",  "colombo",  "colony",   "color",    "combat",   
   34.59 +  "comedy",   "comet",    "command",  "compact",  "company",  "complex",  
   34.60 +  "concept",  "concert",  "connect",  "consul",   "contact",  "context",  
   34.61 +  "contour",  "control",  "convert",  "copy",     "corner",   "corona",   
   34.62 +  "correct",  "cosmos",   "couple",   "courage",  "cowboy",   "craft",    
   34.63 +  "crash",    "credit",   "cricket",  "critic",   "crown",    "crystal",  
   34.64 +  "cuba",     "culture",  "dallas",   "dance",    "daniel",   "david",    
   34.65 +  "decade",   "decimal",  "deliver",  "delta",    "deluxe",   "demand",   
   34.66 +  "demo",     "denmark",  "derby",    "design",   "detect",   "develop",  
   34.67 +  "diagram",  "dialog",   "diamond",  "diana",    "diego",    "diesel",   
   34.68 +  "diet",     "digital",  "dilemma",  "diploma",  "direct",   "disco",    
   34.69 +  "disney",   "distant",  "doctor",   "dollar",   "dominic",  "domino",   
   34.70 +  "donald",   "dragon",   "drama",    "dublin",   "duet",     "dynamic",  
   34.71 +  "east",     "ecology",  "economy",  "edgar",    "egypt",    "elastic",  
   34.72 +  "elegant",  "element",  "elite",    "elvis",    "email",    "energy",   
   34.73 +  "engine",   "english",  "episode",  "equator",  "escort",   "ethnic",   
   34.74 +  "europe",   "everest",  "evident",  "exact",    "example",  "exit",     
   34.75 +  "exotic",   "export",   "express",  "extra",    "fabric",   "factor",   
   34.76 +  "falcon",   "family",   "fantasy",  "fashion",  "fiber",    "fiction",  
   34.77 +  "fidel",    "fiesta",   "figure",   "film",     "filter",   "final",    
   34.78 +  "finance",  "finish",   "finland",  "flash",    "florida",  "flower",   
   34.79 +  "fluid",    "flute",    "focus",    "ford",     "forest",   "formal",   
   34.80 +  "format",   "formula",  "fortune",  "forum",    "fragile",  "france",   
   34.81 +  "frank",    "friend",   "frozen",   "future",   "gabriel",  "galaxy",   
   34.82 +  "gallery",  "gamma",    "garage",   "garden",   "garlic",   "gemini",   
   34.83 +  "general",  "genetic",  "genius",   "germany",  "global",   "gloria",   
   34.84 +  "golf",     "gondola",  "gong",     "good",     "gordon",   "gorilla",  
   34.85 +  "grand",    "granite",  "graph",    "green",    "group",    "guide",    
   34.86 +  "guitar",   "guru",     "hand",     "happy",    "harbor",   "harmony",  
   34.87 +  "harvard",  "havana",   "hawaii",   "helena",   "hello",    "henry",    
   34.88 +  "hilton",   "history",  "horizon",  "hotel",    "human",    "humor",    
   34.89 +  "icon",     "idea",     "igloo",    "igor",     "image",    "impact",   
   34.90 +  "import",   "index",    "india",    "indigo",   "input",    "insect",   
   34.91 +  "instant",  "iris",     "italian",  "jacket",   "jacob",    "jaguar",   
   34.92 +  "janet",    "japan",    "jargon",   "jazz",     "jeep",     "john",     
   34.93 +  "joker",    "jordan",   "jumbo",    "june",     "jungle",   "junior",   
   34.94 +  "jupiter",  "karate",   "karma",    "kayak",    "kermit",   "kilo",     
   34.95 +  "king",     "koala",    "korea",    "labor",    "lady",     "lagoon",   
   34.96 +  "laptop",   "laser",    "latin",    "lava",     "lecture",  "left",     
   34.97 +  "legal",    "lemon",    "level",    "lexicon",  "liberal",  "libra",    
   34.98 +  "limbo",    "limit",    "linda",    "linear",   "lion",     "liquid",   
   34.99 +  "liter",    "little",   "llama",    "lobby",    "lobster",  "local",    
  34.100 +  "logic",    "logo",     "lola",     "london",   "lotus",    "lucas",    
  34.101 +  "lunar",    "machine",  "macro",    "madam",    "madonna",  "madrid",   
  34.102 +  "maestro",  "magic",    "magnet",   "magnum",   "major",    "mama",     
  34.103 +  "mambo",    "manager",  "mango",    "manila",   "marco",    "marina",   
  34.104 +  "market",   "mars",     "martin",   "marvin",   "master",   "matrix",   
  34.105 +  "maximum",  "media",    "medical",  "mega",     "melody",   "melon",    
  34.106 +  "memo",     "mental",   "mentor",   "menu",     "mercury",  "message",  
  34.107 +  "metal",    "meteor",   "meter",    "method",   "metro",    "mexico",   
  34.108 +  "miami",    "micro",    "million",  "mineral",  "minimum",  "minus",    
  34.109 +  "minute",   "miracle",  "mirage",   "miranda",  "mister",   "mixer",    
  34.110 +  "mobile",   "model",    "modem",    "modern",   "modular",  "moment",   
  34.111 +  "monaco",   "monica",   "monitor",  "mono",     "monster",  "montana",  
  34.112 +  "morgan",   "motel",    "motif",    "motor",    "mozart",   "multi",    
  34.113 +  "museum",   "music",    "mustang",  "natural",  "neon",     "nepal",    
  34.114 +  "neptune",  "nerve",    "neutral",  "nevada",   "news",     "ninja",    
  34.115 +  "nirvana",  "normal",   "nova",     "novel",    "nuclear",  "numeric",  
  34.116 +  "nylon",    "oasis",    "object",   "observe",  "ocean",    "octopus",  
  34.117 +  "olivia",   "olympic",  "omega",    "opera",    "optic",    "optimal",  
  34.118 +  "orange",   "orbit",    "organic",  "orient",   "origin",   "orlando",  
  34.119 +  "oscar",    "oxford",   "oxygen",   "ozone",    "pablo",    "pacific",  
  34.120 +  "pagoda",   "palace",   "pamela",   "panama",   "panda",    "panel",    
  34.121 +  "panic",    "paradox",  "pardon",   "paris",    "parker",   "parking",  
  34.122 +  "parody",   "partner",  "passage",  "passive",  "pasta",    "pastel",   
  34.123 +  "patent",   "patriot",  "patrol",   "patron",   "pegasus",  "pelican",  
  34.124 +  "penguin",  "pepper",   "percent",  "perfect",  "perfume",  "period",   
  34.125 +  "permit",   "person",   "peru",     "phone",    "photo",    "piano",    
  34.126 +  "picasso",  "picnic",   "picture",  "pigment",  "pilgrim",  "pilot",    
  34.127 +  "pirate",   "pixel",    "pizza",    "planet",   "plasma",   "plaster",  
  34.128 +  "plastic",  "plaza",    "pocket",   "poem",     "poetic",   "poker",    
  34.129 +  "polaris",  "police",   "politic",  "polo",     "polygon",  "pony",     
  34.130 +  "popcorn",  "popular",  "postage",  "postal",   "precise",  "prefix",   
  34.131 +  "premium",  "present",  "price",    "prince",   "printer",  "prism",    
  34.132 +  "private",  "product",  "profile",  "program",  "project",  "protect",  
  34.133 +  "proton",   "public",   "pulse",    "puma",     "pyramid",  "queen",    
  34.134 +  "radar",    "radio",    "random",   "rapid",    "rebel",    "record",   
  34.135 +  "recycle",  "reflex",   "reform",   "regard",   "regular",  "relax",    
  34.136 +  "report",   "reptile",  "reverse",  "ricardo",  "ringo",    "ritual",   
  34.137 +  "robert",   "robot",    "rocket",   "rodeo",    "romeo",    "royal",    
  34.138 +  "russian",  "safari",   "salad",    "salami",   "salmon",   "salon",    
  34.139 +  "salute",   "samba",    "sandra",   "santana",  "sardine",  "school",   
  34.140 +  "screen",   "script",   "second",   "secret",   "section",  "segment",  
  34.141 +  "select",   "seminar",  "senator",  "senior",   "sensor",   "serial",   
  34.142 +  "service",  "sheriff",  "shock",    "sierra",   "signal",   "silicon",  
  34.143 +  "silver",   "similar",  "simon",    "single",   "siren",    "slogan",   
  34.144 +  "social",   "soda",     "solar",    "solid",    "solo",     "sonic",    
  34.145 +  "soviet",   "special",  "speed",    "spiral",   "spirit",   "sport",    
  34.146 +  "static",   "station",  "status",   "stereo",   "stone",    "stop",     
  34.147 +  "street",   "strong",   "student",  "studio",   "style",    "subject",  
  34.148 +  "sultan",   "super",    "susan",    "sushi",    "suzuki",   "switch",   
  34.149 +  "symbol",   "system",   "tactic",   "tahiti",   "talent",   "tango",    
  34.150 +  "tarzan",   "taxi",     "telex",    "tempo",    "tennis",   "texas",    
  34.151 +  "textile",  "theory",   "thermos",  "tiger",    "titanic",  "tokyo",    
  34.152 +  "tomato",   "topic",    "tornado",  "toronto",  "torpedo",  "total",    
  34.153 +  "totem",    "tourist",  "tractor",  "traffic",  "transit",  "trapeze",  
  34.154 +  "travel",   "tribal",   "trick",    "trident",  "trilogy",  "tripod",   
  34.155 +  "tropic",   "trumpet",  "tulip",    "tuna",     "turbo",    "twist",    
  34.156 +  "ultra",    "uniform",  "union",    "uranium",  "vacuum",   "valid",    
  34.157 +  "vampire",  "vanilla",  "vatican",  "velvet",   "ventura",  "venus",    
  34.158 +  "vertigo",  "veteran",  "victor",   "video",    "vienna",   "viking",   
  34.159 +  "village",  "vincent",  "violet",   "violin",   "virtual",  "virus",    
  34.160 +  "visa",     "vision",   "visitor",  "visual",   "vitamin",  "viva",     
  34.161 +  "vocal",    "vodka",    "volcano",  "voltage",  "volume",   "voyage",   
  34.162 +  "water",    "weekend",  "welcome",  "western",  "window",   "winter",   
  34.163 +  "wizard",   "wolf",     "world",    "xray",     "yankee",   "yoga",     
  34.164 +  "yogurt",   "yoyo",     "zebra",    "zero",     "zigzag",   "zipper",   
  34.165 +  "zodiac",   "zoom",     "abraham",  "action",   "address",  "alabama",  
  34.166 +  "alfred",   "almond",   "ammonia",  "analyze",  "annual",   "answer",   
  34.167 +  "apple",    "arena",    "armada",   "arsenal",  "atlanta",  "atomic",   
  34.168 +  "avenue",   "average",  "bagel",    "baker",    "ballet",   "bambino",  
  34.169 +  "bamboo",   "barbara",  "basket",   "bazaar",   "benefit",  "bicycle",  
  34.170 +  "bishop",   "blitz",    "bonjour",  "bottle",   "bridge",   "british",  
  34.171 +  "brother",  "brush",    "budget",   "cabaret",  "cadet",    "candle",   
  34.172 +  "capitan",  "capsule",  "career",   "cartoon",  "channel",  "chapter",  
  34.173 +  "cheese",   "circle",   "cobalt",   "cockpit",  "college",  "compass",  
  34.174 +  "comrade",  "condor",   "crimson",  "cyclone",  "darwin",   "declare",  
  34.175 +  "degree",   "delete",   "delphi",   "denver",   "desert",   "divide",   
  34.176 +  "dolby",    "domain",   "domingo",  "double",   "drink",    "driver",   
  34.177 +  "eagle",    "earth",    "echo",     "eclipse",  "editor",   "educate",  
  34.178 +  "edward",   "effect",   "electra",  "emerald",  "emotion",  "empire",   
  34.179 +  "empty",    "escape",   "eternal",  "evening",  "exhibit",  "expand",   
  34.180 +  "explore",  "extreme",  "ferrari",  "first",    "flag",     "folio",    
  34.181 +  "forget",   "forward",  "freedom",  "fresh",    "friday",   "fuji",     
  34.182 +  "galileo",  "garcia",   "genesis",  "gold",     "gravity",  "habitat",  
  34.183 +  "hamlet",   "harlem",   "helium",   "holiday",  "house",    "hunter",   
  34.184 +  "ibiza",    "iceberg",  "imagine",  "infant",   "isotope",  "jackson",  
  34.185 +  "jamaica",  "jasmine",  "java",     "jessica",  "judo",     "kitchen",  
  34.186 +  "lazarus",  "letter",   "license",  "lithium",  "loyal",    "lucky",    
  34.187 +  "magenta",  "mailbox",  "manual",   "marble",   "mary",     "maxwell",  
  34.188 +  "mayor",    "milk",     "monarch",  "monday",   "money",    "morning",  
  34.189 +  "mother",   "mystery",  "native",   "nectar",   "nelson",   "network",  
  34.190 +  "next",     "nikita",   "nobel",    "nobody",   "nominal",  "norway",   
  34.191 +  "nothing",  "number",   "october",  "office",   "oliver",   "opinion",  
  34.192 +  "option",   "order",    "outside",  "package",  "pancake",  "pandora",  
  34.193 +  "panther",  "papa",     "patient",  "pattern",  "pedro",    "pencil",   
  34.194 +  "people",   "phantom",  "philips",  "pioneer",  "pluto",    "podium",   
  34.195 +  "portal",   "potato",   "prize",    "process",  "protein",  "proxy",    
  34.196 +  "pump",     "pupil",    "python",   "quality",  "quarter",  "quiet",    
  34.197 +  "rabbit",   "radical",  "radius",   "rainbow",  "ralph",    "ramirez",  
  34.198 +  "ravioli",  "raymond",  "respect",  "respond",  "result",   "resume",   
  34.199 +  "retro",    "richard",  "right",    "risk",     "river",    "roger",    
  34.200 +  "roman",    "rondo",    "sabrina",  "salary",   "salsa",    "sample",   
  34.201 +  "samuel",   "saturn",   "savage",   "scarlet",  "scoop",    "scorpio",  
  34.202 +  "scratch",  "scroll",   "sector",   "serpent",  "shadow",   "shampoo",  
  34.203 +  "sharon",   "sharp",    "short",    "shrink",   "silence",  "silk",     
  34.204 +  "simple",   "slang",    "smart",    "smoke",    "snake",    "society",  
  34.205 +  "sonar",    "sonata",   "soprano",  "source",   "sparta",   "sphere",   
  34.206 +  "spider",   "sponsor",  "spring",   "acid",     "adios",    "agatha",   
  34.207 +  "alamo",    "alert",    "almanac",  "aloha",    "andrea",   "anita",    
  34.208 +  "arcade",   "aurora",   "avalon",   "baby",     "baggage",  "balloon",  
  34.209 +  "bank",     "basil",    "begin",    "biscuit",  "blue",     "bombay",   
  34.210 +  "brain",    "brenda",   "brigade",  "cable",    "carmen",   "cello",    
  34.211 +  "celtic",   "chariot",  "chrome",   "citrus",   "civil",    "cloud",    
  34.212 +  "common",   "compare",  "cool",     "copper",   "coral",    "crater",   
  34.213 +  "cubic",    "cupid",    "cycle",    "depend",   "door",     "dream",    
  34.214 +  "dynasty",  "edison",   "edition",  "enigma",   "equal",    "eric",     
  34.215 +  "event",    "evita",    "exodus",   "extend",   "famous",   "farmer",   
  34.216 +  "food",     "fossil",   "frog",     "fruit",    "geneva",   "gentle",   
  34.217 +  "george",   "giant",    "gilbert",  "gossip",   "gram",     "greek",    
  34.218 +  "grille",   "hammer",   "harvest",  "hazard",   "heaven",   "herbert",  
  34.219 +  "heroic",   "hexagon",  "husband",  "immune",   "inca",     "inch",     
  34.220 +  "initial",  "isabel",   "ivory",    "jason",    "jerome",   "joel",     
  34.221 +  "joshua",   "journal",  "judge",    "juliet",   "jump",     "justice",  
  34.222 +  "kimono",   "kinetic",  "leonid",   "lima",     "maze",     "medusa",   
  34.223 +  "member",   "memphis",  "michael",  "miguel",   "milan",    "mile",     
  34.224 +  "miller",   "mimic",    "mimosa",   "mission",  "monkey",   "moral",    
  34.225 +  "moses",    "mouse",    "nancy",    "natasha",  "nebula",   "nickel",   
  34.226 +  "nina",     "noise",    "orchid",   "oregano",  "origami",  "orinoco",  
  34.227 +  "orion",    "othello",  "paper",    "paprika",  "prelude",  "prepare",  
  34.228 +  "pretend",  "profit",   "promise",  "provide",  "puzzle",   "remote",   
  34.229 +  "repair",   "reply",    "rival",    "riviera",  "robin",    "rose",     
  34.230 +  "rover",    "rudolf",   "saga",     "sahara",   "scholar",  "shelter",  
  34.231 +  "ship",     "shoe",     "sigma",    "sister",   "sleep",    "smile",    
  34.232 +  "spain",    "spark",    "split",    "spray",    "square",   "stadium",  
  34.233 +  "star",     "storm",    "story",    "strange",  "stretch",  "stuart",   
  34.234 +  "subway",   "sugar",    "sulfur",   "summer",   "survive",  "sweet",    
  34.235 +  "swim",     "table",    "taboo",    "target",   "teacher",  "telecom",  
  34.236 +  "temple",   "tibet",    "ticket",   "tina",     "today",    "toga",     
  34.237 +  "tommy",    "tower",    "trivial",  "tunnel",   "turtle",   "twin",     
  34.238 +  "uncle",    "unicorn",  "unique",   "update",   "valery",   "vega",     
  34.239 +  "version",  "voodoo",   "warning",  "william",  "wonder",   "year",     
  34.240 +  "yellow",   "young",    "absent",   "absorb",   "accent",   "alfonso",  
  34.241 +  "alias",    "ambient",  "andy",     "anvil",    "appear",   "apropos",  
  34.242 +  "archer",   "ariel",    "armor",    "arrow",    "austin",   "avatar",   
  34.243 +  "axis",     "baboon",   "bahama",   "bali",     "balsa",    "bazooka",  
  34.244 +  "beach",    "beast",    "beatles",  "beauty",   "before",   "benny",    
  34.245 +  "betty",    "between",  "beyond",   "billy",    "bison",    "blast",    
  34.246 +  "bless",    "bogart",   "bonanza",  "book",     "border",   "brave",    
  34.247 +  "bread",    "break",    "broken",   "bucket",   "buenos",   "buffalo",  
  34.248 +  "bundle",   "button",   "buzzer",   "byte",     "caesar",   "camilla",  
  34.249 +  "canary",   "candid",   "carrot",   "cave",     "chant",    "child",    
  34.250 +  "choice",   "chris",    "cipher",   "clarion",  "clark",    "clever",   
  34.251 +  "cliff",    "clone",    "conan",    "conduct",  "congo",    "content",  
  34.252 +  "costume",  "cotton",   "cover",    "crack",    "current",  "danube",   
  34.253 +  "data",     "decide",   "desire",   "detail",   "dexter",   "dinner",   
  34.254 +  "dispute",  "donor",    "druid",    "drum",     "easy",     "eddie",    
  34.255 +  "enjoy",    "enrico",   "epoxy",    "erosion",  "except",   "exile",    
  34.256 +  "explain",  "fame",     "fast",     "father",   "felix",    "field",    
  34.257 +  "fiona",    "fire",     "fish",     "flame",    "flex",     "flipper",  
  34.258 +  "float",    "flood",    "floor",    "forbid",   "forever",  "fractal",  
  34.259 +  "frame",    "freddie",  "front",    "fuel",     "gallop",   "game",     
  34.260 +  "garbo",    "gate",     "gibson",   "ginger",   "giraffe",  "gizmo",    
  34.261 +  "glass",    "goblin",   "gopher",   "grace",    "gray",     "gregory",  
  34.262 +  "grid",     "griffin",  "ground",   "guest",    "gustav",   "gyro",     
  34.263 +  "hair",     "halt",     "harris",   "heart",    "heavy",    "herman",   
  34.264 +  "hippie",   "hobby",    "honey",    "hope",     "horse",    "hostel",   
  34.265 +  "hydro",    "imitate",  "info",     "ingrid",   "inside",   "invent",   
  34.266 +  "invest",   "invite",   "iron",     "ivan",     "james",    "jester",   
  34.267 +  "jimmy",    "join",     "joseph",   "juice",    "julius",   "july",     
  34.268 +  "justin",   "kansas",   "karl",     "kevin",    "kiwi",     "ladder",   
  34.269 +  "lake",     "laura",    "learn",    "legacy",   "legend",   "lesson",   
  34.270 +  "life",     "light",    "list",     "locate",   "lopez",    "lorenzo",  
  34.271 +  "love",     "lunch",    "malta",    "mammal",   "margo",    "marion",   
  34.272 +  "mask",     "match",    "mayday",   "meaning",  "mercy",    "middle",   
  34.273 +  "mike",     "mirror",   "modest",   "morph",    "morris",   "nadia",    
  34.274 +  "nato",     "navy",     "needle",   "neuron",   "never",    "newton",   
  34.275 +  "nice",     "night",    "nissan",   "nitro",    "nixon",    "north",    
  34.276 +  "oberon",   "octavia",  "ohio",     "olga",     "open",     "opus",     
  34.277 +  "orca",     "oval",     "owner",    "page",     "paint",    "palma",    
  34.278 +  "parade",   "parent",   "parole",   "paul",     "peace",    "pearl",    
  34.279 +  "perform",  "phoenix",  "phrase",   "pierre",   "pinball",  "place",    
  34.280 +  "plate",    "plato",    "plume",    "pogo",     "point",    "polite",   
  34.281 +  "polka",    "poncho",   "powder",   "prague",   "press",    "presto",   
  34.282 +  "pretty",   "prime",    "promo",    "quasi",    "quest",    "quick",    
  34.283 +  "quiz",     "quota",    "race",     "rachel",   "raja",     "ranger",   
  34.284 +  "region",   "remark",   "rent",     "reward",   "rhino",    "ribbon",   
  34.285 +  "rider",    "road",     "rodent",   "round",    "rubber",   "ruby",     
  34.286 +  "rufus",    "sabine",   "saddle",   "sailor",   "saint",    "salt",     
  34.287 +  "satire",   "scale",    "scuba",    "season",   "secure",   "shake",    
  34.288 +  "shallow",  "shannon",  "shave",    "shelf",    "sherman",  "shine",    
  34.289 +  "shirt",    "side",     "sinatra",  "sincere",  "size",     "slalom",   
  34.290 +  "slow",     "small",    "snow",     "sofia",    "song",     "sound",    
  34.291 +  "south",    "speech",   "spell",    "spend",    "spoon",    "stage",    
  34.292 +  "stamp",    "stand",    "state",    "stella",   "stick",    "sting",    
  34.293 +  "stock",    "store",    "sunday",   "sunset",   "support",  "sweden",   
  34.294 +  "swing",    "tape",     "think",    "thomas",   "tictac",   "time",     
  34.295 +  "toast",    "tobacco",  "tonight",  "torch",    "torso",    "touch",    
  34.296 +  "toyota",   "trade",    "tribune",  "trinity",  "triton",   "truck",    
  34.297 +  "trust",    "type",     "under",    "unit",     "urban",    "urgent",   
  34.298 +  "user",     "value",    "vendor",   "venice",   "verona",   "vibrate",  
  34.299 +  "virgo",    "visible",  "vista",    "vital",    "voice",    "vortex",   
  34.300 +  "waiter",   "watch",    "wave",     "weather",  "wedding",  "wheel",    
  34.301 +  "whiskey",  "wisdom",   "deal",     "null",     "nurse",    "quebec",   
  34.302 +  "reserve",  "reunion",  "roof",     "singer",   "verbal",   "amen",     
  34.303 +  "ego",      "fax",      "jet",      "job",      "rio",      "ski",      
  34.304 +  "yes"
  34.305 +};    
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/mnemonicode-0.73/mndecode.c	Sat Mar 08 21:04:41 2008 -0800
    35.3 @@ -0,0 +1,21 @@
    35.4 +#include <stdio.h>
    35.5 +#include "mnemonic.h"
    35.6 +
    35.7 +main ()
    35.8 +{
    35.9 +  char buf[0x90000];
   35.10 +  mn_byte outbuf[0x10000];
   35.11 +  int buflen;
   35.12 +  int n;
   35.13 +
   35.14 +  buflen = fread (buf, 1, sizeof buf - 1, stdin);
   35.15 +  buf[buflen] = 0;
   35.16 +
   35.17 +  n = mn_decode (buf, outbuf, sizeof outbuf);
   35.18 +  if (n < 0)
   35.19 +    fprintf (stderr, "mn_decode result %d\n", n);
   35.20 +  else 
   35.21 +    fwrite (outbuf, 1, n, stdout);
   35.22 +
   35.23 +  return 0;
   35.24 +}
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/mnemonicode-0.73/mnemonic.c	Sat Mar 08 21:04:41 2008 -0800
    36.3 @@ -0,0 +1,467 @@
    36.4 +/* mnemonic.c
    36.5 +
    36.6 + Copyright (c) 2000  Oren Tirosh <oren@hishome.net>
    36.7 +
    36.8 + Permission is hereby granted, free of charge, to any person obtaining a copy
    36.9 + of this software and associated documentation files (the "Software"), to deal
   36.10 + in the Software without restriction, including without limitation the rights
   36.11 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   36.12 + copies of the Software, and to permit persons to whom the Software is
   36.13 + furnished to do so, subject to the following conditions:
   36.14 +
   36.15 + The above copyright notice and this permission notice shall be included in
   36.16 + all copies or substantial portions of the Software.
   36.17 +
   36.18 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   36.19 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   36.20 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
   36.21 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   36.22 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   36.23 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   36.24 + THE SOFTWARE.
   36.25 +
   36.26 +*/
   36.27 +
   36.28 +#include "mnemonic.h"
   36.29 +#include <string.h>
   36.30 +
   36.31 +
   36.32 +/*
   36.33 + * mn_words_required
   36.34 + * 
   36.35 + * Description:
   36.36 + *  Calculate the number of words required to encode data using mnemonic
   36.37 + *  encoding.
   36.38 + *
   36.39 + * Parameters:
   36.40 + *  size - Size in bytes of data to be encoded
   36.41 + * 
   36.42 + * Return value:
   36.43 + *  number of words required for the encoding
   36.44 + */
   36.45 +
   36.46 +int
   36.47 +mn_words_required (int size)
   36.48 +{
   36.49 +  return ((size + 1) * 3) / 4;
   36.50 +}
   36.51 +
   36.52 +
   36.53 +/*
   36.54 + * mn_encode_word_index
   36.55 + *
   36.56 + * Description:
   36.57 + *  Perform one step of encoding binary data into words. Returns word index.
   36.58 + *
   36.59 + * Parameters:
   36.60 + *   src - Pointer to data buffer to encode
   36.61 + *   srcsize - Size in bytes of data to encode 
   36.62 + *   n - Sequence number of word to encode
   36.63 + *       0 <= n < mn_words_required(srcsize)
   36.64 + *
   36.65 + * Return value:
   36.66 + *   0 - no more words to encode / n is out of range
   36.67 + *   1..MN_WORDS - word index. May be used as index to the mn_words[] array
   36.68 + */
   36.69 +
   36.70 +mn_index mn_encode_word_index (void *src, int srcsize, int n)
   36.71 +{
   36.72 +  mn_word32 x = 0;		/* Temporary for MN_BASE arithmetic */
   36.73 +  int offset;			/* Offset into src */
   36.74 +  int remaining;		/* Octets remaining to end of src */
   36.75 +  int extra = 0;		/* Index 7 extra words for 24 bit data */
   36.76 +  int i;
   36.77 +
   36.78 +  if (n < 0 || n >= mn_words_required (srcsize))
   36.79 +    return 0;			/* word out of range */
   36.80 +  offset = (n / 3) * 4;		/* byte offset into src */
   36.81 +  remaining = srcsize - offset;
   36.82 +  if (remaining <= 0)
   36.83 +    return 0;
   36.84 +  if (remaining >= 4)
   36.85 +    remaining = 4;
   36.86 +  for (i = 0; i < remaining; i++)
   36.87 +    x |= ((mn_byte *) src)[offset + i] << (i * 8);	/* endianness-agnostic */
   36.88 +
   36.89 +  switch (n % 3)
   36.90 +    {
   36.91 +    case 2:			/* Third word of group */
   36.92 +      if (remaining == 3)	/*  special case for 24 bits */
   36.93 +	extra = MN_BASE;	/*  use one of the 7 3-letter words */
   36.94 +      x /= (MN_BASE * MN_BASE);
   36.95 +      break;
   36.96 +    case 1:			/* Second word of group */
   36.97 +      x /= MN_BASE;
   36.98 +    }
   36.99 +  return x % MN_BASE + extra + 1;
  36.100 +}
  36.101 +
  36.102 +
  36.103 +/*
  36.104 + * mn_encode_word
  36.105 + *
  36.106 + * Description:
  36.107 + *  Perform one step of encoding binary data into words. Returns pointer 
  36.108 + *  to word.
  36.109 + *
  36.110 + * Parameters:
  36.111 + *   src - Pointer to data buffer to encode
  36.112 + *   srcsize - Size of data to encode in bytes
  36.113 + *   n - Sequence number of word to encode. 
  36.114 + *       0 <= n < mn_words_required(srcsize)
  36.115 + *
  36.116 + * Return value:
  36.117 + *   NULL - no more words to encode / n is out of range
  36.118 + *   valid pointer - pointer to null-terminated lowercase word. length<=7
  36.119 + */
  36.120 +
  36.121 +const char *
  36.122 +mn_encode_word (void *src, int srcsize, int n)
  36.123 +{
  36.124 +  return mn_words[mn_encode_word_index (src, srcsize, n)];
  36.125 +}
  36.126 +
  36.127 +
  36.128 +/*
  36.129 + * isletter
  36.130 + * Utility function - returns nonzero if character c is an ASCII letter.
  36.131 + */
  36.132 +
  36.133 +static int
  36.134 +isletter (char c)
  36.135 +{
  36.136 +  return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
  36.137 +}
  36.138 +
  36.139 +/*
  36.140 + * mn_next_word_index
  36.141 + *
  36.142 + * Description:
  36.143 + *  Perform one step of decoding a null-terminated buffer into word indices.
  36.144 + *  A word is defined as a sequence of letter character separated by one
  36.145 + *  or more non-letter separator characters.
  36.146 + *
  36.147 + * Parameters:
  36.148 + *  ptr - Pointer to a pointer to the next character in the buffer.
  36.149 + *  *ptr is modified by the function; see Return Value below.
  36.150 + *
  36.151 + * Return value:
  36.152 + *  0  - If *ptr==0 (points to the null at the end of the buffer) no more 
  36.153 + *       words were found in the buffer. Otherwise *ptr points to beginning 
  36.154 + *       of an unrecognized word.
  36.155 + *  >0 - index of word found, suitable for decoding with mn_decode_word_index
  36.156 + *       or comparison to values returned from mn_encode_index. *ptr points 
  36.157 + *       to first character of next word or to terminating null.
  36.158 + */
  36.159 +
  36.160 +mn_index
  36.161 +mn_next_word_index (char **ptr)
  36.162 +{
  36.163 +  char *wordstart;
  36.164 +  char wordbuf[MN_WORD_BUFLEN];
  36.165 +  int i = 0;
  36.166 +  char c;
  36.167 +  mn_index idx;
  36.168 +
  36.169 +  while (**ptr && !isletter (**ptr))	/* skip separator chars */
  36.170 +    (*ptr)++;
  36.171 +  wordstart = *ptr;		/* save for error reporting */
  36.172 +  while (**ptr && isletter (**ptr) && i < MN_WORD_BUFLEN - 1)
  36.173 +    {
  36.174 +      c = *(*ptr)++;
  36.175 +      if (c >= 'A' && c <= 'Z')
  36.176 +	c += 'a' - 'A';		/* convert to lowercase */
  36.177 +      wordbuf[i++] = c;
  36.178 +    }
  36.179 +  wordbuf[i] = '\0';
  36.180 +  while (**ptr && isletter (**ptr))	/* skip tail of long words */
  36.181 +    (*ptr)++;
  36.182 +  while (**ptr && !isletter (**ptr))	/* skip separators */
  36.183 +    (*ptr)++;
  36.184 +
  36.185 +  if (wordbuf[0] == '\0')
  36.186 +    return 0;			/* EOF, no word found */
  36.187 +
  36.188 +  for (idx = 1; idx <= MN_WORDS; idx++)
  36.189 +    {
  36.190 +      if (!strcmp (wordbuf, mn_words[idx]))
  36.191 +	return idx;
  36.192 +      /* FIXME: some fancy code should go here
  36.193 +         to accept misspellings and soundalikes.
  36.194 +         (replacing the linear search would also be nice) */
  36.195 +    }
  36.196 +  *ptr = wordstart;
  36.197 +  return 0;			/* not found */
  36.198 +}
  36.199 +
  36.200 +
  36.201 +/*
  36.202 + * mn_decode_word_index
  36.203 + *
  36.204 + * Description:
  36.205 + *  Perform one step of decoding a sequence of words into binary data.
  36.206 + *
  36.207 + * Parameters:
  36.208 + *  index    - Index of word, e.g. return value of mn_next_word_index. Use
  36.209 + *             the value MN_EOF(=0) to signal the end of input.
  36.210 + *  dest     - Points to buffer to receive decoded binary result.
  36.211 + *  destsize - Size of buffer 
  36.212 + *  offset   - Pointer to an integer offset into the destination buffer for 
  36.213 + *             next data byte. Initialize *offset to 0 before first call to 
  36.214 + *             function. Modified by function and may be used as an 
  36.215 + * 	       indication for the amount of data actually decoded.
  36.216 + *
  36.217 + * Return value:
  36.218 + *  The return value indicates the status of the decoding function. It is
  36.219 + *  ok to ignore this value on all calls to the function except the last
  36.220 + *  one (with index=MN_EOF). Any errors encountered will be reported on. 
  36.221 + *  the last call. The error code is also returned in *offset (negative 
  36.222 + *  values indicate error).
  36.223 + *
  36.224 + * MN_OK (==0)	
  36.225 + *	for index!=MN_EOF a return value of MN_OK means that 
  36.226 + *	decoding has been successful so far.
  36.227 + *	for index==MN_EOF a return value of MN_OK means that decoding
  36.228 + *	of the entire buffer has been successful and the decoder is in
  36.229 + *	a valid state for the end of the message. A total of *offset
  36.230 + *	valid decoded bytes is in the buffer.
  36.231 + *  MN_EREM      
  36.232 + *	returned on MN_EOF when an unaccounted arithmetic remainder is
  36.233 + *	in the decoder. Most likely indicates a truncated word sequence.
  36.234 + *  MN_EOVERRUN	
  36.235 + *	Not enough room in buffer for decoded data.
  36.236 + *  MN_EOVERRUN24 
  36.237 + *	Returned when decoding of data is attempted after decoding one
  36.238 + *	of the 7 words reserved for 24 bit remainders at the end of the
  36.239 + *	message. Probably indicates a garbled messages.
  36.240 + *  MN_EINDEX	
  36.241 + *	Bad input index. Naturally this should not happen when using 
  36.242 + *	the result of mn_next_word_index.
  36.243 + *  MN_EINDEX24
  36.244 + *	Returned when one of the 7 words reserved for 24 bit remainders
  36.245 + *	is received at an offset inappropriate for a 24 bit remainder.
  36.246 + *  MN_EENCODING
  36.247 + *	Indicates an overflow in MN_BASE arithmetic. Approximately 0.09%
  36.248 + *	of the 3 word combinations are unused and will generate this error.
  36.249 + */
  36.250 +
  36.251 +int
  36.252 +mn_decode_word_index (mn_index index, void *dest, int destsize, int *offset)
  36.253 +{
  36.254 +  mn_word32 x;			/* Temporary for MN_BASE arithmetic */
  36.255 +  int groupofs;
  36.256 +  int i;
  36.257 +
  36.258 +  if (*offset < 0)		/* Error from previous call? report it */
  36.259 +    return *offset;
  36.260 +
  36.261 +  if (index < 0 || index > MN_WORDS)	/* Word index out of range */
  36.262 +    {
  36.263 +      *offset = MN_EINDEX;
  36.264 +      return *offset;
  36.265 +    }
  36.266 +
  36.267 +  if (*offset > destsize)	/* out of range? */
  36.268 +    {
  36.269 +      *offset = MN_EOVERRUN;
  36.270 +      return *offset;
  36.271 +    }
  36.272 +
  36.273 +  if (index > MN_BASE && *offset % 4 != 2)
  36.274 +    {				/* Unexpected 24 bit remainder word */
  36.275 +      *offset = MN_EINDEX24;
  36.276 +      return *offset;
  36.277 +    }
  36.278 +
  36.279 +  groupofs = *offset & ~3;	/* Offset of 4 byte group containing offet */
  36.280 +  x = 0;
  36.281 +  for (i = 0; i < 4; i++)
  36.282 +    if (groupofs + i < destsize)	/* Ignore any bytes outside buffer */
  36.283 +      x |= ((mn_byte *) dest)[groupofs + i] << (i * 8);	/* assemble number */
  36.284 +
  36.285 +  if (index == MN_EOF)		/* Got EOF signal */
  36.286 +    {
  36.287 +      switch (*offset % 4)
  36.288 +	{
  36.289 +	case 3:		/* group was three words and the last */
  36.290 +	  return MN_OK;		/*  word was a 24 bit remainder */
  36.291 +	case 2:		/* last group has two words */
  36.292 +	  if (x <= 0xFFFF)	/*  should encode 16 bit data */
  36.293 +	    return MN_OK;
  36.294 +	  else
  36.295 +	    {
  36.296 +	      *offset = MN_EREM;
  36.297 +	      return *offset;
  36.298 +	    }
  36.299 +	case 1:		/* last group has just one word */
  36.300 +	  if (x <= 0xFF)	/*  should encode 8 bits */
  36.301 +	    return MN_OK;
  36.302 +	  else
  36.303 +	    {
  36.304 +	      *offset = MN_EREM;
  36.305 +	      return *offset;
  36.306 +	    }
  36.307 +
  36.308 +	case 0:		/* last group was full 3 words */
  36.309 +	  return MN_OK;
  36.310 +	}
  36.311 +    }
  36.312 +  if (*offset == destsize)	/* At EOF but didn't get MN_EOF */
  36.313 +    {
  36.314 +      *offset = MN_EOVERRUN;
  36.315 +      return *offset;
  36.316 +    }
  36.317 +
  36.318 +  index--;			/* 1 based to 0 based index */
  36.319 +
  36.320 +  switch (*offset % 4)
  36.321 +    {
  36.322 +    case 3:			/* Got data past 24 bit remainder */
  36.323 +      *offset = MN_EOVERRUN24;
  36.324 +      return *offset;
  36.325 +    case 2:
  36.326 +      if (index >= MN_BASE)
  36.327 +	{			/* 24 bit remainder */
  36.328 +	  x += (index - MN_BASE) * MN_BASE * MN_BASE;
  36.329 +	  (*offset)++;		/* *offset%4 == 3 for next time */
  36.330 +	}
  36.331 +      else
  36.332 +	{			/* catch invalid encodings */
  36.333 +	  if (index >= 1625 || (index == 1624 && x > 1312671))
  36.334 +	    {
  36.335 +	      *offset = MN_EENCODING;
  36.336 +	      return *offset;
  36.337 +	    }
  36.338 +	  x += index * MN_BASE * MN_BASE;
  36.339 +	  (*offset) += 2;	/* *offset%4 == 0 for next time */
  36.340 +	}
  36.341 +      break;
  36.342 +    case 1:
  36.343 +      x += index * MN_BASE;
  36.344 +      (*offset)++;
  36.345 +      break;
  36.346 +    case 0:
  36.347 +      x = index;
  36.348 +      (*offset)++;
  36.349 +      break;
  36.350 +    }
  36.351 +
  36.352 +  for (i = 0; i < 4; i++)
  36.353 +    if (groupofs + i < destsize)	/* Don't step outside the buffer */
  36.354 +      {
  36.355 +	((mn_byte *) dest)[groupofs + i] = (mn_byte) x % 256;
  36.356 +	x /= 256;
  36.357 +      }
  36.358 +  return MN_OK;
  36.359 +}
  36.360 +
  36.361 +/*
  36.362 + * mn_encode
  36.363 + *
  36.364 + * Description:
  36.365 + *  Encode a binary data buffer into a null-terminated sequence of words.
  36.366 + *  The word separators are taken from the format string. 
  36.367 + *
  36.368 + * Parameters:
  36.369 + *  src      - Pointer to the beginning of the binary data buffer.
  36.370 + *  srcsize  - Size in bytes of binary data buffer
  36.371 + *  dest     - Pointer to the beginning of a character buffer 
  36.372 + *  destsize - Size in characters of character buffer
  36.373 + *  format   - Null-terminated string describing the output format.
  36.374 + *             In the format string any letter or sequence of letters
  36.375 + *             acts as a placeholder for the encoded words. The word 
  36.376 + *             placeholders are separated by one or more non-letter
  36.377 + *             characters. When the encoder reaches the end of the 
  36.378 + *             format string it starts reading it again.
  36.379 + *             For sample formats see MN_F* constants in mnemonic.h
  36.380 + *	       If format is empty or NULL the format MN_FDEFAULT
  36.381 + *	       is used.
  36.382 + *
  36.383 + * Return value:
  36.384 + *  MN_OK(=0)
  36.385 + *	Encoding was successful.
  36.386 + *  MN_EOVERRUN
  36.387 + *	Output size exceeds size of destination buffer
  36.388 + *  MN_EFORMAT
  36.389 + *	Invalid format string. This function enforces formats which
  36.390 + *	will result in a string which can be successfully decoded by
  36.391 + *	the mn_decode function.
  36.392 + */
  36.393 +
  36.394 +int
  36.395 +mn_encode (void *src, int srcsize, char *dest, int destsize, char *format)
  36.396 +{
  36.397 +  int n;
  36.398 +  char *fmt;
  36.399 +  char *destend = dest + destsize;
  36.400 +  const char *word;
  36.401 +
  36.402 +  if (format == 0 || format[0] == '\0')
  36.403 +    format = MN_FDEFAULT;
  36.404 +  fmt = format;
  36.405 +  for (n = 0; n < mn_words_required (srcsize); n++)
  36.406 +    {
  36.407 +      while (dest < destend && *fmt != '\0' && !isletter (*fmt))
  36.408 +	*dest++ = *fmt++;
  36.409 +      if (dest >= destend)
  36.410 +	return MN_EOVERRUN;
  36.411 +      if (*fmt == '\0')
  36.412 +	{
  36.413 +	  if (isletter (fmt[-1]) && isletter (format[0]))
  36.414 +	    return MN_EFORMAT;
  36.415 +	  fmt = format;
  36.416 +	  while (dest < destend && *fmt != '\0' && !isletter (*fmt))
  36.417 +	    *dest++ = *fmt++;
  36.418 +	  if (!isletter (*fmt))
  36.419 +	    return MN_EFORMAT;
  36.420 +	}
  36.421 +      word = mn_encode_word (src, srcsize, n);
  36.422 +      if (word == 0)
  36.423 +	return MN_EOVERRUN;	/* shouldn't happen, actually */
  36.424 +
  36.425 +      while (isletter (*fmt))
  36.426 +	fmt++;
  36.427 +      while (dest < destend && *word != '\0')
  36.428 +	*dest++ = *word++;
  36.429 +    }
  36.430 +  if (dest < destend)
  36.431 +    *dest++ = '\0';
  36.432 +  else
  36.433 +    return MN_EOVERRUN;
  36.434 +  return MN_OK;
  36.435 +}
  36.436 +
  36.437 +/*
  36.438 + * mn_decode
  36.439 + *
  36.440 + * Description:
  36.441 + *  Decode a text representation in null-terminated character buffer src to 
  36.442 + *  binary buffer dest.
  36.443 + *
  36.444 + * Parameters:
  36.445 + *  src      - Pointer to null-terminated character buffer 
  36.446 + *  dest     - Pointer to beginning of destination buffer
  36.447 + *  destsize - Size in bytes of destination buffer
  36.448 + *
  36.449 + * Return value:
  36.450 + *  This function may return all the value returned by mn_decode_word_index
  36.451 + *  plus the following result code:
  36.452 + *
  36.453 + * MN_EWORD  - Unrecognized word.
  36.454 + */
  36.455 +
  36.456 +int
  36.457 +mn_decode (char *src, void *dest, int destsize)
  36.458 +{
  36.459 +  mn_index index;
  36.460 +  int offset = 0;
  36.461 +
  36.462 +  while ((index = mn_next_word_index (&src)) != 0)
  36.463 +    {
  36.464 +      if (index == 0 && *src != 0)
  36.465 +	return MN_EWORD;
  36.466 +      (void) mn_decode_word_index (index, dest, destsize, &offset);
  36.467 +    }
  36.468 +  (void) mn_decode_word_index (MN_EOF, dest, destsize, &offset);
  36.469 +  return offset;
  36.470 +}
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/mnemonicode-0.73/mnemonic.h	Sat Mar 08 21:04:41 2008 -0800
    37.3 @@ -0,0 +1,68 @@
    37.4 +/* mnemonic.h 
    37.5 +
    37.6 + Copyright (c) 2000  Oren Tirosh <oren@hishome.net>
    37.7 +
    37.8 + Permission is hereby granted, free of charge, to any person obtaining a copy
    37.9 + of this software and associated documentation files (the "Software"), to deal
   37.10 + in the Software without restriction, including without limitation the rights
   37.11 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   37.12 + copies of the Software, and to permit persons to whom the Software is
   37.13 + furnished to do so, subject to the following conditions:
   37.14 +
   37.15 + The above copyright notice and this permission notice shall be included in
   37.16 + all copies or substantial portions of the Software.
   37.17 +
   37.18 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   37.19 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   37.20 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
   37.21 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   37.22 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   37.23 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   37.24 + THE SOFTWARE.
   37.25 +
   37.26 +*/
   37.27 +
   37.28 +#define MN_BASE		1626		/* cubic root of 2^32, rounded up */
   37.29 +#define MN_REMAINDER	7		/* extra words for 24 bit remainders */
   37.30 +#define MN_WORDS (MN_BASE+MN_REMAINDER)	/* total number of words */
   37.31 +#define MN_WORD_BUFLEN	25		/* size for a word buffer+headroom */
   37.32 +
   37.33 +#define MN_EOF		0		/* signal end to mn_decode_word_index */
   37.34 +
   37.35 +/* result codes */
   37.36 +#define MN_OK		0		/* decoding ok */
   37.37 +#define MN_EREM		-1		/* unexpected arithmetic remainder */
   37.38 +#define MN_EOVERRUN	-2		/* output buffer overrun */
   37.39 +#define MN_EOVERRUN24	-3		/* data after 24 bit remainder */
   37.40 +#define MN_EINDEX	-4		/* bad word index */
   37.41 +#define MN_EINDEX24	-5		/* unexpected 24 bit remainder word */
   37.42 +#define MN_EENCODING	-6		/* invalid arithmetic encoding */
   37.43 +#define MN_EWORD	-7		/* unrecognized word */
   37.44 +#define MN_EFORMAT	-8		/* bad format string */
   37.45 +
   37.46 +/* Sample formats for mn_encode */
   37.47 +#define MN_FDEFAULT 		"x-x-x--"
   37.48 +#define MN_F64BITSPERLINE	" x-x-x--x-x-x\n"
   37.49 +#define MN_F96BITSPERLINE	" x-x-x--x-x-x--x-x-x\n"
   37.50 +#define MN_F128BITSPERLINE	" x-x-x--x-x-x--x-x-x--x-x-x\n"
   37.51 +/* Note that the last format does not fit in a standard 80 character line */
   37.52 +
   37.53 +typedef unsigned char mn_byte;		/* 8 bit quantity */
   37.54 +typedef unsigned long mn_word32;	/* temporary value, at least 32 bits */
   37.55 +typedef unsigned int mn_index;		/* index into wordlist */
   37.56 +
   37.57 +extern const char *mn_words[];		/* the word list itself */
   37.58 +extern const char *mn_wordlist_version;	/* version notice string */
   37.59 +
   37.60 +int 		mn_decode (char *src, void *dest, int destsize);
   37.61 +int 		mn_encode (void *src , int srcsize, 
   37.62 +			   char *dest, int destsize, char *format);
   37.63 +
   37.64 +int 		mn_words_required (int size);
   37.65 +mn_index 	mn_encode_word_index (void *src, int srcsize, int n);
   37.66 +const char*	mn_encode_word (void *src, int srcsize, int n);
   37.67 +mn_index 	mn_next_word_index (char **ptr);
   37.68 +int 		mn_decode_word_index (mn_index index, void *dest, 
   37.69 +				     int destsize, int *offset);
   37.70 +
   37.71 +
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/mnemonicode-0.73/mnencode.c	Sat Mar 08 21:04:41 2008 -0800
    38.3 @@ -0,0 +1,22 @@
    38.4 +#include <stdio.h>
    38.5 +#include "mnemonic.h"
    38.6 +
    38.7 +main ()
    38.8 +{
    38.9 +  mn_byte buf[0x10000];
   38.10 +  char outbuf[0x90000];
   38.11 +  int buflen;
   38.12 +  int n;
   38.13 +
   38.14 +  fprintf (stderr, "%s\n", mn_wordlist_version);
   38.15 +
   38.16 +  buflen = fread (buf, 1, sizeof (buf), stdin);
   38.17 +  n = mn_encode (buf, buflen, outbuf, sizeof outbuf, MN_F64BITSPERLINE);
   38.18 +  if (n == 0)
   38.19 +    fwrite (outbuf, 1, strlen (outbuf), stdout);
   38.20 +  else
   38.21 +    fprintf (stderr, "mn_encode error %d\n", n);
   38.22 +  putchar ('\n');
   38.23 +
   38.24 +  return 0;
   38.25 +}