267 lines
12 KiB
C++
267 lines
12 KiB
C++
/*
|
|
* Copyright (c) 2014, Oculus VR, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*
|
|
*/
|
|
|
|
/// \file FileList.h
|
|
///
|
|
|
|
|
|
#include "NativeFeatureIncludes.hpp"
|
|
#if _RAKNET_SUPPORT_FileOperations==1
|
|
|
|
#ifndef __FILE_LIST
|
|
#define __FILE_LIST
|
|
|
|
#include "Export.hpp"
|
|
#include "DS_List.hpp"
|
|
#include "RakMemoryOverride.hpp"
|
|
#include "RakNetTypes.hpp"
|
|
#include "FileListNodeContext.hpp"
|
|
#include "RakString.hpp"
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning( push )
|
|
#endif
|
|
|
|
namespace RakNet
|
|
{
|
|
class BitStream;
|
|
}
|
|
|
|
namespace RakNet
|
|
{
|
|
/// Forward declarations
|
|
class RakPeerInterface;
|
|
class FileList;
|
|
|
|
|
|
/// Represents once instance of a file
|
|
struct FileListNode
|
|
{
|
|
/// Name of the file
|
|
RakNet::RakString filename;
|
|
|
|
/// Full path to the file, which may be different than filename
|
|
RakNet::RakString fullPathToFile;
|
|
|
|
/// File data (may be null if not ready)
|
|
char *data;
|
|
|
|
/// Length of \a data. May be greater than fileLength if prepended with a file hash
|
|
BitSize_t dataLengthBytes;
|
|
|
|
/// Length of the file
|
|
unsigned fileLengthBytes;
|
|
|
|
/// User specific data for whatever, describing this file.
|
|
FileListNodeContext context;
|
|
|
|
/// If true, data and dataLengthBytes should be empty. This is just storing the filename
|
|
bool isAReference;
|
|
};
|
|
|
|
/// Callback interface set with FileList::SetCallback() in case you want progress notifications when FileList::AddFilesFromDirectory() is called
|
|
class RAK_DLL_EXPORT FileListProgress
|
|
{
|
|
public:
|
|
// GetInstance() and DestroyInstance(instance*)
|
|
STATIC_FACTORY_DECLARATIONS(FileListProgress)
|
|
|
|
FileListProgress() {}
|
|
virtual ~FileListProgress() {}
|
|
|
|
/// First callback called when FileList::AddFilesFromDirectory() starts
|
|
virtual void OnAddFilesFromDirectoryStarted(FileList *fileList, char *dir) {
|
|
(void) fileList;
|
|
(void) dir;
|
|
}
|
|
|
|
/// Called for each directory, when that directory begins processing
|
|
virtual void OnDirectory(FileList *fileList, char *dir, unsigned int directoriesRemaining) {
|
|
(void) fileList;
|
|
(void) dir;
|
|
(void) directoriesRemaining;
|
|
}
|
|
|
|
/// Called for each file, when that file begins processing
|
|
virtual void OnFile(FileList *fileList, char *dir, char *fileName, unsigned int fileSize) {
|
|
(void) fileList;
|
|
(void) dir;
|
|
(void) fileName;
|
|
(void) fileSize;
|
|
}
|
|
|
|
/// \brief This function is called when we are sending a file to a remote system.
|
|
/// \param[in] fileName The name of the file being sent
|
|
/// \param[in] fileLengthBytes How long the file is
|
|
/// \param[in] offset The offset in bytes into the file that we are sending
|
|
/// \param[in] bytesBeingSent How many bytes we are sending this push
|
|
/// \param[in] done If this file is now done with this push
|
|
/// \param[in] targetSystem Who we are sending to
|
|
virtual void OnFilePush(const char *fileName, unsigned int fileLengthBytes, unsigned int offset, unsigned int bytesBeingSent, bool done, SystemAddress targetSystem, unsigned short setId)
|
|
{
|
|
(void) fileName;
|
|
(void) fileLengthBytes;
|
|
(void) offset;
|
|
(void) bytesBeingSent;
|
|
(void) done;
|
|
(void) targetSystem;
|
|
(void) setId;
|
|
}
|
|
|
|
/// \brief This function is called when all files have been read and are being transferred to a remote system
|
|
virtual void OnFilePushesComplete( SystemAddress systemAddress, unsigned short setId )
|
|
{
|
|
(void) systemAddress;
|
|
(void) setId;
|
|
}
|
|
|
|
/// \brief This function is called when a send to a system was aborted (probably due to disconnection)
|
|
virtual void OnSendAborted( SystemAddress systemAddress )
|
|
{
|
|
(void) systemAddress;
|
|
}
|
|
};
|
|
|
|
/// Implementation of FileListProgress to use RAKNET_DEBUG_PRINTF
|
|
class RAK_DLL_EXPORT FLP_Printf : public FileListProgress
|
|
{
|
|
public:
|
|
// GetInstance() and DestroyInstance(instance*)
|
|
STATIC_FACTORY_DECLARATIONS(FLP_Printf)
|
|
|
|
FLP_Printf() {}
|
|
virtual ~FLP_Printf() {}
|
|
|
|
/// First callback called when FileList::AddFilesFromDirectory() starts
|
|
virtual void OnAddFilesFromDirectoryStarted(FileList *fileList, char *dir);
|
|
|
|
/// Called for each directory, when that directory begins processing
|
|
virtual void OnDirectory(FileList *fileList, char *dir, unsigned int directoriesRemaining);
|
|
|
|
/// \brief This function is called when all files have been transferred to a particular remote system
|
|
virtual void OnFilePushesComplete( SystemAddress systemAddress, unsigned short setID );
|
|
|
|
/// \brief This function is called when a send to a system was aborted (probably due to disconnection)
|
|
virtual void OnSendAborted( SystemAddress systemAddress );
|
|
};
|
|
|
|
class RAK_DLL_EXPORT FileList
|
|
{
|
|
public:
|
|
// GetInstance() and DestroyInstance(instance*)
|
|
STATIC_FACTORY_DECLARATIONS(FileList)
|
|
|
|
FileList();
|
|
~FileList();
|
|
/// \brief Add all the files at a given directory.
|
|
/// \param[in] applicationDirectory The first part of the path. This is not stored as part of the filename. Use \ as the path delineator.
|
|
/// \param[in] subDirectory The rest of the path to the file. This is stored as a prefix to the filename
|
|
/// \param[in] writeHash The first 4 bytes is a hash of the file, with the remainder the actual file data (should \a writeData be true)
|
|
/// \param[in] writeData Write the contents of each file
|
|
/// \param[in] recursive Whether or not to visit subdirectories
|
|
/// \param[in] context User defined byte to store with each file. Use for whatever you want.
|
|
void AddFilesFromDirectory(const char *applicationDirectory, const char *subDirectory, bool writeHash, bool writeData, bool recursive, FileListNodeContext context);
|
|
|
|
/// Deallocate all memory
|
|
void Clear(void);
|
|
|
|
/// Write all encoded data into a bitstream
|
|
void Serialize(RakNet::BitStream *outBitStream);
|
|
|
|
/// Read all encoded data from a bitstream. Clear() is called before deserializing.
|
|
bool Deserialize(RakNet::BitStream *inBitStream);
|
|
|
|
/// \brief Given the existing set of files, search applicationDirectory for the same files.
|
|
/// \details For each file that is missing or different, add that file to \a missingOrChangedFiles. Note: the file contents are not written, and only the hash if written if \a alwaysWriteHash is true
|
|
/// alwaysWriteHash and neverWriteHash are optimizations to avoid reading the file contents to generate the hash if not necessary because the file is missing or has different lengths anyway.
|
|
/// \param[in] applicationDirectory The first part of the path. This is not stored as part of the filename. Use \ as the path delineator.
|
|
/// \param[out] missingOrChangedFiles Output list written to
|
|
/// \param[in] alwaysWriteHash If true, and neverWriteHash is false, will hash the file content of the file on disk, and write that as the file data with a length of SHA1_LENGTH bytes. If false, if the file length is different, will only write the filename.
|
|
/// \param[in] neverWriteHash If true, will never write the hash, even if available. If false, will write the hash if the file lengths are the same and it was forced to do a comparison.
|
|
void ListMissingOrChangedFiles(const char *applicationDirectory, FileList *missingOrChangedFiles, bool alwaysWriteHash, bool neverWriteHash);
|
|
|
|
/// \brief Return the files that need to be written to make \a input match this current FileList.
|
|
/// \details Specify dirSubset to only consider files that start with this path
|
|
/// specify remoteSubdir to assume that all filenames in input start with this path, so strip it off when comparing filenames.
|
|
/// \param[in] input Full list of files
|
|
/// \param[out] output Files that we need to match input
|
|
/// \param[in] dirSubset If the filename does not start with this path, just skip this file.
|
|
/// \param[in] remoteSubdir Remove this from the filenames of \a input when comparing to existing filenames.
|
|
void GetDeltaToCurrent(FileList *input, FileList *output, const char *dirSubset, const char *remoteSubdir);
|
|
|
|
/// \brief Assuming FileList contains a list of filenames presumably without data, read the data for these filenames
|
|
/// \param[in] applicationDirectory Prepend this path to each filename. Trailing slash will be added if necessary. Use \ as the path delineator.
|
|
/// \param[in] writeFileData True to read and store the file data. The first SHA1_LENGTH bytes will contain the hash if \a writeFileHash is true
|
|
/// \param[in] writeFileHash True to read and store the hash of the file data. The first SHA1_LENGTH bytes will contain the hash if \a writeFileHash is true
|
|
/// \param[in] removeUnknownFiles If a file does not exist on disk but is in the file list, remove it from the file list?
|
|
void PopulateDataFromDisk(const char *applicationDirectory, bool writeFileData, bool writeFileHash, bool removeUnknownFiles);
|
|
|
|
/// By default, GetDeltaToCurrent tags files as non-references, meaning they are assumed to be populated later
|
|
/// This tags all files as references, required for IncrementalReadInterface to process them incrementally
|
|
void FlagFilesAsReferences(void);
|
|
|
|
/// \brief Write all files to disk, prefixing the paths with applicationDirectory
|
|
/// \param[in] applicationDirectory path prefix
|
|
void WriteDataToDisk(const char *applicationDirectory);
|
|
|
|
/// \brief Add a file, given data already in memory.
|
|
/// \param[in] filename Name of a file, optionally prefixed with a partial or complete path. Use \ as the path delineator.
|
|
/// \param[in] fullPathToFile Full path to the file on disk
|
|
/// \param[in] data Contents to write
|
|
/// \param[in] dataLength length of the data, which may be greater than fileLength should you prefix extra data, such as the hash
|
|
/// \param[in] fileLength Length of the file
|
|
/// \param[in] context User defined byte to store with each file. Use for whatever you want.
|
|
/// \param[in] isAReference Means that this is just a reference to a file elsewhere - does not actually have any data
|
|
/// \param[in] takeDataPointer If true, do not allocate dataLength. Just take the pointer passed to the \a data parameter
|
|
void AddFile(const char *filename, const char *fullPathToFile, const char *data, const unsigned dataLength, const unsigned fileLength, FileListNodeContext context, bool isAReference=false, bool takeDataPointer=false);
|
|
|
|
/// \brief Add a file, reading it from disk.
|
|
/// \param[in] filepath Complete path to the file, including the filename itself
|
|
/// \param[in] filename filename to store internally, anything you want, but usually either the complete path or a subset of the complete path.
|
|
/// \param[in] context User defined byte to store with each file. Use for whatever you want.
|
|
void AddFile(const char *filepath, const char *filename, FileListNodeContext context);
|
|
|
|
/// \brief Delete all files stored in the file list.
|
|
/// \param[in] applicationDirectory Prefixed to the path to each filename. Use \ as the path delineator.
|
|
void DeleteFiles(const char *applicationDirectory);
|
|
|
|
/// \brief Adds a callback to get progress reports about what the file list instances do.
|
|
/// \param[in] cb A pointer to an externally defined instance of FileListProgress. This pointer is held internally, so should remain valid as long as this class is valid.
|
|
void AddCallback(FileListProgress *cb);
|
|
|
|
/// \brief Removes a callback
|
|
/// \param[in] cb A pointer to an externally defined instance of FileListProgress that was previously added with AddCallback()
|
|
void RemoveCallback(FileListProgress *cb);
|
|
|
|
/// \brief Removes all callbacks
|
|
void ClearCallbacks(void);
|
|
|
|
/// Returns all callbacks added with AddCallback()
|
|
/// \param[out] callbacks The list is set to the list of callbacks
|
|
void GetCallbacks(DataStructures::List<FileListProgress*> &callbacks);
|
|
|
|
// Here so you can read it, but don't modify it
|
|
DataStructures::List<FileListNode> fileList;
|
|
|
|
static bool FixEndingSlash(char *str);
|
|
protected:
|
|
DataStructures::List<FileListProgress*> fileListProgressCallbacks;
|
|
};
|
|
|
|
} // namespace RakNet
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning( pop )
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#endif // _RAKNET_SUPPORT_FileOperations
|