TweetFollow Us on Twitter

X Files Carbonara

Volume Number: 19 (2003)
Issue Number: 8
Column Tag: Recipes

X Files Carbonara

Making Navigation Easier for the Impatient

by Richard Patterson

The Good ol' ways

Before I was coerced into being carbonized, I had a simple scrap of code I could grab and use whenever I needed my application to create and write a file.

   long            byteCounter;
   StandardFileReply   reply;
   FSSpec         asciFile;
   short         asciFileNum;
   char            *textData;
   OSErr         err = noErr;
StandardPutFile("\pSave Text Data as:", 
"\pFullLookupTable.txt", &reply);
   if(reply.sfGood)
   {
      asciFile = reply.sfFile;
      FSpDelete(&asciFile);
// ignore any error caused if there is no such file
      err = FSpCreate(&asciFile,'XCEL','TEXT', -1);   /* -1 = system script */
      err = FSpOpenDF(&asciFile, fsCurPerm, &asciFileNum);
      if (err != noErr) return err;
      err = FSWrite(asciFileNum, &byteCounter, textData);
      if (err != noErr) return err;
      err = FSClose(asciFileNum);
   }
   return err;

It couldn't get much more straightforward than that. Those were the days when the Toolbox really made life simpler for a programmer. It helped me tell the user (generally myself) what he was supposed to do and even suggest a default name for the file. The only suspect part of this code was the shortcut method of insuring that the file was indeed a virgin file by attempting to delete it before (re)creating it. I knew there were more elegant ways to let StandardPutFile tell me that the user was replacing an existing file rather than just creating a brand new one, but most of the time I didn't care. I just wanted to write the file and get on with it. (Most of my programming is for in-house use only, so I can get away with quick-and-dirty solutions that you should only try at home.)

Recently I was desperately trying to debug an After Effects plug-in to send images to a film recorder, and I realized the only way I was going to be able tell what was going on would be to save a file capturing the state of the image at a certain point. I don't write applications that write files all that often, but years ago I acquired the prejudice that reading and writing files is one of the most basic functions the operating system needs to do and should therefore be a very simple programming task. So I resurrected a scrap of code designed to save an image buffer as a simple Photoshop file and threw it into the soup.

The next thing I knew I was spending two days trying to figure out how to replace the method shown above with something that would work inside my carbon code running on OS-X. I found myself floating around in all kinds of convoluted discussions of Apple Events and Unicode text. I eventually vented my frustration on Apple Developer Support whose suggestions for further reading and examples only seemed to complicate what I thought I was beginning to grasp. Fortunately the support technician was very patient, and I was able to crystallize my ferment into a rational suggestion that OS-X should provide a much simpler higher level function to help the less experienced programmer create and write a file. The support technician agreed that was a good idea, but indicated that it was not at the top of their priorites. When I finally saw the light thanks to Mr. K.J. Bricknell's indispensable tome, Carbon Programming; I realized that perhaps I should write a sample function that might spare someone else the agony I had just experienced.

Non Standard

The functions for opening and writing to a file (FspOpenDF and FSWrite) still work in Carbon on OS-X, but the StandardPutFile and StandardGetFile functions have been replaced by Navigation Services. The system had just outgrown the functionality provided by the Standard File Package. There is a Navigation Services function NavPutFile that was the original replacement for StandardPutFile, but with OS-X Apple recommends that we use NavCreatePutFileDialog. If I had been keeping up, the transition from StandardPutFile to NavPutFile to NavCreatePutFileDialog might have been smooth and effortless. Instead I woke up and found the following definition staring me in the face:

OSStatus NavCreatePutFileDialog (
   const NavDialogCreationOptions * inOptions,
   OSType inFileType,
   OSType inFileCreator,
   NavEventUPP inEventProc,
   void * inClientData,
   NavDialogRef * outDialog
);

Then I discovered there were 11 other functions I must call before I can have an FSSpec to use in the familiar way.

