Android: Add specialized content provider implementation of DoFileSearch
This commit is contained in:
parent
01b964b01a
commit
d78277c063
|
@ -130,8 +130,8 @@ public final class MainPresenter
|
||||||
|
|
||||||
boolean recursive = BooleanSetting.MAIN_RECURSIVE_ISO_PATHS.getBooleanGlobal();
|
boolean recursive = BooleanSetting.MAIN_RECURSIVE_ISO_PATHS.getBooleanGlobal();
|
||||||
String[] childNames = ContentHandler.getChildNames(uri, recursive);
|
String[] childNames = ContentHandler.getChildNames(uri, recursive);
|
||||||
if (Arrays.stream(childNames).noneMatch((name) ->
|
if (Arrays.stream(childNames).noneMatch((name) -> FileBrowserHelper.GAME_EXTENSIONS.contains(
|
||||||
FileBrowserHelper.GAME_EXTENSIONS.contains(FileBrowserHelper.getExtension(name))))
|
FileBrowserHelper.getExtension(name, false))))
|
||||||
{
|
{
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(mContext, R.style.DolphinDialogBase);
|
AlertDialog.Builder builder = new AlertDialog.Builder(mContext, R.style.DolphinDialogBase);
|
||||||
builder.setMessage(mContext.getString(R.string.wrong_file_extension_in_directory,
|
builder.setMessage(mContext.getString(R.string.wrong_file_extension_in_directory,
|
||||||
|
|
|
@ -15,7 +15,9 @@ import org.dolphinemu.dolphinemu.DolphinApplication;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We use a lot of "catch (Exception e)" in this class. This is for two reasons:
|
We use a lot of "catch (Exception e)" in this class. This is for two reasons:
|
||||||
|
@ -184,34 +186,94 @@ public class ContentHandler
|
||||||
public static String[] getChildNames(@NonNull Uri uri, boolean recursive)
|
public static String[] getChildNames(@NonNull Uri uri, boolean recursive)
|
||||||
{
|
{
|
||||||
ArrayList<String> result = new ArrayList<>();
|
ArrayList<String> result = new ArrayList<>();
|
||||||
getChildNames(uri, DocumentsContract.getDocumentId(treeToDocument(uri)), recursive, result);
|
|
||||||
|
ForEachChildCallback callback = new ForEachChildCallback()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void run(String displayName, String documentId, boolean isDirectory)
|
||||||
|
{
|
||||||
|
if (recursive && isDirectory)
|
||||||
|
{
|
||||||
|
forEachChild(uri, documentId, this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.add(displayName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
forEachChild(uri, DocumentsContract.getDocumentId(treeToDocument(uri)), callback);
|
||||||
|
|
||||||
return result.toArray(new String[0]);
|
return result.toArray(new String[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void getChildNames(@NonNull Uri uri, @NonNull String documentId, boolean recursive,
|
@NonNull @Keep
|
||||||
List<String> resultOut)
|
public static String[] doFileSearch(@NonNull String directory, @NonNull String[] extensions,
|
||||||
|
boolean recursive)
|
||||||
|
{
|
||||||
|
ArrayList<String> result = new ArrayList<>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Uri uri = unmangle(directory);
|
||||||
|
String documentId = DocumentsContract.getDocumentId(treeToDocument(uri));
|
||||||
|
boolean acceptAll = extensions.length == 0;
|
||||||
|
Predicate<String> extensionCheck = (displayName) ->
|
||||||
|
{
|
||||||
|
String extension = FileBrowserHelper.getExtension(displayName, true);
|
||||||
|
return extension != null && Arrays.stream(extensions).anyMatch(extension::equalsIgnoreCase);
|
||||||
|
};
|
||||||
|
doFileSearch(uri, directory, documentId, recursive, result, acceptAll, extensionCheck);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.toArray(new String[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void doFileSearch(@NonNull Uri baseUri, @NonNull String path,
|
||||||
|
@NonNull String documentId, boolean recursive, @NonNull List<String> resultOut,
|
||||||
|
boolean acceptAll, @NonNull Predicate<String> extensionCheck)
|
||||||
|
{
|
||||||
|
forEachChild(baseUri, documentId, (displayName, childDocumentId, isDirectory) ->
|
||||||
|
{
|
||||||
|
String childPath = path + '/' + displayName;
|
||||||
|
if (acceptAll || (!isDirectory && extensionCheck.test(displayName)))
|
||||||
|
{
|
||||||
|
resultOut.add(childPath);
|
||||||
|
}
|
||||||
|
if (recursive && isDirectory)
|
||||||
|
{
|
||||||
|
doFileSearch(baseUri, childPath, childDocumentId, recursive, resultOut, acceptAll,
|
||||||
|
extensionCheck);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface ForEachChildCallback
|
||||||
|
{
|
||||||
|
void run(String displayName, String documentId, boolean isDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void forEachChild(@NonNull Uri uri, @NonNull String documentId,
|
||||||
|
@NonNull ForEachChildCallback callback)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(uri, documentId);
|
Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(uri, documentId);
|
||||||
|
|
||||||
final String[] projection = recursive ? new String[]{Document.COLUMN_DISPLAY_NAME,
|
final String[] projection = new String[]{Document.COLUMN_DISPLAY_NAME,
|
||||||
Document.COLUMN_MIME_TYPE, Document.COLUMN_DOCUMENT_ID} :
|
Document.COLUMN_MIME_TYPE, Document.COLUMN_DOCUMENT_ID};
|
||||||
new String[]{Document.COLUMN_DISPLAY_NAME};
|
|
||||||
try (Cursor cursor = getContentResolver().query(childrenUri, projection, null, null, null))
|
try (Cursor cursor = getContentResolver().query(childrenUri, projection, null, null, null))
|
||||||
{
|
{
|
||||||
if (cursor != null)
|
if (cursor != null)
|
||||||
{
|
{
|
||||||
while (cursor.moveToNext())
|
while (cursor.moveToNext())
|
||||||
{
|
{
|
||||||
if (recursive && Document.MIME_TYPE_DIR.equals(cursor.getString(1)))
|
callback.run(cursor.getString(0), cursor.getString(2),
|
||||||
{
|
Document.MIME_TYPE_DIR.equals(cursor.getString(1)));
|
||||||
getChildNames(uri, cursor.getString(2), recursive, resultOut);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
resultOut.add(cursor.getString(0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,10 +88,10 @@ public final class FileBrowserHelper
|
||||||
|
|
||||||
String path = uri.getLastPathSegment();
|
String path = uri.getLastPathSegment();
|
||||||
if (path != null)
|
if (path != null)
|
||||||
extension = getExtension(new File(path).getName());
|
extension = getExtension(new File(path).getName(), false);
|
||||||
|
|
||||||
if (extension == null)
|
if (extension == null)
|
||||||
extension = getExtension(ContentHandler.getDisplayName(uri));
|
extension = getExtension(ContentHandler.getDisplayName(uri), false);
|
||||||
|
|
||||||
if (extension != null && validExtensions.contains(extension))
|
if (extension != null && validExtensions.contains(extension))
|
||||||
{
|
{
|
||||||
|
@ -122,13 +122,15 @@ public final class FileBrowserHelper
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static String getExtension(@Nullable String fileName)
|
public static String getExtension(@Nullable String fileName, boolean includeDot)
|
||||||
{
|
{
|
||||||
if (fileName == null)
|
if (fileName == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
int dotIndex = fileName.lastIndexOf(".");
|
int dotIndex = fileName.lastIndexOf(".");
|
||||||
return dotIndex != -1 ? fileName.substring(dotIndex + 1) : null;
|
if (dotIndex == -1)
|
||||||
|
return null;
|
||||||
|
return fileName.substring(dotIndex + (includeDot ? 0 : 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String setToSortedDelimitedString(Set<String> set)
|
public static String setToSortedDelimitedString(Set<String> set)
|
||||||
|
|
|
@ -44,6 +44,14 @@ std::vector<std::string> JStringArrayToVector(JNIEnv* env, jobjectArray array)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jobjectArray JStringArrayFromVector(JNIEnv* env, std::vector<std::string> vector)
|
||||||
|
{
|
||||||
|
jobjectArray result = env->NewObjectArray(vector.size(), IDCache::GetStringClass(), nullptr);
|
||||||
|
for (jsize i = 0; i < vector.size(); ++i)
|
||||||
|
env->SetObjectArrayElement(result, i, ToJString(env, vector[i]));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsPathAndroidContent(const std::string& uri)
|
bool IsPathAndroidContent(const std::string& uri)
|
||||||
{
|
{
|
||||||
return StringBeginsWith(uri, "content://");
|
return StringBeginsWith(uri, "content://");
|
||||||
|
@ -130,6 +138,17 @@ std::vector<std::string> GetAndroidContentChildNames(const std::string& uri)
|
||||||
return JStringArrayToVector(env, reinterpret_cast<jobjectArray>(children));
|
return JStringArrayToVector(env, reinterpret_cast<jobjectArray>(children));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> DoFileSearchAndroidContent(const std::string& directory,
|
||||||
|
const std::vector<std::string>& extensions,
|
||||||
|
bool recursive)
|
||||||
|
{
|
||||||
|
JNIEnv* env = IDCache::GetEnvForThread();
|
||||||
|
jobject result = env->CallStaticObjectMethod(
|
||||||
|
IDCache::GetContentHandlerClass(), IDCache::GetContentHandlerDoFileSearch(),
|
||||||
|
ToJString(env, directory), JStringArrayFromVector(env, extensions), recursive);
|
||||||
|
return JStringArrayToVector(env, reinterpret_cast<jobjectArray>(result));
|
||||||
|
}
|
||||||
|
|
||||||
int GetNetworkIpAddress()
|
int GetNetworkIpAddress()
|
||||||
{
|
{
|
||||||
JNIEnv* env = IDCache::GetEnvForThread();
|
JNIEnv* env = IDCache::GetEnvForThread();
|
||||||
|
|
|
@ -38,6 +38,10 @@ std::string GetAndroidContentDisplayName(const std::string& uri);
|
||||||
// Returns the display names of all children of a directory, non-recursively.
|
// Returns the display names of all children of a directory, non-recursively.
|
||||||
std::vector<std::string> GetAndroidContentChildNames(const std::string& uri);
|
std::vector<std::string> GetAndroidContentChildNames(const std::string& uri);
|
||||||
|
|
||||||
|
std::vector<std::string> DoFileSearchAndroidContent(const std::string& directory,
|
||||||
|
const std::vector<std::string>& extensions,
|
||||||
|
bool recursive);
|
||||||
|
|
||||||
int GetNetworkIpAddress();
|
int GetNetworkIpAddress();
|
||||||
int GetNetworkPrefixLength();
|
int GetNetworkPrefixLength();
|
||||||
int GetNetworkGateway();
|
int GetNetworkGateway();
|
||||||
|
|
|
@ -10,6 +10,8 @@ static constexpr jint JNI_VERSION = JNI_VERSION_1_6;
|
||||||
|
|
||||||
static JavaVM* s_java_vm;
|
static JavaVM* s_java_vm;
|
||||||
|
|
||||||
|
static jclass s_string_class;
|
||||||
|
|
||||||
static jclass s_native_library_class;
|
static jclass s_native_library_class;
|
||||||
static jmethodID s_display_alert_msg;
|
static jmethodID s_display_alert_msg;
|
||||||
static jmethodID s_do_rumble;
|
static jmethodID s_do_rumble;
|
||||||
|
@ -47,6 +49,7 @@ static jmethodID s_content_handler_delete;
|
||||||
static jmethodID s_content_handler_get_size_and_is_directory;
|
static jmethodID s_content_handler_get_size_and_is_directory;
|
||||||
static jmethodID s_content_handler_get_display_name;
|
static jmethodID s_content_handler_get_display_name;
|
||||||
static jmethodID s_content_handler_get_child_names;
|
static jmethodID s_content_handler_get_child_names;
|
||||||
|
static jmethodID s_content_handler_do_file_search;
|
||||||
|
|
||||||
static jclass s_network_helper_class;
|
static jclass s_network_helper_class;
|
||||||
static jmethodID s_network_helper_get_network_ip_address;
|
static jmethodID s_network_helper_get_network_ip_address;
|
||||||
|
@ -78,6 +81,11 @@ JNIEnv* GetEnvForThread()
|
||||||
return owned.env;
|
return owned.env;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jclass GetStringClass()
|
||||||
|
{
|
||||||
|
return s_string_class;
|
||||||
|
}
|
||||||
|
|
||||||
jclass GetNativeLibraryClass()
|
jclass GetNativeLibraryClass()
|
||||||
{
|
{
|
||||||
return s_native_library_class;
|
return s_native_library_class;
|
||||||
|
@ -228,6 +236,11 @@ jmethodID GetContentHandlerGetChildNames()
|
||||||
return s_content_handler_get_child_names;
|
return s_content_handler_get_child_names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jmethodID GetContentHandlerDoFileSearch()
|
||||||
|
{
|
||||||
|
return s_content_handler_do_file_search;
|
||||||
|
}
|
||||||
|
|
||||||
jclass GetNetworkHelperClass()
|
jclass GetNetworkHelperClass()
|
||||||
{
|
{
|
||||||
return s_network_helper_class;
|
return s_network_helper_class;
|
||||||
|
@ -262,6 +275,9 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
||||||
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION) != JNI_OK)
|
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION) != JNI_OK)
|
||||||
return JNI_ERR;
|
return JNI_ERR;
|
||||||
|
|
||||||
|
const jclass string_class = env->FindClass("java/lang/String");
|
||||||
|
s_string_class = reinterpret_cast<jclass>(env->NewGlobalRef(string_class));
|
||||||
|
|
||||||
const jclass native_library_class = env->FindClass("org/dolphinemu/dolphinemu/NativeLibrary");
|
const jclass native_library_class = env->FindClass("org/dolphinemu/dolphinemu/NativeLibrary");
|
||||||
s_native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class));
|
s_native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class));
|
||||||
s_display_alert_msg = env->GetStaticMethodID(s_native_library_class, "displayAlertMsg",
|
s_display_alert_msg = env->GetStaticMethodID(s_native_library_class, "displayAlertMsg",
|
||||||
|
@ -331,6 +347,9 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
||||||
s_content_handler_class, "getDisplayName", "(Ljava/lang/String;)Ljava/lang/String;");
|
s_content_handler_class, "getDisplayName", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||||
s_content_handler_get_child_names = env->GetStaticMethodID(
|
s_content_handler_get_child_names = env->GetStaticMethodID(
|
||||||
s_content_handler_class, "getChildNames", "(Ljava/lang/String;Z)[Ljava/lang/String;");
|
s_content_handler_class, "getChildNames", "(Ljava/lang/String;Z)[Ljava/lang/String;");
|
||||||
|
s_content_handler_do_file_search =
|
||||||
|
env->GetStaticMethodID(s_content_handler_class, "doFileSearch",
|
||||||
|
"(Ljava/lang/String;[Ljava/lang/String;Z)[Ljava/lang/String;");
|
||||||
|
|
||||||
const jclass network_helper_class =
|
const jclass network_helper_class =
|
||||||
env->FindClass("org/dolphinemu/dolphinemu/utils/NetworkHelper");
|
env->FindClass("org/dolphinemu/dolphinemu/utils/NetworkHelper");
|
||||||
|
|
|
@ -10,6 +10,8 @@ namespace IDCache
|
||||||
{
|
{
|
||||||
JNIEnv* GetEnvForThread();
|
JNIEnv* GetEnvForThread();
|
||||||
|
|
||||||
|
jclass GetStringClass();
|
||||||
|
|
||||||
jclass GetNativeLibraryClass();
|
jclass GetNativeLibraryClass();
|
||||||
jmethodID GetDisplayAlertMsg();
|
jmethodID GetDisplayAlertMsg();
|
||||||
jmethodID GetDoRumble();
|
jmethodID GetDoRumble();
|
||||||
|
@ -47,6 +49,7 @@ jmethodID GetContentHandlerDelete();
|
||||||
jmethodID GetContentHandlerGetSizeAndIsDirectory();
|
jmethodID GetContentHandlerGetSizeAndIsDirectory();
|
||||||
jmethodID GetContentHandlerGetDisplayName();
|
jmethodID GetContentHandlerGetDisplayName();
|
||||||
jmethodID GetContentHandlerGetChildNames();
|
jmethodID GetContentHandlerGetChildNames();
|
||||||
|
jmethodID GetContentHandlerDoFileSearch();
|
||||||
|
|
||||||
jclass GetNetworkHelperClass();
|
jclass GetNetworkHelperClass();
|
||||||
jmethodID GetNetworkHelperGetNetworkIpAddress();
|
jmethodID GetNetworkHelperGetNetworkIpAddress();
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
#include "Common/CommonPaths.h"
|
#include "Common/CommonPaths.h"
|
||||||
#include "Common/FileSearch.h"
|
#include "Common/FileSearch.h"
|
||||||
|
@ -15,6 +16,10 @@
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
#define HAS_STD_FILESYSTEM
|
#define HAS_STD_FILESYSTEM
|
||||||
#else
|
#else
|
||||||
|
#ifdef ANDROID
|
||||||
|
#include "jni/AndroidCommon/AndroidCommon.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "Common/CommonFuncs.h"
|
#include "Common/CommonFuncs.h"
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
|
@ -24,36 +29,30 @@ namespace Common
|
||||||
{
|
{
|
||||||
#ifndef HAS_STD_FILESYSTEM
|
#ifndef HAS_STD_FILESYSTEM
|
||||||
|
|
||||||
static std::vector<std::string>
|
static void FileSearchWithTest(const std::string& directory, bool recursive,
|
||||||
FileSearchWithTest(const std::vector<std::string>& directories, bool recursive,
|
std::vector<std::string>* result_out,
|
||||||
std::function<bool(const File::FSTEntry&)> callback)
|
std::function<bool(const File::FSTEntry&)> callback)
|
||||||
{
|
{
|
||||||
std::vector<std::string> result;
|
File::FSTEntry top = File::ScanDirectoryTree(directory, recursive);
|
||||||
for (const std::string& directory : directories)
|
|
||||||
{
|
|
||||||
File::FSTEntry top = File::ScanDirectoryTree(directory, recursive);
|
|
||||||
|
|
||||||
std::function<void(File::FSTEntry&)> DoEntry;
|
const std::function<void(File::FSTEntry&)> DoEntry = [&](File::FSTEntry& entry) {
|
||||||
DoEntry = [&](File::FSTEntry& entry) {
|
if (callback(entry))
|
||||||
if (callback(entry))
|
result_out->push_back(entry.physicalName);
|
||||||
result.push_back(entry.physicalName);
|
for (auto& child : entry.children)
|
||||||
for (auto& child : entry.children)
|
|
||||||
DoEntry(child);
|
|
||||||
};
|
|
||||||
for (auto& child : top.children)
|
|
||||||
DoEntry(child);
|
DoEntry(child);
|
||||||
}
|
};
|
||||||
// remove duplicates
|
|
||||||
std::sort(result.begin(), result.end());
|
for (auto& child : top.children)
|
||||||
result.erase(std::unique(result.begin(), result.end()), result.end());
|
DoEntry(child);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> DoFileSearch(const std::vector<std::string>& directories,
|
std::vector<std::string> DoFileSearch(const std::vector<std::string>& directories,
|
||||||
const std::vector<std::string>& exts, bool recursive)
|
const std::vector<std::string>& exts, bool recursive)
|
||||||
{
|
{
|
||||||
|
std::vector<std::string> result;
|
||||||
|
|
||||||
bool accept_all = exts.empty();
|
bool accept_all = exts.empty();
|
||||||
return FileSearchWithTest(directories, recursive, [&](const File::FSTEntry& entry) {
|
const auto callback = [&exts, accept_all](const File::FSTEntry& entry) {
|
||||||
if (accept_all)
|
if (accept_all)
|
||||||
return true;
|
return true;
|
||||||
if (entry.isDirectory)
|
if (entry.isDirectory)
|
||||||
|
@ -63,7 +62,34 @@ std::vector<std::string> DoFileSearch(const std::vector<std::string>& directorie
|
||||||
return name.length() >= ext.length() &&
|
return name.length() >= ext.length() &&
|
||||||
strcasecmp(name.c_str() + name.length() - ext.length(), ext.c_str()) == 0;
|
strcasecmp(name.c_str() + name.length() - ext.length(), ext.c_str()) == 0;
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
|
|
||||||
|
for (const std::string& directory : directories)
|
||||||
|
{
|
||||||
|
#ifdef ANDROID
|
||||||
|
// While File::ScanDirectoryTree (which is called in FileSearchWithTest) does handle Android
|
||||||
|
// content correctly, having a specialized implementation of DoFileSearch for Android content
|
||||||
|
// provides a much needed performance boost. Also, this specialized implementation will be
|
||||||
|
// required if we in the future replace the use of File::ScanDirectoryTree with std::filesystem.
|
||||||
|
if (IsPathAndroidContent(directory))
|
||||||
|
{
|
||||||
|
const std::vector<std::string> partial_result =
|
||||||
|
DoFileSearchAndroidContent(directory, exts, recursive);
|
||||||
|
|
||||||
|
result.insert(result.end(), std::make_move_iterator(partial_result.begin()),
|
||||||
|
std::make_move_iterator(partial_result.end()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
FileSearchWithTest(directory, recursive, &result, callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove duplicates
|
||||||
|
std::sort(result.begin(), result.end());
|
||||||
|
result.erase(std::unique(result.begin(), result.end()), result.end());
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
Loading…
Reference in New Issue