#include "mupdf/fitz/stream.h" #include "mupdf/fitz/string.h" #if (defined(_WIN32) || defined(_WIN64)) && !defined(NDEBUG) #include "windows.h" static void show_progress(int av, int pos) { char text[80]; sprintf(text, "Have %d, Want %d\n", av, pos); OutputDebugStringA(text); } #else #define show_progress(A,B) do {} while (0) #endif /* File stream - progressive reading to simulate http download */ typedef struct prog_state { FILE *file; fz_off_t length; fz_off_t available; int bps; clock_t start_time; unsigned char buffer[4096]; } prog_state; static int next_prog(fz_context *ctx, fz_stream *stm, int len) { prog_state *ps = (prog_state *)stm->state; int n; unsigned char *buf = ps->buffer; if (len > sizeof(ps->buffer)) len = sizeof(ps->buffer); /* Simulate more data having arrived */ if (ps->available < ps->length) { fz_off_t av = (fz_off_t)((double)(clock() - ps->start_time) * ps->bps / (CLOCKS_PER_SEC*8)); if (av > ps->length) av = ps->length; ps->available = av; /* Limit any fetches to be within the data we have */ if (av < ps->length && len + stm->pos > av) { len = av - stm->pos; if (len <= 0) { show_progress(av, stm->pos); fz_throw(ctx, FZ_ERROR_TRYLATER, "Not enough data yet"); } } } n = (len > 0 ? fread(buf, 1, (unsigned int)len, ps->file) : 0); if (n < 0) fz_throw(ctx, FZ_ERROR_GENERIC, "read error: %s", strerror(errno)); stm->rp = ps->buffer + stm->pos; stm->wp = ps->buffer + stm->pos + n; stm->pos += n; if (n == 0) return EOF; return *stm->rp++; } static void seek_prog(fz_context *ctx, fz_stream *stm, fz_off_t offset, int whence) { prog_state *ps = (prog_state *)stm->state; /* Simulate more data having arrived */ if (ps->available < ps->length) { int av = (int)((float)(clock() - ps->start_time) * ps->bps / (CLOCKS_PER_SEC*8)); if (av > ps->length) av = ps->length; ps->available = av; } if (ps->available < ps->length) { if (whence == SEEK_END) { show_progress(ps->available, ps->length); fz_throw(ctx, FZ_ERROR_TRYLATER, "Not enough data to seek to end yet"); } } if (whence == SEEK_CUR) { whence = SEEK_SET; offset += stm->pos; if (offset > ps->available) { show_progress(ps->available, offset); fz_throw(ctx, FZ_ERROR_TRYLATER, "Not enough data to seek (relatively) to offset yet"); } } if (whence == SEEK_SET) { if (offset > ps->available) { show_progress(ps->available, offset); fz_throw(ctx, FZ_ERROR_TRYLATER, "Not enough data to seek to offset yet"); } } if (fz_fseek(ps->file, offset, whence) != 0) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot seek: %s", strerror(errno)); stm->pos = offset; stm->wp = stm->rp; } static void close_prog(fz_context *ctx, void *state) { prog_state *ps = (prog_state *)state; fclose(ps->file); fz_free(ctx, state); } static int meta_prog(fz_context *ctx, fz_stream *stm, int key, int size, void *ptr) { prog_state *ps = (prog_state *)stm->state; switch(key) { case FZ_STREAM_META_PROGRESSIVE: return 1; break; case FZ_STREAM_META_LENGTH: return ps->length; } return -1; } fz_stream * fz_open_file_ptr_progressive(fz_context *ctx, FILE *file, int bps) { fz_stream *stm; prog_state *state; state = fz_malloc_struct(ctx, prog_state); state->file = file; state->bps = bps; state->start_time = clock(); state->available = 0; fz_fseek(state->file, 0, SEEK_END); state->length = fz_ftell(state->file); fz_fseek(state->file, 0, SEEK_SET); fz_try(ctx) { stm = fz_new_stream(ctx, state, next_prog, close_prog); } fz_catch(ctx) { fz_free(ctx, state); fz_rethrow(ctx); } stm->seek = seek_prog; stm->meta = meta_prog; return stm; } fz_stream * fz_open_file_progressive(fz_context *ctx, const char *name, int bps) { FILE *f; #if defined(_WIN32) || defined(_WIN64) char *s = (char*)name; wchar_t *wname, *d; int c; d = wname = fz_malloc(ctx, (strlen(name)+1) * sizeof(wchar_t)); while (*s) { s += fz_chartorune(&c, s); *d++ = c; } *d = 0; f = _wfopen(wname, L"rb"); fz_free(ctx, wname); #else f = fz_fopen(name, "rb"); #endif if (f == NULL) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open %s", name); return fz_open_file_ptr_progressive(ctx, f, bps); }