What I wanted was one function that took care of all the user interaction and just gave me a ready-to-wear FSSpec. It would need to know what kind of file I am trying to create, so there are three things I need to give it: the file type, the file creator and a pointer to the FSSpec.

OSErr SimpleNavPutFile(   OSType fileType, 
OSType fileCreator, 
FSSpec *theFileSpec)
{
   OSStatus         theStatus;
   NavDialogRef   theDialog;
   NavReplyRecord theReply;
   AEDesc            aeDesc;
   FSRef            fsRefParent, fsRefDelete;
   UniChar         *nameBuffer;
   UniCharCount   nameLength;
   FInfo            fileInfo;
   OSErr            err = noErr;
   theStatus = NavCreatePutFileDialog(NULL, fileType, fileCreator,
NULL, NULL,
&theDialog);
   NavDialogRun(theDialog);
   theStatus = NavDialogGetReply ( theDialog, &theReply); 
   NavDialogDispose(theDialog);
         
   if(!theReply.validRecord)
   {
      // Assuming the user changed his/her mind? No harm; no foul.
      // Still need to indicate that a file has not been created
      return -1;   
   }   
                        
   err = AECoerceDesc(&theReply.selection, typeFSRef, &aeDesc);
   if(err != noErr) return err;
   err = AEGetDescData(&aeDesc, &fsRefParent, sizeof(FSRef));
   if(err != noErr) return err;
   nameLength = 
(UniCharCount)CFStringGetLength(theReply.saveFileName);
   nameBuffer = (UniChar *) NewPtr((long)nameLength);
   CFStringGetCharacters(theReply.saveFileName, 
CFRangeMake(0, (long)nameLength), 
&nameBuffer[0]);
   if(nameBuffer == NULL) return -1; // generic error
   if(theReply.replacing)
   {
      err = FSMakeFSRefUnicode(&fsRefParent, 
nameLength, nameBuffer, 
                        kTextEncodingUnicodeDefault, 
                        &fsRefDelete);
      if(err == noErr) err = FSDeleteObject(&fsRefDelete);
      if(err == fBsyErr)
      {
         DisposePtr((Ptr)nameBuffer);
         return err;
      }
   }
   
   err = FSCreateFileUnicode(&fsRefParent, nameLength, nameBuffer,
                      kFSCatInfoNone, NULL, NULL,
theFileSpec);
   
   err = FSpGetFInfo(theFileSpec, &fileInfo);
   fileInfo.fdType = fileType;
   fileInfo.fdCreator = fileCreator;
   err = FSpSetFInfo(theFileSpec, &fileInfo);
   
   return err;
}   

So now my original scrap of code would become:

long                           byteCounter;
   StandardFileReply      reply;
   FSSpec                     asciFile;
   short                     asciFileNum;
   char                        *textData;
   OSErr                     err = noErr;
err = SimpleNavPutFile('TEXT', 'XCEL' &asciFile);
   if(err == noErr)   // a file was created
   {
      err = FSpOpenDF(&asciFile, fsCurPerm, &asciFileNum);
      if (err != noErr) return err;
      err = FSWrite(asciFileNum, &byteCounter, textData);
      if (err != noErr) return err;
      err = FSClose(asciFileNum);
   }
   return err;

I've sacrificed a little functionality in the dialog, since I can no longer suggest a default file name and prompt the forgetful user about what he is supposed to be doing. This scrap is fewer lines of code than my original, though, and even easier to use. I shall not attempt to explain what all the functions are doing in my SimpleNavPutFile. All I can say is that this works on my machine and is not meant to be anything other than a quick and dirty solution. Note that it includes the call creating the file and deals with the choice to replace an existing file. It may just amount to the same thing as using the now-deprecated NavPutFile, but I believe it lets OS-X put up the latest and greatest file navigation dialog.

I should confess that this solution will fail with OS-9 because it gives up if it cannot coerce the AEDesc to an FSRef. Bricknell's book has a discussion on page 960 of how to derive the FSSpec in OS-9 when this coercion fails. I have not included it, because my immediate concern was getting over the hump in OS-X, and I want to keep this as simple as possible.

