home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / PostScript OSA / DropShell3 / FileIterators.cp < prev    next >
Encoding:
Text File  |  2000-06-23  |  8.0 KB  |  321 lines

  1. /*    A set of objects for iterating a collection of files/folders */
  2. #ifndef    _FILEITERATORS_
  3. #include "FileIterators.h"
  4. #endif
  5.  
  6. /*    -------------------- TFileIterator --------------------- */
  7. TFileIterator:: TFileIterator ( long options ) { fOptions = options; }
  8. TFileIterator:: TFileIterator ( TFileIterator &rhs ) { fOptions = rhs.fOptions; }
  9. TFileIterator::~TFileIterator () {}
  10.  
  11. TFileIterator& TFileIterator::operator= ( TFileIterator& rhs ) {
  12.  
  13. //    Check for assignment to self
  14.     if ( &rhs == this )
  15.         return *this;
  16.         
  17.     fOptions = rhs.fOptions;
  18.     return *this;
  19.     }
  20.  
  21.  
  22.  
  23. /*    -------------------- TDirectoryIterator --------------------- */
  24. TDirectoryIterator:: TDirectoryIterator () {
  25. //    AssertStr ( 0, "\pDefault Constructor for TDirectoryIterator::TDirectoryIterator" );
  26.     }
  27.  
  28.  
  29. TDirectoryIterator:: TDirectoryIterator ( FSSpec *startPoint, long options ) : TFileIterator ( options ) {
  30.     OSErr    err = noErr;
  31.     
  32. //    Resolve the FSSpec to either a file or a folder.
  33.     fPb.hFileInfo.ioCompletion    = 0;
  34.     fPb.hFileInfo.ioVRefNum        = startPoint->vRefNum;
  35.     fPb.hFileInfo.ioDirID        = startPoint->parID;
  36.     fPb.hFileInfo.ioNamePtr        = startPoint->name;
  37.     fPb.hFileInfo.ioFDirIndex    = 0;    // use vrefNum/dirid/ioNamePtr
  38.     err = PBGetCatInfoSync ( &fPb );
  39. //    AssertStr ( err == noErr, "\pCan't get info in TDirectoryIterator::TDirectoryIterator" );
  40.  
  41.     if ( err != noErr ) {
  42.         fVRefNum    = -1;                //    This will have no files!
  43.         fParID        = fsRtParID;
  44.         }
  45.     else if (( fPb.hFileInfo.ioFlAttrib & ioDirMask ) == 0 ) {    // it's a file!
  46.         fVRefNum    = fPb.hFileInfo.ioVRefNum;
  47.         fParID        = fPb.hFileInfo.ioFlParID;
  48.         }
  49.     else {
  50.         fVRefNum    = fPb.dirInfo.ioVRefNum;
  51.         fParID        = fPb.dirInfo.ioDrDirID;
  52.         }
  53.  
  54. //    If it's a file, then walk the directory containing the file.
  55.     fNextIdx = -1;
  56.     fNumItems = -1;
  57.     }
  58.  
  59. TDirectoryIterator:: TDirectoryIterator ( short vRefNum, long dirID, long options ) : TFileIterator ( options ) {
  60.  
  61. //    If the vRefNum is a WDirID, resolve it.
  62.     fVRefNum    = vRefNum;
  63.     fParID        = dirID;
  64.     fNextIdx = -1;
  65.     fNumItems = -1;
  66.     }
  67.  
  68.  
  69. TDirectoryIterator:: TDirectoryIterator ( TFileIterator & /*rhs*/ ) {
  70. //    !!!
  71.     }
  72.  
  73.  
  74. TDirectoryIterator::~TDirectoryIterator () {}
  75.  
  76.  
  77. TDirectoryIterator& TDirectoryIterator::operator= ( TDirectoryIterator& rhs ) {
  78.  
  79. //    Check for assignment to self
  80.     if ( &rhs == this )
  81.         return *this;
  82.         
  83.     fOptions = rhs.fOptions;
  84.     return *this;
  85.     }
  86.  
  87.  
  88. //    detects if the directory has changed, and does stuff
  89. //    Currently it updates the number of items in the folder.
  90. //    Later it will attempt to adjust the "current item" pointer.
  91. void TDirectoryIterator::Synchronize ( void ) {
  92.     OSErr    err = noErr;
  93.     
  94. //    Check the mod date
  95.     fPb.hFileInfo.ioNamePtr        = nil;
  96.     fPb.hFileInfo.ioFDirIndex    = -1;    // Ignore namePtr, just use vRefNum/dirID
  97.     fPb.hFileInfo.ioVRefNum        = fVRefNum;
  98.     fPb.hFileInfo.ioDirID        = fParID;
  99.     err = PBGetCatInfoSync ( &fPb );
  100. //    If we can't get info then there are no files!
  101.     if ( err != noErr )
  102.         fNumItems = 0;
  103.     else if ( fModDate < fPb.dirInfo.ioDrMdDat ) {
  104.         fNumItems = fPb.dirInfo.ioDrNmFls;
  105.         fModDate = fPb.dirInfo.ioDrMdDat;
  106.         }    
  107.     }
  108.  
  109. //    Get the next item in the directory
  110. OSErr TDirectoryIterator::GetNextItem ( FSSpec *theSpec, Boolean *isFolder ) {
  111.     OSErr    err = noErr;
  112.     
  113.     if ( fNextIdx > fNumItems )
  114.         err = fnfErr;        // It _could_ happen!
  115.     else {
  116.         Str31    fileName;
  117.         
  118.     //    Get the n'th item in the directory
  119.         fPb.hFileInfo.ioCompletion    = 0;
  120.         fPb.hFileInfo.ioNamePtr        = fileName;
  121.         fPb.hFileInfo.ioVRefNum        = fVRefNum;
  122.         fPb.hFileInfo.ioDirID        = fParID;
  123.         fPb.hFileInfo.ioFDirIndex    = fNextIdx++;
  124.         err = PBGetCatInfoSync ( &fPb );
  125.     //    We have to resolve aliases, even if the user doesn't want any info
  126.     //    because she may be counting the contents
  127.         if ( err == noErr || ( fOptions & kResolveAliases ) != 0 ) {
  128.             FSSpec    aSpec;
  129.             Boolean    aFolder, wasAlias;
  130.  
  131.         //    Get the basic information
  132.             (void) FSMakeFSSpec ( fPb.hFileInfo.ioVRefNum, fPb.hFileInfo.ioFlParID, fPb.hFileInfo.ioNamePtr, &aSpec );
  133.             aFolder = ( fPb.hFileInfo.ioFlAttrib & ioDirMask ) != 0;
  134.  
  135.         //    We know we can't have folders that are aliases!
  136.             if (( fOptions & kResolveAliases ) && !aFolder )
  137.                 err = ResolveAliasFile ( &aSpec, true, &aFolder, &wasAlias ); 
  138.  
  139.             if ( theSpec != nil )
  140.                 *theSpec = aSpec;
  141.             if ( isFolder != nil )
  142.                 *isFolder = aFolder;
  143.             }
  144.         }
  145.     
  146. //    ReportError ( err );
  147.     return err;
  148.     }
  149.  
  150.  
  151. void TDirectoryIterator::Start ( void ) {
  152.  
  153. //    Set up fNumItems, etc
  154.     fNextIdx = -1;        // Flag which says we are "starting"
  155.     fModDate = 0;
  156.     fPb.hFileInfo.ioCompletion    = 0;
  157.     fPb.hFileInfo.ioNamePtr        = nil;
  158.     fPb.hFileInfo.ioVRefNum        = fVRefNum;
  159.     fPb.hFileInfo.ioDirID        = fParID;
  160.     this->Synchronize ();
  161.     
  162. //    Start at item 1
  163.     fNextIdx = 1;
  164.     }
  165.  
  166.  
  167. Boolean    TDirectoryIterator::More ( void ) {
  168.  
  169. //    Re-sync if the directory has been changed
  170.     this->Synchronize ();
  171.     return fNextIdx <= fNumItems;
  172.     }
  173.  
  174.  
  175. OSErr TDirectoryIterator::Next ( FSSpec *theSpec, Boolean *isFolder ) {
  176.     OSErr    err = noErr;
  177.     Boolean    aFolder = true;
  178.     
  179. //    Figure out how many items there are
  180. //    Re-sync if the number has changed
  181.     this->Synchronize ();
  182.  
  183. //    We need this info
  184.     if ( isFolder == nil )
  185.         isFolder = &aFolder;
  186.         
  187. //    look at items until:
  188. //    1> We get an error
  189. //    2> We get a file
  190. //    3> The options say that a folder is OK
  191.     do {
  192.     //    Get the next item, leaving if we got an error
  193.         if (( err = this->GetNextItem ( theSpec, isFolder )) != noErr )
  194.             break;
  195.         
  196.     //    If the user asked for just files, and we got a folder, try again
  197.         if (( fOptions & kJustFiles ) != 0 && *isFolder )
  198.             continue;
  199.  
  200.     //    If the thing is invisible and the caller asked for visible, try again
  201.         if (( fOptions & kJustVisible ) != 0 &&
  202.             ( fPb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible ) != 0 )
  203.             continue;
  204.         
  205.     //    None of those are true, so we're done
  206.         break;
  207.         } while ( true );
  208.     
  209. //    ReportError ( err );
  210.     return err;
  211.     }
  212.  
  213.  
  214. /*    -------------- TFileTreeIterator -------------------------- */
  215.  
  216. TFileTreeIterator:: TFileTreeIterator () {
  217. //    AssertStr ( 0, "\pDefault Constructor for TFileTreeIterator::TFileTreeIterator" );
  218.     }
  219.  
  220.  
  221. TFileTreeIterator::TFileTreeIterator ( FSSpec *startPoint, long options ) : TDirectoryIterator ( startPoint, options ) {
  222.     fChild = NULL;
  223.     }
  224.  
  225.  
  226. TFileTreeIterator::TFileTreeIterator ( short vRefNum, long dirID, long options ) : TDirectoryIterator ( vRefNum, dirID, options ) {
  227.     fChild = NULL;
  228.     }
  229.  
  230.  
  231. TFileTreeIterator::TFileTreeIterator ( TFileTreeIterator &rhs ) {
  232.     fChild = rhs.fChild;
  233.     }
  234.  
  235.  
  236. TFileTreeIterator::~TFileTreeIterator () {
  237.     if ( fChild != NULL )
  238.         delete fChild;
  239.     }
  240.  
  241.     
  242. TFileTreeIterator& TFileTreeIterator::operator= ( TFileTreeIterator& rhs ) {
  243.  
  244. //    Check for assignment to self
  245.     if ( &rhs == this )
  246.         return *this;
  247.  
  248. //    Let the superclass deal with its bits
  249.     * (TDirectoryIterator *) this = * (TDirectoryIterator *) &rhs;        
  250.  
  251. //    Do our work
  252.     fChild = rhs.fChild;
  253.     return *this;
  254.     }
  255.  
  256.  
  257. void TFileTreeIterator::Start ( void ) {
  258.     if ( fChild != NULL ) {
  259.         delete fChild;
  260.         fChild = NULL;
  261.         }
  262.     
  263.     TDirectoryIterator::Start ();
  264.     }
  265.  
  266.  
  267. Boolean    TFileTreeIterator::More ( void ) {
  268.     Boolean    retVal = false;
  269.     
  270.     if ( fChild != NULL ) {
  271.         retVal = fChild->More ();
  272.         if ( !retVal ) {
  273.             delete fChild;
  274.             fChild = NULL;
  275.             }
  276.         }
  277.     
  278.     if ( !retVal )
  279.         retVal = TDirectoryIterator::More ();
  280.     
  281.     return retVal;
  282.     }
  283.  
  284.  
  285. OSErr TFileTreeIterator::Next ( FSSpec *theSpec, Boolean *isFolder ) {
  286.     OSErr    err = noErr;
  287.     Boolean    fold;
  288.     
  289.     if ( isFolder == NULL )
  290.         isFolder = &fold;
  291.  
  292.     while ( err == noErr ) {
  293.         if ( fChild != NULL )
  294.             err = fChild->Next ( theSpec, isFolder );
  295.         else {
  296.         //    Get the next item
  297.             err = GetNextItem ( theSpec, isFolder );
  298.             if ( err == noErr ) {
  299.             //    If the thing is invisible and the caller asked for visible, try again
  300.                 if (( fOptions & kJustVisible ) != 0 &&
  301.                     ( fPb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible ) != 0 )
  302.                     continue;
  303.             
  304.             //    If we've found a directory, then spawn a new object
  305.                 if ( err == noErr && *isFolder ) {
  306.                     fChild = new TFileTreeIterator ( theSpec, fOptions );
  307.     //                AssertStr ( fChild != NULL, "\pCan't allocate new iterator in TFileTreeIterator::Next" );
  308.                     fChild->Start ();
  309.                     }
  310.                 }
  311.             }
  312.             
  313.     //    If we said just files, and we've got a folder, try again
  314.         if ( !*isFolder || ( fOptions & kJustFiles ) == 0 )
  315.             break;
  316.         }
  317.     
  318. //    ReportError ( err );
  319.     return err;
  320.     }
  321.