filename.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,162 行 · 第 1/5 页

CPP
2,162
字号
/////////////////////////////////////////////////////////////////////////////
// Name:        src/common/filename.cpp
// Purpose:     wxFileName - encapsulates a file path
// Author:      Robert Roebling, Vadim Zeitlin
// Modified by:
// Created:     28.12.2000
// RCS-ID:      $Id: filename.cpp,v 1.158.2.6 2006/03/02 12:46:06 JS Exp $
// Copyright:   (c) 2000 Robert Roebling
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

/*
   Here are brief descriptions of the filename formats supported by this class:

   wxPATH_UNIX: standard Unix format, used under Darwin as well, absolute file
                names have the form:
                /dir1/dir2/.../dirN/filename, "." and ".." stand for the
                current and parent directory respectively, "~" is parsed as the
                user HOME and "~username" as the HOME of that user

   wxPATH_DOS:  DOS/Windows format, absolute file names have the form:
                drive:\dir1\dir2\...\dirN\filename.ext where drive is a single
                letter. "." and ".." as for Unix but no "~".

                There are also UNC names of the form \\share\fullpath

   wxPATH_MAC:  Mac OS 8/9 and Mac OS X under CodeWarrior 7 format, absolute file
                names have the form
                    volume:dir1:...:dirN:filename
                and the relative file names are either
                    :dir1:...:dirN:filename
                or just
                    filename
                (although :filename works as well).
                Since the volume is just part of the file path, it is not
                treated like a separate entity as it is done under DOS and
                VMS, it is just treated as another dir.

   wxPATH_VMS:  VMS native format, absolute file names have the form
                    <device>:[dir1.dir2.dir3]file.txt
                or
                    <device>:[000000.dir1.dir2.dir3]file.txt

                the <device> is the physical device (i.e. disk). 000000 is the
                root directory on the device which can be omitted.

                Note that VMS uses different separators unlike Unix:
                 : always after the device. If the path does not contain : than
                   the default (the device of the current directory) is assumed.
                 [ start of directory specification
                 . separator between directory and subdirectory
                 ] between directory and file
 */

// ============================================================================
// declarations
// ============================================================================

// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------

#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "filename.h"
#endif

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx/intl.h"
#include "wx/log.h"
#include "wx/file.h"
#endif

#include "wx/filename.h"
#include "wx/tokenzr.h"
#include "wx/config.h"          // for wxExpandEnvVars
#include "wx/utils.h"
#include "wx/file.h"
#include "wx/dynlib.h"

// For GetShort/LongPathName
#ifdef __WIN32__
#include "wx/msw/wrapwin.h"
#if defined(__MINGW32__)
#include "wx/msw/gccpriv.h"
#endif
#endif

#ifdef __WXWINCE__
#include "wx/msw/private.h"
#endif

#if defined(__WXMAC__)
  #include  "wx/mac/private.h"  // includes mac headers
#endif

// utime() is POSIX so should normally be available on all Unices
#ifdef __UNIX_LIKE__
#include <sys/types.h>
#include <utime.h>
#include <sys/stat.h>
#include <unistd.h>
#endif

#ifdef __DJGPP__
#include <unistd.h>
#endif

#ifdef __MWERKS__
#ifdef __MACH__
#include <sys/types.h>
#include <utime.h>
#include <sys/stat.h>
#include <unistd.h>
#else
#include <stat.h>
#include <unistd.h>
#include <unix.h>
#endif
#endif

#ifdef __WATCOMC__
#include <io.h>
#include <sys/utime.h>
#include <sys/stat.h>
#endif

#ifdef __VISAGECPP__
#ifndef MAX_PATH
#define MAX_PATH 256
#endif
#endif

#ifdef __EMX__
#include <os2.h>
#define MAX_PATH _MAX_PATH
#endif

// ----------------------------------------------------------------------------
// private classes
// ----------------------------------------------------------------------------

