summaryrefslogtreecommitdiffstats
path: root/src/Authoring/Common/Code/Qt3DSFileTools.h
blob: 7dc7e8e3318edbb901cdfc93de91566024a8e4ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
/****************************************************************************
**
** Copyright (C) 1999-2001 NVIDIA Corporation.
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt 3D Studio.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

//==============================================================================
//	Prefix
//==============================================================================
#ifndef INCLUDED_QT3DS_FILETOOLS_H
#define INCLUDED_QT3DS_FILETOOLS_H 1

#pragma once

//==============================================================================
//	Includes
//==============================================================================
#include "Qt3DSString.h"
#include "foundation/Qt3DS.h"
#include "foundation/Qt3DSAssert.h"
#include "foundation/Qt3DSFlags.h"
#include "Qt3DSFileToolTypes.h"
#include "Qt3DSDMWStrOpsImpl.h"

#include <QtCore/qdir.h>
#include <QtCore/qfileinfo.h>

namespace Q3DStudio {
using qt3ds::QT3DSI64;
using qt3ds::foundation::SeekPosition;
using qt3ds::foundation::FileOpenFlags;
using qt3ds::foundation::FileOpenFlagValues;
using qt3dsdm::WStrOps;

struct SFileModificationRecord;

// FIXME: This class should ultimately be removed and replaced with direct
// calls to QFileInfo and friends.
class CFilePath : public QFileInfo
{
public:
    CFilePath();
    CFilePath(const wchar_t *path);
    CFilePath(const char *path);
    CFilePath(const CString &path);
    CFilePath(const QString &path);

    // FIXME: remove when RecursivelyFindFilesOfType is refactored
    // Note: Also needed by binary_sort_insert_unique
    bool operator<(const CFilePath &path) const
    { return filePath() < path.filePath(); }

    // Needed by binary_sort_insert_unique, QFileInfo's corresponding operator doesn't work
    // correctly for paths that do not exist.
    bool operator==(const CFilePath &path) const
    { return filePath() == path.filePath(); }

    // FIXME: refactor call sites to just use 'filePath()'
    QString toQString() const { return filePath(); }
    CString toCString() const { return CString::fromQString(filePath()); }

    // FIXME: refactor at call sites to no longer use implicit casts
    operator const CString()
    { return toCString(); }

    CFilePath GetDirectory() const;
    CString GetFileName() const;
    CString GetFileStem() const; // no extension, test.png -> test
    CString GetExtension() const;

    CString GetPathWithIdentifier() const;
    CString GetIdentifier() const { return CString::fromQString(m_identifier); }
    void SetIdentifier(const QString &identifier) { m_identifier = identifier; }
    void SetIdentifier(const CString &identifier)
    { m_identifier = identifier.toQString(); }

    void ConvertToRelative(const CFilePath &inBaseAbsolute);
    static CFilePath GetRelativePathFromBase(const CFilePath &inBase, const CFilePath &inPath)
    {
        CFilePath retval(inPath);
        retval.ConvertToRelative(inBase);
        return retval;
    }

    /**
    *	Return true if this string is in subdirectory of inBasePath
    *	For example, basepath is C:\Folder\Project.uip
    *	This string is C:\Folder\Resources\Image.png
    *	The function should return true.
    *	@param inBasePath absolute path to base off from
    *	@return bool to indicate if is in subdirectory of inBasePath
    */
    bool IsInSubDirectory(const CFilePath &inBasePath) const;

    void CombineBaseAndRelative(const CFilePath &inBase);

    // Given a base CFilePath, convert it to an absolute CFilePath.
    static CFilePath CombineBaseAndRelative(const CFilePath &inBase, const CFilePath &inRelative)
    {
        CFilePath retval(inRelative);
        retval.CombineBaseAndRelative(inBase);
        return retval;
    }

    bool IsAbsolute() const;
    bool ConvertToAbsolute();
    static CFilePath GetAbsolutePath(const CFilePath &inBaseFilePath)
    {
        CFilePath retval(inBaseFilePath);
        retval.ConvertToAbsolute();
        return retval;
    }
    // Make a save file stem from this string.  Involves replacing characters
    // that are illegal (:,\\,//,etc).
    static CString MakeSafeFileStem(const CString &name);

    // Create this directory, recursively creating parent directories
    // if necessary.
    bool CreateDir(bool recurse) const;
    // Returns true if exists and is directory
    bool IsDirectory() const;
    // returns true if exists and is a file
    bool IsFile() const;

    // If the file doesn't exist, create an empty file at this location.
    // If the file does exist, update its modification time to the current time.
    void Touch() const;
    // Returns true if this exists on the filesystem and is a directory or file.
    bool Exists() const;
    // Delete this file from the filesystem
    bool DeleteThisFile();
    // Delete this directory
    bool DeleteThisDirectory(bool recursive);

    // If this is a directory, list all contents.
    // ignore special files ".\\" and "..\\"
    // Returns absolute paths combined with this
    // this.combineBaseAndRelative( result );
    void ListFilesAndDirectories(std::vector<CFilePath> &files) const;

    // Returns absolute paths
    // This object has to be a directory
    // extension list needs to be null terminated
    // Returns results alphabetically sorted
    // If makeRelative is true, returns paths relative to
    // this directory.
    // Else returns absolute paths.
    // ExtensionList should not contain the "." in ".png" for example.
    // It should just contain { L"png", NULL }
    // An empty extension list means return all files.
    void RecursivelyFindFilesOfType(const wchar_t **inExtensionList, std::vector<CFilePath> &files,
                                    bool inMakeRelative, bool inIncludeDirectories = false) const;

    // Given the list of differences from last time this function was called (which may be empty)
    // and the list of new differences to put new results into, recursively diff this directory's
    // contents with the last time this function was called.
    // IF this is a file, the function asserts and immediately returns.
    // All file paths are absolute paths!!
    // Returns all files (and directories) recursively, sorted by name, for which either no record
    // exists
    // or for which the record entry has changed it's value since last time.
    // inOldDifferences and outNewDifferences may point to the same location.
    // We are expecting inOldDifferences to be sorted by filename; do not change the order of
    // the return value *or* call std::stable_sort( ) on the vector before you call this
    // method
    // If at any point inCancel is true then this function will abort at that moment.
    void FindDirectoryDifferences(const std::vector<SFileModificationRecord> &inOldDifferences,
                                  std::vector<SFileModificationRecord> &outNewDifferences,
                                  volatile bool *inCancel = NULL) const;

    SFileInfoFlags GetFileFlags() const;
    // Requires opening the file!!!
    // Not valid for things that aren't files.
    SFileData GetFileData() const;

    // Get the directory where applications can write data.
    static QString GetUserApplicationDirectory();

    static bool copyFolder(const QString &srcFolder, const QString &destFolder);

