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

Symbian

开发平台:

Visual C++

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