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

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