// small helper class which opens and closes the file - we use it just to get
// a file handle for the given file name to pass it to some Win32 API function
#if defined(__WIN32__) && !defined(__WXMICROWIN__)

class wxFileHandle
{
public:
    enum OpenMode
    {
        Read,
        Write
    };

    wxFileHandle(const wxString& filename, OpenMode mode)
    {
        m_hFile = ::CreateFile
                    (
                     filename,                      // name
                     mode == Read ? GENERIC_READ    // access mask
                                  : GENERIC_WRITE,
                     FILE_SHARE_READ |              // sharing mode
                     FILE_SHARE_WRITE,              // (allow everything)
                     NULL,                          // no secutity attr
                     OPEN_EXISTING,                 // creation disposition
                     0,                             // no flags
                     NULL                           // no template file
                    );

        if ( m_hFile == INVALID_HANDLE_VALUE )
        {
            wxLogSysError(_("Failed to open '%s' for %s"),
                          filename.c_str(),
                          mode == Read ? _("reading") : _("writing"));
        }
    }

    ~wxFileHandle()
    {
        if ( m_hFile != INVALID_HANDLE_VALUE )
        {
            if ( !::CloseHandle(m_hFile) )
            {
                wxLogSysError(_("Failed to close file handle"));
            }
        }
    }

    // return true only if the file could be opened successfully
    bool IsOk() const { return m_hFile != INVALID_HANDLE_VALUE; }

    // get the handle
    operator HANDLE() const { return m_hFile; }

private:
    HANDLE m_hFile;
};

#endif // __WIN32__

// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------

#if wxUSE_DATETIME && defined(__WIN32__) && !defined(__WXMICROWIN__)

// convert between wxDateTime and FILETIME which is a 64-bit value representing
// the number of 100-nanosecond intervals since January 1, 1601.

