Added natural sorting for filenames.

This commit is contained in:
TheFloW 2018-01-25 11:11:08 +01:00
parent 6c2c40caab
commit 4a31ac8100
11 changed files with 260 additions and 45 deletions

View File

@ -100,6 +100,7 @@ add_executable(VitaShell
minizip/zip.c
minizip/ioapi.c
bm.c
strnatcmp.c
audio/vita_audio.c
audio/player.c
audio/id3.c

View File

@ -102,6 +102,8 @@ The english language file is provided in **'VitaShellCustomization.rar'** and av
### Changelog 1.79 ###
- Added support for multi volume rar archives.
- Added support for password encrypted zip archives.
- Added support for file property in archives, now it can show size and contains.
- Added natural sorting for filenames.
- Fixed bug where size of files in archives over 2GB where shown as 16EB.
### Changelog 1.78 ###

View File

@ -555,7 +555,7 @@ int fileListGetArchiveEntries(FileList *list, const char *path, int sort) {
return 0;
}
int getArchivePathInfo(const char *path, uint64_t *size, uint32_t *folders, uint32_t *files) {
int getArchivePathInfo(const char *path, uint64_t *size, uint32_t *folders, uint32_t *files, int (* handler)(const char *path)) {
SceIoStat stat;
memset(&stat, 0, sizeof(SceIoStat));
@ -571,15 +571,18 @@ int getArchivePathInfo(const char *path, uint64_t *size, uint32_t *folders, uint
FileListEntry *entry = list.head->next; // Ignore ..
int i;
for (i = 0; i < list.length - 1; i++) {
for (i = 0; i < list.length - 1; i++, entry = entry->next) {
char *new_path = malloc(strlen(path) + strlen(entry->name) + 2);
snprintf(new_path, MAX_PATH_LENGTH - 1, "%s%s", path, entry->name);
getArchivePathInfo(new_path, size, folders, files);
if (handler && handler(new_path)) {
free(new_path);
continue;
}
getArchivePathInfo(new_path, size, folders, files, handler);
free(new_path);
entry = entry->next;
}
if (folders)
@ -587,6 +590,9 @@ int getArchivePathInfo(const char *path, uint64_t *size, uint32_t *folders, uint
fileListEmpty(&list);
} else {
if (handler && handler(path))
return 1;
if (size)
(*size) += stat.st_size;
@ -632,7 +638,7 @@ int extractArchivePath(const char *src, const char *dst, FileProcessParam *param
FileListEntry *entry = list.head->next; // Ignore ..
int i;
for (i = 0; i < list.length - 1; i++) {
for (i = 0; i < list.length - 1; i++, entry = entry->next) {
char *src_path = malloc(strlen(src) + strlen(entry->name) + 2);
snprintf(src_path, MAX_PATH_LENGTH - 1, "%s%s", src, entry->name);
@ -648,8 +654,6 @@ int extractArchivePath(const char *src, const char *dst, FileProcessParam *param
fileListEmpty(&list);
return ret;
}
entry = entry->next;
}
fileListEmpty(&list);

View File

@ -25,7 +25,7 @@
int fileListGetArchiveEntries(FileList *list, const char *path, int sort);
int getArchivePathInfo(const char *path, uint64_t *size, uint32_t *folders, uint32_t *files);
int getArchivePathInfo(const char *path, uint64_t *size, uint32_t *folders, uint32_t *files, int (* handler)(const char *path));
int extractArchivePath(const char *src, const char *dst, FileProcessParam *param);
int archiveFileGetstat(const char *file, SceIoStat *stat);

30
file.c
View File

@ -22,6 +22,7 @@
#include "file.h"
#include "utils.h"
#include "sha1.h"
#include "strnatcmp.h"
static char *devices[] = {
"gro0:",
@ -747,17 +748,20 @@ void fileListAddEntry(FileList *list, FileListEntry *entry, int sort) {
FileListEntry *p = list->head;
FileListEntry *previous = NULL;
char entry_name[MAX_NAME_LENGTH];
strcpy(entry_name, entry->name);
removeEndSlash(entry_name);
while (p) {
// Get the minimum length without /
int len = MIN(entry->name_length, p->name_length);
if (entry->name[len - 1] == '/' || p->name[len - 1] == '/')
len--;
char p_name[MAX_NAME_LENGTH];
strcpy(p_name, p->name);
removeEndSlash(p_name);
// '..' is always at first
if (strcmp(entry->name, "..") == 0)
if (strcmp(entry_name, "..") == 0)
break;
if (strcmp(p->name, "..") == 0) {
if (strcmp(p_name, "..") == 0) {
previous = p;
p = p->next;
continue;
@ -777,16 +781,14 @@ void fileListAddEntry(FileList *list, FileListEntry *entry, int sort) {
if (sort == SORT_BY_NAME) {
// Sort by name within the same type
if (entry->is_folder == p->is_folder) {
int diff = strncasecmp(entry->name, p->name, len);
if (diff < 0 || (diff == 0 && entry->name_length < p->name_length)) {
if (strnatcasecmp(entry_name, p_name) < 0) {
break;
}
}
} else if (sort == SORT_BY_SIZE) {
// Sort by name for folders
if (entry->is_folder && p->is_folder) {
int diff = strncasecmp(entry->name, p->name, len);
if (diff < 0 || (diff == 0 && entry->name_length < p->name_length)) {
if (strnatcasecmp(entry_name, p_name) < 0) {
break;
}
} else if (!entry->is_folder && !p->is_folder) {
@ -796,8 +798,7 @@ void fileListAddEntry(FileList *list, FileListEntry *entry, int sort) {
// Sort by name for files with the same size
if (entry->size == p->size) {
int diff = strncasecmp(entry->name, p->name, len);
if (diff < 0 || (diff == 0 && entry->name_length < p->name_length)) {
if (strnatcasecmp(entry_name, p_name) < 0) {
break;
}
}
@ -814,8 +815,7 @@ void fileListAddEntry(FileList *list, FileListEntry *entry, int sort) {
// Sort by name for files and folders with the same date
if (entry_tick.tick == p_tick.tick) {
int diff = strncasecmp(entry->name, p->name, len);
if (diff < 0 || (diff == 0 && entry->name_length < p->name_length)) {
if (strnatcasecmp(entry_name, p_name) < 0) {
break;
}
}

View File

@ -242,7 +242,7 @@ int copy_thread(SceSize args_size, CopyArguments *args) {
snprintf(src_path, MAX_PATH_LENGTH - 1, "%s%s", args->copy_list->path, copy_entry->name);
if (args->copy_mode == COPY_MODE_EXTRACT) {
getArchivePathInfo(src_path, &size, &folders, &files);
getArchivePathInfo(src_path, &size, &folders, &files, NULL);
} else {
getPathInfo(src_path, &size, &folders, &files, NULL);
}

View File

@ -139,10 +139,10 @@ int update_extract_thread(SceSize args, void *argp) {
// Get archive path info
uint64_t size = 0;
uint32_t folders = 0, files = 0;
getArchivePathInfo(src_path, &size, &folders, &files);
getArchivePathInfo(src_path, &size, &folders, &files, NULL);
// Update thread
thid = createStartUpdateThread(size + folders*DIRECTORY_SIZE, 1);
thid = createStartUpdateThread(size + folders * DIRECTORY_SIZE, 1);
// Extract process
uint64_t value = 0;

View File

@ -429,7 +429,7 @@ int install_thread(SceSize args_size, InstallArguments *args) {
// Get archive path info
uint64_t size = 0;
uint32_t folders = 0, files = 0;
getArchivePathInfo(src_path, &size, &folders, &files);
getArchivePathInfo(src_path, &size, &folders, &files, NULL);
// Check memory card free space
if (checkMemoryCardFreeSpace(PACKAGE_DIR, size))

View File

@ -110,7 +110,11 @@ static int info_thread(SceSize args_size, InfoArguments *args) {
uint32_t folders = 0, files = 0;
info_done = 0;
getPathInfo(args->path, &size, &folders, &files, propertyCancelHandler);
if (isInArchive()) {
getArchivePathInfo(args->path, &size, &folders, &files, propertyCancelHandler);
} else {
getPathInfo(args->path, &size, &folders, &files, propertyCancelHandler);
}
info_done = 1;
if (folders > 0)
@ -265,23 +269,18 @@ int initPropertyDialog(char *path, FileListEntry *entry) {
// Size & contains
if (entry->is_folder) {
if (isInArchive()) {
property_entries[PROPERTY_ENTRY_SIZE].visibility = PROPERTY_ENTRY_INVISIBLE;
property_entries[PROPERTY_ENTRY_CONTAINS].visibility = PROPERTY_ENTRY_INVISIBLE;
} else {
strcpy(property_size, "...");
strcpy(property_contains, "...");
strcpy(property_size, "...");
strcpy(property_contains, "...");
// Info thread
InfoArguments info_args;
info_args.path = path;
// Info thread
InfoArguments info_args;
info_args.path = path;
info_thid = sceKernelCreateThread("info_thread", (SceKernelThreadEntry)info_thread, 0x10000100, 0x100000, 0, 0, NULL);
if (info_thid >= 0)
sceKernelStartThread(info_thid, sizeof(InfoArguments), &info_args);
property_entries[PROPERTY_ENTRY_CONTAINS].visibility = PROPERTY_ENTRY_VISIBLE;
}
info_thid = sceKernelCreateThread("info_thread", (SceKernelThreadEntry)info_thread, 0x10000100, 0x100000, 0, 0, NULL);
if (info_thid >= 0)
sceKernelStartThread(info_thid, sizeof(InfoArguments), &info_args);
property_entries[PROPERTY_ENTRY_CONTAINS].visibility = PROPERTY_ENTRY_VISIBLE;
// property_entries[PROPERTY_ENTRY_COMPRESSED_SIZE].visibility = PROPERTY_ENTRY_INVISIBLE;
} else {

178
strnatcmp.c Normal file
View File

@ -0,0 +1,178 @@
/* -*- mode: c; c-file-style: "k&r" -*-
strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/* partial change history:
*
* 2004-10-10 mbp: Lift out character type dependencies into macros.
*
* Eric Sosman pointed out that ctype functions take a parameter whose
* value must be that of an unsigned int, even on platforms that have
* negative chars in their default char type.
*/
#include <ctype.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include "strnatcmp.h"
/* These are defined as macros to make it easier to adapt this code to
* different characters types or comparison functions. */
static inline int
nat_isdigit(nat_char a)
{
return isdigit((unsigned char) a);
}
static inline int
nat_isspace(nat_char a)
{
return isspace((unsigned char) a);
}
static inline nat_char
nat_toupper(nat_char a)
{
return toupper((unsigned char) a);
}
static int
compare_right(nat_char const *a, nat_char const *b)
{
int bias = 0;
/* The longest run of digits wins. That aside, the greatest
value wins, but we can't know that it will until we've scanned
both numbers to know that they have the same magnitude, so we
remember it in BIAS. */
for (;; a++, b++) {
if (!nat_isdigit(*a) && !nat_isdigit(*b))
return bias;
else if (!nat_isdigit(*a))
return -1;
else if (!nat_isdigit(*b))
return +1;
else if (*a < *b) {
if (!bias)
bias = -1;
} else if (*a > *b) {
if (!bias)
bias = +1;
} else if (!*a && !*b)
return bias;
}
return 0;
}
static int
compare_left(nat_char const *a, nat_char const *b)
{
/* Compare two left-aligned numbers: the first to have a
different value wins. */
for (;; a++, b++) {
if (!nat_isdigit(*a) && !nat_isdigit(*b))
return 0;
else if (!nat_isdigit(*a))
return -1;
else if (!nat_isdigit(*b))
return +1;
else if (*a < *b)
return -1;
else if (*a > *b)
return +1;
}
return 0;
}
static int strnatcmp0(nat_char const *a, nat_char const *b, int fold_case)
{
int ai, bi;
nat_char ca, cb;
int fractional, result;
assert(a && b);
ai = bi = 0;
while (1) {
ca = a[ai]; cb = b[bi];
/* skip over leading spaces or zeros */
while (nat_isspace(ca))
ca = a[++ai];
while (nat_isspace(cb))
cb = b[++bi];
/* process run of digits */
if (nat_isdigit(ca) && nat_isdigit(cb)) {
fractional = (ca == '0' || cb == '0');
if (fractional) {
if ((result = compare_left(a+ai, b+bi)) != 0)
return result;
} else {
if ((result = compare_right(a+ai, b+bi)) != 0)
return result;
}
}
if (!ca && !cb) {
/* The strings compare the same. Perhaps the caller
will want to call strcmp to break the tie. */
return 0;
}
if (fold_case) {
ca = nat_toupper(ca);
cb = nat_toupper(cb);
}
if (ca < cb)
return -1;
else if (ca > cb)
return +1;
++ai; ++bi;
}
}
int strnatcmp(nat_char const *a, nat_char const *b) {
return strnatcmp0(a, b, 0);
}
/* Compare, recognizing numeric string and ignoring case. */
int strnatcasecmp(nat_char const *a, nat_char const *b) {
return strnatcmp0(a, b, 1);
}

31
strnatcmp.h Normal file
View File

@ -0,0 +1,31 @@
/* -*- mode: c; c-file-style: "k&r" -*-
strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/* CUSTOMIZATION SECTION
*
* You can change this typedef, but must then also change the inline
* functions in strnatcmp.c */
typedef char nat_char;
int strnatcmp(nat_char const *a, nat_char const *b);
int strnatcasecmp(nat_char const *a, nat_char const *b);