Split out AndroidStorage.cpp from android/jni/app-android.cpp, move to Common

This commit is contained in:
Henrik Rydgård 2021-06-05 19:29:23 +02:00
parent f8b595521d
commit 9b32ea2f55
10 changed files with 262 additions and 212 deletions

View file

@ -502,6 +502,8 @@ add_library(Common STATIC
Common/File/VFS/VFS.cpp
Common/File/VFS/AssetReader.cpp
Common/File/VFS/AssetReader.h
Common/File/AndroidStorage.h
Common/File/AndroidStorage.cpp
Common/File/DiskFree.h
Common/File/DiskFree.cpp
Common/File/Path.h

View file

@ -409,6 +409,7 @@
<ClInclude Include="Data\Text\Parsers.h" />
<ClInclude Include="Data\Text\WrapText.h" />
<ClInclude Include="FakeEmitter.h" />
<ClInclude Include="File\AndroidStorage.h" />
<ClInclude Include="File\DirListing.h" />
<ClInclude Include="File\DiskFree.h" />
<ClInclude Include="File\FileDescriptor.h" />
@ -831,6 +832,7 @@
<ClCompile Include="Data\Text\I18n.cpp" />
<ClCompile Include="Data\Text\Parsers.cpp" />
<ClCompile Include="Data\Text\WrapText.cpp" />
<ClCompile Include="File\AndroidStorage.cpp" />
<ClCompile Include="File\DirListing.cpp" />
<ClCompile Include="File\DiskFree.cpp" />
<ClCompile Include="File\FileDescriptor.cpp" />

View file

@ -395,6 +395,9 @@
<Filter>File</Filter>
</ClInclude>
<ClInclude Include="LogReporting.h" />
<ClInclude Include="File\AndroidStorage.h">
<Filter>File</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="ABI.cpp" />
@ -762,6 +765,9 @@
<Filter>File</Filter>
</ClCompile>
<ClCompile Include="LogReporting.cpp" />
<ClCompile Include="File\AndroidStorage.cpp">
<Filter>File</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="Crypto">
@ -877,4 +883,4 @@
<Filter>Math\fast</Filter>
</None>
</ItemGroup>
</Project>
</Project>

View file

@ -0,0 +1,190 @@
#include "Common/File/AndroidStorage.h"
#include "Common/StringUtils.h"
#include "Common/Log.h"
#include "Common/TimeUtil.h"
#include "android/jni/app-android.h"
#if PPSSPP_PLATFORM(ANDROID) && !defined(__LIBRETRO__)
static jmethodID openContentUri;
static jmethodID listContentUriDir;
static jmethodID contentUriCreateFile;
static jmethodID contentUriCreateDirectory;
static jmethodID contentUriRemoveFile;
static jmethodID contentUriGetFileInfo;
static jmethodID contentUriGetFreeStorageSpace;
static jmethodID filePathGetFreeStorageSpace;
static jobject g_nativeActivity;
void Android_StorageSetNativeActivity(jobject nativeActivity) {
g_nativeActivity = nativeActivity;
}
void Android_RegisterStorageCallbacks(JNIEnv * env, jobject obj) {
openContentUri = env->GetMethodID(env->GetObjectClass(obj), "openContentUri", "(Ljava/lang/String;Ljava/lang/String;)I");
_dbg_assert_(openContentUri);
listContentUriDir = env->GetMethodID(env->GetObjectClass(obj), "listContentUriDir", "(Ljava/lang/String;)[Ljava/lang/String;");
_dbg_assert_(listContentUriDir);
contentUriCreateDirectory = env->GetMethodID(env->GetObjectClass(obj), "contentUriCreateDirectory", "(Ljava/lang/String;Ljava/lang/String;)Z");
_dbg_assert_(contentUriCreateDirectory);
contentUriCreateFile = env->GetMethodID(env->GetObjectClass(obj), "contentUriCreateFile", "(Ljava/lang/String;Ljava/lang/String;)Z");
_dbg_assert_(contentUriCreateFile);
contentUriRemoveFile = env->GetMethodID(env->GetObjectClass(obj), "contentUriRemoveFile", "(Ljava/lang/String;)Z");
_dbg_assert_(contentUriRemoveFile);
contentUriGetFileInfo = env->GetMethodID(env->GetObjectClass(obj), "contentUriGetFileInfo", "(Ljava/lang/String;)Ljava/lang/String;");
_dbg_assert_(contentUriGetFileInfo);
contentUriGetFreeStorageSpace = env->GetMethodID(env->GetObjectClass(obj), "contentUriGetFreeStorageSpace", "(Ljava/lang/String;)J");
_dbg_assert_(contentUriGetFreeStorageSpace);
filePathGetFreeStorageSpace = env->GetMethodID(env->GetObjectClass(obj), "filePathGetFreeStorageSpace", "(Ljava/lang/String;)J");
_dbg_assert_(filePathGetFreeStorageSpace);
}
bool Android_IsContentUri(const std::string &filename) {
return startsWith(filename, "content://");
}
int Android_OpenContentUriFd(const std::string &filename, Android_OpenContentUriMode mode) {
if (!g_nativeActivity) {
return -1;
}
std::string fname = filename;
// PPSSPP adds an ending slash to directories before looking them up.
// TODO: Fix that in the caller (or don't call this for directories).
if (fname.back() == '/')
fname.pop_back();
auto env = getEnv();
const char *modeStr = "";
switch (mode) {
case Android_OpenContentUriMode::READ: modeStr = "r"; break;
case Android_OpenContentUriMode::READ_WRITE: modeStr = "rw"; break;
case Android_OpenContentUriMode::READ_WRITE_TRUNCATE: modeStr = "rwt"; break;
}
jstring j_filename = env->NewStringUTF(fname.c_str());
jstring j_mode = env->NewStringUTF(modeStr);
int fd = env->CallIntMethod(g_nativeActivity, openContentUri, j_filename, j_mode);
return fd;
}
bool Android_CreateDirectory(const std::string &rootTreeUri, const std::string &dirName) {
if (!g_nativeActivity) {
return false;
}
auto env = getEnv();
jstring paramRoot = env->NewStringUTF(rootTreeUri.c_str());
jstring paramDirName = env->NewStringUTF(dirName.c_str());
return env->CallBooleanMethod(g_nativeActivity, contentUriCreateDirectory, paramRoot, paramDirName);
}
bool Android_CreateFile(const std::string &parentTreeUri, const std::string &fileName) {
if (!g_nativeActivity) {
return false;
}
auto env = getEnv();
jstring paramRoot = env->NewStringUTF(parentTreeUri.c_str());
jstring paramFileName = env->NewStringUTF(fileName.c_str());
return env->CallBooleanMethod(g_nativeActivity, contentUriCreateFile, paramRoot, paramFileName);
}
bool Android_RemoveFile(const std::string &fileUri) {
if (!g_nativeActivity) {
return false;
}
auto env = getEnv();
jstring paramFileName = env->NewStringUTF(fileUri.c_str());
return env->CallBooleanMethod(g_nativeActivity, contentUriRemoveFile, paramFileName);
}
static bool ParseFileInfo(const std::string &line, File::FileInfo *fileInfo) {
INFO_LOG(FILESYS, "!! %s", line.c_str());
std::vector<std::string> parts;
SplitString(line, '|', parts);
if (parts.size() != 5) {
ERROR_LOG(FILESYS, "Bad format: %s", line.c_str());
return false;
}
fileInfo->name = std::string(parts[2]);
fileInfo->isDirectory = parts[0][0] == 'D';
fileInfo->exists = true;
sscanf(parts[1].c_str(), "%ld", &fileInfo->size);
fileInfo->fullName = Path(parts[3]);
fileInfo->isWritable = false; // TODO: We don't yet request write access
sscanf(parts[4].c_str(), "%ld", &fileInfo->lastModified);
return true;
}
bool Android_GetFileInfo(const std::string &fileUri, File::FileInfo *fileInfo) {
if (!g_nativeActivity) {
return false;
}
auto env = getEnv();
jstring paramFileUri = env->NewStringUTF(fileUri.c_str());
jstring str = (jstring)env->CallObjectMethod(g_nativeActivity, contentUriGetFileInfo, paramFileUri);
if (!str) {
return false;
}
const char *charArray = env->GetStringUTFChars(str, 0);
bool retval = ParseFileInfo(std::string(charArray), fileInfo);
env->DeleteLocalRef(str);
return retval && fileInfo->exists;
}
std::vector<File::FileInfo> Android_ListContentUri(const std::string &path) {
if (!g_nativeActivity) {
return std::vector<File::FileInfo>();
}
auto env = getEnv();
double start = time_now_d();
jstring param = env->NewStringUTF(path.c_str());
jobject retval = env->CallObjectMethod(g_nativeActivity, listContentUriDir, param);
jobjectArray fileList = (jobjectArray)retval;
std::vector<File::FileInfo> items;
int size = env->GetArrayLength(fileList);
for (int i = 0; i < size; i++) {
jstring str = (jstring)env->GetObjectArrayElement(fileList, i);
const char *charArray = env->GetStringUTFChars(str, 0);
if (charArray) { // paranoia
std::string file = charArray;
File::FileInfo info;
if (ParseFileInfo(file, &info)) {
items.push_back(info);
}
}
env->ReleaseStringUTFChars(str, charArray);
env->DeleteLocalRef(str);
}
env->DeleteLocalRef(fileList);
double elapsed = time_now_d() - start;
INFO_LOG(FILESYS, "Listing directory on content URI took %0.3f s", elapsed);
return items;
}
int64_t Android_GetFreeSpaceByContentUri(const std::string &uri) {
if (!g_nativeActivity) {
return false;
}
auto env = getEnv();
jstring param = env->NewStringUTF(uri.c_str());
return env->CallLongMethod(g_nativeActivity, contentUriGetFreeStorageSpace, param);
}
int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath) {
if (!g_nativeActivity) {
return false;
}
auto env = getEnv();
jstring param = env->NewStringUTF(filePath.c_str());
return env->CallLongMethod(g_nativeActivity, filePathGetFreeStorageSpace, param);
}
#endif

