Skip to content

Commit

Permalink
Extend fz_archive for directories to count/list entries.
Browse files Browse the repository at this point in the history
Also, move APIs to consistently use "fz_archive *dir"
rather than "fz_archive *zip" as this is felt to be
better.
  • Loading branch information
robinwatts committed Jan 11, 2024
1 parent 97a8e74 commit 65733cc
Show file tree
Hide file tree
Showing 15 changed files with 202 additions and 61 deletions.
9 changes: 5 additions & 4 deletions include/mupdf/fitz/document.h
Original file line number Diff line number Diff line change
Expand Up @@ -323,12 +323,13 @@ typedef void (fz_page_delete_link_fn)(fz_context *ctx, fz_page *page, fz_link *l
accel: fz_stream to read accelerator data from. May be
NULL. May be ignored.
zip: Archive to read associated content from (like images for
an html stream). Maybe NULL. May be ignored.
dir: 'Directory context' in which the document is loaded;
associated content from (like images for an html stream
will be loaded from this). Maybe NULL. May be ignored.
Pointer to opened document. Throws exception in case of error.
*/
typedef fz_document *(fz_document_open_fn)(fz_context *ctx, fz_stream *stream, fz_stream *accel, fz_archive *zip);
typedef fz_document *(fz_document_open_fn)(fz_context *ctx, fz_stream *stream, fz_stream *accel, fz_archive *dir);

/**
Recognize a document type from
Expand All @@ -349,7 +350,7 @@ typedef int (fz_document_recognize_fn)(fz_context *ctx, const char *magic);
stream: stream contents to recognise (may be NULL if document is
a directory).
dir: directory from which stream is loaded.
dir: directory context from which stream is loaded.
Returns a number between 0 (not recognized) and 100
(fully recognized) based on how certain the recognizer
Expand Down
6 changes: 3 additions & 3 deletions include/mupdf/fitz/story-writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,8 @@ void fz_write_story(
* story content has been written to the device).
* pagefn_ref:
* Passed to pagefn().
* archive:
* NULL, or an archive to load images etc from.
* dir:
* NULL, or a directory context to load images etc from.
*/
void fz_write_stabilized_story(
fz_context *ctx,
Expand All @@ -203,7 +203,7 @@ void fz_write_stabilized_story(
void *rectfn_ref,
fz_write_story_pagefn pagefn,
void *pagefn_ref,
fz_archive *archive
fz_archive *dir
);

#endif
4 changes: 2 additions & 2 deletions include/mupdf/fitz/story.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,11 @@ typedef struct fz_story fz_story;
Passing a NULL buffer will be treated as an empty document.
Passing a NULL user_css will be treated as an empty CSS string.
A non-NULL archive will allow images etc to be loaded. The
A non-NULL dir will allow images etc to be loaded. The
story keeps its own reference, so the caller can drop its
reference after this call.
*/
fz_story *fz_new_story(fz_context *ctx, fz_buffer *buf, const char *user_css, float em, fz_archive *archive);
fz_story *fz_new_story(fz_context *ctx, fz_buffer *buf, const char *user_css, float em, fz_archive *dir);

/*
Retrieve the warnings given from parsing this story.
Expand Down
8 changes: 4 additions & 4 deletions include/mupdf/fitz/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,22 +108,22 @@ int fz_search_display_list(fz_context *ctx, fz_display_list *list, const char *n
/**
Parse an SVG document into a display-list.
*/
fz_display_list *fz_new_display_list_from_svg(fz_context *ctx, fz_buffer *buf, const char *base_uri, fz_archive *zip, float *w, float *h);
fz_display_list *fz_new_display_list_from_svg(fz_context *ctx, fz_buffer *buf, const char *base_uri, fz_archive *dir, float *w, float *h);

/**
Create a scalable image from an SVG document.
*/
fz_image *fz_new_image_from_svg(fz_context *ctx, fz_buffer *buf, const char *base_uri, fz_archive *zip);
fz_image *fz_new_image_from_svg(fz_context *ctx, fz_buffer *buf, const char *base_uri, fz_archive *dir);

/**
Parse an SVG document into a display-list.
*/
fz_display_list *fz_new_display_list_from_svg_xml(fz_context *ctx, fz_xml_doc *xmldoc, fz_xml *xml, const char *base_uri, fz_archive *zip, float *w, float *h);
fz_display_list *fz_new_display_list_from_svg_xml(fz_context *ctx, fz_xml_doc *xmldoc, fz_xml *xml, const char *base_uri, fz_archive *dir, float *w, float *h);

/**
Create a scalable image from an SVG document.
*/
fz_image *fz_new_image_from_svg_xml(fz_context *ctx, fz_xml_doc *xmldoc, fz_xml *xml, const char *base_uri, fz_archive *zip);
fz_image *fz_new_image_from_svg_xml(fz_context *ctx, fz_xml_doc *xmldoc, fz_xml *xml, const char *base_uri, fz_archive *dir);

/**
Write image as a data URI (for HTML and SVG output).
Expand Down
4 changes: 2 additions & 2 deletions include/mupdf/fitz/xml.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ fz_xml *fz_parse_xml_stream(fz_context *ctx, fz_stream *stream, int preserve_whi
preserve_white: whether to keep or delete all-whitespace nodes.
*/
fz_xml *fz_parse_xml_archive_entry(fz_context *ctx, fz_archive *arch, const char *filename, int preserve_white);
fz_xml *fz_parse_xml_archive_entry(fz_context *ctx, fz_archive *dir, const char *filename, int preserve_white);

/**
Try and parse the contents of an archive entry into a tree of xml nodes.
Expand All @@ -67,7 +67,7 @@ fz_xml *fz_parse_xml_archive_entry(fz_context *ctx, fz_archive *arch, const char
Will return NULL if the archive entry can't be found. Otherwise behaves
the same as fz_parse_xml_archive_entry. May throw exceptions.
*/
fz_xml *fz_try_parse_xml_archive_entry(fz_context *ctx, fz_archive *arch, const char *filename, int preserve_white);
fz_xml *fz_try_parse_xml_archive_entry(fz_context *ctx, fz_archive *dir, const char *filename, int preserve_white);

/**
Parse the contents of a buffer into a tree of XML nodes,
Expand Down
4 changes: 2 additions & 2 deletions include/mupdf/html.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ typedef struct
int patch_mobi;
} fz_htdoc_format_t;

fz_document *fz_htdoc_open_document_with_buffer(fz_context *ctx, fz_archive *zip, fz_buffer *buf, const fz_htdoc_format_t *format);
fz_document *fz_htdoc_open_document_with_buffer(fz_context *ctx, fz_archive *dir, fz_buffer *buf, const fz_htdoc_format_t *format);

fz_document *fz_htdoc_open_document_with_stream_and_dir(fz_context *ctx, fz_stream *stm, fz_archive *zip, const fz_htdoc_format_t *format);
fz_document *fz_htdoc_open_document_with_stream_and_dir(fz_context *ctx, fz_stream *stm, fz_archive *dir, const fz_htdoc_format_t *format);



Expand Down
30 changes: 17 additions & 13 deletions source/cbz/mucbz.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ cbz_lookup_metadata(fz_context *ctx, fz_document *doc_, const char *key, char *b
}

static fz_document *
cbz_open_document(fz_context *ctx, fz_stream *file, fz_stream *accel, fz_archive *zip)
cbz_open_document(fz_context *ctx, fz_stream *file, fz_stream *accel, fz_archive *dir)
{
cbz_document *doc = fz_new_derived_document(ctx, cbz_document);

Expand All @@ -269,7 +269,10 @@ cbz_open_document(fz_context *ctx, fz_stream *file, fz_stream *accel, fz_archive

fz_try(ctx)
{
doc->arch = fz_open_archive_with_stream(ctx, file);
if (file)
doc->arch = fz_open_archive_with_stream(ctx, file);
else
doc->arch = fz_keep_archive(ctx, dir);
cbz_create_page_list(ctx, doc);
}
fz_catch(ctx)
Expand Down Expand Up @@ -318,26 +321,27 @@ cbz_recognize_doc_content(fz_context *ctx, fz_stream *stream, fz_archive *dir)
fz_var(arch);
fz_var(ret);

/* FIXME: Maybe consider: if stream == NULL then use dir as archive.
* This would enable us to open directories of unpacked cbz's. Is
* this a good thing, or is it too permissive? */

if (stream == NULL)
return 0;

fz_try(ctx)
{
arch = fz_try_open_archive_with_stream(ctx, stream);
if (arch == NULL)
break;
if (stream == NULL)
arch = fz_keep_archive(ctx, dir);
else
{
arch = fz_try_open_archive_with_stream(ctx, stream);
if (arch == NULL)
break;
}

/* If it's an archive, and we can find at least one plausible page
* then we can open it as a cbz. */
count = fz_count_archive_entries(ctx, arch);
for (i = 0; i < count && ret == 0; i++)
{
const char *name = fz_list_archive_entry(ctx, arch, i);
const char *ext = name ? strrchr(name, '.') : NULL;
const char *ext;
if (name == NULL)
continue;
ext = strrchr(name, '.');
if (ext)
{
for (k = 0; cbz_ext_list[k]; k++)
Expand Down
2 changes: 1 addition & 1 deletion source/cbz/muimg.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ img_lookup_metadata(fz_context *ctx, fz_document *doc_, const char *key, char *b
}

static fz_document *
img_open_document(fz_context *ctx, fz_stream *file, fz_stream *accel, fz_archive *zip)
img_open_document(fz_context *ctx, fz_stream *file, fz_stream *accel, fz_archive *dir)
{
img_document *doc = fz_new_derived_document(ctx, img_document);

Expand Down
136 changes: 136 additions & 0 deletions source/fitz/directory.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,32 @@
#include <sys/stat.h>

#ifdef _MSC_VER
#include <windows.h>
#define stat _stat
#else
#include <dirent.h>
#endif

typedef struct
{
fz_archive super;

char *path;

int max_entries;
int num_entries;
char **entries;
} fz_directory;

static void drop_directory(fz_context *ctx, fz_archive *arch)
{
fz_directory *dir = (fz_directory *) arch;
int i;

fz_free(ctx, dir->path);
for (i = 0; i < dir->num_entries; i++)
fz_free(ctx, dir->entries[i]);
fz_free(ctx, dir->entries);
}

static fz_stream *open_dir_entry(fz_context *ctx, fz_archive *arch, const char *name)
Expand Down Expand Up @@ -85,25 +96,150 @@ fz_is_directory(fz_context *ctx, const char *path)
return S_ISDIR(info.st_mode);
}

static int
count_dir_entries(fz_context *ctx, fz_archive *arch)
{
fz_directory *dir = (fz_directory *) arch;

return dir->num_entries;
}

const char *
list_dir_entry(fz_context *ctx, fz_archive *arch, int n)
{
fz_directory *dir = (fz_directory *) arch;

if (n < 0 || n >= dir->num_entries)
return NULL;

return dir->entries[n];
}

fz_archive *
fz_open_directory(fz_context *ctx, const char *path)
{
fz_directory *dir;
#ifdef _MSC_VER
WCHAR *wpath = NULL;
size_t z = 3;
HANDLE h = NULL;
WIN32_FIND_DATAW dw;

fz_var(wpath);
fz_var(h);
#else
DIR *dp;
struct dirent *ep;

fz_var(dp);
#endif

if (!fz_is_directory(ctx, path))
fz_throw(ctx, FZ_ERROR_FORMAT, "'%s' is not a directory", path);

dir = fz_new_derived_archive(ctx, NULL, fz_directory);
dir->super.format = "dir";
dir->super.count_entries = count_dir_entries;
dir->super.list_entry = list_dir_entry;
dir->super.has_entry = has_dir_entry;
dir->super.read_entry = read_dir_entry;
dir->super.open_entry = open_dir_entry;
dir->super.drop_archive = drop_directory;

fz_try(ctx)
{
#ifdef _MSC_VER
char const *p = path;
WCHAR *w;
while (*p)
{
int rune;
p += fz_chartorune(&rune, p);
if (rune >= 0x10000 || rune < 0)
fz_throw(ctx, FZ_ERROR_GENERIC, "Unrepresentable UTF-8 char in directory name");
z++;
}
w = wpath = fz_malloc(ctx, z * sizeof(WCHAR));
p = path;
while (*p)
{
int rune;
p += fz_chartorune(&rune, p);
*w++ = rune;
}
w[0] = '\\';
w[1] = '*';
w[2] = 0;

/* Now enumerate the paths. */
h = FindFirstFileW(wpath, &dw);
if (h == INVALID_HANDLE_VALUE)
break;

do
{
char *u;

if (dir->max_entries == dir->num_entries)
{
int newmax = dir->max_entries * 2;
if (newmax == 0)
newmax = 32;

dir->entries = fz_realloc(ctx, dir->entries, sizeof(*dir->entries) * newmax);
dir->max_entries = newmax;
}

/* Count the len as utf-8. */
w = dw.cFileName;
z = 1;
while (*w)
z += fz_runelen(*w++);

u = dir->entries[dir->num_entries] = fz_malloc(ctx, z);
dir->num_entries++;

/* Copy the name across. */
w = dw.cFileName;
while (*w)
u += fz_runetochar(u, *w++);
*u = 0;
}
while (FindNextFileW(h, &dw));
#else
dp = opendir(path);
if (dp == NULL)
break;

while ((ep = readdir(dp)) != NULL)
{
if (dir->max_entries == dir->num_entries)
{
int newmax = dir->max_entries * 2;
if (newmax == 0)
newmax = 32;

dir->entries = fz_realloc(ctx, dir->entries, sizeof(*dir->entries) * newmax);
dir->max_entries = newmax;
}

dir->entries[dir->num_entries] = fz_strdup(ctx, ep->d_name);
dir->num_entries++;
}
#endif
dir->path = fz_strdup(ctx, path);
}
fz_always(ctx)
{
#ifdef _MSC_VER
fz_free(ctx, wpath);
if (h)
(void)FindClose(h);
#else
if (dp)
(void)closedir(dp);
#endif
}
fz_catch(ctx)
{
fz_drop_archive(ctx, &dir->super);
Expand Down
10 changes: 5 additions & 5 deletions source/fitz/document.c
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,9 @@ fz_open_document_with_stream(fz_context *ctx, const char *magic, fz_stream *stre
}

fz_document *
fz_open_document_with_stream_and_dir(fz_context *ctx, const char *magic, fz_stream *stream, fz_archive *zip)
fz_open_document_with_stream_and_dir(fz_context *ctx, const char *magic, fz_stream *stream, fz_archive *dir)
{
return fz_open_accelerated_document_with_stream_and_dir(ctx, magic, stream, NULL, zip);
return fz_open_accelerated_document_with_stream_and_dir(ctx, magic, stream, NULL, dir);
}

fz_document *
Expand Down Expand Up @@ -288,12 +288,12 @@ fz_open_accelerated_document(fz_context *ctx, const char *filename, const char *
if (fz_is_directory(ctx, filename))
{
/* Cannot accelerate directories, currently. */
fz_archive *zip = fz_open_directory(ctx, filename);
fz_archive *dir = fz_open_directory(ctx, filename);

fz_try(ctx)
doc = fz_open_accelerated_document_with_stream_and_dir(ctx, filename, NULL, NULL, zip);
doc = fz_open_accelerated_document_with_stream_and_dir(ctx, filename, NULL, NULL, dir);
fz_always(ctx)
fz_drop_archive(ctx, zip);
fz_drop_archive(ctx, dir);
fz_catch(ctx)
fz_rethrow(ctx);

Expand Down
Loading

0 comments on commit 65733cc

Please sign in to comment.