From f664ced049394e2a5d4300ba526e206df73ec729 Mon Sep 17 00:00:00 2001 From: "Dr.Smile" Date: Thu, 11 Nov 2021 05:42:40 +0300 Subject: Add partial unicode support for Windows --- libass/Makefile.am | 3 +- libass/ass.c | 9 +- libass/ass.h | 19 ++- libass/ass_filesystem.c | 412 ++++++++++++++++++++++++++++++++++++++++++++++++ libass/ass_filesystem.h | 44 ++++++ libass/ass_fontselect.c | 40 ++--- libass/ass_library.h | 4 +- 7 files changed, 497 insertions(+), 34 deletions(-) create mode 100644 libass/ass_filesystem.c create mode 100644 libass/ass_filesystem.h 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 #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 + +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 +#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 +#include + +#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 #include #include -#include #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 +#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 */ -- cgit v1.2.3