View file

@ -0,0 +1,53 @@
#pragma once
#include <vector>
#include <string>
#include "Common/File/DirListing.h"
// To emphasize that Android storage mode strings are different, let's just use
// an enum.
enum class Android_OpenContentUriMode {
READ = 0, // "r"
READ_WRITE = 1, // "rw"
READ_WRITE_TRUNCATE = 2, // "rwt"
};
#if PPSSPP_PLATFORM(ANDROID) && !defined(__LIBRETRO__)
#include <jni.h>
extern std::string g_extFilesDir;
void Android_StorageSetNativeActivity(jobject nativeActivity);
bool Android_IsContentUri(const std::string &uri);
int Android_OpenContentUriFd(const std::string &uri, const Android_OpenContentUriMode mode);
bool Android_CreateDirectory(const std::string &parentTreeUri, const std::string &dirName);
bool Android_CreateFile(const std::string &parentTreeUri, const std::string &fileName);
bool Android_RemoveFile(const std::string &fileUri);
bool Android_GetFileInfo(const std::string &fileUri, File::FileInfo *info);
int64_t Android_GetFreeSpaceByContentUri(const std::string &uri);
int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath);
std::vector<File::FileInfo> Android_ListContentUri(const std::string &uri);
void Android_RegisterStorageCallbacks(JNIEnv * env, jobject obj);
#else
// Stub out the Android Storage wrappers, so that we can avoid ifdefs everywhere.
inline bool Android_IsContentUri(const std::string &uri) { return false; }
inline int Android_OpenContentUriFd(const std::string &uri, const Android_OpenContentUriMode mode) { return -1; }
inline bool Android_CreateDirectory(const std::string &parentTreeUri, const std::string &dirName) { return false; }
inline bool Android_CreateFile(const std::string &parentTreeUri, const std::string &fileName) { return false; }
inline bool Android_RemoveFile(const std::string &fileUri) { return false; }
inline bool Android_GetFileInfo(const std::string &fileUri, File::FileInfo *info) { return false; }
inline int64_t Android_GetFreeSpaceByContentUri(const std::string &uri) { return -1; }
inline int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath) { return -1; }
inline std::vector<File::FileInfo> Android_ListContentUri(const std::string &uri) {
return std::vector<File::FileInfo>();
}
#endif

