- put the entire filesystem code into a namespace and created some subdirectories.
This commit is contained in:
parent
94c9ee4593
commit
ebb71cebf1
108 changed files with 308 additions and 225 deletions
401
src/common/filesystem/include/fs_files.h
Normal file
401
src/common/filesystem/include/fs_files.h
Normal file
|
|
@ -0,0 +1,401 @@
|
|||
/*
|
||||
** files.h
|
||||
** Implements classes for reading from files or memory blocks
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2008 Randy Heit
|
||||
** Copyright 2005-2008 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef FILES_H
|
||||
#define FILES_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <functional>
|
||||
#include "fs_swap.h"
|
||||
|
||||
#include "tarray.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
class FileSystemException : public std::exception
|
||||
{
|
||||
protected:
|
||||
static const int MAX_FSERRORTEXT = 1024;
|
||||
char m_Message[MAX_FSERRORTEXT];
|
||||
|
||||
public:
|
||||
FileSystemException(const char* error, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
va_start(argptr, error);
|
||||
vsnprintf(m_Message, MAX_FSERRORTEXT, error, argptr);
|
||||
va_end(argptr);
|
||||
}
|
||||
FileSystemException(const char* error, va_list argptr)
|
||||
{
|
||||
vsnprintf(m_Message, MAX_FSERRORTEXT, error, argptr);
|
||||
}
|
||||
char const* what() const noexcept override
|
||||
{
|
||||
return m_Message;
|
||||
}
|
||||
};
|
||||
|
||||
// Zip compression methods, extended by some internal types to be passed to OpenDecompressor
|
||||
enum
|
||||
{
|
||||
METHOD_STORED = 0,
|
||||
METHOD_SHRINK = 1,
|
||||
METHOD_IMPLODE = 6,
|
||||
METHOD_DEFLATE = 8,
|
||||
METHOD_BZIP2 = 12,
|
||||
METHOD_LZMA = 14,
|
||||
METHOD_PPMD = 98,
|
||||
METHOD_LZSS = 1337, // not used in Zips - this is for Console Doom compression
|
||||
METHOD_ZLIB = 1338, // Zlib stream with header, used by compressed nodes.
|
||||
METHOD_TRANSFEROWNER = 0x8000,
|
||||
};
|
||||
|
||||
class FileReader;
|
||||
|
||||
class FileReaderInterface
|
||||
{
|
||||
public:
|
||||
long Length = -1;
|
||||
virtual ~FileReaderInterface() {}
|
||||
virtual long Tell () const = 0;
|
||||
virtual long Seek (long offset, int origin) = 0;
|
||||
virtual long Read (void *buffer, long len) = 0;
|
||||
virtual char *Gets(char *strbuf, int len) = 0;
|
||||
virtual const char *GetBuffer() const { return nullptr; }
|
||||
long GetLength () const { return Length; }
|
||||
};
|
||||
|
||||
class MemoryReader : public FileReaderInterface
|
||||
{
|
||||
protected:
|
||||
const char * bufptr = nullptr;
|
||||
long FilePos = 0;
|
||||
|
||||
MemoryReader()
|
||||
{}
|
||||
|
||||
public:
|
||||
MemoryReader(const char *buffer, long length)
|
||||
{
|
||||
bufptr = buffer;
|
||||
Length = length;
|
||||
FilePos = 0;
|
||||
}
|
||||
|
||||
long Tell() const override;
|
||||
long Seek(long offset, int origin) override;
|
||||
long Read(void *buffer, long len) override;
|
||||
char *Gets(char *strbuf, int len) override;
|
||||
virtual const char *GetBuffer() const override { return bufptr; }
|
||||
};
|
||||
|
||||
|
||||
struct FResourceLump;
|
||||
|
||||
class FileReader
|
||||
{
|
||||
friend struct FResourceLump; // needs access to the private constructor.
|
||||
|
||||
FileReaderInterface *mReader = nullptr;
|
||||
|
||||
FileReader(const FileReader &r) = delete;
|
||||
FileReader &operator=(const FileReader &r) = delete;
|
||||
|
||||
public:
|
||||
|
||||
explicit FileReader(FileReaderInterface *r)
|
||||
{
|
||||
mReader = r;
|
||||
}
|
||||
|
||||
enum ESeek
|
||||
{
|
||||
SeekSet = SEEK_SET,
|
||||
SeekCur = SEEK_CUR,
|
||||
SeekEnd = SEEK_END
|
||||
};
|
||||
|
||||
typedef ptrdiff_t Size; // let's not use 'long' here.
|
||||
|
||||
FileReader() {}
|
||||
|
||||
FileReader(FileReader &&r)
|
||||
{
|
||||
mReader = r.mReader;
|
||||
r.mReader = nullptr;
|
||||
}
|
||||
|
||||
FileReader& operator =(FileReader &&r)
|
||||
{
|
||||
Close();
|
||||
mReader = r.mReader;
|
||||
r.mReader = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// This is for wrapping the actual reader for custom access where a managed FileReader won't work.
|
||||
FileReaderInterface* GetInterface()
|
||||
{
|
||||
auto i = mReader;
|
||||
mReader = nullptr;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
~FileReader()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
bool isOpen() const
|
||||
{
|
||||
return mReader != nullptr;
|
||||
}
|
||||
|
||||
void Close()
|
||||
{
|
||||
if (mReader != nullptr) delete mReader;
|
||||
mReader = nullptr;
|
||||
}
|
||||
|
||||
bool OpenFile(const char *filename, Size start = 0, Size length = -1);
|
||||
bool OpenFilePart(FileReader &parent, Size start, Size length);
|
||||
bool OpenMemory(const void *mem, Size length); // read directly from the buffer
|
||||
bool OpenMemoryArray(const void *mem, Size length); // read from a copy of the buffer.
|
||||
bool OpenMemoryArray(std::function<bool(std::vector<uint8_t>&)> getter); // read contents to a buffer and return a reader to it
|
||||
bool OpenDecompressor(FileReader &parent, Size length, int method, bool seekable, bool exceptions = false); // creates a decompressor stream. 'seekable' uses a buffered version so that the Seek and Tell methods can be used.
|
||||
|
||||
Size Tell() const
|
||||
{
|
||||
return mReader->Tell();
|
||||
}
|
||||
|
||||
Size Seek(Size offset, ESeek origin)
|
||||
{
|
||||
return mReader->Seek((long)offset, origin);
|
||||
}
|
||||
|
||||
Size Read(void *buffer, Size len) const
|
||||
{
|
||||
return mReader->Read(buffer, (long)len);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Read(size_t len)
|
||||
{
|
||||
std::vector<uint8_t> buffer(len);
|
||||
Size length = mReader->Read(&buffer[0], (long)len);
|
||||
buffer.resize((size_t)length);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Read()
|
||||
{
|
||||
return Read(GetLength());
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ReadPadded(size_t padding)
|
||||
{
|
||||
auto len = GetLength();
|
||||
std::vector<uint8_t> buffer(len + padding);
|
||||
Size length = mReader->Read(&buffer[0], (long)len);
|
||||
if (length < len) buffer.clear();
|
||||
else memset(buffer.data() + len, 0, padding);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char *Gets(char *strbuf, Size len)
|
||||
{
|
||||
return mReader->Gets(strbuf, (int)len);
|
||||
}
|
||||
|
||||
const char *GetBuffer()
|
||||
{
|
||||
return mReader->GetBuffer();
|
||||
}
|
||||
|
||||
Size GetLength() const
|
||||
{
|
||||
return mReader->GetLength();
|
||||
}
|
||||
|
||||
uint8_t ReadUInt8()
|
||||
{
|
||||
uint8_t v = 0;
|
||||
Read(&v, 1);
|
||||
return v;
|
||||
}
|
||||
|
||||
int8_t ReadInt8()
|
||||
{
|
||||
int8_t v = 0;
|
||||
Read(&v, 1);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
uint16_t ReadUInt16()
|
||||
{
|
||||
uint16_t v = 0;
|
||||
Read(&v, 2);
|
||||
return byteswap::LittleShort(v);
|
||||
}
|
||||
|
||||
int16_t ReadInt16()
|
||||
{
|
||||
return (int16_t)ReadUInt16();
|
||||
}
|
||||
|
||||
int16_t ReadUInt16BE()
|
||||
{
|
||||
uint16_t v = 0;
|
||||
Read(&v, 2);
|
||||
return byteswap::BigShort(v);
|
||||
}
|
||||
|
||||
int16_t ReadInt16BE()
|
||||
{
|
||||
return (int16_t)ReadUInt16BE();
|
||||
}
|
||||
|
||||
uint32_t ReadUInt32()
|
||||
{
|
||||
uint32_t v = 0;
|
||||
Read(&v, 4);
|
||||
return byteswap::LittleLong(v);
|
||||
}
|
||||
|
||||
int32_t ReadInt32()
|
||||
{
|
||||
return (int32_t)ReadUInt32();
|
||||
}
|
||||
|
||||
uint32_t ReadUInt32BE()
|
||||
{
|
||||
uint32_t v = 0;
|
||||
Read(&v, 4);
|
||||
return byteswap::BigLong(v);
|
||||
}
|
||||
|
||||
int32_t ReadInt32BE()
|
||||
{
|
||||
return (int32_t)ReadUInt32BE();
|
||||
}
|
||||
|
||||
uint64_t ReadUInt64()
|
||||
{
|
||||
uint64_t v = 0;
|
||||
Read(&v, 8);
|
||||
// Prove to me that there's a relevant 64 bit Big Endian architecture and I fix this! :P
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
friend class FileSystem;
|
||||
};
|
||||
|
||||
class DecompressorBase : public FileReaderInterface
|
||||
{
|
||||
bool exceptions = false;
|
||||
public:
|
||||
// These do not work but need to be defined to satisfy the FileReaderInterface.
|
||||
// They will just error out when called.
|
||||
long Tell() const override;
|
||||
long Seek(long offset, int origin) override;
|
||||
char* Gets(char* strbuf, int len) override;
|
||||
void DecompressionError(const char* error, ...) const;
|
||||
void SetOwnsReader();
|
||||
void EnableExceptions(bool on) { exceptions = on; }
|
||||
|
||||
protected:
|
||||
FileReader* File = nullptr;
|
||||
FileReader OwnedFile;
|
||||
};
|
||||
|
||||
|
||||
class FileWriter
|
||||
{
|
||||
protected:
|
||||
bool OpenDirect(const char *filename);
|
||||
|
||||
public:
|
||||
FileWriter(FILE *f = nullptr) // if passed, this writer will take over the file.
|
||||
{
|
||||
File = f;
|
||||
}
|
||||
virtual ~FileWriter()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
static FileWriter *Open(const char *filename);
|
||||
|
||||
virtual size_t Write(const void *buffer, size_t len);
|
||||
virtual long Tell();
|
||||
virtual long Seek(long offset, int mode);
|
||||
size_t Printf(const char *fmt, ...);
|
||||
|
||||
virtual void Close()
|
||||
{
|
||||
if (File != NULL) fclose(File);
|
||||
File = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
FILE *File;
|
||||
|
||||
protected:
|
||||
bool CloseOnDestruct;
|
||||
};
|
||||
|
||||
class BufferWriter : public FileWriter
|
||||
{
|
||||
protected:
|
||||
TArray<unsigned char> mBuffer;
|
||||
public:
|
||||
|
||||
BufferWriter() {}
|
||||
virtual size_t Write(const void *buffer, size_t len) override;
|
||||
TArray<unsigned char> *GetBuffer() { return &mBuffer; }
|
||||
TArray<unsigned char>&& TakeBuffer() { return std::move(mBuffer); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
216
src/common/filesystem/include/fs_filesystem.h
Normal file
216
src/common/filesystem/include/fs_filesystem.h
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
#pragma once
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// File system I/O functions.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
#include "fs_files.h"
|
||||
#include "resourcefile.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
class FResourceFile;
|
||||
struct FResourceLump;
|
||||
|
||||
union LumpShortName
|
||||
{
|
||||
char String[9];
|
||||
|
||||
uint32_t dword; // These are for accessing the first 4 or 8 chars of
|
||||
uint64_t qword; // Name as a unit without breaking strict aliasing rules
|
||||
};
|
||||
|
||||
|
||||
// A lump in memory.
|
||||
class FileData
|
||||
{
|
||||
public:
|
||||
FileData() { lump = nullptr; }
|
||||
const void *GetMem () { return lump->Cache; }
|
||||
size_t GetSize () { return lump->LumpSize; }
|
||||
const char* GetString () const { return (const char*)lump->Cache; }
|
||||
const uint8_t* GetBytes() const { return (const uint8_t*)lump->Cache; }
|
||||
|
||||
FileData& operator = (const FileData& copy) = delete;
|
||||
|
||||
FileData(const FileData& copy)
|
||||
{
|
||||
lump = copy.lump;
|
||||
lump->Lock();
|
||||
}
|
||||
|
||||
~FileData()
|
||||
{
|
||||
if (lump) lump->Unlock();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
FileData(FResourceLump* nlump)
|
||||
{
|
||||
lump = nlump;
|
||||
if (lump) lump->Lock();
|
||||
}
|
||||
|
||||
FResourceLump* lump;
|
||||
|
||||
friend class FileSystem;
|
||||
};
|
||||
|
||||
struct FolderEntry
|
||||
{
|
||||
const char *name;
|
||||
unsigned lumpnum;
|
||||
};
|
||||
|
||||
class FileSystem
|
||||
{
|
||||
public:
|
||||
FileSystem();
|
||||
~FileSystem ();
|
||||
|
||||
// The wadnum for the IWAD
|
||||
int GetIwadNum() { return IwadIndex; }
|
||||
void SetIwadNum(int x) { IwadIndex = x; }
|
||||
|
||||
int GetMaxIwadNum() { return MaxIwadIndex; }
|
||||
void SetMaxIwadNum(int x) { MaxIwadIndex = x; }
|
||||
|
||||
bool InitSingleFile(const char *filename, FileSystemMessageFunc Printf = nullptr);
|
||||
bool InitMultipleFiles (std::vector<std::string>& filenames, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, bool allowduplicates = false, FILE* hashfile = nullptr);
|
||||
void AddFile (const char *filename, FileReader *wadinfo, LumpFilterInfo* filter, FileSystemMessageFunc Printf, FILE* hashfile);
|
||||
int CheckIfResourceFileLoaded (const char *name) noexcept;
|
||||
void AddAdditionalFile(const char* filename, FileReader* wadinfo = NULL) {}
|
||||
|
||||
const char *GetResourceFileName (int filenum) const noexcept;
|
||||
const char *GetResourceFileFullName (int wadnum) const noexcept;
|
||||
|
||||
int GetFirstEntry(int wadnum) const noexcept;
|
||||
int GetLastEntry(int wadnum) const noexcept;
|
||||
int GetEntryCount(int wadnum) const noexcept;
|
||||
|
||||
int CheckNumForName (const char *name, int namespc) const;
|
||||
int CheckNumForName (const char *name, int namespc, int wadfile, bool exact = true) const;
|
||||
int GetNumForName (const char *name, int namespc) const;
|
||||
|
||||
inline int CheckNumForName (const uint8_t *name) const { return CheckNumForName ((const char *)name, ns_global); }
|
||||
inline int CheckNumForName (const char *name) const { return CheckNumForName (name, ns_global); }
|
||||
inline int CheckNumForName (const uint8_t *name, int ns) const { return CheckNumForName ((const char *)name, ns); }
|
||||
inline int GetNumForName (const char *name) const { return GetNumForName (name, ns_global); }
|
||||
inline int GetNumForName (const uint8_t *name) const { return GetNumForName ((const char *)name); }
|
||||
inline int GetNumForName (const uint8_t *name, int ns) const { return GetNumForName ((const char *)name, ns); }
|
||||
|
||||
int CheckNumForFullName (const char *cname, bool trynormal = false, int namespc = ns_global, bool ignoreext = false) const;
|
||||
int CheckNumForFullName (const char *name, int wadfile) const;
|
||||
int GetNumForFullName (const char *name) const;
|
||||
int FindFile(const char* name) const
|
||||
{
|
||||
return CheckNumForFullName(name);
|
||||
}
|
||||
|
||||
bool FileExists(const char* name) const
|
||||
{
|
||||
return FindFile(name) >= 0;
|
||||
}
|
||||
|
||||
bool FileExists(const std::string& name) const
|
||||
{
|
||||
return FindFile(name.c_str()) >= 0;
|
||||
}
|
||||
|
||||
LumpShortName& GetShortName(int i); // may only be called before the hash chains are set up.
|
||||
void RenameFile(int num, const char* fn);
|
||||
bool CreatePathlessCopy(const char* name, int id, int flags);
|
||||
|
||||
void ReadFile (int lump, void *dest);
|
||||
// These should only be used if the file data really needs padding.
|
||||
FileData ReadFile (int lump);
|
||||
FileData ReadFile (const char *name) { return ReadFile (GetNumForName (name)); }
|
||||
FileData ReadFileFullName(const char* name) { return ReadFile(GetNumForFullName(name)); }
|
||||
|
||||
FileReader OpenFileReader(int lump); // opens a reader that redirects to the containing file's one.
|
||||
FileReader ReopenFileReader(int lump, bool alwayscache = false); // opens an independent reader.
|
||||
FileReader OpenFileReader(const char* name);
|
||||
|
||||
int FindLump (const char *name, int *lastlump, bool anyns=false); // [RH] Find lumps with duplication
|
||||
int FindLumpMulti (const char **names, int *lastlump, bool anyns = false, int *nameindex = NULL); // same with multiple possible names
|
||||
int FindLumpFullName(const char* name, int* lastlump, bool noext = false);
|
||||
bool CheckFileName (int lump, const char *name); // [RH] True if lump's name == name
|
||||
|
||||
int FindFileWithExtensions(const char* name, const char* const* exts, int count) const;
|
||||
int FindResource(int resid, const char* type, int filenum = -1) const noexcept;
|
||||
int GetResource(int resid, const char* type, int filenum = -1) const;
|
||||
|
||||
|
||||
static uint32_t LumpNameHash (const char *name); // [RH] Create hash key from an 8-char name
|
||||
|
||||
int FileLength (int lump) const;
|
||||
int GetFileOffset (int lump); // [RH] Returns offset of lump in the wadfile
|
||||
int GetFileFlags (int lump); // Return the flags for this lump
|
||||
const char* GetFileShortName(int lump) const;
|
||||
const char *GetFileFullName (int lump, bool returnshort = true) const; // [RH] Returns the lump's full name
|
||||
std::string GetFileFullPath (int lump) const; // [RH] Returns wad's name + lump's full name
|
||||
int GetFileContainer (int lump) const; // [RH] Returns wadnum for a specified lump
|
||||
int GetFileNamespace (int lump) const; // [RH] Returns the namespace a lump belongs to
|
||||
void SetFileNamespace(int lump, int ns);
|
||||
int GetResourceId(int lump) const; // Returns the RFF index number for this lump
|
||||
const char* GetResourceType(int lump) const;
|
||||
bool CheckFileName (int lump, const char *name) const; // [RH] Returns true if the names match
|
||||
unsigned GetFilesInFolder(const char *path, std::vector<FolderEntry> &result, bool atomic) const;
|
||||
|
||||
int GetNumEntries() const
|
||||
{
|
||||
return NumEntries;
|
||||
}
|
||||
|
||||
int GetNumWads() const
|
||||
{
|
||||
return (int)Files.size();
|
||||
}
|
||||
|
||||
void AddLump(FResourceLump* lump);
|
||||
int AddExternalFile(const char *filename);
|
||||
int AddFromBuffer(const char* name, const char* type, char* data, int size, int id, int flags);
|
||||
FileReader* GetFileReader(int wadnum); // Gets a FileReader object to the entire WAD
|
||||
void InitHashChains();
|
||||
FResourceLump* GetFileAt(int no);
|
||||
|
||||
protected:
|
||||
|
||||
struct LumpRecord;
|
||||
|
||||
std::vector<FResourceFile *> Files;
|
||||
std::vector<LumpRecord> FileInfo;
|
||||
|
||||
std::vector<uint32_t> Hashes; // one allocation for all hash lists.
|
||||
uint32_t *FirstLumpIndex; // [RH] Hashing stuff moved out of lumpinfo structure
|
||||
uint32_t *NextLumpIndex;
|
||||
|
||||
uint32_t *FirstLumpIndex_FullName; // The same information for fully qualified paths from .zips
|
||||
uint32_t *NextLumpIndex_FullName;
|
||||
|
||||
uint32_t *FirstLumpIndex_NoExt; // The same information for fully qualified paths from .zips
|
||||
uint32_t *NextLumpIndex_NoExt;
|
||||
|
||||
uint32_t* FirstLumpIndex_ResId; // The same information for fully qualified paths from .zips
|
||||
uint32_t* NextLumpIndex_ResId;
|
||||
|
||||
uint32_t NumEntries = 0; // Not necessarily the same as FileInfo.Size()
|
||||
uint32_t NumWads;
|
||||
|
||||
int IwadIndex = -1;
|
||||
int MaxIwadIndex = -1;
|
||||
|
||||
StringPool* stringpool;
|
||||
|
||||
private:
|
||||
void DeleteAll();
|
||||
void MoveLumpsInFolder(const char *);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
39
src/common/filesystem/include/fs_findfile.h
Normal file
39
src/common/filesystem/include/fs_findfile.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
// Directory searching routines
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
struct FileListEntry
|
||||
{
|
||||
std::string FileName; // file name only
|
||||
std::string FilePath; // full path to file
|
||||
std::string FilePathRel; // path relative to the scanned directory.
|
||||
size_t Length = 0;
|
||||
bool isDirectory = false;
|
||||
bool isReadonly = false;
|
||||
bool isHidden = false;
|
||||
bool isSystem = false;
|
||||
};
|
||||
|
||||
using FileList = std::vector<FileListEntry>;
|
||||
|
||||
struct FCompressedBuffer;
|
||||
bool ScanDirectory(std::vector<FileListEntry>& list, const char* dirpath, const char* match, bool nosubdir = false, bool readhidden = false);
|
||||
bool WriteZip(const char* filename, const FCompressedBuffer* content, size_t contentcount);
|
||||
bool FS_DirEntryExists(const char* pathname, bool* isdir);
|
||||
|
||||
inline void FixPathSeparator(char* path)
|
||||
{
|
||||
while (*path)
|
||||
{
|
||||
if (*path == '\\')
|
||||
*path = '/';
|
||||
path++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
122
src/common/filesystem/include/fs_swap.h
Normal file
122
src/common/filesystem/include/fs_swap.h
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
//
|
||||
// DESCRIPTION:
|
||||
// Endianess handling, swapping 16bit and 32bit.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __FS_SWAP_H__
|
||||
#define __FS_SWAP_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
// Endianess handling.
|
||||
// WAD files are stored little endian.
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#endif
|
||||
|
||||
namespace FileSys {
|
||||
namespace byteswap {
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
inline unsigned short LittleShort(unsigned short x)
|
||||
{
|
||||
return OSSwapLittleToHostInt16(x);
|
||||
}
|
||||
|
||||
inline unsigned int LittleLong(unsigned int x)
|
||||
{
|
||||
return OSSwapLittleToHostInt32(x);
|
||||
}
|
||||
|
||||
inline unsigned short BigShort(unsigned short x)
|
||||
{
|
||||
return OSSwapBigToHostInt16(x);
|
||||
}
|
||||
|
||||
inline unsigned int BigLong(unsigned int x)
|
||||
{
|
||||
return OSSwapBigToHostInt32(x);
|
||||
}
|
||||
|
||||
|
||||
#elif defined __BIG_ENDIAN__
|
||||
|
||||
// Swap 16bit, that is, MSB and LSB byte.
|
||||
// No masking with 0xFF should be necessary.
|
||||
inline unsigned short LittleShort (unsigned short x)
|
||||
{
|
||||
return (unsigned short)((x>>8) | (x<<8));
|
||||
}
|
||||
|
||||
inline unsigned int LittleLong (unsigned int x)
|
||||
{
|
||||
return (unsigned int)(
|
||||
(x>>24)
|
||||
| ((x>>8) & 0xff00)
|
||||
| ((x<<8) & 0xff0000)
|
||||
| (x<<24));
|
||||
}
|
||||
|
||||
inline unsigned short BigShort(unsigned short x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
inline unsigned int BigLong(unsigned int x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline unsigned short LittleShort(unsigned short x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
inline unsigned int LittleLong(unsigned int x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
inline unsigned short BigShort(unsigned short x)
|
||||
{
|
||||
return _byteswap_ushort(x);
|
||||
}
|
||||
|
||||
inline unsigned int BigLong(unsigned int x)
|
||||
{
|
||||
return (unsigned int)_byteswap_ulong((unsigned long)x);
|
||||
}
|
||||
|
||||
#pragma warning (default: 4035)
|
||||
|
||||
#else
|
||||
|
||||
inline unsigned short BigShort (unsigned short x)
|
||||
{
|
||||
return (unsigned short)((x>>8) | (x<<8));
|
||||
}
|
||||
|
||||
inline unsigned int BigLong (unsigned int x)
|
||||
{
|
||||
return (unsigned int)(
|
||||
(x>>24)
|
||||
| ((x>>8) & 0xff00)
|
||||
| ((x<<8) & 0xff0000)
|
||||
| (x<<24));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // __BIG_ENDIAN__
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __M_SWAP_H__
|
||||
253
src/common/filesystem/include/resourcefile.h
Normal file
253
src/common/filesystem/include/resourcefile.h
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
|
||||
|
||||
#ifndef __RESFILE_H
|
||||
#define __RESFILE_H
|
||||
|
||||
#include <limits.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "fs_files.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
class StringPool;
|
||||
std::string ExtractBaseName(const char* path, bool include_extension = false);
|
||||
void strReplace(std::string& str, const char* from, const char* to);
|
||||
|
||||
// user context in which the file system gets opened. This also contains a few callbacks to avoid direct dependencies on the engine.
|
||||
struct LumpFilterInfo
|
||||
{
|
||||
std::vector<std::string> gameTypeFilter; // this can contain multiple entries
|
||||
std::string dotFilter;
|
||||
|
||||
// The following are for checking if the root directory of a zip can be removed.
|
||||
std::vector<std::string> reservedFolders;
|
||||
std::vector<std::string> requiredPrefixes;
|
||||
std::vector<std::string> embeddings;
|
||||
std::vector<std::string> blockednames; // File names that will never be accepted (e.g. dehacked.exe for Doom)
|
||||
std::function<bool(const char*, const char*)> filenamecheck; // for scanning directories, this allows to eliminate unwanted content.
|
||||
std::function<void()> postprocessFunc;
|
||||
};
|
||||
|
||||
enum class FSMessageLevel
|
||||
{
|
||||
Error = 1,
|
||||
Warning = 2,
|
||||
Attention = 3,
|
||||
Message = 4,
|
||||
DebugWarn = 5,
|
||||
DebugNotify = 6,
|
||||
};
|
||||
|
||||
// pass the text output function as parameter to avoid a hard dependency on higher level code.
|
||||
using FileSystemMessageFunc = int(*)(FSMessageLevel msglevel, const char* format, ...);
|
||||
|
||||
|
||||
class FResourceFile;
|
||||
|
||||
// [RH] Namespaces from BOOM.
|
||||
// These are needed here in the low level part so that WAD files can be properly set up.
|
||||
typedef enum {
|
||||
ns_hidden = -1,
|
||||
|
||||
ns_global = 0,
|
||||
ns_sprites,
|
||||
ns_flats,
|
||||
ns_colormaps,
|
||||
ns_acslibrary,
|
||||
ns_newtextures,
|
||||
ns_bloodraw, // no longer used - kept for ZScript.
|
||||
ns_bloodsfx, // no longer used - kept for ZScript.
|
||||
ns_bloodmisc, // no longer used - kept for ZScript.
|
||||
ns_strifevoices,
|
||||
ns_hires,
|
||||
ns_voxels,
|
||||
|
||||
// These namespaces are only used to mark lumps in special subdirectories
|
||||
// so that their contents doesn't interfere with the global namespace.
|
||||
// searching for data in these namespaces works differently for lumps coming
|
||||
// from Zips or other files.
|
||||
ns_specialzipdirectory,
|
||||
ns_sounds,
|
||||
ns_patches,
|
||||
ns_graphics,
|
||||
ns_music,
|
||||
|
||||
ns_firstskin,
|
||||
} namespace_t;
|
||||
|
||||
enum ELumpFlags
|
||||
{
|
||||
LUMPF_MAYBEFLAT = 1, // might be a flat outside F_START/END
|
||||
LUMPF_FULLPATH = 2, // contains a full path. This will trigger extended namespace checks when looking up short names.
|
||||
LUMPF_EMBEDDED = 4, // marks an embedded resource file for later processing.
|
||||
LUMPF_SHORTNAME = 8, // the stored name is a short extension-less name
|
||||
LUMPF_COMPRESSED = 16, // compressed or encrypted, i.e. cannot be read with the container file's reader.
|
||||
};
|
||||
|
||||
// This holds a compresed Zip entry with all needed info to decompress it.
|
||||
struct FCompressedBuffer
|
||||
{
|
||||
unsigned mSize;
|
||||
unsigned mCompressedSize;
|
||||
int mMethod;
|
||||
int mZipFlags;
|
||||
unsigned mCRC32;
|
||||
char *mBuffer;
|
||||
const char* filename;
|
||||
|
||||
bool Decompress(char *destbuffer);
|
||||
void Clean()
|
||||
{
|
||||
mSize = mCompressedSize = 0;
|
||||
if (mBuffer != nullptr)
|
||||
{
|
||||
delete[] mBuffer;
|
||||
mBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct FResourceLump
|
||||
{
|
||||
friend class FResourceFile;
|
||||
friend class FWadFile; // this still needs direct access.
|
||||
|
||||
int LumpSize;
|
||||
int RefCount;
|
||||
protected:
|
||||
const char* FullName;
|
||||
public:
|
||||
uint8_t Flags;
|
||||
char * Cache;
|
||||
FResourceFile * Owner;
|
||||
|
||||
FResourceLump()
|
||||
{
|
||||
Cache = NULL;
|
||||
Owner = NULL;
|
||||
Flags = 0;
|
||||
RefCount = 0;
|
||||
FullName = "";
|
||||
}
|
||||
|
||||
virtual ~FResourceLump();
|
||||
virtual FileReader *GetReader();
|
||||
virtual FileReader NewReader();
|
||||
virtual int GetFileOffset() { return -1; }
|
||||
virtual int GetIndexNum() const { return -1; }
|
||||
virtual int GetNamespace() const { return 0; }
|
||||
void LumpNameSetup(const char* iname, StringPool* allocator);
|
||||
void CheckEmbedded(LumpFilterInfo* lfi);
|
||||
virtual FCompressedBuffer GetRawData();
|
||||
|
||||
void *Lock(); // validates the cache and increases the refcount.
|
||||
int Unlock(); // decreases the refcount and frees the buffer
|
||||
|
||||
unsigned Size() const{ return LumpSize; }
|
||||
int LockCount() const { return RefCount; }
|
||||
const char* getName() { return FullName; }
|
||||
void clearName() { FullName = ""; }
|
||||
|
||||
protected:
|
||||
virtual int FillCache() { return -1; }
|
||||
|
||||
};
|
||||
|
||||
class FResourceFile
|
||||
{
|
||||
public:
|
||||
FileReader Reader;
|
||||
const char* FileName;
|
||||
protected:
|
||||
uint32_t NumLumps;
|
||||
char Hash[48];
|
||||
StringPool* stringpool;
|
||||
|
||||
FResourceFile(const char *filename, StringPool* sp);
|
||||
FResourceFile(const char *filename, FileReader &r, StringPool* sp);
|
||||
|
||||
// for archives that can contain directories
|
||||
void GenerateHash();
|
||||
void PostProcessArchive(void *lumps, size_t lumpsize, LumpFilterInfo *filter);
|
||||
|
||||
private:
|
||||
uint32_t FirstLump;
|
||||
|
||||
int FilterLumps(const std::string& filtername, void *lumps, size_t lumpsize, uint32_t max);
|
||||
int FilterLumpsByGameType(LumpFilterInfo *filter, void *lumps, size_t lumpsize, uint32_t max);
|
||||
bool FindPrefixRange(const char* filter, void *lumps, size_t lumpsize, uint32_t max, uint32_t &start, uint32_t &end);
|
||||
void JunkLeftoverFilters(void *lumps, size_t lumpsize, uint32_t max);
|
||||
static FResourceFile *DoOpenResourceFile(const char *filename, FileReader &file, bool containeronly, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
|
||||
|
||||
public:
|
||||
static FResourceFile *OpenResourceFile(const char *filename, FileReader &file, bool containeronly = false, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, StringPool* sp = nullptr);
|
||||
static FResourceFile *OpenResourceFile(const char *filename, bool containeronly = false, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, StringPool* sp = nullptr);
|
||||
static FResourceFile *OpenDirectory(const char *filename, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, StringPool* sp = nullptr);
|
||||
virtual ~FResourceFile();
|
||||
// If this FResourceFile represents a directory, the Reader object is not usable so don't return it.
|
||||
FileReader *GetReader() { return Reader.isOpen()? &Reader : nullptr; }
|
||||
uint32_t LumpCount() const { return NumLumps; }
|
||||
uint32_t GetFirstEntry() const { return FirstLump; }
|
||||
void SetFirstLump(uint32_t f) { FirstLump = f; }
|
||||
const char* GetHash() const { return Hash; }
|
||||
|
||||
|
||||
virtual FResourceLump *GetLump(int no) = 0;
|
||||
FResourceLump *FindLump(const char *name);
|
||||
};
|
||||
|
||||
struct FUncompressedLump : public FResourceLump
|
||||
{
|
||||
int Position;
|
||||
|
||||
virtual FileReader *GetReader();
|
||||
virtual int FillCache() override;
|
||||
virtual int GetFileOffset() { return Position; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Base class for uncompressed resource files (WAD, GRP, PAK and single lumps)
|
||||
class FUncompressedFile : public FResourceFile
|
||||
{
|
||||
protected:
|
||||
TArray<FUncompressedLump> Lumps;
|
||||
|
||||
FUncompressedFile(const char *filename, StringPool* sp);
|
||||
FUncompressedFile(const char *filename, FileReader &r, StringPool* sp);
|
||||
virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; }
|
||||
};
|
||||
|
||||
|
||||
// should only be used internally.
|
||||
struct FExternalLump : public FResourceLump
|
||||
{
|
||||
const char* FileName;
|
||||
|
||||
FExternalLump(const char *_filename, int filesize, StringPool* sp);
|
||||
virtual int FillCache() override;
|
||||
|
||||
};
|
||||
|
||||
struct FMemoryLump : public FResourceLump
|
||||
{
|
||||
FMemoryLump(const void* data, int length)
|
||||
{
|
||||
RefCount = INT_MAX / 2;
|
||||
LumpSize = length;
|
||||
Cache = new char[length];
|
||||
memcpy(Cache, data, length);
|
||||
}
|
||||
|
||||
virtual int FillCache() override
|
||||
{
|
||||
RefCount = INT_MAX / 2; // Make sure it never counts down to 0 by resetting it to something high each time it is used.
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue