filespec.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:18k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. #include "hxstring.h"
  36. #include "filespec.h"
  37. #include "dbcs.h"
  38. #define MAX_PATH_COMPONENTS 256
  39. //////////////////////////////////////////////////////////
  40. //
  41. // Utility base class -- CHXPathParser
  42. //
  43. //////////////////////////////////////////////////////////
  44. CHXPathParser::CHXPathParser()
  45. : m_bEmpty(TRUE)
  46. , m_bIsValid(FALSE)
  47. {
  48. }
  49. CHXPathParser &CHXPathParser::operator=(const CHXPathParser &other)
  50. {
  51.     if(!other.IsSet())
  52.     {
  53. m_bEmpty = TRUE;
  54. m_path = "";
  55.     }
  56.     else
  57. ParsePath(other.m_path);
  58.     return *this;
  59. }
  60. BOOL CHXPathParser::operator==(const CHXPathParser &other)
  61. {
  62.     // for now, just returns if the paths are identical
  63.     // in the future, should normalize paths (i.e. remove duplicate slashes, resolve ...... type issues
  64.     return m_path.CompareNoCase(other.m_path) == 0;
  65. }
  66. BOOL CHXPathParser::operator!=(const CHXPathParser &other)
  67. {
  68.     // for now, just returns if the paths are not identical
  69.     // in the future, should normalize paths (i.e. remove duplicate slashes, resolve ...... type issues
  70.     return !(*this == other);
  71. }
  72. CHXString CHXPathParser::GetPathName() const
  73. {
  74.     return m_path;
  75. }
  76. BOOL CHXPathParser::IsSet() const
  77. {
  78.     return !m_bEmpty;
  79. }
  80. void CHXPathParser::UnSet()
  81. {
  82. m_path = "";
  83. m_bEmpty = TRUE;
  84. }
  85. void CHXPathParser::ParsePath(const char *psz)
  86. {
  87.     m_path = psz;
  88.     int i, nStart, nLength;
  89.     int nPathLength = m_path.GetLength();
  90.     m_bIsValid = TRUE; // possibly set to false later in this method
  91.     m_bCannotBeFile = FALSE;
  92.     m_bAbsolute = TRUE;
  93.     m_bEmpty = FALSE;
  94.     m_nVolumeLength = 0;
  95.     m_nParentLength = 0;
  96.     m_nSeparatorLength = 0;
  97.     m_nNameLength = 0;
  98.     m_nExtensionSeparatorLength = 0;
  99.     m_nExtensionLength = 0;
  100.     if(psz == NULL || m_path.IsEmpty())
  101.     {
  102. m_bIsValid = FALSE;
  103. m_bCannotBeFile = TRUE;
  104. m_bEmpty = TRUE;
  105. return;
  106.     }
  107.     // first, parse the local disk name, if present
  108.     if(nPathLength >= 2 && m_path[1] == ':')
  109.     {
  110. // local disk/volume
  111. m_nVolumeLength = 2;
  112. nStart = 2;
  113.     }
  114.     else
  115.     {
  116. m_nVolumeLength = 0;
  117. nStart = 0;
  118.     }
  119.     // now, break the rest of the path up into components based on slashes
  120.     // Here is an example of how the path will be broken up.  The carats point
  121.     // to the start of each component.  The separator length will be the
  122.     // number of slashes following the carat, and the name will be the remaining
  123.     // characters in that component.
  124.     //
  125.     // \hostnameblablablafile.txt
  126.     // ^         ^   ^   ^   ^ 
  127.     //
  128.     // In the case of a trailing slash:
  129.     //
  130.     // blabla
  131.     // ^   ^   ^
  132.     //
  133.     int anStart[MAX_PATH_COMPONENTS];
  134.     int anSeparatorLen[MAX_PATH_COMPONENTS];
  135.     int anNameLen[MAX_PATH_COMPONENTS];
  136.     int nNumComponents = 0;
  137.     while(nStart < nPathLength && nNumComponents < MAX_PATH_COMPONENTS)
  138.     {
  139. int nNumSep, nNameLen;
  140. // count the number of separators starting at position nStart
  141. for(nNumSep = 0; 
  142. nStart + nNumSep < nPathLength && 
  143. (m_path[nStart + nNumSep] == '\' || 
  144.  m_path[nStart + nNumSep] == '/');
  145. nNumSep++);
  146. // count the number of non-separators starting at position nStart + nNumSep
  147. for(nNameLen = 0; 
  148. nStart + nNumSep + nNameLen < nPathLength && 
  149. (m_path[nStart + nNumSep + nNameLen] != '\' &&
  150.  m_path[nStart + nNumSep + nNameLen] != '/');
  151. nNameLen++)
  152. if (HXIsLeadByte(m_path[nStart + nNumSep + nNameLen])) nNameLen++;
  153. anStart[nNumComponents] = nStart;
  154. anSeparatorLen[nNumComponents] = nNumSep;
  155. anNameLen[nNumComponents] = nNameLen;
  156. nNumComponents++;
  157. nStart += nNumSep + nNameLen;
  158.     }
  159.     // now we are ready to interpret the results
  160.     if(nNumComponents == 0)
  161.     {
  162. // no components at all.  If there was a volume, then this is a relative
  163. // path on the volume [and cannot be a file].  If there was no volume, then
  164. // this is invalid
  165. if(m_nVolumeLength > 0)
  166. {
  167.     m_bAbsolute = FALSE;
  168.     m_bCannotBeFile = TRUE;
  169. }
  170. else
  171.     m_bIsValid = FALSE;
  172.     }
  173.     else
  174.     {
  175. // we will now start using nStart as the component number of the start of the actual path [excluding volume]
  176. nStart = 0;
  177. // here, we look for a possible \hostname type of volume
  178. if(anSeparatorLen[0] > 1)
  179. {
  180.     if(m_nVolumeLength > 0)
  181.     {
  182. // this catches these invalid paths: C:\\temp, C:\hostnamebla
  183. // the problem with the second one is that it has both a local and network volume
  184. // the problem with the first one is it has too many slashes to be an absolute path
  185. m_bIsValid = FALSE;
  186. // however, we continue parsing the path, as if this was ok
  187. nStart = 0;
  188.     }
  189.     else if(anSeparatorLen[0] > 2)
  190.     {
  191. // this catches these invalid paths: \\hostnamebla
  192. m_bIsValid = FALSE;
  193. // however, we continue parsing the path, as if this was ok,
  194. // and if it was not a hostname
  195. nStart = 0;
  196.     }
  197.     else
  198.     {
  199. // this catches these *valid* paths: \hostnamebla
  200. m_nVolumeLength = anSeparatorLen[0] + anNameLen[0];
  201. nStart = 1;
  202.     }
  203. }
  204. // now that we have dealt with all possible volumes, nStart points to the first component in the
  205. // actual path.  There are still several possibilities:
  206. //
  207. // "" [i.e. no more components]
  208. // 
  209. // bla
  210. // bla.txt
  211. // blabla.txt
  212. // bla
  213. // bla.txt
  214. // blabla.txt
  215. // these cannot be files: "", "bla", "blabla"
  216. if(nNumComponents == nStart || anNameLen[nNumComponents - 1] == 0)
  217.     m_bCannotBeFile = TRUE;
  218. // these are not valid: "\\file.txt",
  219. if(nNumComponents > nStart && anSeparatorLen[nStart] > 1)
  220.     m_bIsValid = FALSE;
  221. // these are absolute: "blafile.txt"
  222. // there is one special case: the full path "\hostname" is absolute
  223. if((nNumComponents > nStart && anSeparatorLen[nStart] >= 1) || m_path[0] == '\' || m_path[0] == '/')
  224.     m_bAbsolute = TRUE;
  225. else
  226.     m_bAbsolute = FALSE;
  227. if(nNumComponents == nStart + 1 && anNameLen[nStart] == 0)
  228. {
  229.     // the path is simply: ""
  230.     m_nParentLength = anSeparatorLen[nStart];
  231.     nStart = nPathLength;
  232.     nLength = 0;
  233. }
  234. else if(nNumComponents > nStart)
  235. {
  236.     // remove the last component if it is just a slash
  237.     if(nNumComponents > nStart && anNameLen[nNumComponents-1] == 0)
  238. nNumComponents--;
  239.     if(nNumComponents == nStart + 1)
  240.     {
  241. // just one component
  242. m_nParentLength = anSeparatorLen[nStart];
  243. // back to using nStart as an index into the path.
  244. // note that we must set nLength first, since it
  245. // uses nStart as the index
  246. nLength = anNameLen[nStart];
  247. nStart = anStart[nStart] + anSeparatorLen[nStart];
  248.     }
  249.     else
  250.     {
  251. // more than one component
  252. m_nParentLength = anStart[nNumComponents - 1] - m_nVolumeLength;
  253. m_nSeparatorLength = anSeparatorLen[nNumComponents - 1];
  254. // back to using nStart as an index into the path
  255. nLength = anNameLen[nNumComponents - 1];
  256. nStart = anStart[nNumComponents - 1] + anSeparatorLen[nNumComponents - 1];
  257.     }
  258. }
  259. else
  260. {
  261.     // no more components
  262.     nStart = nPathLength;
  263.     nLength = 0;
  264. }
  265. // now, use nStart and nLength as the portion of the path to look at for the name
  266. // now we break it up into name, extension separator, and extension
  267. for(i = nStart + nLength - 1; i >= nStart; i--)
  268.     if(m_path[i] == '.')
  269. break;
  270. if(i < nStart)
  271.     m_nNameLength = nLength;
  272. else
  273. {
  274.     m_nNameLength = i - nStart;
  275.     m_nExtensionSeparatorLength = 1;
  276.     m_nExtensionLength = nStart + nLength - i - 1;
  277. }
  278.     }
  279. }
  280. CHXString CHXPathParser::GetSubstring(int nStart, int nLength) const
  281. {
  282.     if(nLength == -1)
  283. nLength = m_path.GetLength() - nStart;
  284.     return m_path.Mid(nStart, nLength);
  285. }
  286. CHXString CHXPathParser::GetPersistentString() const
  287. {
  288.     return m_path;
  289. }
  290. void CHXPathParser::SetFromPersistentString(const char *pBuffer)
  291. {
  292.     ParsePath(pBuffer);
  293. }
  294. //////////////////////////////////////////////////////////
  295. //
  296. // CHXFileSpecifier
  297. //
  298. //////////////////////////////////////////////////////////
  299. CHXFileSpecifier::CHXFileSpecifier()
  300. {
  301. }
  302. CHXFileSpecifier::CHXFileSpecifier(const char* psz)
  303. {
  304.     m_parser.ParsePath(psz);
  305. }
  306. CHXFileSpecifier::CHXFileSpecifier(const CHXString &str)
  307. {
  308.     m_parser.ParsePath(str);
  309. }
  310. CHXFileSpecifier::CHXFileSpecifier(const CHXFileSpecifier &other)
  311. {
  312.     *this = other;
  313. }
  314. CHXFileSpecifier::~CHXFileSpecifier()
  315. {
  316. }
  317. CHXFileSpecifier &CHXFileSpecifier::operator=(const CHXFileSpecifier &other)
  318. {
  319.     m_parser = other.m_parser;
  320.     return *this;
  321. }
  322. CHXFileSpecifier& CHXFileSpecifier::operator=(const char* sPath)
  323. {
  324. m_parser.ParsePath(sPath);
  325. return *this;
  326. }
  327. CHXFileSpecifier& CHXFileSpecifier::operator=(const CHXString& sPath)
  328. {
  329. m_parser.ParsePath(sPath);
  330. return *this;
  331. }
  332. BOOL CHXFileSpecifier::operator==(const CHXFileSpecifier &other)
  333. {
  334.     // for now, just returns if the paths are identical
  335.     // in the future, should normalize paths (i.e. remove duplicate slashes, resolve ...... type issues
  336.     return m_parser == other.m_parser;
  337. }
  338. BOOL CHXFileSpecifier::operator!=(const CHXFileSpecifier &other)
  339. {
  340.     // for now, just returns if the paths are not identical
  341.     // in the future, should normalize paths (i.e. remove duplicate slashes, resolve ...... type issues
  342.     return m_parser != other.m_parser;
  343. }
  344. CHXString CHXFileSpecifier::GetPathName() const
  345. {
  346.     return m_parser.GetPathName();
  347. }
  348. CHXString CHXFileSpecifier::GetURL() const
  349. {
  350.     const BOOL kReplaceAll = TRUE;
  351.     
  352.     CHXString strPath, strURL;
  353.     
  354.     strPath = m_parser.GetPathName();
  355.     if (strPath.GetLength() > 0)
  356.     {
  357.         strPath.FindAndReplace("\", "/", kReplaceAll); // replace path separators
  358.         strURL = "file://";
  359.     strURL += strPath;
  360.     }
  361.     
  362.     return strURL;
  363. }
  364. BOOL CHXFileSpecifier::IsSet() const
  365. {
  366.     return m_parser.IsSet();
  367. }
  368. CHXDirSpecifier CHXFileSpecifier::GetParentDirectory() const
  369. {
  370.     if(IsSet())
  371. return m_parser.GetSubstring(0, m_parser.m_nVolumeLength + m_parser.m_nParentLength);
  372.     else
  373. return CHXDirSpecifier();
  374. }
  375. CHXDirSpecifier CHXFileSpecifier::GetVolume() const
  376. {
  377.     if(IsSet())
  378. return m_parser.GetSubstring(0, m_parser.m_nVolumeLength);
  379.     else
  380. return CHXDirSpecifier();
  381. }
  382. CHXString CHXFileSpecifier::GetName() const
  383. {
  384.     if(IsSet())
  385. return m_parser.GetSubstring(m_parser.m_nVolumeLength + m_parser.m_nParentLength + m_parser.m_nSeparatorLength,
  386.     m_parser.m_nNameLength + m_parser.m_nExtensionSeparatorLength + m_parser.m_nExtensionLength);
  387.     else
  388. return "";
  389. }
  390. CHXString CHXFileSpecifier::GetTitle() const
  391. {
  392.     if(IsSet())
  393. return m_parser.GetSubstring(m_parser.m_nVolumeLength + m_parser.m_nParentLength + m_parser.m_nSeparatorLength,
  394.     m_parser.m_nNameLength);
  395.     else
  396. return "";
  397. }
  398. CHXString CHXFileSpecifier::GetExtension() const
  399. {
  400.     if(IsSet())
  401. return m_parser.GetSubstring(m_parser.m_nVolumeLength + m_parser.m_nParentLength + m_parser.m_nSeparatorLength +
  402.     m_parser.m_nNameLength + m_parser.m_nExtensionSeparatorLength,-1);
  403.     else
  404. return "";
  405. }
  406. CHXString CHXFileSpecifier::GetPersistentString() const
  407. {
  408.     return m_parser.GetPersistentString();
  409. }
  410. HX_RESULT CHXFileSpecifier::SetFromPersistentString(const char *pBuffer)
  411. {
  412.     m_parser.SetFromPersistentString(pBuffer);
  413. return HXR_OK;
  414. }
  415. void CHXFileSpecifier::Unset()
  416. {
  417. m_parser.UnSet();
  418. }
  419. HX_RESULT CHXFileSpecifier::SetFromURL(const char *pBuffer)
  420. {
  421. CHXString  strURL, strChoppedURL;
  422. int nChop;
  423. int nLength;
  424.     const BOOL kReplaceAll = TRUE;
  425. Unset();
  426. strURL = pBuffer;
  427. nLength = strURL.GetLength();
  428. nChop = 0;
  429. if (strURL.Left(9) == "file:////") nChop = 7;
  430. else if (strURL.Left(8) == "file:///") nChop = 8;
  431. else if (strURL.Left(7) == "file://") nChop = 7;
  432. else if (strURL.Left(5) == "file:") nChop = 5;
  433. else if (strURL.Left(10) == "tfile:////") nChop = 8;
  434. else if (strURL.Left(9) == "tfile:///") nChop = 9;
  435. else if (strURL.Left(8) == "tfile://") nChop = 8;
  436. else if (strURL.Left(6) == "tfile:") nChop = 6;
  437. if (nChop > 0)
  438. {
  439. strChoppedURL = strURL.Right(nLength - nChop);
  440. strChoppedURL.FindAndReplace("|", ":", kReplaceAll);
  441. strChoppedURL.FindAndReplace("/", "\", kReplaceAll);
  442.     m_parser.ParsePath(strChoppedURL);
  443. }
  444. return IsSet() ? HXR_OK : HXR_FAILED;
  445. }
  446. //////////////////////////////////////////////////////////
  447. //
  448. // CHXDirSpecifier
  449. //
  450. //////////////////////////////////////////////////////////
  451. CHXDirSpecifier::CHXDirSpecifier()
  452. {
  453. }
  454. CHXDirSpecifier::CHXDirSpecifier(const char* psz)
  455. {
  456.     m_parser.ParsePath(psz);
  457. }
  458. CHXDirSpecifier::CHXDirSpecifier(const CHXString &str)
  459. {
  460.     m_parser.ParsePath(str);
  461. }
  462. CHXDirSpecifier::CHXDirSpecifier(const CHXDirSpecifier &other)
  463. {
  464.     *this = other;
  465. }
  466. CHXDirSpecifier::~CHXDirSpecifier()
  467. {
  468. }
  469. CHXDirSpecifier &CHXDirSpecifier::operator=(const CHXDirSpecifier &other)
  470. {
  471.     m_parser = other.m_parser;
  472.     return *this;
  473. }
  474. CHXDirSpecifier& CHXDirSpecifier::operator=(const char* sPath)
  475. {
  476. m_parser.ParsePath(sPath);
  477. return *this;
  478. }
  479. CHXDirSpecifier& CHXDirSpecifier::operator=(const CHXString& sPath)
  480. {
  481. m_parser.ParsePath(sPath);
  482. return *this;
  483. }
  484. BOOL CHXDirSpecifier::operator==(const CHXDirSpecifier &other)
  485. {
  486.     // for now, just returns if the paths are identical
  487.     // in the future, should normalize paths (i.e. remove duplicate slashes, resolve ...... type issues
  488.     return m_parser == other.m_parser;
  489. }
  490. BOOL CHXDirSpecifier::operator!=(const CHXDirSpecifier &other)
  491. {
  492.     // for now, just returns if the paths are not identical
  493.     // in the future, should normalize paths (i.e. remove duplicate slashes, resolve ...... type issues
  494.     return m_parser != other.m_parser;
  495. }
  496. CHXString CHXDirSpecifier::GetPathName() const
  497. {
  498.     return m_parser.GetPathName();
  499. }
  500. BOOL CHXDirSpecifier::IsSet() const
  501. {
  502.     return m_parser.IsSet();
  503. }
  504. BOOL CHXDirSpecifier::IsVolume() const
  505. {
  506.     return (IsSet() ? (m_parser.m_path.GetLength() == (UINT32)m_parser.m_nVolumeLength) : FALSE);
  507. }
  508. CHXString CHXDirSpecifier::GetName() const
  509. {
  510.     if(IsSet())
  511. return m_parser.GetSubstring(m_parser.m_nVolumeLength + m_parser.m_nParentLength + m_parser.m_nSeparatorLength,
  512.     m_parser.m_nNameLength + m_parser.m_nExtensionSeparatorLength + m_parser.m_nExtensionLength);
  513.     else
  514. return "";
  515. }
  516. CHXDirSpecifier CHXDirSpecifier::GetParentDirectory() const
  517. {
  518.     if(IsSet())
  519. return m_parser.GetSubstring(0, m_parser.m_nVolumeLength + m_parser.m_nParentLength);
  520.     else
  521. return CHXDirSpecifier();
  522. }
  523. CHXDirSpecifier CHXDirSpecifier::GetVolume() const
  524. {
  525.     if(IsSet())
  526. return m_parser.GetSubstring(0, m_parser.m_nVolumeLength);
  527.     else
  528. return CHXDirSpecifier();
  529. }
  530. CHXFileSpecifier CHXDirSpecifier::SpecifyChildFile(const char *child) const
  531. {
  532.     if(IsSet())
  533.     {
  534. int nlast_ch = m_parser.m_path.GetLength() - 1;
  535. if(m_parser.m_path.ReverseFind('\') == nlast_ch || m_parser.m_path.ReverseFind('/') == nlast_ch)
  536.     return m_parser.m_path + child;
  537. else
  538.     return m_parser.m_path + '\' + child;
  539.     }
  540.     else
  541. return child;
  542. }
  543. CHXDirSpecifier CHXDirSpecifier::SpecifyChildDirectory(const char *child) const
  544. {
  545.     if(IsSet())
  546.     {
  547. int nlast_ch = m_parser.m_path.GetLength() - 1;
  548. if(m_parser.m_path.ReverseFind('\') == nlast_ch || m_parser.m_path.ReverseFind('/') == nlast_ch)
  549.     return m_parser.m_path + child;
  550. else
  551.     return m_parser.m_path + '\' + child;
  552.     }
  553.     else
  554. return child;
  555. }
  556. CHXString CHXDirSpecifier::GetPersistentString() const
  557. {
  558.     return m_parser.GetPersistentString();
  559. }
  560. HX_RESULT CHXDirSpecifier::SetFromPersistentString(const char *pBuffer)
  561. {
  562.     m_parser.SetFromPersistentString(pBuffer);
  563. return HXR_OK;
  564. }
  565. #if 0
  566. Utility class:
  567. might be things like
  568. IsLocal() is this on a server or a local volume
  569. Rename()
  570. GetFilesInDirectory()  (gets a list into a buffer; much better than an iterator)
  571. GetFileType()
  572. GetFileModificationDate()
  573. GetFileSize()
  574. #endif // 0