The corresponding SimpleNavGetFile is built around

OSStatus NavCreateGetFileDialog (
   const NavDialogCreationOptions * inOptions,   
   NavTypeListHandle inTypeList,      // can be NULL
   NavEventUPP inEventProc,         // can be NULL
   NavPreviewUPP inPreviewProc,      // can be NULL
   NavObjectFilterUPP inFilterProc,   // can be NULL
   void * inClientData,            // can be NULL
   NavDialogRef * outDialog
);

Most of the parameters which can be set to NULL have system defaults that will be used when they are NULL. Setting the NavTypeListHandle to NULL simply results in no file filtering in the dialog. In order to avoid dealing with the NavDialogCreationOptions you can use NavGetDefaultDialogCreationOptions to set everything to a default.

SimpleNavGetFile(FSSpec *theFileSpec)
{   
   OSStatus                        theStatus;
NavDialogRef                     theDialog;
   NavReplyRecord                theReply;
NavDialogCreationOptions    inOptions;
AEKeyword                        theKeyword;
   DescType                      actualType;
   Size                          actualSize;
   OSErr                           err = noErr;
   
   NavGetDefaultDialogCreationOptions(&inOptions);
   theStatus = NavCreateGetFileDialog(&inOptions, 
NULL, NULL, NULL, NULL, NULL, 
&theDialog);
   NavDialogRun(theDialog);
   theStatus = NavDialogGetReply ( theDialog, &theReply); 
   NavDialogDispose(theDialog);
      
   if(!theReply.validRecord)
   {
      return -1;      
// Assuming the user changed his/her mind? 
// No harm; no foul, but need to know 
// not to try to open the file.
   }   
                        
       // Get a pointer to selected file
err = AEGetNthPtr(&(theReply.selection), 1,
                           typeFSS, &theKeyword,
                           &actualType, theFileSpec,
                           sizeof(FSSpec),
                           &actualSize);
      
   return err;
}   

If you want to filter files to limit the options provided the user in the Navigation Dialog, you can either use an 'open' resource created with a resource editor or you can create a NavTypeList. To use an 'open' resource you get the NavTypeListHandle with a GetResoure function.

NavTypeListHandle typeList = 
(NavTypeListHandle)GetResource('open', 128);
   theStatus = NavCreateGetFileDialog(&inOptions, 
typeList, 
NULL, NULL, NULL, NULL, 
&theDialog);

The 128 is just the number of the resource you have created. If no such resource is found typeList will be given a NULL value and you will be doing no file filtering.

To create your own NavTypeList from scratch you need only fill in a few blanks.

   NavTypeList            inTypeList;
   NavTypeListPtr      inTypeListPtr;
   
   inTypeList.componentSignature = kNavGenericSignature;
   inTypeList.osTypeCount = 1;
   inTypeList.osType[0] = 'TEXT';
   
inTypeListPtr = &inTypeList;
   theStatus = NavCreateGetFileDialog(&inOptions, 
&inTypeListPtr, 
NULL, NULL, NULL, NULL, 
&theDialog);

I have used a NavTypeListPtr just to minimize the confusion when it is necessary to pass a NavTypeListHandle to NavCreateGetFileDialog. The kNavGenericSignature is a system constant which tells it not to filter files by their creator. If you wanted to choose from only Excel files you could put 'XCEL' here instead. Since the osType is an array you can list several file types for a given appliction signature, and you can also make NavTypeList itself an array so that the handle tells the dialog to display any number of file types from any number of specifica applications. If you need to do this, though, you are on your own.