View file

@ -23,7 +23,7 @@
#include "Common/Net/URL.h"
#include "Common/File/DirListing.h"
#include "Common/File/FileUtil.h"
#include "android/jni/app-android.h"
#include "Common/File/AndroidStorage.h"
#if !defined(__linux__) && !defined(_WIN32) && !defined(__QNX__)
#define stat64 stat

View file

@ -249,6 +249,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Common/Data/Text/I18n.cpp \
$(SRC)/Common/Data/Text/Parsers.cpp \
$(SRC)/Common/Data/Text/WrapText.cpp \
$(SRC)/Common/File/AndroidStorage.cpp \
$(SRC)/Common/File/VFS/VFS.cpp \
$(SRC)/Common/File/VFS/AssetReader.cpp \
$(SRC)/Common/File/DiskFree.cpp \

View file

@ -64,6 +64,7 @@ struct JNIEnv {};
#include "Common/File/DirListing.h"
#include "Common/File/VFS/VFS.h"
#include "Common/File/VFS/AssetReader.h"
#include "Common/File/AndroidStorage.h"
#include "Common/Input/InputState.h"
#include "Common/Input/KeyCodes.h"
#include "Common/Profiler/Profiler.h"
@ -172,15 +173,6 @@ static float g_safeInsetBottom = 0.0;
static jmethodID postCommand;
static jmethodID openContentUri;
static jmethodID listContentUriDir;
static jmethodID contentUriCreateFile;
static jmethodID contentUriCreateDirectory;
static jmethodID contentUriRemoveFile;
static jmethodID contentUriGetFileInfo;
static jmethodID contentUriGetFreeStorageSpace;
static jmethodID filePathGetFreeStorageSpace;
static jobject nativeActivity;
static volatile bool exitRenderLoop;
static bool renderLoopRunning;
@ -240,152 +232,6 @@ void AndroidLogger::Log(const LogMessage &message) {
}
}
bool Android_IsContentUri(const std::string &filename) {
return startsWith(filename, "content://");
}
int Android_OpenContentUriFd(const std::string &filename, Android_OpenContentUriMode mode) {
if (!nativeActivity) {
return -1;
}
std::string fname = filename;
// PPSSPP adds an ending slash to directories before looking them up.
// TODO: Fix that in the caller (or don't call this for directories).
if (fname.back() == '/')
fname.pop_back();
auto env = getEnv();
const char *modeStr = "";
switch (mode) {
case Android_OpenContentUriMode::READ: modeStr = "r"; break;
case Android_OpenContentUriMode::READ_WRITE: modeStr = "rw"; break;
case Android_OpenContentUriMode::READ_WRITE_TRUNCATE: modeStr = "rwt"; break;
}
jstring j_filename = env->NewStringUTF(fname.c_str());
jstring j_mode = env->NewStringUTF(modeStr);
int fd = env->CallIntMethod(nativeActivity, openContentUri, j_filename, j_mode);
return fd;
}
bool Android_CreateDirectory(const std::string &rootTreeUri, const std::string &dirName) {
if (!nativeActivity) {
return false;
}
auto env = getEnv();
jstring paramRoot = env->NewStringUTF(rootTreeUri.c_str());
jstring paramDirName = env->NewStringUTF(dirName.c_str());
return env->CallBooleanMethod(nativeActivity, contentUriCreateDirectory, paramRoot, paramDirName);
}
bool Android_CreateFile(const std::string &parentTreeUri, const std::string &fileName) {
if (!nativeActivity) {
return false;
}
auto env = getEnv();
jstring paramRoot = env->NewStringUTF(parentTreeUri.c_str());
jstring paramFileName = env->NewStringUTF(fileName.c_str());
return env->CallBooleanMethod(nativeActivity, contentUriCreateFile, paramRoot, paramFileName);
}
bool Android_RemoveFile(const std::string &fileUri) {
if (!nativeActivity) {
return false;
}
auto env = getEnv();
jstring paramFileName = env->NewStringUTF(fileUri.c_str());
return env->CallBooleanMethod(nativeActivity, contentUriRemoveFile, paramFileName);
}
static bool ParseFileInfo(const std::string &line, File::FileInfo *fileInfo) {
INFO_LOG(FILESYS, "!! %s", line.c_str());
std::vector<std::string> parts;
SplitString(line, '|', parts);
if (parts.size() != 5) {
ERROR_LOG(FILESYS, "Bad format: %s", line.c_str());
return false;
}
fileInfo->name = std::string(parts[2]);
fileInfo->isDirectory = parts[0][0] == 'D';
fileInfo->exists = true;
sscanf(parts[1].c_str(), "%ld", &fileInfo->size);
fileInfo->fullName = Path(parts[3]);
fileInfo->isWritable = false; // TODO: We don't yet request write access
sscanf(parts[4].c_str(), "%ld", &fileInfo->lastModified);
return true;
}
bool Android_GetFileInfo(const std::string &fileUri, File::FileInfo *fileInfo) {
if (!nativeActivity) {
return false;
}
auto env = getEnv();
jstring paramFileUri = env->NewStringUTF(fileUri.c_str());
jstring str = (jstring)env->CallObjectMethod(nativeActivity, contentUriGetFileInfo, paramFileUri);
if (!str) {
return false;
}
const char *charArray = env->GetStringUTFChars(str, 0);
bool retval = ParseFileInfo(std::string(charArray), fileInfo);
env->DeleteLocalRef(str);
return retval && fileInfo->exists;
}
std::vector<File::FileInfo> Android_ListContentUri(const std::string &path) {
if (!nativeActivity) {
return std::vector<File::FileInfo>();
}
auto env = getEnv();
double start = time_now_d();
jstring param = env->NewStringUTF(path.c_str());
jobject retval = env->CallObjectMethod(nativeActivity, listContentUriDir, param);
jobjectArray fileList = (jobjectArray)retval;
std::vector<File::FileInfo> items;
int size = env->GetArrayLength(fileList);
for (int i = 0; i < size; i++) {
jstring str = (jstring) env->GetObjectArrayElement(fileList, i);
const char *charArray = env->GetStringUTFChars(str, 0);
if (charArray) { // paranoia
std::string file = charArray;
File::FileInfo info;
if (ParseFileInfo(file, &info)) {
items.push_back(info);
}
}
env->ReleaseStringUTFChars(str, charArray);
env->DeleteLocalRef(str);
}
env->DeleteLocalRef(fileList);
double elapsed = time_now_d() - start;
INFO_LOG(FILESYS, "Listing directory on content URI took %0.3f s");
return items;
}
int64_t Android_GetFreeSpaceByContentUri(const std::string &uri) {
if (!nativeActivity) {
return false;
}
auto env = getEnv();
jstring param = env->NewStringUTF(uri.c_str());
return env->CallLongMethod(nativeActivity, contentUriGetFreeStorageSpace, param);
}
int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath) {
if (!nativeActivity) {
return false;
}
auto env = getEnv();
jstring param = env->NewStringUTF(filePath.c_str());
return env->CallLongMethod(nativeActivity, filePathGetFreeStorageSpace, param);
}
JNIEnv* getEnv() {
JNIEnv *env;
int status = gJvm->GetEnv((void**)&env, JNI_VERSION_1_6);
@ -633,25 +479,12 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeActivity_registerCallbacks(JNIEnv *
postCommand = env->GetMethodID(env->GetObjectClass(obj), "postCommand", "(Ljava/lang/String;Ljava/lang/String;)V");
_dbg_assert_(postCommand);
openContentUri = env->GetMethodID(env->GetObjectClass(obj), "openContentUri", "(Ljava/lang/String;Ljava/lang/String;)I");
_dbg_assert_(openContentUri);
listContentUriDir = env->GetMethodID(env->GetObjectClass(obj), "listContentUriDir", "(Ljava/lang/String;)[Ljava/lang/String;");
_dbg_assert_(listContentUriDir);
contentUriCreateDirectory = env->GetMethodID(env->GetObjectClass(obj), "contentUriCreateDirectory", "(Ljava/lang/String;Ljava/lang/String;)Z");
_dbg_assert_(contentUriCreateDirectory);
contentUriCreateFile = env->GetMethodID(env->GetObjectClass(obj), "contentUriCreateFile", "(Ljava/lang/String;Ljava/lang/String;)Z");
_dbg_assert_(contentUriCreateFile);
contentUriRemoveFile = env->GetMethodID(env->GetObjectClass(obj), "contentUriRemoveFile", "(Ljava/lang/String;)Z");
_dbg_assert_(contentUriRemoveFile);
contentUriGetFileInfo = env->GetMethodID(env->GetObjectClass(obj), "contentUriGetFileInfo", "(Ljava/lang/String;)Ljava/lang/String;");
_dbg_assert_(contentUriGetFileInfo);
contentUriGetFreeStorageSpace = env->GetMethodID(env->GetObjectClass(obj), "contentUriGetFreeStorageSpace", "(Ljava/lang/String;)J");
_dbg_assert_(contentUriGetFreeStorageSpace);
filePathGetFreeStorageSpace = env->GetMethodID(env->GetObjectClass(obj), "filePathGetFreeStorageSpace", "(Ljava/lang/String;)J");
_dbg_assert_(filePathGetFreeStorageSpace);
Android_RegisterStorageCallbacks(env, obj);
Android_StorageSetNativeActivity(nativeActivity);
}
extern "C" void Java_org_ppsspp_ppsspp_NativeActivity_unregisterCallbacks(JNIEnv *env, jobject obj) {
Android_StorageSetNativeActivity(nullptr);
env->DeleteGlobalRef(nativeActivity);
nativeActivity = nullptr;
}

View file

@ -9,14 +9,7 @@
#include "Common/LogManager.h"
#include "Common/File/DirListing.h"
#include "Common/File/Path.h"
// To emphasize that Android storage mode strings are different, let's just use
// an enum.
enum class Android_OpenContentUriMode {
READ = 0, // "r"
READ_WRITE = 1, // "rw"
READ_WRITE_TRUNCATE = 2, // "rwt"
};
#include "Common/File/AndroidStorage.h"
#if PPSSPP_PLATFORM(ANDROID) && !defined(__LIBRETRO__)
@ -30,35 +23,4 @@ public:
void Log(const LogMessage &message) override;
};
extern std::string g_extFilesDir;
// Called from PathBrowser for example.
bool Android_IsContentUri(const std::string &uri);
int Android_OpenContentUriFd(const std::string &uri, const Android_OpenContentUriMode mode);
bool Android_CreateDirectory(const std::string &parentTreeUri, const std::string &dirName);
bool Android_CreateFile(const std::string &parentTreeUri, const std::string &fileName);
bool Android_RemoveFile(const std::string &fileUri);
bool Android_GetFileInfo(const std::string &fileUri, File::FileInfo *info);
int64_t Android_GetFreeSpaceByContentUri(const std::string &uri);
int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath);
std::vector<File::FileInfo> Android_ListContentUri(const std::string &uri);
#else
// Stub out the Android Storage wrappers, so that we can avoid ifdefs everywhere.
inline bool Android_IsContentUri(const std::string &uri) { return false; }
inline int Android_OpenContentUriFd(const std::string &uri, const Android_OpenContentUriMode mode) { return -1; }
inline bool Android_CreateDirectory(const std::string &parentTreeUri, const std::string &dirName) { return false; }
inline bool Android_CreateFile(const std::string &parentTreeUri, const std::string &fileName) { return false; }
inline bool Android_RemoveFile(const std::string &fileUri) { return false; }
inline bool Android_GetFileInfo(const std::string &fileUri, File::FileInfo *info) { return false; }
inline int64_t Android_GetFreeSpaceByContentUri(const std::string &uri) { return -1; }
inline int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath) { return -1; }
inline std::vector<File::FileInfo> Android_ListContentUri(const std::string &uri) {
return std::vector<File::FileInfo>();
}
#endif

View file

@ -233,6 +233,7 @@ SOURCES_CXX += \
$(COMMONDIR)/Data/Text/WrapText.cpp \
$(COMMONDIR)/File/VFS/VFS.cpp \
$(COMMONDIR)/File/VFS/AssetReader.cpp \
$(COMMONDIR)/File/AndroidStorage.cpp \
$(COMMONDIR)/File/DiskFree.cpp \
$(COMMONDIR)/File/Path.cpp \
$(COMMONDIR)/File/PathBrowser.cpp \