On 2009 Jun 03, at 17:26, Bill Monk wrote:

Given that your category depends on FSNewAliasFromPath, which is 10.5-only, both blocks of

#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4....

can be dispensed with.

Hehe. Well, like I said, my code had been "cobbled together over time from various sources". But I believe we need the "modern" block,

                Size size = GetAliasSize(aliasHandle) ;

  AliasPtr aliasPtr = *aliasHandle ;
  data = [NSData dataWithBytes:aliasPtr
                             length:size] ;

Might just as well say:

data = [NSData dataWithBytes:*aliasHandle length:size] ;

Yup.

   AliasRecord aliasHeader = *((AliasPtr)[self bytes]) ;
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4
   AliasPtr ap = &aliasHeader ;
   AliasHandle ah = &ap ;

That sort of machination used to be known as "creating a fake handle" - as distinguished from a "real" Handle, a pointer to a pointer to relocatable block allocated by the Memory Manager . Doing that would cause various havoc and crashes. You can get away with it now because NewHandle ends up as a malloc call, and memory blocks are no longer relocatable. Still, it just looks wrong to my eye. Worse, in recent memory, fake handles could still cause trouble in OS X in certain circumstances. (When I tried to google it, I found my own post from 2005: http://www.cocoabuilder.com/archive/message/cocoa/2005/8/16/144407)

But anyway, easier to sidestep it with GetAliasSizeFromPtr. A one- liner replaces seven lines:

    nBytesAliasRecord = GetAliasSizeFromPtr( (AliasPtr)[self bytes] );

Yes, looks good. But to get seven lines you need to count the comments and unnecessary #ifdefs ;)

// The full path returned by FSRefMakePath will NOT have a trailing slash UNLESS // the path is the root, i.e. @"/". In that case it will. Thus, in order to return // a standard result to which "/Filename.ext" should be appended, we remove that:
   if ([path length] == 1)
       path = @"" ;

How come?

Don't ask me. I believe I pasted in that comment (and the accompanying section of code) from some Apple Sample Code.

If the caller is correctly using stringByAppendingPathComponent:, and not stringByAppendingString", this shouldn't be a problem. The correct path for the root is @"/" and I'd think needing to return anything else here implies a problem elsewhere.

Well, you can have a convention to add trailing slashes or not add trailing slashes. Personally, I think that trailing slashes are more conventional, but apparently whoever specified FSRefMakePath() does not.

   NSLog(@"*** Tests which should fail ***") ;    ...
   ...
   ...
   TestPath(@"/") ;

That test only fails because you force it to fail, by taking steps to return @"" for the root.

Yes, if something is documented to fail, you should test that it fails :))

AliasManager returns the correct path; I'd rather see it return that, and let callers either use stringByAppendingPathComponent, or let it be their problem if they have special reasons for not using it. But maybe that's just me...

Actually, my present purpose is only regarding files, not directories. So I just tried to document what others had done, even if it's odd.

Thanks for the comments.  This code keeps looking better, and shorter!

Jerry

Here's the modified .m. The .h should have documentation added to note that it requires Mac OS 10.5.

#import "NSData+FileAlias.h"

@implementation NSData (FileAlias)

+ (NSData*)aliasRecordFromPath:(NSString*)path {
    if ([path length] == 0) {
        return nil ;
    }

    const char* pathC = [path fileSystemRepresentation] ;

    OSErr osErr ;
    AliasHandle aliasHandle = NULL ;
    osErr = FSNewAliasFromPath (
                                NULL,
                                pathC,
                                0,
                                &aliasHandle,
                                NULL
                                ) ;

    NSData* data = nil ;
    if (
        (osErr == noErr)
        // ... File exists and we have a full alias
        ||
        ((osErr == fnfErr) && (aliasHandle != NULL))
        // ... File does not exist and we have a minimal alias
        ) {

        Size size = GetAliasSize(aliasHandle) ;

        data = [NSData dataWithBytes:*aliasHandle
                              length:size] ;
    }

    return data ;
}

- (NSString*)pathFromAliasRecord {
    unsigned short nBytesAliasRecord ;
    /*
     In Aliases.h, note that the AliasRecord struct is opaque if
     MAC_OS_X_MIN_VERSION_REQUIRED >= MAC_OS_X_VERSION_10_4.  In other
words, if the "Mac OS X Deployment Target" setting for your project is
     10.4 or later, the AliasRecord struct is opaque.

That's because AliasRecords, as you've noticed, get written to disk but are also referenced in data, which means that they often have to be big-endian even on little-endian systems. Rather than enumerate the cases in which you'd want big- or little-endian AliasRecords, we made the data type opaque and added new APIs which deal in native- endian data. They're Get/SetAliasUserType and GetAliasSize, and there are also FromPtr versions of each if you have an AliasRecord * instead of
     an AliasHandle.

     Eric Albert, Apple */

    nBytesAliasRecord = GetAliasSizeFromPtr((AliasPtr)[self bytes]);

    Handle handle = NULL;
    FSRef resolvedFSRef;
    NSString* path = nil ;
    int err = 0 ;

    // Move the now-decoded data into the Handle.
    if (PtrToHand([self bytes], &handle, nBytesAliasRecord) != noErr) {
NSLog(@"Internal Error 589-5451. Can't allocate handle for alias") ;
        err = 1 ;
    }

    if (err == 0) {
        // Successfully created the handle

        // Now try and resolve the alias
        Boolean changed ;
        OSErr osErr = FSResolveAlias(NULL,
                                     (AliasHandle)handle,
                                     &resolvedFSRef,
                                     &changed) ;

        if (osErr == noErr) {
            // Alias was resolved.  Now get its path from resolvedFSRef
            char pathC[4096] ;
            OSStatus osStatus = FSRefMakePath(
                                              &resolvedFSRef,
                                              (UInt8*)pathC,
                                              sizeof(pathC)
            ) ;

            if (osStatus != noErr) {
NSLog(@"Internal Error 959-2697. OSStatus %i from FSResolveAlias", osStatus) ;
                err = 1 ;
            }
            else {
                path = [NSString stringWithCString:pathC
encoding:NSUTF8StringEncoding] ;

// The full path returned by FSRefMakePath will NOT have a trailing slash UNLESS // the path is the root, i.e. @"/". In that case it will. Thus, in order to return // a standard result to which "/Filename.ext" should be appended, we remove that:
                if ([path length] == 1)
                    path = @"" ;
            }
        }
        else if (osErr == fnfErr) {
// The alias could not be resolved because the file does not exist. // However, we can still extract the expected path from the alias.
            osErr = FSCopyAliasInfo (
                                     (AliasHandle)handle,
                                     NULL,
                                     NULL,
                                     (CFStringRef*)&(path),
                                     NULL,
                                     NULL
                                     ) ;

// There may be a bug in the above function. If the alias is to // that of a nonexistent directory in the root, for example,
            //    /Yousers
            // Then the path returned will begin with two slashes.
            // To work around that,
            if ([path hasPrefix:@"//"]) {
                path = [path substringFromIndex:1] ;
            }
        }
    }

    if (handle)
        DisposeHandle(handle);

    return path ;
}

@end
_______________________________________________

Cocoa-dev mailing list ([email protected])

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [email protected]

Reply via email to