Richard Patterson is in charge of digital imaging at Illusion Arts, a visual effects facility in Van Nuys, CA, specializing in matte paintings and bluescreen compositing for movies. You can reach him at richard@illusion-arts.com.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Sketch 47.1 - Design app for UX/UI for i...
Sketch is an innovative and fresh look at vector drawing. Its intentionally minimalist design is based upon a drawing space of unlimited size and layers, free of palettes, panels, menus, windows, and... Read more
Cocktail 11.0.1 - General maintenance an...
Cocktail is a general purpose utility for macOS that lets you clean, repair and optimize your Mac. It is a powerful digital toolset that helps hundreds of thousands of Mac users around the world get... Read more
Path Finder 7.6.1 - Powerful, award-winn...
Path Finder makes you a master of file management. Take full control over your file system. Save your time: compare and synchronize folders, view hidden files, use Dual Pane and full keyboard... Read more
Slack 2.8.2 - Collaborative communicatio...
Slack is a collaborative communication app that simplifies real-time messaging, archiving, and search for modern working teams. Version 2.8.2: A small release containing nothing but another Electron... Read more
Smultron 10.0.2 - Easy-to-use, powerful...
Smultron 10 is an elegant and powerful text editor that is easy to use. You can use Smultron 10 to create or edit any text document. Everything from a web page, a note or a script to any single piece... Read more
Capto 1.2.5 - $29.99
Capto (was Voila) is an easy-to-use app that takes capturing, recording, video and image editing to the next level. With an intelligent file manager and quick sharing options, Capto is perfect for... Read more
ScreenFlow 7.1.1 - Create screen recordi...
ScreenFlow is powerful, easy-to-use screencasting software for the Mac. With ScreenFlow you can record the contents of your entire monitor while also capturing your video camera, microphone and your... Read more
Xcode 9.0.1 - Integrated development env...
Xcode includes everything developers need to create great applications for Mac, iPhone, iPad, and Apple Watch. Xcode provides developers a unified workflow for user interface design, coding, testing... Read more
TotalFinder 1.10.2 - Adds tabs, hotkeys,...
TotalFinder is a universally acclaimed navigational companion for your Mac. Enhance your Mac's Finder with features so smart and convenient, you won't believe you ever lived without them. Features... Read more
Adobe Flash Player 27.0.0.170 - Plug-in...
Adobe Flash Player is a cross-platform, browser-based application runtime that provides uncompromised viewing of expressive applications, content, and videos across browsers and operating systems.... Read more

