Я пытаюсь загрузить файл TTF непосредственно из ZIP-архива, используя libzip и FreeType.
В частности, я использую функцию FT_Open_Face, которая может читать из пользовательского чтения /close функции (ft_zip_read
и ft_zip_close
). Но хотя файл явно прочитан полностью, FT_Open_Face
возвращает FT_Err_Unknown_File_Format
. Открытие того же файла напрямую с диска работает нормально.
Я действительно не знаю, как отладить это, может кто-нибудь помочь?
Единственное, что я могу себе представить сейчас, это то, что моя функция ft_zip_read
не поддерживает поиск, документация говорит:
Эта функция может быть вызвана для выполнения операции поиска или пропуска с «счетчиком», равным 0. Ненулевое возвращаемое значение указывает на ошибку.
И он действительно вызывается пару раз со счетом 0, но я не вижу способа выполнить поиск с помощью libzip.
unsigned long ft_zip_read(FT_Stream stream, unsigned long offset,
unsigned char* buffer, unsigned long count)
{
zip_file* file = static_cast<zip_file*>(stream->descriptor.pointer);
return zip_fread(file, buffer + offset, count);
}
void ft_zip_close(FT_Stream stream)
{
zip_file* file = static_cast<zip_file*>(stream->descriptor.pointer);
zip_fclose(file);
}
FT_Face load_zipped_face(const std::string& name, unsigned int size,
const std::string& zip_path)
{
FT_Library library;
FT_Error error = FT_Init_FreeType(&library);
if (error)
throw freetype_error_string("Failed to initialise FreeType", error);
int zip_error;
zip* zip = zip_open(zip_path.c_str(), 0, &zip_error);
if (!zip) {
std::ostringstream message_stream;
message_stream << "Error loading ZIP (" << zip_path << "): "
<< zip_error;
throw message_stream.str();
}
std::string face_path = name + ".ttf";
struct zip_stat stat;
if (zip_stat(zip, face_path.c_str(), 0, &stat))
throw std::string("zip_stat failed");
zip_file* file = zip_fopen(zip, face_path.c_str(), 0);
if (file == 0)
throw face_path + ": " + strerror(errno);
FT_StreamDesc descriptor;
descriptor.pointer = file;
FT_StreamRec* stream = new FT_StreamRec;
stream->base = 0;
stream->size = stat.size;
stream->descriptor = descriptor;
stream->read = &ft_zip_read;
stream->close = &ft_zip_close;
FT_Open_Args open_args;
open_args.flags = FT_OPEN_STREAM;
open_args.stream = stream;
FT_Face face;
error = FT_Open_Face(library, &open_args, 0, &face);
zip_close(zip);
if (error == FT_Err_Unknown_File_Format)
throw std::string("Unsupported format");
else if (error)
throw freetype_error_string("Unknown error loading font", error);
error = FT_Set_Pixel_Sizes(face, 0, size);
if (error)
throw freetype_error_string("Unable to set pixel sizes", error);
return face;
}