private:
    void normalizeAndSetPath(const QString& path);
    QString m_identifier;
};

struct SFileModificationRecord
{
    CFilePath m_File;
    SFileInfoFlags m_FileInfo;
    SFileData m_FileData;
    FileModificationType::Enum m_ModificationType;

    SFileModificationRecord()
        : m_ModificationType(FileModificationType::Unknown)
    {
    }

    SFileModificationRecord(const CFilePath &inFile, const SFileInfoFlags &inFileInfo,
                            const SFileData &inFileData, FileModificationType::Enum modType)
        : m_File(inFile)
        , m_FileInfo(inFileInfo)
        , m_FileData(inFileData)
        , m_ModificationType(modType)
    {
    }
    // Order lexographically
    bool operator<(const SFileModificationRecord &inOther) const { return m_File.filePath() < inOther.m_File.filePath(); }
};

typedef std::vector<SFileModificationRecord> TFileModificationList;

struct SFile
{
    Q_DISABLE_COPY(SFile)

    QSharedPointer<QFile> m_OpenFile;
    CFilePath m_Path;

    SFile(const QSharedPointer<QFile> &of, const CFilePath &path);
    ~SFile();
    QT3DSU32 Read(void *buffPtr, QT3DSU32 byteSize);
    QT3DSU32 Write(const void *buffPtr, QT3DSU32 byteSize);

    QT3DSI64 GetPosition() { return GetPosition(m_OpenFile); }
    void SetPosition(QT3DSI64 inOffset, SeekPosition::Enum inSeekPos)
    {
        SetPosition(m_OpenFile, inOffset, inSeekPos);
    }

    static QSharedPointer<QFile> OpenForRead(const CFilePath &inPath);

    static QSharedPointer<QFile>
    OpenForWrite(const CFilePath &inPath,
                 FileOpenFlags fileFlags = FileOpenFlags(FileOpenFlagValues::Open
                                                         | FileOpenFlagValues::Create
                                                         | FileOpenFlagValues::Truncate));

    // Copy src to dest, close both src and dest, and
    // return the number of bytes copied.
    static QT3DSU64 Copy(const QSharedPointer<QFile> &destFile, const QSharedPointer<QFile> &srcFile);

    // Attemt to write data, return the number of bytes written.
    static QT3DSU32 WriteData(const QSharedPointer<QFile> &fileHandle, const void *data, QT3DSU32 byteSize);

    // Attempt to read data, return the number of byte read
    static QT3DSU32 ReadData(const QSharedPointer<QFile> &fileHandle, void *data, QT3DSU32 byteSize);