Dune! guide - how to toe the line and ge...
Publisher Voodoo is at it again with an all new high score chaser -- Dune! In this fast-paced arcade game, you have to propel yourself along sand dunes, gaining enough momentum to jump above the line to score points, while making sure you have... | Read more »
The best deals on the App Store this wee...
Happy Tuesday, dear readers. Your favorite part of the week as officially arrived. It's time to take a look at the best deals in games. Things are admittedly a bit sparse, but there are a few diamonds in the rough to see you through if you're... | Read more »
Be the last person standing in Legacy of...
Yoozoo Games’ popular action MMO Legacy of Discord is getting a huge new update to celebrate its first anniversary. Perhaps the biggest change is the addition of an exciting survival mode titled Last Guardian. This new survival mode will pit you... | Read more »
Home Street guide - how to make friends...
From the creators of Food Street comes Home Street, a new simulation game that tasks you with building a social network and designing a beautiful home. It's a bit like The Sims, but you won't have to worry about the daily chores involved (feeding,... | Read more »
Color Ballz guide - how to bounce to the...
Color Ballz is an addictive new arcade title from Ketchapp Studios. It takes old school mechanics from games like Brickles and puts a fun twist on it. Your job? To catch balls with a paddle and send them back into a chute to be carried back to... | Read more »
Q&A: A-33 Studio explains why Combat...
When it comes to mobile FPS, it’s often tricky to get the fundamentals right on a platform lacking a physical controller, large display and hefty RAM. With Combat Squad: Project Wednesday, A-33 Studio bravely took on the challenge of making a... | Read more »
Taichi Panda 3: Dragon Hunter guide - ti...
Taichi Panda 3: Dragon Hunter launched this week to players all over the world. It's a beautiful mobile MMORPG that blends elements of Eastern and Western fantasy. It reminds us of a mix between World of Warcraft and Jade Empire. MMO's can have a... | Read more »
The best new games we played this week -...
Phew. It has been a week, but now it's time to relax, put your feet up, and enjoy some brand new mobile games. It was a bit of slow week, but there's still plenty of new titles to add to your collection. Here are four of our favorites. [Read... | Read more »
Yoink - Improved Drag and Drop (Product...
Yoink - Improved Drag and Drop 1.0 Device: iOS Universal Category: Productivity Price: $2.99, Version: 1.0 (iTunes) Description: Yoink for iPad and iPhone lets you easily and quickly store items you drag, copy or share, for later use... | Read more »
Cottage Garden (Games)
Cottage Garden 1.11 Device: iOS Universal Category: Games Price: $4.99, Version: 1.11 (iTunes) Description: | Read more »

Price Scanner via MacPrices.net

13″ MacBook Pros on sale for up to $120 off M...
B&H Photo has 2017 13″ MacBook Pros in stock today and on sale for up to $120 off MSRP, each including free shipping plus NY & NJ sales tax only: – 13-inch 2.3GHz/128GB Space Gray MacBook... Read more
15″ MacBook Pros on sale for up to $200 off M...
B&H Photo has 15″ MacBook Pros on sale for up to $200 off MSRP. Shipping is free, and B&H charges sales tax in NY & NJ only: – 15″ 2.8GHz MacBook Pro Space Gray (MPTR2LL/A): $2249, $150... Read more
Roundup of Apple Certified Refurbished iMacs,...
Apple has a full line of Certified Refurbished 2017 21″ and 27″ iMacs available starting at $1019 and ranging up to $350 off original MSRP. Apple’s one-year warranty is standard, and shipping is free... Read more
Sale! 27″ 3.8GHz 5K iMac for $2098, save $201...
Amazon has the 27″ 3.8GHz 5K iMac (MNED2LL/A) on sale today for $2098 including free shipping. Their price is $201 off MSRP, and it’s the lowest price available for this model (Apple’s $1949... Read more
Sale! 10″ Apple WiFi iPad Pros for up to $100...
B&H Photo has 10.5″ WiFi iPad Pros in stock today and on sale for $50-$100 off MSRP. Each iPad includes free shipping, and B&H charges sales tax in NY & NJ only: – 10.5″ 64GB iPad Pro: $... Read more
Apple iMacs on sale for up to $130 off MSRP w...
B&H Photo has 21-inch and 27-inch iMacs in stock and on sale for up to $130 off MSRP including free shipping. B&H charges sales tax in NY & NJ only: – 27″ 3.8GHz iMac (MNED2LL/A): $2179 $... Read more
2017 3.5GHz 6-Core Mac Pro on sale for $2799,...
B&H Photo has the 2017 3.5GHz 6-Core Mac Pro (MD878LL/A) on sale today for $2799 including free shipping plus NY & NJ sales tax only . Their price is $200 off MSRP. Read more
12″ 1.2GHz Space Gray MacBook on sale for $11...
Amazon has the 2017 12″ 1.2GHz Space Gray Retina MacBook on sale for $100 off MSRP. Shipping is free: 12″ 1.2GHz Space Gray MacBook: $1199.99 $100 off MSRP Read more
Bare Bones Software Releases macOS High Sierr...
Bare Bones Software has announced the release and immediate availability of BBEdit 12.0, a significant upgrade to its professional strength text and code editor. BBEdit 12 introduces a new foundation... Read more
Yale Announces Availability of Apple HomeKit-...
Yale Locks & Hardware has announced that Apple HomeKit support for its Assure Lock family is available this month. The new Yale iM1 Network Module, which provides support for the Apple Home app... Read more

Jobs Board

*Apple* Information Security - Security Data...
Job Summary This role is responsible for helping to strengthen Apple 's information security posture through the identification and curation of security event data. Read more
Lead *Apple* Solution Consultant - Apple In...
…develop a team of diverse partner employees focusing on excellence to deliver the Apple story. Even when you're not present, you will maintain a consistent influence Read more
watchOS Frameworks Engineering Manager, *App...
Job Summary Join the team that is shaping the future of software development for Apple Watch! Apple is looking for an exceptional software engineering leader to Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.