findFiles method
Implementation
Future<List<Map<String, dynamic>>> findFiles(String startPath, String pattern,
{int maxDepth = -1}) async {
final rootInfo = await resolvePath(startPath);
if (rootInfo['type'] != 'folder') return [];
final treeData = await getFlatFolderTree(rootInfo['uuid']);
final rawFolders = treeData['folders'] as List? ?? [];
final rawFiles =
(treeData['files'] as List?) ?? (treeData['uploads'] as List?) ?? [];
final folderMap = <String, Map<String, dynamic>>{};
for (var f in rawFolders) {
try {
String uuid, encName, parent;
if (f is List) {
if (f.length < 3) continue;
uuid = f[0];
encName = f[1];
parent = f[2];
} else {
if (f['deleted'] == true || f['trash'] == true) continue;
uuid = f['uuid'];
encName = f['name'];
parent = f['parent'];
}
var decName = await crypto.tryDecrypt(encName, masterKeys);
if (decName.startsWith('{')) {
decName = json.decode(decName)['name'];
}
folderMap[uuid] = {'name': decName, 'parent': parent};
} catch (_) {}
}
final results = <Map<String, dynamic>>[];
String? getFullPath(String? parentUuid) {
var parts = <String>[];
var curr = parentUuid;
var seen = <String>{};
while (curr != null && curr != rootInfo['uuid']) {
if (seen.contains(curr)) return null;
seen.add(curr);
if (!folderMap.containsKey(curr)) return null;
final f = folderMap[curr]!;
parts.add(f['name']);
curr = f['parent'];
}
if (curr == null && rootInfo['uuid'] != 'root') return null;
return p.join(startPath, parts.reversed.join('/'));
}
// Glob matching: translate `*`/`?` and escape every other character so
// regex metacharacters in the pattern are matched literally.
final globBuf = StringBuffer('^');
for (final ch in pattern.split('')) {
if (ch == '*') {
globBuf.write('.*');
} else if (ch == '?') {
globBuf.write('.');
} else {
globBuf.write(RegExp.escape(ch));
}
}
globBuf.write(r'$');
final globRegex = RegExp(globBuf.toString(), caseSensitive: false);
for (var f in rawFiles) {
try {
String uuid, encMeta, parent;
if (f is List) {
if (f.length < 6) continue;
uuid = f[0];
parent = f[4];
encMeta = f[5];
} else {
if (f['deleted'] == true || f['trash'] == true) continue;
uuid = f['uuid'];
parent = f['parent'];
encMeta = f['metadata'];
}
final meta = json.decode(await crypto.tryDecrypt(encMeta, masterKeys));
final name = meta['name'];
if (!globRegex.hasMatch(name)) continue;
var dirPath = getFullPath(parent);
if (parent == rootInfo['uuid'])
dirPath = startPath;
else if (dirPath == null) continue;
if (maxDepth != -1) {
final relDepth =
dirPath.split('/').length - startPath.split('/').length;
if (relDepth >= maxDepth) continue;
}
results.add({
'uuid': uuid,
'name': name,
'fullPath': p.join(dirPath, name).replaceAll('\\', '/'),
'size': meta['size'] ?? 0,
'lastModified': meta['lastModified'] ?? 0
});
} catch (_) {}
}
return results;
}