    static QT3DSI64 GetPosition(const QSharedPointer<QFile> &fileHandle);

    static void SetPosition(const QSharedPointer<QFile> &fileHandle, QT3DSI64 inOffset, SeekPosition::Enum inSeekPos);

    // Close the file handle.
    static void Close(const QSharedPointer<QFile> &fileHandle);

    // Set file modification time to the current time.
    static void SetFileTimeToCurrentTime(const QSharedPointer<QFile> &fileHandle);

    static std::shared_ptr<SFile> Wrap(const QSharedPointer<QFile> &inFileHandle, const CFilePath &path);
};

typedef std::shared_ptr<SFile> TFilePtr;

struct SFileErrorCodeAndNumBytes
{
    FileErrorCodes::Enum m_Error;
    QT3DSU64 m_NumBytes;
    SFileErrorCodeAndNumBytes(QT3DSU64 nb)
        : m_Error(FileErrorCodes::NoError)
        , m_NumBytes(nb)
    {
    }
    SFileErrorCodeAndNumBytes(FileErrorCodes::Enum val)
        : m_Error(val)
        , m_NumBytes(0)
    {
    }
};

struct SFileErrorCodeFileNameAndNumBytes
{
    FileErrorCodes::Enum m_Error;
    CFilePath m_DestFilename;
    QT3DSU64 m_NumBytes;
    SFileErrorCodeFileNameAndNumBytes(FileErrorCodes::Enum er, QT3DSU64 nb = 0,
                                      const CString &dfn = CString())
        : m_Error(er)
        , m_DestFilename(dfn)
        , m_NumBytes(nb)
    {
    }
};

struct SFileTools
{
    // Open the file and return an os-specific handle.
    // in windows, this uses CreateFile and returns the file handle.
    // It returns the opened file because this eliminates a race condition where
    // this function returns the file name at the same time another process returns
    // the file name and then we have two objects thinking they own the file.
    // Function appends an index in betwee nthe file stem and the extension
    // in order to generate a possibly unique name.
    // Note that the file is not truncated by default if it already exists.
    // params:
    // inDestDir -> points to destination directory (and is a directory)
    // fstem -> file stem to write to
    // inExt -> extension to use after stem + unique append apparatus.
    static TFilePtr FindUniqueDestFile(const CFilePath &inDestDir, const CString &inFStem,
                                       const CString &inExt);
    static QString FindUniqueDestFile(const QDir &inDestDir, const QString &inFStem,
                                      const QString &inExt);
    // Similar to above but takes care of finding the stem and extension from the full source
    // CFilePath
    static TFilePtr FindUniqueDestFile(const CFilePath &inDestDir,
                                       const CFilePath &inSrcFullFilePath);
    static QString FindUniqueDestFile(const QDir &inDestDir,
                                      const QString &inSrcFullFilePath);

    // Similar to above, but allows specifying whether you want the file to be truncated
    // before writing if it exists.
    static TFilePtr FindUniqueDestFile(const CFilePath &inDestDir, const CString &inFStem,
                                       const CString &inExt, bool truncate);
    static QString FindUniqueDestFile(const QDir &inDestDir, const QString &inFStem,
                                      const QString &inExt, bool truncate);

    // Find a unique destination directory.  This directory was guaranteed not to exist before this
    // call
    // and we are guaranteeing that it was created for this call; i.e. there can't be a race
    // condition
    // We expect dest dir and dir name to be normalized.
    // We also expect that inDestDirectory exists.  Function results are L"" otherwise
    // If the function succeeds, it returns the absolute CFilePath of the new directory.
    // If it fails, it returns L"";
    static CFilePath FindUniqueDestDirectory(const CFilePath &inDestDir, const CString &inDirName);

    static QDir FindUniqueDestDirectory(const QDir &inDestDir, const QString &inDirName);

    // Copy the full file FilePaths.
    // Same file flags as SFile::OpenForWrite
    static SFileErrorCodeAndNumBytes Copy(const CFilePath &destFile, FileOpenFlags fileFlags,
                                          const CFilePath &srcFile);

    // Find a unique dest file based on the src file stem and extension but in the destination
    // directory
    // then copy that file.  Return the file name
    // this -> points to destination directory
    // srcFile -> src file to copy
    static SFileErrorCodeFileNameAndNumBytes FindAndCopyDestFile(const CFilePath &inDestDir,
                                                                 const CFilePath &inSrcFile);
    static bool FindAndCopyDestFile(const QDir &inDestDir, const QString &inSrcFile);
    static bool FindAndCopyDestFile(const QDir &inDestDir, const QString &inSrcFile,
                                    QString &outDestFile);
};

}

#endif // INCLUDED_QT3DS_FILETOOLS_H