mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-09 12:36:23 +02:00
Also, check if 24-bit depth is supported and use it (when packed stencil isn't provided). VideoCore III and VideoCore IV used in Symbian, Android and Raspberry Pi require this as they only support 24-bit depth, 8-bit stencil.
326 lines
6.7 KiB
C++
326 lines
6.7 KiB
C++
#ifdef _WIN32
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <Windows.h>
|
|
#include <direct.h>
|
|
#else
|
|
#include <dirent.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#endif
|
|
#include <cstring>
|
|
#include <string>
|
|
#include <set>
|
|
#include <algorithm>
|
|
#include <stdio.h>
|
|
#include <sys/stat.h>
|
|
#include <ctype.h>
|
|
|
|
#include "base/logging.h"
|
|
#include "base/basictypes.h"
|
|
#include "file/file_util.h"
|
|
|
|
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__SYMBIAN32__)
|
|
#define stat64 stat
|
|
#endif
|
|
|
|
#if !defined(readdir_r)
|
|
static inline int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) {
|
|
struct dirent *readdir_entry;
|
|
|
|
readdir_entry = readdir(dirp);
|
|
if (readdir_entry == NULL) {
|
|
*result = NULL;
|
|
return errno;
|
|
}
|
|
|
|
*entry = *readdir_entry;
|
|
*result = entry;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
bool writeStringToFile(bool text_file, const std::string &str, const char *filename)
|
|
{
|
|
FILE *f = fopen(filename, text_file ? "w" : "wb");
|
|
if (!f)
|
|
return false;
|
|
size_t len = str.size();
|
|
if (len != fwrite(str.data(), 1, str.size(), f))
|
|
{
|
|
fclose(f);
|
|
return false;
|
|
}
|
|
fclose(f);
|
|
return true;
|
|
}
|
|
|
|
bool writeDataToFile(bool text_file, const void* data, const unsigned int size, const char *filename)
|
|
{
|
|
FILE *f = fopen(filename, text_file ? "w" : "wb");
|
|
if (!f)
|
|
return false;
|
|
size_t len = size;
|
|
if (len != fwrite(data, 1, len, f))
|
|
{
|
|
fclose(f);
|
|
return false;
|
|
}
|
|
fclose(f);
|
|
return true;
|
|
}
|
|
|
|
uint64_t GetSize(FILE *f)
|
|
{
|
|
// can't use off_t here because it can be 32-bit
|
|
uint64_t pos = ftell(f);
|
|
if (fseek(f, 0, SEEK_END) != 0) {
|
|
return 0;
|
|
}
|
|
uint64_t size = ftell(f);
|
|
// Reset the seek position to where it was when we started.
|
|
if ((size != pos) && (fseek(f, pos, SEEK_SET) != 0)) {
|
|
// Should error here
|
|
return 0;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
bool ReadFileToString(bool text_file, const char *filename, std::string &str)
|
|
{
|
|
FILE *f = fopen(filename, text_file ? "r" : "rb");
|
|
if (!f)
|
|
return false;
|
|
size_t len = (size_t)GetSize(f);
|
|
char *buf = new char[len + 1];
|
|
buf[fread(buf, 1, len, f)] = 0;
|
|
str = std::string(buf, len);
|
|
fclose(f);
|
|
delete [] buf;
|
|
return true;
|
|
}
|
|
|
|
|
|
bool readDataFromFile(bool text_file, unsigned char* &data, const unsigned int size, const char *filename)
|
|
{
|
|
FILE *f = fopen(filename, text_file ? "r" : "rb");
|
|
if (!f)
|
|
return false;
|
|
size_t len = (size_t)GetSize(f);
|
|
if(len < size)
|
|
{
|
|
fclose(f);
|
|
return false;
|
|
}
|
|
data[fread(data, 1, size, f)] = 0;
|
|
fclose(f);
|
|
return true;
|
|
}
|
|
|
|
|
|
#define DIR_SEP "/"
|
|
#define DIR_SEP_CHR '\\'
|
|
|
|
#ifndef METRO
|
|
|
|
// Remove any ending forward slashes from directory paths
|
|
// Modifies argument.
|
|
static void stripTailDirSlashes(std::string &fname)
|
|
{
|
|
if (fname.length() > 1)
|
|
{
|
|
size_t i = fname.length() - 1;
|
|
while (fname[i] == DIR_SEP_CHR)
|
|
fname[i--] = '\0';
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Returns true if file filename exists
|
|
bool exists(const std::string &filename)
|
|
{
|
|
#ifdef _WIN32
|
|
return GetFileAttributes(filename.c_str()) != 0xFFFFFFFF;
|
|
#else
|
|
struct stat64 file_info;
|
|
|
|
std::string copy(filename);
|
|
stripTailDirSlashes(copy);
|
|
|
|
int result = stat64(copy.c_str(), &file_info);
|
|
|
|
return (result == 0);
|
|
#endif
|
|
}
|
|
|
|
// Returns true if filename is a directory
|
|
bool isDirectory(const std::string &filename)
|
|
{
|
|
FileInfo info;
|
|
getFileInfo(filename.c_str(), &info);
|
|
return info.isDirectory;
|
|
}
|
|
|
|
bool getFileInfo(const char *path, FileInfo *fileInfo)
|
|
{
|
|
// TODO: Expand relative paths?
|
|
fileInfo->fullName = path;
|
|
|
|
#ifdef _WIN32
|
|
DWORD attributes = GetFileAttributes(path);
|
|
fileInfo->isDirectory = (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
|
fileInfo->isWritable = (attributes & FILE_ATTRIBUTE_READONLY) == 0;
|
|
#else
|
|
struct stat64 file_info;
|
|
|
|
std::string copy(path);
|
|
stripTailDirSlashes(copy);
|
|
|
|
int result = stat64(copy.c_str(), &file_info);
|
|
|
|
if (result < 0) {
|
|
WLOG("IsDirectory: stat failed on %s", path);
|
|
return false;
|
|
}
|
|
|
|
fileInfo->isDirectory = S_ISDIR(file_info.st_mode);
|
|
fileInfo->isWritable = false;
|
|
// HACK: approximation
|
|
if (file_info.st_mode & 0200)
|
|
fileInfo->isWritable = true;
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
std::string getFileExtension(const std::string &fn) {
|
|
int pos = fn.rfind(".");
|
|
if (pos < 0) return "";
|
|
std::string ext = fn.substr(pos+1);
|
|
for (size_t i = 0; i < ext.size(); i++) {
|
|
ext[i] = tolower(ext[i]);
|
|
}
|
|
return ext;
|
|
}
|
|
|
|
size_t getFilesInDir(const char *directory, std::vector<FileInfo> *files, const char *filter) {
|
|
size_t foundEntries = 0;
|
|
std::set<std::string> filters;
|
|
std::string tmp;
|
|
if (filter) {
|
|
while (*filter) {
|
|
if (*filter == ':') {
|
|
filters.insert(tmp);
|
|
tmp = "";
|
|
} else {
|
|
tmp.push_back(*filter);
|
|
}
|
|
filter++;
|
|
}
|
|
}
|
|
#ifdef _WIN32
|
|
// Find the first file in the directory.
|
|
WIN32_FIND_DATA ffd;
|
|
#ifdef UNICODE
|
|
HANDLE hFind = FindFirstFile((std::wstring(directory) + "\\*").c_str(), &ffd);
|
|
#else
|
|
HANDLE hFind = FindFirstFile((std::string(directory) + "\\*").c_str(), &ffd);
|
|
#endif
|
|
if (hFind == INVALID_HANDLE_VALUE) {
|
|
FindClose(hFind);
|
|
return 0;
|
|
}
|
|
// windows loop
|
|
do
|
|
{
|
|
const std::string virtualName(ffd.cFileName);
|
|
#else
|
|
struct dirent_large { struct dirent entry; char padding[FILENAME_MAX+1]; };
|
|
struct dirent_large diren;
|
|
struct dirent *result = NULL;
|
|
|
|
DIR *dirp = opendir(directory);
|
|
if (!dirp)
|
|
return 0;
|
|
// non windows loop
|
|
while (!readdir_r(dirp, (dirent*) &diren, &result) && result)
|
|
{
|
|
const std::string virtualName(result->d_name);
|
|
#endif
|
|
// check for "." and ".."
|
|
if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
|
|
((virtualName[0] == '.') && (virtualName[1] == '.') &&
|
|
(virtualName[2] == '\0')))
|
|
continue;
|
|
|
|
// Remove dotfiles (should be made optional?)
|
|
if (virtualName[0] == '.')
|
|
continue;
|
|
|
|
FileInfo info;
|
|
info.name = virtualName;
|
|
info.fullName = std::string(directory) + "/" + virtualName;
|
|
info.isDirectory = isDirectory(info.fullName);
|
|
info.exists = true;
|
|
if (!info.isDirectory) {
|
|
std::string ext = getFileExtension(info.fullName);
|
|
if (filter) {
|
|
if (filters.find(ext) == filters.end())
|
|
continue;
|
|
}
|
|
}
|
|
|
|
files->push_back(info);
|
|
#ifdef _WIN32
|
|
} while (FindNextFile(hFind, &ffd) != 0);
|
|
FindClose(hFind);
|
|
#else
|
|
}
|
|
closedir(dirp);
|
|
#endif
|
|
std::sort(files->begin(), files->end());
|
|
return foundEntries;
|
|
}
|
|
|
|
void deleteFile(const char *file)
|
|
{
|
|
#ifdef _WIN32
|
|
if (!DeleteFile(file)) {
|
|
ELOG("Error deleting %s: %i", file, GetLastError());
|
|
}
|
|
#else
|
|
int err = unlink(file);
|
|
if (err) {
|
|
ELOG("Error unlinking %s: %i", file, err);
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
std::string getDir(const std::string &path)
|
|
{
|
|
if (path == "/")
|
|
return path;
|
|
int n = path.size() - 1;
|
|
while (n >= 0 && path[n] != '\\' && path[n] != '/')
|
|
n--;
|
|
std::string cutpath = path.substr(0, n);
|
|
for (size_t i = 0; i < cutpath.size(); i++)
|
|
{
|
|
if (cutpath[i] == '\\') cutpath[i] = '/';
|
|
}
|
|
#ifndef _WIN32
|
|
if (!cutpath.size()) {
|
|
return "/";
|
|
}
|
|
#endif
|
|
return cutpath;
|
|
}
|
|
|
|
void mkDir(const std::string &path)
|
|
{
|
|
#ifdef _WIN32
|
|
mkdir(path.c_str());
|
|
#else
|
|
mkdir(path.c_str(), 0777);
|
|
#endif
|
|
}
|