mirror of
https://github.com/celisej567/mcpe.git
synced 2025-12-31 17:49:17 +03:00
* Finish level saving.
This commit is contained in:
@@ -103,11 +103,23 @@ void AppPlatform_windows::createUserInput()
|
||||
{
|
||||
m_UserInput.clear();
|
||||
m_UserInputStatus = -1;
|
||||
|
||||
switch (m_DialogType)
|
||||
{
|
||||
case DLG_CREATE_WORLD:
|
||||
{
|
||||
// some placeholder for now
|
||||
m_UserInput.push_back("New World");
|
||||
m_UserInput.push_back("123456");
|
||||
m_UserInputStatus = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppPlatform_windows::showDialog(eDialogType type)
|
||||
{
|
||||
// TODO
|
||||
m_DialogType = type;
|
||||
}
|
||||
|
||||
std::string AppPlatform_windows::getDateString(int time)
|
||||
|
||||
@@ -57,6 +57,8 @@ private:
|
||||
std::vector<std::string> m_UserInput;
|
||||
int m_UserInputStatus = -1;
|
||||
|
||||
eDialogType m_DialogType;
|
||||
|
||||
bool m_bIsFocused = false;
|
||||
bool m_bGrabbedMouse = false;
|
||||
bool m_bActuallyGrabbedMouse = false;
|
||||
|
||||
@@ -92,6 +92,7 @@ void SoundSystemWindows::stop(const std::string& sound)
|
||||
|
||||
void SoundSystemWindows::playAt(const SoundDesc& sound, float x, float y, float z, float volume, float pitch)
|
||||
{
|
||||
return;
|
||||
|
||||
//Release sounds that finished playing
|
||||
for (size_t i = 0; i < m_buffers.size(); i++)
|
||||
|
||||
@@ -8,9 +8,14 @@
|
||||
|
||||
#include "NinecraftApp.hpp"
|
||||
#include "StartMenuScreen.hpp"
|
||||
#include "MemoryLevelStorageSource.hpp"
|
||||
#include "Item.hpp"
|
||||
|
||||
#ifdef DEMO
|
||||
#include "MemoryLevelStorageSource.hpp"
|
||||
#else
|
||||
#include "ExternalFileLevelStorageSource.hpp"
|
||||
#endif
|
||||
|
||||
bool NinecraftApp::_hasInitedStatics;
|
||||
|
||||
bool NinecraftApp::handleBack(bool b)
|
||||
@@ -66,7 +71,13 @@ void NinecraftApp::init()
|
||||
initGLStates();
|
||||
Tesselator::instance.init();
|
||||
Minecraft::init();
|
||||
|
||||
#ifdef DEMO
|
||||
m_pLevelStorageSource = new MemoryLevelStorageSource;
|
||||
#else
|
||||
m_pLevelStorageSource = new ExternalFileLevelStorageSource(m_externalStorageDir);
|
||||
#endif
|
||||
|
||||
field_D9C = 0;
|
||||
|
||||
setScreen(new StartMenuScreen);
|
||||
|
||||
@@ -16,10 +16,6 @@
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
|
||||
// XPL means "Cross PLatform"
|
||||
#define XPL_ACCESS _access
|
||||
#define XPL_MKDIR(path, mode) _mkdir(path)
|
||||
|
||||
// Why are we not using GetTickCount64()? It's simple -- getTimeMs has the exact same problem as using regular old GetTickCount.
|
||||
#pragma warning(disable : 28159)
|
||||
|
||||
@@ -37,6 +33,70 @@
|
||||
|
||||
int g_TimeSecondsOnInit = 0;
|
||||
|
||||
DIR* opendir(const char* name)
|
||||
{
|
||||
size_t len = strlen(name);
|
||||
if (len == 0)
|
||||
return NULL;
|
||||
|
||||
char buf[1024];
|
||||
if (len >= 1024 - 5)
|
||||
return NULL;
|
||||
|
||||
strcpy(buf, name);
|
||||
|
||||
if (name[len - 1] != '/')
|
||||
strcpy(&buf[len], "/*");
|
||||
else
|
||||
strcpy(&buf[len], "*");
|
||||
|
||||
DIR* pDir = (DIR*)malloc(sizeof(DIR));
|
||||
if (!pDir)
|
||||
return pDir;
|
||||
|
||||
memset(pDir, 0, sizeof * pDir);
|
||||
|
||||
pDir->current = FindFirstFile(buf, &pDir->findData);
|
||||
if (pDir->current == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
free(pDir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pDir;
|
||||
}
|
||||
|
||||
dirent* readdir(DIR* dir)
|
||||
{
|
||||
if (dir->current == INVALID_HANDLE_VALUE)
|
||||
return NULL;
|
||||
|
||||
static dirent de;
|
||||
|
||||
if (!dir->returnedFirstFileData)
|
||||
{
|
||||
dir->returnedFirstFileData = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!FindNextFile(dir->current, &dir->findData))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(de.d_name, dir->findData.cFileName);
|
||||
de.d_type = (dir->findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? DT_DIR : DT_REG;
|
||||
|
||||
return &de;
|
||||
}
|
||||
|
||||
void closedir(DIR* dir)
|
||||
{
|
||||
if (dir->current != INVALID_HANDLE_VALUE)
|
||||
FindClose(dir->current);
|
||||
|
||||
free(dir);
|
||||
}
|
||||
|
||||
bool createFolderIfNotExists(const char* pDir)
|
||||
{
|
||||
if (!XPL_ACCESS(pDir, 0))
|
||||
@@ -45,6 +105,31 @@ bool createFolderIfNotExists(const char* pDir)
|
||||
return XPL_MKDIR(pDir, 0755) == 0;
|
||||
}
|
||||
|
||||
bool DeleteDirectory(const std::string& name, bool unused)
|
||||
{
|
||||
DIR* dir = opendir(name.c_str());
|
||||
if (!dir)
|
||||
return false;
|
||||
|
||||
char buffer[1024];
|
||||
|
||||
while (true)
|
||||
{
|
||||
dirent* de = readdir(dir);
|
||||
if (!de)
|
||||
break;
|
||||
|
||||
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
|
||||
continue;
|
||||
|
||||
snprintf(buffer, sizeof buffer, "%s/%s", name.c_str(), de->d_name);
|
||||
remove(buffer);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
return remove(name.c_str()) == 0;
|
||||
}
|
||||
|
||||
const char* GetTerrainName()
|
||||
{
|
||||
return "terrain.png";
|
||||
|
||||
@@ -15,16 +15,51 @@
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// @HACK: Include WinSock2.h also
|
||||
#include <WinSock2.h>
|
||||
#include <Windows.h>
|
||||
#include <WS2tcpip.h>
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
|
||||
// XPL means "Cross PLatform"
|
||||
#define XPL_ACCESS _access
|
||||
#define XPL_MKDIR(path, mode) _mkdir(path)
|
||||
|
||||
// Bare bones non conforming implementation, but good enough
|
||||
struct dirent
|
||||
{
|
||||
int d_type;
|
||||
char d_name[_MAX_PATH + 1];
|
||||
};
|
||||
|
||||
struct DIR
|
||||
{
|
||||
HANDLE current;
|
||||
WIN32_FIND_DATA findData;
|
||||
bool returnedFirstFileData;
|
||||
};
|
||||
|
||||
#define DT_UNKNOWN (0)
|
||||
#define DT_DIR (4)
|
||||
#define DT_REG (8)
|
||||
|
||||
DIR* opendir(const char* name);
|
||||
dirent* readdir(DIR* dir);
|
||||
void closedir(DIR* dir);
|
||||
|
||||
#else
|
||||
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
|
||||
// XPL means "Cross PLatform"
|
||||
#define XPL_ACCESS access
|
||||
#define XPL_MKDIR(path, mode) mkdir(path, mode)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -505,6 +540,7 @@ constexpr float Lerp(float a, float b, float progress)
|
||||
}
|
||||
|
||||
bool createFolderIfNotExists(const char* pDir);
|
||||
bool DeleteDirectory(const std::string& name, bool unused);
|
||||
|
||||
// things that we added:
|
||||
#ifndef ORIGINAL_CODE
|
||||
|
||||
@@ -126,7 +126,10 @@ void SelectWorldScreen::tick()
|
||||
m_pMinecraft->hostMultiplayer();
|
||||
m_pMinecraft->setScreen(new ProgressScreen);
|
||||
|
||||
// @BUG: Use of deallocated memory. SetScreen frees us
|
||||
#ifdef ORIGINAL_CODE
|
||||
field_130 = 0;
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -48,16 +48,8 @@ void StartMenuScreen::buttonClicked(Button* pButton)
|
||||
{
|
||||
if (pButton->field_30 == m_startButton.field_30)
|
||||
{
|
||||
#if defined(DEMO) || !defined(ORIGINAL_CODE)
|
||||
|
||||
# ifdef DEMO
|
||||
# define DEMO_SEED int(getEpochTimeS())
|
||||
# else
|
||||
// 1942892620 = long(12345678901324)
|
||||
# define DEMO_SEED 123456
|
||||
# endif
|
||||
|
||||
m_pMinecraft->selectLevel("_DemoLevel", "_DemoLevel", DEMO_SEED);
|
||||
#if defined(DEMO)
|
||||
m_pMinecraft->selectLevel("_DemoLevel", "_DemoLevel", int(getEpochTimeS()));
|
||||
m_pMinecraft->hostMultiplayer();
|
||||
m_pMinecraft->setScreen(new ProgressScreen);
|
||||
#else
|
||||
|
||||
@@ -45,6 +45,7 @@ void Level::_init(const std::string& str, TLong seed, int x, Dimension* pDimens
|
||||
|
||||
field_B0C = pData == 0;
|
||||
|
||||
// @BUG: leaking a Dimension*?
|
||||
if (pDimension)
|
||||
m_pDimension = pDimension;
|
||||
else
|
||||
|
||||
@@ -55,5 +55,10 @@ struct LevelData
|
||||
{
|
||||
return field_20;
|
||||
}
|
||||
|
||||
void setLevelName(const std::string& name)
|
||||
{
|
||||
field_78 = name;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ RegionFile::RegionFile(const std::string fileName)
|
||||
|
||||
field_20 = new int[1024];
|
||||
field_24 = new int[1024];
|
||||
memset(field_20, 0, 1024 * sizeof(int));
|
||||
memset(field_24, 0, 1024 * sizeof(int));
|
||||
}
|
||||
|
||||
RegionFile::~RegionFile()
|
||||
@@ -48,11 +48,14 @@ bool RegionFile::open()
|
||||
|
||||
for (int i = 0; i < 1024; i++)
|
||||
{
|
||||
if (field_20[i])
|
||||
int v13 = this->field_20[i];
|
||||
if (v13)
|
||||
{
|
||||
for (int j = 0; j < uint8_t(field_20[i]); j++)
|
||||
int v12 = v13 >> 8;
|
||||
int v11 = uint8_t(v13);
|
||||
for (int j = 0; j < v11; ++j)
|
||||
{
|
||||
field_28[j + (field_20[i] >> 8)] = false;
|
||||
field_28[j + v12] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,6 +69,8 @@ bool RegionFile::open()
|
||||
|
||||
WRITE(field_20, sizeof(int), 1024, m_pFile);
|
||||
field_28[0] = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RegionFile::readChunk(int x, int z, RakNet::BitStream** pBitStream)
|
||||
@@ -74,8 +79,11 @@ bool RegionFile::readChunk(int x, int z, RakNet::BitStream** pBitStream)
|
||||
if (!idx)
|
||||
return false;
|
||||
|
||||
int thing = (idx >> 8);
|
||||
int offset = (idx & 0xFF);
|
||||
|
||||
int length = 0;
|
||||
fseek(m_pFile, (idx >> 8) * SECTOR_BYTES, SEEK_SET);
|
||||
fseek(m_pFile, thing * SECTOR_BYTES, SEEK_SET);
|
||||
fread(&length, sizeof(int), 1, m_pFile);
|
||||
|
||||
assert(length < ((offset & 0xff) * SECTOR_BYTES));
|
||||
@@ -104,7 +112,7 @@ bool RegionFile::writeChunk(int x, int z, RakNet::BitStream& bitStream)
|
||||
{
|
||||
int length = bitStream.GetNumberOfBytesUsed();
|
||||
int field20i = field_20[32 * z + x];
|
||||
int lowerIndex = (length + 4) / SECTOR_BYTES;
|
||||
int lowerIndex = (length + 4) / SECTOR_BYTES + 1;
|
||||
if (lowerIndex > 256)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
/********************************************************************
|
||||
Minecraft: Pocket Edition - Decompilation Project
|
||||
Copyright (C) 2023 iProgramInCpp
|
||||
|
||||
The following code is licensed under the BSD 1 clause license.
|
||||
SPDX-License-Identifier: BSD-1-Clause
|
||||
********************************************************************/
|
||||
|
||||
#include "ExternalFileLevelStorage.hpp"
|
||||
#include "Level.hpp"
|
||||
#include "GetTime.h"
|
||||
@@ -237,7 +245,7 @@ bool ExternalFileLevelStorage::readLevelData(const std::string& path, LevelData*
|
||||
|
||||
if (fread(data, sizeof(uint8_t), length, pFile) != length)
|
||||
{
|
||||
SAFE_DELETE(data);
|
||||
SAFE_DELETE_ARRAY(data);
|
||||
goto _cleanup;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
/********************************************************************
|
||||
Minecraft: Pocket Edition - Decompilation Project
|
||||
Copyright (C) 2023 iProgramInCpp
|
||||
|
||||
The following code is licensed under the BSD 1 clause license.
|
||||
SPDX-License-Identifier: BSD-1-Clause
|
||||
********************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
|
||||
164
source/World/Storage/ExternalFileLevelStorageSource.cpp
Normal file
164
source/World/Storage/ExternalFileLevelStorageSource.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
/********************************************************************
|
||||
Minecraft: Pocket Edition - Decompilation Project
|
||||
Copyright (C) 2023 iProgramInCpp
|
||||
|
||||
The following code is licensed under the BSD 1 clause license.
|
||||
SPDX-License-Identifier: BSD-1-Clause
|
||||
********************************************************************/
|
||||
|
||||
#include "ExternalFileLevelStorageSource.hpp"
|
||||
#include "ExternalFileLevelStorage.hpp"
|
||||
#include "Util.hpp"
|
||||
|
||||
ExternalFileLevelStorageSource::ExternalFileLevelStorageSource(const std::string& path)
|
||||
{
|
||||
m_worldsPath = path;
|
||||
|
||||
m_worldsPath += "/games";
|
||||
if (createFolderIfNotExists(m_worldsPath.c_str()))
|
||||
{
|
||||
m_worldsPath += "/com.mojang";
|
||||
if (createFolderIfNotExists(m_worldsPath.c_str()))
|
||||
{
|
||||
m_worldsPath += "/minecraftWorlds";
|
||||
if (createFolderIfNotExists(m_worldsPath.c_str()))
|
||||
{
|
||||
std::vector<LevelSummary> vls;
|
||||
getLevelList(vls);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_worldsPath = path + "/games" + "/com.mojang" + "/minecraftWorlds";
|
||||
}
|
||||
|
||||
std::string ExternalFileLevelStorageSource::getName()
|
||||
{
|
||||
return "External File Level Storage";
|
||||
}
|
||||
|
||||
LevelStorage* ExternalFileLevelStorageSource::selectLevel(const std::string& name, bool b)
|
||||
{
|
||||
return new ExternalFileLevelStorage(name, m_worldsPath + "/" + name);
|
||||
}
|
||||
|
||||
void ExternalFileLevelStorageSource::getLevelList(std::vector<LevelSummary>& vls)
|
||||
{
|
||||
DIR* dir = opendir(m_worldsPath.c_str());
|
||||
if (!dir)
|
||||
return;
|
||||
|
||||
while (true)
|
||||
{
|
||||
dirent* de = readdir(dir);
|
||||
if (!de)
|
||||
break;
|
||||
|
||||
LogMsg("Entry: %s", de->d_name);
|
||||
|
||||
if (de->d_type == DT_DIR)
|
||||
{
|
||||
addLevelSummaryIfExists(vls, de->d_name);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
void ExternalFileLevelStorageSource::clearAll()
|
||||
{
|
||||
}
|
||||
|
||||
int ExternalFileLevelStorageSource::getDataTagFor(const std::string& str)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ExternalFileLevelStorageSource::isNewLevelIdAcceptable(const std::string& levelID)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static char g_EFLSSFilterArray[] = { '/','\n','\r','\x09','\0','\xC','`','?','*','\\','<','>','|','"',':' };
|
||||
|
||||
void ExternalFileLevelStorageSource::deleteLevel(const std::string& levelName)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << m_worldsPath << "/" << levelName;
|
||||
std::string path = ss.str();
|
||||
|
||||
if (DeleteDirectory(path, true))
|
||||
return;
|
||||
|
||||
remove((path + "/chunks.dat").c_str());
|
||||
remove((path + "/player.dat").c_str());
|
||||
remove((path + "/level.dat").c_str());
|
||||
}
|
||||
|
||||
void ExternalFileLevelStorageSource::renameLevel(const std::string& oldName, const std::string& newName)
|
||||
{
|
||||
int accessResult = XPL_ACCESS((m_worldsPath + "/" + oldName).c_str(), 0);
|
||||
if (accessResult)
|
||||
return;
|
||||
|
||||
std::string levelName = Util::stringTrim(newName);
|
||||
for (int i = 0; i < sizeof(g_EFLSSFilterArray); i++)
|
||||
{
|
||||
std::string str;
|
||||
str.push_back(g_EFLSSFilterArray[i]);
|
||||
Util::stringReplace(levelName, str, "");
|
||||
}
|
||||
|
||||
std::vector<LevelSummary> vls;
|
||||
getLevelList(vls);
|
||||
|
||||
std::set<std::string> maps;
|
||||
|
||||
for (const auto& ls : vls)
|
||||
maps.insert(ls.field_0);
|
||||
|
||||
std::string levelUniqueName = levelName;
|
||||
while (maps.find(levelUniqueName) != maps.end())
|
||||
levelUniqueName += "-";
|
||||
|
||||
int renameResult = rename((m_worldsPath + "/" + oldName).c_str(), (m_worldsPath + "/" + levelUniqueName).c_str());
|
||||
if (renameResult != 0)
|
||||
levelUniqueName = oldName;
|
||||
|
||||
LevelData ld;
|
||||
ExternalFileLevelStorage::readLevelData(m_worldsPath + "/" + levelUniqueName + "/" + "level.dat", &ld);
|
||||
ld.setLevelName(levelName);
|
||||
ExternalFileLevelStorage::writeLevelData(m_worldsPath + "/" + levelUniqueName + "/" + "level.dat", &ld);
|
||||
}
|
||||
|
||||
bool ExternalFileLevelStorageSource::isConvertible(const std::string&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ExternalFileLevelStorageSource::requiresConversion(const std::string&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int ExternalFileLevelStorageSource::convertLevel(const std::string&, ProgressListener*)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ExternalFileLevelStorageSource::addLevelSummaryIfExists(std::vector<LevelSummary>& vls, const char* name)
|
||||
{
|
||||
std::string levelDat = m_worldsPath + "/" + name + "/" + "level.dat";
|
||||
|
||||
LevelData ld;
|
||||
|
||||
if (!ExternalFileLevelStorage::readLevelData(levelDat, &ld))
|
||||
return;
|
||||
|
||||
LevelSummary ls;
|
||||
ls.field_0 = name;
|
||||
ls.field_18 = ld.field_78;
|
||||
ls.field_30 = ld.field_14;
|
||||
ls.field_34 = ld.field_18;
|
||||
vls.push_back(ls);
|
||||
}
|
||||
40
source/World/Storage/ExternalFileLevelStorageSource.hpp
Normal file
40
source/World/Storage/ExternalFileLevelStorageSource.hpp
Normal file
@@ -0,0 +1,40 @@
|
||||
/********************************************************************
|
||||
Minecraft: Pocket Edition - Decompilation Project
|
||||
Copyright (C) 2023 iProgramInCpp
|
||||
|
||||
The following code is licensed under the BSD 1 clause license.
|
||||
SPDX-License-Identifier: BSD-1-Clause
|
||||
********************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include "LevelStorageSource.hpp"
|
||||
|
||||
#ifndef DEMO
|
||||
|
||||
class ExternalFileLevelStorageSource : public LevelStorageSource
|
||||
{
|
||||
public:
|
||||
ExternalFileLevelStorageSource(const std::string& path);
|
||||
|
||||
std::string getName() override;
|
||||
LevelStorage* selectLevel(const std::string&, bool) override;
|
||||
void getLevelList(std::vector<LevelSummary>&);
|
||||
void clearAll() override;
|
||||
int getDataTagFor(const std::string&) override;
|
||||
bool isNewLevelIdAcceptable(const std::string&) override;
|
||||
void deleteLevel(const std::string&) override;
|
||||
void renameLevel(const std::string&, const std::string&) override;
|
||||
bool isConvertible(const std::string&) override;
|
||||
bool requiresConversion(const std::string&) override;
|
||||
int convertLevel(const std::string&, ProgressListener*) override;
|
||||
|
||||
void addLevelSummaryIfExists(std::vector<LevelSummary>& vls, const char* name);
|
||||
|
||||
public:
|
||||
std::string m_worldsPath;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -14,6 +14,8 @@ LevelStorage::~LevelStorage()
|
||||
|
||||
void LevelStorage::saveLevelData(LevelData* levelData)
|
||||
{
|
||||
std::vector<Player*> nothing;
|
||||
saveLevelData(levelData, nothing);
|
||||
}
|
||||
|
||||
void LevelStorage::savePlayerData(LevelData* levelData, std::vector<Player*>& players)
|
||||
|
||||
@@ -48,6 +48,6 @@ public:
|
||||
virtual void renameLevel(const std::string&, const std::string&) = 0;
|
||||
virtual bool isConvertible(const std::string&) = 0;
|
||||
virtual bool requiresConversion(const std::string&) = 0;
|
||||
virtual void convertLevel(const std::string&, ProgressListener*) = 0;
|
||||
virtual int convertLevel(const std::string&, ProgressListener*) = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "MemoryLevelStorage.hpp"
|
||||
#include "MemoryLevelStorageSource.hpp"
|
||||
|
||||
#ifdef DEMO
|
||||
|
||||
std::string MemoryLevelStorageSource::getName()
|
||||
{
|
||||
return "Memory Storage";
|
||||
@@ -52,7 +54,9 @@ bool MemoryLevelStorageSource::requiresConversion(const std::string& x)
|
||||
return false;
|
||||
}
|
||||
|
||||
void MemoryLevelStorageSource::convertLevel(const std::string& x, ProgressListener* y)
|
||||
int MemoryLevelStorageSource::convertLevel(const std::string& x, ProgressListener* y)
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "LevelStorageSource.hpp"
|
||||
|
||||
#ifdef DEMO
|
||||
class MemoryLevelStorageSource : public LevelStorageSource
|
||||
{
|
||||
std::string getName() override;
|
||||
@@ -21,6 +22,6 @@ class MemoryLevelStorageSource : public LevelStorageSource
|
||||
void renameLevel(const std::string&, const std::string&) override;
|
||||
bool isConvertible(const std::string&) override;
|
||||
bool requiresConversion(const std::string&) override;
|
||||
void convertLevel(const std::string&, ProgressListener*) override;
|
||||
int convertLevel(const std::string&, ProgressListener*) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
585
thirdparty/direntm.h
vendored
Normal file
585
thirdparty/direntm.h
vendored
Normal file
@@ -0,0 +1,585 @@
|
||||
/*
|
||||
MIT License
|
||||
Copyright (c) 2019 win32ports
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __DIRENT_H_9DE6B42C_8D0C_4D31_A8EF_8E4C30E6C46A__
|
||||
#define __DIRENT_H_9DE6B42C_8D0C_4D31_A8EF_8E4C30E6C46A__
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
//#pragma message("this dirent.h implementation is for Windows only!") -- it's going to just use the regular dirent
|
||||
#include <dirent.h>
|
||||
|
||||
#else /* _WIN32 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <Shlwapi.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "Shlwapi.lib")
|
||||
#endif
|
||||
|
||||
#ifndef NAME_MAX
|
||||
#define NAME_MAX 260
|
||||
#endif /* NAME_MAX */
|
||||
|
||||
#ifndef DT_UNKNOWN
|
||||
#define DT_UNKNOWN 0
|
||||
#endif /* DT_UNKNOWN */
|
||||
|
||||
#ifndef DT_FIFO
|
||||
#define DT_FIFO 1
|
||||
#endif /* DT_FIFO */
|
||||
|
||||
#ifndef DT_CHR
|
||||
#define DT_CHR 2
|
||||
#endif /* DT_CHR */
|
||||
|
||||
#ifndef DT_DIR
|
||||
#define DT_DIR 4
|
||||
#endif /* DT_DIR */
|
||||
|
||||
#ifndef DT_BLK
|
||||
#define DT_BLK 6
|
||||
#endif /* DT_BLK */
|
||||
|
||||
#ifndef DT_REG
|
||||
#define DT_REG 8
|
||||
#endif /* DT_REF */
|
||||
|
||||
#ifndef DT_LNK
|
||||
#define DT_LNK 10
|
||||
#endif /* DT_LNK */
|
||||
|
||||
#ifndef DT_SOCK
|
||||
#define DT_SOCK 12
|
||||
#endif /* DT_SOCK */
|
||||
|
||||
#ifndef DT_WHT
|
||||
#define DT_WHT 14
|
||||
#endif /* DT_WHT */
|
||||
|
||||
#ifndef _DIRENT_HAVE_D_NAMLEN
|
||||
#define _DIRENT_HAVE_D_NAMLEN 1
|
||||
#endif /* _DIRENT_HAVE_D_NAMLEN */
|
||||
|
||||
#ifndef _DIRENT_HAVE_D_RECLEN
|
||||
#define _DIRENT_HAVE_D_RECLEN 1
|
||||
#endif /* _DIRENT_HAVE_D_RECLEN */
|
||||
|
||||
#ifndef _DIRENT_HAVE_D_OFF
|
||||
#define _DIRENT_HAVE_D_OFF 1
|
||||
#endif /* _DIRENT_HAVE_D_OFF */
|
||||
|
||||
#ifndef _DIRENT_HAVE_D_TYPE
|
||||
#define _DIRENT_HAVE_D_TYPE 1
|
||||
#endif /* _DIRENT_HAVE_D_TYPE */
|
||||
|
||||
#ifndef NTFS_MAX_PATH
|
||||
#define NTFS_MAX_PATH 32768
|
||||
#endif /* NTFS_MAX_PATH */
|
||||
|
||||
#ifndef FSCTL_GET_REPARSE_POINT
|
||||
#define FSCTL_GET_REPARSE_POINT 0x900a8
|
||||
#endif /* FSCTL_GET_REPARSE_POINT */
|
||||
|
||||
#ifndef FILE_NAME_NORMALIZED
|
||||
#define FILE_NAME_NORMALIZED 0
|
||||
#endif /* FILE_NAME_NORMALIZED */
|
||||
|
||||
typedef void* DIR;
|
||||
|
||||
typedef struct ino_t
|
||||
{
|
||||
unsigned long long serial;
|
||||
unsigned char fileid[16];
|
||||
} __ino_t;
|
||||
|
||||
struct dirent
|
||||
{
|
||||
__ino_t d_ino;
|
||||
off_t d_off;
|
||||
unsigned short d_reclen;
|
||||
unsigned char d_namelen;
|
||||
unsigned char d_type;
|
||||
char d_name[NAME_MAX];
|
||||
};
|
||||
|
||||
struct __dir
|
||||
{
|
||||
struct dirent* entries;
|
||||
intptr_t fd;
|
||||
long int count;
|
||||
long int index;
|
||||
};
|
||||
|
||||
static int closedir(DIR* dirp)
|
||||
{
|
||||
struct __dir* data = NULL;
|
||||
if (!dirp) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
data = (struct __dir*) dirp;
|
||||
CloseHandle((HANDLE)data->fd);
|
||||
free(data->entries);
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __seterrno(int value)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
_set_errno(value);
|
||||
#else /* _MSC_VER */
|
||||
errno = value;
|
||||
#endif /* _MSC_VER */
|
||||
}
|
||||
|
||||
static int __islink(const wchar_t * name, char * buffer)
|
||||
{
|
||||
DWORD io_result = 0;
|
||||
DWORD bytes_returned = 0;
|
||||
HANDLE hFile = CreateFileW(name, 0, 0, NULL, OPEN_EXISTING,
|
||||
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
io_result = DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0,
|
||||
buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytes_returned, NULL);
|
||||
|
||||
CloseHandle(hFile);
|
||||
|
||||
if (io_result == 0)
|
||||
return 0;
|
||||
|
||||
return ((REPARSE_GUID_DATA_BUFFER*)buffer)->ReparseTag == IO_REPARSE_TAG_SYMLINK;
|
||||
}
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct dirent_FILE_ID_128
|
||||
{
|
||||
BYTE Identifier[16];
|
||||
}
|
||||
dirent_FILE_ID_128;
|
||||
|
||||
typedef struct _dirent_FILE_ID_INFO
|
||||
{
|
||||
ULONGLONG VolumeSerialNumber;
|
||||
dirent_FILE_ID_128 FileId;
|
||||
}
|
||||
dirent_FILE_ID_INFO;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef enum dirent_FILE_INFO_BY_HANDLE_CLASS
|
||||
{ dirent_FileIdInfo = 18 }
|
||||
dirent_FILE_INFO_BY_HANDLE_CLASS;
|
||||
|
||||
static __ino_t __inode(const wchar_t* name)
|
||||
{
|
||||
__ino_t value = { 0 };
|
||||
BOOL result;
|
||||
dirent_FILE_ID_INFO fileid;
|
||||
BY_HANDLE_FILE_INFORMATION info;
|
||||
typedef BOOL (__stdcall* pfnGetFileInformationByHandleEx)(HANDLE hFile,
|
||||
dirent_FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
|
||||
LPVOID lpFileInformation, DWORD dwBufferSize);
|
||||
|
||||
HANDLE hKernel32 = GetModuleHandleW(L"kernel32.dll");
|
||||
if (!hKernel32)
|
||||
return value;
|
||||
|
||||
pfnGetFileInformationByHandleEx fnGetFileInformationByHandleEx = (pfnGetFileInformationByHandleEx) GetProcAddress(hKernel32, "GetFileInformationByHandleEx");
|
||||
if (!fnGetFileInformationByHandleEx)
|
||||
return value;
|
||||
|
||||
HANDLE hFile = CreateFileW(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return value;
|
||||
|
||||
result = fnGetFileInformationByHandleEx(hFile, dirent_FileIdInfo, &fileid, sizeof(fileid));
|
||||
if (result)
|
||||
{
|
||||
value.serial = fileid.VolumeSerialNumber;
|
||||
memcpy(value.fileid, fileid.FileId.Identifier, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = GetFileInformationByHandle(hFile, &info);
|
||||
if(result)
|
||||
{
|
||||
value.serial = info.dwVolumeSerialNumber;
|
||||
memcpy(value.fileid + 8, &info.nFileIndexHigh, 4);
|
||||
memcpy(value.fileid + 12, &info.nFileIndexLow, 4);
|
||||
}
|
||||
}
|
||||
CloseHandle(hFile);
|
||||
return value;
|
||||
}
|
||||
|
||||
static DIR* __internal_opendir(wchar_t* wname, int size)
|
||||
{
|
||||
struct __dir* data = NULL;
|
||||
struct dirent *tmp_entries = NULL;
|
||||
static char default_char = '?';
|
||||
static wchar_t* prefix = L"\\\\?\\";
|
||||
static wchar_t* suffix = L"\\*.*";
|
||||
static int extra_prefix = 4; /* use prefix "\\?\" to handle long file names */
|
||||
static int extra_suffix = 4; /* use suffix "\*.*" to find everything */
|
||||
WIN32_FIND_DATAW w32fd = { 0 };
|
||||
HANDLE hFindFile = INVALID_HANDLE_VALUE;
|
||||
static int grow_factor = 2;
|
||||
char* buffer = NULL;
|
||||
|
||||
BOOL relative = PathIsRelativeW(wname + extra_prefix);
|
||||
|
||||
memcpy(wname + size - 1, suffix, sizeof(wchar_t) * extra_suffix);
|
||||
wname[size + extra_suffix - 1] = 0;
|
||||
|
||||
if (relative) {
|
||||
wname += extra_prefix;
|
||||
size -= extra_prefix;
|
||||
}
|
||||
hFindFile = FindFirstFileW(wname, &w32fd);
|
||||
if (INVALID_HANDLE_VALUE == hFindFile)
|
||||
{
|
||||
__seterrno(ENOENT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = (struct __dir*) malloc(sizeof(struct __dir));
|
||||
if (!data)
|
||||
goto out_of_memory;
|
||||
wname[size - 1] = 0;
|
||||
data->fd = (intptr_t)CreateFileW(wname, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||
wname[size - 1] = L'\\';
|
||||
data->count = 16;
|
||||
data->index = 0;
|
||||
data->entries = (struct dirent*) malloc(sizeof(struct dirent) * data->count);
|
||||
if (!data->entries)
|
||||
goto out_of_memory;
|
||||
buffer = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
|
||||
if (!buffer)
|
||||
goto out_of_memory;
|
||||
do
|
||||
{
|
||||
WideCharToMultiByte(CP_UTF8, 0, w32fd.cFileName, -1, data->entries[data->index].d_name, NAME_MAX, &default_char, NULL);
|
||||
|
||||
memcpy(wname + size, w32fd.cFileName, sizeof(wchar_t) * NAME_MAX);
|
||||
|
||||
if (((w32fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT) && __islink(wname, buffer))
|
||||
data->entries[data->index].d_type = DT_LNK;
|
||||
else if ((w32fd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) == FILE_ATTRIBUTE_DEVICE)
|
||||
data->entries[data->index].d_type = DT_CHR;
|
||||
else if ((w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
|
||||
data->entries[data->index].d_type = DT_DIR;
|
||||
else
|
||||
data->entries[data->index].d_type = DT_REG;
|
||||
|
||||
data->entries[data->index].d_ino = __inode(wname);
|
||||
data->entries[data->index].d_reclen = sizeof(struct dirent);
|
||||
data->entries[data->index].d_namelen = (unsigned char)wcslen(w32fd.cFileName);
|
||||
data->entries[data->index].d_off = 0;
|
||||
|
||||
if (++data->index == data->count) {
|
||||
tmp_entries = (struct dirent*) realloc(data->entries, sizeof(struct dirent) * data->count * grow_factor);
|
||||
if (!tmp_entries)
|
||||
goto out_of_memory;
|
||||
data->entries = tmp_entries;
|
||||
data->count *= grow_factor;
|
||||
}
|
||||
}
|
||||
while (FindNextFileW(hFindFile, &w32fd) != 0);
|
||||
|
||||
free(buffer);
|
||||
FindClose(hFindFile);
|
||||
|
||||
data->count = data->index;
|
||||
data->index = 0;
|
||||
return (DIR*)data;
|
||||
out_of_memory:
|
||||
if (data)
|
||||
{
|
||||
if (INVALID_HANDLE_VALUE != (HANDLE)data->fd)
|
||||
CloseHandle((HANDLE)data->fd);
|
||||
free(data->entries);
|
||||
}
|
||||
free(buffer);
|
||||
free(data);
|
||||
if (INVALID_HANDLE_VALUE != hFindFile)
|
||||
FindClose(hFindFile);
|
||||
__seterrno(ENOMEM);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static wchar_t* __get_buffer()
|
||||
{
|
||||
wchar_t* name = malloc(sizeof(wchar_t) * (NTFS_MAX_PATH + NAME_MAX + 8));
|
||||
if (name)
|
||||
memcpy(name, L"\\\\?\\", sizeof(wchar_t) * 4);
|
||||
return name;
|
||||
}
|
||||
|
||||
static DIR* opendir(const char* name)
|
||||
{
|
||||
DIR* dirp = NULL;
|
||||
wchar_t* wname = __get_buffer();
|
||||
int size = 0;
|
||||
if (!wname)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
size = MultiByteToWideChar(CP_UTF8, 0, name, -1, wname + 4, NTFS_MAX_PATH);
|
||||
if (0 == size)
|
||||
{
|
||||
free(wname);
|
||||
return NULL;
|
||||
}
|
||||
dirp = __internal_opendir(wname, size + 4);
|
||||
free(wname);
|
||||
return dirp;
|
||||
}
|
||||
|
||||
static DIR* _wopendir(const wchar_t* name)
|
||||
{
|
||||
DIR* dirp = NULL;
|
||||
wchar_t* wname = __get_buffer();
|
||||
int size = 0;
|
||||
if (!wname)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
size = (int)wcslen(name);
|
||||
if (size > NTFS_MAX_PATH)
|
||||
{
|
||||
free(wname);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(wname + 4, name, sizeof(wchar_t) * (size + 1));
|
||||
dirp = __internal_opendir(wname, size + 5);
|
||||
free(wname);
|
||||
return dirp;
|
||||
}
|
||||
|
||||
static DIR* fdopendir(intptr_t fd)
|
||||
{
|
||||
DIR* dirp = NULL;
|
||||
wchar_t* wname = __get_buffer();
|
||||
typedef DWORD (__stdcall * pfnGetFinalPathNameByHandleW)(
|
||||
HANDLE hFile, LPWSTR lpszFilePath, DWORD cchFilePath, DWORD dwFlags);
|
||||
|
||||
HANDLE hKernel32 = GetModuleHandleW(L"kernel32.dll");
|
||||
if (!hKernel32)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pfnGetFinalPathNameByHandleW fnGetFinalPathNameByHandleW = (pfnGetFinalPathNameByHandleW) GetProcAddress(hKernel32, "GetFinalPathNameByHandleW");
|
||||
if (!fnGetFinalPathNameByHandleW)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int size = 0;
|
||||
if (!wname)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
size = fnGetFinalPathNameByHandleW((HANDLE) fd, wname + 4, NTFS_MAX_PATH, FILE_NAME_NORMALIZED);
|
||||
if (0 == size)
|
||||
{
|
||||
free(wname);
|
||||
errno = ENOTDIR;
|
||||
return NULL;
|
||||
}
|
||||
dirp = __internal_opendir(wname, size + 5);
|
||||
free(wname);
|
||||
return dirp;
|
||||
}
|
||||
|
||||
static struct dirent* readdir(DIR* dirp)
|
||||
{
|
||||
struct __dir* data = (struct __dir*) dirp;
|
||||
if (!data) {
|
||||
errno = EBADF;
|
||||
return NULL;
|
||||
}
|
||||
if (data->index < data->count)
|
||||
{
|
||||
return &data->entries[data->index++];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int readdir_r(DIR* dirp, struct dirent* entry, struct dirent**result)
|
||||
{
|
||||
struct __dir* data = (struct __dir*) dirp;
|
||||
if (!data) {
|
||||
return EBADF;
|
||||
}
|
||||
if (data->index < data->count)
|
||||
{
|
||||
if (entry)
|
||||
memcpy(entry, &data->entries[data->index++], sizeof(struct dirent));
|
||||
if (result)
|
||||
*result = entry;
|
||||
}
|
||||
else if (result)
|
||||
*result = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void seekdir(DIR* dirp, long int offset)
|
||||
{
|
||||
if (dirp)
|
||||
{
|
||||
struct __dir* data = (struct __dir*) dirp;
|
||||
data->index = (offset < data->count) ? offset : data->index;
|
||||
}
|
||||
}
|
||||
|
||||
static void rewinddir(DIR* dirp)
|
||||
{
|
||||
seekdir(dirp, 0);
|
||||
}
|
||||
|
||||
static long int telldir(DIR* dirp)
|
||||
{
|
||||
if (!dirp) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
return ((struct __dir*)dirp)->count;
|
||||
}
|
||||
|
||||
static intptr_t dirfd(DIR * dirp)
|
||||
{
|
||||
if (!dirp) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return ((struct __dir*)dirp)->fd;
|
||||
}
|
||||
|
||||
static int scandir(const char* dirp, struct dirent*** namelist,
|
||||
int (*filter)(const struct dirent*),
|
||||
int (*compar)(const struct dirent**, const struct dirent**))
|
||||
{
|
||||
struct dirent ** entries = NULL, ** tmp_entries = NULL;
|
||||
long int i = 0, index = 0, count = 16;
|
||||
DIR * d = opendir(dirp);
|
||||
struct __dir* data = (struct __dir*) d;
|
||||
if (!data) {
|
||||
closedir(d);
|
||||
__seterrno(ENOENT);
|
||||
return -1;
|
||||
}
|
||||
entries = (struct dirent**) malloc(sizeof(struct dirent*) * count);
|
||||
if (!entries)
|
||||
{
|
||||
closedir(d);
|
||||
__seterrno(ENOMEM);
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < data->count; ++i)
|
||||
{
|
||||
if (!filter || filter(&data->entries[i]))
|
||||
{
|
||||
entries[index] = (struct dirent*) malloc(sizeof(struct dirent));
|
||||
if (!entries[index])
|
||||
{
|
||||
closedir(d);
|
||||
for (i = 0; i < index; ++i)
|
||||
free(entries[index]);
|
||||
free(entries);
|
||||
__seterrno(ENOMEM);
|
||||
return -1;
|
||||
}
|
||||
memcpy(entries[index], &data->entries[i], sizeof(struct dirent));
|
||||
if (++index == count)
|
||||
{
|
||||
tmp_entries = (struct dirent**)realloc(entries, sizeof(struct dirent*) * count * 2);
|
||||
if (!tmp_entries)
|
||||
{
|
||||
closedir(d);
|
||||
for (i = 0; i < index; ++i)
|
||||
free(entries[index - 1]);
|
||||
free(entries);
|
||||
__seterrno(ENOMEM);
|
||||
return -1;
|
||||
}
|
||||
entries = tmp_entries;
|
||||
count *= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
qsort(entries, index, sizeof(struct dirent*), compar);
|
||||
entries[index] = NULL;
|
||||
if (namelist)
|
||||
*namelist = entries;
|
||||
closedir(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int alphasort(const void* a, const void* b)
|
||||
{
|
||||
struct dirent** dira = (struct dirent**)a, **dirb = (struct dirent**)b;
|
||||
if (!dira || !dirb)
|
||||
return 0;
|
||||
return strcoll((*dira)->d_name, (*dirb)->d_name);
|
||||
}
|
||||
|
||||
static int __strverscmp(const char* s1, const char* s2)
|
||||
{
|
||||
return alphasort(s1, s2);
|
||||
}
|
||||
|
||||
int versionsort(const void* a, const void* b)
|
||||
{
|
||||
struct dirent** dira = (struct dirent**)a, ** dirb = (struct dirent**)b;
|
||||
if (!dira || !dirb)
|
||||
return 0;
|
||||
return __strverscmp((*dira)->d_name, (*dirb)->d_name);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* __DIRENT_H_9DE6B42C_8D0C_4D31_A8EF_8E4C30E6C46A__ */
|
||||
@@ -155,6 +155,7 @@
|
||||
<ClInclude Include="..\source\World\Renderer\TripodCameraRenderer.hpp" />
|
||||
<ClInclude Include="..\source\World\Storage\ChunkStorage.hpp" />
|
||||
<ClInclude Include="..\source\World\Storage\ExternalFileLevelStorage.hpp" />
|
||||
<ClInclude Include="..\source\World\Storage\ExternalFileLevelStorageSource.hpp" />
|
||||
<ClInclude Include="..\source\World\Storage\LevelSource.hpp" />
|
||||
<ClInclude Include="..\source\World\Storage\LevelStorage.hpp" />
|
||||
<ClInclude Include="..\source\World\Storage\LevelStorageSource.hpp" />
|
||||
@@ -474,6 +475,7 @@
|
||||
<ClCompile Include="..\source\World\Renderer\TripodCameraRenderer.cpp" />
|
||||
<ClCompile Include="..\source\World\Storage\ChunkStorage.cpp" />
|
||||
<ClCompile Include="..\source\World\Storage\ExternalFileLevelStorage.cpp" />
|
||||
<ClCompile Include="..\source\World\Storage\ExternalFileLevelStorageSource.cpp" />
|
||||
<ClCompile Include="..\source\World\Storage\LevelSource.cpp" />
|
||||
<ClCompile Include="..\source\World\Storage\LevelStorage.cpp" />
|
||||
<ClCompile Include="..\source\World\Storage\LevelStorageSource.cpp" />
|
||||
|
||||
@@ -1065,6 +1065,9 @@
|
||||
<ClCompile Include="..\source\World\Storage\ExternalFileLevelStorage.cpp">
|
||||
<Filter>Source Files\World\Storage</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\source\World\Storage\ExternalFileLevelStorageSource.cpp">
|
||||
<Filter>Source Files\World\Storage</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\source\Options.hpp">
|
||||
@@ -1934,9 +1937,12 @@
|
||||
<ClInclude Include="..\source\World\RegionFile.hpp">
|
||||
<Filter>Header Files\World</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\source\World\Storage\ExternalFileLevelStorage.hpp">
|
||||
<ClInclude Include="..\source\World\Storage\ExternalFileLevelStorageSource.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\source\World\Storage\ExternalFileLevelStorage.hpp">
|
||||
<Filter>Header Files\World\Storage</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="..\thirdparty\raknet\CMakeLists.txt">
|
||||
|
||||
Reference in New Issue
Block a user