mirror of
https://github.com/joel16/VitaShell.git
synced 2024-11-23 03:39:39 +00:00
Added natural sorting for filenames.
This commit is contained in:
parent
6c2c40caab
commit
4a31ac8100
@ -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
|
||||
|
@ -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 ###
|
||||
|
22
archive.c
22
archive.c
@ -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);
|
||||
|
@ -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
30
file.c
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
|
@ -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
178
strnatcmp.c
Normal 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
31
strnatcmp.h
Normal 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);
|
Loading…
Reference in New Issue
Block a user