chxavfileutil.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:32k
源码类别:

Symbian

开发平台:

Visual C++

  1. /*****************************************************************************
  2.  * chxavfileutil.h
  3.  * ---------------
  4.  *
  5.  * Synopsis:
  6.  * File utility namespace.  Misc stuff for helping to work with filenames and
  7.  * paths.
  8.  *
  9.  * Target:
  10.  * Symbian OS
  11.  *
  12.  *
  13.  * (c) 1995-2003 RealNetworks, Inc. Patents pending. All rights reserved.
  14.  *
  15.  *****************************************************************************/
  16. // Symbian includes...
  17. #include <eikfutil.h>
  18. #include <f32file.h>
  19. #include <apgcli.h>
  20. #include <apmrec.h>
  21. #include <sysutil.h>
  22. #include <eikappui.h>
  23. #include <eikapp.h>
  24. // Helix includes...
  25. #include "hxtypes.h"
  26. #include "hxassert.h"
  27. #include "hxcom.h"
  28. #include "hxprefs.h" //IHXPreferences
  29. // Include from this project...
  30. #include "chxavutil.h"
  31. #include "chxavfileutil.h"
  32. #include "chxavcleanstring.h"
  33. #include "chxavutil.h"
  34. #include "chxavescapedstring.h"
  35. #include "chxavdirectoryreader.h"
  36. #include "chxavcleanupstack.h"
  37. #include "hxsym_debug.h"
  38. #include "hxapihelp.h"
  39. #include "hxsym_leaveutil.h"
  40. #include "hxsym_filetype.h"
  41. #include "hxsym_mimetypes.h"
  42. namespace CHXAvFile
  43. {
  44. // explictly instanciate GetFolderChildCount template here
  45. template
  46. TInt GetFolderChildCount(const TDesC& folderPath, 
  47.  TInt& countOut, bool bWantFolders,
  48.                                  PFNNanoPlayerFilterType isWantedFile);
  49. ////////////////////////////////////////////////////
  50. // get number of folders and files immediately within the
  51. // given directory (not recursive)
  52. //
  53. template <typename FileFilter>
  54. TInt GetFolderChildCount(const TDesC& folderPath, 
  55.  TInt& countOut, bool bWantFolders,
  56.                                  FileFilter isWantedFile)
  57. {
  58.     RFs& fs = CCoeEnv::Static()->FsSession();
  59.     CHXAvDirectoryReader reader(fs);
  60.     TInt error = KErrNone;
  61.     countOut = -1;
  62.     reader.SetSortFlags(ESortNone); // be as fast as possible; don't need sorting here
  63.     if( reader.SetToPath(folderPath) )
  64.     {
  65. countOut = 0;
  66. const CDir* pFiles = reader.GetFiles();
  67. if(pFiles)
  68. {
  69.             // only count files that are of interest and not hidden
  70.             TInt count = pFiles->Count();
  71.             for(TInt idx = 0; idx < count; ++idx)
  72.             {
  73.                 TEntry entry = (*pFiles)[idx];
  74.                 if( !CHXAvUtil::ShouldHideFromUser(entry) && isWantedFile(folderPath, entry.iName) )
  75.                 {
  76.                     ++countOut;
  77.                 }
  78.             }
  79.             pFiles = 0;
  80. }
  81. if( bWantFolders )
  82. {
  83.     const CDir* pFolders = reader.GetDirs();
  84.     if(pFolders)
  85.     {
  86.                 // add non-hidden directories to total
  87.                 TInt count = pFolders->Count();
  88.                 for(TInt idx = 0; idx < count; ++idx)
  89.                 {
  90.                     TEntry entry = (*pFolders)[idx];
  91.                     if( !CHXAvUtil::ShouldHideFromUser(entry) )
  92.                     {
  93.                         countOut += 1;
  94.                     }
  95.                 }
  96.     }
  97. }
  98.     }
  99.     else
  100.     {
  101. error = reader.GetLastError();
  102.     }
  103.     return error;
  104. }
  105. bool IsNanoPlayerFileType(const TDesC& fullPath)
  106. {
  107.     FileType fileType = GetFileType(fullPath);
  108.     return IsNanoPlayerFileType(fileType);
  109. }
  110. bool IsNanoPlayerFileType(const TDesC& folderPath, const TDesC& itemName)
  111. {
  112.     TFileName* fullPath = AllocFileNameL(folderPath, itemName);
  113.     AUTO_PUSH_POP_DEL(fullPath);
  114.     FileType fileType = GetFileType(*fullPath);
  115.     return IsNanoPlayerFileType(fileType);
  116. }
  117. ////////////////////////////////
  118. // get fully qualified absolute path (with drive letter prefix), ensuring that it
  119. // exists
  120. //
  121. // searches all available drives: first session drive (normally 'c:'), then y to a, then z
  122. //
  123. // if a drive letter is supplied, only that drive will be searched; other
  124. // drives are not searched
  125. //
  126. // Parameters:
  127. //
  128. // path     - absolute (with drive) or relative (to unspecified drive) path;
  129. //            must have folder suffix if a folder is wanted
  130. // fullPath - fully qualified absolute and verified path (with drive letter prefix) 
  131. //            if return is KErrNone
  132. //
  133. // bAllowWildCard - returns first match if true (even if multiple matches!)
  134. //
  135. TInt GetFullPath(RFs& fs, const TDesC& path, TDes& fullPath, bool bAllowWildCard)
  136. {
  137.     DPRINTF(SYMP_FILE, ("CHXAvFile::GetFullPath(): looking for '%s'n", dbg::CharPtr(path)()));
  138.     TInt err = KErrNotFound;
  139.     fullPath = KNullDesC;
  140.     
  141.     TInt idxDrive = GetDriveIndex(path);
  142.     if( (-1 != idxDrive) && path.Length() <= 3 )
  143.     {
  144.         //
  145.         // special case: confirming that drive root path (e.g. 'e:') exists
  146.         // 
  147.         // TFileFind fails if we specify root path 
  148.         //
  149.         if(PathExists(path))
  150.         {
  151.             fullPath = path;
  152.             err = KErrNone;
  153.         }
  154.     }
  155.     else
  156.     {
  157.         TFindFile find(fs);
  158.     
  159.         CDir* pDir = 0;
  160.         if(bAllowWildCard)
  161.         {
  162.             // search for first match
  163.             err = find. FindWildByDir(path, KNullDesC, pDir);
  164.         }
  165.         else
  166.         {
  167.             err = find.FindByDir(path, KNullDesC);
  168.         }
  169.         if (err == KErrNone)
  170.         {
  171.             if(pDir)
  172.             {
  173.                 fullPath = GetFolderPath(find.File());
  174.                 if( pDir->Count() > 0 )
  175.                 {
  176.                     // File() returns drive and path in this case; set returned path to first entry found
  177.                     fullPath.Append( (*pDir)[0].iName );
  178.                 }
  179.                 HX_DELETE(pDir);
  180.             }
  181.             else
  182.             {
  183.                 fullPath = find.File();
  184.             }
  185.             // if drive was specified for sought-after path, ensure found path matches
  186.         
  187.             if( idxDrive != -1 )
  188.             {
  189.                 //
  190.                 // TFindFile will search for path on an alternate drive
  191.                 // if it fails to find a path on a specified drive; it treats drive letter
  192.                 // as meaning 'preferred' as opposed to 'required' (as we do)
  193.                 //
  194.                 TInt idxDriveFound = GetDriveIndex(fullPath);
  195.                 if(idxDriveFound != idxDrive)
  196.                 {
  197.                     // path doesn't exist on drive we wanted; refuse path on alternate drive
  198.                     fullPath = KNullDesC;
  199.                     err = KErrNotFound;
  200.                 }
  201.             }
  202.         }
  203.     }
  204.     
  205.     DPRINTF(SYMP_FILE, ("GetFullPath(): found '%s'n", dbg::CharPtr(fullPath)()));
  206.     return err;
  207. }
  208. ////////////////////////////////////////////////////////
  209. // alloc default name; append (N) to name until name is unique
  210. // within the path 
  211. //
  212. // defaultName      - name of file or folder to begin with ('name' or 'name/')
  213. // basePath         - full base path
  214. //
  215. // e.g., New Folder, New Folder(01), New Folder(02)
  216. //
  217. // returns 0 if: 
  218. //    a) no unique name could be found (bad base path or roque tester); 
  219. //    b) not enough space to fit suggested name plus prefix (base path + default name near max TFileName)
  220. //
  221. // XXXLCM consider using CApaApplication::GenerateFileName
  222. //
  223. TFileName* AllocUniqueDefaultNameL(const TDesC& basePath, 
  224.                                const TDesC& defaultName, 
  225.                                bool bWantFolder, 
  226.                                const CHXAvNameDisplayTrait& nameTrait)
  227. {
  228.     _LIT(KDuplicateNameFormat, "%S(%02d)");
  229.     const TUint k_cchSuffix = 4; //"(NN)"
  230.     const TUint k_maxTries = 100;
  231.     TFileName* pPathOut = 0;
  232.     
  233.     // make sure we have a qualified name (indicating folder or file)
  234.     TFileName* pFullDefaultName = AllocFileNameL(defaultName, (bWantFolder ? CHXAvFile::ntFolder : CHXAvFile::ntFile));
  235.     AUTO_PUSH_POP_DEL(pFullDefaultName);
  236.     // break up qualified name for display and formatting
  237.     NameExt nameInfo = nameTrait.GetDisplayText(*pFullDefaultName, bWantFolder);
  238.     // max chars for 'name' in 'name.xx'
  239.     TInt cchMaxNamePart = KMaxFileName - basePath.Length() - nameInfo.second.Length();
  240.     if( !HasFolderSuffix(basePath) )
  241.     {
  242.         cchMaxNamePart -= 1; // for path sep that would be added to form full path
  243.     }
  244.     if ( cchMaxNamePart > 0 )
  245.     {
  246.         // possibly crop 'name' in 'name.xx' 
  247.         if( nameInfo.first.Length() > cchMaxNamePart )
  248.         {
  249.             nameInfo.first.Set(nameInfo.first.Ptr(), cchMaxNamePart);
  250.         }
  251.         // working display name buffer
  252.         HBufC* pDisplayName = HBufC::NewMaxL(nameInfo.first.Length() + k_cchSuffix);
  253.         AUTO_PUSH_POP_DEL(pDisplayName);
  254.         TPtr ptrDisplayName = pDisplayName->Des();
  255.     
  256.         // potential name to be displayed to user
  257.         ptrDisplayName.Copy(nameInfo.first);
  258.         // full path to go out
  259.         pPathOut = new (ELeave) TFileName;
  260.         AUTO_PUSH_POP(pPathOut);
  261.         bool bFound = false;
  262.         for(TInt idx = 0; idx < k_maxTries; ++idx)
  263.         {
  264.             // re-form path and see if it is unique
  265.             pPathOut->Copy(basePath);
  266.             AppendPath(*pPathOut, ptrDisplayName, CHXAvFile::ntUnspecified);
  267.             pPathOut->Append(nameInfo.second);
  268.         
  269.             DPRINTF(SYMP_FILE, ("AllocUniqueDefaultFilenameL(): testing '%s'n", dbg::CharPtr(*pPathOut)()));
  270.             if(!PathExists(*pPathOut))
  271.             {
  272.                 // found a unique name
  273.                 bFound = true;
  274.                 break;
  275.             }
  276.             // from now on we'll be adding suffix...
  277.             // max chars for 'name' in 'name(NN).xx'
  278.             TInt cchMaxNamePartMinusSuffix = cchMaxNamePart - k_cchSuffix;
  279.             if(cchMaxNamePartMinusSuffix <= 0 )
  280.             {
  281.                 // give up...
  282.                 break;
  283.             }
  284.             // possibly crop 'name' in 'name(NN)' 
  285.             if( nameInfo.first.Length() > cchMaxNamePartMinusSuffix )
  286.             {
  287.                 nameInfo.first.Set(nameInfo.first.Ptr(), cchMaxNamePartMinusSuffix);
  288.             }
  289.             // name was not unique; try next (start with 01)
  290.             ptrDisplayName.Format(KDuplicateNameFormat, &nameInfo.first, idx + 1);
  291.         }
  292.         if( !bFound )
  293.         { 
  294.             HX_DELETE(pPathOut);
  295.         }
  296.     }
  297.     return pPathOut;
  298. }
  299. ////////////////////////////////////////////////////////////
  300. //
  301. // fullPath     - full path to file or folder; folders must have folder suffix
  302. //
  303. bool PathExists(const TDesC& fullPath)
  304. {
  305.     DPRINTF(SYMP_FILE, ("PathExists(): checking path '%s'n", dbg::CharPtr(fullPath)()));
  306.     RFs& fs = CCoeEnv::Static()->FsSession();
  307.     
  308.     //
  309.     // note: BaflUtils::PathExists() is only api that appears to correctly 
  310.     // validate a root folder, e.g., 'c:')
  311.     //
  312.     if(HasFolderSuffix(fullPath))
  313.     {
  314.         return BaflUtils::PathExists(fs, fullPath);
  315.     }
  316.     return BaflUtils::FileExists(fs, fullPath);
  317.     
  318. }
  319. ////////////////////////////////
  320. //
  321. // return 0-based index of drive relative to 'a'; -1 if no drive specified
  322. //
  323. // (note: a valid index maps to TDriveNumer)
  324. //
  325. // 'c:'             -> 2
  326. // 'a:'            -> 0
  327. // 'e:foobar     -> 4
  328. // 'foobar'       -> -1
  329. // 'c:hello'        -> -1
  330. //
  331. TInt GetDriveIndex(const TDesC& path)
  332. {
  333.     DPRINTF(SYMP_FILE, ("GetDriveIndex(): checking '%s'n", dbg::CharPtr(path)()));
  334.     TInt idx = -1;
  335.     const TInt k_cchMinPath = 2; // must have at least 'a:'
  336.     TInt cchPath = path.Length();
  337.     if( cchPath >= k_cchMinPath )
  338.     {
  339.         TChar ch = path[0];
  340.         bool bGood = ( ch.IsAlpha() && (path[1] == KDriveDelimiter) );
  341.         if( bGood && (cchPath != k_cchMinPath) )
  342.         {
  343.             // a '' is required unless the path is solely in the format 'a:'
  344.             bGood = (path[2] == KPathDelimiter);
  345.         }
  346.         if( bGood )
  347.         {
  348.             ch.LowerCase();
  349.             idx = ch - TChar('a');
  350.         }
  351.     }
  352.     DPRINTF(SYMP_FILE, ("GetDriveIndex(): index is %dn", idx));
  353.     return idx;
  354. }
  355. ////////////////////////////////////////////////////
  356. //
  357. CHXAvFile::DriveState TranslateDriveErrorCode(TInt err)
  358. {
  359.     CHXAvFile::DriveState driveState(dsUnknown);
  360.     
  361.     DPRINTF(SYMP_FILE, ("TranslateDriveErrorCode(): epoc code = %dn", err));
  362.     // translate error code
  363.     switch (err)
  364.     {
  365.         case KErrNone:
  366.             driveState = dsAccessible;
  367.             break;
  368.         case KErrLocked:
  369.             driveState = dsLocked;
  370.             break;
  371.         case KErrCorrupt:
  372.             driveState = dsCorrupted;
  373.             break;
  374.         default:
  375.             driveState = dsUnknown;
  376.             break;
  377.     }
  378.     DPRINTF(SYMP_FILE, ("TranslateDriveErrorCode(): code = %dn", driveState));
  379.     return driveState;
  380. }
  381. ////////////////////////////////////////////////////
  382. //
  383. // lazy-mount drive (if necessary) and return true if locked
  384. //
  385. bool IsMountLocked(TInt idxDrive)
  386. {
  387.     DPRINTF(SYMP_FILE, ("IsMountLocked(): idxDrive = %dn", idxDrive));
  388.     RFs& fs = CCoeEnv::Static()->FsSession();
  389.     TFullName fsName;
  390.     TInt err = fs.FileSystemName(fsName, idxDrive);
  391.     DPRINTF(SYMP_FILE, ("IsMountLocked(): err = %d; fs name = %sn", err, dbg::CharPtr(fsName)()));
  392.     if( (KErrNone == err) && (0 == fsName.Length()) )
  393.     {
  394.         DPRINTF(SYMP_FILE, ("IsMountLocked(): no name; mountingn"));
  395.         //
  396.         // drive is present but not mounted; attempt to mount drive
  397.         // now; mmc mount will succeed if password is cached
  398.         //
  399.         _LIT( KFat, "Fat" );
  400.         err = fs.MountFileSystem(KFat, idxDrive);
  401.     }
  402.     
  403.     return (err == KErrLocked);
  404. }
  405. ////////////////////////////////////////////////////
  406. // from experimentation on device:
  407. //
  408. // local fs:
  409. //  FileSystemName returns 0; name = 'Lffs'
  410. //  type = 6 (EMediaFlash); drive attr = 145; media_attr = 4(KMediaAttFormattable)
  411. //
  412. // unlocked mmc inserted:
  413. //  FileSystemName returns 0; name = 'Fat'
  414. //  type = 3 (EMediaHardDisk); drive attr = 33; media attr = 84(KMediaAttFormattable + 0x80)
  415. //
  416. // unlocked mmc, low mem:
  417. //  type = 0 (EMediaNotPresent); attr = 33; media att = 112 (0x20 = KMediaAttLocked)
  418. //
  419. // locked mmc inserted:
  420. //  FileSystemName returns 0; name = ''
  421. //  MountFileSystem returns -22 (KErrLocked) 
  422. //  Volume() fails, returns -18 (KErrNotReady) 
  423. //
  424. // mmc not inserted
  425. //  FileSystemName returns 0; name = 'Fat'
  426. //  Volume() fails, returns -18 (KErrNotReady)
  427. //
  428. ////////////////////////////////////////////////////
  429. // get drive information from drive index
  430. //
  431. DriveInfo GetDriveInfo(TInt idxDrive)
  432. {
  433.     DPRINTF(SYMP_FILE, ("GetDriveInfo(): looking at drive '%c:'n", idxDrive + 'a'));
  434.     DriveInfo info;
  435.    
  436.     if(idxDrive != -1)
  437.     {
  438.         info.idxDrive = idxDrive;
  439.         
  440.         //
  441.         // This will fail if drive is locked or not inserted
  442.         //
  443.         RFs& fs = CCoeEnv::Static()->FsSession();
  444.         TInt err = fs.Volume(info.volInfo, idxDrive);
  445.         if( KErrNone == err )
  446.         {
  447.             info.bVolInfoValid = true;
  448.         
  449.             TDriveInfo& drive = info.volInfo.iDrive;
  450.             DPRINTF(SYMP_FILE, ("GetDriveInfo(): type = %d; drive_attr = %d; media_attr = %dn",
  451.                                 drive.iType, drive.iDriveAtt, drive.iMediaAtt));
  452.             info.type = drive.iType;
  453.             if(drive.iDriveAtt != EMediaNotPresent)
  454.             {
  455.                 // only in this case can we access...
  456.                 info.state = dsAccessible;
  457.             }
  458.             else
  459.             {
  460.                 // this case (not normal) appears to occur when memory is low!
  461.                 DPRINTF(SYMP_FILE, ("GetDriveInfo(): drive absentn"));
  462.                 info.state = dsUnknown;
  463.                 info.type = EMediaNotPresent; // just for sanity
  464.             }
  465.             if( drive.iMediaAtt & KMediaAttLocked)
  466.             {
  467.                 // drive is reported locked when it is not when memory is low; we won't argue
  468.                 info.state = dsLocked;
  469.             }
  470.         }
  471.         else
  472.         {
  473.             DPRINTF(SYMP_FILE, ("GetDriveInfo(): Volume() failedn"));
  474.             //
  475.             // Volume() doesn't fail with KErrLocked as you might expect (when drive is in fact locked)! Do explicit check.
  476.             //
  477.             if( IsMountLocked(idxDrive) )
  478.             {
  479.                 info.state = dsLocked;
  480.             }
  481.             else
  482.             {
  483.                 
  484.                 info.state = TranslateDriveErrorCode(err);
  485.             }
  486.         }
  487.     }
  488.     return info;
  489. }
  490. ////////////////////////////////////////////////////////////
  491. // allocate a TFileName with assembled folder and name:
  492. //
  493. //  first        - folder suffix '/' is optional; KNullDesC is OK
  494. //  second       - folder prefix '/' is optional; KNullDesC is OK
  495. //  type         - if ntFolder, ensure trailing folder suffix '/'
  496. //               - if ntFile, ensure no trailing folder suffix
  497. //               - if ntUnspecified, append second as is
  498. //
  499. // examples (before possibly adding or removing trailing folder suffix based on type):          
  500. //
  501. // "path"   + "file"   -> "pathfile"
  502. // "path"  + "file'    -> "pathfile"
  503. // ""       + "file"    -> "file"
  504. // "c:path"   + ""     -> "c:path"
  505. // "path"   + "file"  -> "pathfile"
  506. //
  507. //
  508. TFileName* AllocFileNameL(const TDesC& first, const TDesC& second, NameType type)
  509. {
  510.     TFileName* pName = new (ELeave) TFileName;
  511.     AUTO_PUSH_POP(pName);
  512.     pName->Copy(first);
  513.     AppendPath(*pName, second, type);
  514.     return pName;
  515. }
  516. TFileName* AllocFileNameL(const TDesC& path, NameType type )
  517. {
  518.     return AllocFileNameL(path, KNullDesC, type);
  519. }
  520. HBufC* AllocFileUrlL(const TDesC& path)
  521. {
  522.     // get path with backslashes converted to forward slashes
  523.     HBufC* pbuff = CHXAvStringUtils::AllocTextL(path);
  524.     AUTO_PUSH_POP_DEL(pbuff);
  525.     TPtr ptr = pbuff->Des();
  526.     BackToForwardSlash(ptr);
  527.     // in case path has special characters that need to be escaped (e.g., '#' or '%')
  528.     CHXAvEscapedString escPath;
  529.     escPath.EscapePathStr(CHXAvStringUtils::DescToString(*pbuff));
  530.     CHXString strEscaped = escPath.GetEscapedStr();
  531.     HBufC* pEscaped = CHXAvStringUtils::StringToHBuf(strEscaped);
  532.     AUTO_PUSH_POP_DEL(pEscaped);
  533.     // concatenate file:// prefix
  534.     HBufC* pURL = CHXAvStringUtils::AllocTextL(KFileProtocolPrefix, *pEscaped);
  535.     
  536.     return pURL;
  537. }
  538. ////////////////////////////////////////////////////////////
  539. //
  540. // append path element to path, ensuring that optional path 
  541. // separators make sense
  542. //
  543. //    path              - folder suffix ('/') at end  is optional
  544. //    tail              - path prefix ('/') at beggining is optional; will be added if missing
  545. //
  546. //    type              - if 'folder' ensures trailing '/' exists on end of path
  547. //                      - if 'file' ensures trailing '/' does not exist on end of path
  548. //                      - if 'unspecified', just appends tail as is
  549. void AppendPath(TDes& path, const TDesC& name, NameType type)
  550. {
  551.     // XXXLCM check total size doesn't overflow KMaxFileName (AppendPathL, or copy to max)
  552.     if( name.Length() > 0 )
  553.     {
  554.         // make sure existing path has trailing folder suffix
  555.         EnsureFolderSuffix(path);
  556.         TPtrC ptrName;
  557.         TInt idxBegin = 0;
  558.         TInt idxEnd = name.Length();
  559.         if( (ntFile == type) && HasFolderSuffix(name) )
  560.         {
  561.             // don't include trailing slash - we are forming a filename
  562.             idxEnd--;
  563.         }
  564.         if(HasFolderPrefix(name))
  565.         {
  566.             // don't append the first path sep
  567.             idxBegin++;
  568.         }
  569.             
  570.         ptrName.Set(name.Mid(idxBegin, idxEnd - idxBegin));
  571.         path.Append(ptrName);
  572.     }
  573.     if( ntFolder == type )
  574.     {
  575.         EnsureFolderSuffix(path);
  576.     }
  577. }
  578. ////////////////////////////////////////////////////////////
  579. //
  580. // return path with filename part lopped off
  581. //
  582. // "foobar"  -> foo          <-- bar is interpreted as file
  583. // "foobar" -> foobar
  584. // "foo"     -> foo
  585. // "file.rm"  -> 
  586. // "foo"       -> KNullDesc
  587. // ""          -> KNullDesc
  588. //
  589. TPtrC GetFolderPath(const TDesC& path)
  590. {
  591.     TInt idx = path.Length();
  592.     if( idx > 0 )
  593.     {
  594. // find current folder root
  595. idx = path.LocateReverse(KPathDelimiter);
  596. if( KErrNotFound != idx )
  597. {
  598.     // include trailing ''
  599.     return path.Left(idx + 1);
  600. }
  601.     }
  602.     return TPtrC(KNullDesC);
  603. }
  604. ////////////////////////////////////////////////////////////
  605. //
  606. // return path to folder that is parent of current
  607. // folder
  608. //
  609. // "foobar"  -> foo       <-- bar is interpreted as file
  610. // "foobar" -> foo
  611. // "foo"     -> 
  612. // ""         -> KNullDesc
  613. // "foo"       -> KNullDesc
  614. // ""          -> KNullDesc
  615. //
  616. TPtrC GetParentFolder(const TDesC& path)
  617. {
  618.     TPtrC parent(KNullDesC);
  619.     // find current folder root
  620.     TInt idx = path.LocateReverse(KPathDelimiter);
  621.     if( idx > 0 )
  622.     {
  623.         if( HasFolderSuffix(path) )
  624.         {
  625.             // path name is a folder; skip the folder suffix and get parent folder
  626.     TPtrC current = path.Left(idx);
  627.     idx = current.LocateReverse(KPathDelimiter);
  628.         }
  629.         if( idx > 0 )
  630.         {
  631.             parent.Set(path.Left(idx + 1));
  632.         }
  633.     }
  634.     
  635.     return parent;
  636. }
  637. ////////////////////////////////////
  638. // return true if 'childPath' specifies a path that
  639. // is under the parentPath
  640. //
  641. // c:myfoldermusic      c:myfoldermusicrock      true
  642. // c:myfoldermusic      c:myfoldermusicstyx.rm    true
  643. // myfoldermusic        myfoldermusicclassical    true
  644. // c:myfoldermusic      myfoldermusicrock        false (ambiguous)
  645. // c:myfoldermusic      c:myfoldermusic           false (same path)
  646. // {empty path}            {whatever}                   false (an invalid path can't have children)
  647. //
  648. bool IsSubPath(const TDesC& parentPath, const TDesC& childPath)
  649. {
  650.     bool bIsSubPath = false;
  651.     TInt parentLength = parentPath.Length();
  652.     // empty parent path means no path (can't have child)
  653.     if( parentLength > 0 )
  654.     {
  655.         // a child path must be longer than the parent path
  656.         if(childPath.Length() > parentPath.Length())
  657.         {
  658.     // get possible matching base path from the parent
  659.     TPtrC childBasePath = childPath.Left(parentLength);
  660.     bIsSubPath = (0 == childBasePath.CompareF(parentPath));
  661.         }
  662.     }
  663.     return bIsSubPath;
  664. }
  665. ////////////////////////////////////
  666. //
  667. // get name-only part of most-significant part of path
  668. //
  669. // "foobarfile.rm" -> "file.rm"
  670. // "foobar"        -> "bar"
  671. // "foobar"         -> "bar"
  672. // "foobar "       -> " "
  673. // "bar"             -> "bar"
  674. // "bar"              -> "bar"
  675. // ""                -> ""
  676. //
  677. // other stuff (e.g., "\\") undefined
  678. //
  679. TPtrC GetNakedPathNode(const TDesC& path)
  680. {
  681.     TPtrC name(path);
  682.     TInt idxLastPathSep = path.LocateReverse(KPathDelimiter);
  683.     if( KErrNotFound != idxLastPathSep )
  684.     {
  685. HX_ASSERT(path.Length() > 0);
  686. if( idxLastPathSep == path.Length() - 1)
  687. {
  688.     // node is a folder
  689.     // make path look like a file  and recurse
  690.     TPtrC newPath = path.Left(path.Length() - 1);
  691.     name.Set(GetNakedPathNode(newPath));
  692. }
  693. else
  694. {
  695.     // node is a file
  696.     name.Set(path.Mid(idxLastPathSep + 1));
  697. }
  698.     }
  699.     return name;
  700. }
  701. ////////////////////////////////////
  702. // same as GetNakedPathNode(), but
  703. // also trims of off file extension
  704. //
  705. // "folder/foo.rm" ->       "foo"
  706. // "folder/child/" ->       "child"
  707. // "folder/child.rm/ ->     "child" <- oops?
  708. //
  709. TPtrC GetNakedName(const TDesC& path)
  710. {
  711.     TPtrC ptrName = GetNakedPathNode(path);
  712.     TInt idx = ptrName.LocateReverse(KExtDelimiter);
  713.     if( KErrNotFound != idx )
  714.     {
  715. ptrName.Set(ptrName.Ptr(), idx);
  716.     }
  717.     return ptrName;
  718. }
  719. /////////////////////////////////////
  720. // get extension only (with dot)
  721. //
  722. // "folder/foo.rm" -> ".rm"
  723. //
  724. TPtrC GetExtension(const TDesC& path)
  725. {
  726.     TPtrC ptrExt = GetNakedPathNode(path);
  727.     TInt idx = ptrExt.LocateReverse(KExtDelimiter);
  728.     if(KErrNotFound != idx)
  729.     {
  730. ptrExt.Set(ptrExt.Mid(idx));
  731.     }
  732.     else
  733.     {
  734. ptrExt.Set(KNullDesC);
  735.     }
  736.     return ptrExt;
  737. }
  738. /////////////////////////////////////
  739. // Trim folder suffix if present and return path
  740. //
  741. // c:myfoldermusic   =>  c:myfoldermusic
  742. // myfolder            =>  myfolder
  743. // c:myfolderfile.rm  =>  c:myfolderfile.rm
  744. //
  745. TPtrC GetEnsureNoFolderSuffix(const TDesC& path)
  746. {
  747.     TPtrC name(path);
  748.     if( HasFolderSuffix(path) )
  749.     {
  750.         name.Set(path.Left(path.Length() - 1));
  751.     }
  752.     return name;
  753. }
  754. ////////////////////////////////////////////////////////////
  755. // make sure we have enough disk space to make the copy
  756. // 
  757. // copy goes to flash or mmc
  758. //
  759. TInt CheckDiskSpaceForCopyL(const TDesC& fullPathSource, TInt idxDriveDest)
  760. {
  761.     CCoeEnv* pEnv = CCoeEnv::Static();
  762.     RFs& fs = pEnv->FsSession();
  763.     TEntry entry;
  764.     TInt err = fs.Entry(fullPathSource, entry);
  765.     if( KErrNone == err )
  766.     {
  767.         if( EDriveE == idxDriveDest )
  768.         {
  769.             // assume drive E is mmc
  770.             if( SysUtil::MMCSpaceBelowCriticalLevelL( &fs, entry.iSize) ) 
  771.     {
  772.         err = KErrDiskFull;
  773.     }
  774.         }
  775.         else
  776.         {
  777.             // assume everything else is flash
  778.             if( SysUtil::FFSSpaceBelowCriticalLevelL( &fs, entry.iSize) ) 
  779.             {
  780.                 err = KErrDiskFull;
  781.             }
  782.         }
  783.     }
  784.     return err;
  785. }
  786. ////////////////////////////////////////////////////
  787. // create list of folders under the parent path
  788. // 
  789. // useful for populating a folder list (e.g., 'move to', 'save to')
  790. // 
  791. CDesCArrayFlat* AllocFolderListL(const TDesC& parentPath, bool bSorted)
  792. {
  793.     CDesCArrayFlat* pItems = new (ELeave) CDesCArrayFlat(20 /*granularity*/);
  794.     AUTO_PUSH_POP(pItems); // out
  795.     // read directory contents under parent path path...
  796.     CHXAvDirectoryReader reader;
  797.     if( reader.SetToPath(parentPath) )
  798.     {
  799. const CDir* pFolders = reader.GetDirs();
  800. if( pFolders )
  801. {
  802.     TInt count = pFolders->Count();
  803.     for( TInt idx = 0; idx < count; ++idx )
  804.     {
  805. const TEntry& entry = (*pFolders)[idx];
  806. HX_ASSERT(entry.IsDir()); 
  807.                 if( !CHXAvUtil::ShouldHideFromUser(entry) )
  808.                 {
  809.                     // add this folder
  810.     pItems->AppendL(entry.iName);
  811.                 }
  812.     }
  813. }
  814.         // just in case; underlying api should sort directory list
  815.         if( bSorted )
  816.         {
  817.     pItems->Sort(ECmpCollated);
  818.         }
  819.     }
  820.     else
  821.     {
  822.         HXSYM_LEAVE(reader.GetLastError());
  823.     }
  824.      
  825.     return pItems;
  826. }
  827. ////////////////////////////////////////
  828. // additional filename validity checking beyond just checking
  829. // for illegal characters
  830. //
  831. //      name        - filename-only part of path (i.e., not a path)
  832. //
  833. FileNameValidity GetFileNameValidity(const TDesC& name)
  834. {
  835.     FileNameValidity validity = nvValid;
  836.     //
  837.     // check special cases first; RFs::IsValidName() doesn't catch everything
  838.     //
  839.     if(name.Length() > KMaxFileName )
  840.     {
  841.         // name is too long for sure (RFs::IsValidName() will simply return 'false')
  842.         validity = nvTooLong;
  843.     }
  844.     else if(0 == name.Right(1).Compare(CHXAvUtil::KDot) )
  845.     {
  846.         // name can never end in dot
  847.         validity = nvInvalidDots;
  848.     }
  849.     else if(0 == name.Compare(CHXAvUtil::KDot) || 0 == name.Compare(CHXAvUtil::KDoubleDot))
  850.     {
  851.         // name cannot be '.' or '..'
  852.         validity = nvInvalidDots;
  853.     }
  854.     else
  855.     {
  856.         RFs& fs = CCoeEnv::Static()->FsSession();
  857.         if(!fs.IsValidName(name))
  858.         {
  859.             validity = nvInvalidIllegalChars;
  860.         }
  861.     }
  862.     return validity;
  863. }
  864. ////////////////////////////////////////////////////////////
  865. // return file size in bytes (-1 if can't determine)
  866. TInt GetFileSize(const TDesC& fileName)
  867. {
  868.     CCoeEnv* pEnv = CCoeEnv::Static();
  869.     RFs& fs = pEnv->FsSession();
  870.     TEntry entry;
  871.     TInt err = fs.Entry(fileName, entry);
  872.     if(KErrNone != err)
  873.     {
  874.         entry.iSize = -1;
  875.     }
  876.     return entry.iSize;
  877. }
  878. // Unset read-only attribute for file (not folder)
  879. TInt EnsureClearReadOnlyAttributeForFile(const TDesC& fileName)
  880. {
  881.     HX_ASSERT(!HasFolderSuffix(fileName));
  882.     CCoeEnv* pEnv = CCoeEnv::Static();
  883.     RFs& fs = pEnv->FsSession();
  884.     //KEntryAttVolume
  885.     //KEntryAttDir
  886.     //KEntryAttArchive
  887.     //KEntryAttSystem
  888.     //KEntryAttHidden
  889.     //KEntryAttReadOnly
  890.     //KEntryAttNormal
  891.     TUint attr = 0;
  892.     TInt err = fs.Att(fileName, attr);
  893.     if( KErrNone == err )
  894.     {
  895.         //DPRINTF(SYMP_FILE, ("EnsureClearReadOnlyAttributeForFile(): att for '%s' = 0x%08xn", dbg::CharPtr(fileName)(), attr));
  896.         if( attr & KEntryAttReadOnly )
  897.         {
  898.             DPRINTF(SYMP_FILE, ("EnsureClearReadOnlyAttributeForFile(): unsetting read-only attributen"));
  899.             err = fs.SetAtt(fileName, 0, KEntryAttReadOnly /*remove*/);
  900.         }
  901.     }
  902.     return err;
  903. }
  904. //
  905. // Unset read-only attribute for given file. If fileName is a folder (indicated
  906. // by trailing slash), all folder children will have read-only attributes removed.
  907. //
  908. TInt EnsureClearReadOnlyAttributeL(const TDesC& fileName)
  909. {
  910.     RFs& fs = CCoeEnv::Static()->FsSession();
  911.     TInt err = KErrNone;
  912.     if( HasFolderSuffix(fileName) )
  913.     {
  914.         DPRINTF(SYMP_FILE, ("EnsureClearReadOnlyAttributeL(): unsetting read-only attribute for foldern"));
  915.         // recursively unset attributes for folder 
  916.         CFileMan* pFileMan = CFileMan::NewL(fs);
  917.         AUTO_PUSH_POP_DEL(pFileMan);
  918.    
  919.         TTime tm; // ignored
  920.         const TUint setMask = 0;
  921.         const TUint clearMask = KEntryAttReadOnly;
  922.         // trim folder suffix
  923.         TPtrC ptrName = CHXAvFile::GetEnsureNoFolderSuffix(fileName);
  924.         // note: this does not work well for filenames (even with flag set 0)?!? (in emulator file becomes inaccessible)
  925.         err = pFileMan->Attribs(ptrName, setMask, clearMask, tm, CFileMan::ERecurse); 
  926.     }
  927.     else
  928.     {
  929.         err = EnsureClearReadOnlyAttributeForFile(fileName);
  930.     }
  931.     DPRINTF(SYMP_FILE, ("EnsureClearReadOnlyAttributeL(): result = %dn", err));
  932.     return err;
  933. }
  934. ////////////////////////////////////////////////
  935. // return 'true' if path is absolute, i.e., begins with:
  936. //
  937. //  a) a drive letter colon and slash (c:)
  938. //  b) a slash ()
  939. //
  940. bool HasDriveOrRootPrefix(const TDesC& path)
  941. {
  942.     bool bHasIt = false;
  943.     TInt idx = GetDriveIndex(path);
  944.     if( idx != -1 )
  945.     {
  946.         bHasIt = false;
  947.     }
  948.     else
  949.     {
  950.         bHasIt = HasFolderPrefix(path);
  951.     }
  952.     return bHasIt;
  953. }
  954. ////////////////////////////////////////////////
  955. // prefix given relative path with full player app folder path
  956. //
  957. TFileName* AllocAppFolderPathL(const TDesC& path)
  958. {
  959.     // also see:
  960.     // #include <aknutils.h>
  961.     // CompleteWithAppPath(fullPathLibRoot);
  962.     HX_ASSERT(!HasDriveOrRootPrefix(path));
  963.     TFileName* pOut = new (ELeave) TFileName;
  964.     AUTO_PUSH_POP(pOut);  
  965.     // get our app directory base path
  966.     CEikAppUi* pAppUI = reinterpret_cast<CEikAppUi*>(CCoeEnv::Static()->AppUi());
  967.     HX_ASSERT(pAppUI);
  968.     TFileName dllName = pAppUI->Application()->DllName();
  969.     TPtrC appRootPath = GetFolderPath(dllName);
  970.     pOut->Copy(appRootPath);
  971.     AppendPath(*pOut, path, CHXAvFile::ntUnspecified);
  972.   
  973.     return pOut;
  974. }
  975. ////////////////////////////////////////////////////////
  976. // Allocate path from preferences. If path is not fully 
  977. // specified (with drive letter), assume it is relative
  978. // to app folder
  979. //
  980. // return 0 if pref key does not exist
  981. //
  982. TFileName* AllocFullPrefPathL(IHXPreferences* pPrefs, const char* prefKey)
  983. {
  984.     TFileName* pFullPath = 0;
  985.     
  986.     // get path from prefs
  987.     CHXString strPath = prefs::GetString(pPrefs, prefKey);
  988.     if(!strPath.IsEmpty())
  989.     {
  990.         CHXAvCleanString descPath(strPath);
  991.         if(!CHXAvFile::HasDriveOrRootPrefix(descPath()))
  992.         {
  993.             pFullPath = CHXAvFile::AllocAppFolderPathL(descPath());
  994.         }
  995.         else
  996.         {
  997.             pFullPath = new (ELeave) TFileName();
  998.             HXSYM_LEAVE_IF_FALSE(descPath().Length() <= KMaxFileName);
  999.             pFullPath->Copy(descPath());
  1000.         }
  1001.     }
  1002.     return pFullPath;
  1003. }
  1004. } //ns CHXAvFile