pathname.cpp

Go to the documentation of this file.
00001 // $Id: pathname.cpp 1282 2006-06-09 09:46:49Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 
00099                     
00100 #include "camtypes.h"
00101 //#include "pathname.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00102 
00103 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00104 //#include "mario.h"
00105 //#include "hotlink.h"
00106 //#include "unicdman.h"
00107 
00108 //#include "resimmap.h" 
00109 
00110 #define MAXDRIVE 3
00111 #define MAXNAME 8
00112 #define MAXNETNAME 256
00113 #define MAXEXT 16
00114 
00115 #if defined(__WXMSW__)
00116     #define SEPARATOR       _T('\\')
00117 #elif defined(__WXGTK__)
00118     #define SEPARATOR       _T('/')
00119 #elif defined(__WXMAC__)
00120     #define SEPARATOR       _T('/')
00121 #else
00122     #error "You will need to setup the path separator for your platform"
00123 #endif
00124 
00125 #define FULLSTOP        '.'
00126 #define COLON           ':'
00127 #define END_OF_PATH     '\0'
00128 #define END_OF_STRING   '\0'
00129 
00130 #define SEPARATOR_SYM   "\\"
00131 #define FULLSTOP_SYM    "."
00132 #define COLON_SYM       ":"
00133 #define END_OF_PATH_SYM "\0"
00134 #define NET_DRIVE_SYM   "\\\\"
00135 
00136 DECLARE_SOURCE("$Revision: 1282 $");
00137 
00138 extern void AbbreviateName(LPTSTR lpszCanon, INT32 cchMax, BOOL bAtLeastName);
00139 
00140 
00141 // Forward Declarations
00142 
00143 BOOL getDrive(const TCHAR**, TCHAR* drive);
00144 BOOL getNetDrive(const TCHAR**, TCHAR* drive, BOOL *BadCharacter);
00145 BOOL getIdentifier(const TCHAR**, TCHAR* identifier, UINT32 MaxSize, BOOL *BadCharacter);
00146 BOOL getExtension(const TCHAR**, TCHAR* extension, UINT32 MaxSize, const TCHAR* );
00147 BOOL getParentDirectory(const TCHAR **fn, TCHAR *directory, UINT32 MaxSize, const TCHAR * StartOfPath);
00148 BOOL IsReservedChar(const TCHAR **fn);
00149 BOOL IsDeviceName(const String_256& path);
00150 
00151 
00152 /**********************************************************************************************
00153 
00154 >   PathName::PathName()
00155 
00156     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00157     Created:    12/5/93
00158     Inputs:     None
00159     Outputs:    None
00160     Returns:    None
00161     Purpose:    Default PathName class constructor
00162     Errors:     None
00163 
00164 **********************************************************************************************/
00165 
00166 PathName::PathName()
00167   : PathNameValid(FALSE)
00168 {
00169     // Empty.
00170 }
00171 
00172 /**********************************************************************************************
00173 
00174 >   PathName::PathName(const PathName& newPath)
00175 
00176     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00177     Created:    12/5/93
00178     Inputs:     newPath
00179     Outputs:    None
00180     Returns:    None
00181     Purpose:    Copy Constructor for the PathName class
00182     Errors:     None
00183 
00184 **********************************************************************************************/
00185 
00186 PathName::PathName(const PathName& other)
00187   : PathNameValid(other.PathNameValid),
00188     location(other.location),
00189     filename(other.filename),
00190     filetype(other.filetype),
00191     drivename(other.drivename)
00192 {
00193     // Empty.
00194 }
00195 
00196 /**********************************************************************************************
00197 
00198 >   PathName::PathName(const String_256&)
00199 
00200     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00201     Created:    12/5/93
00202     Inputs:     String representing the path.
00203     Outputs:    None
00204     Returns:    None
00205     Purpose:    Is to parse the path string passed in as a parameter.
00206                 Also, it sets up the internal variables for location, filename and filetype.
00207     Errors:     If a problem is found it will call set error with _R(IDE_PATH_ERROR) but will
00208                 not call InformError as this is a contructor!
00209 
00210 **********************************************************************************************/
00211 
00212 PathName::PathName(const String_256& path)
00213 {
00214     // Set up the protected variables at our disposal
00215     PathNameValid = FALSE;
00216 
00217     // Check if supplied path is valid or not, if so then set up our internal variables
00218     // Use the internal form of the checking code which returns the values back to us,
00219     // blanked if a problem has happened.
00220     BOOL ok;
00221     String_256 tempFilename;            //temporary string to hold the filename
00222     String_256 tempLocation;            //temporary string to hold the location
00223     String_256 tempFiletype;            //temporary string to hold the filetype
00224     String_256 tempDrivename;           //temporary string to hold the drive name
00225 
00226     // Use the internal form of the routine which returns us information which
00227     // we do not want and so just throw away  
00228     ok = IsValidAndReturnInfo(path, tempFilename, tempLocation, tempFiletype, tempDrivename);
00229 
00230     // We could return the result to the user but we are a constructor and so cannot.
00231     // but we will set up our variables to be the returned variables 
00232     filename = tempFilename;
00233     location = tempLocation;
00234     filetype = tempFiletype;
00235     drivename = tempDrivename;
00236     PathNameValid = ok;
00237 }
00238 
00239 /**********************************************************************************************
00240 
00241 >   const String_256 PathName::GetPath(BOOL TrailingSlash=FALSE) const
00242 
00243     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>   (modified for new Strings by JCF 13/8/93)
00244                                 (modified by Neville 25/8/94 to cope with null file types)
00245                                 (modified by Richard 15/2/96 for TrailingSlash biz)
00246     Created:    12/5/93
00247     Inputs:     TrailingSlash   - If TRUE, returned string will have a trailing '\' assigned to it...
00248     Outputs:    None
00249     Returns:    A Path = Location + filename + filetype
00250     Purpose:    To reconstruct path name and return it.
00251     Errors:     None
00252 
00253 **********************************************************************************************/
00254 
00255 const String_256 PathName::GetPath(BOOL TrailingSlash) const
00256 {            
00257     String_256 path;
00258     path.Empty();          
00259     
00260     // Concatenation of Location, FileName and FileType
00261     path += location;   
00262     path += filename;
00263 
00264     // Changed by Neville 25/8/94 so that if no filetype is present then a full stop
00265     // is not added to the filename.
00266     if ( !filetype.IsEmpty() )
00267     {
00268         path += String( wxT(FULLSTOP_SYM) );
00269         path += filetype;
00270     }
00271 
00272     // Though it might not make much sense for filenames, it's invaluable for directory paths in the
00273     // library gallery system...
00274     if(TrailingSlash)
00275     {
00276         // Add a trailing slash if it hasn't got one (usually, roots have 'em, but sub-dirs don't)
00277         INT32 ByteLength = path.Length();
00278 PORTNOTE("other","Removed UnicodeManager usage")
00279         if( path[ByteLength-1]!=SEPARATOR )
00280 #ifndef EXCLUDE_FROM_XARALX
00281              //|| ((path[ByteLength-1]==SEPARATOR) && UnicodeManager::IsDBCSLeadByte(path[ByteLength-2])))
00282 #endif
00283             path += SEPARATOR;
00284     }
00285     
00286     return path;
00287 }
00288 
00289 /**********************************************************************************************
00290 
00291 >   const String_256 PathName::GetWebAddress() const
00292 
00293     Author:     Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com>
00294     Created:    21/4/97
00295     Inputs:     -
00296     Outputs:    -
00297     Returns:    The path name as a URL
00298     Purpose:    This function returns the path name in URL form.
00299 
00300                 The resulting URL will be recognised by browsers
00301                 as pointing to a local file.
00302 
00303                 The way we do this is:
00304                 a. Convert all backslashes to forward slashes
00305                 b. Add "file:///" to the start to the string
00306 
00307                 Remarkably, this works both with UNC pathnames and ordinary ones. So:
00308 
00309                 \\earth\progtemp\imagemaps/test.htm
00310                 becomes
00311                 file://///earth/progtemp/imagemaps/test.htm
00312 
00313                 d:\imagemaps\test.htm
00314                 becomes
00315                 file:///d:/imagemaps/test.htm
00316 
00317                 bugfix #10747 (Marc 20/9/04) -  some browsers (notably Opera) choked on the | character 
00318                 when used to replace the colon in a path, so this behaviour was removed. Also, the host
00319                 was not correctly specified, so it is now specified as the local machine with "file:///".
00320 
00321                 Notes: it was not possible to rewrite a UNC as "file://<host>/<path>" because this fails in 
00322                 Mozilla & Netscape. So we are left with the "file://///<host>/<path>" solution which 
00323                 unfortunately does not work in Opera but at least works in IE,Netscape & Mozilla!
00324 
00325     Errors:     None
00326 
00327 **********************************************************************************************/
00328 
00329 String_256 PathName::GetWebAddress() const
00330 {            
00331     //First let's get this path as a string
00332     String_256 strPath=GetPath(FALSE);
00333 
00334     //Convert all the backslashes to forward slashes
00335     strPath.SwapChar('\\', '/');
00336 
00337     //Add "file:///" to the start of the sting
00338     String_256 strToReturn( wxT("file:///") );
00339 
00340     strToReturn+=strPath;
00341 
00342     //And return
00343     return strToReturn;
00344 
00345 }
00346 
00347 
00348 /**********************************************************************************************
00349 
00350 >   const String_256 PathName::GetTruncatedPath(UINT32 MaxSize = 0) const
00351 
00352     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00353     Created:    21/3/95
00354     Inputs:     MaxSize determines the maximum length of the string required.
00355                 Defaults to 0 = return full path
00356     Outputs:    None
00357     Returns:    A Path = Location + filename + filetype which may be truncated to the specified
00358                 size or less so that it can be displayed in the space required.  
00359     Purpose:    Display fields which require a pathname to be shown in a fixed sized space will
00360                 need the path name truncated if it is too long to fit into the space. This
00361                 routine should do this in the standard Microsoft way.
00362                 We use an OS/MFC routine, AbbreviateName, to do the work for for us.
00363     Errors:     None
00364 
00365 **********************************************************************************************/
00366 
00367 const String_256 PathName::GetTruncatedPath(UINT32 MaxSize) const
00368 {            
00369     // Use the normal routine to get the pathname
00370     String_256 path;
00371     path = GetPath();
00372 
00373     // Shorten the filename down a bit.
00374     String_256 ShortPath;
00375     ShortPath.Empty();
00376     TruncateName(path, &ShortPath, (INT32)MaxSize);
00377     return ShortPath;
00378 }
00379 
00380 
00381 
00382 
00383 /********************************************************************************************
00384 
00385 >   void PathName::TruncateName(String_256& FullName, String_256* pShortName, UINT32 MaxSize)
00386 
00387     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00388     Created:    9/5/95
00389     Inputs:     FullName - The Full Path name of the file we need to shrink
00390                 MaxSize - The maximum number of characters that the path name is allowed to
00391                 take up. A value of zero means infinite (ie, the whole path will be returned)
00392     Outputs:    pShortName - the shortened version of the file name
00393     Purpose:    This function shortens a file name, replacing the middle sections of the
00394                 name with ... if needed. eg if the input path is
00395                 m:\materials\graphics\artwork\myfile.art
00396                 Resulting Filename                            MaxSize
00397                 myfile.art                                      0-16
00398                 c:\...\myfile.art                              17-24
00399                 c:\...\artwork\myfile.art                      25-33
00400                 c:\...\graphics\artwork\myfile.art             34-etc
00401                 if the filename is longer than MaxSize then the filename will still be
00402                 returned. In other words, it is possible for a string longer than MaxSize
00403                 to be returned, so if this is important, check the length after you get
00404                 your string back.
00405 
00406                 NOTE: Made DBCS compatiable by Peter 9/8/96
00407 
00408 ********************************************************************************************/
00409 
00410 void PathName::TruncateName(String_256& FullName, String_256* pShortName, INT32 MaxSize) const
00411 {
00412     // If maxsize is zero, then give back the whole path name
00413     if (MaxSize==0)
00414     {
00415         *pShortName = FullName;
00416         return;
00417     }
00418 
00419     // Find out how long the full path is
00420     INT32 FullLength = FullName.Length();
00421 
00422     // if we can fit it into MaxSize, then return it
00423     if (FullLength<=MaxSize)
00424     {
00425         *pShortName = FullName;
00426         return;
00427     }
00428 
00429     // OK, we will need to compress it, so look for the actual filename part of the path
00430     // the filename goes from the end of the string to the last \ in the string
00431     const TCHAR* pFullName = (const TCHAR*)FullName;
00432     const TCHAR* pLastSlash = camStrrchr(pFullName, SEPARATOR);
00433 
00434     // if we fell off the end of the string, we only had a filename, so return it
00435     if (pLastSlash == NULL)
00436     {
00437         *pShortName = FullName;
00438         return;
00439     }
00440 
00441     // Find out the length of the filename
00442     INT32 FileNameLen = FullLength - (pLastSlash - pFullName);
00443     INT32 FileNameStart = pLastSlash - pFullName;
00444 
00445     // Now, starting from the front of the string, we have to try and add
00446     // in more and more of the path, until it will fit no more.
00447     // We will skip the first 2 chars as they will be either c: or \\.
00448     const TCHAR* pCurrent = pFullName;
00449     pCurrent = camStrinc(pCurrent);
00450     pCurrent = camStrinc(pCurrent);     // Now pointing at the third character
00451 
00452     // see if this is a UNC filename
00453     if (*pCurrent != SEPARATOR)
00454     {
00455         // yes, it's UNC, so walk though the server name
00456         do
00457         {
00458             pCurrent = camStrinc(pCurrent);
00459         } while (*pCurrent != SEPARATOR);
00460     }
00461 
00462     // Up to here is the volume name really
00463     INT32 VolumeNameLen = pCurrent-pFullName;
00464 
00465     // and we need at least the first directory
00466     do
00467     {
00468         pCurrent = camStrinc(pCurrent);
00469     } while (*pCurrent != SEPARATOR);
00470 
00471     // See if what we have will fit
00472     INT32 CurrentLength = pCurrent - pFullName;
00473     if ((CurrentLength+FileNameLen+4)>MaxSize)
00474     {
00475         // maybe we could have just volume name\...\filename
00476         if ((VolumeNameLen+4+FileNameLen)>MaxSize)
00477         {
00478             // Nope, it won't fit, so just return the filename
00479             *pShortName = String_256(pFullName+FileNameStart+1);
00480             return;
00481         }
00482         else
00483         {
00484             // Yep, we can fit it in...
00485             // Build the resulting short path
00486             FullName.Left(pShortName, VolumeNameLen);
00487             *pShortName+=TEXT(SEPARATOR_SYM) TEXT("...");
00488             *pShortName+=pFullName+FileNameStart;
00489             return;
00490         }
00491     }
00492 
00493     // Since we can fit the first directory, keep it as part of the volume name
00494     VolumeNameLen = pCurrent-pFullName;
00495 
00496     // put i back to the start of the filename and start working backwards
00497     pCurrent = pFullName + FileNameStart;
00498     INT32 DirectoryStart = FileNameStart;
00499     while ((VolumeNameLen+4+(FullLength-(pCurrent-pFullName))) < MaxSize)
00500     {
00501         DirectoryStart = pCurrent-pFullName;
00502         do
00503         {
00504             pCurrent = camStrdec(pFullName, pCurrent);
00505         } while ((*pCurrent!=SEPARATOR) && ((pCurrent-pFullName)>VolumeNameLen));
00506     }
00507 
00508     // We got all the way back to the start of the volume name
00509     if (DirectoryStart==VolumeNameLen)
00510     {
00511         *pShortName = FullName;
00512         return;
00513     }
00514 
00515     // Build the resulting short path
00516     FullName.Left(pShortName, VolumeNameLen);
00517     *pShortName+=TEXT(SEPARATOR_SYM) TEXT("...");
00518     *pShortName+=pFullName+DirectoryStart;
00519 }
00520 
00521 
00522 
00523 /**********************************************************************************************
00524 
00525 >   const String_256 PathName::GetTruncatedLocation(UINT32 MaxSize = 0) const
00526 
00527     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00528     Created:    21/3/95
00529     Inputs:     MaxSize determines the maximum length of the string required.
00530                 Defaults to 0 = return full path
00531     Outputs:    None
00532     Returns:    A Path = Location, which may be truncated to the specified size or less so that
00533                 it can be displayed in the space required.  
00534     Purpose:    Display fields which require a location to be shown in a fixed sized space will
00535                 need the location truncated if it is too long to fit into the space. This
00536                 routine should do this in the standard Microsoft way.
00537                 We use an OS/MFC routine, AbbreviateName, to do the work for for us.
00538     Errors:     None
00539 
00540 **********************************************************************************************/
00541 
00542 const String_256 PathName::GetTruncatedLocation(UINT32 MaxSize) const
00543 {            
00544     // Use the normal routine to get the pathname
00545     static String_256 path;
00546     path = GetLocation(FALSE);
00547 
00548     // Shorten the filename down a bit.
00549     String_256 ShortPath;
00550     TruncateName(path, &ShortPath, (INT32)MaxSize);
00551     return ShortPath;
00552 }
00553 
00554 /**********************************************************************************************
00555 
00556 >   const String_256 PathName::GetLocation(BOOL KeepSep = TRUE) const
00557 
00558     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00559     Created:    14/3/94
00560     Inputs:     KeepSep - if TRUE, it leaves the terminating backslash on the end of
00561                 the location name; if FALSE, it removes it.  Defaults to TRUE.
00562     Returns:    The location.
00563     Purpose:    To obtain the location from a pathname.
00564 
00565 **********************************************************************************************/
00566 
00567 const String_256 PathName::GetLocation(BOOL KeepSep) const
00568 {            
00569     String_256 path;
00570 
00571     path = location;
00572     if (!KeepSep)
00573     {
00574         // Get the last character and remove it if it is a backslash.
00575         INT32 Length = path.Length() - 1;
00576         TCHAR *pLocation = (TCHAR *) path;
00577 PORTNOTE("other","Removed UnicodeManager usage")
00578         if( pLocation[Length] == SEPARATOR )
00579 #ifndef EXCLUDE_FROM_XARALX
00580     //&& !UnicodeManager::IsDBCSLeadByte(pLocation[Length-1]))
00581 #endif
00582             pLocation[Length] = 0;
00583     }
00584 
00585     return path;
00586 }
00587 
00588 
00589 /**********************************************************************************************
00590 
00591 >   const String_256 PathName::GetFileName(BOOL FullName=TRUE) const
00592 
00593     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com> (modified by Neville 25/8/94 to cope with null file types)
00594     Created:    12/5/93
00595     Inputs:     FullName TRUE means that we are interested in the name plus extension
00596                          FALSE means that we are showing the user and so the extension is not
00597                          important, especially on Windows 95 (Chicago). 
00598     Outputs:    None
00599     Returns:    FileName and FileType
00600     Purpose:    To Construct the FileName out of the FileName and FileType
00601     Errors:     None
00602 
00603 **********************************************************************************************/
00604 
00605 const String_256 PathName::GetFileName(BOOL FullName) const
00606 {            
00607     String_256 fname;
00608     fname.Empty();
00609     
00610     //Concatenation of FileName and FileType
00611     fname += filename;
00612 
00613     // Changed by Neville 25/8/94 so that if no filetype is present then a full stop
00614     // is not added to the filename.
00615     // FullName parameter added 21/3/95 so that can just specify the filename itself,
00616     // without the extension.
00617     // Use IsWin32c() to test for Windows 95/Chicago 
00618     if ( !filetype.IsEmpty() && FullName)
00619     {
00620         fname += String( wxT(FULLSTOP_SYM) );
00621         fname += filetype;
00622     }
00623 
00624     return fname;
00625 }
00626 
00627 /**********************************************************************************************
00628 
00629 >   const String_256 PathName::GetType() const
00630 
00631     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00632     Created:    12/5/93
00633     Inputs:     None
00634     Outputs:    None
00635     Returns:    FileType
00636     Purpose:    Extracts the file type.
00637     Errors:     None
00638 
00639 **********************************************************************************************/
00640 
00641 const String_256 PathName::GetType() const
00642 {
00643     return filetype;
00644 }
00645 
00646 
00647 
00648 /********************************************************************************************
00649 
00650 >   BOOL PathName::SetType(const String_256& NewType)
00651 
00652     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00653     Created:    14/2/95
00654     Inputs:     NewType - The new extension for the path name
00655     Returns:    TRUE if it changed the extension OK
00656     Purpose:    Changes the Pathnames type (extension). 
00657 
00658 ********************************************************************************************/
00659 
00660 BOOL PathName::SetType(const String_256& NewType)
00661 {
00662     // set the filetype to the new one
00663     filetype = NewType;
00664 
00665     // all worked
00666     return TRUE;
00667 }
00668 
00669 
00670 /********************************************************************************************
00671 
00672 >   BOOL PathName::SetFileName(const String_256& NewFileName)
00673 
00674     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
00675     Created:    25/06/96
00676     Inputs:     NewFileName - The new filename for the path name
00677     Returns:    TRUE if NewFileName is a valid file name consisting solely of the name
00678                 of a file with no path delimiters, drive specification, etc.
00679                 FALSE otherwise
00680     Purpose:    Allow alteration of the filename component of the path
00681 
00682 ********************************************************************************************/
00683 
00684 BOOL PathName::SetFileName(const String_256& NewFileName)
00685 {
00686     const TCHAR* fn = NewFileName;
00687     String_256 newfilename;
00688     BOOL BadCharacter = FALSE;
00689     BOOL ok = FALSE;
00690     ok = getIdentifier(&fn, newfilename, NewFileName.Length(), &BadCharacter);
00691     if (!ok || BadCharacter || newfilename.Length() != NewFileName.Length())
00692     {
00693         // don't allow any bad characters & ensure given NewFileName is the whole thing
00694         return FALSE;
00695     }
00696 
00697     String_32 temp;
00698     ok = getExtension(&fn, temp, MAXEXT, fn);
00699     if (ok)
00700     {
00701         // an extnesion was found - don't allow it
00702         return FALSE;
00703     }
00704 
00705     // set the filename to the new one
00706     filename = newfilename;
00707 
00708     return TRUE;
00709 }
00710 
00711 /**********************************************************************************************
00712 
00713 >   BOOL PathName::SetFileNameAndType(const String_256& NewFileName)
00714 
00715     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00716     Created:    10/12/96
00717     Inputs:     NewFileName - String representing a filename and type
00718     Outputs:    None
00719     Returns:    TRUE if the filename is parsed successfully or FALSE otherwise
00720     Purpose:    Parses a string representing a filename type and sets up the class
00721                 variables filetype and filename if the path is valid
00722                 otherwise it leaves them sets them to null strings.
00723                 Always sets the filename and filetype regardless of whether there is a file
00724                 type present or not. SetFileName will not set the name if there is a type present.
00725     SeeAlso:    SetFileName();
00726     Errors:     None
00727 
00728 **********************************************************************************************/
00729 
00730 BOOL PathName::SetFileNameAndType(const String_256& NewFileName)
00731 {
00732     // Check if supplied path is valid or not, if so then set up our internal variables
00733     // Use the internal form of the checking code which returns the values back to us,
00734     // blanked and with an error flag set if a problem has happened.
00735     BOOL ok;
00736     String_256 tempFilename;            //temporary string to hold the filename
00737     String_256 tempLocation;            //temporary string to hold the location
00738     String_256 tempFiletype;            //temporary string to hold the filetype
00739     String_256 tempDrivename;           //temporary string to hold the drive name
00740 
00741     // Use the internal form of the routine which returns us information which
00742     // we do not want and so just throw away  
00743     ok = IsValidAndReturnInfo(NewFileName, tempFilename, tempLocation, tempFiletype, tempDrivename);
00744 
00745     // Set up our class variables to be the returned variables 
00746     // Only set the ones that we are interested in though.
00747     filename = tempFilename;
00748     filetype = tempFiletype;
00749 
00750     // Set up our class variable which holds this validation information
00751     PathNameValid = ok;
00752 
00753     // return the result of the parsing of the pathname to the caller.  
00754     return ok;
00755 }
00756  
00757 /**********************************************************************************************
00758 
00759 >   BOOL PathName::SetPathName(const String_256&, BOOL SetErrors)
00760 
00761     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00762     Created:    12/5/93
00763     Inputs:     String representing a pathname and SetErrors - enables us to ignore errors.
00764                 This should ONLY be false when we call this routine with an empty path
00765                 (thereby ensuring that any subsequent calls to this routine (that fail) will
00766                 result in an empty (but valid!) path).  For an example of this, look at
00767                 SGLibDisplayItem::GetFileName(PathName *Result).
00768     Outputs:    None
00769     Returns:    TRUE if the pathname is parsed successfully or FALSE otherwise
00770     Purpose:    Parses a string representing a path and sets up the class
00771                 variables filetype, filename and location if the path is valid
00772                 otherwise it sets them to null strings. 
00773     Errors:     None
00774 
00775 **********************************************************************************************/
00776 
00777 BOOL PathName::SetPathName(const String_256& path, BOOL SetErrors)
00778 {
00779     // Check if supplied path is valid or not, if so then set up our internal variables
00780     // Use the internal form of the checking code which returns the values back to us,
00781     // blanked and with an error flag set if a problem has happened.
00782     BOOL ok;
00783     String_256 tempFilename;            //temporary string to hold the filename
00784     String_256 tempLocation;            //temporary string to hold the location
00785     String_256 tempFiletype;            //temporary string to hold the filetype
00786     String_256 tempDrivename;           //temporary string to hold the drive name
00787 
00788     // Use the internal form of the routine which returns us information which
00789     // we do not want and so just throw away  
00790     ok = IsValidAndReturnInfo(path, tempFilename, tempLocation, tempFiletype, tempDrivename,
00791                               SetErrors);
00792 
00793     // Set up our class variables to be the returned variables 
00794     filename = tempFilename;
00795     location = tempLocation;
00796     filetype = tempFiletype;
00797     drivename = tempDrivename;
00798 
00799     // Set up our class variable which holds this validation information
00800     PathNameValid = ok;
00801 
00802     // return the result of the parsing of the pathname to the caller.  
00803     return ok;
00804 }
00805 
00806 /**********************************************************************************************
00807 
00808 >   BOOL PathName::IsValid(const String_256&) const
00809 
00810     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00811     Created:    12/5/93
00812     Inputs:     String representing a pathname
00813     Outputs:    None
00814     Returns:    TRUE if the pathname is parsed successfully or FALSE otherwise
00815     Purpose:    Parses a string representing a path and sets up the class
00816                 variables filetype, filename and location if the path is valid.
00817                 Cannot do the usual 8.3 checking of things like filenames as this is no longer
00818                 valid given Chicargo and NT non-FAT filing systems. 
00819     Errors:     If it fails then it will call set error with the error found.
00820 
00821 **********************************************************************************************/
00822 /*
00823 Technical notes:
00824 We used to do explicit checking of 8.3 filenames, correct letters being used in all filenames
00825 and directory names but unfortunately we did not cope with things like long directory names,
00826 spaces in filenames and directory names, relative paths. Unfortunately, there is no nice
00827 operating system routine to do this checking for us so all we can do is some basic checking of
00828 validity like a null path being specified, bad names such as d:\ and \\blobby. A lot of the
00829 time the data being passed to us has been validated by the Common Dialogs for open and save.  
00830 
00831 **********************************************************************************************/
00832 
00833 BOOL PathName::IsValid(const String_256& path) const
00834 {
00835     BOOL ok;
00836     String_256 tempFilename;            //temporary string to hold the filename
00837     String_256 tempLocation;            //temporary string to hold the location
00838     String_256 tempFiletype;            //temporary string to hold the filetype
00839     String_256 tempDrivename;           //temporary string to hold the drive name
00840 
00841     // Use the internal form of the routine which returns us information which
00842     // we do not want and so just throw away  
00843     ok = IsValidAndReturnInfo(path, tempFilename, tempLocation, tempFiletype, tempDrivename);
00844 
00845     // Set up our class variable which holds this validation information
00846     //PathNameValid = ok; // don't be so stupid
00847 
00848     // return result to the user
00849     return ok;
00850 }
00851 
00852 /**********************************************************************************************
00853 
00854 >   BOOL PathName::IsValid() const
00855 
00856     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00857     Created:    7/3/95
00858     Inputs:     None
00859     Outputs:    None
00860     Returns:    TRUE if the present pathname has been parsed successfully or FALSE otherwise
00861     Purpose:    Says whether the pathname currently in the class has been parsed correctly.
00862                 This should only be used if the non-blank contructors have been called and more
00863                 specifically the contructor which takes a pathname as a parameter has been used.
00864                 This function then returns the result of the validation that happens in the 
00865                 constructor as of course constructors cannot return results!
00866     SeeAlso:    PathName::IsValid(const String_256& path);  
00867     Errors:     If it fails then it will call set error with the error found.
00868 
00869 **********************************************************************************************/
00870 
00871 BOOL PathName::IsValid() const
00872 {
00873     // Just return the result that we have found earlier to the caller
00874     // If the wrong constructor has been called then should be automatically FALSE.
00875     return PathNameValid;
00876 }
00877 
00878 
00879 
00880 
00881 /**********************************************************************************************
00882 
00883 >   virtual BOOL PathName::IsValidAndReturnInfo(const String_256& ConstPath, String_256& tempFilename,
00884         String_256& tempLocation, String_256& tempFiletype, String_256& tempDrivename, BOOL SetErrors = TRUE) const
00885 
00886     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> (with updated function protocol comments by Richard !)
00887     Created:    12/5/93
00888 
00889     Inputs:     ConstPath       - String representing the pathname to check
00890                 SetErrors       - Flag to say whether we should set errors or not (defaults to TRUE)
00891 
00892     Outputs:    tempFilename    - String representing the filename
00893                 tempLocation    - String representing the location
00894                 tempFiletype    - String representing the filetype
00895                 tempDrivename   - String representing the drive name
00896     
00897     Returns:    TRUE if the pathname is parsed successfully or FALSE otherwise
00898     Purpose:    Parses a string representing a path and returns the filetype, filename
00899                 and location to the caller if the path is valid.
00900                 Cannot do the usual 8.3 checking of things like filenames as this is no longer
00901                 valid given Chicago and NT non-FAT filing systems.
00902                 Routine called by IsValid to actually go and do the work involved with
00903                 checking the pathname. Done this way so that internal calls do not have to
00904                 parse the data again to get at the variables.  
00905     Errors:     If it fails then it will call set error with the error found.
00906                 This can now be supressed if required. 
00907 
00908 **********************************************************************************************/
00909 
00910 BOOL PathName::IsValidAndReturnInfo(const String_256& ConstPath,
00911                                     String_256& tempFilename,
00912                                     String_256& tempLocation,
00913                                     String_256& tempFiletype,
00914                                     String_256& tempDrivename,
00915                                     BOOL SetErrors) const
00916 {
00917     // First ensure the strings passed in are blanked 
00918     tempFilename.Empty();
00919     tempLocation.Empty();
00920     tempFiletype.Empty();
00921     tempDrivename.Empty();
00922     
00923     // Get a non const version, as this function tends to party a bit too much
00924     String_256 path = ConstPath;
00925 
00926     // Then check for an empty path being passed to us
00927     // and also that a device name is not being specified 
00928     if ( !path.IsEmpty() && !IsDeviceName(path))
00929     {
00930         BOOL ok         = TRUE;         // General flag for returning results
00931         BOOL driveFound = FALSE;        // Flag for valid drive found
00932         BOOL fnameFound = FALSE;        // Flag for valid filename found
00933         BOOL BadCharacter = FALSE;      // Flag for bad character found
00934 
00935         String_256 temp;                // temporary string buffer
00936         String_256 tempDrive;           // temporary string to hold drive
00937 
00938         const TCHAR *fn;                // File Name Pointer 
00939     
00940         fn = path;
00941         temp.Empty();
00942 
00943         // First check if there is a valid drive name or net drive name present
00944         // If the first character of the path is an alpha then assume drive and check if valid
00945         // and so of the form D:/
00946         // Otherwise, check for a UNC (Universal naming convention) form of drive of the form
00947         // \\Deepthought 
00948         if (*fn == SEPARATOR)           
00949             driveFound = getNetDrive(&fn, temp, &BadCharacter); //Parse as UNC or network drive
00950         else 
00951             driveFound = getDrive(&fn, temp);   // Parse the Drive 
00952         
00953         // If parsed that ok then add the drive to our location store
00954         // otherwise reset back to the entire path string and look for a relative style path 
00955         if (driveFound)
00956         {
00957             tempLocation = temp;        // Add drive to location string
00958             tempDrivename = temp;       // Note drive name found for future use
00959         }
00960         else
00961             fn = path;                  // Start again at first character
00962 
00963         // If no drive or net drive (UNC) present then this may be a relative path so do not
00964         // assume that everything fails because of this.
00965         // Now move along the path to see if we have a correct filename with possible multiple
00966         // directories being specified before it.
00967         while (ok && !fnameFound) 
00968         {
00969             temp.Empty();                       // Clear temporary
00970             // The size of the file/directory name is really max string size - current size
00971             // of the location string i.e. the space remaining in our fixed length strings.
00972             UINT32 MaxSize = temp.MaxLength() - tempLocation.Length(); 
00973             ok = getIdentifier(&fn, temp, MaxSize, &BadCharacter);  //Get the Identifier
00974             if (ok)
00975             {
00976                 if (*fn == SEPARATOR)       // If it is a directory location\path 
00977                 {
00978                     tempLocation += temp;   // add to file location\path temp buffer
00979                     fn++;                   // and move to after separator
00980                 }
00981                 else                        // If it is a filename 
00982                 {
00983                     tempFilename = temp;    // add to file name temp buffer
00984                     fnameFound = TRUE;      // and flag found to terminate search
00985                 }
00986             }
00987         }
00988 
00989         // If everything went well then we should now have a filename with an optional
00990         // drive/net drive and optional directory list. Now check for a file extension
00991         // on the end of the filename.
00992         // fn is pointing at the end of the found filename if everything ok 
00993 
00994         if (ok)                                     // If ok so far 
00995         {
00996             // Note current position i.e. end of supplied path
00997             // We will scan from the end backwards to locate the extension.
00998 //          const TCHAR* CurrentPos = fn;
00999             const TCHAR* StartOfPath = path;
01000                 
01001             if (*fn == END_OF_PATH || *fn == END_OF_STRING)
01002             {
01003                 fn = camStrdec(path, fn);       // move to last valid character
01004                 // Get File Extension
01005                 // If we don't find a vlaid extension then do not complain as this should
01006                 // not be a problem.
01007                 BOOL ExtOk = getExtension(&fn, temp, MAXEXT, StartOfPath);
01008 
01009                 if (ExtOk)
01010                 {
01011                     // We parsed it ok, so make a note of it.
01012                     tempFiletype = temp;            // FileType = File Extension
01013                     // tempFileName should already be = leafname found
01014                     // tempLocation should already be = directory path found
01015                     // And remove it from the filename
01016                     UINT32 LenFilename = tempFilename.Length();
01017                     UINT32 LenExtensionName = tempFiletype.Length();
01018                     // Strip the extension name plus the full stop from the filename.
01019                     if (LenFilename > LenExtensionName)
01020                     {
01021                         temp.Empty();
01022                         tempFilename.Left(&temp, (LenFilename - LenExtensionName - 1));
01023                         tempFilename = temp;
01024                     }
01025                 }
01026                 else
01027                 {
01028                     // We have not found what we consider to be a valid extension so say
01029                     // we have a blank filetype.
01030                     tempFiletype.Empty();               // FileType = File Extension
01031                     // The filename is the valid leafname that has been found, possibly
01032                     // including a dodgy extension name that we did not like at all.
01033                 }
01034             }
01035             else
01036             {
01037                 tempFiletype.Empty();               // FileType = File Extension = none
01038             }
01039         }
01040 
01041         // Ok is the flag that says whether we have found a valid filename or not so return
01042         // this to the caller.
01043         // Now we also have a flag BadCharacter. If set we have found what we consider to be
01044         // an illegal/reserved character in the filename and so should return false but may
01045         // have parsed the filename ok so that this can be shown to the user.
01046 //      if (BadCharacter)
01047 //      {
01048 //          // If set errors has been specified then set up the required error
01049 //          if (SetErrors)
01050 //              Error::SetError(_R(IDE_PATH_ERROR), 0); // Set up the correct error
01051 //          return FALSE;
01052 //      }
01053 //      else
01054 //          return ok;                              // Return ok flag   
01055         
01056         // Always return the result, if we reach this point. Ignore bad characters as these
01057         // are ok under NT.
01058         if (!ok)
01059         {
01060             if (SetErrors)
01061             {
01062                 Error::SetError(_R(IDE_PATH_ERROR), 0);
01063             }
01064         }
01065         return ok;
01066     }
01067     else
01068     {
01069         tempFiletype.Empty();                   //Return blank fileType 
01070         tempFilename.Empty();                   //Return blank fileName
01071         tempLocation.Empty();                   //Return blank location
01072 
01073         // If set errors has been specified then set up the required error
01074         if (SetErrors)
01075             Error::SetError(_R(IDE_PATH_ERROR), 0);     // Set up the correct error
01076         return FALSE;                           // Null path passed to us   
01077     }
01078 
01079     // If we reach here then things must have gone terribly wrong so return False
01080     return FALSE;
01081 } 
01082 
01083 
01084 /**********************************************************************************************
01085 
01086 >   PathName& PathName::operator=(const PathName& newPath)
01087 
01088     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
01089     Created:    31/8/93
01090     Inputs:     newPath
01091     Outputs:    None
01092     Returns:    PathName
01093     Purpose:    Assignment operator for pathnames.
01094     Errors:     None
01095 
01096 **********************************************************************************************/
01097 
01098 PathName& PathName::operator=(const PathName& newPath)
01099 {
01100     filename = newPath.filename;
01101     location = newPath.location;
01102     filetype = newPath.filetype;
01103     drivename = newPath.drivename;
01104 
01105     PathNameValid = newPath.PathNameValid;
01106 
01107     return *this;
01108 }
01109 
01110 
01111 /**********************************************************************************************
01112     Win16 Path String Parser Functions
01113 
01114 **********************************************************************************************/
01115 
01116 /**********************************************************************************************
01117 
01118 >   BOOL getDrive(TCHAR **fn, TCHAR *drive)
01119 
01120     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
01121     Created:    12/5/93
01122     Inputs:     A pointer to the pointer to the path string
01123     Outputs:    drive - the parsed Drive Letter 
01124     Returns:    TRUE if parsed ok and false otherwise
01125     Purpose:    Parses the Drive location of file.
01126     Scope:      Private
01127     SeeAlso:    PathName();
01128     SeeAlso:    SetPath();
01129     Errors:     None
01130 
01131 **********************************************************************************************/
01132 
01133 BOOL getDrive(const TCHAR **fn, TCHAR *drive)
01134 {
01135     UINT32 i = 0;   
01136                        
01137     if  (String::IsAlpha(**fn))
01138     {
01139         drive[i++] = **fn;                      // Parse Drive Letter
01140         (*fn)++;
01141         if (**fn == COLON)                      // Parse colon
01142         {
01143             drive[i++] = **fn;
01144             (*fn)++;
01145             if (**fn == SEPARATOR)              // Parse slash
01146             {
01147                 drive[i++] = **fn;
01148                 (*fn)++;
01149             }
01150             else 
01151                 return FALSE;                    // Else Syntax error
01152         }
01153         else 
01154             return FALSE;   
01155     }
01156     else 
01157         return FALSE; 
01158     
01159     drive[i++] = END_OF_STRING;
01160 
01161     return TRUE;
01162 }
01163 
01164 /**********************************************************************************************
01165 
01166 >   BOOL getNetDrive(TCHAR **fn, TCHAR *drive, BOOL *BadCharacter)
01167 
01168     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
01169     Created:    3/9/93
01170     Inputs:     A pointer to the pointer to the path string
01171                 A pointer to the current bad character flag state
01172     Outputs:    A network drive Letter
01173                 A pointer to the potentially new bad character flag state 
01174     Returns:    TRUE if parsed ok FALSE otherwise
01175     Purpose:    Parses the network Drive location of file and returns whether this was
01176                 accomplished or not.
01177                 The network name will consist of the server name followed by a mount point name.
01178     Scope:      Private
01179     SeeAlso:    PathName();
01180     SeeAlso:    SetPath();
01181     Errors:     None
01182 
01183 **********************************************************************************************/
01184 
01185 BOOL getNetDrive(const TCHAR **fn, TCHAR *drive, BOOL *pBadCharacter)
01186 {                                               
01187     // Used for storing either <ServerName> or <DirectoryName> 
01188     String_256 identifier;
01189     TCHAR* pId;
01190         
01191     UINT32 i = 0;
01192                        
01193     if  (**fn == SEPARATOR)                         // Parse '\\' bit
01194     {
01195         drive[i++] = **fn;
01196 
01197         (*fn)++;
01198 
01199         if (**fn == SEPARATOR)                  
01200         {
01201 
01202             drive[i++] = **fn;
01203 
01204             (*fn)++;                        
01205 
01206             identifier.Empty();                     
01207                                                     
01208             // We have a valid network name start
01209             // Parse Network drive name(s)
01210             if ( getIdentifier(&(*fn), identifier, MAXNETNAME, pBadCharacter) )
01211             {
01212                 pId = identifier;                   // Copy identifier into drive
01213 
01214                 while (*pId != END_OF_STRING)
01215                 {
01216                     drive[i++] = *pId;
01217                     pId++;
01218                 }
01219 
01220                 (*fn)++;                        
01221 
01222                 identifier.Empty();
01223 
01224                 // We have a valid network drive name and so parse the mount point name
01225                 if ( getIdentifier(&(*fn), identifier, MAXNETNAME, pBadCharacter) )
01226                 {
01227                     pId = identifier;               // Copy identifier into drive
01228 
01229                     while (*pId != END_OF_STRING)
01230                     {
01231                         drive[i++] = *pId;
01232                         pId++;
01233                     }
01234 
01235                     (*fn)++;                        
01236                 
01237                     drive[i++] = END_OF_STRING;
01238 
01239                     // Everything has gone ok so now exit
01240                     return TRUE;
01241                 }
01242                 else 
01243                     return FALSE;
01244             }
01245             else 
01246                 return FALSE;
01247         }
01248         else 
01249             return FALSE;   
01250     }
01251     else 
01252         return FALSE; 
01253 }
01254 
01255 // Forward Declaration
01256 
01257 //BOOL IsSpecialChar(TCHAR **fn);
01258 
01259 /**********************************************************************************************
01260 
01261 >   BOOL getIdentifier(TCHAR **fn, TCHAR *identifier, UINT32 MaxSize, BOOL *BadCharacter)
01262 
01263     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
01264     Created:    12/5/93
01265