summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDr.Smile <vabnick@gmail.com>2021-11-11 05:42:40 +0300
committerDr.Smile <vabnick@gmail.com>2022-03-31 17:00:21 +0300
commitf664ced049394e2a5d4300ba526e206df73ec729 (patch)
tree7c527c1e81c570289819f913c85b03e6fc32734f
parent42f1fa1b2e5128f8dbb99b7da5f2665b78de0046 (diff)
downloadlibass-f664ced049394e2a5d4300ba526e206df73ec729.tar.bz2
libass-f664ced049394e2a5d4300ba526e206df73ec729.tar.xz
Add partial unicode support for Windows
-rw-r--r--libass/Makefile.am3
-rw-r--r--libass/ass.c9
-rw-r--r--libass/ass.h19
-rw-r--r--libass/ass_filesystem.c412
-rw-r--r--libass/ass_filesystem.h44
-rw-r--r--libass/ass_fontselect.c40
-rw-r--r--libass/ass_library.h4
7 files changed, 497 insertions, 34 deletions
diff --git a/libass/Makefile.am b/libass/Makefile.am
index a088130..465ecd0 100644
--- a/libass/Makefile.am
+++ b/libass/Makefile.am
@@ -24,7 +24,8 @@ SRC_CORETEXT = ass_coretext.c ass_coretext.h
lib_LTLIBRARIES = libass.la
libass_la_SOURCES = ass.h ass.c ass_types.h ass_utils.h ass_utils.c \
ass_compat.h ass_string.h ass_string.c ass_strtod.c \
- ass_library.h ass_library.c ass_cache.h ass_cache.c ass_cache_template.h \
+ ass_filesystem.h ass_filesystem.c ass_library.h ass_library.c \
+ ass_cache.h ass_cache.c ass_cache_template.h \
ass_font.h ass_font.c ass_fontselect.h ass_fontselect.c \
ass_render.h ass_render.c ass_render_api.c \
ass_parse.h ass_parse.c ass_priv.h ass_shaper.h ass_shaper.c \
diff --git a/libass/ass.c b/libass/ass.c
index ba60eda..b9eac1b 100644
--- a/libass/ass.c
+++ b/libass/ass.c
@@ -1238,17 +1238,18 @@ out:
/**
* \brief read file contents into newly allocated buffer
* \param fname file name
+ * \param hint file name origin
* \param bufsize out: file size
* \return pointer to file contents. Caller is responsible for its deallocation.
*/
-char *read_file(ASS_Library *library, char *fname, size_t *bufsize)
+char *read_file(ASS_Library *library, const char *fname, FileNameSource hint, size_t *bufsize)
{
int res;
long sz;
long bytes_read;
char *buf;
- FILE *fp = fopen(fname, "rb");
+ FILE *fp = ass_open_file(fname, hint);
if (!fp) {
ass_msg(library, MSGL_WARN,
"ass_read_file(%s): fopen failed", fname);
@@ -1373,7 +1374,7 @@ static char *read_file_recode(ASS_Library *library, char *fname,
char *buf;
size_t bufsize;
- buf = read_file(library, fname, &bufsize);
+ buf = read_file(library, fname, FN_EXTERNAL, &bufsize);
if (!buf)
return 0;
#ifdef CONFIG_ICONV
@@ -1429,7 +1430,7 @@ int ass_read_styles(ASS_Track *track, char *fname, char *codepage)
ParserState old_state;
size_t sz;
- buf = read_file(track->library, fname, &sz);
+ buf = read_file(track->library, fname, FN_EXTERNAL, &sz);
if (!buf)
return 1;
#ifdef CONFIG_ICONV
diff --git a/libass/ass.h b/libass/ass.h
index 60b8453..18aa419 100644
--- a/libass/ass.h
+++ b/libass/ass.h
@@ -24,7 +24,7 @@
#include <stdarg.h>
#include "ass_types.h"
-#define LIBASS_VERSION 0x01502001
+#define LIBASS_VERSION 0x01502002
#ifdef __cplusplus
extern "C" {
@@ -283,6 +283,11 @@ void ass_library_done(ASS_Library *priv);
* Optional directory that will be scanned for fonts. The fonts
* found are used for font lookup.
* NOTE: A valid font directory is not needed to support embedded fonts.
+ * On Microsoft Windows, when using WIN32-APIs, fonts_dir must be in either
+ * UTF-8 mixed with lone or paired UTF-16 surrogates encoded like in CESU-8
+ * or the encoding accepted by fopen with the former taking precedence
+ * if both versions are valid and exist.
+ * On all other systems there is no need for special considerations like that.
*
* \param priv library handle
* \param fonts_dir directory with additional fonts
@@ -510,7 +515,7 @@ void ass_get_available_font_providers(ASS_Library *priv,
* If the requested fontprovider does not exist or fails to initialize, the
* behavior is the same as when ASS_FONTPROVIDER_NONE was passed.
* \param config path to fontconfig configuration file, or NULL. Only relevant
- * if fontconfig is used.
+ * if fontconfig is used. The encoding must match the one accepted by fontconfig.
* \param update whether fontconfig cache should be built/updated now. Only
* relevant if fontconfig is used.
*
@@ -701,6 +706,11 @@ void ass_flush_events(ASS_Track *track);
* \param fname file name
* \param codepage encoding (iconv format)
* \return newly allocated track or NULL on failure
+ * NOTE: On Microsoft Windows, when using WIN32-APIs, fname must be in either
+ * UTF-8 mixed with lone or paired UTF-16 surrogates encoded like in CESU-8
+ * or the encoding accepted by fopen with the former taking precedence
+ * if both versions are valid and exist.
+ * On all other systems there is no need for special considerations like that.
*/
ASS_Track *ass_read_file(ASS_Library *library, char *fname,
char *codepage);
@@ -720,6 +730,11 @@ ASS_Track *ass_read_memory(ASS_Library *library, char *buf,
* \param fname file name
* \param codepage encoding (iconv format)
* \return 0 on success
+ * NOTE: On Microsoft Windows, when using WIN32-APIs, fname must be in either
+ * UTF-8 mixed with lone or paired UTF-16 surrogates encoded like in CESU-8
+ * or the encoding accepted by fopen with the former taking precedence
+ * if both versions are valid and exist.
+ * On all other systems there is no need for special considerations like that.
*/
int ass_read_styles(ASS_Track *track, char *fname, char *codepage);
diff --git a/libass/ass_filesystem.c b/libass/ass_filesystem.c
new file mode 100644
index 0000000..fa7bbab
--- /dev/null
+++ b/libass/ass_filesystem.c
@@ -0,0 +1,412 @@
+/*
+ * Copyright (C) 2021 libass contributors
+ *
+ * This file is part of libass.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+#include "ass_compat.h"
+
+#include "ass_filesystem.h"
+#include "ass_utils.h"
+
+
+static inline bool check_add_size(size_t *size, size_t amount)
+{
+ size_t res = *size + amount;
+ if (res < amount)
+ return false;
+ *size = res;
+ return true;
+}
+
+#define NAME_BUF_SIZE 256
+// NAME_BUF_SIZE + 2 <= SIZE_MAX
+
+static bool alloc_path(ASS_Dir *dir, size_t size)
+{
+ if (size <= dir->max_path)
+ return true;
+ if (!check_add_size(&size, NAME_BUF_SIZE))
+ return false;
+ char *path = realloc(dir->path, size);
+ if (!path)
+ return false;
+ dir->path = path;
+ dir->max_path = size;
+ return true;
+}
+
+
+#if !defined(_WIN32) || defined(__CYGWIN__)
+
+#include <dirent.h>
+
+FILE *ass_open_file(const char *filename, FileNameSource hint)
+{
+ return fopen(filename, "rb");
+}
+
+bool ass_open_dir(ASS_Dir *dir, const char *path)
+{
+ dir->handle = NULL;
+ dir->path = NULL;
+ dir->name = NULL;
+
+ size_t len = strlen(path);
+ if (len && path[len - 1] == '/')
+ len--;
+
+ size_t size = NAME_BUF_SIZE + 2;
+ if (!check_add_size(&size, len))
+ return false;
+ dir->path = malloc(size);
+ if (!dir->path)
+ return false;
+ dir->max_path = size;
+ memcpy(dir->path, path, len);
+ dir->path[len] = '/';
+ dir->prefix = len + 1;
+
+ dir->handle = opendir(path);
+ if (dir->handle)
+ return true;
+
+ free(dir->path);
+ dir->path = NULL;
+ return false;
+}
+
+const char *ass_read_dir(ASS_Dir *dir)
+{
+ struct dirent *entry = readdir(dir->handle);
+ return dir->name = entry ? entry->d_name : NULL;
+}
+
+const char *ass_current_file_path(ASS_Dir *dir)
+{
+ size_t size = dir->prefix + 1, len = strlen(dir->name);
+ if (!check_add_size(&size, len) || !alloc_path(dir, size))
+ return NULL;
+ memcpy(dir->path + dir->prefix, dir->name, len + 1);
+ return dir->path;
+}
+
+void ass_close_dir(ASS_Dir *dir)
+{
+ if (dir->handle)
+ closedir(dir->handle);
+ free(dir->path);
+ dir->handle = NULL;
+ dir->path = NULL;
+ dir->name = NULL;
+}
+
+
+#else // Windows
+
+#include <windows.h>
+#include "ass_directwrite.h" // for ASS_WINAPI_DESKTOP
+
+
+static const uint8_t wtf8_len_table[256] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1x
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2x
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3x
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4x
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5x
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6x
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7x
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
+
+ 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // Cx
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // Dx
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
+ 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
+};
+
+static const uint8_t wtf8_len4_range[5][2] = {
+ { 0x90, 0x30 }, { 0x80, 0x40 }, { 0x80, 0x40 }, { 0x80, 0x40 }, { 0x80, 0x10 }
+};
+
+static inline bool check_add_size_wtf8to16(size_t *size, size_t len)
+{
+ return len > SIZE_MAX / sizeof(WCHAR) ? false : check_add_size(size, len * sizeof(WCHAR));
+}
+
+// does not append zero termination implicitly
+// expects preallocated buffer (use check_add_size_wtf8to16() for size)
+static WCHAR *convert_wtf8to16(WCHAR *dst, ASS_StringView src)
+{
+ const char *str = src.str;
+ for (const char *end = str + src.len; str < end; str++) {
+ uint8_t ch = *str;
+ switch(wtf8_len_table[ch]) {
+ case 1: // 1 -> 1w
+ *dst++ = ch;
+ continue;
+
+ case 2: // 2 -> 1w
+ if (str + 1 < end) {
+ uint8_t next = *++str;
+ if ((next & 0xC0) != 0x80)
+ return NULL;
+ *dst++ = (ch & 0x1F) << 6 | (next & 0x3F);
+ continue;
+ }
+ return NULL;
+
+ case 3: // 3 -> 1w
+ if (str + 2 < end) {
+ ch &= 0xF;
+ uint8_t next1 = *++str, next2 = *++str;
+ if (next1 < (ch ? 0x80 : 0xA0) || next1 >= 0xC0 || (next2 & 0xC0) != 0x80)
+ return NULL;
+ *dst++ = ch << 12 | (next1 & 0x3F) << 6 | (next2 & 0x3F);
+ continue;
+ }
+ return NULL;
+
+ case 4: // 4 -> 2w
+ if (str + 3 < end) {
+ ch &= 0x7;
+ uint8_t next1 = *++str, next2 = *++str, next3 = *++str;
+ if ((uint8_t) (next1 - wtf8_len4_range[ch][0]) >= wtf8_len4_range[ch][1] ||
+ (next2 & 0xC0) != 0x80 || (next3 & 0xC0) != 0x80)
+ return NULL;
+ *dst++ = 0xD800 | ((ch << 8 | (next1 & 0x3F) << 2) - 0x40) | (next2 & 0x3F) >> 4;
+ *dst++ = 0xDC00 | (next2 & 0xF) << 6 | (next3 & 0x3F);
+ continue;
+ }
+ return NULL;
+
+ default:
+ return NULL;
+ }
+ }
+ return dst;
+}
+
+static inline bool check_add_size_wtf16to8(size_t *size, size_t wlen)
+{
+ enum { max_bytes_per_wchar = 3 };
+ return wlen > SIZE_MAX / max_bytes_per_wchar ? false :
+ check_add_size(size, max_bytes_per_wchar * wlen);
+}
+
+// does not append zero termination implicitly
+// expects preallocated buffer (use check_add_size_wtf16to8() for size)
+static char *convert_wtf16to8(char *dst, const WCHAR *src, size_t wlen)
+{
+ for (const WCHAR *end = src + wlen; src < end; src++) {
+ uint16_t wch = *src;
+ if (wch < 0x80) {
+ // 1w -> 1
+ *dst++ = wch;
+ continue;
+ }
+ if (wch < 0x800) {
+ // 1w -> 2
+ *dst++ = 0xC0 | wch >> 6;
+ *dst++ = 0x80 | (wch & 0x3F);
+ continue;
+ }
+ if (wch >= 0xD800 && wch < 0xDC00 && src + 1 < end) {
+ uint16_t next = src[1];
+ if (next >= 0xDC00 && next < 0xE000) { // correctly paired surrogates
+ src++; // 2w -> 4
+ uint32_t full = (uint32_t) ((wch & 0x3FF) + 0x40) << 10 | (next & 0x3FF);
+ *dst++ = 0xF0 | full >> 18;
+ *dst++ = 0x80 | ((full >> 12) & 0x3F);
+ *dst++ = 0x80 | ((full >> 6) & 0x3F);
+ *dst++ = 0x80 | (full & 0x3F);
+ continue;
+ }
+ }
+ // unpaired surrogates fall through here
+ // 1w -> 3
+ *dst++ = 0xE0 | wch >> 12;
+ *dst++ = 0x80 | ((wch >> 6) & 0x3F);
+ *dst++ = 0x80 | (wch & 0x3F);
+ }
+ return dst;
+}
+
+static FILE *open_file_wtf8(const char *filename)
+{
+ size_t size = sizeof(WCHAR);
+ ASS_StringView name = { filename, strlen(filename) };
+ if (!check_add_size_wtf8to16(&size, name.len))
+ return NULL;
+ WCHAR *wname = malloc(size);
+ if (!wname)
+ return NULL;
+ WCHAR *end = convert_wtf8to16(wname, name);
+ FILE *fp = NULL;
+ if (end) {
+ *end = L'\0';
+ fp = _wfopen(wname, L"rb");
+ }
+ free(wname);
+ return fp;
+}
+
+FILE *ass_open_file(const char *filename, FileNameSource hint)
+{
+ FILE *fp = open_file_wtf8(filename);
+ if (fp || hint == FN_DIR_LIST)
+ return fp;
+ return fopen(filename, "rb");
+}
+
+
+static const WCHAR dir_tail[] = L"\\*";
+
+static bool append_tail(WCHAR *wpath, size_t wlen)
+{
+ size_t offs = 0;
+ if (wlen == 2 && wpath[1] == L':')
+ offs = 1;
+ else if (wlen && (wpath[wlen - 1] == L'/' || wpath[wlen - 1] == L'\\'))
+ offs = 1;
+ memcpy(wpath + wlen, dir_tail + offs, sizeof(dir_tail) - offs);
+ return !offs;
+}
+
+static bool open_dir_wtf8(ASS_Dir *dir, ASS_StringView path)
+{
+ assert(dir->handle == INVALID_HANDLE_VALUE && !dir->path);
+
+ size_t size = sizeof(dir_tail);
+ if (!check_add_size_wtf8to16(&size, path.len))
+ return false;
+
+ WCHAR *wpath = malloc(size);
+ if (!wpath)
+ return false;
+
+ bool add_separator;
+ WIN32_FIND_DATAW data;
+ WCHAR *end = convert_wtf8to16(wpath, path);
+ if (end) {
+ add_separator = append_tail(wpath, end - wpath);
+ dir->handle = FindFirstFileExW(wpath, FindExInfoBasic, &data, FindExSearchNameMatch, NULL, 0);
+ }
+ free(wpath);
+ if (dir->handle == INVALID_HANDLE_VALUE)
+ return false;
+
+ size = NAME_BUF_SIZE + 2;
+ size_t wlen = wcslen(data.cFileName);
+ if (!check_add_size(&size, path.len) || !check_add_size_wtf16to8(&size, wlen) ||
+ !(dir->path = malloc(size))) {
+ FindClose(dir->handle);
+ return false;
+ }
+ dir->max_path = size;
+ memcpy(dir->path, path.str, path.len);
+ if (add_separator)
+ dir->path[path.len++] = '\\';
+ *convert_wtf16to8(dir->path + path.len, data.cFileName, wlen) = '\0';
+ dir->prefix = path.len;
+ return true;
+}
+
+bool ass_open_dir(ASS_Dir *dir, const char *path)
+{
+ dir->handle = INVALID_HANDLE_VALUE;
+ dir->path = NULL;
+ dir->name = NULL;
+
+ size_t len = strlen(path);
+ if (open_dir_wtf8(dir, (ASS_StringView) { path, len }))
+ return true;
+
+ if (len > INT_MAX)
+ return false;
+
+ UINT cp = CP_ACP;
+#if ASS_WINAPI_DESKTOP
+ if (!AreFileApisANSI())
+ cp = CP_OEMCP;
+#endif
+ size_t wlen = MultiByteToWideChar(cp, 0, path, len, NULL, 0);
+ if (wlen > (SIZE_MAX - sizeof(dir_tail)) / sizeof(WCHAR))
+ return false;
+ WCHAR *wpath = malloc(wlen * sizeof(WCHAR) + sizeof(dir_tail));
+ if (!wpath)
+ return false;
+ MultiByteToWideChar(cp, 0, path, len, wpath, wlen);
+ bool add_separator = append_tail(wpath, wlen);
+
+ WIN32_FIND_DATAW data;
+ dir->handle = FindFirstFileExW(wpath, FindExInfoBasic, &data, FindExSearchNameMatch, NULL, 0);
+ if (dir->handle == INVALID_HANDLE_VALUE) {
+ free(wpath);
+ return false;
+ }
+ size_t size = NAME_BUF_SIZE + 2, wlen1 = wcslen(data.cFileName);
+ if (!check_add_size_wtf16to8(&size, wlen) || !check_add_size_wtf16to8(&size, wlen1) ||
+ !(dir->path = malloc(size))) {
+ FindClose(dir->handle);
+ return false;
+ }
+ dir->max_path = size;
+ char *ptr = convert_wtf16to8(dir->path, wpath, wlen);
+ if (add_separator)
+ *ptr++ = '\\';
+ convert_wtf16to8(ptr, data.cFileName, wlen1 + 1);
+ dir->prefix = ptr - dir->path;
+ return true;
+}
+
+const char *ass_read_dir(ASS_Dir *dir)
+{
+ if (!dir->name) // first invocation
+ return dir->name = dir->path + dir->prefix;
+
+ WIN32_FIND_DATAW data;
+ while (FindNextFileW(dir->handle, &data)) {
+ size_t size = dir->prefix + 1, wlen = wcslen(data.cFileName);
+ if (!check_add_size_wtf16to8(&size, wlen) || !alloc_path(dir, size))
+ continue;
+ convert_wtf16to8(dir->path + dir->prefix, data.cFileName, wlen + 1);
+ return dir->name = dir->path + dir->prefix;
+ }
+ return NULL;
+}
+
+const char *ass_current_file_path(ASS_Dir *dir)
+{
+ return dir->path;
+}
+
+void ass_close_dir(ASS_Dir *dir)
+{
+ if (dir->handle != INVALID_HANDLE_VALUE)
+ FindClose(dir->handle);
+ free(dir->path);
+ dir->handle = INVALID_HANDLE_VALUE;
+ dir->path = NULL;
+ dir->name = NULL;
+}
+
+#endif // Windows
diff --git a/libass/ass_filesystem.h b/libass/ass_filesystem.h
new file mode 100644
index 0000000..88742da
--- /dev/null
+++ b/libass/ass_filesystem.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 libass contributors
+ *
+ * This file is part of libass.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdbool.h>
+
+#ifndef LIBASS_FILESYSTEM_H
+#define LIBASS_FILESYSTEM_H
+
+typedef enum {
+ FN_EXTERNAL,
+ FN_DIR_LIST,
+} FileNameSource;
+
+FILE *ass_open_file(const char *filename, FileNameSource hint);
+
+typedef struct {
+ void *handle;
+ char *path;
+ size_t prefix, max_path;
+ const char *name;
+} ASS_Dir;
+
+bool ass_open_dir(ASS_Dir *dir, const char *path);
+const char *ass_read_dir(ASS_Dir *dir);
+const char *ass_current_file_path(ASS_Dir *dir);
+void ass_close_dir(ASS_Dir *dir);
+
+#endif /* LIBASS_FILESYSTEM_H */
diff --git a/libass/ass_fontselect.c b/libass/ass_fontselect.c
index 02b8d9c..c229189 100644
--- a/libass/ass_fontselect.c
+++ b/libass/ass_fontselect.c
@@ -31,7 +31,6 @@
#include <limits.h>
#include <ft2build.h>
#include <sys/types.h>
-#include <dirent.h>
#include FT_FREETYPE_H
#include FT_SFNT_NAMES_H
#include FT_TRUETYPE_IDS_H
@@ -40,6 +39,7 @@
#include "ass_utils.h"
#include "ass.h"
#include "ass_library.h"
+#include "ass_filesystem.h"
#include "ass_fontselect.h"
#include "ass_fontconfig.h"
#include "ass_coretext.h"
@@ -168,39 +168,27 @@ static ASS_FontProviderFuncs ft_funcs = {
static void load_fonts_from_dir(ASS_Library *library, const char *dir)
{
- DIR *d = opendir(dir);
- if (!d)
+ ASS_Dir d;
+ if (!ass_open_dir(&d, dir))
return;
- size_t dirlen = strlen(dir);
- size_t namemax = 0;
- char *namebuf = NULL;
- while (1) {
- struct dirent *entry = readdir(d);
- if (!entry)
+ while (true) {
+ const char *name = ass_read_dir(&d);
+ if (!name)
break;
- if (entry->d_name[0] == '.')
+ if (name[0] == '.')
continue;
- size_t namelen = dirlen + strlen(entry->d_name) + 2u;
- if (namelen < 2 || namelen - 2 < dirlen)
+ const char *path = ass_current_file_path(&d);
+ if (!path)
continue;
- if (namelen > namemax) {
- size_t newlen = FFMAX(2048, namelen + FFMIN(256, SIZE_MAX - namelen));
- if (ASS_REALLOC_ARRAY(namebuf, newlen))
- namemax = newlen;
- else
- continue;
- }
- snprintf(namebuf, namemax, "%s/%s", dir, entry->d_name);
- size_t bufsize = 0;
- ass_msg(library, MSGL_INFO, "Loading font file '%s'", namebuf);
- void *data = read_file(library, namebuf, &bufsize);
+ ass_msg(library, MSGL_INFO, "Loading font file '%s'", path);
+ size_t size = 0;
+ void *data = read_file(library, path, FN_DIR_LIST, &size);
if (data) {
- ass_add_font(library, entry->d_name, data, bufsize);
+ ass_add_font(library, name, data, size);
free(data);
}
}
- free(namebuf);
- closedir(d);
+ ass_close_dir(&d);
}
/**
diff --git a/libass/ass_library.h b/libass/ass_library.h
index 674e06c..e30609f 100644
--- a/libass/ass_library.h
+++ b/libass/ass_library.h
@@ -21,6 +21,8 @@
#include <stdarg.h>
+#include "ass_filesystem.h"
+
typedef struct {
char *name;
char *data;
@@ -38,6 +40,6 @@ struct ass_library {
void *msg_callback_data;
};
-char *read_file(struct ass_library *library, char *fname, size_t *bufsize);
+char *read_file(struct ass_library *library, const char *fname, FileNameSource hint, size_t *bufsize);
#endif /* LIBASS_LIBRARY_H */