static void ConvertFileTimeToWx(wxDateTime *dt, const FILETIME &ft)
{
    FILETIME ftcopy = ft;
    FILETIME ftLocal;
    if ( !::FileTimeToLocalFileTime(&ftcopy, &ftLocal) )
    {
        wxLogLastError(_T("FileTimeToLocalFileTime"));
    }

    SYSTEMTIME st;
    if ( !::FileTimeToSystemTime(&ftLocal, &st) )
    {
        wxLogLastError(_T("FileTimeToSystemTime"));
    }

    dt->Set(st.wDay, wxDateTime::Month(st.wMonth - 1), st.wYear,
            st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
}

static void ConvertWxToFileTime(FILETIME *ft, const wxDateTime& dt)
{
    SYSTEMTIME st;
    st.wDay = dt.GetDay();
    st.wMonth = (WORD)(dt.GetMonth() + 1);
    st.wYear = (WORD)dt.GetYear();
    st.wHour = dt.GetHour();
    st.wMinute = dt.GetMinute();
    st.wSecond = dt.GetSecond();
    st.wMilliseconds = dt.GetMillisecond();

    FILETIME ftLocal;
    if ( !::SystemTimeToFileTime(&st, &ftLocal) )
    {
        wxLogLastError(_T("SystemTimeToFileTime"));
    }

    if ( !::LocalFileTimeToFileTime(&ftLocal, ft) )
    {
        wxLogLastError(_T("LocalFileTimeToFileTime"));
    }
}

#endif // wxUSE_DATETIME && __WIN32__

// return a string with the volume par
static wxString wxGetVolumeString(const wxString& volume, wxPathFormat format)
{
    wxString path;

    if ( !volume.empty() )
    {
        format = wxFileName::GetFormat(format);

        // Special Windows UNC paths hack, part 2: undo what we did in
        // SplitPath() and make an UNC path if we have a drive which is not a
        // single letter (hopefully the network shares can't be one letter only
        // although I didn't find any authoritative docs on this)
        if ( format == wxPATH_DOS && volume.length() > 1 )
        {
            path << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_DOS << volume;
        }
        else if  ( format == wxPATH_DOS || format == wxPATH_VMS )
        {
            path << volume << wxFileName::GetVolumeSeparator(format);
        }
        // else ignore
    }

    return path;
}

// ============================================================================
// implementation
// ============================================================================

// ----------------------------------------------------------------------------
// wxFileName construction
// ----------------------------------------------------------------------------

void wxFileName::Assign( const wxFileName &filepath )
{
    m_volume = filepath.GetVolume();
    m_dirs = filepath.GetDirs();
    m_name = filepath.GetName();
    m_ext = filepath.GetExt();
    m_relative = filepath.m_relative;
    m_hasExt = filepath.m_hasExt;
}

void wxFileName::Assign(const wxString& volume,
                        const wxString& path,
                        const wxString& name,
                        const wxString& ext,
                        bool hasExt,
                        wxPathFormat format )
{
    SetPath( path, format );

    m_volume = volume;
    m_ext = ext;
    m_name = name;

    m_hasExt = hasExt;
}

void wxFileName::SetPath( const wxString& pathOrig, wxPathFormat format )
{
    m_dirs.Clear();

    if ( pathOrig.empty() )
    {
        // no path at all
        m_relative = true;

        return;
    }

    format = GetFormat( format );

    // 0) deal with possible volume part first
    wxString volume,
             path;
    SplitVolume(pathOrig, &volume, &path, format);
    if ( !volume.empty() )
    {
        m_relative = false;

        SetVolume(volume);
    }

    // 1) Determine if the path is relative or absolute.
    wxChar leadingChar = path[0u];

    switch (format)
    {
        case wxPATH_MAC:
            m_relative = leadingChar == wxT(':');

            // We then remove a leading ":". The reason is in our
            // storage form for relative paths:
            // ":dir:file.txt" actually means "./dir/file.txt" in
            // DOS notation and should get stored as
            // (relative) (dir) (file.txt)
            // "::dir:file.txt" actually means "../dir/file.txt"
            // stored as (relative) (..) (dir) (file.txt)
            // This is important only for the Mac as an empty dir
            // actually means <UP>, whereas under DOS, double
            // slashes can be ignored: "\\\\" is the same as "\\".
            if (m_relative)
                path.erase( 0, 1 );
            break;

        case wxPATH_VMS:
            // TODO: what is the relative path format here?
            m_relative = false;
            break;

        default:
            wxFAIL_MSG( _T("Unknown path format") );
            // !! Fall through !!

        case wxPATH_UNIX:
            // the paths of the form "~" or "~username" are absolute
            m_relative = leadingChar != wxT('/') && leadingChar != _T('~');
            break;

        case wxPATH_DOS:
            m_relative = !IsPathSeparator(leadingChar, format);
            break;

    }

    // 2) Break up the path into its members. If the original path
    //    was just "/" or "\\", m_dirs will be empty. We know from
    //    the m_relative field, if this means "nothing" or "root dir".

    wxStringTokenizer tn( path, GetPathSeparators(format) );

    while ( tn.HasMoreTokens() )
    {
        wxString token = tn.GetNextToken();

        // Remove empty token under DOS and Unix, interpret them
        // as .. under Mac.
        if (token.empty())
        {
            if (format == wxPATH_MAC)
                m_dirs.Add( wxT("..") );
            // else ignore
        }
        else
        {
           m_dirs.Add( token );
        }
    }
}

void wxFileName::Assign(const wxString& fullpath,
                        wxPathFormat format)
{
    wxString volume, path, name, ext;
    bool hasExt;
    SplitPath(fullpath, &volume, &path, &name, &ext, &hasExt, format);

    Assign(volume, path, name, ext, hasExt, format);
}

void wxFileName::Assign(const wxString& fullpathOrig,
                        const wxString& fullname,
                        wxPathFormat format)
{
    // always recognize fullpath as directory, even if it doesn't end with a
    // slash
    wxString fullpath = fullpathOrig;
    if ( !wxEndsWithPathSeparator(fullpath) )
    {
        fullpath += GetPathSeparator(format);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?