Gfxprim
Threads by month
- ----- 2026 -----
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- 929 discussions
16 Jan '14
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via 690b25c07649dab4d217e1d0ecbf9c56a20fc48b (commit)
via a3aacf197945a7d0473b8710f3b67fa1e6232f31 (commit)
via 349102348826ddb75fa961b9fa8c26ba6b545977 (commit)
via dca1a2fe0c5bb6597965e33f0bf4907216d97bc2 (commit)
via 52d18d34cd935319a82de09923943ccf96b0219f (commit)
via c4b0e581c43bb9bfc6ca3738d19aa9ff5b15e836 (commit)
via 5955c59467a2b043812d2fa02c783b1c9e4e2562 (commit)
via 503fa7970aed181aa853406c3e04f6debaa7d5dd (commit)
via 9fa629c10033f45505f2348eae343f6eb4a2b01b (commit)
via 1486958906f687d667ff7c47c2af60c4110bd0c9 (commit)
via c7a22b3bf489a9a42e29e66af3890f250e4a42df (commit)
from 2ac9facaf575685be1e6ab95492f2c5bf0562567 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/690b25c07649dab4d217e1d0ecbf9c56a20f…
commit 690b25c07649dab4d217e1d0ecbf9c56a20fc48b
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Thu Jan 16 00:33:50 2014 +0100
loaders: IO: Fix empty variable array in GP_IOReadF()
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/libs/loaders/GP_IO.c b/libs/loaders/GP_IO.c
index a1409a6..e09df1b 100644
--- a/libs/loaders/GP_IO.c
+++ b/libs/loaders/GP_IO.c
@@ -356,12 +356,14 @@ static int needs_swap(uint16_t type)
int GP_IOReadF(GP_IO *self, uint16_t *types, ...)
{
unsigned int size = readf_size(types);
- uint8_t buffer[size], *buf = buffer;
int ret;
va_list va;
uint8_t *ptr;
- buf[0] = 0;
+ if (size == 0)
+ return 0;
+
+ uint8_t buffer[size], *buf = buffer;
if (GP_IOFill(self, buf, size))
return -1;
http://repo.or.cz/w/gfxprim.git/commit/a3aacf197945a7d0473b8710f3b67fa1e623…
commit a3aacf197945a7d0473b8710f3b67fa1e6232f31
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Thu Jan 16 00:28:59 2014 +0100
loaders: GIF: Set errno correctly on no image record
Set errno correctly if there was no image record found in a GIF image.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/libs/loaders/GP_GIF.c b/libs/loaders/GP_GIF.c
index 88bddee..0c286b9 100644
--- a/libs/loaders/GP_GIF.c
+++ b/libs/loaders/GP_GIF.c
@@ -346,8 +346,8 @@ GP_Context *GP_ReadGIF(GP_IO *io, GP_ProgressCallback *callback)
DGifCloseFile(gf);
/* No Image record found :( */
- if (res == NULL)
- err = EIO;
+ if (!res)
+ errno = EINVAL;
return res;
err2:
http://repo.or.cz/w/gfxprim.git/commit/349102348826ddb75fa961b9fa8c26ba6b54…
commit 349102348826ddb75fa961b9fa8c26ba6b545977
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Thu Jan 16 00:15:23 2014 +0100
loaders: Remove now unused GP_FRead()
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/build/syms/Loaders_symbols.txt b/build/syms/Loaders_symbols.txt
index bac234f..7b40c8c 100644
--- a/build/syms/Loaders_symbols.txt
+++ b/build/syms/Loaders_symbols.txt
@@ -1,5 +1,4 @@
GP_FWrite
-GP_FRead
GP_MatchJPG
GP_ReadJPG
diff --git a/demos/c_simple/Makefile b/demos/c_simple/Makefile
index 68fa14a..ed75f7a 100644
--- a/demos/c_simple/Makefile
+++ b/demos/c_simple/Makefile
@@ -18,7 +18,7 @@ APPS=backend_example loaders_example loaders filters_symmetry gfx_koch v4l2_show v4l2_grab convolution weighted_median shapetest koch input_example fileview linetest randomshapetest fonttest loaders_register blittest textaligntest sin_AA x11_windows- debug_handler gaussian_noise byte_utils version pretty_print timers+ debug_handler gaussian_noise version pretty_print timers zip_container backend_timers_example memory_io
ifeq ($(HAVE_LIBSDL),yes)
@@ -52,7 +52,6 @@ fonttest: LDLIBS+=$(LDLIBS_BACKENDS)
textaligntest: LDLIBS+=$(LDLIBS_BACKENDS)
loaders_register: LDLIBS+=$(LDLIBS_LOADERS)
gaussian_noise: LDLIBS+=$(LDLIBS_LOADERS)
-byte_utils: LDLIBS+=$(LDLIBS_LOADERS)
blittest: LDLIBS+=$(LDLIBS_BACKENDS) $(LDLIBS_LOADERS)
sin_AA: LDLIBS+=$(LDLIBS_BACKENDS)
x11_windows: LDLIBS+=$(LDLIBS_BACKENDS)
diff --git a/demos/c_simple/byte_utils.c b/demos/c_simple/byte_utils.c
deleted file mode 100644
index 4c9053f..0000000
--- a/demos/c_simple/byte_utils.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*****************************************************************************
- * This file is part of gfxprim library. *
- * *
- * Gfxprim is free software; you can redistribute it and/or *
- * modify it under the terms of the GNU Lesser General Public *
- * License as published by the Free Software Foundation; either *
- * version 2.1 of the License, or (at your option) any later version. *
- * *
- * Gfxprim is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
- * Lesser General Public License for more details. *
- * *
- * You should have received a copy of the GNU Lesser General Public *
- * License along with gfxprim; if not, write to the Free Software *
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
- * Boston, MA 02110-1301 USA *
- * *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
- * *
- *****************************************************************************/
-
-/*
- * Byte utils are utils to ease reading and parsing various image headers.
- *
- * This is internal API for loaders.
- */
-
-#include <stdint.h>
-#include <stdio.h>
-
-#include <loaders/GP_ByteUtils.h>
-
-#define FILENAME "file.tmp"
-
-static void write_file(void)
-{
- FILE *f;
- int ret;
-
- f = fopen(FILENAME, "wb");
-
- if (f == NULL) {
- fprintf(stderr, "Failed to open file '" FILENAME "'");
- return;
- }
-
- uint16_t w = 800;
- uint16_t h = 600;
- uint8_t bpp = 4;
- char *sig = "MG";
-
- ret = GP_FWrite(f, "A2 0x00 0x00 B2 B2 B1", sig, w, h, bpp);
-
- if (ret != 6)
- printf("Failed to write header, ret = %in", ret);
-
- fclose(f);
-}
-
-static void read_file(void)
-{
- FILE *f;
- int ret;
-
- f = fopen(FILENAME, "rb");
-
- if (f == NULL) {
- fprintf(stderr, "Failed to open file '" FILENAME "'");
- return;
- }
-
- uint16_t w;
- uint16_t h;
- uint8_t bpp;
- char sig[3] = {0};
-
- ret = GP_FRead(f, "A2 I2 B2 B2 B1", sig, &w, &h, &bpp);
-
- if (ret != 5)
- printf("Failed to read header, ret = %in", ret);
-
- printf("SIG=%s, w=%u, h=%u, bpp=%un", sig, w, h, bpp);
-
- fclose(f);
-}
-
-int main(void)
-{
- write_file();
- read_file();
- return 0;
-}
diff --git a/include/loaders/GP_ByteUtils.h b/include/loaders/GP_ByteUtils.h
index 8916fd7..92b2fec 100644
--- a/include/loaders/GP_ByteUtils.h
+++ b/include/loaders/GP_ByteUtils.h
@@ -32,39 +32,6 @@
#include <stdio.h>
/*
- * The format string examples:
- *
- * Type Modifiers:
- *
- * L - little endian (passed as value to write, passed as pointer to read)
- * B - big endian
- * A - byte array (passed as bointer for both read and write)
- * I - ignore xxx bytes, GP_Fread() only
- *
- * Size Modifiers are just numbers.
- *
- * To read and write header with two byte signature, two reserved zero bytes
- * and size in 16 bit unsigned little endian variables.
- *
- * uint16_t w;
- * uint16_t h;
- * char sig[2];
- *
- * if (GP_FWrite(f, "A2 0x00 0x00 L2 L2", "SG", w, h) != 5)
- * //ERROR
- *
- * if (GP_FRead(f, "A2 I2 L2 L2", sig, &w, &h) != 4)
- * //ERROR
- */
-
-/*
- * Printf-like function to read file headers.
- *
- * Returns number of items successfully matched/converted.
- */
-int GP_FRead(FILE *f, const char *fmt, ...);
-
-/*
* Printf-like function to write file headers.
*
* Returns number of items sucessfully written.
diff --git a/libs/loaders/GP_ByteUtils.c b/libs/loaders/GP_ByteUtils.c
index b56c20d..4a83d5d 100644
--- a/libs/loaders/GP_ByteUtils.c
+++ b/libs/loaders/GP_ByteUtils.c
@@ -205,56 +205,6 @@ static void swap_bytes(void *ptr, int len, int type)
}
}
-int GP_FRead(FILE *f, const char *fmt, ...)
-{
- int type, val, ret = 0;
- void *ptr;
- va_list va;
-
- va_start(va, fmt);
-
- for (;;) {
- fmt = get_next(fmt, &type, &val);
-
- /* end of the string or error */
- if (fmt == NULL)
- goto end;
-
- switch (type) {
- case BYTE_ARRAY:
- if (fread(va_arg(va, void*), val, 1, f) != 1)
- goto end;
- break;
- case CONST_BYTE:
- if (fgetc(f) != val)
- goto end;
- break;
- case LITTLE_ENDIAN_VAR:
- case BIG_ENDIAN_VAR:
- ptr = va_arg(va, void*);
-
- if (fread(ptr, val, 1, f) != 1)
- goto end;
-
- swap_bytes(ptr, val, type);
- break;
- case IGNORE:
- while (val--)
- fgetc(f);
- break;
- default:
- GP_BUG("Wrong format type for reading (%i)", type);
- goto end;
- }
-
- ret++;
-
- }
-end:
- va_end(va);
- return ret;
-}
-
int GP_FWrite(FILE *f, const char *fmt, ...)
{
int type, val, ret = 0;
http://repo.or.cz/w/gfxprim.git/commit/dca1a2fe0c5bb6597965e33f0bf4907216d9…
commit dca1a2fe0c5bb6597965e33f0bf4907216d97bc2
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Thu Jan 16 00:02:58 2014 +0100
pywrap: loaders.i: Cleanup Loaders wrappings.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/pylib/gfxprim/loaders/loaders.i b/pylib/gfxprim/loaders/loaders.i
index f310e74..bab032c 100644
--- a/pylib/gfxprim/loaders/loaders.i
+++ b/pylib/gfxprim/loaders/loaders.i
@@ -10,81 +10,62 @@
%import ../core/core.i
+/* TODO IO from fd */
+
+%define LOADER_FUNC(FMT)
+%newobject GP_Load ## FMT;
+ERROR_ON_NULL(GP_Load ## FMT);
+%newobject GP_Read ## FMT;
+ERROR_ON_NULL(GP_Read ## FMT);
+%enddef
+
ERROR_ON_NULL(GP_LoadImage);
-ERROR_ON_NONZERO(GP_LoadMetaData);
+ERROR_ON_NONZERO(GP_ReadImage);
ERROR_ON_NONZERO(GP_SaveImage);
%newobject GP_LoadImage;
%include "GP_Loader.h"
-ERROR_ON_NONZERO(GP_OpenJPG);
-ERROR_ON_NULL(GP_ReadJPG);
-ERROR_ON_NULL(GP_LoadJPG);
-ERROR_ON_NONZERO(GP_ReadJPGMetaData);
-ERROR_ON_NONZERO(GP_LoadJPGMetaData);
+LOADER_FUNC(JPG);
ERROR_ON_NONZERO(GP_SaveJPG);
-%newobject GP_LoadJPG;
-
%include "GP_JPG.h"
-ERROR_ON_NONZERO(GP_OpenBMP);
-ERROR_ON_NULL(GP_ReadBMP);
-ERROR_ON_NULL(GP_LoadBMP);
-
-%newobject GP_LoadBMP;
+LOADER_FUNC(BMP);
+ERROR_ON_NONZERO(GP_SaveBMP);
%include "GP_BMP.h"
-ERROR_ON_NONZERO(GP_OpenGIF);
-ERROR_ON_NULL(GP_ReadGIF);
-ERROR_ON_NULL(GP_LoadGIF);
-
-%newobject GP_LoadGIF;
+LOADER_FUNC(GIF);
%include "GP_GIF.h"
-ERROR_ON_NONZERO(GP_OpenPNG);
-ERROR_ON_NULL(GP_ReadPNG);
-ERROR_ON_NULL(GP_LoadPNG);
-ERROR_ON_NONZERO(GP_ReadPNGMetaData);
-ERROR_ON_NONZERO(GP_LoadPNGMetaData);
+LOADER_FUNC(PNG);
ERROR_ON_NONZERO(GP_SavePNG);
-%newobject GP_LoadPNG;
-
%include "GP_PNG.h"
-ERROR_ON_NULL(GP_LoadPBM);
-ERROR_ON_NULL(GP_LoadPGM);
-ERROR_ON_NULL(GP_LoadPPM);
-ERROR_ON_NULL(GP_LoadPNM);
+LOADER_FUNC(PBM);
+LOADER_FUNC(PGM);
+LOADER_FUNC(PPM);
+LOADER_FUNC(PNM);
ERROR_ON_NONZERO(GP_SavePBM);
ERROR_ON_NONZERO(GP_SavePGM);
ERROR_ON_NONZERO(GP_SavePPM);
ERROR_ON_NONZERO(GP_SavePNM);
-%newobject GP_LoadPBM;
-%newobject GP_LoadPGM;
-%newobject GP_LoadPPM;
-%newobject GP_LoadPNM;
-
%include "GP_PNM.h"
-ERROR_ON_NULL(GP_LoadTIFF);
+LOADER_FUNC(TIFF);
ERROR_ON_NONZERO(GP_SaveTIFF);
-%newobject GP_LoadTIFF;
-
%include "GP_TIFF.h"
-ERROR_ON_NULL(GP_LoadPSP);
-%newobject GP_LoadPSP;
+LOADER_FUNC(PSP);
%include "GP_PSP.h"
-ERROR_ON_NULL(GP_LoadJP2);
-%newobject GP_LoadJP2;
+LOADER_FUNC(JP2);
%include "GP_JP2.h"
http://repo.or.cz/w/gfxprim.git/commit/52d18d34cd935319a82de09923943ccf96b0…
commit 52d18d34cd935319a82de09923943ccf96b0219f
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Wed Jan 15 23:34:07 2014 +0100
gfx: GP_Polygon: Remove unused initialization.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/libs/gfx/GP_Polygon.c b/libs/gfx/GP_Polygon.c
index e76babe..dd397b5 100644
--- a/libs/gfx/GP_Polygon.c
+++ b/libs/gfx/GP_Polygon.c
@@ -186,7 +186,7 @@ void GP_FillPolygon_Raw(GP_Context *context, unsigned int nvert,
*/
float inter[nedges];
unsigned int ninter;
- int y = ymin;
+ int y;
for (y = ymin; y <= ymax; y++) {
/* mark edges we have just reached as active */
http://repo.or.cz/w/gfxprim.git/commit/c4b0e581c43bb9bfc6ca3738d19aa9ff5b15…
commit c4b0e581c43bb9bfc6ca3738d19aa9ff5b15e836
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Wed Jan 15 23:20:42 2014 +0100
tests: loaders: Now 100% coverage for reading PNM
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/tests/loaders/test_list.txt b/tests/loaders/.gitignore
similarity index 77%
copy from tests/loaders/test_list.txt
copy to tests/loaders/.gitignore
index add0cb3..047646e 100644
--- a/tests/loaders/test_list.txt
+++ b/tests/loaders/.gitignore
@@ -1,11 +1,11 @@
-# Loaders testsuite
-loaders_suite
-PNG
+GIF
+IO
PBM
PGM
+PNG
+PNM
PPM
-ZIP
-GIF
-IO
-SaveLoad.gen
SaveAbort.gen
+SaveLoad.gen
+ZIP
+loaders_suite
diff --git a/tests/loaders/Loader.h b/tests/loaders/Loader.h
index 36b20ef..ec1fe62 100644
--- a/tests/loaders/Loader.h
+++ b/tests/loaders/Loader.h
@@ -16,10 +16,15 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
+#ifndef TESTS_LOADER_H
+#define TESTS_LOADER_H
+
+#include "loaders/GP_IO.h"
+
struct testcase {
GP_Size w;
GP_Size h;
@@ -27,26 +32,10 @@ struct testcase {
char *path;
};
-static int test_load(struct testcase *test)
+static int test_check(struct testcase *test, GP_Context *img)
{
- GP_Context *img;
unsigned int x, y, err = 0;
- errno = 0;
-
- img = LOAD(test->path, NULL);
-
- if (img == NULL) {
- switch (errno) {
- case ENOSYS:
- tst_msg("Not Implemented");
- return TST_SKIPPED;
- default:
- tst_msg("Got %s", strerror(errno));
- return TST_FAILED;
- }
- }
-
if (img->w != test->w || img->h != test->h) {
tst_msg("Invalid image size have %ux%u expected %ux%u",
img->w, img->h, test->w, test->h);
@@ -68,7 +57,8 @@ static int test_load(struct testcase *test)
}
}
- GP_ContextFree(img);
+ if (err > 5)
+ tst_msg("And %u errors...", err);
if (err)
return TST_FAILED;
@@ -76,6 +66,72 @@ static int test_load(struct testcase *test)
return TST_SUCCESS;
}
+static int test_read(struct testcase *test)
+{
+ GP_Context *img;
+ GP_IO *io;
+ int err;
+
+ io = GP_IOMem(test->path, strlen(test->path), NULL);
+
+ if (!io) {
+ tst_msg("Failed to initialize memory IO: %s", strerror(errno));
+ return TST_UNTESTED;
+ }
+
+ img = READ(io, NULL);
+
+ if (!img) {
+ switch (errno) {
+ case ENOSYS:
+ tst_msg("Not Implemented");
+ err = TST_SKIPPED;
+ goto out;
+ default:
+ tst_msg("Got %s", strerror(errno));
+ err = TST_FAILED;
+ goto out;
+ }
+ }
+
+ err = test_check(test, img);
+
+ GP_ContextFree(img);
+out:
+ GP_IOClose(io);
+ return err;
+}
+
+# ifdef LOAD
+
+static int test_load(struct testcase *test)
+{
+ GP_Context *img;
+ int err;
+
+ errno = 0;
+
+ img = LOAD(test->path, NULL);
+
+ if (!img) {
+ switch (errno) {
+ case ENOSYS:
+ tst_msg("Not Implemented");
+ return TST_SKIPPED;
+ default:
+ tst_msg("Got %s", strerror(errno));
+ return TST_FAILED;
+ }
+ }
+
+ err = test_check(test, img);
+
+ GP_ContextFree(img);
+
+ return err;
+}
+
+
static int test_load_fail(const char *path)
{
GP_Context *img;
@@ -103,6 +159,11 @@ static int test_load_fail(const char *path)
}
}
+# endif /* LOAD */
+
+
+# if defined(SAVE) && defined(LOAD)
+
/*
* Saves and loads image using the SAVE and LOAD functions
* and compares the results.
@@ -188,3 +249,7 @@ static int test_save_load(struct testcase_save_load *test)
return TST_SUCCESS;
}
+
+# endif /* SAVE && LOAD */
+
+#endif /* TESTS_LOADER_H */
diff --git a/tests/loaders/Makefile b/tests/loaders/Makefile
index 6678352..31eaea4 100644
--- a/tests/loaders/Makefile
+++ b/tests/loaders/Makefile
@@ -1,10 +1,10 @@
TOPDIR=../..
include $(TOPDIR)/pre.mk
-CSOURCES=loaders_suite.c PNG.c PBM.c PGM.c PPM.c ZIP.c GIF.c IO.c
+CSOURCES=loaders_suite.c PNG.c PBM.c PGM.c PPM.c ZIP.c GIF.c IO.c PNM.c
GENSOURCES=SaveLoad.gen.c SaveAbort.gen.c
-APPS=loaders_suite PNG PBM PGM PPM SaveLoad.gen SaveAbort.gen ZIP GIF IO
+APPS=loaders_suite PNG PBM PGM PPM PNM SaveLoad.gen SaveAbort.gen ZIP GIF IO
include ../tests.mk
diff --git a/tests/loaders/PBM.c b/tests/loaders/PBM.c
index 86a20a5..9b71f04 100644
--- a/tests/loaders/PBM.c
+++ b/tests/loaders/PBM.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -32,7 +32,9 @@
#define LOAD GP_LoadPBM
#define SAVE GP_SavePBM
+#define READ GP_ReadPBM
#include "Loader.h"
+#include "PBM.h"
struct testcase black_1x1_1 = {
.w = 1,
@@ -148,6 +150,26 @@ const struct tst_suite tst_suite = {
.data = &black_3x9_bin,
.flags = TST_TMPDIR | TST_CHECK_MALLOC},
+ {.name = "PBM Read 1x1 (black)",
+ .tst_fn = test_read,
+ .data = &PBM_ascii_1x1_black,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PBM Read 1x1 (white)",
+ .tst_fn = test_read,
+ .data = &PBM_ascii_1x1_white,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PBM Read 1x1 (black) Raw",
+ .tst_fn = test_read,
+ .data = &PBM_bin_1x1_black,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PBM Read 1x1 (white) Raw",
+ .tst_fn = test_read,
+ .data = &PBM_bin_1x1_white,
+ .flags = TST_CHECK_MALLOC},
+
{.name = "PBM Load corrupt",
.tst_fn = test_load_fail,
.res_path = "data/pbm/corrupt/short.pbm",
diff --git a/tests/loaders/PPM.c b/tests/loaders/PBM.h
similarity index 57%
copy from tests/loaders/PPM.c
copy to tests/loaders/PBM.h
index 3082ce4..3a45967 100644
--- a/tests/loaders/PPM.c
+++ b/tests/loaders/PBM.h
@@ -16,63 +16,48 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
-#include <string.h>
-#include <errno.h>
-#include <sys/stat.h>
-
-#include <core/GP_Context.h>
-#include <core/GP_GetPutPixel.h>
-#include <loaders/GP_Loaders.h>
-
-#include "tst_test.h"
-
-#define LOAD GP_LoadPPM
-#define SAVE GP_SavePPM
#include "Loader.h"
-struct testcase black_1x1 = {
+static struct testcase PBM_ascii_1x1_black = {
.w = 1,
.h = 1,
.pix = 0,
- .path = "black_1x1.ppm",
+ .path = "P1n"
+ "# 1x1 black PBM ascii imagen"
+ "1 1n"
+ "1"
};
-struct testcase_save_load save_load = {
- .w = 100,
- .h = 100,
- .pixel_type = GP_PIXEL_RGB888,
+static struct testcase PBM_ascii_1x1_white = {
+ .w = 1,
+ .h = 1,
+ .pix = 1,
+ .path = "P1n"
+ "# 1x1 black PBM ascii imagen"
+ "1 1n"
+ "0"
};
-const struct tst_suite tst_suite = {
- .suite_name = "PPM",
- .tests = {
- {.name = "PPM Load 1x1 (black)",
- .tst_fn = test_load,
- .res_path = "data/ppm/valid/black_1x1.ppm",
- .data = &black_1x1,
- .flags = TST_TMPDIR | TST_CHECK_MALLOC},
-
- {.name = "PPM Save Load",
- .tst_fn = test_save_load,
- .data = &save_load,
- .flags = TST_TMPDIR | TST_CHECK_MALLOC},
-
- {.name = "PPM Load wrong header",
- .tst_fn = test_load_fail,
- .res_path = "data/ppm/corrupt/wrong_header.ppm",
- .data = "wrong_header.ppm",
- .flags = TST_TMPDIR | TST_CHECK_MALLOC},
-
- {.name = "PPM Load incomplete",
- .tst_fn = test_load_fail,
- .res_path = "data/ppm/corrupt/incomplete.ppm",
- .data = "incomplete.ppm",
- .flags = TST_TMPDIR | TST_CHECK_MALLOC},
+static struct testcase PBM_bin_1x1_black = {
+ .w = 1,
+ .h = 1,
+ .pix = 0,
+ .path = "P4n"
+ "# 1x1 black PBM binary imagen"
+ "1 1n"
+ "x80"
+};
- {.name = NULL},
- }
+static struct testcase PBM_bin_1x1_white = {
+ .w = 1,
+ .h = 1,
+ .pix = 1,
+ .path = "P4n"
+ "# 1x1 black PBM binary imagen"
+ "1 1n"
+ "x01"
};
diff --git a/tests/loaders/PGM.c b/tests/loaders/PGM.c
index 6bac05a..1fae867 100644
--- a/tests/loaders/PGM.c
+++ b/tests/loaders/PGM.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -32,7 +32,9 @@
#define LOAD GP_LoadPGM
#define SAVE GP_SavePGM
+#define READ GP_ReadPGM
#include "Loader.h"
+#include "PGM.h"
struct testcase black_1x1_1bpp = {
.w = 1,
@@ -113,6 +115,66 @@ const struct tst_suite tst_suite = {
.data = &black_1x1_8bpp,
.flags = TST_TMPDIR | TST_CHECK_MALLOC},
+ {.name = "PGM Read 1x1 1bpp (black)",
+ .tst_fn = test_read,
+ .data = &PGM_ascii_1x1_1bpp_black,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 2bpp (black)",
+ .tst_fn = test_read,
+ .data = &PGM_ascii_1x1_2bpp_black,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 4bpp (black)",
+ .tst_fn = test_read,
+ .data = &PGM_ascii_1x1_4bpp_black,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 8bpp (black)",
+ .tst_fn = test_read,
+ .data = &PGM_ascii_1x1_8bpp_black,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 1bpp (white)",
+ .tst_fn = test_read,
+ .data = &PGM_ascii_1x1_1bpp_white,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 2bpp (white)",
+ .tst_fn = test_read,
+ .data = &PGM_ascii_1x1_2bpp_white,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 4bpp (white)",
+ .tst_fn = test_read,
+ .data = &PGM_ascii_1x1_4bpp_white,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 8bpp (white)",
+ .tst_fn = test_read,
+ .data = &PGM_ascii_1x1_8bpp_white,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 1bpp (white) Raw",
+ .tst_fn = test_read,
+ .data = &PGM_bin_1x1_1bpp_white,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 2bpp (white) Raw",
+ .tst_fn = test_read,
+ .data = &PGM_bin_1x1_2bpp_white,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 4bpp (white) Raw",
+ .tst_fn = test_read,
+ .data = &PGM_bin_1x1_4bpp_white,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 8bpp (white) Raw",
+ .tst_fn = test_read,
+ .data = &PGM_bin_1x1_8bpp_white,
+ .flags = TST_CHECK_MALLOC},
+
{.name = "PGM Save Load 1bpp",
.tst_fn = test_save_load,
.data = &save_load_1bpp,
diff --git a/tests/loaders/PGM.h b/tests/loaders/PGM.h
new file mode 100644
index 0000000..a4f406e
--- /dev/null
+++ b/tests/loaders/PGM.h
@@ -0,0 +1,155 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+#include "Loader.h"
+
+static struct testcase PGM_ascii_1x1_1bpp_black = {
+ .w = 1,
+ .h = 1,
+ .pix = 0,
+ .path = "P2n"
+ "# 1x1 black PGM 1bpp ascii imagen"
+ "1 1n"
+ "1n"
+ "0"
+};
+
+static struct testcase PGM_ascii_1x1_2bpp_black = {
+ .w = 1,
+ .h = 1,
+ .pix = 0,
+ .path = "P2n"
+ "# 1x1 black PGM 2bpp ascii imagen"
+ "1 1n"
+ "3n"
+ "0"
+};
+
+static struct testcase PGM_ascii_1x1_4bpp_black = {
+ .w = 1,
+ .h = 1,
+ .pix = 0,
+ .path = "P2n"
+ "# 1x1 black PGM 4bpp ascii imagen"
+ "1 1n"
+ "15n"
+ "0"
+};
+
+static struct testcase PGM_ascii_1x1_8bpp_black = {
+ .w = 1,
+ .h = 1,
+ .pix = 0,
+ .path = "P2n"
+ "# 1x1 black PGM 8bpp ascii imagen"
+ "1 1n"
+ "255n"
+ "0"
+};
+
+static struct testcase PGM_ascii_1x1_1bpp_white = {
+ .w = 1,
+ .h = 1,
+ .pix = 1,
+ .path = "P2n"
+ "# 1x1 white PGM 1bpp ascii imagen"
+ "1 1n"
+ "1n"
+ "1"
+};
+
+static struct testcase PGM_ascii_1x1_2bpp_white = {
+ .w = 1,
+ .h = 1,
+ .pix = 3,
+ .path = "P2n"
+ "# 1x1 white PGM 2bpp ascii imagen"
+ "1 1n"
+ "3n"
+ "3"
+};
+
+static struct testcase PGM_ascii_1x1_4bpp_white = {
+ .w = 1,
+ .h = 1,
+ .pix = 15,
+ .path = "P2n"
+ "# 1x1 white PGM 4bpp ascii imagen"
+ "1 1n"
+ "15n"
+ "15"
+};
+
+static struct testcase PGM_ascii_1x1_8bpp_white = {
+ .w = 1,
+ .h = 1,
+ .pix = 255,
+ .path = "P2n"
+ "# 1x1 white PGM 8bpp ascii imagen"
+ "1 1n"
+ "255n"
+ "255"
+};
+
+static struct testcase PGM_bin_1x1_1bpp_white = {
+ .w = 1,
+ .h = 1,
+ .pix = 1,
+ .path = "P5n"
+ "# 1x1 white PGM 1bpp binary imagen"
+ "1 1n"
+ "1n"
+ "x01"
+};
+
+static struct testcase PGM_bin_1x1_2bpp_white = {
+ .w = 1,
+ .h = 1,
+ .pix = 3,
+ .path = "P5n"
+ "# 1x1 white PGM 2bpp binary imagen"
+ "1 1n"
+ "3n"
+ "x03"
+};
+
+static struct testcase PGM_bin_1x1_4bpp_white = {
+ .w = 1,
+ .h = 1,
+ .pix = 15,
+ .path = "P5n"
+ "# 1x1 white PGM 4bpp binary imagen"
+ "1 1n"
+ "15n"
+ "x0f"
+};
+
+static struct testcase PGM_bin_1x1_8bpp_white = {
+ .w = 1,
+ .h = 1,
+ .pix = 255,
+ .path = "P5n"
+ "# 1x1 white PGM 8bpp binary imagen"
+ "1 1n"
+ "255n"
+ "xff"
+};
diff --git a/tests/loaders/PNM.c b/tests/loaders/PNM.c
new file mode 100644
index 0000000..c1f75b7
--- /dev/null
+++ b/tests/loaders/PNM.c
@@ -0,0 +1,147 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <core/GP_Context.h>
+#include <core/GP_GetPutPixel.h>
+#include <loaders/GP_Loaders.h>
+
+#include "tst_test.h"
+
+#define READ GP_ReadPNM
+#include "Loader.h"
+#include "PBM.h"
+#include "PGM.h"
+#include "PPM.h"
+
+const struct tst_suite tst_suite = {
+ .suite_name = "PNM",
+ .tests = {
+ /* PBM tests */
+ {.name = "PBM Read 1x1 (black)",
+ .tst_fn = test_read,
+ .data = &PBM_ascii_1x1_black,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PBM Read 1x1 (white)",
+ .tst_fn = test_read,
+ .data = &PBM_ascii_1x1_white,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PBM Read 1x1 (black) Raw",
+ .tst_fn = test_read,
+ .data = &PBM_bin_1x1_black,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PBM Read 1x1 (white) Raw",
+ .tst_fn = test_read,
+ .data = &PBM_bin_1x1_white,
+ .flags = TST_CHECK_MALLOC},
+
+ /* PGM tests */
+ {.name = "PGM Read 1x1 1bpp (black)",
+ .tst_fn = test_read,
+ .data = &PGM_ascii_1x1_1bpp_black,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 2bpp (black)",
+ .tst_fn = test_read,
+ .data = &PGM_ascii_1x1_2bpp_black,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 4bpp (black)",
+ .tst_fn = test_read,
+ .data = &PGM_ascii_1x1_4bpp_black,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 8bpp (black)",
+ .tst_fn = test_read,
+ .data = &PGM_ascii_1x1_8bpp_black,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 1bpp (white)",
+ .tst_fn = test_read,
+ .data = &PGM_ascii_1x1_1bpp_white,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 2bpp (white)",
+ .tst_fn = test_read,
+ .data = &PGM_ascii_1x1_2bpp_white,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 4bpp (white)",
+ .tst_fn = test_read,
+ .data = &PGM_ascii_1x1_4bpp_white,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 8bpp (white)",
+ .tst_fn = test_read,
+ .data = &PGM_ascii_1x1_8bpp_white,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 1bpp (white) Raw",
+ .tst_fn = test_read,
+ .data = &PGM_bin_1x1_1bpp_white,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 2bpp (white) Raw",
+ .tst_fn = test_read,
+ .data = &PGM_bin_1x1_2bpp_white,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 4bpp (white) Raw",
+ .tst_fn = test_read,
+ .data = &PGM_bin_1x1_4bpp_white,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PGM Read 1x1 8bpp (white) Raw",
+ .tst_fn = test_read,
+ .data = &PGM_bin_1x1_8bpp_white,
+ .flags = TST_CHECK_MALLOC},
+
+ /* PPM tests */
+ {.name = "PPM Read 1x1 4bpp (black)",
+ .tst_fn = test_read,
+ .data = &PPM_ascii_1x1_4bpp_black,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PPM Read 1x1 8bpp (black)",
+ .tst_fn = test_read,
+ .data = &PPM_ascii_1x1_8bpp_black,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PPM Read 1x1 8bpp (white)",
+ .tst_fn = test_read,
+ .data = &PPM_ascii_1x1_8bpp_white,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PPM Read 1x1 8bpp (white) Raw",
+ .tst_fn = test_read,
+ .data = &PPM_bin_1x1_8bpp_white,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = NULL},
+ }
+};
diff --git a/tests/loaders/PPM.c b/tests/loaders/PPM.c
index 3082ce4..a3c7b84 100644
--- a/tests/loaders/PPM.c
+++ b/tests/loaders/PPM.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -32,16 +32,18 @@
#define LOAD GP_LoadPPM
#define SAVE GP_SavePPM
+#define READ GP_ReadPPM
#include "Loader.h"
+#include "PPM.h"
-struct testcase black_1x1 = {
+static struct testcase PPM_black_1x1 = {
.w = 1,
.h = 1,
.pix = 0,
.path = "black_1x1.ppm",
};
-struct testcase_save_load save_load = {
+static struct testcase_save_load PPM_save_load = {
.w = 100,
.h = 100,
.pixel_type = GP_PIXEL_RGB888,
@@ -53,12 +55,32 @@ const struct tst_suite tst_suite = {
{.name = "PPM Load 1x1 (black)",
.tst_fn = test_load,
.res_path = "data/ppm/valid/black_1x1.ppm",
- .data = &black_1x1,
+ .data = &PPM_black_1x1,
.flags = TST_TMPDIR | TST_CHECK_MALLOC},
+ {.name = "PPM Read 1x1 4bpp (black)",
+ .tst_fn = test_read,
+ .data = &PPM_ascii_1x1_4bpp_black,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PPM Read 1x1 8bpp (black)",
+ .tst_fn = test_read,
+ .data = &PPM_ascii_1x1_8bpp_black,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PPM Read 1x1 8bpp (white)",
+ .tst_fn = test_read,
+ .data = &PPM_ascii_1x1_8bpp_white,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "PPM Read 1x1 8bpp (white) Raw",
+ .tst_fn = test_read,
+ .data = &PPM_bin_1x1_8bpp_white,
+ .flags = TST_CHECK_MALLOC},
+
{.name = "PPM Save Load",
.tst_fn = test_save_load,
- .data = &save_load,
+ .data = &PPM_save_load,
.flags = TST_TMPDIR | TST_CHECK_MALLOC},
{.name = "PPM Load wrong header",
diff --git a/tests/loaders/PPM.c b/tests/loaders/PPM.h
similarity index 57%
copy from tests/loaders/PPM.c
copy to tests/loaders/PPM.h
index 3082ce4..7de53a7 100644
--- a/tests/loaders/PPM.c
+++ b/tests/loaders/PPM.h
@@ -16,63 +16,52 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
-#include <string.h>
-#include <errno.h>
-#include <sys/stat.h>
-
-#include <core/GP_Context.h>
-#include <core/GP_GetPutPixel.h>
-#include <loaders/GP_Loaders.h>
-
-#include "tst_test.h"
-
-#define LOAD GP_LoadPPM
-#define SAVE GP_SavePPM
#include "Loader.h"
-struct testcase black_1x1 = {
+static struct testcase PPM_ascii_1x1_4bpp_black = {
.w = 1,
.h = 1,
.pix = 0,
- .path = "black_1x1.ppm",
+ .path = "P3n"
+ "# 1x1 black PPM ascii 4bpp imagen"
+ "1 1n"
+ "15n"
+ "0 0 0"
};
-struct testcase_save_load save_load = {
- .w = 100,
- .h = 100,
- .pixel_type = GP_PIXEL_RGB888,
+static struct testcase PPM_ascii_1x1_8bpp_black = {
+ .w = 1,
+ .h = 1,
+ .pix = 0,
+ .path = "P3n"
+ "# 1x1 black PPM ascii 8bpp imagen"
+ "1 1n"
+ "255n"
+ "0 0 0"
};
-const struct tst_suite tst_suite = {
- .suite_name = "PPM",
- .tests = {
- {.name = "PPM Load 1x1 (black)",
- .tst_fn = test_load,
- .res_path = "data/ppm/valid/black_1x1.ppm",
- .data = &black_1x1,
- .flags = TST_TMPDIR | TST_CHECK_MALLOC},
-
- {.name = "PPM Save Load",
- .tst_fn = test_save_load,
- .data = &save_load,
- .flags = TST_TMPDIR | TST_CHECK_MALLOC},
-
- {.name = "PPM Load wrong header",
- .tst_fn = test_load_fail,
- .res_path = "data/ppm/corrupt/wrong_header.ppm",
- .data = "wrong_header.ppm",
- .flags = TST_TMPDIR | TST_CHECK_MALLOC},
-
- {.name = "PPM Load incomplete",
- .tst_fn = test_load_fail,
- .res_path = "data/ppm/corrupt/incomplete.ppm",
- .data = "incomplete.ppm",
- .flags = TST_TMPDIR | TST_CHECK_MALLOC},
+static struct testcase PPM_ascii_1x1_8bpp_white = {
+ .w = 1,
+ .h = 1,
+ .pix = 0xffffff,
+ .path = "P3n"
+ "# 1x1 white PPM ascii 8bpp imagen"
+ "1 1n"
+ "255n"
+ "255 255 255"
+};
- {.name = NULL},
- }
+static struct testcase PPM_bin_1x1_8bpp_white = {
+ .w = 1,
+ .h = 1,
+ .pix = 0xffffff,
+ .path = "P6n"
+ "# 1x1 white PPM binary 8bpp imagen"
+ "1 1n"
+ "255n"
+ "xffxffxff"
};
diff --git a/tests/loaders/test_list.txt b/tests/loaders/test_list.txt
index add0cb3..d4410cb 100644
--- a/tests/loaders/test_list.txt
+++ b/tests/loaders/test_list.txt
@@ -4,6 +4,7 @@ PNG
PBM
PGM
PPM
+PNM
ZIP
GIF
IO
http://repo.or.cz/w/gfxprim.git/commit/5955c59467a2b043812d2fa02c783b1c9e4e…
commit 5955c59467a2b043812d2fa02c783b1c9e4e2562
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Wed Jan 15 22:03:58 2014 +0100
text: Fix GP_VALIGN_BASELINE.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/demos/c_simple/textaligntest.c b/demos/c_simple/textaligntest.c
index 1e8a77d..70b2fd2 100644
--- a/demos/c_simple/textaligntest.c
+++ b/demos/c_simple/textaligntest.c
@@ -19,14 +19,15 @@
* Copyright (C) 2009-2010 Jiri "BlueBear" Dluhos *
* <jiri.bluebear.dluhos(a)gmail.com> *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
+#include <stdio.h>
#include <GP.h>
static GP_Pixel black_pixel, red_pixel, yellow_pixel, green_pixel, blue_pixel,
- darkgray_pixel;
+ darkgray_pixel, white_pixel;
static int font_flag = 0;
@@ -34,6 +35,7 @@ static int X = 640;
static int Y = 480;
static GP_FontFace *font = NULL;
+static GP_TextStyle style = GP_DEFAULT_TEXT_STYLE;
static GP_Backend *win;
@@ -45,8 +47,6 @@ void redraw_screen(void)
GP_HLine(win->context, 0, X, Y/2, darkgray_pixel);
GP_VLine(win->context, X/2, 0, Y, darkgray_pixel);
- GP_TextStyle style = GP_DEFAULT_TEXT_STYLE;
-
switch (font_flag) {
case 0:
style.font = &GP_DefaultProportionalFont;
@@ -55,6 +55,15 @@ void redraw_screen(void)
style.font = &GP_DefaultConsoleFont;
break;
case 2:
+ style.font = GP_FontTinyMono;
+ break;
+ case 3:
+ style.font = GP_FontTiny;
+ break;
+ case 4:
+ style.font = GP_FontC64;
+ break;
+ case 5:
style.font = font;
break;
}
@@ -67,6 +76,10 @@ void redraw_screen(void)
blue_pixel, black_pixel, "top right");
GP_Text(win->context, &style, X/2, Y/2, GP_ALIGN_LEFT|GP_VALIGN_ABOVE,
green_pixel, black_pixel, "top left");
+
+ GP_HLine(win->context, 0, X, Y/3, darkgray_pixel);
+ GP_Text(win->context, &style, X/2, Y/3, GP_ALIGN_CENTER|GP_VALIGN_BASELINE,
+ white_pixel, black_pixel, "x center y baseline");
}
static void event_loop(void)
@@ -96,13 +109,29 @@ static void event_loop(void)
font_flag++;
if (font) {
- if (font_flag >= 3)
+ if (font_flag > 5)
font_flag = 0;
} else {
- if (font_flag >= 2)
+ if (font_flag > 4)
font_flag = 0;
}
break;
+ case GP_KEY_UP:
+ style.pixel_xspace++;
+ style.pixel_yspace++;
+ break;
+ case GP_KEY_DOWN:
+ style.pixel_xspace--;
+ style.pixel_yspace--;
+ break;
+ case GP_KEY_RIGHT:
+ style.pixel_xmul++;
+ style.pixel_ymul++;
+ break;
+ case GP_KEY_LEFT:
+ style.pixel_xmul--;
+ style.pixel_ymul--;
+ break;
case GP_KEY_ESC:
GP_BackendExit(win);
exit(0);
@@ -127,10 +156,12 @@ static void event_loop(void)
void print_instructions(void)
{
printf("Use the following keys to control the test:n");
- printf(" Space ........ toggle proportional/nonproportional fontn");
+ printf(" Space ........ toggle fontn");
printf(" X ............ mirror Xn");
printf(" Y ............ mirror Yn");
printf(" R ............ reverse X and Yn");
+ printf(" UP/DOWN ...... increase/decrease X and Y spacen");
+ printf(" RIGHT/LEFT ... increase/decrease X and Y muln");
}
int main(int argc, char *argv[])
@@ -138,7 +169,7 @@ int main(int argc, char *argv[])
const char *backend_opts = "X11";
if (argc > 1)
- font = GP_FontFaceLoad(argv[1], 0, 16);
+ font = GP_FontFaceLoad(argv[1], 0, 20);
print_instructions();
@@ -155,6 +186,7 @@ int main(int argc, char *argv[])
blue_pixel = GP_ColorToContextPixel(GP_COL_BLUE, win->context);
green_pixel = GP_ColorToContextPixel(GP_COL_GREEN, win->context);
yellow_pixel = GP_ColorToContextPixel(GP_COL_YELLOW, win->context);
+ white_pixel = GP_ColorToContextPixel(GP_COL_WHITE, win->context);
darkgray_pixel = GP_ColorToContextPixel(GP_COL_GRAY_DARK, win->context);
redraw_screen();
diff --git a/libs/text/GP_Text.c b/libs/text/GP_Text.c
index 07df462..14a28e7 100644
--- a/libs/text/GP_Text.c
+++ b/libs/text/GP_Text.c
@@ -19,13 +19,14 @@
* Copyright (C) 2009-2011 Jiri "BlueBear" Dluhos *
* <jiri.bluebear.dluhos(a)gmail.com> *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
#include "gfx/GP_Gfx.h"
#include "core/GP_FnPerBpp.h"
#include "core/GP_Debug.h"
+#include "GP_TextMetric.h"
#include "GP_Text.h"
GP_TextStyle GP_DefaultStyle = GP_DEFAULT_TEXT_STYLE;
@@ -34,7 +35,7 @@ static int do_align(GP_Coord *topleft_x, GP_Coord *topleft_y, int align,
GP_Coord x, GP_Coord y, const GP_TextStyle *style,
GP_Size width)
{
- int height = GP_TextHeight(style);
+ GP_Size height = GP_TextHeight(style);
switch (align & 0x0f) {
case GP_ALIGN_LEFT:
@@ -59,7 +60,7 @@ static int do_align(GP_Coord *topleft_x, GP_Coord *topleft_y, int align,
*topleft_y = y - height/2;
break;
case GP_VALIGN_BASELINE:
- // *topleft_y = y - height + style->font->baseline;
+ *topleft_y = y - GP_TextAscent(style) + 1;
break;
case GP_VALIGN_BELOW:
*topleft_y = y;
@@ -86,6 +87,7 @@ void GP_Text(GP_Context *context, const GP_TextStyle *style,
style = &GP_DefaultStyle;
GP_Coord topleft_x, topleft_y;
+
GP_Size w = GP_TextWidth(style, str);
GP_ASSERT(do_align(&topleft_x, &topleft_y, align, x, y, style, w) == 0,
diff --git a/libs/text/GP_TextMetric.c b/libs/text/GP_TextMetric.c
index 9c98ad7..d1a4ea6 100644
--- a/libs/text/GP_TextMetric.c
+++ b/libs/text/GP_TextMetric.c
@@ -123,9 +123,9 @@ static const GP_TextStyle *assert_style(const GP_TextStyle *style)
*
* There are two problems with text width it's start and it's end.
*
- * At the start the first letter may have bearing_x negative, making it
- * overflow out of the bouding box and even in case it's possitive the returned
- * size would be slightly bigger. This one is easy to fix.
+ * First letter may have bearing_x negative, making it overflow out of the
+ * bouding box and even in case it's possitive the returned size would be
+ * slightly bigger. This one is easy to fix.
*
* The end of the string is problematic too, some of the glyphs may have
* advance smaller than sum of the bitmap width and bearing_x that way we would
@@ -145,9 +145,8 @@ unsigned int GP_TextWidth(const GP_TextStyle *style, const char *str)
return 0;
/* special case, one letter */
- if (str[1] == '0') {
+ if (str[1] == '0')
return glyph_width(style, str[0]);
- }
/* first letter */
len = first_glyph_width(style, str[0]) + style->char_xspace;
http://repo.or.cz/w/gfxprim.git/commit/503fa7970aed181aa853406c3e04f6debaa7…
commit 503fa7970aed181aa853406c3e04f6debaa7d5dd
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Wed Jan 15 21:45:54 2014 +0100
GP_Text: Fix rendering xspace handling and ymul.
The xspace should be multiplied by (width - 1) not by width in order to
be consistent with GP_TextWidth().
Moreover the 8 BPP ymul was never working, fix it.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/libs/text/GP_Text.gen.c.t b/libs/text/GP_Text.gen.c.t
index 479cfb7..b15d33a 100644
--- a/libs/text/GP_Text.gen.c.t
+++ b/libs/text/GP_Text.gen.c.t
@@ -1,3 +1,28 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2011 Jiri "BlueBear" Dluhos *
+ * <jiri.bluebear.dluhos(a)gmail.com> *
+ * *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
%% extends "base.c.t"
{% block descr %}Text rendering rutines{% endblock %}
@@ -12,6 +37,11 @@
#define WIDTH_TO_1BPP_BPP(width) ((width)/8 + ((width)%8 != 0))
+static int get_width(GP_TextStyle *style, int width)
+{
+ return width * style->pixel_xmul + (width - 1) * style->pixel_xspace;
+}
+
%% for pt in pixeltypes
%% if not pt.is_unknown()
@@ -58,10 +88,10 @@ static void text_draw_1BPP_{{ pt.name }}(GP_Context *context, GP_TextStyle *styl
y += style->pixel_ymul + style->pixel_yspace;
}
- x += glyph->advance_x * x_mul + style->char_xspace;
+ x += get_width(style, glyph->advance_x) + style->char_xspace;
if (p == str)
- x -= glyph->bearing_x * x_mul;
+ x -= get_width(style, glyph->bearing_x);
}
}
@@ -118,14 +148,14 @@ static void text_draw_1BPP(GP_Context *context, GP_TextStyle *style, int x, int
for (k = 0; k < style->pixel_ymul; k++) {
%% if use_bg
- GP_HLine(context, x_start, x_start + style->pixel_xmul - 1, cur_y,
+ GP_HLine(context, x_start, x_start + style->pixel_xmul - 1, cur_y + k,
GP_MIX_PIXELS_{{ pt.name }}(fg, bg, gray));
%% else
unsigned int l;
for (l = x_start; l < x_start + style->pixel_xmul; l++) {
unsigned int px = l;
- unsigned int py = cur_y;
+ unsigned int py = cur_y + k;
//TODO: optimize this
GP_TRANSFORM_POINT(context, px, py);
GP_MixPixel_Raw_Clipped_{{ pt.name }}(context, px, py, fg, gray);
@@ -137,10 +167,10 @@ static void text_draw_1BPP(GP_Context *context, GP_TextStyle *style, int x, int
y += style->pixel_ymul + style->pixel_yspace;
}
- x += glyph->advance_x * x_mul + style->char_xspace;
+ x += get_width(style, glyph->advance_x) + style->char_xspace;
if (p == str)
- x -= glyph->bearing_x * x_mul;
+ x -= get_width(style, glyph->bearing_x);
}
%% endmacro
http://repo.or.cz/w/gfxprim.git/commit/9fa629c10033f45505f2348eae343f6eb4a2…
commit 9fa629c10033f45505f2348eae343f6eb4a2b01b
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Wed Jan 15 21:17:18 2014 +0100
GP_Text.gen.c.t: Fix whitespaces.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/libs/text/GP_Text.gen.c.t b/libs/text/GP_Text.gen.c.t
index 8df9c36..479cfb7 100644
--- a/libs/text/GP_Text.gen.c.t
+++ b/libs/text/GP_Text.gen.c.t
@@ -28,7 +28,7 @@ static void text_draw_1BPP_{{ pt.name }}(GP_Context *context, GP_TextStyle *styl
if (glyph == NULL)
glyph = GP_GetGlyphBitmap(style->font, ' ');
-
+
int i, j, k;
unsigned int x_mul = style->pixel_xmul + style->pixel_xspace;
@@ -41,15 +41,15 @@ static void text_draw_1BPP_{{ pt.name }}(GP_Context *context, GP_TextStyle *styl
for (j = 0; j < glyph->height; j++) {
for (i = 0; i < glyph->width; i++) {
uint8_t bit = (glyph->bitmap[i/8 + j * bpp]) & (0x80>>(i%8));
-
+
unsigned int x_start = x + (i + glyph->bearing_x) * x_mul;
-
+
if (p == str)
x_start -= glyph->bearing_x * x_mul;
if (!bit)
continue;
-
+
for (k = 0; k < style->pixel_ymul; k++)
GP_HLine(context, x_start, x_start + style->pixel_xmul - 1,
y - (glyph->bearing_y - style->font->ascend) * y_mul + k, fg);
@@ -57,9 +57,9 @@ static void text_draw_1BPP_{{ pt.name }}(GP_Context *context, GP_TextStyle *styl
y += style->pixel_ymul + style->pixel_yspace;
}
-
+
x += glyph->advance_x * x_mul + style->char_xspace;
-
+
if (p == str)
x -= glyph->bearing_x * x_mul;
}
@@ -94,7 +94,7 @@ static void text_draw_1BPP(GP_Context *context, GP_TextStyle *style, int x, int
if (glyph == NULL)
glyph = GP_GetGlyphBitmap(style->font, ' ');
-
+
int i, j, k;
unsigned int x_mul = style->pixel_xmul + style->pixel_xspace;
@@ -105,12 +105,12 @@ static void text_draw_1BPP(GP_Context *context, GP_TextStyle *style, int x, int
for (j = 0; j < glyph->height; j++) {
for (i = 0; i < glyph->width; i++) {
uint8_t gray = glyph->bitmap[i + j * glyph->width];
-
+
unsigned int x_start = x + (i + glyph->bearing_x) * x_mul;
-
+
if (p == str)
x_start -= glyph->bearing_x * x_mul;
-
+
if (!gray)
continue;
@@ -119,10 +119,10 @@ static void text_draw_1BPP(GP_Context *context, GP_TextStyle *style, int x, int
for (k = 0; k < style->pixel_ymul; k++) {
%% if use_bg
GP_HLine(context, x_start, x_start + style->pixel_xmul - 1, cur_y,
- GP_MIX_PIXELS_{{ pt.name }}(fg, bg, gray));
+ GP_MIX_PIXELS_{{ pt.name }}(fg, bg, gray));
%% else
unsigned int l;
-
+
for (l = x_start; l < x_start + style->pixel_xmul; l++) {
unsigned int px = l;
unsigned int py = cur_y;
@@ -138,7 +138,7 @@ static void text_draw_1BPP(GP_Context *context, GP_TextStyle *style, int x, int
}
x += glyph->advance_x * x_mul + style->char_xspace;
-
+
if (p == str)
x -= glyph->bearing_x * x_mul;
}
http://repo.or.cz/w/gfxprim.git/commit/1486958906f687d667ff7c47c2af60c4110b…
commit 1486958906f687d667ff7c47c2af60c4110bd0c9
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Wed Jan 15 19:47:21 2014 +0100
spiv: image action: Fix command buffer allocation.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/demos/spiv/image_actions.c b/demos/spiv/image_actions.c
index afeebe6..ad875d1 100644
--- a/demos/spiv/image_actions.c
+++ b/demos/spiv/image_actions.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -204,6 +204,23 @@ static char *cmd = NULL;
static size_t cmd_size;
static size_t cmd_pos;
+#define CMD_CHUNK 1024
+
+static int cmd_resize(void)
+{
+ char *new_cmd = realloc(cmd, cmd_size + CMD_CHUNK);
+
+ if (!new_cmd) {
+ fprintf(stderr, "Failed to allocate command buffern");
+ return 1;
+ }
+
+ cmd = new_cmd;
+ cmd_size += CMD_CHUNK;
+
+ return 0;
+}
+
static int cmd_append(const char *str, size_t len)
{
if (len == 0)
@@ -211,8 +228,8 @@ static int cmd_append(const char *str, size_t len)
/* Initial allocation size */
if (!cmd) {
- cmd = malloc(1024);
- cmd_size = 1024;
+ cmd = malloc(CMD_CHUNK);
+ cmd_size = CMD_CHUNK;
}
if (!cmd) {
@@ -220,13 +237,9 @@ static int cmd_append(const char *str, size_t len)
return 1;
}
- if (cmd_size - cmd_pos <= len) {
- char *new_cmd = realloc(cmd, cmd_size + 1024);
-
- if (new_cmd == NULL) {
- fprintf(stderr, "Failed to allocated command buffern");
+ while (cmd_size - cmd_pos <= len) {
+ if (cmd_resize())
return 1;
- }
}
memcpy(cmd + cmd_pos, str, len);
@@ -244,12 +257,8 @@ static int cmd_append_escape(const char *str, size_t len)
len = strlen(str);
while ((ret = escape(str, len, cmd + cmd_pos, cmd_size - cmd_pos)) < 0) {
- char *new_cmd = realloc(cmd, cmd_size + 1024);
-
- if (new_cmd == NULL) {
- fprintf(stderr, "Failed to allocated command buffern");
+ if (cmd_resize())
return 1;
- }
}
cmd_pos += ret;
http://repo.or.cz/w/gfxprim.git/commit/c7a22b3bf489a9a42e29e66af3890f250e4a…
commit c7a22b3bf489a9a42e29e66af3890f250e4a42df
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Wed Jan 15 19:44:43 2014 +0100
spiv: help: Fix email address.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/demos/spiv/spiv.1 b/demos/spiv/spiv.1
index 6599330..386706e 100644
--- a/demos/spiv/spiv.1
+++ b/demos/spiv/spiv.1
@@ -309,12 +309,12 @@ spiv -b 'X11:create_root' -t 10 images/
Bugs happen. If you find one, report it on the GFXprim mailing list at
.I gfxprim(a)ucw.cz
.SH AUTHORS
-Spiv is developed by Cyril Hrubis <chrubis(a)ucw.cz>
+Spiv is developed by Cyril Hrubis <metan(a)ucw.cz>
.PP
GFXprim was/is developed by:
.PP
.nf
-Cyril Hrubis <chrubis(a)ucw.cz>
+Cyril Hrubis <metan(a)ucw.cz>
.nf
Jiri "BlueBear" Dluhos <jiri.bluebear.dluhos(a)gmail.com>
.nf
diff --git a/demos/spiv/spiv_help.c b/demos/spiv/spiv_help.c
index 0f9e222..3af2b03 100644
--- a/demos/spiv/spiv_help.c
+++ b/demos/spiv/spiv_help.c
@@ -181,9 +181,9 @@ static const char *man_tail =
"Bugs happen. If you find one, report it on the GFXprim mailing list atn"
".I gfxprim(a)ucw.czn"
".SH AUTHORSn"
- "Spiv is developed by Cyril Hrubis <chrubis(a)ucw.cz>n"
+ "Spiv is developed by Cyril Hrubis <metan(a)ucw.cz>n"
".PPnGFXprim was/is developed by:n"
- ".PPn.nfnCyril Hrubis <chrubis(a)ucw.cz>n"
+ ".PPn.nfnCyril Hrubis <metan(a)ucw.cz>n"
".nfnJiri "BlueBear" Dluhos <jiri.bluebear.dluhos(a)gmail.com>n"
".nfnTomas Gavenciak <gavento(a)ucw.cz>n";
-----------------------------------------------------------------------
Summary of changes:
build/syms/Loaders_symbols.txt | 1 -
demos/c_simple/Makefile | 3 +-
demos/c_simple/byte_utils.c | 93 --------------
demos/c_simple/textaligntest.c | 48 ++++++--
demos/spiv/image_actions.c | 37 ++++--
demos/spiv/spiv.1 | 4 +-
demos/spiv/spiv_help.c | 4 +-
include/loaders/GP_ByteUtils.h | 33 -----
libs/gfx/GP_Polygon.c | 2 +-
libs/loaders/GP_ByteUtils.c | 50 --------
libs/loaders/GP_GIF.c | 4 +-
libs/loaders/GP_IO.c | 6 +-
libs/text/GP_Text.c | 8 +-
libs/text/GP_Text.gen.c.t | 68 +++++++---
libs/text/GP_TextMetric.c | 9 +-
pylib/gfxprim/loaders/loaders.i | 63 ++++------
tests/loaders/{test_list.txt => .gitignore} | 14 +-
tests/loaders/Loader.h | 103 ++++++++++++---
tests/loaders/Makefile | 4 +-
tests/loaders/PBM.c | 24 ++++-
include/loaders/GP_JP2.h => tests/loaders/PBM.h | 73 ++++++-----
tests/loaders/PGM.c | 64 +++++++++-
tests/loaders/PGM.h | 155 +++++++++++++++++++++++
tests/loaders/PNM.c | 147 +++++++++++++++++++++
tests/loaders/PPM.c | 32 ++++-
include/loaders/GP_GIF.h => tests/loaders/PPM.h | 69 ++++++----
tests/loaders/test_list.txt | 1 +
27 files changed, 746 insertions(+), 373 deletions(-)
delete mode 100644 demos/c_simple/byte_utils.c
copy tests/loaders/{test_list.txt => .gitignore} (77%)
copy include/loaders/GP_JP2.h => tests/loaders/PBM.h (70%)
create mode 100644 tests/loaders/PGM.h
create mode 100644 tests/loaders/PNM.c
copy include/loaders/GP_GIF.h => tests/loaders/PPM.h (68%)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
11 Jan '14
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via 2ac9facaf575685be1e6ab95492f2c5bf0562567 (commit)
from 7365572a6c0e30a31eb955994a9414fad2fd39f6 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/2ac9facaf575685be1e6ab95492f2c5bf056…
commit 2ac9facaf575685be1e6ab95492f2c5bf0562567
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sat Jan 11 23:06:27 2014 +0100
loaders: JPG: Fix skip_input_data()
Fix stupid bug in skip_input_data().
The size of data in buffer needs to be first substracted from the seek
bytes and then zeroed, not the other way around.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/libs/loaders/GP_JPG.c b/libs/loaders/GP_JPG.c
index 0457cba..9d19d9c 100644
--- a/libs/loaders/GP_JPG.c
+++ b/libs/loaders/GP_JPG.c
@@ -172,8 +172,8 @@ static void skip_input_data(struct jpeg_decompress_struct *cinfo, long num_bytes
GP_DEBUG(3, "Skipping %li bytes", num_bytes);
if (src->mgr.bytes_in_buffer < (unsigned long)num_bytes) {
- src->mgr.bytes_in_buffer = 0;
GP_IOSeek(src->io, num_bytes - src->mgr.bytes_in_buffer, GP_IO_SEEK_CUR);
+ src->mgr.bytes_in_buffer = 0;
} else {
src->mgr.bytes_in_buffer -= num_bytes;
src->mgr.next_input_byte += num_bytes;
-----------------------------------------------------------------------
Summary of changes:
libs/loaders/GP_JPG.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
11 Jan '14
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via 7365572a6c0e30a31eb955994a9414fad2fd39f6 (commit)
via e275d5c011bbd00f9bb26df13ff53196e6ba71cd (commit)
via 56b6786f99a94d99b003a93a3de7f4993d25d6e9 (commit)
from 8a2d9db9af54358efd9752da3299edb678abd8c3 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/7365572a6c0e30a31eb955994a9414fad2fd…
commit 7365572a6c0e30a31eb955994a9414fad2fd39f6
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sat Jan 11 21:13:09 2014 +0100
loaders: TIFF: Change tmsize_t to tsize_t
Fixes build with tiff 3.9.6
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/libs/loaders/GP_TIFF.c b/libs/loaders/GP_TIFF.c
index 5ecdf19..f8e56d6 100644
--- a/libs/loaders/GP_TIFF.c
+++ b/libs/loaders/GP_TIFF.c
@@ -435,12 +435,12 @@ static int tiff_read(TIFF *tiff, GP_Context *res, struct tiff_header *header,
return 0;
}
-static tmsize_t tiff_io_read(thandle_t io, void *buf, tmsize_t size)
+static tsize_t tiff_io_read(thandle_t io, void *buf, tsize_t size)
{
return GP_IORead(io, buf, size);
}
-static tmsize_t tiff_io_write(thandle_t io, void *buf, tmsize_t size)
+static tsize_t tiff_io_write(thandle_t io, void *buf, tsize_t size)
{
(void) io;
(void) buf;
http://repo.or.cz/w/gfxprim.git/commit/e275d5c011bbd00f9bb26df13ff53196e6ba…
commit e275d5c011bbd00f9bb26df13ff53196e6ba71cd
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Tue Jan 7 19:35:46 2014 +0100
configure: Make use of args.
* Make use of args, so that ./configure CC=gcc works in
addition to CC=gcc ./configure and ./configure --CC=gcc
* Complain loudly on invalid arguments, previously
everything that wasn't option (haven't started with '-'
was silently ignored).
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/configure b/configure
index 728a180..b6e24fb 100755
--- a/configure
+++ b/configure
@@ -318,6 +318,17 @@ def write_gfxprim_config(cfg, libs):
f.close()
os.system('chmod +x gfxprim-config')
+def cfg_parse_args(cfg, args):
+ for i in args:
+ par = i.split('=');
+ if (len(par) != 2):
+ die_screaming('Invalid argument %s' % i)
+
+ if (par[0] not in cfg):
+ die_screaming('Invalid config key %s' % i)
+
+ cfg[par[0]][0] = par[1]
+
if __name__ == '__main__':
#
# Dictionary for default configuration parameters
@@ -429,6 +440,11 @@ if __name__ == '__main__':
if getattr(options, i) is not None:
cfg[i][0] = getattr(options, i)
+ #
+ # Handle args such as CC=gcc passed after options
+ #
+ cfg_parse_args(cfg, args)
+
basic_checks(cfg);
l.check()
http://repo.or.cz/w/gfxprim.git/commit/56b6786f99a94d99b003a93a3de7f4993d25…
commit 56b6786f99a94d99b003a93a3de7f4993d25d6e9
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Tue Jan 7 18:34:52 2014 +0100
loaders: Fix stubs.
Fix GP_ReadJPG() and GP_ReadTIFF() stubs.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/libs/loaders/GP_JPG.c b/libs/loaders/GP_JPG.c
index 8448ba0..0457cba 100644
--- a/libs/loaders/GP_JPG.c
+++ b/libs/loaders/GP_JPG.c
@@ -549,8 +549,8 @@ int GP_OpenJPG(const char GP_UNUSED(*src_path), FILE GP_UNUSED(**f))
return 1;
}
-GP_Context *GP_ReadJPG(FILE GP_UNUSED(*f),
- GP_ProgressCallback GP_UNUSED(*callback))
+GP_Context *GP_ReadJPG(GP_IO GP_UNUSED(*io),
+ GP_ProgressCallback GP_UNUSED(*callback))
{
errno = ENOSYS;
return NULL;
diff --git a/libs/loaders/GP_TIFF.c b/libs/loaders/GP_TIFF.c
index 93e5b42..5ecdf19 100644
--- a/libs/loaders/GP_TIFF.c
+++ b/libs/loaders/GP_TIFF.c
@@ -739,7 +739,7 @@ int GP_OpenTIFF(const char GP_UNUSED(*src_path),
return 1;
}
-GP_Context *GP_ReadTIFF(void GP_UNUSED(*t),
+GP_Context *GP_ReadTIFF(GP_IO GP_UNUSED(*io),
GP_ProgressCallback GP_UNUSED(*callback))
{
errno = ENOSYS;
-----------------------------------------------------------------------
Summary of changes:
configure | 16 ++++++++++++++++
libs/loaders/GP_JPG.c | 4 ++--
libs/loaders/GP_TIFF.c | 6 +++---
3 files changed, 21 insertions(+), 5 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
05 Jan '14
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via 8a2d9db9af54358efd9752da3299edb678abd8c3 (commit)
via bdbe0d6c43da1d7db6e81916f8672ff1df583c40 (commit)
via da87f51a835bae627bf9e1365fd504d04063b312 (commit)
from 68bfb03b0e8eb136310c54be62f50802631fa428 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/8a2d9db9af54358efd9752da3299edb678ab…
commit 8a2d9db9af54358efd9752da3299edb678abd8c3
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jan 5 22:13:37 2014 +0100
loaders: ZIP: Make use of GP_ReadImage()
Now we can finally read any supported image format from a zip file.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/libs/loaders/GP_ZIP.c b/libs/loaders/GP_ZIP.c
index d6cbdd1..c0b417a 100644
--- a/libs/loaders/GP_ZIP.c
+++ b/libs/loaders/GP_ZIP.c
@@ -38,8 +38,7 @@
#include "core/GP_Debug.h"
#include "loaders/GP_ByteUtils.h"
-#include "loaders/GP_JPG.h"
-#include "loaders/GP_PNG.h"
+#include "loaders/GP_Loader.h"
#include "loaders/GP_ZIP.h"
@@ -181,8 +180,6 @@ static int deflate_out(void *out_desc, unsigned char *buf, unsigned len)
struct deflate_outbuf *out = out_desc;
out->crc = crc32(out->crc, buf, len);
- out->size += len;
-
memcpy(out->buf + out->size, buf, len);
out->size += len;
@@ -381,29 +378,19 @@ static GP_Context *zip_next_file(struct zip_priv *priv,
GP_IOMark(priv->io, GP_IO_MARK);
- ret = GP_ReadJPG(priv->io, callback);
-
- if (!ret) {
- GP_IOMark(priv->io, GP_IO_REWIND);
- ret = GP_ReadPNG(priv->io, callback);
- }
+ ret = GP_ReadImage(priv->io, callback);
GP_IOSeek(priv->io, priv->io->mark + header.comp_size, GP_IO_SEEK_SET);
goto out;
break;
case COMPRESS_DEFLATE:
- if (read_deflate(priv->io, &header, &io)) {
+ if ((err = read_deflate(priv->io, &header, &io))) {
err = errno;
goto out;
}
-
- ret = GP_ReadJPG(io, callback);
-
- if (!ret) {
- GP_IORewind(io);
- ret = GP_ReadPNG(io, callback);
- }
+ GP_DEBUG(1, "Reading image");
+ ret = GP_ReadImage(io, callback);
GP_IOClose(io);
goto out;
http://repo.or.cz/w/gfxprim.git/commit/bdbe0d6c43da1d7db6e81916f8672ff1df58…
commit bdbe0d6c43da1d7db6e81916f8672ff1df583c40
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jan 5 22:11:17 2014 +0100
loaders: Add GP_ReadImage()
Add a function that can read an image from an IO stream.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/build/syms/Loaders_symbols.txt b/build/syms/Loaders_symbols.txt
index d2121fe..bac234f 100644
--- a/build/syms/Loaders_symbols.txt
+++ b/build/syms/Loaders_symbols.txt
@@ -62,6 +62,7 @@ GP_LoadTmpFile
GP_MatchSignature
GP_MatchExtension
+GP_ReadImage
GP_LoadImage
GP_SaveImage
GP_LoadMetaData
diff --git a/include/loaders/GP_Loader.h b/include/loaders/GP_Loader.h
index 925f358..3b5bc8f 100644
--- a/include/loaders/GP_Loader.h
+++ b/include/loaders/GP_Loader.h
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -31,8 +31,17 @@
#include "core/GP_Context.h"
#include "core/GP_ProgressCallback.h"
+#include "loaders/GP_IO.h"
+#include "loaders/GP_MetaData.h"
-#include "GP_MetaData.h"
+
+/*
+ * Reads an image from a IO stream.
+ *
+ * The image format is matched from the file signature (first few bytes of the
+ * IO stream).
+ */
+GP_Context *GP_ReadImage(GP_IO *io, GP_ProgressCallback *callback);
/*
* Tries to load image accordingly to the file extension.
@@ -64,14 +73,21 @@ int GP_SaveImage(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
/*
- * You can register your own loader here.
+ * Describes image loader/saver.
*/
typedef struct GP_Loader {
/*
- * Loads an image.
+ * Reads an image from an IO stream.
+ *
+ * Returns newly allocated context cotaining the loaded image or in
+ * case of failure NULL and errno is set.
+ */
+ GP_Context *(*Read)(GP_IO *io, GP_ProgressCallback *callback);
+
+ /*
+ * Loads an image from a file.
*
- * Returns allocated and initialized bitmap on success, NULL on failure
- * and errno must be set.
+ * TODO: Remove due to Read
*/
GP_Context *(*Load)(const char *src_path, GP_ProgressCallback *callback);
diff --git a/libs/loaders/GP_Loader.c b/libs/loaders/GP_Loader.c
index 0abd6d5..aa793ba 100644
--- a/libs/loaders/GP_Loader.c
+++ b/libs/loaders/GP_Loader.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -32,14 +32,15 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <ctype.h>
#include "core/GP_Debug.h"
-#include "GP_Loaders.h"
-
-#include "GP_Loader.h"
+#include "loaders/GP_Loaders.h"
+#include "loaders/GP_Loader.h"
static GP_Loader psp_loader = {
+ .Read = GP_ReadPSP,
.Load = GP_LoadPSP,
.Save = NULL,
.Match = GP_MatchPSP,
@@ -49,6 +50,7 @@ static GP_Loader psp_loader = {
};
static GP_Loader pbm_loader = {
+ .Read = GP_ReadPBM,
.Load = GP_LoadPBM,
.Save = GP_SavePBM,
.Match = GP_MatchPBM,
@@ -58,6 +60,7 @@ static GP_Loader pbm_loader = {
};
static GP_Loader pgm_loader = {
+ .Read = GP_ReadPGM,
.Load = GP_LoadPGM,
.Save = GP_SavePGM,
.Match = GP_MatchPGM,
@@ -67,8 +70,9 @@ static GP_Loader pgm_loader = {
};
static GP_Loader ppm_loader = {
+ .Read = GP_ReadPPM,
.Load = GP_LoadPPM,
- .Save = NULL,
+ .Save = GP_SavePPM,
.Match = GP_MatchPPM,
.fmt_name = "Netpbm portable Pixmap",
.next = &pgm_loader,
@@ -76,8 +80,9 @@ static GP_Loader ppm_loader = {
};
static GP_Loader pnm_loader = {
+ .Read = GP_ReadPNM,
.Load = GP_LoadPNM,
- .Save = NULL,
+ .Save = GP_SavePNM,
/*
* Avoid double Match
* This format is covered by PBM, PGM and PPM
@@ -89,6 +94,7 @@ static GP_Loader pnm_loader = {
};
static GP_Loader jp2_loader = {
+ .Read = GP_ReadJP2,
.Load = GP_LoadJP2,
.Save = NULL,
.Match = GP_MatchJP2,
@@ -98,6 +104,7 @@ static GP_Loader jp2_loader = {
};
static GP_Loader bmp_loader = {
+ .Read = GP_ReadBMP,
.Load = GP_LoadBMP,
.Save = GP_SaveBMP,
.Match = GP_MatchBMP,
@@ -107,6 +114,7 @@ static GP_Loader bmp_loader = {
};
static GP_Loader gif_loader = {
+ .Read = GP_ReadGIF,
.Load = GP_LoadGIF,
.Save = NULL,
.Match = GP_MatchGIF,
@@ -116,6 +124,7 @@ static GP_Loader gif_loader = {
};
static GP_Loader tiff_loader = {
+ .Read = GP_ReadTIFF,
.Load = GP_LoadTIFF,
.Save = GP_SaveTIFF,
.Match = GP_MatchTIFF,
@@ -125,6 +134,7 @@ static GP_Loader tiff_loader = {
};
static GP_Loader png_loader = {
+ .Read = GP_ReadPNG,
.Load = GP_LoadPNG,
.Save = GP_SavePNG,
.Match = GP_MatchPNG,
@@ -134,6 +144,7 @@ static GP_Loader png_loader = {
};
static GP_Loader jpeg_loader = {
+ .Read = GP_ReadJPG,
.Load = GP_LoadJPG,
.Save = GP_SaveJPG,
.Match = GP_MatchJPG,
@@ -183,6 +194,7 @@ void GP_ListLoaders(void)
for (i = loaders; i != NULL; i = i->next) {
printf("Format: %sn", i->fmt_name);
+ printf("Read:t%sn", i->Read ? "Yes" : "No");
printf("Load:t%sn", i->Load ? "Yes" : "No");
printf("Save:t%sn", i->Save ? "Yes" : "No");
printf("Match:t%sn", i->Match ? "Yes" : "No");
@@ -279,6 +291,52 @@ err0:
return NULL;
}
+GP_Context *GP_ReadImage(GP_IO *io, GP_ProgressCallback *callback)
+{
+ char buf[32];
+ off_t start;
+ const GP_Loader *loader;
+
+ start = GP_IOTell(io);
+ if (start == (off_t)-1) {
+ GP_DEBUG(1, "Failed to get IO stream offset: %s",
+ strerror(errno));
+ return NULL;
+ }
+
+ if (GP_IOFill(io, buf, sizeof(buf))) {
+ GP_DEBUG(1, "Failed to read first 32 bytes: %s",
+ strerror(errno));
+ return NULL;
+ }
+
+ if (GP_IOSeek(io, start, GP_IO_SEEK_SET) != start) {
+ GP_DEBUG(1, "Failed to seek at the start of the stream: %s",
+ strerror(errno));
+ return NULL;
+ }
+
+ loader = GP_MatchSignature(buf);
+
+ if (!loader) {
+ GP_DEBUG(1, "Failed to find a loader by signature for"
+ "(%x (%c) %x (%c)...)",
+ buf[0], isprint(buf[0]) ? buf[0] : ' ',
+ buf[1], isprint(buf[1]) ? buf[1] : ' ');
+ errno = ENOSYS;
+ return NULL;
+ }
+
+ if (!loader->Read) {
+ GP_DEBUG(1, "Loader for '%s' does not support reading",
+ loader->fmt_name);
+ errno = ENOSYS;
+ return NULL;
+ }
+
+ return loader->Read(io, callback);
+}
+
GP_Context *GP_LoadImage(const char *src_path, GP_ProgressCallback *callback)
{
int err;
http://repo.or.cz/w/gfxprim.git/commit/da87f51a835bae627bf9e1365fd504d04063…
commit da87f51a835bae627bf9e1365fd504d04063b312
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jan 5 21:29:02 2014 +0100
core: Make GP_DebugPrint() preserve errno.
Now all variants of GP_DebugPrint() (i.e. GP_DEBUG(), GP_WARN(), ...)
preserves errno which simplifies common pattern of:
if (failure) {
err = errno;
GP_DEBUG(1, "Foo has failed");
errno = err;
return 1;
}
to much clearer:
if (failure) {
GP_DEBUG(1, "Foo has failed");
return 1;
}
This commit also adds a test.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/doc/debug.txt b/doc/debug.txt
index 83cf91d..7424064 100644
--- a/doc/debug.txt
+++ b/doc/debug.txt
@@ -69,6 +69,8 @@ void GP_DebugPrint(int level, const char *file, const char *function, int line,
Printf-like macros used to print debug messages. All of them calls the
'GP_DebugPrint()' function with slightly different parameters.
+NOTE: 'GP_DebugPrint()' function preserves 'errno'.
+
[source,c]
-------------------------------------------------------------------------------
enum GP_DebugType {
diff --git a/libs/core/GP_Debug.c b/libs/core/GP_Debug.c
index 9605507..c53ad51 100644
--- a/libs/core/GP_Debug.c
+++ b/libs/core/GP_Debug.c
@@ -16,11 +16,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
#include <stdarg.h>
+#include <errno.h>
#include "core/GP_Version.h"
#include "core/GP_Debug.h"
@@ -49,7 +50,9 @@ void GP_SetDebugHandler(void (*handler)(const struct GP_DebugMsg *msg))
void GP_DebugPrint(int level, const char *file, const char *function, int line,
const char *fmt, ...)
{
- int i;
+ int i, err;
+
+ err = errno;
if (!env_used) {
char *level = getenv("GP_DEBUG");
@@ -72,7 +75,7 @@ void GP_DebugPrint(int level, const char *file, const char *function, int line,
}
if (level > (int)debug_level)
- return;
+ goto end;
/* If handler is set, fill struct msg and call it */
if (debug_handler) {
@@ -93,7 +96,7 @@ void GP_DebugPrint(int level, const char *file, const char *function, int line,
debug_handler(&msg);
- return;
+ goto end;
}
for (i = 1; i < level; i++)
@@ -124,4 +127,6 @@ void GP_DebugPrint(int level, const char *file, const char *function, int line,
va_end(va);
fputc('n', stderr);
+end:
+ errno = err;
}
diff --git a/tests/core/Debug.c b/tests/core/Debug.c
new file mode 100644
index 0000000..a32e7fd
--- /dev/null
+++ b/tests/core/Debug.c
@@ -0,0 +1,77 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+/*
+
+ Test that GP_DEBUG() preserves errno.
+
+ */
+#include <errno.h>
+
+#include <core/GP_Debug.h>
+
+#include "tst_test.h"
+
+static int handler_called;
+
+static void debug_handler(const struct GP_DebugMsg *msg)
+{
+ (void)msg;
+ handler_called = 1;
+ errno = 0;
+ tst_msg("Errno changed in debug handler");
+}
+
+/*
+ * Check that GP_DEBUG() preserves errno.
+ */
+static int DEBUG_preserves_errno(void)
+{
+ GP_SetDebugHandler(debug_handler);
+ GP_SetDebugLevel(1);
+
+ handler_called = 0;
+ errno = 1;
+
+ GP_DEBUG(1, "Debug message");
+
+ if (!handler_called) {
+ tst_msg("Debug handler wasn't called");
+ return TST_FAILED;
+ }
+
+ if (errno != 1) {
+ tst_msg("Errno not preserved");
+ return TST_FAILED;
+ }
+
+ return TST_SUCCESS;
+}
+
+const struct tst_suite tst_suite = {
+ .suite_name = "Debug",
+ .tests = {
+ {.name = "Debug messages preserves errno",
+ .tst_fn = DEBUG_preserves_errno},
+ {.name = NULL},
+ }
+};
diff --git a/tests/core/Makefile b/tests/core/Makefile
index 9ede6dc..737fc17 100644
--- a/tests/core/Makefile
+++ b/tests/core/Makefile
@@ -2,13 +2,13 @@ TOPDIR=../..
include $(TOPDIR)/pre.mk
-CSOURCES=Context.c Pixel.c BlitClipped.c
+CSOURCES=Context.c Pixel.c BlitClipped.c Debug.c
GENSOURCES+=WritePixel.gen.c GetPutPixel.gen.c Convert.gen.c BlitConv.gen.c Convert_Scale.gen.c GetSetBits.gen.c
APPS=WritePixel.gen Pixel Context GetPutPixel.gen Convert.gen BlitConv.gen - Convert_Scale.gen GetSetBits.gen BlitClipped
+ Convert_Scale.gen GetSetBits.gen BlitClipped Debug
include ../tests.mk
diff --git a/tests/core/test_list.txt b/tests/core/test_list.txt
index c728b8b..1ff15be 100644
--- a/tests/core/test_list.txt
+++ b/tests/core/test_list.txt
@@ -8,3 +8,4 @@ Convert.gen
Convert_Scale.gen
BlitConv.gen
BlitClipped
+Debug
-----------------------------------------------------------------------
Summary of changes:
build/syms/Loaders_symbols.txt | 1 +
doc/debug.txt | 2 +
include/loaders/GP_Loader.h | 28 ++++++++++---
libs/core/GP_Debug.c | 13 ++++--
libs/loaders/GP_Loader.c | 70 ++++++++++++++++++++++++++++++---
libs/loaders/GP_ZIP.c | 23 ++--------
tests/{loaders/GIF.c => core/Debug.c} | 61 ++++++++++++++++------------
tests/core/Makefile | 4 +-
tests/core/test_list.txt | 1 +
9 files changed, 141 insertions(+), 62 deletions(-)
copy tests/{loaders/GIF.c => core/Debug.c} (71%)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
discards 10a52540db85b4635b27062dc42e5be14f760088 (commit)
via 68bfb03b0e8eb136310c54be62f50802631fa428 (commit)
This update added new revisions after undoing existing revisions. That is
to say, the old revision is not a strict subset of the new revision. This
situation occurs when you --force push a change and generate a repository
containing something like this:
* -- * -- B -- O -- O -- O (10a52540db85b4635b27062dc42e5be14f760088)
N -- N -- N (68bfb03b0e8eb136310c54be62f50802631fa428)
When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/68bfb03b0e8eb136310c54be62f50802631f…
commit 68bfb03b0e8eb136310c54be62f50802631fa428
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sat Jan 4 00:55:28 2014 +0100
loaders: Add I/O abstraction and convert loaders.
This commit adds and abstract I/O interface and converts all image
loaders to use it. This is a big step towards better faster and nicer
containers (i.e. tar, tar.bz2, tar, etc...). It also allows you to read
images from memory or whatever else by implementing simple read() and
seek() wrappers.
It also updates loaders documentation, adds a few testcases and example
for loading images from a memory buffer.
BEWARE: The work is not finalized and only basically tested. The ZIP
loader is a bit broken (seeking does not work correctly).
(More tests and fixes will come soon)
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/build/syms/Loaders_symbols.txt b/build/syms/Loaders_symbols.txt
index e424e98..d2121fe 100644
--- a/build/syms/Loaders_symbols.txt
+++ b/build/syms/Loaders_symbols.txt
@@ -2,7 +2,6 @@ GP_FWrite
GP_FRead
GP_MatchJPG
-GP_OpenJPG
GP_ReadJPG
GP_LoadJPG
GP_SaveJPG
@@ -10,7 +9,6 @@ GP_ReadJPGMetaData
GP_LoadJPGMetaData
GP_MatchPNG
-GP_OpenPNG
GP_ReadPNG
GP_LoadPNG
GP_ReadPNGMetaData
@@ -18,45 +16,44 @@ GP_LoadPNGMetaData
GP_SavePNG
GP_MatchBMP
-GP_OpenBMP
GP_LoadBMP
GP_ReadBMP
GP_SaveBMP
GP_MatchPSP
-GP_OpenPSP
GP_ReadPSP
GP_LoadPSP
GP_MatchGIF
GP_LoadGIF
GP_ReadGIF
-GP_OpenGIF
GP_MatchTIFF
-GP_OpenTIFF
GP_ReadTIFF
GP_LoadTIFF
GP_SaveTIFF
-GP_SavePBM
+GP_ReadPBM
GP_LoadPBM
+GP_SavePBM
GP_MatchPBM
-GP_SavePGM
+GP_ReadPGM
GP_LoadPGM
+GP_SavePGM
GP_MatchPGM
-GP_SavePPM
+GP_ReadPPM
GP_LoadPPM
+GP_SavePPM
GP_MatchPPM
+GP_ReadPNM
GP_LoadPNM
GP_SavePNM
GP_MatchPNM
GP_ReadJP2
-GP_OpenJP2
GP_LoadJP2
GP_MatchJP2
@@ -94,3 +91,10 @@ GP_OpenZip
GP_LineConvertible
GP_LineConvertGet
+
+GP_IOFile
+GP_IOMem
+GP_IOMark
+GP_IOSize
+GP_IOFill
+GP_IOReadF
diff --git a/demos/c_simple/Makefile b/demos/c_simple/Makefile
index 2d91834..68fa14a 100644
--- a/demos/c_simple/Makefile
+++ b/demos/c_simple/Makefile
@@ -19,7 +19,7 @@ APPS=backend_example loaders_example loaders filters_symmetry gfx_koch input_example fileview linetest randomshapetest fonttest loaders_register blittest textaligntest sin_AA x11_windows debug_handler gaussian_noise byte_utils version pretty_print timers- zip_container backend_timers_example
+ zip_container backend_timers_example memory_io
ifeq ($(HAVE_LIBSDL),yes)
APPS+=SDL_glue
@@ -57,6 +57,7 @@ blittest: LDLIBS+=$(LDLIBS_BACKENDS) $(LDLIBS_LOADERS)
sin_AA: LDLIBS+=$(LDLIBS_BACKENDS)
x11_windows: LDLIBS+=$(LDLIBS_BACKENDS)
zip_container: LDLIBS+=$(LDLIBS_LOADERS) $(LDLIBS_BACKENDS)
+memory_io: LDLIBS+=$(LDLIBS_BACKENDS) $(LDLIBS_LOADERS)
include $(TOPDIR)/app.mk
include $(TOPDIR)/post.mk
diff --git a/demos/c_simple/memory_io.c b/demos/c_simple/memory_io.c
new file mode 100644
index 0000000..873b27c
--- /dev/null
+++ b/demos/c_simple/memory_io.c
@@ -0,0 +1,118 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+ /*
+
+ Simple memory IO example.
+
+ */
+
+#include <stdio.h>
+#include <GP.h>
+
+/*
+ * Binary PGM stored in an array
+ */
+static char pgm[] = {
+ /* header */
+ 'P', '5', 'n',
+ '1', '0', ' ', '1', '0', 'n',
+ '2', '5', '5', 'n',
+ /* data */
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+};
+
+#define WIN_W 100
+#define WIN_H 100
+
+int main(void)
+{
+ GP_Backend *b;
+ GP_Context *img;
+ GP_IO *io;
+
+ io = GP_IOMem(pgm, sizeof(pgm), NULL);
+
+ if (!io) {
+ fprintf(stderr, "Failed to initialize IOn");
+ return 1;
+ }
+
+ img = GP_ReadPGM(io, NULL);
+ GP_IOClose(io);
+
+ if (!img) {
+ fprintf(stderr, "Failed to load imagen");
+ return 1;
+ }
+
+ b = GP_BackendX11Init(NULL, 0, 0, WIN_W, WIN_H, "IO Example", 0);
+
+ if (!b) {
+ fprintf(stderr, "Failed to initialize backendn");
+ return 1;
+ }
+
+ GP_Fill(b->context, 0);
+ GP_Blit_Clipped(img, 0, 0, img->w, img->h, b->context,
+ (WIN_W - img->w)/2, (WIN_H - img->h)/2);
+ GP_BackendFlip(b);
+
+ for (;;) {
+ GP_Event ev;
+
+ GP_BackendWaitEvent(b, &ev);
+
+ switch (ev.type) {
+ case GP_EV_KEY:
+ switch (ev.val.val) {
+ case GP_KEY_ESC:
+ case GP_KEY_Q:
+ GP_BackendExit(b);
+ return 0;
+ break;
+ }
+ break;
+ case GP_EV_SYS:
+ switch (ev.code) {
+ case GP_EV_SYS_RESIZE:
+ case GP_EV_SYS_QUIT:
+ GP_BackendExit(b);
+ return 0;
+ break;
+ }
+ break;
+ }
+ }
+
+ GP_BackendExit(b);
+ return 0;
+}
diff --git a/doc/Makefile b/doc/Makefile
index 05ae191..ac8868c 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -5,7 +5,7 @@ SOURCES=index.html about.txt context.txt loaders.txt filters.txt get_put_pixel.txt blits.txt progress_callback.txt text.txt event_queue.txt compilation.txt filters_resize.txt filters_dithering.txt filters_python.txt spiv.txt core_common.txt - convert.txt news_1_0_0-rc1.txt
+ convert.txt news_1_0_0-rc1.txt loaders_io.txt
SOURCES+=core_python.txt gfx_python.txt loaders_python.txt backends_python.txt
diff --git a/doc/example_memory_io.txt b/doc/example_memory_io.txt
new file mode 100644
index 0000000..1488bba
--- /dev/null
+++ b/doc/example_memory_io.txt
@@ -0,0 +1,9 @@
+Memory IO with Loaders
+----------------------
+
+This example shows how to read an image from a memory buffer.
+
+[source,c]
+------------------------------------------------------------------
+include::../demos/c_simple/memory_io.c[]
+------------------------------------------------------------------
diff --git a/doc/loaders.txt b/doc/loaders.txt
index b42c47e..5ac5743 100644
--- a/doc/loaders.txt
+++ b/doc/loaders.txt
@@ -3,22 +3,25 @@ Context loaders
This part of GFXprim library aims to create API to load and save images
from/to common image file formats.
-Currently we support JPEG, PNG, BMP, TIFF and PNM images for loading and
-saving and GIF, JPEG2000 and PSP for loading.
+Currently we support 'JPEG', 'PNG', 'BMP', 'TIFF' and 'PNM' images for loading
+and saving and 'GIF', 'JPEG2000' and 'PSP' for loading.
Have a look at the link:about.html#Loaders[supported formats].
Image Loaders and Savers
~~~~~~~~~~~~~~~~~~~~~~~~
-All loading functions returns a pointer to allocated and loaded image or upon
-a failure 'NULL'.
+All loading functions exists in at least two flavors. One that works with a
+path to a file and one that reads from an link:loaders_io.html[IO stream].
+
+All loading functions returns a pointer to newly allocated and loaded image
+or upon a failure 'NULL' and 'errno' is set.
All saving functions returns zero on success and non-zero on failure. If
image saving is aborted by a callback, the opened file is closed and removed
-from a filesystem before the call returns.
+from a file-system before the call returns.
-The signature matching functions takes a 32 bytes long buffer and looks for a
+The signature matching functions takes a 32 bytes long buffer and looks for a
valid image signature. If signature is found non-zero is returned.
In case of a failure 'errno' is set, possible 'errno' values are:
@@ -36,7 +39,6 @@ In case of a failure 'errno' is set, possible 'errno' values are:
You can get more information about the error condition by turning on GFXprim
link:environment_variables.html#GP_DEBUG[debug messages].
-
[[Load_Image]]
[source,c]
-------------------------------------------------------------------------------
@@ -50,7 +52,7 @@ GP_Context *GP_LoadImage(const char *src_path, GP_ProgressCallback *callback);
Loads an image from a file.
The image format is first guessed by the file extension. If loader for the
-file extension is found it's called and if it succedes the image data is
+file extension is found it's called and if it succeeds the image data is
returned.
If file extension based guess fails either because the extension wasn't
@@ -105,7 +107,7 @@ typedef struct GP_Loader {
/*
* Save an image.
*
- * Returns zero on succes, non-zero on failure and errno must be set.
+ * Returns zero on success, non-zero on failure and errno must be set.
*/
int (*Save)(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
@@ -192,9 +194,9 @@ const GP_Loader *GP_MatchExtension(const char *path)
Matches loader by the file extension. This function does not check that the
file exists or that it could be opened it only looks at the extension (i.e.
-string after the dot) and matches it agains known extensions.
+string after the dot) and matches it against known extensions.
-WARNING: If you attempt to modify the content of the strucutre the behavior is
+WARNING: If you attempt to modify the content of the structure the behavior is
undefined. Most likely the program will crash.
PNG Loader
@@ -207,28 +209,14 @@ The 'PNG' image support is implemented by the libpng library.
/* or */
#include <GP.h>
-int GP_OpenPNG(const char *src_path, FILE **f);
+GP_Context *GP_ReadPNG(GP_IO *io, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Opens file and checks for 'PNG' signature. Returns zero on success (file
-could be opened, signature matches), the opened file is returned and the file
-position points right after the end of the 'PNG' signature.
+Reads a 'PNG' image from readable 'GP_IO'. The link:loaders_io.html[IO stream]
+is expected to start exactly at the 'PNG' file signature.
-This function is semi-internal, you should rather use functions listed below.
-
-[source,c]
--------------------------------------------------------------------------------
-#include <loaders/GP_PNG.h>
-/* or */
-#include <GP.h>
-
-GP_Context *GP_ReadPNG(FILE *f, GP_ProgressCallback *callback);
--------------------------------------------------------------------------------
-
-Loads 'PNG' file into context the file pointer must point to the start of the
-'PNG' data stream (i.e. should point right after the signature). The context,
-to store the image to, is allocated. The loading process could by aborted by a
-callback, in such case all memory is freed.
+Returns newly allocated context (containing decompressed image) or in case of
+failure 'NULL' and 'errno' is set.
[source,c]
-------------------------------------------------------------------------------
@@ -239,8 +227,10 @@ callback, in such case all memory is freed.
GP_Context *GP_LoadPNG(const char *src_path, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Same as above but takes path to the file as a parameter and check for the
-signature. Basically this combines both of the calls above.
+Loads a 'PNG' image from a file.
+
+Returns a pointer to newly allocated loaded image, or in case of failure
+'NULL' and 'errno' is set.
[source,c]
-------------------------------------------------------------------------------
@@ -252,9 +242,11 @@ int GP_SavePNG(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Currently only 'RGB888' format is supported, you should convert the
-'GP_Context' to 'RGB888' before calling this function otherwise non-zero is
-returned and 'errno' is set to 'ENOSYS'.
+Saves a 'Context' into a 'PNG' image, in case particular pixel type is not
+supported non-zero is returned and 'errno' is set to 'ENOSYS'.
+
+Supports 'G1', 'G2', 'G4', 'G8', 'G16', and 8-bit 'RGB' and 'RGBA' pixel
+types.
[source,c]
-------------------------------------------------------------------------------
@@ -265,7 +257,7 @@ returned and 'errno' is set to 'ENOSYS'.
int GP_MatchPNG(const void *buf);
-------------------------------------------------------------------------------
-Matches a PNG signature.
+Matches a 'PNG' file signature. Returns non-zero if found.
JPEG Loader
~~~~~~~~~~~
@@ -277,32 +269,14 @@ The 'JPEG' image support is implemented by the jpeg library.
/* or */
#include <GP.h>
-int GP_OpenJPG(const char *src_path, FILE **f);
+GP_Context *GP_ReadJPG(GP_IO *io, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Opens file and checks for 'JPG' signature upon successful return (file could
-be opened, signature matches), the opened file is returned and the file
-position points right after the end of the 'JPG' signature.
+Reads a 'JPEG' image from readable 'GP_IO'. The link:loaders_io.html[IO
+stream] is expected to start exactly at the 'JPEG' file signature.
-This function is semi-internal, you should rather use functions listed below.
-
-'TODO:' This is not finished yet, currently this just opens and returns the
-file and the 'GP_ReadJPG()' reads the signature instead.
-
-[source,c]
--------------------------------------------------------------------------------
-#include <loaders/GP_JPG.h>
-/* or */
-#include <GP.h>
-
-GP_Context *GP_ReadJPG(FILE *f, GP_ProgressCallback *callback);
--------------------------------------------------------------------------------
-
-Loads 'JPG' file into context the file pointer must point to the start of the
-'JPG' data stream (i.e. should point right after the signature). The context,
-to store the image to, is allocated. The loading process could by aborted by a
-callback, in such case all memory is freed and the call returns 'NULL' and
-'errno' is set to 'ECANCELED'.
+Returns newly allocated context (containing decompressed image) or in case of
+failure 'NULL' and 'errno' is set.
[source,c]
-------------------------------------------------------------------------------
@@ -313,8 +287,10 @@ callback, in such case all memory is freed and the call returns 'NULL' and
GP_Context *GP_LoadJPG(const char *src_path, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Same as above but takes path to the file as a parameter and check for the
-signature. Basically this combines both of the calls above.
+Loads an 'JPEG' image from a file.
+
+Returns a pointer to newly allocated loaded image, or in case of failure
+'NULL' and 'errno' is set.
[source,c]
-------------------------------------------------------------------------------
@@ -326,12 +302,11 @@ int GP_SaveJPG(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Writes a Context into a 'JPG' image. If aborted by a callback, the opened file
-is closed and removed before the call returns non-zero and 'errno' is set to
-'ECANCELED'.
+Writes a 'Context' into a 'JPEG' image. If aborted by a callback, the opened
+file is closed and removed before the call returns non-zero and 'errno' is set
+to 'ECANCELED'.
-The 'JPG' format could store either 'G8' or 'RGB888' pixeltypes and you must
-convert the context into one of them before this functions is called.
+The 'JPEG' format could store either 'G8' or 8-bit 'RGB' pixel-types.
[source,c]
-------------------------------------------------------------------------------
@@ -342,7 +317,7 @@ convert the context into one of them before this functions is called.
int GP_MatchJPG(const void *buf);
-------------------------------------------------------------------------------
-Matches a JPG signature.
+Matches a 'JPEG' file signature. Returns non-zero if found.
JPEG 2000 Loader
~~~~~~~~~~~~~~~~
@@ -354,32 +329,45 @@ The 'JPEG 2000' image support is implemented using the openjpeg library.
/* or */
#include <GP.h>
-GP_Context *GP_LoadJP2(const char *src_path, GP_ProgressCallback *callback);
+GP_Context *GP_ReadJP2(GP_IO *io, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Loads 'JPEG 2000' image.
+Reads a 'JPEG2000' image from readable 'GP_IO'. The link:loaders_io.html[IO
+stream] is expected to start exactly at the 'JPEG2000' file signature.
-Due to limitations of the openjpeg library progress callback does not work.
+Returns newly allocated context (containing decompressed image) or in case of
+failure 'NULL' and 'errno' is set.
-GIF Loader
-~~~~~~~~~~
+NOTE: Due to limitations of the openjpeg library progress callback does not work.
-The 'GIF' image support is implemented by the giflib library.
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_JP2.h>
+/* or */
+#include <GP.h>
+
+GP_Context *GP_LoadJP2(const char *src_path, GP_ProgressCallback *callback);
+-------------------------------------------------------------------------------
+
+Loads 'JPEG2000' image from a file.
+
+NOTE: Due to limitations of the openjpeg library progress callback does not work.
[source,c]
-------------------------------------------------------------------------------
-#include <loaders/GP_GIF.h>
+#include <loaders/GP_JP2.h>
/* or */
#include <GP.h>
-int GP_OpenGIF(const char *src_path, void **f);
+int GP_MatchJP2(const void *buf);
-------------------------------------------------------------------------------
-Opens file and checks for 'GIF' signature upon successful return (file could
-be opened, signature matches) zero is returned and gif handle f is set
-otherwise non-zero is returned and 'errno' is set.
+Matches a 'JPEG2000' file signature. Returns non-zero if found.
+
+GIF Loader
+~~~~~~~~~~
-This function is semi-internal, you should rather use functions listed below.
+The 'GIF' image support is implemented by the giflib library.
[source,c]
-------------------------------------------------------------------------------
@@ -387,16 +375,16 @@ This function is semi-internal, you should rather use functions listed below.
/* or */
#include <GP.h>
-GP_Context *GP_ReadGIF(void *f, GP_ProgressCallback *callback);
+GP_Context *GP_ReadGIF(GP_IO *io, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Loads 'GIF' file into context. The pointer must point to the 'GIF' handle as
-returned by 'GP_OpenGIF()' function. The context, to store the image to, is
-allocated. The loading process could by aborted by a callback, in such case
-all memory is freed and the call returns 'NULL' and 'errno' is set to
-'ECANCELED'.
+Reads a 'GIF' image from readable 'GP_IO'. The link:loaders_io.html[IO stream]
+is expected to start exactly at the 'GIF' file signature.
+
+Returns newly allocated context (containing decompressed image) or in case of
+failure 'NULL' and 'errno' is set.
-Currently this function loads only first image from the gif container.
+NOTE: Currently this function loads only first image from the 'GIF' container.
[source,c]
-------------------------------------------------------------------------------
@@ -407,8 +395,7 @@ Currently this function loads only first image from the gif container.
GP_Context *GP_LoadGIF(const char *src_path, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Same as above but takes path to the file as a parameter and check for the
-signature. Basically this combines both of the calls above.
+Loads 'GIF' image from a file.
[source,c]
-------------------------------------------------------------------------------
@@ -419,7 +406,7 @@ signature. Basically this combines both of the calls above.
int GP_MatchGIF(const void *buf);
-------------------------------------------------------------------------------
-Matches a GIF signature.
+Matches a 'GIF' file signature. Returns non-zero if found.
BMP Loader
~~~~~~~~~~
@@ -433,30 +420,14 @@ be exotic RGB compressions (RGB101010 for example) and RLE4 support.
/* or */
#include <GP.h>
-int GP_OpenBMP(const char *src_path, FILE **f,
- GP_Size *w, GP_Size *h, GP_PixelType *pixel_type);
--------------------------------------------------------------------------------
-
-Opens file and checks for 'BMP' signature upon successful return (file could
-be opened, signature matches) zero is returned and the parameters, if
-non-'NULL', are initialized. Upon failure non-zero is returned and 'errno' is
-set.
-
-This function is semi-internal, you should rather use functions listed below.
-
-[source,c]
+GP_Context *GP_ReadBMP(GP_IO *io, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-#include <loaders/GP_BMP.h>
-/* or */
-#include <GP.h>
-GP_Context *GP_ReadBMP(FILE *f, GP_ProgressCallback *callback);
--------------------------------------------------------------------------------
+Reads a 'BMP' image from readable 'GP_IO'. The link:loaders_io.html[IO stream]
+is expected to start exactly at the 'BMP' file signature.
-Loads 'BMP' file into context. The 'FILE' pointer must point to opened 'BMP'
-file. The context, to store the image to, is allocated. The loading process
-could by aborted by a callback, in such case all memory is freed and the call
-returns 'NULL' and 'errno' is set to 'ECANCELED'.
+Returns newly allocated context (containing decompressed image) or in case of
+failure 'NULL' and 'errno' is set.
[source,c]
-------------------------------------------------------------------------------
@@ -467,8 +438,7 @@ returns 'NULL' and 'errno' is set to 'ECANCELED'.
GP_Context *GP_LoadBMP(const char *src_path, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Same as above but takes path to the file as a parameter and check for the
-signature. Basically this combines both of the calls above.
+Loads 'BMP' image from a file.
[source,c]
-------------------------------------------------------------------------------
@@ -480,7 +450,9 @@ int GP_SaveBMP(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Saves 'RGB888' (24 bit RGB) image into BMP bitmap.
+Writes a 'Context' into a 'BMP' file.
+
+Currently only 8-bit 'RGB' formats are supported.
[source,c]
-------------------------------------------------------------------------------
@@ -491,7 +463,7 @@ Saves 'RGB888' (24 bit RGB) image into BMP bitmap.
int GP_MatchBMP(const void *buf);
-------------------------------------------------------------------------------
-Matches a BMP signature.
+Matches a 'BMP' file signature. Returns non-zero if found.
PSP Loader
~~~~~~~~~~
@@ -504,23 +476,14 @@ The 'PSP' loader can load a composite image from a Paint Shop Pro Image Files.
/* or */
#include <GP.h>
-int GP_OpenPSP(const char *src_path, FILE **f);
--------------------------------------------------------------------------------
-
-Opens file and checks for 'PSP' signature. Upon successful return (file could
-be opened, signature matches) zero is returned. Upon failure non-zero is
-returned and 'errno' is set.
-
-[source,c]
+GP_Context *GP_ReadPSP(GP_IO *io, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-#include <loaders/GP_PSP.h>
-/* or */
-#include <GP.h>
-GP_Context *GP_ReadPSP(FILE *f, GP_ProgressCallback *callback);
--------------------------------------------------------------------------------
+Reads a 'PSP' image from readable 'GP_IO'. The link:loaders_io.html[IO stream]
+is expected to start exactly at the 'PSP' file signature.
-Reads 'PSP' image into a context.
+Returns newly allocated context (containing decompressed image) or in case of
+failure 'NULL' and 'errno' is set.
[source,c]
-------------------------------------------------------------------------------
@@ -531,8 +494,7 @@ Reads 'PSP' image into a context.
GP_Context *GP_LoadPSP(const char *src_path, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Same as above but takes path to the file as a parameter and checks for the
-signature. Basically this combines both of the calls above.
+Loads a composite image from a 'PSP' file.
[source,c]
-------------------------------------------------------------------------------
@@ -543,10 +505,10 @@ signature. Basically this combines both of the calls above.
int GP_MatchPSP(const void *buf);
-------------------------------------------------------------------------------
-Matches a PSP signature.
+Matches a 'PSP' file signature. Returns non-zero if found.
-PNM
-~~~
+PNM Loaders
+~~~~~~~~~~~
[source,c]
-------------------------------------------------------------------------------
@@ -563,10 +525,9 @@ GP_Context *GP_LoadPPM(const char *src_path, GP_ProgressCallback *callback);
GP_Context *GP_LoadPNM(const char *src_path, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Loads either ASCII or Rawbits (binary) PBM, PGM and PPM.
-
-The PNM can load all of them i.e. PBM, PGM and PPM.
+Loads either ASCII or Rawbits (binary) 'PBM', 'PGM' and 'PPM'.
+The 'PNM' can load all of them i.e. 'PBM', 'PGM' and 'PPM'.
[source,c]
-------------------------------------------------------------------------------
@@ -578,7 +539,7 @@ GP_Context *GP_SavePBM(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Saves 'G1' (1 bit grayscale) image into ASCII PBM.
+Saves 'G1' (1 bit grayscale) image into ASCII 'PBM'.
[source,c]
-------------------------------------------------------------------------------
@@ -591,7 +552,7 @@ GP_Context *GP_SavePGM(const GP_Context *src, const char *dst_path,
-------------------------------------------------------------------------------
Saves 'G1', 'G2', 'G4' and 'G8' (1, 2, 4 and 8 bit grayscale) image into ASCII
-PGM.
+'PGM'.
[source,c]
-------------------------------------------------------------------------------
@@ -603,7 +564,7 @@ GP_Context *GP_SavePPM(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Saves 'RGB888' (24 bit RGB) image into ASCII PPM.
+Saves 'RGB888' (24 bit RGB) image into ASCII 'PPM'.
[source,c]
-------------------------------------------------------------------------------
@@ -616,7 +577,7 @@ GP_Context *GP_SavePNM(const GP_Context *src, const char *dst_path,
-------------------------------------------------------------------------------
Saves 'G1', 'G2', 'G4' and 'G8' (1, 2, 4, 8 bit grayscale) or 'RGB888' (24 bit
-RGB) image into ASCII PNM.
+RGB) image into ASCII 'PNM'.
[source,c]
-------------------------------------------------------------------------------
@@ -633,7 +594,9 @@ int GP_MatchPPM(const void *buf);
int GP_MatchPNM(const void *buf);
-------------------------------------------------------------------------------
-Matches either ASCII or Rawbits (binary) PBM, PGM and PPM.
+Matches either ASCII or Rawbits (binary) 'PBM', 'PGM' and 'PPM' file
+signatures.
-The PNM matches all of them i.e. PBM, PGM and PPM.
+The 'PNM' matches all of the formats. i.e. 'PBM', 'PGM' and 'PPM'.
+All functions return non-zero if found.
diff --git a/doc/loaders_io.txt b/doc/loaders_io.txt
new file mode 100644
index 0000000..e12e746
--- /dev/null
+++ b/doc/loaders_io.txt
@@ -0,0 +1,190 @@
+IO Interface
+------------
+
+GFXprim implements an I/O interface which is used by all image loaders.
+
+The purpose of the interface is:
+
+* Make it easy to load and save images from/into memory buffers
+* Fast and clean containers (ZIP for example) implementation
+ (zlib deflate could feed data directly into a memory based IO stream)
+
+The I/O interface is defined by a structure with callbacks.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_IO.h>
+/* or */
+#include <GP.h>
+
+/*
+ * Values are 1:1 with constants passed to lseek()
+ */
+enum GP_IOWhence {
+ GP_IO_SEEK_SET = 0,
+ GP_IO_SEEK_CUR = 1,
+ GP_IO_SEEK_END = 2,
+};
+
+
+typedef struct GP_IO {
+ ssize_t (*Read)(struct GP_IO *self, void *buf, size_t size);
+ ssize_t (*Write)(struct GP_IO *self, void *buf, size_t size);
+ off_t (*Seek)(struct GP_IO *self, off_t off, enum GP_IOWhence whence);
+ int (*Close)(struct GP_IO *self);
+
+ off_t mark;
+ char priv[];
+} GP_IO;
+-------------------------------------------------------------------------------
+
+The fields of the I/O stream structure are mostly self describing. The 'Seek'
+behaves exactly as 'lseek(2)', the 'Read' as 'read(2)' and the 'Write' as
+'write(2)'.
+
+The 'mark' and 'priv' are private fields that shall not be touched by user.
+
+An IO reader must implement at least 'Read', 'Seek' (at least able to seek
+forward to skip some data) and 'Close'.
+
+An IO writer must implement at least 'Write' and 'Close'.
+
+Return value from the 'Seek' is a value of current offset in the stream (after
+the seek has been done) or in case of failure '(off_t)-1'.
+
+Return value from 'Read' or 'Write' is a number of bytes read/written or in
+case of failure a negative number (-1).
+
+Return value from 'Close' is zero on success and non-zero on IO failure.
+
+NOTE: Make sure 'errno' is set if any of the operations has failed.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_IO.h>
+/* or */
+#include <GP.h>
+
+ssize_t GP_IORead(GP_IO *io, void *buf, size_t size);
+-------------------------------------------------------------------------------
+
+This is a wrapper to 'io->Read()'.
+
+Reads at most 'size' bytes from an 'IO' stream and stores them into the
+buffer. Returns number of bytes read.
+
+On failure the return value is negative and 'errno' is set.
+
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_IO.h>
+/* or */
+#include <GP.h>
+
+ssize_t GP_IOWrite(GP_IO *io, void *buf, size_t size);
+-------------------------------------------------------------------------------
+
+This is a wrapper to 'io->Write()'.
+
+Writes at most 'size' bytes from an 'IO' stream and stores them into the
+buffer. Returns number of bytes read.
+
+On failure the return value is negative and 'errno' is set.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_IO.h>
+/* or */
+#include <GP.h>
+
+int GP_IOClose(GP_IO *io);
+-------------------------------------------------------------------------------
+
+This is a wrapper to 'io->Close()'.
+
+Finalizes reading/writing, closes file descriptors (in case of file IO), frees
+memory buffers.
+
+Returns zero on success, non-zero on IO failure and 'errno' is set.
+
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_IO.h>
+/* or */
+#include <GP.h>
+
+off_t GP_IOSeek(GP_IO *io, off_t off, enum GP_IOWhence whence);
+-------------------------------------------------------------------------------
+
+This is a wrapper to 'io->Seek()'.
+
+//TODO
+
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_IO.h>
+/* or */
+#include <GP.h>
+
+off_t GP_IOTell(GP_IO *io);
+-------------------------------------------------------------------------------
+
+Wrapper to 'GP_IOSeek()', returns current position in IO stream.
+
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_IO.h>
+/* or */
+#include <GP.h>
+
+off_t GP_IORewind(GP_IO *io)
+-------------------------------------------------------------------------------
+
+Wrapper to 'GP_IOSeek()', rewinds to the start of the IO stream.
+
+Returns zero on success, non-zero on failure and 'errno' is set.
+
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_IO.h>
+/* or */
+#include <GP.h>
+
+GP_IO *GP_IOMem(void *buf, size_t size, void (*free)(void *));
+-------------------------------------------------------------------------------
+
+Creates an read-only IO from a memory buffer.
+
+Returns initialized IO or in case of failure 'NULL' and 'errno' is set.
+
+The 'buf' is pointer to the start of the buffer, the 'size' is size in bytes.
+
+The 'free()' callback if not 'NULL' is called with the start of the buffer as
+an argument on 'IOClose()'.
+
+TIP: See link:example_memory_io.html[memory IO example].
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_IO.h>
+/* or */
+#include <GP.h>
+
+enum GP_IOFileMode {
+ GP_IO_RDONLY = 0x00,
+ GP_IO_WRONLY = 0x01,
+ GP_IO_RDWR = 0x02,
+};
+
+GP_IO *GP_IOFile(const char *path, enum GP_IOFileMode mode);
+-------------------------------------------------------------------------------
+
+Creates an IO stream from a file.
+
+Returns a pointer to initialized IO stream, or in case of failure 'NULL' and
+'errno' is set.
diff --git a/include/loaders/GP_BMP.h b/include/loaders/GP_BMP.h
index 4c5ca26..48eff73 100644
--- a/include/loaders/GP_BMP.h
+++ b/include/loaders/GP_BMP.h
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -25,40 +25,18 @@
#include "core/GP_Context.h"
#include "core/GP_ProgressCallback.h"
+#include "loaders/GP_IO.h"
/*
- * The possible errno values:
+ * Reads a BMP from an IO stream.
*
- * - Anything FILE operation may return (fopen(), fclose(), fseek(), ...).
- * - EIO for fread()/fwrite() failure
- * - ENOSYS for not implemented bitmap format
- * - ENOMEM from malloc()
- * - EILSEQ for wrong image signature/data
- * - ECANCELED when call was aborted from callback
+ * Returns newly allocated context cotaining the loaded image or in case of
+ * failure NULL and errno is set.
*/
+GP_Context *GP_ReadBMP(GP_IO *io, GP_ProgressCallback *callback);
/*
- * Opens up a bmp file, checks signature, parses metadata.
- *
- * The file, width, height and pixel type are filled upon succcessful return.
- *
- * Upon failure, non zero return value is returned and errno is filled.
- */
-int GP_OpenBMP(const char *src_path, FILE **f,
- GP_Size *w, GP_Size *h, GP_PixelType *pixel_type);
-
-/*
- * Reads a BMP from a opened file.
- *
- * Upon successful return, context to store bitmap is allocated and image is
- * loaded.
- *
- * Upon failure NULL is returned and errno is filled.
- */
-GP_Context *GP_ReadBMP(FILE *f, GP_ProgressCallback *callback);
-
-/*
- * Does both GP_OpenBMP and GP_ReadBMP.
+ * Loads a BMP image from a file.
*/
GP_Context *GP_LoadBMP(const char *src_path, GP_ProgressCallback *callback);
@@ -70,7 +48,7 @@ int GP_SaveBMP(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
/*
- * Match BMP signature.
+ * Looks for BMP file signature. Returns non-zero if found.
*/
int GP_MatchBMP(const void *buf);
diff --git a/include/loaders/GP_GIF.h b/include/loaders/GP_GIF.h
index b2ee363..23405e2 100644
--- a/include/loaders/GP_GIF.h
+++ b/include/loaders/GP_GIF.h
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -29,37 +29,25 @@
#ifndef LOADERS_GP_GIF_H
#define LOADERS_GP_GIF_H
-#include "core/GP_ProgressCallback.h"
#include "core/GP_Context.h"
+#include "core/GP_ProgressCallback.h"
+#include "loaders/GP_IO.h"
/*
- * The possible errno values:
+ * Reads first image found in GIF container from an IO stream.
*
- * - EIO for read/write failure
- * - ENOSYS for not implemented bitmap format
- * - ENOMEM from malloc()
- * - EILSEQ for wrong image signature/data
- * - ECANCELED when call was aborted from callback
- */
-
-/*
- * Opens up the Gif image and checks signature.
- * Returns zero on success.
- */
-int GP_OpenGIF(const char *src_path, void **f);
-
-/*
- * Reads first image found in GIF container.
+ * Returns newly allocated context cotaining the loaded image or in case of
+ * failure NULL and errno is set.
*/
-GP_Context *GP_ReadGIF(void *f, GP_ProgressCallback *callback);
+GP_Context *GP_ReadGIF(GP_IO *io, GP_ProgressCallback *callback);
/*
- * Does both GP_OpenGIF and GP_ReadGIF at once.
+ * Loads first image found in GIF container from a file.
*/
GP_Context *GP_LoadGIF(const char *src_path, GP_ProgressCallback *callback);
/*
- * Match GIF signature.
+ * Looks for GIF file signature. Returns non-zero if found.
*/
int GP_MatchGIF(const void *buf);
diff --git a/include/loaders/GP_IO.h b/include/loaders/GP_IO.h
new file mode 100644
index 0000000..fa1046f
--- /dev/null
+++ b/include/loaders/GP_IO.h
@@ -0,0 +1,184 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+ /*
+
+ I/O abstraction for GFXprim loaders.
+
+ */
+
+#ifndef LOADERS_GP_IO_H
+#define LOADERS_GP_IO_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+/*
+ * Values are 1:1 with constants passed to lseek()
+ */
+enum GP_IOWhence {
+ GP_IO_SEEK_SET = 0,
+ GP_IO_SEEK_CUR = 1,
+ GP_IO_SEEK_END = 2,
+};
+
+typedef struct GP_IO {
+ ssize_t (*Read)(struct GP_IO *self, void *buf, size_t size);
+ ssize_t (*Write)(struct GP_IO *self, void *buf, size_t size);
+ off_t (*Seek)(struct GP_IO *self, off_t off, enum GP_IOWhence whence);
+ int (*Close)(struct GP_IO *self);
+
+// void *(*Map)(struct GP_IO *self, size_t len, off_t off);
+// void (*UnMap)(struct GP_IO *self, void *addr, size_t len);
+
+ off_t mark;
+ char priv[];
+} GP_IO;
+
+#define GP_IO_PRIV(io) ((void *)(io)->priv)
+
+/*
+ * Just inline wrappers.
+ */
+static inline ssize_t GP_IORead(GP_IO *io, void *buf, size_t size)
+{
+ return io->Read(io, buf, size);
+}
+
+static inline ssize_t GP_IOWrite(GP_IO *io, void *buf, size_t size)
+{
+ return io->Write(io, buf, size);
+}
+
+static inline int GP_IOClose(GP_IO *io)
+{
+ return io->Close(io);
+}
+
+static inline off_t GP_IOSeek(GP_IO *io, off_t off, enum GP_IOWhence whence)
+{
+ return io->Seek(io, off, whence);
+}
+
+//static inline void *GP_IOMap(GP_IO *io, size_t len, off_t off)
+//{
+// return io->Map(io, len, off);
+//}
+
+//static inline void *GP_IOUnMap(GP_IO *io, size_t len, off_t off)
+//{
+// return io->UnMap(io, len, off);
+//}
+
+/*
+ * Returns current offset
+ */
+static inline off_t GP_IOTell(GP_IO *io)
+{
+ return io->Seek(io, 0, GP_IO_SEEK_CUR);
+}
+
+/*
+ * Rewinds to start of the I/O stream.
+ */
+static inline off_t GP_IORewind(GP_IO *io)
+{
+ return io->Seek(io, 0, GP_IO_SEEK_SET);
+}
+
+/*
+ * Returns I/O stream size.
+ *
+ * May return (off_t)-1 in case that GP_IO_SEEK_END is not possible.
+ */
+off_t GP_IOSize(GP_IO *io);
+
+/*
+ * Like a Read but either fills whole buffer or returns error.
+ *
+ * Returns zero on success non-zero on failure.
+ */
+int GP_IOFill(GP_IO *io, void *buf, size_t size);
+
+/*
+ * Marks a current position, returns to mark in I/O stream.
+ */
+enum GP_IOMarkTypes {
+ GP_IO_MARK,
+ GP_IO_REWIND,
+};
+
+int GP_IOMark(GP_IO *self, enum GP_IOMarkTypes type);
+
+/*
+ * Formatted read.
+ *
+ *
+ */
+enum GP_IOReadFTypes {
+ /* Constant byte in lower half */
+ GP_IO_CONST = 0x0000,
+ /* Pointer to one byte */
+ GP_IO_BYTE = 0x0100,
+ /* Pointer to byte integer in litte endian */
+ GP_IO_L2 = 0x0200,
+ /* Poiter to four byte integer in litte endian */
+ GP_IO_L4 = 0x0300,
+ /* Pointer to two byte integer in big endian */
+ GP_IO_B2 = 0x0400,
+ /* Pointer to four byte integer in big endian */
+ GP_IO_B4 = 0x0500,
+ /* Pointer to byte array, size in lower half */
+ GP_IO_ARRAY = 0x0600,
+ /* Ignore bytes on read, size in lower half */
+ GP_IO_IGN = 0x0700,
+ GP_IO_I1 = GP_IO_IGN | 1,
+ GP_IO_I2 = GP_IO_IGN | 2,
+ GP_IO_I3 = GP_IO_IGN | 3,
+ GP_IO_I4 = GP_IO_IGN | 4,
+ /* End of the types array */
+ GP_IO_END = 0xff00,
+};
+
+#define GP_IO_TYPE_MASK 0xff00
+
+int GP_IOReadF(GP_IO *self, uint16_t *types, ...);
+
+enum GP_IOFileMode {
+ GP_IO_RDONLY = 0x00,
+ GP_IO_WRONLY = 0x01,
+ GP_IO_RDWR = 0x02,
+};
+
+/*
+ * Creates I/O from a file. On error NULL is returned and errno is set.
+ */
+GP_IO *GP_IOFile(const char *path, enum GP_IOFileMode mode);
+
+/*
+ * Creates I/O from a memory buffer.
+ *
+ * If free is not NULL, it's called on buf pointer on GP_IOClose().
+ */
+GP_IO *GP_IOMem(void *buf, size_t size, void (*free)(void *));
+
+#endif /* LOADERS_GP_IO_H */
diff --git a/include/loaders/GP_JP2.h b/include/loaders/GP_JP2.h
index 7068a46..574cfbc 100644
--- a/include/loaders/GP_JP2.h
+++ b/include/loaders/GP_JP2.h
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -31,24 +31,23 @@
#include "core/GP_Context.h"
#include "core/GP_ProgressCallback.h"
+#include "loaders/GP_IO.h"
/*
- * Opens up file and checks signature.
+ * Reads a JPEG2000 from an IO stream.
+ *
+ * Returns newly allocated context cotaining the loaded image or in case of
+ * failure NULL and errno is set.
*/
-int GP_OpenJP2(const char *src_path, FILE **f);
+GP_Context *GP_ReadJP2(GP_IO *io, GP_ProgressCallback *callback);
/*
- * Reads JP2 from an open FILE.
- */
-GP_Context *GP_ReadJP2(FILE *f, GP_ProgressCallback *callback);
-
-/*
- * Loads a JP2 file into GP_Context. The Context is newly allocated.
+ * Loads a JPEG2000 image from a file.
*/
GP_Context *GP_LoadJP2(const char *src_path, GP_ProgressCallback *callback);
/*
- * Match JP2 signature.
+ * Looks for JPEG2000 file signature. Returns non-zero if found.
*/
int GP_MatchJP2(const void *buf);
diff --git a/include/loaders/GP_JPG.h b/include/loaders/GP_JPG.h
index 8f6a920..95123ec 100644
--- a/include/loaders/GP_JPG.h
+++ b/include/loaders/GP_JPG.h
@@ -16,13 +16,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
/*
- JPG support using jpeg library.
+ JPEG support using jpeg library.
*/
@@ -31,22 +31,19 @@
#include "core/GP_Context.h"
#include "core/GP_ProgressCallback.h"
-
-#include "GP_MetaData.h"
-
-/*
- * Opens up file and checks signature.
- */
-int GP_OpenJPG(const char *src_path, FILE **f);
+#include "loaders/GP_IO.h"
+#include "loaders/GP_MetaData.h"
/*
- * Reads JPG from an open FILE. Expects the file position set after the eight
- * bytes JPG signature.
+ * Reads a JPEG from an IO stream.
+ *
+ * Returns newly allocated context cotaining the loaded image or in case of
+ * failure NULL and errno is set.
*/
-GP_Context *GP_ReadJPG(FILE *f, GP_ProgressCallback *callback);
+GP_Context *GP_ReadJPG(GP_IO *io, GP_ProgressCallback *callback);
/*
- * Loads a JPG file into GP_Context. The Context is newly allocated.
+ * Loads a JPEG image from a file.
*/
GP_Context *GP_LoadJPG(const char *src_path, GP_ProgressCallback *callback);
@@ -57,13 +54,13 @@ int GP_ReadJPGMetaData(FILE *f, GP_MetaData *data);
int GP_LoadJPGMetaData(const char *src_path, GP_MetaData *data);
/*
- * Saves JPG to a file.
+ * Saves JPEG to a file.
*/
int GP_SaveJPG(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
/*
- * Match JPG signature.
+ * Looks for JPEG file signature. Returns non-zero if found.
*/
int GP_MatchJPG(const void *buf);
diff --git a/include/loaders/GP_Loader.h b/include/loaders/GP_Loader.h
index 6522c0a..925f358 100644
--- a/include/loaders/GP_Loader.h
+++ b/include/loaders/GP_Loader.h
@@ -49,7 +49,7 @@ int GP_LoadMetaData(const char *src_path, GP_MetaData *data);
/*
* Simple saving function, the image format is matched by file extension.
*
- * Retruns zero on succes.
+ * Retruns zero on success.
*
* On failure non-zero is returned.
*
diff --git a/include/loaders/GP_PNG.h b/include/loaders/GP_PNG.h
index e9b72ce..0b440d0 100644
--- a/include/loaders/GP_PNG.h
+++ b/include/loaders/GP_PNG.h
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -31,38 +31,19 @@
#include "core/GP_ProgressCallback.h"
#include "core/GP_Context.h"
-
-#include "GP_MetaData.h"
-
-/*
- * The possible errno values:
- *
- * - Anything FILE operation may return (fopen(), fclose(), fseek(), ...).
- * - EIO for png_read()/png_write() failure
- * - ENOSYS for not implemented bitmap format
- * - ENOMEM from malloc()
- * - EILSEQ for wrong image signature/data
- * - ECANCELED when call was aborted from callback
- */
-
-/*
- * Opens up file and checks signature. Upon successful return (zero is
- * returned) the file position would be set to eight bytes (exactly after the
- * PNG signature).
- */
-int GP_OpenPNG(const char *src_path, FILE **f);
+#include "loaders/GP_IO.h"
+#include "loaders/GP_MetaData.h"
/*
- * Reads PNG from an open FILE. Expects the file position set after the eight
- * bytes PNG signature.
+ * Reads a PNG from an IO stream.
*
- * Upon succesfull return pointer to newly allocated context is returned.
- * Otherwise NULL is returned and errno is filled.
+ * Returns newly allocated context cotaining the loaded image or in case of
+ * failure NULL and errno is set.
*/
-GP_Context *GP_ReadPNG(FILE *f, GP_ProgressCallback *callback);
+GP_Context *GP_ReadPNG(GP_IO *io, GP_ProgressCallback *callback);
/*
- * Does both GP_OpenPNG and GP_ReadPNG at once.
+ * Loads a PNG image from a file.
*/
GP_Context *GP_LoadPNG(const char *src_path, GP_ProgressCallback *callback);
@@ -80,7 +61,7 @@ int GP_SavePNG(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
/*
- * Match PNG signature.
+ * Looks for PNG file signature. Returns non-zero if found.
*/
int GP_MatchPNG(const void *buf);
diff --git a/include/loaders/GP_PNM.h b/include/loaders/GP_PNM.h
index 150ff21..4f2dd11 100644
--- a/include/loaders/GP_PNM.h
+++ b/include/loaders/GP_PNM.h
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -25,10 +25,13 @@
#include "core/GP_Context.h"
#include "core/GP_ProgressCallback.h"
+#include "loaders/GP_IO.h"
/*
* PBM Bitmap
*/
+GP_Context *GP_ReadPBM(GP_IO *io, GP_ProgressCallback *callback);
+
GP_Context *GP_LoadPBM(const char *src_path, GP_ProgressCallback *callback);
int GP_SavePBM(const GP_Context *src, const char *dst_path,
@@ -37,6 +40,8 @@ int GP_SavePBM(const GP_Context *src, const char *dst_path,
/*
* PGM Graymap
*/
+GP_Context *GP_ReadPGM(GP_IO *io, GP_ProgressCallback *callback);
+
GP_Context *GP_LoadPGM(const char *src_path,
GP_ProgressCallback *callback);
@@ -46,6 +51,8 @@ int GP_SavePGM(const GP_Context *src, const char *dst_path,
/*
* PPM Pixmap
*/
+GP_Context *GP_ReadPPM(GP_IO *io, GP_ProgressCallback *callback);
+
GP_Context *GP_LoadPPM(const char *src_path, GP_ProgressCallback *callback);
int GP_SavePPM(const GP_Context *src, const char *dst_path,
@@ -54,6 +61,8 @@ int GP_SavePPM(const GP_Context *src, const char *dst_path,
/*
* PNM Anymap (All of above)
*/
+GP_Context *GP_ReadPNM(GP_IO *io, GP_ProgressCallback *callback);
+
GP_Context *GP_LoadPNM(const char *src_path, GP_ProgressCallback *callback);
int GP_SavePNM(const GP_Context *src, const char *dst_path,
diff --git a/include/loaders/GP_PSP.h b/include/loaders/GP_PSP.h
index 3ddf75c..1109bd9 100644
--- a/include/loaders/GP_PSP.h
+++ b/include/loaders/GP_PSP.h
@@ -16,13 +16,15 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
/*
- Experimental Paint Shop Pro image loader.
+ Paint Shop Pro image loader.
+
+ Loads composite image from a PSP file.
*/
@@ -31,35 +33,23 @@
#include "core/GP_ProgressCallback.h"
#include "core/GP_Context.h"
+#include "loaders/GP_IO.h"
/*
- * The possible errno values:
+ * Reads a BMP from an IO stream.
*
- * - EIO for read/write failure
- * - ENOSYS for not implemented bitmap format
- * - ENOMEM from malloc()
- * - EILSEQ for wrong image signature/data
- * - ECANCELED when call was aborted from callback
- */
-
-/*
- * Opens up the PSP image and checks signature.
- * Returns zero on success.
- */
-int GP_OpenPSP(const char *src_path, FILE **f);
-
-/*
- * Reads image from PSP format.
+ * Returns newly allocated context cotaining the loaded image or in case of
+ * failure NULL and errno is set.
*/
-GP_Context *GP_ReadPSP(FILE *f, GP_ProgressCallback *callback);
+GP_Context *GP_ReadPSP(GP_IO *io, GP_ProgressCallback *callback);
/*
- * Does both GP_OpenPSP and GP_ReadPSP at once.
+ * Loads a PSP image from a file.
*/
GP_Context *GP_LoadPSP(const char *src_path, GP_ProgressCallback *callback);
/*
- * Match PSP signature.
+ * Looks for PSP file signature. Returns non-zero if found.
*/
int GP_MatchPSP(const void *buf);
diff --git a/include/loaders/GP_TIFF.h b/include/loaders/GP_TIFF.h
index 73acb5f..8c7c45f 100644
--- a/include/loaders/GP_TIFF.h
+++ b/include/loaders/GP_TIFF.h
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -25,39 +25,18 @@
#include "core/GP_Context.h"
#include "core/GP_ProgressCallback.h"
+#include "loaders/GP_IO.h"
/*
- * The possible errno values:
+ * Reads first image in TIFF from an IO stream.
*
- * - Anything FILE operation may return (fopen(), fclose(), fseek(), ...).
- * - EIO for fread()/fwrite() failure
- * - ENOSYS for not implemented bitmap format
- * - ENOMEM from malloc()
- * - EILSEQ for wrong image signature/data
- * - ECANCELED when call was aborted from callback
+ * Returns newly allocated context cotaining the loaded image or in case of
+ * failure NULL and errno is set.
*/
+GP_Context *GP_ReadTIFF(GP_IO *io, GP_ProgressCallback *callback);
/*
- * Opens up a bmp file, checks signature, parses metadata.
- *
- * The file, width, height and pixel type are filled upon succcessful return.
- *
- * Upon failure, non zero return value is returned and errno is filled.
- */
-int GP_OpenTIFF(const char *src_path, void **t);
-
-/*
- * Reads a TIFF from a opened file.
- *
- * Upon successful return, context to store bitmap is allocated and image is
- * loaded.
- *
- * Upon failure NULL is returned and errno is filled.
- */
-GP_Context *GP_ReadTIFF(void *t, GP_ProgressCallback *callback);
-
-/*
- * Does both GP_OpenTIFF and GP_ReadTIFF.
+ * Loads fist image in TIFF from a file.
*/
GP_Context *GP_LoadTIFF(const char *src_path, GP_ProgressCallback *callback);
@@ -68,7 +47,7 @@ int GP_SaveTIFF(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
/*
- * Match TIFF signature.
+ * Looks for TIFF file signature. Returns non-zero if found.
*/
int GP_MatchTIFF(const void *buf);
diff --git a/libs/loaders/GP_BMP.c b/libs/loaders/GP_BMP.c
index d7ea61f..cc03a5e 100644
--- a/libs/loaders/GP_BMP.c
+++ b/libs/loaders/GP_BMP.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -24,7 +24,7 @@
BMP loader and writer.
- Thanks Wikipedia for the format specification.
+ Thanks Wikipedia for excellent format specification.
*/
@@ -46,12 +46,6 @@
#define BMP_HEADER_OFFSET 0x0a /* info header offset - 4 bytes */
-#define BUF_TO_4(buf, off) - (buf[off] + (buf[off+1]<<8) + (buf[off+2]<<16) + (buf[off+3]<<24))
-
-#define BUF_TO_2(buf, off) - (buf[off] + (buf[off+1]<<8))
-
struct bitmap_info_header {
/*
* Offset to image data.
@@ -155,16 +149,19 @@ static uint32_t get_palette_size(struct bitmap_info_header *header)
return (1 << header->bpp);
}
-static int read_bitfields(FILE *f, struct bitmap_info_header *header)
+static int read_bitfields(GP_IO *io, struct bitmap_info_header *header)
{
- int ret;
+ uint16_t bitfields[] = {
+ GP_IO_L4, /* red mask */
+ GP_IO_L4, /* green mask */
+ GP_IO_L4, /* blue mask */
+ GP_IO_END
+ };
- ret = GP_FRead(f, "L4 L4 L4",
+ if (GP_IOReadF(io, bitfields,
&header->R_mask,
&header->G_mask,
- &header->B_mask);
-
- if (ret != 3) {
+ &header->B_mask) != 3) {
GP_DEBUG(1, "Failed to read BITFIELDS");
return EIO;
}
@@ -177,17 +174,21 @@ static int read_bitfields(FILE *f, struct bitmap_info_header *header)
return 0;
}
-static int read_alphabitfields(FILE *f, struct bitmap_info_header *header)
+static int read_alphabitfields(GP_IO *io, struct bitmap_info_header *header)
{
- int ret;
+ uint16_t abitfields[] = {
+ GP_IO_L4, /* red mask */
+ GP_IO_L4, /* green mask */
+ GP_IO_L4, /* blue mask */
+ GP_IO_L4, /* alpha mask */
+ GP_IO_END
+ };
- ret = GP_FRead(f, "L4 L4 L4 L4",
+ if (GP_IOReadF(io, abitfields,
&header->R_mask,
&header->G_mask,
&header->B_mask,
- &header->A_mask);
-
- if (ret != 4) {
+ &header->A_mask) != 4) {
GP_DEBUG(1, "Failed to read BITFIELDS");
return EIO;
}
@@ -199,11 +200,23 @@ static int read_alphabitfields(FILE *f, struct bitmap_info_header *header)
return 0;
}
-static int read_bitmap_info_header(FILE *f, struct bitmap_info_header *header)
+static int read_bitmap_info_header(GP_IO *io, struct bitmap_info_header *header)
{
uint16_t nr_planes;
- if (GP_FRead(f, "L4 L4 L2 L2 L4 I12 L4 I4",
+ uint16_t bmp_info_header[] = {
+ GP_IO_L4, /* width */
+ GP_IO_L4, /* height */
+ GP_IO_L2, /* number of planes */
+ GP_IO_L2, /* bpp */
+ GP_IO_L4, /* compression type */
+ GP_IO_IGN | 12, /* bitmap size in bytes, resolution */
+ GP_IO_L4, /* palette colors */
+ GP_IO_I4, /* number of significant colors */
+ GP_IO_END
+ };
+
+ if (GP_IOReadF(io, bmp_info_header,
&header->w, &header->h, &nr_planes, &header->bpp,
&header->compress_type, &header->palette_colors) != 8) {
@@ -227,39 +240,46 @@ static int read_bitmap_info_header(FILE *f, struct bitmap_info_header *header)
switch (header->header_size) {
case BITMAPINFOHEADER:
case BITMAPINFOHEADER2:
- return read_bitfields(f, header);
+ return read_bitfields(io, header);
default:
/* Alpha is default in BITMAPINFOHEADER3 and newer */
- return read_alphabitfields(f, header);
+ return read_alphabitfields(io, header);
}
/* Only in BITMAPINFOHEADER */
case COMPRESS_ALPHABITFIELDS:
if (header->header_size != BITMAPINFOHEADER)
GP_DEBUG(1, "Unexpected ALPHABITFIELDS in %s",
bitmap_header_size_name(header->header_size));
- return read_alphabitfields(f, header);
+ return read_alphabitfields(io, header);
}
return 0;
}
-static int read_bitmap_core_header(FILE *f, struct bitmap_info_header *header)
+static int read_bitmap_core_header(GP_IO *io, struct bitmap_info_header *header)
{
- uint8_t buf[12];
+ int16_t nr_planes, w, h;
+
+ uint16_t bmp_core_header[] = {
+ GP_IO_L2, /* width */
+ GP_IO_L2, /* height */
+ GP_IO_L2, /* number of planes */
+ GP_IO_L2, /* bpp */
+ //GP_IO_I4,//TODO read till 12?
+ GP_IO_END
+ };
- if (fread(buf, 1, sizeof(buf), f) != sizeof(buf)) {
+ if (GP_IOReadF(io, bmp_core_header, &w, &h,
+ &nr_planes, &header->bpp) != 4) {
GP_DEBUG(1, "Failed to read bitmap core header");
return EIO;
}
- header->w = BUF_TO_2(buf, 0);
- header->h = BUF_TO_2(buf, 2);
- header->bpp = BUF_TO_2(buf, 6);
+ header->w = w;
+ header->h = h;
header->compress_type = COMPRESS_RGB;
header->palette_colors = 0;
- uint16_t nr_planes = BUF_TO_2(buf, 4);
-
/* This must be 1 according to specs */
if (nr_planes != 1)
GP_DEBUG(1, "Number of planes is %"PRId16" should be 1",
@@ -271,33 +291,32 @@ static int read_bitmap_core_header(FILE *f, struct bitmap_info_header *header)
return 0;
}
-static int read_bitmap_header(FILE *f, struct bitmap_info_header *header)
+static int read_bitmap_header(GP_IO *io, struct bitmap_info_header *header)
{
- uint8_t buf[8];
int err;
- if (fseek(f, BMP_HEADER_OFFSET, SEEK_SET)) {
- err = errno;
- GP_DEBUG(1, "fseek(f, 0x%02x) failed: '%s'",
- BMP_HEADER_OFFSET, strerror(errno));
- return err;
- }
+ uint16_t bmp_header[] = {
+ 'B',
+ 'M',
+ GP_IO_IGN | (4 + 2 + 2), /* 4 bytes filesize + 4 bytes reserved */
+ GP_IO_L4, /* offset to pixel data */
+ GP_IO_L4, /* info header size */
+ GP_IO_END,
+ };
- /* Read info header size, header size determines header type */
- if (fread(buf, 1, sizeof(buf), f) != sizeof(buf)) {
- GP_DEBUG(1, "Failed to read info header size");
+ if (GP_IOReadF(io, bmp_header, &header->pixel_offset,
+ &header->header_size) != 5) {
+ GP_DEBUG(1, "Failed to read header");
+ //TODO: EIO vs EINVAL
return EIO;
}
- header->pixel_offset = BUF_TO_4(buf, 0);
- header->header_size = BUF_TO_4(buf, 4);
-
GP_DEBUG(2, "BMP header type '%s'",
bitmap_header_size_name(header->header_size));
switch (header->header_size) {
case BITMAPCOREHEADER:
- err = read_bitmap_core_header(f, header);
+ err = read_bitmap_core_header(io, header);
break;
case BITMAPCOREHEADER2:
return ENOSYS;
@@ -306,11 +325,11 @@ static int read_bitmap_header(FILE *f, struct bitmap_info_header *header)
case BITMAPINFOHEADER2:
case BITMAPINFOHEADER3:
case BITMAPINFOHEADER4:
- err = read_bitmap_info_header(f, header);
+ err = read_bitmap_info_header(io, header);
break;
default:
GP_DEBUG(1, "Unknown header type, continuing anyway");
- err = read_bitmap_info_header(f, header);
+ err = read_bitmap_info_header(io, header);
break;
};
@@ -320,7 +339,7 @@ static int read_bitmap_header(FILE *f, struct bitmap_info_header *header)
/*
* Reads palette, the format is R G B X, each one byte.
*/
-static int read_bitmap_palette(FILE *f, struct bitmap_info_header *header,
+static int read_bitmap_palette(GP_IO *io, struct bitmap_info_header *header,
GP_Pixel *palette)
{
uint32_t palette_colors = get_palette_size(header);
@@ -342,22 +361,24 @@ static int read_bitmap_palette(FILE *f, struct bitmap_info_header *header,
"pixel size %"PRIu8"bytes",
palette_offset, palette_offset, pixel_size);
- if (fseek(f, palette_offset, SEEK_SET)) {
+ if (GP_IOSeek(io, palette_offset, GP_IO_SEEK_SET) != palette_offset) {
err = errno;
- GP_DEBUG(1, "fseek(f, 0x%02x) failed: '%s'",
+ GP_DEBUG(1, "Seek to 0x%02x failed: '%s'",
BMP_HEADER_OFFSET, strerror(errno));
return err;
}
- for (i = 0; i < palette_colors; i++) {
- uint8_t buf[4];
+ uint8_t buf[pixel_size * palette_colors];
- if (fread(buf, 1, pixel_size, f) != pixel_size) {
- GP_DEBUG(1, "Failed to read palette %"PRIu32, i);
- return EIO;
- }
+ if (GP_IOFill(io, buf, sizeof(buf))) {
+ GP_DEBUG(1, "Failed to read palette: %s", strerror(errno));
+ return EIO;
+ }
+
+ for (i = 0; i < palette_colors; i++) {
+ unsigned int j = i * pixel_size;
- palette[i] = GP_Pixel_CREATE_RGB888(buf[2], buf[1], buf[0]);
+ palette[i] = GP_Pixel_CREATE_RGB888(buf[j+2], buf[j+1], buf[j]);
GP_DEBUG(3, "Palette[%"PRIu32"] = [0x%02x, 0x%02x, 0x%02x]", i,
GP_Pixel_GET_R_RGB888(palette[i]),
@@ -368,17 +389,17 @@ static int read_bitmap_palette(FILE *f, struct bitmap_info_header *header,
return 0;
}
-static int seek_pixels_offset(struct bitmap_info_header *header, FILE *f)
+static int seek_pixels_offset(GP_IO *io, struct bitmap_info_header *header)
{
int err;
GP_DEBUG(2, "Offset to BMP pixels is 0x%x (%ubytes)",
header->pixel_offset, header->pixel_offset);
- if (fseek(f, header->pixel_offset, SEEK_SET)) {
+ if (GP_IOSeek(io, header->pixel_offset, GP_IO_SEEK_SET) != header->pixel_offset) {
err = errno;
- GP_DEBUG(1, "fseek(f, 0x%02x) failed: '%s'",
- header->pixel_offset, strerror(errno));
+ GP_DEBUG(1, "Seek to 0x%02x failed: %s",
+ header->pixel_offset, strerror(err));
return err;
}
@@ -482,17 +503,17 @@ static uint8_t get_idx(struct bitmap_info_header *header,
#include "GP_BMP_RLE.h"
-static int read_palette(FILE *f, struct bitmap_info_header *header,
+static int read_palette(GP_IO *io, struct bitmap_info_header *header,
GP_Context *context, GP_ProgressCallback *callback)
{
uint32_t palette_size = get_palette_size(header);
GP_Pixel palette[get_palette_size(header)];
int err;
- if ((err = read_bitmap_palette(f, header, palette)))
+ if ((err = read_bitmap_palette(io, header, palette)))
return err;
- if ((err = seek_pixels_offset(header, f)))
+ if ((err = seek_pixels_offset(io, header)))
return err;
uint32_t row_size = bitmap_row_size(header);
@@ -502,9 +523,11 @@ static int read_palette(FILE *f, struct bitmap_info_header *header,
int32_t x;
uint8_t row[row_size];
- if (fread(row, 1, row_size, f) != row_size) {
- GP_DEBUG(1, "Failed to read row %"PRId32, y);
- return EIO;
+ if (GP_IOFill(io, row, row_size)) {
+ err = errno;
+ GP_DEBUG(1, "Failed to read row %"PRId32": %s",
+ y, strerror(errno));
+ return err;
}
for (x = 0; x < header->w; x++) {
@@ -539,17 +562,30 @@ static int read_palette(FILE *f, struct bitmap_info_header *header,
return 0;
}
-static int read_bitfields_or_rgb(FILE *f, struct bitmap_info_header *header,
+static int read_bitfields_or_rgb(GP_IO *io, struct bitmap_info_header *header,
GP_Context *context,
GP_ProgressCallback *callback)
{
uint32_t row_size = header->w * (header->bpp / 8);
+ uint32_t row_padd = 0;
int32_t y;
int err;
- if ((err = seek_pixels_offset(header, f)))
+ if ((err = seek_pixels_offset(io, header)))
return err;
+ /* Rows are four byte aligned */
+ switch (row_size % 4) {
+ case 1:
+ row_padd++;
+ case 2:
+ row_padd++;
+ case 3:
+ row_padd++;
+ case 0:
+ break;
+ }
+
for (y = 0; y < GP_ABS(header->h); y++) {
int32_t ry;
@@ -560,21 +596,20 @@ static int read_bitfields_or_rgb(FILE *f, struct bitmap_info_header *header,
uint8_t *row = GP_PIXEL_ADDR(context, 0, ry);
- if (fread(row, 1, row_size, f) != row_size) {
- GP_DEBUG(1, "Failed to read row %"PRId32, y);
- return EIO;
+ if (GP_IOFill(io, row, row_size)) {
+ err = errno;
+ GP_DEBUG(1, "Failed to read row %"PRId32": %s",
+ y, strerror(err));
+ return err;
}
- /* Rows are four byte aligned */
- switch (row_size % 4) {
- case 1:
- fgetc(f);
- case 2:
- fgetc(f);
- case 3:
- fgetc(f);
- case 0:
- break;
+ if (row_padd) {
+ if (GP_IOSeek(io, row_padd, GP_IO_SEEK_CUR) == (off_t)-1) {
+ err = errno;
+ GP_DEBUG(1, "Failed to seek row %"PRId32": %s",
+ y, strerror(err));
+ return err;
+ }
}
if (GP_ProgressCallbackReport(callback, y,
@@ -588,11 +623,11 @@ static int read_bitfields_or_rgb(FILE *f, struct bitmap_info_header *header,
return 0;
}
-static int read_bitmap_pixels(FILE *f, struct bitmap_info_header *header,
+static int read_bitmap_pixels(GP_IO *io, struct bitmap_info_header *header,
GP_Context *context, GP_ProgressCallback *callback)
{
if (header->compress_type == COMPRESS_RLE8)
- return read_RLE8(f, header, context, callback);
+ return read_RLE8(io, header, context, callback);
switch (header->bpp) {
case 1:
@@ -600,11 +635,11 @@ static int read_bitmap_pixels(FILE *f, struct bitmap_info_header *header,
case 2:
case 4:
case 8:
- return read_palette(f, header, context, callback);
+ return read_palette(io, header, context, callback);
case 16:
case 24:
case 32:
- return read_bitfields_or_rgb(f, header, context, callback);
+ return read_bitfields_or_rgb(io, header, context, callback);
}
return ENOSYS;
@@ -615,68 +650,19 @@ int GP_MatchBMP(const void *buf)
return !memcmp(buf, "BM", 2);
}
-int GP_OpenBMP(const char *src_path, FILE **f,
- GP_Size *w, GP_Size *h, GP_PixelType *pixel_type)
-{
- int err;
-
- *f = fopen(src_path, "rb");
-
- if (*f == NULL) {
- err = errno;
- GP_DEBUG(1, "Failed to open '%s' : %s",
- src_path, strerror(errno));
- goto err2;
- }
-
- int ch1 = fgetc(*f);
- int ch2 = fgetc(*f);
-
- if (ch1 != 'B' || ch2 != 'M') {
- GP_DEBUG(1, "Unexpected bitmap header 0x%02x (%c) 0x%02x (%c)",
- ch1, isascii(ch1) ? ch1 : ' ',
- ch2, isascii(ch2) ? ch2 : ' ');
- err = EIO;
- goto err1;
- }
-
- if (w != NULL || h != NULL || pixel_type != NULL) {
- struct bitmap_info_header header;
-
- if ((err = read_bitmap_header(*f, &header)))
- goto err1;
-
- if (w != NULL)
- *w = header.w;
-
- if (h != NULL)
- *h = header.h;
-
- if (pixel_type != NULL)
- *pixel_type = match_pixel_type(&header);
- }
-
- return 0;
-err1:
- fclose(*f);
-err2:
- errno = err;
- return 1;
-}
-
-GP_Context *GP_ReadBMP(FILE *f, GP_ProgressCallback *callback)
+GP_Context *GP_ReadBMP(GP_IO *io, GP_ProgressCallback *callback)
{
struct bitmap_info_header header;
GP_PixelType pixel_type;
GP_Context *context;
int err;
- if ((err = read_bitmap_header(f, &header)))
+ if ((err = read_bitmap_header(io, &header)))
goto err1;
if (header.w <= 0 || header.h == 0) {
GP_WARN("Width and/or Height is not > 0");
- err = EIO;
+ err = EINVAL;
goto err1;
}
@@ -705,7 +691,7 @@ GP_Context *GP_ReadBMP(FILE *f, GP_ProgressCallback *callback)
goto err1;
}
- if ((err = read_bitmap_pixels(f, &header, context, callback)))
+ if ((err = read_bitmap_pixels(io, &header, context, callback)))
goto err2;
return context;
@@ -718,14 +704,19 @@ err1:
GP_Context *GP_LoadBMP(const char *src_path, GP_ProgressCallback *callback)
{
- FILE *f;
+ GP_IO *io;
GP_Context *res;
+ int err;
- if (GP_OpenBMP(src_path, &f, NULL, NULL, NULL))
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
return NULL;
- res = GP_ReadBMP(f, callback);
- fclose(f);
+ res = GP_ReadBMP(io, callback);
+
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
return res;
}
diff --git a/libs/loaders/GP_BMP_RLE.h b/libs/loaders/GP_BMP_RLE.h
index 6f7645f..4c228fb 100644
--- a/libs/loaders/GP_BMP_RLE.h
+++ b/libs/loaders/GP_BMP_RLE.h
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -57,20 +57,34 @@ struct RLE {
/* current value */
int c;
+
+ GP_IO *io;
+
+ int buf_pos;
+ int buf_end;
+ uint8_t buf[512];
};
-#define DECLARE_RLE(name, iw, ih) struct RLE name = { +#define DECLARE_RLE(name, iw, ih, iio) struct RLE name = { .state = RLE_START, - .w = iw, .h = ih, - .x = 0, .y = 0, - .rep = 0+ .w = iw, .h = ih, + .x = 0, .y = 0, + .rep = 0, + .io = io, + .buf_pos = 0, + .buf_end = 0, }
-#define GETC(f, rle) do { - rle->c = fgetc(f); - - if (rle->c == EOF) - return EIO; +#define GETC(rle) do { + if (rle->buf_pos < rle->buf_end) { + rle->c = rle->buf[rle->buf_pos++]; + } else { + rle->buf_end = GP_IORead(rle->io, rle->buf, sizeof(rle->buf));+ if (rle->buf_end <= 0) + return EIO; + rle->c = rle->buf[0]; + rle->buf_pos = 1; + } } while (0)
static void RLE8_move(struct RLE *rle)
@@ -119,9 +133,9 @@ static int RLE8_end_of_bitmap(struct RLE *rle)
return 0;
}
-static int RLE8_repeat(FILE *f, uint8_t rep, struct RLE *rle)
+static int RLE8_repeat(uint8_t rep, struct RLE *rle)
{
- GETC(f, rle);
+ GETC(rle);
GP_DEBUG(4, "RLE Repeat %i x 0x%02x", rep, rle->c);
@@ -131,12 +145,14 @@ static int RLE8_repeat(FILE *f, uint8_t rep, struct RLE *rle)
return 0;
}
-static int RLE8_offset(FILE *f, struct RLE *rle)
+static int RLE8_offset(struct RLE *rle)
{
int x, y;
- x = fgetc(f);
- y = fgetc(f);
+ GETC(rle);
+ x = rle->c;
+ GETC(rle);
+ y = rle->c;
if (x == EOF || y == EOF)
return EIO;
@@ -154,9 +170,9 @@ static int RLE8_offset(FILE *f, struct RLE *rle)
return 0;
}
-static int RLE8_next_undecoded(FILE *f, struct RLE *rle)
+static int RLE8_next_undecoded(struct RLE *rle)
{
- GETC(f, rle);
+ GETC(rle);
RLE8_move(rle);
@@ -166,7 +182,7 @@ static int RLE8_next_undecoded(FILE *f, struct RLE *rle)
rle->state = RLE_START;
/* must be padded to odd number of bytes */
if (rle->flag)
- fgetc(f);
+ GETC(rle);
}
rle->move = 1;
@@ -188,9 +204,9 @@ static int RLE8_next_repeat(struct RLE *rle)
return 0;
}
-static int RLE8_esc(FILE *f, struct RLE *rle)
+static int RLE8_esc(struct RLE *rle)
{
- GETC(f, rle);
+ GETC(rle);
GP_DEBUG(4, "RLE ESC %02x", rle->c);
@@ -200,43 +216,43 @@ static int RLE8_esc(FILE *f, struct RLE *rle)
case 0x01:
return RLE8_end_of_bitmap(rle);
case 0x02:
- return RLE8_offset(f, rle);
+ return RLE8_offset(rle);
/* Undecoded sequence */
default:
GP_DEBUG(4, "RLE Undecoded x %i", rle->c);
rle->state = RLE_UNDECODED;
- rle->rep = rle->c;
+ rle->rep = rle->c;
rle->flag = rle->c % 2;
return 0;
}
}
-static int RLE8_start(FILE *f, struct RLE *rle)
+static int RLE8_start(struct RLE *rle)
{
- GETC(f, rle);
+ GETC(rle);
switch (rle->c) {
case 0x00:
- return RLE8_esc(f, rle);
+ return RLE8_esc(rle);
default:
- return RLE8_repeat(f, rle->c, rle);
+ return RLE8_repeat(rle->c, rle);
}
}
-static int RLE8_next(FILE *f, struct RLE *rle)
+static int RLE8_next(struct RLE *rle)
{
int err;
for (;;) {
switch (rle->state) {
case RLE_START:
- if ((err = RLE8_start(f, rle)))
+ if ((err = RLE8_start(rle)))
return err;
break;
case RLE_REPEAT:
return RLE8_next_repeat(rle);
case RLE_UNDECODED:
- return RLE8_next_undecoded(f, rle);
+ return RLE8_next_undecoded(rle);
case RLE_STOP:
return 0;
default:
@@ -247,18 +263,18 @@ static int RLE8_next(FILE *f, struct RLE *rle)
}
}
-static int read_RLE8(FILE *f, struct bitmap_info_header *header,
+static int read_RLE8(GP_IO *io, struct bitmap_info_header *header,
GP_Context *context, GP_ProgressCallback *callback)
{
uint32_t palette_size = get_palette_size(header);
GP_Pixel palette[get_palette_size(header)];
- DECLARE_RLE(rle, header->w, GP_ABS(header->h));
+ DECLARE_RLE(rle, header->w, GP_ABS(header->h), io);
int err;
- if ((err = read_bitmap_palette(f, header, palette)))
+ if ((err = read_bitmap_palette(io, header, palette)))
return err;
- if ((err = seek_pixels_offset(header, f)))
+ if ((err = seek_pixels_offset(io, header)))
return err;
int cnt = 0;
@@ -272,7 +288,7 @@ static int read_RLE8(FILE *f, struct bitmap_info_header *header,
GP_Fill(context, palette[0]);
for (;;) {
- if ((err = RLE8_next(f, &rle)))
+ if ((err = RLE8_next(&rle)))
return err;
if (rle.state == RLE_STOP)
diff --git a/libs/loaders/GP_GIF.c b/libs/loaders/GP_GIF.c
index 688f914..88bddee 100644
--- a/libs/loaders/GP_GIF.c
+++ b/libs/loaders/GP_GIF.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -38,7 +38,8 @@
#include "core/GP_Fill.h"
#include "core/GP_Debug.h"
-#include "GP_GIF.h"
+#include "loaders/GP_IO.h"
+#include "loaders/GP_GIF.h"
#ifdef HAVE_GIFLIB
@@ -61,39 +62,11 @@ int GP_MatchGIF(const void *buf)
return 0;
}
-int GP_OpenGIF(const char *src_path, void **f)
+static int gif_input_func(GifFileType* gif, GifByteType* bytes, int size)
{
- GifFileType *gf;
-
- errno = 0;
-
-#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
- gf = DGifOpenFileName(src_path, NULL);
-#else
- gf = DGifOpenFileName(src_path);
-#endif
+ GP_IO *io = gif->UserData;
- if (gf == NULL) {
- /*
- * The giflib uses open() so when we got a failure and errno
- * is set => open() has failed.
- *
- * When errno is not set the file content was not valid so we
- * set errno to EIO.
- */
- if (errno == 0)
- errno = EIO;
-
- return 1;
- }
-
- GP_DEBUG(1, "Have GIF image %ix%i, %i colors, %i bpp",
- gf->SWidth, gf->SHeight, gf->SColorResolution,
- gf->SColorMap ? gf->SColorMap->BitsPerPixel : -1);
-
- *f = gf;
-
- return 0;
+ return GP_IORead(io, bytes, size);
}
static const char *rec_type_name(GifRecordType rec_type)
@@ -255,15 +228,41 @@ static inline unsigned int interlace_real_y(GifFileType *gf, unsigned int y)
return 0;
}
-GP_Context *GP_ReadGIF(void *f, GP_ProgressCallback *callback)
+GP_Context *GP_ReadGIF(GP_IO *io, GP_ProgressCallback *callback)
{
- GifFileType *gf = f;
+ GifFileType *gf;
GifRecordType rec_type;
GP_Context *res = NULL;
GP_Pixel bg;
int32_t x, y;
int err;
+ errno = 0;
+#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
+ gf = DGifOpen(io, gif_input_func, NULL);
+#else
+ gf = DGifOpen(io, gif_input_func);
+#endif
+
+ if (gf == NULL) {
+ /*
+ * The giflib uses open() so when we got a failure and errno
+ * is set => open() has failed.
+ *
+ * When errno is not set the file content was not valid so we
+ * set errno to EIO.
+ */
+ if (errno == 0)
+ errno = EIO;
+
+ return NULL;
+ }
+
+ GP_DEBUG(1, "Have GIF image %ix%i, %i colors, %i bpp",
+ gf->SWidth, gf->SHeight, gf->SColorResolution,
+ gf->SColorMap ? gf->SColorMap->BitsPerPixel : -1);
+
+
do {
if (DGifGetRecordType(gf, &rec_type) != GIF_OK) {
//TODO: error handling
@@ -361,12 +360,21 @@ err1:
GP_Context *GP_LoadGIF(const char *src_path, GP_ProgressCallback *callback)
{
- void *f;
+ GP_IO *io;
+ GP_Context *res;
+ int err;
- if (GP_OpenGIF(src_path, &f))
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
return NULL;
- return GP_ReadGIF(f, callback);
+ res = GP_ReadGIF(io, callback);
+
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
+
+ return res;
}
#else
@@ -377,14 +385,7 @@ int GP_MatchGIF(const void GP_UNUSED(*buf))
return -1;
}
-int GP_OpenGIF(const char GP_UNUSED(*src_path),
- void GP_UNUSED(**f))
-{
- errno = ENOSYS;
- return 1;
-}
-
-GP_Context *GP_ReadGIF(void GP_UNUSED(*f),
+GP_Context *GP_ReadGIF(GP_IO GP_UNUSED(*io),
GP_ProgressCallback GP_UNUSED(*callback))
{
errno = ENOSYS;
diff --git a/libs/loaders/GP_IO.c b/libs/loaders/GP_IO.c
new file mode 100644
index 0000000..a1409a6
--- /dev/null
+++ b/libs/loaders/GP_IO.c
@@ -0,0 +1,432 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdarg.h>
+
+#include <core/GP_ByteOrder.h>
+#include <core/GP_Debug.h>
+#include <core/GP_Common.h>
+
+#include "loaders/GP_IO.h"
+
+struct file_io {
+ int fd;
+};
+
+static ssize_t file_read(GP_IO *self, void *buf, size_t size)
+{
+ struct file_io *file_io = GP_IO_PRIV(self);
+
+ return read(file_io->fd, buf, size);
+}
+
+static ssize_t file_write(GP_IO *self, void *buf, size_t size)
+{
+ struct file_io *file_io = GP_IO_PRIV(self);
+
+ return write(file_io->fd, buf, size);
+}
+
+static off_t file_seek(GP_IO *self, off_t off, enum GP_IOWhence whence)
+{
+ struct file_io *file_io = GP_IO_PRIV(self);
+
+ switch (whence) {
+ case GP_IO_SEEK_SET:
+ case GP_IO_SEEK_CUR:
+ case GP_IO_SEEK_END:
+ break;
+ default:
+ GP_WARN("Invalid whence");
+ return (off_t)-1;
+ }
+
+ return lseek(file_io->fd, off, whence);
+}
+
+static int file_close(GP_IO *self)
+{
+ struct file_io *file_io = GP_IO_PRIV(self);
+ int fd;
+
+ GP_DEBUG(1, "Closing IOFile");
+
+ fd = file_io->fd;
+ free(self);
+
+ return close(fd);
+}
+
+GP_IO *GP_IOFile(const char *path, enum GP_IOFileMode mode)
+{
+ int err, flags;
+ GP_IO *io;
+ struct file_io *file_io;
+
+ GP_DEBUG(1, "Creating IOFile '%s'", path);
+
+ io = malloc(sizeof(GP_IO) + sizeof(struct file_io));
+
+ if (!io) {
+ GP_DEBUG(1, "Malloc failed :(");
+ err = ENOMEM;
+ goto err0;
+ }
+
+ switch (mode) {
+ case GP_IO_WRONLY:
+ flags = O_CREAT | O_WRONLY;
+ break;
+ case GP_IO_RDONLY:
+ flags = O_RDONLY;
+ break;
+ case GP_IO_RDWR:
+ flags = O_CREAT | O_RDWR;
+ break;
+ }
+
+ file_io = GP_IO_PRIV(io);
+ file_io->fd = open(path, flags, 0666);
+
+ if (file_io->fd < 0) {
+ err = errno;
+ GP_DEBUG(1, "Failed to open '%s': %s", path, strerror(errno));
+ goto err1;
+ }
+
+ io->mark = 0;
+
+ io->Seek = file_seek;
+ io->Read = file_read;
+ io->Write = file_write;
+
+ if (mode == GP_IO_RDONLY)
+ io->Write = NULL;
+
+ if (mode == GP_IO_WRONLY)
+ io->Read = NULL;
+
+ io->Close = file_close;
+
+ return io;
+err1:
+ free(io);
+err0:
+ errno = err;
+ return NULL;
+}
+
+struct mem_io {
+ uint8_t *buf;
+ size_t size;
+ size_t pos;
+ void (*free)(void *);
+};
+
+static ssize_t mem_read(GP_IO *io, void *buf, size_t size)
+{
+ struct mem_io *mem_io = GP_IO_PRIV(io);
+ size_t rest = mem_io->size - mem_io->pos;
+ ssize_t ret = GP_MIN(rest, size);
+
+ if (ret <= 0) {
+ errno = EIO;
+ return 0;
+ }
+
+ memcpy(buf, mem_io->buf + mem_io->pos, ret);
+ mem_io->pos += ret;
+
+ return ret;
+}
+
+static off_t mem_seek(GP_IO *io, off_t off, enum GP_IOWhence whence)
+{
+ struct mem_io *mem_io = GP_IO_PRIV(io);
+
+ switch (whence) {
+ case GP_IO_SEEK_CUR:
+ if (off + mem_io->pos > mem_io->size) {
+ errno = EINVAL;
+ return (off_t)-1;
+ }
+
+ mem_io->pos += off;
+ break;
+ case GP_IO_SEEK_SET:
+ if (off < 0 || off > (off_t)mem_io->pos) {
+ errno = EINVAL;
+ return (off_t)-1;
+ }
+ mem_io->pos = off;
+ break;
+ case GP_IO_SEEK_END:
+ if (off) {
+ errno = EINVAL;
+ return (off_t)-1;
+ }
+ mem_io->pos = mem_io->size;
+ break;
+ default:
+ GP_WARN("Invalid whence");
+ return (off_t)-1;
+ }
+
+ return mem_io->pos;
+}
+
+static int mem_close(GP_IO *io)
+{
+ struct mem_io *mem_io = GP_IO_PRIV(io);
+
+ GP_DEBUG(1, "Closing IOMem");
+
+ if (mem_io->free)
+ mem_io->free(mem_io->buf);
+
+ free(io);
+
+ return 0;
+}
+
+GP_IO *GP_IOMem(void *buf, size_t size, void (*free)(void *))
+{
+ GP_IO *io;
+ struct mem_io *mem_io;
+
+ GP_DEBUG(1, "Creating IOMem %p size=%zu", buf, size);
+
+ io = malloc(sizeof(GP_IO) + sizeof(*mem_io));
+
+ if (!io) {
+ GP_DEBUG(1, "Malloc failed :(");
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ io->Read = mem_read;
+ io->Seek = mem_seek;
+ io->Close = mem_close;
+ io->Write = NULL;
+
+ mem_io = GP_IO_PRIV(io);
+
+ mem_io->free = free;
+ mem_io->buf = buf;
+ mem_io->size = size;
+ mem_io->pos = 0;
+
+ return io;
+}
+
+int GP_IOMark(GP_IO *self, enum GP_IOMarkTypes type)
+{
+ off_t ret;
+
+ switch (type) {
+ case GP_IO_MARK:
+ ret = GP_IOSeek(self, 0, GP_IO_SEEK_CUR);
+ break;
+ case GP_IO_REWIND:
+ ret = GP_IOSeek(self, self->mark, SEEK_SET);
+ break;
+ default:
+ GP_WARN("Invalid mark type");
+ return -1;
+ }
+
+ if (ret == (off_t)-1) {
+ GP_WARN("Failed to lseek IO Stream");
+ return -1;
+ }
+
+ self->mark = ret;
+ return 0;
+}
+
+off_t GP_IOSize(GP_IO *io)
+{
+ off_t cur = GP_IOTell(io);
+ off_t ret;
+
+ ret = GP_IOSeek(io, 0, GP_IO_SEEK_END);
+
+ if (ret == (off_t)-1)
+ return ret;
+
+ GP_IOSeek(io, cur, GP_IO_SEEK_SET);
+
+ GP_DEBUG(2, "IO Size = %lli", (long long)ret);
+
+ return ret;
+}
+
+int GP_IOFill(GP_IO *io, void *buf, size_t size)
+{
+ size_t read = 0;
+ int ret;
+
+ do {
+ ret = GP_IORead(io, (char*)buf + read, size - read);
+
+ if (ret <= 0) {
+ GP_DEBUG(1, "Failed to fill buffer");
+ return 1;
+ }
+
+ read += ret;
+
+ } while (read < size);
+
+ return 0;
+}
+
+#define TYPE(x) ((x) & GP_IO_TYPE_MASK)
+#define VAL(x) ((x) & ~GP_IO_TYPE_MASK)
+
+static unsigned int readf_size(uint16_t *types)
+{
+ unsigned int size = 0;
+
+ while (*types != GP_IO_END) {
+ switch (TYPE(*types)) {
+ case GP_IO_CONST:
+ case GP_IO_BYTE:
+ size++;
+ break;
+ case GP_IO_L2:
+ case GP_IO_B2:
+ size += 2;
+ break;
+ case GP_IO_L4:
+ case GP_IO_B4:
+ size += 4;
+ break;
+ case GP_IO_ARRAY:
+ case GP_IO_IGN:
+ size+=VAL(*types);
+ break;
+ }
+ types++;
+ }
+
+ return size;
+}
+
+static int needs_swap(uint16_t type)
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ if (type == GP_IO_L2 || type == GP_IO_L4)
+ return 1;
+ return 0;
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ if (type == GP_IO_B2 || type == GP_IO_B4)
+ return 1;
+ return 0;
+#else
+# error Unknown Endianity
+#endif
+}
+
+int GP_IOReadF(GP_IO *self, uint16_t *types, ...)
+{
+ unsigned int size = readf_size(types);
+ uint8_t buffer[size], *buf = buffer;
+ int ret;
+ va_list va;
+ uint8_t *ptr;
+
+ buf[0] = 0;
+
+ if (GP_IOFill(self, buf, size))
+ return -1;
+
+ ret = 0;
+ va_start(va, types);
+
+ while (*types != GP_IO_END) {
+ switch (TYPE(*types)) {
+ case GP_IO_CONST:
+ //TODO: Seek back?
+ if (VAL(*types) != *buf) {
+ errno = EINVAL;
+ goto end;
+ }
+ buf++;
+ break;
+ case GP_IO_BYTE:
+ ptr = va_arg(va, uint8_t*);
+ *ptr = *buf;
+ buf++;
+ break;
+ case GP_IO_L2:
+ case GP_IO_B2:
+ ptr = va_arg(va, uint8_t*);
+
+ if (needs_swap(*types)) {
+ ptr[0] = buf[1];
+ ptr[1] = buf[0];
+ } else {
+ ptr[0] = buf[0];
+ ptr[1] = buf[1];
+ }
+ buf += 2;
+ break;
+ case GP_IO_L4:
+ case GP_IO_B4:
+ ptr = va_arg(va, uint8_t*);
+
+ if (needs_swap(*types)) {
+ ptr[0] = buf[3];
+ ptr[1] = buf[2];
+ ptr[2] = buf[1];
+ ptr[3] = buf[0];
+ } else {
+ ptr[0] = buf[0];
+ ptr[1] = buf[1];
+ ptr[2] = buf[2];
+ ptr[3] = buf[3];
+ }
+ buf += 4;
+ break;
+ case GP_IO_ARRAY:
+ ptr = va_arg(va, void*);
+ memcpy(ptr, buf, VAL(*types));
+ case GP_IO_IGN:
+ buf += VAL(*types);
+ break;
+ }
+
+ types++;
+ ret++;
+ }
+
+end:
+ va_end(va);
+ return ret;
+}
diff --git a/libs/loaders/GP_JP2.c b/libs/loaders/GP_JP2.c
index 2a8d11d..ef412ca 100644
--- a/libs/loaders/GP_JP2.c
+++ b/libs/loaders/GP_JP2.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -36,10 +36,6 @@
#include "GP_JP2.h"
-#ifdef HAVE_OPENJPEG
-
-#include <openjpeg-2.0/openjpeg.h>
-
#define JP2_SIG "x00x00x00x0cjPx20x20x0dx0ax87x0a"
#define JP2_SIG_LEN 12
@@ -48,24 +44,9 @@ int GP_MatchJP2(const void *buf)
return !memcmp(buf, JP2_SIG, JP2_SIG_LEN);
}
-int GP_OpenJP2(const char *src_path, FILE **f)
-{
- int err;
-
- *f = fopen(src_path, "rb");
-
- if (*f == NULL) {
- err = errno;
- GP_DEBUG(1, "Failed to open '%s' : %s",
- src_path, strerror(errno));
- errno = err;
- return 1;
- }
-
- //TODO: check signature and rewind the stream
+#ifdef HAVE_OPENJPEG
- return 0;
-}
+#include <openjpeg-2.0/openjpeg.h>
static void jp2_err_callback(const char *msg, void *priv)
{
@@ -81,11 +62,8 @@ static void jp2_warn_callback(const char *msg, void *priv)
static void jp2_info_callback(const char *msg, void *priv)
{
- GP_ProgressCallback *callback = priv;
-
+ (void) priv;
GP_DEBUG(1, "openjpeg: %s", msg);
-
- GP_ProgressCallbackReport(callback, 100, 100, 100);
}
static const char *color_space_name(OPJ_COLOR_SPACE color_space)
@@ -106,7 +84,12 @@ static const char *color_space_name(OPJ_COLOR_SPACE color_space)
}
}
-GP_Context *GP_ReadJP2(FILE *f, GP_ProgressCallback *callback)
+static OPJ_SIZE_T jp2_io_read(void *buf, OPJ_SIZE_T size, void *io)
+{
+ return GP_IORead(io, buf, size);
+}
+
+GP_Context *GP_ReadJP2(GP_IO *io, GP_ProgressCallback *callback)
{
opj_dparameters_t params;
opj_codec_t *codec;
@@ -138,7 +121,7 @@ GP_Context *GP_ReadJP2(FILE *f, GP_ProgressCallback *callback)
goto err1;
}
- stream = opj_stream_create_default_file_stream(f, OPJ_TRUE);
+ stream = opj_stream_default_create(OPJ_TRUE);
if (!stream) {
GP_DEBUG(1, "opj_stream_create_default_file_stream faled");
@@ -146,6 +129,10 @@ GP_Context *GP_ReadJP2(FILE *f, GP_ProgressCallback *callback)
goto err1;
}
+ //TODO: Do we need seek and skip?
+ opj_stream_set_read_function(stream, jp2_io_read);
+ opj_stream_set_user_data(stream, io);
+
if (!opj_read_header(stream, codec, &img)) {
GP_DEBUG(1, "opj_read_header failed");
err = EINVAL;
@@ -197,6 +184,8 @@ GP_Context *GP_ReadJP2(FILE *f, GP_ProgressCallback *callback)
goto err3;
}
+ GP_ProgressCallbackReport(callback, 0, 100, 100);
+
if (!opj_decode(codec, stream, img)) {
GP_DEBUG(1, "opj_decode failed");
err = EINVAL;
@@ -238,35 +227,27 @@ err0:
GP_Context *GP_LoadJP2(const char *src_path, GP_ProgressCallback *callback)
{
- FILE *f;
+ GP_IO *io;
GP_Context *res;
+ int err;
- if (GP_OpenJP2(src_path, &f))
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
return NULL;
- res = GP_ReadJP2(f, callback);
+ res = GP_ReadJP2(io, callback);
- fclose(f);
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
return res;
}
#else
-int GP_MatchJP2(const void GP_UNUSED(*buf))
-{
- errno = ENOSYS;
- return -1;
-}
-
-int GP_OpenJP2(const char GP_UNUSED(*src_path), FILE GP_UNUSED(**f))
-{
- errno = ENOSYS;
- return 1;
-}
-
-GP_Context *GP_ReadJP2(FILE GP_UNUSED(*f),
- GP_ProgressCallback GP_UNUSED(*callback))
+GP_Context *GP_ReadJP2(GP_IO GP_UNUSED(*io),
+ GP_ProgressCallback GP_UNUSED(*callback))
{
errno = ENOSYS;
return NULL;
diff --git a/libs/loaders/GP_JPG.c b/libs/loaders/GP_JPG.c
index aa6b1c4..8448ba0 100644
--- a/libs/loaders/GP_JPG.c
+++ b/libs/loaders/GP_JPG.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -56,25 +56,6 @@ int GP_MatchJPG(const void *buf)
return !memcmp(buf, JPEG_SIGNATURE, JPEG_SIGNATURE_LEN);
}
-int GP_OpenJPG(const char *src_path, FILE **f)
-{
- int err;
-
- *f = fopen(src_path, "rb");
-
- if (*f == NULL) {
- err = errno;
- GP_DEBUG(1, "Failed to open '%s' : %s",
- src_path, strerror(errno));
- errno = err;
- return 1;
- }
-
- //TODO: check signature and rewind the stream
-
- return 0;
-}
-
struct my_jpg_err {
struct jpeg_error_mgr error_mgr;
jmp_buf setjmp_buf;
@@ -155,11 +136,57 @@ static int load_cmyk(struct jpeg_decompress_struct *cinfo, GP_Context *ret,
return 0;
}
-GP_Context *GP_ReadJPG(FILE *f, GP_ProgressCallback *callback)
+
+struct my_source_mgr {
+ struct jpeg_source_mgr mgr;
+ void *buffer;
+ size_t size;
+ GP_IO *io;
+};
+
+static void dummy(j_decompress_ptr GP_UNUSED(cinfo))
+{
+}
+
+static boolean fill_input_buffer(struct jpeg_decompress_struct *cinfo)
+{
+ int ret;
+ struct my_source_mgr* src = (void*)cinfo->src;
+
+ ret = GP_IORead(src->io, src->buffer, src->size);
+
+ if (ret < 0) {
+ GP_WARN("Failed to fill buffer");
+ return 0;
+ }
+
+ src->mgr.next_input_byte = src->buffer;
+ src->mgr.bytes_in_buffer = src->size;
+ return 1;
+}
+
+static void skip_input_data(struct jpeg_decompress_struct *cinfo, long num_bytes)
+{
+ struct my_source_mgr* src = (void*)cinfo->src;
+
+ GP_DEBUG(3, "Skipping %li bytes", num_bytes);
+
+ if (src->mgr.bytes_in_buffer < (unsigned long)num_bytes) {
+ src->mgr.bytes_in_buffer = 0;
+ GP_IOSeek(src->io, num_bytes - src->mgr.bytes_in_buffer, GP_IO_SEEK_CUR);
+ } else {
+ src->mgr.bytes_in_buffer -= num_bytes;
+ src->mgr.next_input_byte += num_bytes;
+ }
+}
+
+GP_Context *GP_ReadJPG(GP_IO *io, GP_ProgressCallback *callback)
{
struct jpeg_decompress_struct cinfo;
+ struct my_source_mgr src;
struct my_jpg_err my_err;
GP_Context *ret = NULL;
+ uint8_t buffer[1024];
int err;
cinfo.err = jpeg_std_error(&my_err.error_mgr);
@@ -171,7 +198,19 @@ GP_Context *GP_ReadJPG(FILE *f, GP_ProgressCallback *callback)
}
jpeg_create_decompress(&cinfo);
- jpeg_stdio_src(&cinfo, f);
+
+ /* Initialize custom source manager */
+ src.mgr.init_source = dummy;
+ src.mgr.resync_to_restart = jpeg_resync_to_restart;
+ src.mgr.term_source = dummy;
+ src.mgr.fill_input_buffer = fill_input_buffer;
+ src.mgr.skip_input_data = skip_input_data;
+ src.mgr.bytes_in_buffer = 0;
+ src.mgr.next_input_byte = NULL;
+ src.io = io;
+ src.buffer = buffer;
+ src.size = sizeof(buffer);
+ cinfo.src = (void*)&src;
jpeg_read_header(&cinfo, TRUE);
@@ -245,15 +284,19 @@ err1:
GP_Context *GP_LoadJPG(const char *src_path, GP_ProgressCallback *callback)
{
- FILE *f;
+ GP_IO *io;
GP_Context *res;
+ int err;
- if (GP_OpenJPG(src_path, &f))
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
return NULL;
- res = GP_ReadJPG(f, callback);
+ res = GP_ReadJPG(io, callback);
- fclose(f);
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
return res;
}
@@ -333,15 +376,15 @@ err1:
int GP_LoadJPGMetaData(const char *src_path, GP_MetaData *data)
{
- FILE *f;
- int ret;
+ //FILE *f;
+ int ret = -1;
- if (GP_OpenJPG(src_path, &f))
- return 1;
+ //if (GP_OpenJPG(src_path, &f))
+ // return 1;
- ret = GP_ReadJPGMetaData(f, data);
+ //ret = GP_ReadJPGMetaData(f, data);
- fclose(f);
+ //fclose(f);
return ret;
}
diff --git a/libs/loaders/GP_PNG.c b/libs/loaders/GP_PNG.c
index 384d599..71812ba 100644
--- a/libs/loaders/GP_PNG.c
+++ b/libs/loaders/GP_PNG.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -49,46 +49,6 @@ int GP_MatchPNG(const void *buf)
return !png_sig_cmp(buf, 0, 8);
}
-int GP_OpenPNG(const char *src_path, FILE **f)
-{
- uint8_t sig[8];
- int err;
-
- *f = fopen(src_path, "r");
-
- if (*f == NULL) {
- err = errno;
- GP_DEBUG(1, "Failed to open '%s' : %s",
- src_path, strerror(errno));
- goto err1;
- }
-
- if (fread(sig, 1, 8, *f) <= 0) {
- err = EIO;
- GP_DEBUG(1, "Failed to read '%s' : %s",
- src_path, strerror(errno));
- goto err2;
- }
-
- if (png_sig_cmp(sig, 0, 8)) {
- GP_DEBUG(1, "Invalid file header, '%s' not a PNG image?",
- src_path);
- err = EINVAL;
- goto err2;
- }
-
- GP_DEBUG(1, "Found PNG signature in '%s'", src_path);
-
- rewind(*f);
-
- return 0;
-err2:
- fclose(*f);
-err1:
- errno = err;
- return 1;
-}
-
static const char *interlace_type_name(int interlace)
{
switch (interlace) {
@@ -101,7 +61,18 @@ static const char *interlace_type_name(int interlace)
}
}
-GP_Context *GP_ReadPNG(FILE *f, GP_ProgressCallback *callback)
+static void read_data(png_structp png_ptr, png_bytep data, png_size_t len)
+{
+ int res;
+ GP_IO *io = png_get_io_ptr(png_ptr);
+
+ res = GP_IORead(io, data, len);
+
+ if (res < 0 || (png_size_t)res != len)
+ png_error(png_ptr, "Read Error");
+}
+
+GP_Context *GP_ReadPNG(GP_IO *io, GP_ProgressCallback *callback)
{
png_structp png;
png_infop png_info = NULL;
@@ -135,7 +106,8 @@ GP_Context *GP_ReadPNG(FILE *f, GP_ProgressCallback *callback)
goto err2;
}
- png_init_io(png, f);
+ //png_init_io(png, f);
+ png_set_read_fn(png, io, read_data);
png_set_sig_bytes(png, 0);
png_read_info(png, png_info);
@@ -291,15 +263,19 @@ err1:
GP_Context *GP_LoadPNG(const char *src_path, GP_ProgressCallback *callback)
{
- FILE *f;
+ GP_IO *io;
GP_Context *res;
+ int err;
- if (GP_OpenPNG(src_path, &f))
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
return NULL;
- res = GP_ReadPNG(f, callback);
+ res = GP_ReadPNG(io, callback);
- fclose(f);
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
return res;
}
@@ -413,8 +389,8 @@ int GP_LoadPNGMetaData(const char *src_path, GP_MetaData *data)
FILE *f;
int ret;
- if (GP_OpenPNG(src_path, &f))
- return 1;
+// if (GP_OpenPNG(src_path, &f))
+// return 1;
ret = GP_ReadPNGMetaData(f, data);
@@ -636,14 +612,7 @@ int GP_MatchPNG(const void GP_UNUSED(*buf))
return -1;
}
-int GP_OpenPNG(const char GP_UNUSED(*src_path),
- FILE GP_UNUSED(**f))
-{
- errno = ENOSYS;
- return 1;
-}
-
-GP_Context *GP_ReadPNG(FILE GP_UNUSED(*f),
+GP_Context *GP_ReadPNG(GP_IO GP_UNUSED(*io),
GP_ProgressCallback GP_UNUSED(*callback))
{
errno = ENOSYS;
diff --git a/libs/loaders/GP_PNM.c b/libs/loaders/GP_PNM.c
index de81c4b..1a17e53 100644
--- a/libs/loaders/GP_PNM.c
+++ b/libs/loaders/GP_PNM.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -156,12 +156,67 @@ enum state {
S_INT,
};
-static int load_header(FILE *f, struct pnm_header *header)
+/*
+ * Simple buffer implementation on the top of the GP_IO
+ */
+struct buf {
+ uint8_t buf[100];
+ unsigned int buf_end;
+ unsigned int buf_pos;
+ GP_IO *io;
+};
+
+#define DECLARE_BUFFER(name, bio) + struct buf name = {.buf_end = 0, .buf_pos = 0, .io = bio}
+
+static int getb(struct buf *buf)
+{
+ int ret;
+
+ if (buf->buf_pos < buf->buf_end)
+ return buf->buf[buf->buf_pos++];
+
+ ret = GP_IORead(buf->io, buf->buf, sizeof(buf->buf));
+
+ if (ret <= 0)
+ return EOF;
+
+ buf->buf_pos = 1;
+ buf->buf_end = ret;
+
+ return buf->buf[0];
+}
+
+static void ungetb(struct buf *buf, uint8_t byte)
+{
+ buf->buf[--buf->buf_pos] = byte;
+}
+
+static int fillb(struct buf *buf, void *ptr, size_t size)
+{
+ unsigned int buffered = buf->buf_end - buf->buf_pos;
+
+ if (buffered) {
+ unsigned int to_copy = GP_MIN(buffered, size);
+ memcpy(ptr, buf->buf + buf->buf_pos, to_copy);
+ buf->buf_pos += to_copy;
+ }
+
+ //TODO: refill buffer if request < 128
+ if (size > buffered) {
+ return GP_IOFill(buf->io, (char*)ptr + buffered,
+ size - buffered);
+ }
+
+ return 0;
+}
+
+static int load_header(struct buf *buf, struct pnm_header *header)
{
int h1, h2, c, state = S_START, val = 0, i = 0, err;
- h1 = fgetc(f);
- h2 = fgetc(f);
+ h1 = getb(buf);
+ h2 = getb(buf);
if (h1 == EOF || h2 == EOF) {
GP_DEBUG(1, "Failed to read header");
@@ -180,7 +235,7 @@ static int load_header(FILE *f, struct pnm_header *header)
header->w = 0;
for (;;) {
- c = fgetc(f);
+ c = getb(buf);
if (c == EOF) {
err = EIO;
@@ -231,7 +286,7 @@ static int load_header(FILE *f, struct pnm_header *header)
header->depth = val;
goto out;
}
- ungetc(c, f);
+ ungetb(buf, c);
state = S_START;
break;
}
@@ -252,13 +307,13 @@ err:
/*
* ASCII data parser
*/
-static int get_ascii_int(FILE *f, int *val)
+static int get_ascii_int(struct buf *buf, int *val)
{
int c, in_number = 0;
*val = 0;
for (;;) {
- c = getc_unlocked(f);
+ c = getb(buf);
switch (c) {
case EOF:
@@ -309,7 +364,8 @@ static inline int write_ascii_byte(FILE *f, uint8_t byte)
/*
* The PBM ASCII has the values inverted
*/
-static int load_ascii_g1_inv(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
+static int load_ascii_g1_inv(struct buf *buf, GP_Context *ctx,
+ GP_ProgressCallback *cb)
{
uint32_t x, y;
int val, err;
@@ -317,7 +373,7 @@ static int load_ascii_g1_inv(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
for (y = 0; y < ctx->h; y++) {
for (x = 0; x < ctx->w; x++) {
- if ((err = get_ascii_int(f, &val)))
+ if ((err = get_ascii_int(buf, &val)))
return err;
GP_PutPixel_Raw_1BPP_LE(ctx, x, y, !val);
@@ -336,7 +392,8 @@ static int load_ascii_g1_inv(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
//TODO: This is temporary till blit works with bitendian
#include "core/GP_BitSwap.h"
-static int load_raw_g1_inv(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
+static int load_raw_g1_inv(struct buf *buf, GP_Context *ctx,
+ GP_ProgressCallback *cb)
{
uint32_t x, y;
uint8_t *addr;
@@ -345,7 +402,7 @@ static int load_raw_g1_inv(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
for (y = 0; y < ctx->h; y++) {
for (x = 0; x < ctx->w; x+=8) {
- if ((val = fgetc(f)) == EOF)
+ if ((val = getb(buf)) == EOF)
return EIO;
addr = GP_PIXEL_ADDR(ctx, x, y);
@@ -362,7 +419,8 @@ static int load_raw_g1_inv(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
return 0;
}
-static int load_ascii_g1(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
+static int load_ascii_g1(struct buf *buf, GP_Context *ctx,
+ GP_ProgressCallback *cb)
{
uint32_t x, y;
int val, err;
@@ -370,11 +428,11 @@ static int load_ascii_g1(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
for (y = 0; y < ctx->h; y++) {
for (x = 0; x < ctx->w; x++) {
- if ((err = get_ascii_int(f, &val)))
+ if ((err = get_ascii_int(buf, &val)))
return err;
if (val > 1) {
- GP_WARN("Value too large for 2BPP (%i)", val);
+ GP_WARN("Value too large for 1BPP (%i)", val);
val = 1;
}
@@ -391,7 +449,8 @@ static int load_ascii_g1(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
return 0;
}
-static int load_ascii_g2(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
+static int load_ascii_g2(struct buf *buf, GP_Context *ctx,
+ GP_ProgressCallback *cb)
{
uint32_t x, y;
int val, err;
@@ -399,7 +458,7 @@ static int load_ascii_g2(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
for (y = 0; y < ctx->h; y++) {
for (x = 0; x < ctx->w; x++) {
- if ((err = get_ascii_int(f, &val)))
+ if ((err = get_ascii_int(buf, &val)))
return err;
if (val > 3) {
@@ -420,7 +479,8 @@ static int load_ascii_g2(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
return 0;
}
-static int load_ascii_g4(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
+static int load_ascii_g4(struct buf *buf, GP_Context *ctx,
+ GP_ProgressCallback *cb)
{
uint32_t x, y;
int val, err;
@@ -428,12 +488,12 @@ static int load_ascii_g4(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
for (y = 0; y < ctx->h; y++) {
for (x = 0; x < ctx->w; x++) {
- if ((err = get_ascii_int(f, &val)))
+ if ((err = get_ascii_int(buf, &val)))
return err;
if (val > 15) {
GP_WARN("Value too large for 4BPP (%i)", val);
- val = 3;
+ val = 15;
}
GP_PutPixel_Raw_4BPP_LE(ctx, x, y, val);
@@ -449,7 +509,8 @@ static int load_ascii_g4(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
return 0;
}
-static int load_ascii_g8(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
+static int load_ascii_g8(struct buf *buf, GP_Context *ctx,
+ GP_ProgressCallback *cb)
{
uint32_t x, y;
int val, err;
@@ -457,12 +518,12 @@ static int load_ascii_g8(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
for (y = 0; y < ctx->h; y++) {
for (x = 0; x < ctx->w; x++) {
- if ((err = get_ascii_int(f, &val)))
+ if ((err = get_ascii_int(buf, &val)))
return err;
- if (val > 15) {
- GP_WARN("Value too large for 4BPP (%i)", val);
- val = 3;
+ if (val > 255) {
+ GP_WARN("Value too large for 8BPP (%i)", val);
+ val = 255;
}
GP_PutPixel_Raw_8BPP(ctx, x, y, val);
@@ -478,14 +539,15 @@ static int load_ascii_g8(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
return 0;
}
-static int load_bin_g8(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
+static int load_bin_g8(struct buf *buf, GP_Context *ctx,
+ GP_ProgressCallback *cb)
{
uint32_t y;
for (y = 0; y < ctx->h; y++) {
uint8_t *addr = GP_PIXEL_ADDR(ctx, 0, y);
- if (fread(addr, ctx->w, 1, f) != 1)
+ if (fillb(buf, addr, ctx->w))
return errno;
if (GP_ProgressCallbackReport(cb, y, ctx->h, ctx->w)) {
@@ -498,7 +560,8 @@ static int load_bin_g8(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
return 0;
}
-static int load_ascii_rgb888(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
+static int load_ascii_rgb888(struct buf *buf, GP_Context *ctx,
+ GP_ProgressCallback *cb)
{
uint32_t x, y;
int r, g, b, err;
@@ -506,7 +569,7 @@ static int load_ascii_rgb888(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
for (y = 0; y < ctx->h; y++) {
for (x = 0; x < ctx->w; x++) {
- if ((err = get_ascii_int(f, &r)))
+ if ((err = get_ascii_int(buf, &r)))
return err;
if (r > 255) {
@@ -514,7 +577,7 @@ static int load_ascii_rgb888(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
r = 255;
}
- if ((err = get_ascii_int(f, &g)))
+ if ((err = get_ascii_int(buf, &g)))
return err;
if (g > 255) {
@@ -522,7 +585,7 @@ static int load_ascii_rgb888(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
g = 255;
}
- if ((err = get_ascii_int(f, &b)))
+ if ((err = get_ascii_int(buf, &b)))
return err;
if (b > 255) {
@@ -544,14 +607,15 @@ static int load_ascii_rgb888(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
return 0;
}
-static int load_bin_rgb888(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
+static int load_bin_rgb888(struct buf *buf, GP_Context *ctx,
+ GP_ProgressCallback *cb)
{
uint32_t y, x;
for (y = 0; y < ctx->h; y++) {
uint8_t *addr = GP_PIXEL_ADDR(ctx, 0, y);
- if (fread(addr, ctx->w * 3, 1, f) != 1)
+ if (fillb(buf, addr, ctx->w * 3))
return errno;
for (x = 0; x < ctx->w; x++)
@@ -598,26 +662,7 @@ static int save_ascii(FILE *f, const GP_Context *ctx,
return 0;
}
-static FILE *read_header(const char *src_path, struct pnm_header *header)
-{
- FILE *f;
- int err;
-
- f = fopen(src_path, "r");
-
- if (f == NULL)
- return NULL;
-
- if ((err = load_header(f, header))) {
- fclose(f);
- errno = err;
- return NULL;
- }
-
- return f;
-}
-
-static GP_Context *read_bitmap(FILE *f, struct pnm_header *header, int flag,
+static GP_Context *read_bitmap(struct buf *buf, struct pnm_header *header,
GP_ProgressCallback *callback)
{
GP_Context *ret;
@@ -637,38 +682,53 @@ static GP_Context *read_bitmap(FILE *f, struct pnm_header *header, int flag,
}
if (header->magic == '1')
- err = load_ascii_g1_inv(f, ret, callback);
+ err = load_ascii_g1_inv(buf, ret, callback);
else
- err = load_raw_g1_inv(f, ret, callback);
+ err = load_raw_g1_inv(buf, ret, callback);
if (err)
goto err1;
- if (flag)
- fclose(f);
-
return ret;
err1:
GP_ContextFree(ret);
-
- if (flag)
- fclose(f);
err0:
errno = err;
return NULL;
}
-GP_Context *GP_LoadPBM(const char *src_path, GP_ProgressCallback *callback)
+GP_Context *GP_ReadPBM(GP_IO *io, GP_ProgressCallback *callback)
{
struct pnm_header header;
- FILE *f;
+ DECLARE_BUFFER(buf, io);
+ int err;
- f = read_header(src_path, &header);
+ err = load_header(&buf, &header);
+ if (err) {
+ errno = err;
+ return NULL;
+ }
- if (f == NULL)
+ return read_bitmap(&buf, &header, callback);
+}
+
+GP_Context *GP_LoadPBM(const char *src_path, GP_ProgressCallback *callback)
+{
+ GP_IO *io;
+ GP_Context *res;
+ int err;
+
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
return NULL;
- return read_bitmap(f, &header, 1, callback);
+ res = GP_ReadPBM(io, callback);
+
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
+
+ return res;
}
int GP_SavePBM(const GP_Context *src, const char *dst_path,
@@ -728,44 +788,44 @@ static GP_Pixel depth_to_pixel(int depth)
}
}
-static int load_ascii_graymap(FILE *f, struct pnm_header *header,
+static int load_ascii_graymap(struct buf *buf, struct pnm_header *header,
GP_Context *ret, GP_ProgressCallback *callback)
{
int err = ENOSYS;
switch (header->depth) {
case 1:
- err = load_ascii_g1(f, ret, callback);
+ err = load_ascii_g1(buf, ret, callback);
break;
case 3:
- err = load_ascii_g2(f, ret, callback);
+ err = load_ascii_g2(buf, ret, callback);
break;
case 15:
- err = load_ascii_g4(f, ret, callback);
+ err = load_ascii_g4(buf, ret, callback);
break;
case 255:
- err = load_ascii_g8(f, ret, callback);
+ err = load_ascii_g8(buf, ret, callback);
break;
}
return err;
}
-static int load_bin_graymap(FILE *f, struct pnm_header *header,
+static int load_bin_graymap(struct buf *buf, struct pnm_header *header,
GP_Context *ret, GP_ProgressCallback *callback)
{
int err = ENOSYS;
switch (header->depth) {
case 255:
- err = load_bin_g8(f, ret, callback);
+ err = load_bin_g8(buf, ret, callback);
break;
}
return err;
}
-static GP_Context *read_graymap(FILE *f, struct pnm_header *header, int flag,
+static GP_Context *read_graymap(struct buf *buf, struct pnm_header *header,
GP_ProgressCallback *callback)
{
GP_Context *ret;
@@ -792,38 +852,53 @@ static GP_Context *read_graymap(FILE *f, struct pnm_header *header, int flag,
}
if (header->magic == '5')
- err = load_bin_graymap(f, header, ret, callback);
+ err = load_bin_graymap(buf, header, ret, callback);
else
- err = load_ascii_graymap(f, header, ret, callback);
+ err = load_ascii_graymap(buf, header, ret, callback);
if (err)
goto err1;
- if (flag)
- fclose(f);
-
return ret;
err1:
GP_ContextFree(ret);
-
- if (flag)
- fclose(f);
err0:
errno = err;
return NULL;
}
-GP_Context *GP_LoadPGM(const char *src_path, GP_ProgressCallback *callback)
+GP_Context *GP_ReadPGM(GP_IO *io, GP_ProgressCallback *callback)
{
struct pnm_header header;
- FILE *f;
+ DECLARE_BUFFER(buf, io);
+ int err;
+
+ err = load_header(&buf, &header);
+ if (err) {
+ errno = err;
+ return NULL;
+ }
- f = read_header(src_path, &header);
+ return read_graymap(&buf, &header, callback);
+}
- if (f == NULL)
+GP_Context *GP_LoadPGM(const char *src_path, GP_ProgressCallback *callback)
+{
+ GP_IO *io;
+ GP_Context *res;
+ int err;
+
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
return NULL;
- return read_graymap(f, &header, 1, callback);
+ res = GP_ReadPGM(io, callback);
+
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
+
+ return res;
}
static int pixel_to_depth(GP_Pixel pixel)
@@ -891,11 +966,11 @@ err0:
return 1;
}
-static GP_Context *read_pixmap(FILE *f, struct pnm_header *header, int flag,
- GP_ProgressCallback *callback)
+static GP_Context *read_pixmap(struct buf *buf, struct pnm_header *header,
+ GP_ProgressCallback *callback)
{
GP_Context *ret;
- int err;
+ int err = 0;
if (!is_pixmap(header->magic)) {
GP_DEBUG(1, "Invalid Pixmap magic P%c", header->magic);
@@ -918,40 +993,56 @@ static GP_Context *read_pixmap(FILE *f, struct pnm_header *header, int flag,
switch (header->magic) {
case '3':
- if ((err = load_ascii_rgb888(f, ret, callback)))
- goto err1;
+ err = load_ascii_rgb888(buf, ret, callback);
break;
case '6':
- if ((err = load_bin_rgb888(f, ret, callback)))
- goto err1;
+ err = load_bin_rgb888(buf, ret, callback);
break;
}
- if (flag)
- fclose(f);
+ if (err)
+ goto err1;
return ret;
err1:
GP_ContextFree(ret);
-
- if (flag)
- fclose(f);
err0:
errno = err;
return NULL;
}
-GP_Context *GP_LoadPPM(const char *src_path, GP_ProgressCallback *callback)
+GP_Context *GP_ReadPPM(GP_IO *io, GP_ProgressCallback *callback)
{
struct pnm_header header;
- FILE *f;
+ DECLARE_BUFFER(buf, io);
+ int err;
- f = read_header(src_path, &header);
+ err = load_header(&buf, &header);
+ if (err) {
+ errno = err;
+ return NULL;
+ }
- if (f == NULL)
+ return read_pixmap(&buf, &header, callback);
+}
+
+GP_Context *GP_LoadPPM(const char *src_path, GP_ProgressCallback *callback)
+{
+ GP_IO *io;
+ GP_Context *res;
+ int err;
+
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
return NULL;
- return read_pixmap(f, &header, 1, callback);
+ res = GP_ReadPPM(io, callback);
+
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
+
+ return res;
}
static int write_binary_ppm(FILE *f, GP_Context *src)
@@ -1072,40 +1163,48 @@ err0:
return 1;
}
-GP_Context *GP_LoadPNM(const char *src_path, GP_ProgressCallback *callback)
+GP_Context *GP_ReadPNM(GP_IO *io, GP_ProgressCallback *callback)
{
- FILE *f;
- GP_Context *ret = NULL;
struct pnm_header header;
+ DECLARE_BUFFER(buf, io);
+ GP_Context *ret = NULL;
int err;
- f = fopen(src_path, "r");
-
- if (f == NULL) {
- err = errno;
- GP_DEBUG(1, "Failed to open file '%s': %s",
- src_path, strerror(errno));
- goto err0;
+ err = load_header(&buf, &header);
+ if (err) {
+ errno = err;
+ return NULL;
}
- if ((err = load_header(f, &header)))
- goto err1;
-
if (is_bitmap(header.magic))
- ret = read_bitmap(f, &header, 1, callback);
+ ret = read_bitmap(&buf, &header, callback);
if (is_graymap(header.magic))
- ret = read_graymap(f, &header, 1, callback);
+ ret = read_graymap(&buf, &header, callback);
if (is_pixmap(header.magic))
- ret = read_pixmap(f, &header, 1, callback);
+ ret = read_pixmap(&buf, &header, callback);
return ret;
-err1:
- fclose(f);
-err0:
+}
+
+GP_Context *GP_LoadPNM(const char *src_path, GP_ProgressCallback *callback)
+{
+ GP_IO *io;
+ GP_Context *res;
+ int err;
+
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
+ return NULL;
+
+ res = GP_ReadPNM(io, callback);
+
+ err = errno;
+ GP_IOClose(io);
errno = err;
- return NULL;
+
+ return res;
}
int GP_SavePNM(const GP_Context *src, const char *dst_path,
diff --git a/libs/loaders/GP_PSP.c b/libs/loaders/GP_PSP.c
index f5c6c28..d99ca03 100644
--- a/libs/loaders/GP_PSP.c
+++ b/libs/loaders/GP_PSP.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -42,17 +42,6 @@
#include "GP_JPG.h"
#include "GP_PSP.h"
-#define BUF_TO_8(buf, off) - (buf[off] + (buf[off+1]<<8) + (buf[off+2]<<16) + (buf[off+3]<<24) + - ((uint64_t)buf[off+4]<<32) + ((uint64_t)buf[off+5]<<40) + - ((uint64_t)buf[off+6]<<48) + ((uint64_t)buf[off+7]<<56))
-
-#define BUF_TO_4(buf, off) - (buf[off] + (buf[off+1]<<8) + (buf[off+2]<<16) + (buf[off+3]<<24))
-
-#define BUF_TO_2(buf, off) - (buf[off] + (buf[off+1]<<8))
-
#define PSP_SIGNATURE "Paint Shop Pro Image Filenx1a00000000"
#define PSP_SIGNATURE_LEN 32
@@ -66,49 +55,6 @@ int GP_MatchPSP(const void *buf)
return !memcmp(buf, PSP_SIGNATURE, PSP_SIGNATURE_LEN);
}
-int GP_OpenPSP(const char *src_path, FILE **f)
-{
- int err;
-
- *f = fopen(src_path, "rb");
-
- if (*f == NULL) {
- err = errno;
- GP_DEBUG(1, "Failed to open '%s' : %s",
- src_path, strerror(errno));
- goto err2;
- }
-
- char buf[36];
-
- if (fread(buf, sizeof(buf), 1, *f) < 1) {
- GP_DEBUG(1, "Failed to read file header");
- err = EIO;
- goto err1;
- }
-
- if (memcmp(buf, PSP_SIGNATURE, PSP_SIGNATURE_LEN)) {
- GP_DEBUG(1, "Invalid signature, not a PSP image?");
- err = EINVAL;
- goto err1;
- }
-
- struct psp_version version;
-
- version.major = BUF_TO_2(buf, 32);
- version.minor = BUF_TO_2(buf, 34);
-
- GP_DEBUG(1, "Have PSP image version %u.%u",
- version.major, version.minor);
-
- return 0;
-err1:
- fclose(*f);
-err2:
- errno = err;
- return 1;
-}
-
enum psp_block_id {
PSP_IMAGE_BLOCK,
PSP_CREATOR_BLOCK,
@@ -229,40 +175,46 @@ struct psp_img_attrs {
GP_Context *img;
};
-static int psp_read_general_img_attr_chunk(FILE *f,
+static int psp_read_general_img_attr_chunk(GP_IO *io,
struct psp_img_attrs *attrs)
{
- uint8_t buf[38];
+ int err;
if (attrs->is_loaded) {
GP_WARN("Found Second Image Block");
return EINVAL;
}
- //TODO SHIFT!!!
- if (fread(buf, 4, 1, f) < 1) {
- GP_DEBUG(1, "Failed to read Image block header");
- return EIO;
- }
-
- if (fread(buf, sizeof(buf), 1, f) < 1) {
- GP_DEBUG(1, "Failed to read Image chunk data");
- return EIO;
+ uint16_t general_image_info[] = {
+ GP_IO_I4, /* ??? */
+ GP_IO_L4, /* width */
+ GP_IO_L4, /* height */
+ GP_IO_ARRAY | 8, /* resolution FIXME: double */
+ GP_IO_BYTE, /* resolution metric */
+ GP_IO_L2, /* compression type */
+ GP_IO_L2, /* bit depth */
+ GP_IO_L2, /* plane count */
+ GP_IO_L2, /* color count */
+ GP_IO_BYTE, /* grayscale flag */
+ GP_IO_L4, /* total image size */
+ GP_IO_I2, /* ??? */
+ GP_IO_L4, /* active layer */
+ GP_IO_L2, /* layer count */
+ GP_IO_END
+ };
+
+ if (GP_IOReadF(io, general_image_info, &attrs->w, &attrs->h,
+ &attrs->res, &attrs->res_metric, &attrs->comp_type,
+ &attrs->bit_depth, &attrs->plane_count,
+ &attrs->color_count, &attrs->grayscale_flag,
+ &attrs->total_img_size, &attrs->active_layer,
+ &attrs->layer_count) != 14) {
+ err = errno;
+ GP_DEBUG(1, "Failed to read Image attributes: %s",
+ strerror(errno));
+ return err;
}
- attrs->w = BUF_TO_4(buf, 0);
- attrs->h = BUF_TO_4(buf, 4);
- attrs->res = BUF_TO_8(buf, 8);
- attrs->res_metric = buf[16];
- attrs->comp_type = BUF_TO_2(buf, 17);
- attrs->bit_depth = BUF_TO_2(buf, 19);
- attrs->plane_count = BUF_TO_2(buf, 21);
- attrs->color_count = BUF_TO_2(buf, 23);
- attrs->grayscale_flag = buf[25];
- attrs->total_img_size = BUF_TO_4(buf, 26);
- attrs->active_layer = BUF_TO_4(buf, 32);
- attrs->layer_count = BUF_TO_2(buf, 36);
-
GP_DEBUG(3, "Image w=%u h=%u, compress=%s, bit_depth=%u, grayscale=%u",
attrs->w, attrs->h, psp_comp_type_name(attrs->comp_type),
attrs->bit_depth, attrs->grayscale_flag);
@@ -275,10 +227,10 @@ static int psp_read_general_img_attr_chunk(FILE *f,
return 0;
}
-static int psp_next_block(FILE *f, struct psp_img_attrs *attrs,
+static int psp_next_block(GP_IO *io, struct psp_img_attrs *attrs,
GP_ProgressCallback *callback);
-static int psp_read_layer_start_block(FILE *f, struct psp_img_attrs *attrs,
+static int psp_read_layer_start_block(GP_IO *io, struct psp_img_attrs *attrs,
GP_ProgressCallback *callback)
{
int i;
@@ -292,18 +244,18 @@ static int psp_read_layer_start_block(FILE *f, struct psp_img_attrs *attrs,
attrs->subblock++;
for (i = 0; i < attrs->layer_count; i++)
- psp_next_block(f, attrs, callback);
+ psp_next_block(io, attrs, callback);
attrs->subblock--;
return 0;
}
-static int psp_read_composite_image_block(FILE *f, struct psp_img_attrs *attrs,
+static int psp_read_composite_image_block(GP_IO *io, struct psp_img_attrs *attrs,
GP_ProgressCallback *callback)
{
- uint8_t buf[8];
uint32_t i, composite_image_count;
+ int err;
/* we are allready in subblock -> error */
if (attrs->subblock) {
@@ -311,13 +263,18 @@ static int psp_read_composite_image_block(FILE *f, struct psp_img_attrs *attrs,
return EINVAL;
}
- if (fread(buf, sizeof(buf), 1, f) < 1) {
+ uint16_t composite_image[] = {
+ GP_IO_I4, /* chunk size */
+ GP_IO_L4, /* composit image count */
+ GP_IO_END,
+ };
+
+ if (GP_IOReadF(io, composite_image, &composite_image_count) != 2) {
+ err = errno;
GP_DEBUG(1, "Failed to read Composite Image Bank Info Chunk");
- return EIO;
+ return err;
}
- composite_image_count = BUF_TO_4(buf, 4);
-
//TODO: utilize chunk_size
GP_DEBUG(3, "Composite image count=%u", composite_image_count);
@@ -325,7 +282,7 @@ static int psp_read_composite_image_block(FILE *f, struct psp_img_attrs *attrs,
attrs->subblock++;
for (i = 0; i < composite_image_count; i++)
- psp_next_block(f, attrs, callback);
+ psp_next_block(io, attrs, callback);
attrs->subblock--;
@@ -359,25 +316,33 @@ struct psp_comp_img_attr_info {
uint16_t comp_img_type;
};
-static int psp_read_composite_attributes_block(FILE *f, struct psp_img_attrs *attrs,
+static int psp_read_composite_attributes_block(GP_IO *io, struct psp_img_attrs *attrs,
GP_ProgressCallback *callback)
{
- uint8_t buf[24];
struct psp_comp_img_attr_info info;
+ int err;
- if (fread(buf, sizeof(buf), 1, f) < 1) {
- GP_DEBUG(1, "Failed to read Composite Image Bank Info Chunk");
- return EIO;
+ uint16_t info_chunk[] = {
+ GP_IO_I4, /* chunk size */
+ GP_IO_L4, /* width */
+ GP_IO_L4, /* height */
+ GP_IO_L2, /* bit depth */
+ GP_IO_L2, /* compression type */
+ GP_IO_L2, /* plane count */
+ GP_IO_L4, /* color count */
+ GP_IO_L2, /* composite image type */
+ GP_IO_END
+ };
+
+ if (GP_IOReadF(io, info_chunk, &info.w, &info.h, &info.bit_depth,
+ &info.comp_type, &info.plane_count, &info.color_count,
+ &info.comp_img_type) != 8) {
+ err = errno;
+ GP_DEBUG(1, "Failed to read Composite Image Attrs Info: %s",
+ strerror(err));
+ return err;
}
- info.w = BUF_TO_4(buf, 4);
- info.h = BUF_TO_4(buf, 8);
- info.bit_depth = BUF_TO_2(buf, 12);
- info.comp_type = BUF_TO_2(buf, 14);
- info.plane_count = BUF_TO_2(buf, 16);
- info.color_count = BUF_TO_4(buf, 18);
- info.comp_img_type = BUF_TO_2(buf, 22);
-
GP_DEBUG(4, "Composite Image w=%u h=%u, bit_depth=%u, comp_type=%s, "
"comp_img_type=%s",
info.w, info.h, info.bit_depth, psp_comp_type_name(info.comp_type),
@@ -387,7 +352,7 @@ static int psp_read_composite_attributes_block(FILE *f, struct psp_img_attrs *at
attrs->subblock++;
if (info.comp_img_type == PSP_IMAGE_COMPOSITE)
- psp_next_block(f, attrs, callback);
+ psp_next_block(io, attrs, callback);
attrs->subblock--;
attrs->priv = NULL;
@@ -395,22 +360,23 @@ static int psp_read_composite_attributes_block(FILE *f, struct psp_img_attrs *at
return 0;
}
-static int psp_read_jpeg(FILE *f, struct psp_img_attrs *attrs,
+static int psp_read_jpeg(GP_IO *io, struct psp_img_attrs *attrs,
GP_ProgressCallback *callback)
{
- uint8_t buf[14];
int err;
+ GP_IOSeek(io, 14, GP_IO_SEEK_CUR);
+/*
if (fread(buf, sizeof(buf), 1, f) < 1) {
GP_DEBUG(1, "Failed to read JPEG Information Chunk");
return EIO;
}
-
+*/
//TODO: utilize chunk_size
GP_DEBUG(5, "JPEG Chunk");
- attrs->img = GP_ReadJPG(f, callback);
+ attrs->img = GP_ReadJPG(io, callback);
if (attrs->img == NULL) {
err = errno;
@@ -421,99 +387,123 @@ static int psp_read_jpeg(FILE *f, struct psp_img_attrs *attrs,
return 0;
}
-#define GEN_IMG_HEADER_ID "~BK"
-#define GEN_IMG_HEADER_ID_LEN 4
-
-static int psp_next_block(FILE *f, struct psp_img_attrs *attrs,
+static int psp_next_block(GP_IO *io, struct psp_img_attrs *attrs,
GP_ProgressCallback *callback)
{
- uint8_t buf[10];
uint16_t block_id;
uint32_t block_size;
- long offset;
+ off_t offset;
int err = 0;
- if (fread(buf, sizeof(buf), 1, f) < 1) {
- GP_DEBUG(1, "Failed to read block header");
- return EIO;
- }
+ uint16_t block_header[] = {
+ '~', 'B', 'K', 0x00,
+ GP_IO_L2, /* block id */
+ GP_IO_L4, /* block size */
+ GP_IO_END
+ };
- if (memcmp(buf, GEN_IMG_HEADER_ID, GEN_IMG_HEADER_ID_LEN)) {
- GP_DEBUG(1, "Invalid block header identifier");
- return EINVAL;
+ if (GP_IOReadF(io, block_header, &block_id, &block_size) != 6) {
+ err = errno;
+ GP_DEBUG(1, "Failed to read block header: %s", strerror(errno));
+ return err;
}
- block_id = BUF_TO_2(buf, 4);
- block_size = BUF_TO_4(buf, 6);
-
GP_DEBUG(2 + attrs->subblock, "%s Block size %u",
psp_block_id_name(block_id), block_size);
- offset = ftell(f) + block_size;
+ offset = GP_IOTell(io) + block_size;
switch (block_id) {
case PSP_IMAGE_BLOCK:
- err = psp_read_general_img_attr_chunk(f, attrs);
+ err = psp_read_general_img_attr_chunk(io, attrs);
break;
case PSP_LAYER_START_BLOCK:
- err = psp_read_layer_start_block(f, attrs, callback);
+ err = psp_read_layer_start_block(io, attrs, callback);
break;
case PSP_COMPOSITE_IMAGE_BANK_BLOCK:
- err = psp_read_composite_image_block(f, attrs, callback);
+ err = psp_read_composite_image_block(io, attrs, callback);
break;
case PSP_COMPOSITE_ATTRIBUTES_BLOCK:
- err = psp_read_composite_attributes_block(f, attrs, callback);
+ err = psp_read_composite_attributes_block(io, attrs, callback);
break;
case PSP_JPEG_BLOCK:
- err = psp_read_jpeg(f, attrs, callback);
+ err = psp_read_jpeg(io, attrs, callback);
break;
}
if (err)
return err;
- if (fseek(f, offset, SEEK_SET) == -1) {
+ if (GP_IOSeek(io, offset, GP_IO_SEEK_SET) != offset) {
err = errno;
- GP_DEBUG(1, "Failed to seek to next block");
- return errno;
+ GP_DEBUG(1, "Failed to seek to next block; %s",
+ strerror(errno));
+ return err;
}
return 0;
}
-GP_Context *GP_ReadPSP(FILE *f, GP_ProgressCallback *callback)
+GP_Context *GP_ReadPSP(GP_IO *io, GP_ProgressCallback *callback)
{
int err = 0;
struct psp_img_attrs attrs = {.is_loaded = 0, .subblock = 0,
.priv = NULL, .img = NULL};
+ struct psp_version version;
+
+ uint16_t psp_header[] = {
+ 'P', 'a', 'i', 'n', 't', ' ',
+ 'S', 'h', 'o', 'p', ' ',
+ 'P', 'r', 'o', ' ',
+ 'I', 'm', 'a', 'g', 'e', ' ',
+ 'F', 'i', 'l', 'e', 'n', 0x1a,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ GP_IO_L2, /* version major */
+ GP_IO_L2, /* version minor */
+ GP_IO_END
+ };
+
+ if (GP_IOReadF(io, psp_header, &version.major, &version.minor) != 34) {
+ GP_DEBUG(1, "Failed to read file header");
+ err = EIO;
+ goto err0;
+ }
+
+ GP_DEBUG(1, "Have PSP image version %u.%u",
+ version.major, version.minor);
while (!err) {
- err = psp_next_block(f, &attrs, callback);
+ err = psp_next_block(io, &attrs, callback);
if (err)
- goto err1;
+ goto err0;
- if (attrs.img != NULL) {
- fclose(f);
+ if (attrs.img != NULL)
return attrs.img;
- }
}
- fclose(f);
errno = ENOSYS;
return NULL;
-err1:
- fclose(f);
+err0:
errno = err;
return NULL;
}
GP_Context *GP_LoadPSP(const char *src_path, GP_ProgressCallback *callback)
{
- FILE *f;
+ GP_IO *io;
+ GP_Context *res;
+ int err;
- if (GP_OpenPSP(src_path, &f))
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
return NULL;
- return GP_ReadPSP(f, callback);
+ res = GP_ReadPSP(io, callback);
+
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
+
+ return res;
}
diff --git a/libs/loaders/GP_TIFF.c b/libs/loaders/GP_TIFF.c
index f9d32c8..93e5b42 100644
--- a/libs/loaders/GP_TIFF.c
+++ b/libs/loaders/GP_TIFF.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -58,17 +58,6 @@ int GP_MatchTIFF(const void *buf)
return 0;
}
-int GP_OpenTIFF(const char *src_path, void **t)
-{
- TIFF *tiff = TIFFOpen(src_path, "r");
-
- if (tiff == NULL)
- return 1;
-
- *t = tiff;
- return 0;
-}
-
static const char *compression_name(uint16_t compression)
{
switch (compression) {
@@ -446,17 +435,70 @@ static int tiff_read(TIFF *tiff, GP_Context *res, struct tiff_header *header,
return 0;
}
-GP_Context *GP_ReadTIFF(void *t, GP_ProgressCallback *callback)
+static tmsize_t tiff_io_read(thandle_t io, void *buf, tmsize_t size)
+{
+ return GP_IORead(io, buf, size);
+}
+
+static tmsize_t tiff_io_write(thandle_t io, void *buf, tmsize_t size)
{
+ (void) io;
+ (void) buf;
+ GP_WARN("stub called");
+ return size;
+}
+
+static toff_t tiff_io_seek(thandle_t io, toff_t offset, int whence)
+{
+ return GP_IOSeek(io, offset, whence);
+}
+
+static int tiff_io_close(thandle_t GP_UNUSED(io))
+{
+ return 0;
+}
+
+static toff_t tiff_io_size(thandle_t io)
+{
+ return GP_IOSize(io);
+}
+
+/*
+static int tiff_io_map(thandle_t io, void **base, toff_t *size)
+{
+ GP_WARN("stub called");
+ return 0;
+}
+
+static void tiff_io_unmap(thandle_t io, void *base, toff_t size)
+{
+ GP_WARN("stub called");
+ return 0;
+}
+*/
+
+GP_Context *GP_ReadTIFF(GP_IO *io, GP_ProgressCallback *callback)
+{
+ TIFF *tiff;
struct tiff_header header;
- GP_Context *res = NULL;
+ GP_Context *res;
GP_PixelType pixel_type;
int err;
- if ((err = read_header(t, &header)))
+ tiff = TIFFClientOpen("GFXprim IO", "r", io, tiff_io_read,
+ tiff_io_write, tiff_io_seek, tiff_io_close,
+ tiff_io_size, NULL, NULL);
+
+ if (!tiff) {
+ GP_DEBUG(1, "TIFFClientOpen failed");
+ err = EIO;
+ goto err0;
+ }
+
+ if ((err = read_header(tiff, &header)))
goto err1;
- pixel_type = match_pixel_type(t, &header);
+ pixel_type = match_pixel_type(tiff, &header);
if (pixel_type == GP_PIXEL_UNKNOWN) {
err = ENOSYS;
@@ -473,33 +515,42 @@ GP_Context *GP_ReadTIFF(void *t, GP_ProgressCallback *callback)
switch (header.photometric) {
case PHOTOMETRIC_PALETTE:
- err = tiff_read_palette(t, res, &header, callback);
+ err = tiff_read_palette(tiff, res, &header, callback);
break;
default:
- err = tiff_read(t, res, &header, callback);
+ err = tiff_read(tiff, res, &header, callback);
}
if (err)
- goto err1;
+ goto err2;
+
+ TIFFClose(tiff);
return res;
-err1:
+err2:
GP_ContextFree(res);
+err1:
+ TIFFClose(tiff);
+err0:
errno = err;
return NULL;
}
GP_Context *GP_LoadTIFF(const char *src_path, GP_ProgressCallback *callback)
{
- void *t;
+ GP_IO *io;
GP_Context *res;
+ int err;
- if (GP_OpenTIFF(src_path, &t))
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
return NULL;
- res = GP_ReadTIFF(t, callback);
+ res = GP_ReadTIFF(io, callback);
- TIFFClose(t);
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
return res;
}
diff --git a/libs/loaders/GP_ZIP.c b/libs/loaders/GP_ZIP.c
index c64214e..d6cbdd1 100644
--- a/libs/loaders/GP_ZIP.c
+++ b/libs/loaders/GP_ZIP.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -57,7 +57,7 @@ struct zip_chunks_table {
};
struct zip_priv {
- FILE *f;
+ GP_IO *io;
/* Current position in zip continer counted in images we found */
unsigned int cur_pos;
@@ -131,14 +131,14 @@ static const char *compress_method_name(enum compress_method comp)
return compress_method_names[comp];
}
-static int seek_bytes(FILE *f, uint32_t bytes)
+static int seek_bytes(GP_IO *io, uint32_t bytes)
{
if (bytes == 0)
return 0;
- GP_DEBUG(4, "Moving forward by %"PRIu32"bytes", bytes);
+ GP_DEBUG(4, "Moving forward by %"PRIu32" bytes", bytes);
- if (fseek(f, bytes, SEEK_CUR)) {
+ if (GP_IOSeek(io, bytes, GP_IO_SEEK_CUR) == (off_t)-1) {
int err = errno;
GP_DEBUG(1, "Failed to seek: %s", strerror(errno));
return err;
@@ -153,21 +153,21 @@ struct deflate_inbuf {
struct zip_local_header *zip_header;
uint32_t to_read;
unsigned char buf[CHUNK];
- FILE *f;
+ GP_IO *io;
};
struct deflate_outbuf {
uint32_t crc;
uint32_t size;
- FILE *f;
+ uint8_t *buf;
};
static unsigned deflate_in(void *in_desc, unsigned char **buf)
{
struct deflate_inbuf *in = in_desc;
- uint32_t chunk = in->to_read >= CHUNK ? CHUNK : in->to_read;
+ int chunk = in->to_read >= CHUNK ? CHUNK : in->to_read;
- if (fread(in->buf, chunk, 1, in->f) != 1)
+ if (GP_IORead(in->io, in->buf, chunk) != chunk)
return 0;
*buf = in->buf;
@@ -183,33 +183,25 @@ static int deflate_out(void *out_desc, unsigned char *buf, unsigned len)
out->crc = crc32(out->crc, buf, len);
out->size += len;
- if (fwrite(buf, len, 1, out->f) != 1) {
- GP_DEBUG(1, "Failed to write temp file");
- return 1;
- }
+ memcpy(out->buf + out->size, buf, len);
+ out->size += len;
return 0;
}
-static int read_deflate(FILE *f, struct zip_local_header *header, FILE **res_f)
+static int read_deflate(GP_IO *io, struct zip_local_header *header, GP_IO **rio)
{
uint8_t *window;
int err = 0, ret;
- FILE *tf;
-
- tf = tmpfile();
-
- if (!tf) {
- err = errno;
- GP_DEBUG(1, "Failed to create temp file");
- return err;
- }
+ uint8_t *buf;
window = malloc(32 * 1024);
+ //TODO: Unsafe
+ buf = malloc(header->uncomp_size);
- if (!window) {
+ if (!window || !buf) {
err = ENOMEM;
- goto err0;
+ goto err1;
}
z_stream strm = {
@@ -229,12 +221,12 @@ static int read_deflate(FILE *f, struct zip_local_header *header, FILE **res_f)
struct deflate_outbuf outbuf = {
.crc = crc32(0, NULL, 0),
.size = 0,
- .f = tf,
+ .buf = buf,
};
struct deflate_inbuf inbuf = {
.zip_header = header,
- .f = f,
+ .io = io,
.to_read = header->comp_size,
};
@@ -261,32 +253,35 @@ static int read_deflate(FILE *f, struct zip_local_header *header, FILE **res_f)
inflateBackEnd(&strm);
free(window);
- rewind(tf);
- *res_f = tf;
+ //TODO: Failure
+ *rio = GP_IOMem(outbuf.buf, outbuf.size, free);
return 0;
err2:
inflateBackEnd(&strm);
err1:
free(window);
-err0:
- fclose(tf);
+ free(buf);
return err;
}
-static int zip_load_header(FILE *f, struct zip_local_header *header)
+static int zip_load_header(GP_IO *io, struct zip_local_header *header)
{
- int ret, ch;
+ int ret;
+ uint8_t byte;
- ret = GP_FRead(f, "0x50 0x4b");
+ uint16_t zip_header[] = {
+ 'P',
+ 'K',
+ GP_IO_BYTE,
+ GP_IO_END
+ };
- if (ret != 2) {
+ if (GP_IOReadF(io, zip_header, &byte) != 3) {
GP_DEBUG(1, "Failed to read header");
return EIO;
}
- ch = fgetc(f);
-
- switch (ch) {
+ switch (byte) {
/* Central directory -> end of archive */
case 0x01:
GP_DEBUG(1, "Reached end of the archive");
@@ -296,11 +291,25 @@ static int zip_load_header(FILE *f, struct zip_local_header *header)
case 0x03:
break;
default:
- GP_DEBUG(1, "Unexpected header PK%x", ch);
+ GP_DEBUG(1, "Unexpected header PK%x", byte);
return EIO;
}
- ret = GP_FRead(f, "0x04 L2 L2 L2 I4 L4 L4 L4 L2 L2",
+ uint16_t zip_local_header[] = {
+ 0x04,
+ GP_IO_L2, /* version */
+ GP_IO_L2, /* bit flags */
+ GP_IO_L2, /* compression type */
+ GP_IO_IGN | 4,
+ GP_IO_L4, /* CRC */
+ GP_IO_L4, /* compressed size */
+ GP_IO_L4, /* uncompressed size */
+ GP_IO_L2, /* filename length */
+ GP_IO_L2, /* extra fields lenght */
+ GP_IO_END
+ };
+
+ ret = GP_IOReadF(io, zip_local_header,
&header->ver, &header->bit_flags, &header->comp_type,
&header->crc, &header->comp_size, &header->uncomp_size,
&header->fname_len, &header->extf_len);
@@ -313,14 +322,15 @@ static int zip_load_header(FILE *f, struct zip_local_header *header)
return 0;
}
-static GP_Context *zip_next_file(FILE *f, GP_ProgressCallback *callback)
+static GP_Context *zip_next_file(struct zip_priv *priv,
+ GP_ProgressCallback *callback)
{
struct zip_local_header header = {.file_name = NULL};
int err = 0;
GP_Context *ret = NULL;
- FILE *fres;
+ GP_IO *io;
- if ((err = zip_load_header(f, &header)))
+ if ((err = zip_load_header(priv->io, &header)))
goto out;
GP_DEBUG(1, "Have ZIP local header version %u.%u compression %s",
@@ -347,7 +357,7 @@ static GP_Context *zip_next_file(FILE *f, GP_ProgressCallback *callback)
header.file_name[header.fname_len] = '0';
- if (fread(header.file_name, header.fname_len, 1, f) != 1) {
+ if (GP_IORead(priv->io, header.file_name, header.fname_len) != header.fname_len) {
GP_DEBUG(1, "Failed to read filename");
err = EIO;
goto out;
@@ -359,41 +369,43 @@ static GP_Context *zip_next_file(FILE *f, GP_ProgressCallback *callback)
header.uncomp_size);
}
- seek_bytes(f, header.extf_len);
+ seek_bytes(priv->io, header.extf_len);
switch (header.comp_type) {
case COMPRESS_STORED:
/* skip directories */
- if (header.uncomp_size == 0)
+ if (header.uncomp_size == 0) {
+ GP_DEBUG(2, "Skipping directory");
goto out;
+ }
- off_t cur_off = ftell(f);
+ GP_IOMark(priv->io, GP_IO_MARK);
- ret = GP_ReadJPG(f, callback);
+ ret = GP_ReadJPG(priv->io, callback);
if (!ret) {
- fseek(f, cur_off, SEEK_SET);
- ret = GP_ReadPNG(f, callback);
+ GP_IOMark(priv->io, GP_IO_REWIND);
+ ret = GP_ReadPNG(priv->io, callback);
}
- fseek(f, cur_off + header.comp_size, SEEK_SET);
+ GP_IOSeek(priv->io, priv->io->mark + header.comp_size, GP_IO_SEEK_SET);
goto out;
break;
case COMPRESS_DEFLATE:
- if (read_deflate(f, &header, &fres)) {
+ if (read_deflate(priv->io, &header, &io)) {
err = errno;
goto out;
}
- ret = GP_ReadJPG(fres, callback);
+ ret = GP_ReadJPG(io, callback);
if (!ret) {
- rewind(fres);
- ret = GP_ReadPNG(fres, callback);
+ GP_IORewind(io);
+ ret = GP_ReadPNG(io, callback);
}
- fclose(fres);
+ GP_IOClose(io);
goto out;
break;
default:
@@ -476,8 +488,8 @@ static GP_Context *zip_load_next(GP_Container *self,
GP_DEBUG(1, "Trying to load next image from ZIP container");
do {
- offset = ftell(priv->f);
- ret = zip_next_file(priv->f, callback);
+ offset = GP_IOTell(priv->io);
+ ret = zip_next_file(priv, callback);
} while (ret == NULL && errno == 0);
if (!ret)
@@ -524,25 +536,25 @@ static void seek_cur_pos(struct zip_priv *priv)
GP_DEBUG(2, "Setting current position to %u (%li)",
priv->cur_pos, priv->cur_table->offsets[cur_pos]);
- fseek(priv->f, priv->cur_table->offsets[cur_pos], SEEK_SET);
+ GP_IOSeek(priv->io, priv->cur_table->offsets[cur_pos], GP_IO_SEEK_SET);
}
static int load_next_offset(struct zip_priv *priv)
{
struct zip_local_header header = {.file_name = NULL};
int ret;
- long offset = ftell(priv->f);
+ long offset = GP_IOTell(priv->io);
- if ((ret = zip_load_header(priv->f, &header)))
+ if ((ret = zip_load_header(priv->io, &header)))
return ret;
//TODO: Match image extension and signature
record_offset(priv, offset);
/* Seek to the next local header */
- seek_bytes(priv->f, (uint32_t)header.fname_len +
+ seek_bytes(priv->io, (uint32_t)header.fname_len +
(uint32_t)header.extf_len);
- seek_bytes(priv->f, header.comp_size);
+ seek_bytes(priv->io, header.comp_size);
return 0;
}
@@ -641,39 +653,54 @@ static void zip_close(GP_Container *self)
/* Free allocated offset tables */
for (i = priv->table.next; i != NULL; j = i, i = i->next, free(j));
- fclose(priv->f);
+ GP_IOClose(priv->io);
free(self);
}
-static int open_zip(const char *path, FILE **file)
+static GP_IO *open_zip(const char *path)
{
- FILE *f;
+ GP_IO *io;
int err = 0;
- f = fopen(path, "rb");
+ io = GP_IOFile(path, GP_IO_RDONLY);
- if (f == NULL) {
+ if (!io) {
err = errno;
GP_DEBUG(1, "Failed to open '%s': %s", path, strerror(errno));
- if (!err)
- err = EIO;
- return err;
+ goto err0;
}
/* Check zip local file header and seek back */
- if (GP_FRead(f, "0x50 0x4b 0x03 0x04") != 4) {
+ if (GP_IOMark(io, GP_IO_MARK)) {
+ err = errno;
+ goto err1;
+ }
+
+ static uint16_t zip_header[] = {
+ 'P',
+ 'K',
+ 0x03,
+ 0x04,
+ GP_IO_END
+ };
+
+ if (GP_IOReadF(io, zip_header) != 4) {
GP_DEBUG(1, "Invalid zip header");
err = EINVAL;
- goto err0;
+ goto err1;
}
- rewind(f);
+ if (GP_IOMark(io, GP_IO_REWIND)) {
+ err = errno;
+ goto err1;
+ }
- *file = f;
- return 0;
+ return io;
+err1:
+ GP_IOClose(io);
err0:
- fclose(f);
- return err;
+ errno = err;
+ return NULL;
}
static const struct GP_ContainerOps zip_ops = {
@@ -688,13 +715,13 @@ GP_Container *GP_OpenZip(const char *path)
{
struct zip_priv *priv;
GP_Container *ret;
- FILE *f;
+ GP_IO *io;
int err;
- if ((err = open_zip(path, &f))) {
- errno = err;
+ io = open_zip(path);
+
+ if (!io)
return NULL;
- }
ret = malloc(sizeof(GP_Container) + sizeof(struct zip_priv));
@@ -711,7 +738,7 @@ GP_Container *GP_OpenZip(const char *path)
priv = GP_CONTAINER_PRIV(ret);
- priv->f = f;
+ priv->io = io;
priv->table.next = NULL;
priv->table.prev = NULL;
@@ -730,16 +757,15 @@ GP_Container *GP_OpenZip(const char *path)
return ret;
err0:
- fclose(f);
+ GP_IOClose(io);
errno = err;
return NULL;
}
#else
-GP_Container *GP_OpenZip(const char *path)
+GP_Container *GP_OpenZip(const char GP_UNUSED(*path))
{
- (void) path;
GP_FATAL("zlib support not compiled in");
errno = ENOSYS;
return NULL;
diff --git a/tests/loaders/IO.c b/tests/loaders/IO.c
new file mode 100644
index 0000000..32cfa2a
--- /dev/null
+++ b/tests/loaders/IO.c
@@ -0,0 +1,274 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+
+#include <core/GP_Common.h>
+#include <loaders/GP_IO.h>
+
+#include "tst_test.h"
+
+/*
+ * Expects IO buffer filled with monotonically increasing bytes, i.e.
+ * 0x00 0x01 0x02 ...
+ */
+static int do_test(GP_IO *io)
+{
+ int ret;
+ uint8_t buf[10];
+ unsigned int i;
+
+ ret = GP_IORead(io, buf, 10);
+
+ if (ret != 10) {
+ tst_msg("First IO read failed");
+ return TST_FAILED;
+ }
+
+ for (i = 0; i < 10; i++) {
+ if (i != buf[i]) {
+ tst_msg("Read wrong data at %u", i);
+ return TST_FAILED;
+ }
+ }
+
+ ret = GP_IOTell(io);
+
+ if (ret != 10) {
+ tst_msg("Have wrong offset %u, after read 10", ret);
+ return TST_FAILED;
+ }
+
+
+ ret = GP_IORead(io, buf, 10);
+
+ if (ret != 10) {
+ tst_msg("Second IO read failed");
+ return TST_FAILED;
+ }
+
+ for (i = 0; i < 10; i++) {
+ if (i + 10 != buf[i]) {
+ tst_msg("Read wrong data at %u", i + 10);
+ return TST_FAILED;
+ }
+ }
+
+ if (GP_IORewind(io)) {
+ tst_msg("Failed to rewind to start");
+ return TST_FAILED;
+ }
+
+ ret = GP_IOTell(io);
+
+ if (ret != 0) {
+ tst_msg("Have wrong offset %u, after rewind", ret);
+ return TST_FAILED;
+ }
+
+ uint16_t header[] = {
+ 0x00,
+ 0x01,
+ GP_IO_BYTE,
+ GP_IO_IGN | 7,
+ GP_IO_L2,
+ GP_IO_END
+ };
+
+ uint8_t byte;
+ uint16_t val;
+
+ if (GP_IOReadF(io, header, &byte, &val) != 5) {
+ tst_msg("Failed to ReadF from Memory IO");
+ return TST_FAILED;
+ }
+
+ if (byte != 2) {
+ tst_msg("Read wrong value byte = %u (expected 2)", byte);
+ return TST_FAILED;
+ }
+
+ if (val != 0x0b0a) {
+ tst_msg("Read wrong value = %04x (expected 0x0b0a)", val);
+ return TST_FAILED;
+ }
+
+ return TST_SUCCESS;
+}
+
+static int test_IOMem(void)
+{
+ uint8_t buffer[128];
+ unsigned int i;
+ GP_IO *io;
+ int ret;
+
+ for (i = 0; i < sizeof(buffer); i++)
+ buffer[i] = i;
+
+ io = GP_IOMem(buffer, sizeof(buffer), NULL);
+
+ if (!io) {
+ tst_msg("Failed to initialize memory IO");
+ return TST_FAILED;
+ }
+
+ ret = do_test(io);
+ if (ret)
+ return ret;
+
+ if (GP_IOClose(io)) {
+ tst_msg("Failed to close memory IO");
+ return TST_FAILED;
+ }
+
+ return TST_SUCCESS;
+}
+
+#define TFILE "test.io"
+
+static int test_IOFile(void)
+{
+ uint8_t buffer[128];
+ unsigned int i;
+ int ret;
+ GP_IO *io;
+
+ for (i = 0; i < sizeof(buffer); i++)
+ buffer[i] = i;
+
+ io = GP_IOFile(TFILE, GP_IO_WRONLY);
+
+ if (!io) {
+ tst_msg("Failed to open file IO for writing: %s",
+ strerror(errno));
+ return TST_FAILED;
+ }
+
+ ret = GP_IOWrite(io, buffer, sizeof(buffer));
+
+ if (ret != sizeof(buffer)) {
+ tst_msg("Failed to write: %s", strerror(errno));
+ return TST_FAILED;
+ }
+
+ if (GP_IOClose(io)) {
+ tst_msg("Failed to close file IO: %s", strerror(errno));
+ return TST_FAILED;
+ }
+
+ io = GP_IOFile(TFILE, GP_IO_RDONLY);
+
+ if (!io) {
+ tst_msg("Failed to open file IO for reading: %s",
+ strerror(errno));
+ return TST_FAILED;
+ }
+
+ ret = do_test(io);
+ if (ret)
+ return ret;
+
+ if (GP_IOClose(io)) {
+ tst_msg("Failed to close file IO: %s", strerror(errno));
+ return TST_FAILED;
+ }
+
+ return TST_SUCCESS;
+}
+
+static ssize_t test_IOFill_read(GP_IO GP_UNUSED(*io), void *buf, size_t size)
+{
+ ssize_t ret = GP_MIN(7u, size);
+
+ memset(buf, 'a', ret);
+
+ return ret;
+}
+
+static int try_IOFill_and_check(GP_IO *io, unsigned int size)
+{
+ uint8_t buf[125];
+ unsigned int i, fail = 0;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (GP_IOFill(io, buf, size)) {
+ tst_msg("Failed to fill buffer size=%u: %s",
+ size, strerror(errno));
+ return TST_FAILED;
+ }
+
+ for (i = 0; i < size; i++) {
+ if (buf[i] != 'a') {
+ tst_msg("Wrong data in buffer at %u", i);
+ fail++;
+ }
+ }
+
+ for (i = size; i < sizeof(buf); i++) {
+ if (buf[i] != 0) {
+ tst_msg("Wrong data in buffer at %u", i);
+ fail++;
+ }
+ }
+
+ if (fail)
+ return TST_FAILED;
+
+ return TST_SUCCESS;
+}
+
+static int test_IOFill(void)
+{
+ GP_IO io = {.Read = test_IOFill_read};
+ int ret = 0;
+
+ ret += try_IOFill_and_check(&io, 7);
+ ret += try_IOFill_and_check(&io, 10);
+ ret += try_IOFill_and_check(&io, 43);
+ ret += try_IOFill_and_check(&io, 69);
+
+ if (ret)
+ return TST_FAILED;
+
+ return TST_SUCCESS;
+}
+
+const struct tst_suite tst_suite = {
+ .suite_name = "IO",
+ .tests = {
+ {.name = "IOMem",
+ .tst_fn = test_IOMem,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "IOFile",
+ .tst_fn = test_IOFile,
+ .flags = TST_CHECK_MALLOC | TST_TMPDIR},
+
+ {.name = "IOFill",
+ .tst_fn = test_IOFill},
+
+ {.name = NULL},
+ }
+};
diff --git a/tests/loaders/Makefile b/tests/loaders/Makefile
index a5a14cf..6678352 100644
--- a/tests/loaders/Makefile
+++ b/tests/loaders/Makefile
@@ -1,10 +1,10 @@
TOPDIR=../..
include $(TOPDIR)/pre.mk
-CSOURCES=loaders_suite.c PNG.c PBM.c PGM.c PPM.c ZIP.c GIF.c
+CSOURCES=loaders_suite.c PNG.c PBM.c PGM.c PPM.c ZIP.c GIF.c IO.c
GENSOURCES=SaveLoad.gen.c SaveAbort.gen.c
-APPS=loaders_suite PNG PBM PGM PPM SaveLoad.gen SaveAbort.gen ZIP GIF
+APPS=loaders_suite PNG PBM PGM PPM SaveLoad.gen SaveAbort.gen ZIP GIF IO
include ../tests.mk
diff --git a/tests/loaders/data/gif/valid/100x100-white.gif b/tests/loaders/data/gif/valid/100x100-white.gif
new file mode 100644
index 0000000..11f0f8f
Binary files /dev/null and b/tests/loaders/data/gif/valid/100x100-white.gif differ
diff --git a/tests/loaders/test_list.txt b/tests/loaders/test_list.txt
index 4ff3077..add0cb3 100644
--- a/tests/loaders/test_list.txt
+++ b/tests/loaders/test_list.txt
@@ -6,5 +6,6 @@ PGM
PPM
ZIP
GIF
+IO
SaveLoad.gen
SaveAbort.gen
-----------------------------------------------------------------------
Summary of changes:
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via 10a52540db85b4635b27062dc42e5be14f760088 (commit)
via 342537c6df7ca58ca4ac35d0b6f1dae16ef6746a (commit)
via f36c5f6d8df50ad268711cc97c9bc369672b7fe8 (commit)
from 40750bfe2c6ba222376f458bb80e8e48ecf93e52 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/10a52540db85b4635b27062dc42e5be14f76…
commit 10a52540db85b4635b27062dc42e5be14f760088
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sat Jan 4 00:55:28 2014 +0100
loaders: Add I/O abstraction and convert loaders.
This commit adds and abstract I/O interface and converts all image
loaders to use it. This is a big step towards better faster and nicer
containers (i.e. tar, tar.bz2, tar, etc...). It also allows you to read
images from memory or whatever else for what by implementing simple
read() and seek() wrappers.
It also updates loaders documentation, adds a few testcases and example
for loading images from a memory buffer.
BEWARE: The work is not finalized and only basically tested. The ZIP
loader is a bit broken (seeking does not work correctly).
(More tests and fixes will come soon)
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/build/syms/Loaders_symbols.txt b/build/syms/Loaders_symbols.txt
index e424e98..d2121fe 100644
--- a/build/syms/Loaders_symbols.txt
+++ b/build/syms/Loaders_symbols.txt
@@ -2,7 +2,6 @@ GP_FWrite
GP_FRead
GP_MatchJPG
-GP_OpenJPG
GP_ReadJPG
GP_LoadJPG
GP_SaveJPG
@@ -10,7 +9,6 @@ GP_ReadJPGMetaData
GP_LoadJPGMetaData
GP_MatchPNG
-GP_OpenPNG
GP_ReadPNG
GP_LoadPNG
GP_ReadPNGMetaData
@@ -18,45 +16,44 @@ GP_LoadPNGMetaData
GP_SavePNG
GP_MatchBMP
-GP_OpenBMP
GP_LoadBMP
GP_ReadBMP
GP_SaveBMP
GP_MatchPSP
-GP_OpenPSP
GP_ReadPSP
GP_LoadPSP
GP_MatchGIF
GP_LoadGIF
GP_ReadGIF
-GP_OpenGIF
GP_MatchTIFF
-GP_OpenTIFF
GP_ReadTIFF
GP_LoadTIFF
GP_SaveTIFF
-GP_SavePBM
+GP_ReadPBM
GP_LoadPBM
+GP_SavePBM
GP_MatchPBM
-GP_SavePGM
+GP_ReadPGM
GP_LoadPGM
+GP_SavePGM
GP_MatchPGM
-GP_SavePPM
+GP_ReadPPM
GP_LoadPPM
+GP_SavePPM
GP_MatchPPM
+GP_ReadPNM
GP_LoadPNM
GP_SavePNM
GP_MatchPNM
GP_ReadJP2
-GP_OpenJP2
GP_LoadJP2
GP_MatchJP2
@@ -94,3 +91,10 @@ GP_OpenZip
GP_LineConvertible
GP_LineConvertGet
+
+GP_IOFile
+GP_IOMem
+GP_IOMark
+GP_IOSize
+GP_IOFill
+GP_IOReadF
diff --git a/demos/c_simple/Makefile b/demos/c_simple/Makefile
index 2d91834..68fa14a 100644
--- a/demos/c_simple/Makefile
+++ b/demos/c_simple/Makefile
@@ -19,7 +19,7 @@ APPS=backend_example loaders_example loaders filters_symmetry gfx_koch input_example fileview linetest randomshapetest fonttest loaders_register blittest textaligntest sin_AA x11_windows debug_handler gaussian_noise byte_utils version pretty_print timers- zip_container backend_timers_example
+ zip_container backend_timers_example memory_io
ifeq ($(HAVE_LIBSDL),yes)
APPS+=SDL_glue
@@ -57,6 +57,7 @@ blittest: LDLIBS+=$(LDLIBS_BACKENDS) $(LDLIBS_LOADERS)
sin_AA: LDLIBS+=$(LDLIBS_BACKENDS)
x11_windows: LDLIBS+=$(LDLIBS_BACKENDS)
zip_container: LDLIBS+=$(LDLIBS_LOADERS) $(LDLIBS_BACKENDS)
+memory_io: LDLIBS+=$(LDLIBS_BACKENDS) $(LDLIBS_LOADERS)
include $(TOPDIR)/app.mk
include $(TOPDIR)/post.mk
diff --git a/demos/c_simple/memory_io.c b/demos/c_simple/memory_io.c
new file mode 100644
index 0000000..873b27c
--- /dev/null
+++ b/demos/c_simple/memory_io.c
@@ -0,0 +1,118 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+ /*
+
+ Simple memory IO example.
+
+ */
+
+#include <stdio.h>
+#include <GP.h>
+
+/*
+ * Binary PGM stored in an array
+ */
+static char pgm[] = {
+ /* header */
+ 'P', '5', 'n',
+ '1', '0', ' ', '1', '0', 'n',
+ '2', '5', '5', 'n',
+ /* data */
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+};
+
+#define WIN_W 100
+#define WIN_H 100
+
+int main(void)
+{
+ GP_Backend *b;
+ GP_Context *img;
+ GP_IO *io;
+
+ io = GP_IOMem(pgm, sizeof(pgm), NULL);
+
+ if (!io) {
+ fprintf(stderr, "Failed to initialize IOn");
+ return 1;
+ }
+
+ img = GP_ReadPGM(io, NULL);
+ GP_IOClose(io);
+
+ if (!img) {
+ fprintf(stderr, "Failed to load imagen");
+ return 1;
+ }
+
+ b = GP_BackendX11Init(NULL, 0, 0, WIN_W, WIN_H, "IO Example", 0);
+
+ if (!b) {
+ fprintf(stderr, "Failed to initialize backendn");
+ return 1;
+ }
+
+ GP_Fill(b->context, 0);
+ GP_Blit_Clipped(img, 0, 0, img->w, img->h, b->context,
+ (WIN_W - img->w)/2, (WIN_H - img->h)/2);
+ GP_BackendFlip(b);
+
+ for (;;) {
+ GP_Event ev;
+
+ GP_BackendWaitEvent(b, &ev);
+
+ switch (ev.type) {
+ case GP_EV_KEY:
+ switch (ev.val.val) {
+ case GP_KEY_ESC:
+ case GP_KEY_Q:
+ GP_BackendExit(b);
+ return 0;
+ break;
+ }
+ break;
+ case GP_EV_SYS:
+ switch (ev.code) {
+ case GP_EV_SYS_RESIZE:
+ case GP_EV_SYS_QUIT:
+ GP_BackendExit(b);
+ return 0;
+ break;
+ }
+ break;
+ }
+ }
+
+ GP_BackendExit(b);
+ return 0;
+}
diff --git a/doc/Makefile b/doc/Makefile
index 05ae191..ac8868c 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -5,7 +5,7 @@ SOURCES=index.html about.txt context.txt loaders.txt filters.txt get_put_pixel.txt blits.txt progress_callback.txt text.txt event_queue.txt compilation.txt filters_resize.txt filters_dithering.txt filters_python.txt spiv.txt core_common.txt - convert.txt news_1_0_0-rc1.txt
+ convert.txt news_1_0_0-rc1.txt loaders_io.txt
SOURCES+=core_python.txt gfx_python.txt loaders_python.txt backends_python.txt
diff --git a/doc/example_memory_io.txt b/doc/example_memory_io.txt
new file mode 100644
index 0000000..1488bba
--- /dev/null
+++ b/doc/example_memory_io.txt
@@ -0,0 +1,9 @@
+Memory IO with Loaders
+----------------------
+
+This example shows how to read an image from a memory buffer.
+
+[source,c]
+------------------------------------------------------------------
+include::../demos/c_simple/memory_io.c[]
+------------------------------------------------------------------
diff --git a/doc/loaders.txt b/doc/loaders.txt
index b42c47e..5ac5743 100644
--- a/doc/loaders.txt
+++ b/doc/loaders.txt
@@ -3,22 +3,25 @@ Context loaders
This part of GFXprim library aims to create API to load and save images
from/to common image file formats.
-Currently we support JPEG, PNG, BMP, TIFF and PNM images for loading and
-saving and GIF, JPEG2000 and PSP for loading.
+Currently we support 'JPEG', 'PNG', 'BMP', 'TIFF' and 'PNM' images for loading
+and saving and 'GIF', 'JPEG2000' and 'PSP' for loading.
Have a look at the link:about.html#Loaders[supported formats].
Image Loaders and Savers
~~~~~~~~~~~~~~~~~~~~~~~~
-All loading functions returns a pointer to allocated and loaded image or upon
-a failure 'NULL'.
+All loading functions exists in at least two flavors. One that works with a
+path to a file and one that reads from an link:loaders_io.html[IO stream].
+
+All loading functions returns a pointer to newly allocated and loaded image
+or upon a failure 'NULL' and 'errno' is set.
All saving functions returns zero on success and non-zero on failure. If
image saving is aborted by a callback, the opened file is closed and removed
-from a filesystem before the call returns.
+from a file-system before the call returns.
-The signature matching functions takes a 32 bytes long buffer and looks for a
+The signature matching functions takes a 32 bytes long buffer and looks for a
valid image signature. If signature is found non-zero is returned.
In case of a failure 'errno' is set, possible 'errno' values are:
@@ -36,7 +39,6 @@ In case of a failure 'errno' is set, possible 'errno' values are:
You can get more information about the error condition by turning on GFXprim
link:environment_variables.html#GP_DEBUG[debug messages].
-
[[Load_Image]]
[source,c]
-------------------------------------------------------------------------------
@@ -50,7 +52,7 @@ GP_Context *GP_LoadImage(const char *src_path, GP_ProgressCallback *callback);
Loads an image from a file.
The image format is first guessed by the file extension. If loader for the
-file extension is found it's called and if it succedes the image data is
+file extension is found it's called and if it succeeds the image data is
returned.
If file extension based guess fails either because the extension wasn't
@@ -105,7 +107,7 @@ typedef struct GP_Loader {
/*
* Save an image.
*
- * Returns zero on succes, non-zero on failure and errno must be set.
+ * Returns zero on success, non-zero on failure and errno must be set.
*/
int (*Save)(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
@@ -192,9 +194,9 @@ const GP_Loader *GP_MatchExtension(const char *path)
Matches loader by the file extension. This function does not check that the
file exists or that it could be opened it only looks at the extension (i.e.
-string after the dot) and matches it agains known extensions.
+string after the dot) and matches it against known extensions.
-WARNING: If you attempt to modify the content of the strucutre the behavior is
+WARNING: If you attempt to modify the content of the structure the behavior is
undefined. Most likely the program will crash.
PNG Loader
@@ -207,28 +209,14 @@ The 'PNG' image support is implemented by the libpng library.
/* or */
#include <GP.h>
-int GP_OpenPNG(const char *src_path, FILE **f);
+GP_Context *GP_ReadPNG(GP_IO *io, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Opens file and checks for 'PNG' signature. Returns zero on success (file
-could be opened, signature matches), the opened file is returned and the file
-position points right after the end of the 'PNG' signature.
+Reads a 'PNG' image from readable 'GP_IO'. The link:loaders_io.html[IO stream]
+is expected to start exactly at the 'PNG' file signature.
-This function is semi-internal, you should rather use functions listed below.
-
-[source,c]
--------------------------------------------------------------------------------
-#include <loaders/GP_PNG.h>
-/* or */
-#include <GP.h>
-
-GP_Context *GP_ReadPNG(FILE *f, GP_ProgressCallback *callback);
--------------------------------------------------------------------------------
-
-Loads 'PNG' file into context the file pointer must point to the start of the
-'PNG' data stream (i.e. should point right after the signature). The context,
-to store the image to, is allocated. The loading process could by aborted by a
-callback, in such case all memory is freed.
+Returns newly allocated context (containing decompressed image) or in case of
+failure 'NULL' and 'errno' is set.
[source,c]
-------------------------------------------------------------------------------
@@ -239,8 +227,10 @@ callback, in such case all memory is freed.
GP_Context *GP_LoadPNG(const char *src_path, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Same as above but takes path to the file as a parameter and check for the
-signature. Basically this combines both of the calls above.
+Loads a 'PNG' image from a file.
+
+Returns a pointer to newly allocated loaded image, or in case of failure
+'NULL' and 'errno' is set.
[source,c]
-------------------------------------------------------------------------------
@@ -252,9 +242,11 @@ int GP_SavePNG(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Currently only 'RGB888' format is supported, you should convert the
-'GP_Context' to 'RGB888' before calling this function otherwise non-zero is
-returned and 'errno' is set to 'ENOSYS'.
+Saves a 'Context' into a 'PNG' image, in case particular pixel type is not
+supported non-zero is returned and 'errno' is set to 'ENOSYS'.
+
+Supports 'G1', 'G2', 'G4', 'G8', 'G16', and 8-bit 'RGB' and 'RGBA' pixel
+types.
[source,c]
-------------------------------------------------------------------------------
@@ -265,7 +257,7 @@ returned and 'errno' is set to 'ENOSYS'.
int GP_MatchPNG(const void *buf);
-------------------------------------------------------------------------------
-Matches a PNG signature.
+Matches a 'PNG' file signature. Returns non-zero if found.
JPEG Loader
~~~~~~~~~~~
@@ -277,32 +269,14 @@ The 'JPEG' image support is implemented by the jpeg library.
/* or */
#include <GP.h>
-int GP_OpenJPG(const char *src_path, FILE **f);
+GP_Context *GP_ReadJPG(GP_IO *io, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Opens file and checks for 'JPG' signature upon successful return (file could
-be opened, signature matches), the opened file is returned and the file
-position points right after the end of the 'JPG' signature.
+Reads a 'JPEG' image from readable 'GP_IO'. The link:loaders_io.html[IO
+stream] is expected to start exactly at the 'JPEG' file signature.
-This function is semi-internal, you should rather use functions listed below.
-
-'TODO:' This is not finished yet, currently this just opens and returns the
-file and the 'GP_ReadJPG()' reads the signature instead.
-
-[source,c]
--------------------------------------------------------------------------------
-#include <loaders/GP_JPG.h>
-/* or */
-#include <GP.h>
-
-GP_Context *GP_ReadJPG(FILE *f, GP_ProgressCallback *callback);
--------------------------------------------------------------------------------
-
-Loads 'JPG' file into context the file pointer must point to the start of the
-'JPG' data stream (i.e. should point right after the signature). The context,
-to store the image to, is allocated. The loading process could by aborted by a
-callback, in such case all memory is freed and the call returns 'NULL' and
-'errno' is set to 'ECANCELED'.
+Returns newly allocated context (containing decompressed image) or in case of
+failure 'NULL' and 'errno' is set.
[source,c]
-------------------------------------------------------------------------------
@@ -313,8 +287,10 @@ callback, in such case all memory is freed and the call returns 'NULL' and
GP_Context *GP_LoadJPG(const char *src_path, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Same as above but takes path to the file as a parameter and check for the
-signature. Basically this combines both of the calls above.
+Loads an 'JPEG' image from a file.
+
+Returns a pointer to newly allocated loaded image, or in case of failure
+'NULL' and 'errno' is set.
[source,c]
-------------------------------------------------------------------------------
@@ -326,12 +302,11 @@ int GP_SaveJPG(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Writes a Context into a 'JPG' image. If aborted by a callback, the opened file
-is closed and removed before the call returns non-zero and 'errno' is set to
-'ECANCELED'.
+Writes a 'Context' into a 'JPEG' image. If aborted by a callback, the opened
+file is closed and removed before the call returns non-zero and 'errno' is set
+to 'ECANCELED'.
-The 'JPG' format could store either 'G8' or 'RGB888' pixeltypes and you must
-convert the context into one of them before this functions is called.
+The 'JPEG' format could store either 'G8' or 8-bit 'RGB' pixel-types.
[source,c]
-------------------------------------------------------------------------------
@@ -342,7 +317,7 @@ convert the context into one of them before this functions is called.
int GP_MatchJPG(const void *buf);
-------------------------------------------------------------------------------
-Matches a JPG signature.
+Matches a 'JPEG' file signature. Returns non-zero if found.
JPEG 2000 Loader
~~~~~~~~~~~~~~~~
@@ -354,32 +329,45 @@ The 'JPEG 2000' image support is implemented using the openjpeg library.
/* or */
#include <GP.h>
-GP_Context *GP_LoadJP2(const char *src_path, GP_ProgressCallback *callback);
+GP_Context *GP_ReadJP2(GP_IO *io, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Loads 'JPEG 2000' image.
+Reads a 'JPEG2000' image from readable 'GP_IO'. The link:loaders_io.html[IO
+stream] is expected to start exactly at the 'JPEG2000' file signature.
-Due to limitations of the openjpeg library progress callback does not work.
+Returns newly allocated context (containing decompressed image) or in case of
+failure 'NULL' and 'errno' is set.
-GIF Loader
-~~~~~~~~~~
+NOTE: Due to limitations of the openjpeg library progress callback does not work.
-The 'GIF' image support is implemented by the giflib library.
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_JP2.h>
+/* or */
+#include <GP.h>
+
+GP_Context *GP_LoadJP2(const char *src_path, GP_ProgressCallback *callback);
+-------------------------------------------------------------------------------
+
+Loads 'JPEG2000' image from a file.
+
+NOTE: Due to limitations of the openjpeg library progress callback does not work.
[source,c]
-------------------------------------------------------------------------------
-#include <loaders/GP_GIF.h>
+#include <loaders/GP_JP2.h>
/* or */
#include <GP.h>
-int GP_OpenGIF(const char *src_path, void **f);
+int GP_MatchJP2(const void *buf);
-------------------------------------------------------------------------------
-Opens file and checks for 'GIF' signature upon successful return (file could
-be opened, signature matches) zero is returned and gif handle f is set
-otherwise non-zero is returned and 'errno' is set.
+Matches a 'JPEG2000' file signature. Returns non-zero if found.
+
+GIF Loader
+~~~~~~~~~~
-This function is semi-internal, you should rather use functions listed below.
+The 'GIF' image support is implemented by the giflib library.
[source,c]
-------------------------------------------------------------------------------
@@ -387,16 +375,16 @@ This function is semi-internal, you should rather use functions listed below.
/* or */
#include <GP.h>
-GP_Context *GP_ReadGIF(void *f, GP_ProgressCallback *callback);
+GP_Context *GP_ReadGIF(GP_IO *io, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Loads 'GIF' file into context. The pointer must point to the 'GIF' handle as
-returned by 'GP_OpenGIF()' function. The context, to store the image to, is
-allocated. The loading process could by aborted by a callback, in such case
-all memory is freed and the call returns 'NULL' and 'errno' is set to
-'ECANCELED'.
+Reads a 'GIF' image from readable 'GP_IO'. The link:loaders_io.html[IO stream]
+is expected to start exactly at the 'GIF' file signature.
+
+Returns newly allocated context (containing decompressed image) or in case of
+failure 'NULL' and 'errno' is set.
-Currently this function loads only first image from the gif container.
+NOTE: Currently this function loads only first image from the 'GIF' container.
[source,c]
-------------------------------------------------------------------------------
@@ -407,8 +395,7 @@ Currently this function loads only first image from the gif container.
GP_Context *GP_LoadGIF(const char *src_path, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Same as above but takes path to the file as a parameter and check for the
-signature. Basically this combines both of the calls above.
+Loads 'GIF' image from a file.
[source,c]
-------------------------------------------------------------------------------
@@ -419,7 +406,7 @@ signature. Basically this combines both of the calls above.
int GP_MatchGIF(const void *buf);
-------------------------------------------------------------------------------
-Matches a GIF signature.
+Matches a 'GIF' file signature. Returns non-zero if found.
BMP Loader
~~~~~~~~~~
@@ -433,30 +420,14 @@ be exotic RGB compressions (RGB101010 for example) and RLE4 support.
/* or */
#include <GP.h>
-int GP_OpenBMP(const char *src_path, FILE **f,
- GP_Size *w, GP_Size *h, GP_PixelType *pixel_type);
--------------------------------------------------------------------------------
-
-Opens file and checks for 'BMP' signature upon successful return (file could
-be opened, signature matches) zero is returned and the parameters, if
-non-'NULL', are initialized. Upon failure non-zero is returned and 'errno' is
-set.
-
-This function is semi-internal, you should rather use functions listed below.
-
-[source,c]
+GP_Context *GP_ReadBMP(GP_IO *io, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-#include <loaders/GP_BMP.h>
-/* or */
-#include <GP.h>
-GP_Context *GP_ReadBMP(FILE *f, GP_ProgressCallback *callback);
--------------------------------------------------------------------------------
+Reads a 'BMP' image from readable 'GP_IO'. The link:loaders_io.html[IO stream]
+is expected to start exactly at the 'BMP' file signature.
-Loads 'BMP' file into context. The 'FILE' pointer must point to opened 'BMP'
-file. The context, to store the image to, is allocated. The loading process
-could by aborted by a callback, in such case all memory is freed and the call
-returns 'NULL' and 'errno' is set to 'ECANCELED'.
+Returns newly allocated context (containing decompressed image) or in case of
+failure 'NULL' and 'errno' is set.
[source,c]
-------------------------------------------------------------------------------
@@ -467,8 +438,7 @@ returns 'NULL' and 'errno' is set to 'ECANCELED'.
GP_Context *GP_LoadBMP(const char *src_path, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Same as above but takes path to the file as a parameter and check for the
-signature. Basically this combines both of the calls above.
+Loads 'BMP' image from a file.
[source,c]
-------------------------------------------------------------------------------
@@ -480,7 +450,9 @@ int GP_SaveBMP(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Saves 'RGB888' (24 bit RGB) image into BMP bitmap.
+Writes a 'Context' into a 'BMP' file.
+
+Currently only 8-bit 'RGB' formats are supported.
[source,c]
-------------------------------------------------------------------------------
@@ -491,7 +463,7 @@ Saves 'RGB888' (24 bit RGB) image into BMP bitmap.
int GP_MatchBMP(const void *buf);
-------------------------------------------------------------------------------
-Matches a BMP signature.
+Matches a 'BMP' file signature. Returns non-zero if found.
PSP Loader
~~~~~~~~~~
@@ -504,23 +476,14 @@ The 'PSP' loader can load a composite image from a Paint Shop Pro Image Files.
/* or */
#include <GP.h>
-int GP_OpenPSP(const char *src_path, FILE **f);
--------------------------------------------------------------------------------
-
-Opens file and checks for 'PSP' signature. Upon successful return (file could
-be opened, signature matches) zero is returned. Upon failure non-zero is
-returned and 'errno' is set.
-
-[source,c]
+GP_Context *GP_ReadPSP(GP_IO *io, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-#include <loaders/GP_PSP.h>
-/* or */
-#include <GP.h>
-GP_Context *GP_ReadPSP(FILE *f, GP_ProgressCallback *callback);
--------------------------------------------------------------------------------
+Reads a 'PSP' image from readable 'GP_IO'. The link:loaders_io.html[IO stream]
+is expected to start exactly at the 'PSP' file signature.
-Reads 'PSP' image into a context.
+Returns newly allocated context (containing decompressed image) or in case of
+failure 'NULL' and 'errno' is set.
[source,c]
-------------------------------------------------------------------------------
@@ -531,8 +494,7 @@ Reads 'PSP' image into a context.
GP_Context *GP_LoadPSP(const char *src_path, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Same as above but takes path to the file as a parameter and checks for the
-signature. Basically this combines both of the calls above.
+Loads a composite image from a 'PSP' file.
[source,c]
-------------------------------------------------------------------------------
@@ -543,10 +505,10 @@ signature. Basically this combines both of the calls above.
int GP_MatchPSP(const void *buf);
-------------------------------------------------------------------------------
-Matches a PSP signature.
+Matches a 'PSP' file signature. Returns non-zero if found.
-PNM
-~~~
+PNM Loaders
+~~~~~~~~~~~
[source,c]
-------------------------------------------------------------------------------
@@ -563,10 +525,9 @@ GP_Context *GP_LoadPPM(const char *src_path, GP_ProgressCallback *callback);
GP_Context *GP_LoadPNM(const char *src_path, GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Loads either ASCII or Rawbits (binary) PBM, PGM and PPM.
-
-The PNM can load all of them i.e. PBM, PGM and PPM.
+Loads either ASCII or Rawbits (binary) 'PBM', 'PGM' and 'PPM'.
+The 'PNM' can load all of them i.e. 'PBM', 'PGM' and 'PPM'.
[source,c]
-------------------------------------------------------------------------------
@@ -578,7 +539,7 @@ GP_Context *GP_SavePBM(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Saves 'G1' (1 bit grayscale) image into ASCII PBM.
+Saves 'G1' (1 bit grayscale) image into ASCII 'PBM'.
[source,c]
-------------------------------------------------------------------------------
@@ -591,7 +552,7 @@ GP_Context *GP_SavePGM(const GP_Context *src, const char *dst_path,
-------------------------------------------------------------------------------
Saves 'G1', 'G2', 'G4' and 'G8' (1, 2, 4 and 8 bit grayscale) image into ASCII
-PGM.
+'PGM'.
[source,c]
-------------------------------------------------------------------------------
@@ -603,7 +564,7 @@ GP_Context *GP_SavePPM(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
-------------------------------------------------------------------------------
-Saves 'RGB888' (24 bit RGB) image into ASCII PPM.
+Saves 'RGB888' (24 bit RGB) image into ASCII 'PPM'.
[source,c]
-------------------------------------------------------------------------------
@@ -616,7 +577,7 @@ GP_Context *GP_SavePNM(const GP_Context *src, const char *dst_path,
-------------------------------------------------------------------------------
Saves 'G1', 'G2', 'G4' and 'G8' (1, 2, 4, 8 bit grayscale) or 'RGB888' (24 bit
-RGB) image into ASCII PNM.
+RGB) image into ASCII 'PNM'.
[source,c]
-------------------------------------------------------------------------------
@@ -633,7 +594,9 @@ int GP_MatchPPM(const void *buf);
int GP_MatchPNM(const void *buf);
-------------------------------------------------------------------------------
-Matches either ASCII or Rawbits (binary) PBM, PGM and PPM.
+Matches either ASCII or Rawbits (binary) 'PBM', 'PGM' and 'PPM' file
+signatures.
-The PNM matches all of them i.e. PBM, PGM and PPM.
+The 'PNM' matches all of the formats. i.e. 'PBM', 'PGM' and 'PPM'.
+All functions return non-zero if found.
diff --git a/doc/loaders_io.txt b/doc/loaders_io.txt
new file mode 100644
index 0000000..e12e746
--- /dev/null
+++ b/doc/loaders_io.txt
@@ -0,0 +1,190 @@
+IO Interface
+------------
+
+GFXprim implements an I/O interface which is used by all image loaders.
+
+The purpose of the interface is:
+
+* Make it easy to load and save images from/into memory buffers
+* Fast and clean containers (ZIP for example) implementation
+ (zlib deflate could feed data directly into a memory based IO stream)
+
+The I/O interface is defined by a structure with callbacks.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_IO.h>
+/* or */
+#include <GP.h>
+
+/*
+ * Values are 1:1 with constants passed to lseek()
+ */
+enum GP_IOWhence {
+ GP_IO_SEEK_SET = 0,
+ GP_IO_SEEK_CUR = 1,
+ GP_IO_SEEK_END = 2,
+};
+
+
+typedef struct GP_IO {
+ ssize_t (*Read)(struct GP_IO *self, void *buf, size_t size);
+ ssize_t (*Write)(struct GP_IO *self, void *buf, size_t size);
+ off_t (*Seek)(struct GP_IO *self, off_t off, enum GP_IOWhence whence);
+ int (*Close)(struct GP_IO *self);
+
+ off_t mark;
+ char priv[];
+} GP_IO;
+-------------------------------------------------------------------------------
+
+The fields of the I/O stream structure are mostly self describing. The 'Seek'
+behaves exactly as 'lseek(2)', the 'Read' as 'read(2)' and the 'Write' as
+'write(2)'.
+
+The 'mark' and 'priv' are private fields that shall not be touched by user.
+
+An IO reader must implement at least 'Read', 'Seek' (at least able to seek
+forward to skip some data) and 'Close'.
+
+An IO writer must implement at least 'Write' and 'Close'.
+
+Return value from the 'Seek' is a value of current offset in the stream (after
+the seek has been done) or in case of failure '(off_t)-1'.
+
+Return value from 'Read' or 'Write' is a number of bytes read/written or in
+case of failure a negative number (-1).
+
+Return value from 'Close' is zero on success and non-zero on IO failure.
+
+NOTE: Make sure 'errno' is set if any of the operations has failed.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_IO.h>
+/* or */
+#include <GP.h>
+
+ssize_t GP_IORead(GP_IO *io, void *buf, size_t size);
+-------------------------------------------------------------------------------
+
+This is a wrapper to 'io->Read()'.
+
+Reads at most 'size' bytes from an 'IO' stream and stores them into the
+buffer. Returns number of bytes read.
+
+On failure the return value is negative and 'errno' is set.
+
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_IO.h>
+/* or */
+#include <GP.h>
+
+ssize_t GP_IOWrite(GP_IO *io, void *buf, size_t size);
+-------------------------------------------------------------------------------
+
+This is a wrapper to 'io->Write()'.
+
+Writes at most 'size' bytes from an 'IO' stream and stores them into the
+buffer. Returns number of bytes read.
+
+On failure the return value is negative and 'errno' is set.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_IO.h>
+/* or */
+#include <GP.h>
+
+int GP_IOClose(GP_IO *io);
+-------------------------------------------------------------------------------
+
+This is a wrapper to 'io->Close()'.
+
+Finalizes reading/writing, closes file descriptors (in case of file IO), frees
+memory buffers.
+
+Returns zero on success, non-zero on IO failure and 'errno' is set.
+
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_IO.h>
+/* or */
+#include <GP.h>
+
+off_t GP_IOSeek(GP_IO *io, off_t off, enum GP_IOWhence whence);
+-------------------------------------------------------------------------------
+
+This is a wrapper to 'io->Seek()'.
+
+//TODO
+
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_IO.h>
+/* or */
+#include <GP.h>
+
+off_t GP_IOTell(GP_IO *io);
+-------------------------------------------------------------------------------
+
+Wrapper to 'GP_IOSeek()', returns current position in IO stream.
+
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_IO.h>
+/* or */
+#include <GP.h>
+
+off_t GP_IORewind(GP_IO *io)
+-------------------------------------------------------------------------------
+
+Wrapper to 'GP_IOSeek()', rewinds to the start of the IO stream.
+
+Returns zero on success, non-zero on failure and 'errno' is set.
+
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_IO.h>
+/* or */
+#include <GP.h>
+
+GP_IO *GP_IOMem(void *buf, size_t size, void (*free)(void *));
+-------------------------------------------------------------------------------
+
+Creates an read-only IO from a memory buffer.
+
+Returns initialized IO or in case of failure 'NULL' and 'errno' is set.
+
+The 'buf' is pointer to the start of the buffer, the 'size' is size in bytes.
+
+The 'free()' callback if not 'NULL' is called with the start of the buffer as
+an argument on 'IOClose()'.
+
+TIP: See link:example_memory_io.html[memory IO example].
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_IO.h>
+/* or */
+#include <GP.h>
+
+enum GP_IOFileMode {
+ GP_IO_RDONLY = 0x00,
+ GP_IO_WRONLY = 0x01,
+ GP_IO_RDWR = 0x02,
+};
+
+GP_IO *GP_IOFile(const char *path, enum GP_IOFileMode mode);
+-------------------------------------------------------------------------------
+
+Creates an IO stream from a file.
+
+Returns a pointer to initialized IO stream, or in case of failure 'NULL' and
+'errno' is set.
diff --git a/include/loaders/GP_BMP.h b/include/loaders/GP_BMP.h
index 4c5ca26..48eff73 100644
--- a/include/loaders/GP_BMP.h
+++ b/include/loaders/GP_BMP.h
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -25,40 +25,18 @@
#include "core/GP_Context.h"
#include "core/GP_ProgressCallback.h"
+#include "loaders/GP_IO.h"
/*
- * The possible errno values:
+ * Reads a BMP from an IO stream.
*
- * - Anything FILE operation may return (fopen(), fclose(), fseek(), ...).
- * - EIO for fread()/fwrite() failure
- * - ENOSYS for not implemented bitmap format
- * - ENOMEM from malloc()
- * - EILSEQ for wrong image signature/data
- * - ECANCELED when call was aborted from callback
+ * Returns newly allocated context cotaining the loaded image or in case of
+ * failure NULL and errno is set.
*/
+GP_Context *GP_ReadBMP(GP_IO *io, GP_ProgressCallback *callback);
/*
- * Opens up a bmp file, checks signature, parses metadata.
- *
- * The file, width, height and pixel type are filled upon succcessful return.
- *
- * Upon failure, non zero return value is returned and errno is filled.
- */
-int GP_OpenBMP(const char *src_path, FILE **f,
- GP_Size *w, GP_Size *h, GP_PixelType *pixel_type);
-
-/*
- * Reads a BMP from a opened file.
- *
- * Upon successful return, context to store bitmap is allocated and image is
- * loaded.
- *
- * Upon failure NULL is returned and errno is filled.
- */
-GP_Context *GP_ReadBMP(FILE *f, GP_ProgressCallback *callback);
-
-/*
- * Does both GP_OpenBMP and GP_ReadBMP.
+ * Loads a BMP image from a file.
*/
GP_Context *GP_LoadBMP(const char *src_path, GP_ProgressCallback *callback);
@@ -70,7 +48,7 @@ int GP_SaveBMP(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
/*
- * Match BMP signature.
+ * Looks for BMP file signature. Returns non-zero if found.
*/
int GP_MatchBMP(const void *buf);
diff --git a/include/loaders/GP_GIF.h b/include/loaders/GP_GIF.h
index b2ee363..23405e2 100644
--- a/include/loaders/GP_GIF.h
+++ b/include/loaders/GP_GIF.h
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -29,37 +29,25 @@
#ifndef LOADERS_GP_GIF_H
#define LOADERS_GP_GIF_H
-#include "core/GP_ProgressCallback.h"
#include "core/GP_Context.h"
+#include "core/GP_ProgressCallback.h"
+#include "loaders/GP_IO.h"
/*
- * The possible errno values:
+ * Reads first image found in GIF container from an IO stream.
*
- * - EIO for read/write failure
- * - ENOSYS for not implemented bitmap format
- * - ENOMEM from malloc()
- * - EILSEQ for wrong image signature/data
- * - ECANCELED when call was aborted from callback
- */
-
-/*
- * Opens up the Gif image and checks signature.
- * Returns zero on success.
- */
-int GP_OpenGIF(const char *src_path, void **f);
-
-/*
- * Reads first image found in GIF container.
+ * Returns newly allocated context cotaining the loaded image or in case of
+ * failure NULL and errno is set.
*/
-GP_Context *GP_ReadGIF(void *f, GP_ProgressCallback *callback);
+GP_Context *GP_ReadGIF(GP_IO *io, GP_ProgressCallback *callback);
/*
- * Does both GP_OpenGIF and GP_ReadGIF at once.
+ * Loads first image found in GIF container from a file.
*/
GP_Context *GP_LoadGIF(const char *src_path, GP_ProgressCallback *callback);
/*
- * Match GIF signature.
+ * Looks for GIF file signature. Returns non-zero if found.
*/
int GP_MatchGIF(const void *buf);
diff --git a/include/loaders/GP_IO.h b/include/loaders/GP_IO.h
new file mode 100644
index 0000000..fa1046f
--- /dev/null
+++ b/include/loaders/GP_IO.h
@@ -0,0 +1,184 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+ /*
+
+ I/O abstraction for GFXprim loaders.
+
+ */
+
+#ifndef LOADERS_GP_IO_H
+#define LOADERS_GP_IO_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+/*
+ * Values are 1:1 with constants passed to lseek()
+ */
+enum GP_IOWhence {
+ GP_IO_SEEK_SET = 0,
+ GP_IO_SEEK_CUR = 1,
+ GP_IO_SEEK_END = 2,
+};
+
+typedef struct GP_IO {
+ ssize_t (*Read)(struct GP_IO *self, void *buf, size_t size);
+ ssize_t (*Write)(struct GP_IO *self, void *buf, size_t size);
+ off_t (*Seek)(struct GP_IO *self, off_t off, enum GP_IOWhence whence);
+ int (*Close)(struct GP_IO *self);
+
+// void *(*Map)(struct GP_IO *self, size_t len, off_t off);
+// void (*UnMap)(struct GP_IO *self, void *addr, size_t len);
+
+ off_t mark;
+ char priv[];
+} GP_IO;
+
+#define GP_IO_PRIV(io) ((void *)(io)->priv)
+
+/*
+ * Just inline wrappers.
+ */
+static inline ssize_t GP_IORead(GP_IO *io, void *buf, size_t size)
+{
+ return io->Read(io, buf, size);
+}
+
+static inline ssize_t GP_IOWrite(GP_IO *io, void *buf, size_t size)
+{
+ return io->Write(io, buf, size);
+}
+
+static inline int GP_IOClose(GP_IO *io)
+{
+ return io->Close(io);
+}
+
+static inline off_t GP_IOSeek(GP_IO *io, off_t off, enum GP_IOWhence whence)
+{
+ return io->Seek(io, off, whence);
+}
+
+//static inline void *GP_IOMap(GP_IO *io, size_t len, off_t off)
+//{
+// return io->Map(io, len, off);
+//}
+
+//static inline void *GP_IOUnMap(GP_IO *io, size_t len, off_t off)
+//{
+// return io->UnMap(io, len, off);
+//}
+
+/*
+ * Returns current offset
+ */
+static inline off_t GP_IOTell(GP_IO *io)
+{
+ return io->Seek(io, 0, GP_IO_SEEK_CUR);
+}
+
+/*
+ * Rewinds to start of the I/O stream.
+ */
+static inline off_t GP_IORewind(GP_IO *io)
+{
+ return io->Seek(io, 0, GP_IO_SEEK_SET);
+}
+
+/*
+ * Returns I/O stream size.
+ *
+ * May return (off_t)-1 in case that GP_IO_SEEK_END is not possible.
+ */
+off_t GP_IOSize(GP_IO *io);
+
+/*
+ * Like a Read but either fills whole buffer or returns error.
+ *
+ * Returns zero on success non-zero on failure.
+ */
+int GP_IOFill(GP_IO *io, void *buf, size_t size);
+
+/*
+ * Marks a current position, returns to mark in I/O stream.
+ */
+enum GP_IOMarkTypes {
+ GP_IO_MARK,
+ GP_IO_REWIND,
+};
+
+int GP_IOMark(GP_IO *self, enum GP_IOMarkTypes type);
+
+/*
+ * Formatted read.
+ *
+ *
+ */
+enum GP_IOReadFTypes {
+ /* Constant byte in lower half */
+ GP_IO_CONST = 0x0000,
+ /* Pointer to one byte */
+ GP_IO_BYTE = 0x0100,
+ /* Pointer to byte integer in litte endian */
+ GP_IO_L2 = 0x0200,
+ /* Poiter to four byte integer in litte endian */
+ GP_IO_L4 = 0x0300,
+ /* Pointer to two byte integer in big endian */
+ GP_IO_B2 = 0x0400,
+ /* Pointer to four byte integer in big endian */
+ GP_IO_B4 = 0x0500,
+ /* Pointer to byte array, size in lower half */
+ GP_IO_ARRAY = 0x0600,
+ /* Ignore bytes on read, size in lower half */
+ GP_IO_IGN = 0x0700,
+ GP_IO_I1 = GP_IO_IGN | 1,
+ GP_IO_I2 = GP_IO_IGN | 2,
+ GP_IO_I3 = GP_IO_IGN | 3,
+ GP_IO_I4 = GP_IO_IGN | 4,
+ /* End of the types array */
+ GP_IO_END = 0xff00,
+};
+
+#define GP_IO_TYPE_MASK 0xff00
+
+int GP_IOReadF(GP_IO *self, uint16_t *types, ...);
+
+enum GP_IOFileMode {
+ GP_IO_RDONLY = 0x00,
+ GP_IO_WRONLY = 0x01,
+ GP_IO_RDWR = 0x02,
+};
+
+/*
+ * Creates I/O from a file. On error NULL is returned and errno is set.
+ */
+GP_IO *GP_IOFile(const char *path, enum GP_IOFileMode mode);
+
+/*
+ * Creates I/O from a memory buffer.
+ *
+ * If free is not NULL, it's called on buf pointer on GP_IOClose().
+ */
+GP_IO *GP_IOMem(void *buf, size_t size, void (*free)(void *));
+
+#endif /* LOADERS_GP_IO_H */
diff --git a/include/loaders/GP_JP2.h b/include/loaders/GP_JP2.h
index 7068a46..574cfbc 100644
--- a/include/loaders/GP_JP2.h
+++ b/include/loaders/GP_JP2.h
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -31,24 +31,23 @@
#include "core/GP_Context.h"
#include "core/GP_ProgressCallback.h"
+#include "loaders/GP_IO.h"
/*
- * Opens up file and checks signature.
+ * Reads a JPEG2000 from an IO stream.
+ *
+ * Returns newly allocated context cotaining the loaded image or in case of
+ * failure NULL and errno is set.
*/
-int GP_OpenJP2(const char *src_path, FILE **f);
+GP_Context *GP_ReadJP2(GP_IO *io, GP_ProgressCallback *callback);
/*
- * Reads JP2 from an open FILE.
- */
-GP_Context *GP_ReadJP2(FILE *f, GP_ProgressCallback *callback);
-
-/*
- * Loads a JP2 file into GP_Context. The Context is newly allocated.
+ * Loads a JPEG2000 image from a file.
*/
GP_Context *GP_LoadJP2(const char *src_path, GP_ProgressCallback *callback);
/*
- * Match JP2 signature.
+ * Looks for JPEG2000 file signature. Returns non-zero if found.
*/
int GP_MatchJP2(const void *buf);
diff --git a/include/loaders/GP_JPG.h b/include/loaders/GP_JPG.h
index 8f6a920..95123ec 100644
--- a/include/loaders/GP_JPG.h
+++ b/include/loaders/GP_JPG.h
@@ -16,13 +16,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
/*
- JPG support using jpeg library.
+ JPEG support using jpeg library.
*/
@@ -31,22 +31,19 @@
#include "core/GP_Context.h"
#include "core/GP_ProgressCallback.h"
-
-#include "GP_MetaData.h"
-
-/*
- * Opens up file and checks signature.
- */
-int GP_OpenJPG(const char *src_path, FILE **f);
+#include "loaders/GP_IO.h"
+#include "loaders/GP_MetaData.h"
/*
- * Reads JPG from an open FILE. Expects the file position set after the eight
- * bytes JPG signature.
+ * Reads a JPEG from an IO stream.
+ *
+ * Returns newly allocated context cotaining the loaded image or in case of
+ * failure NULL and errno is set.
*/
-GP_Context *GP_ReadJPG(FILE *f, GP_ProgressCallback *callback);
+GP_Context *GP_ReadJPG(GP_IO *io, GP_ProgressCallback *callback);
/*
- * Loads a JPG file into GP_Context. The Context is newly allocated.
+ * Loads a JPEG image from a file.
*/
GP_Context *GP_LoadJPG(const char *src_path, GP_ProgressCallback *callback);
@@ -57,13 +54,13 @@ int GP_ReadJPGMetaData(FILE *f, GP_MetaData *data);
int GP_LoadJPGMetaData(const char *src_path, GP_MetaData *data);
/*
- * Saves JPG to a file.
+ * Saves JPEG to a file.
*/
int GP_SaveJPG(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
/*
- * Match JPG signature.
+ * Looks for JPEG file signature. Returns non-zero if found.
*/
int GP_MatchJPG(const void *buf);
diff --git a/include/loaders/GP_Loader.h b/include/loaders/GP_Loader.h
index 6522c0a..925f358 100644
--- a/include/loaders/GP_Loader.h
+++ b/include/loaders/GP_Loader.h
@@ -49,7 +49,7 @@ int GP_LoadMetaData(const char *src_path, GP_MetaData *data);
/*
* Simple saving function, the image format is matched by file extension.
*
- * Retruns zero on succes.
+ * Retruns zero on success.
*
* On failure non-zero is returned.
*
diff --git a/include/loaders/GP_PNG.h b/include/loaders/GP_PNG.h
index e9b72ce..0b440d0 100644
--- a/include/loaders/GP_PNG.h
+++ b/include/loaders/GP_PNG.h
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -31,38 +31,19 @@
#include "core/GP_ProgressCallback.h"
#include "core/GP_Context.h"
-
-#include "GP_MetaData.h"
-
-/*
- * The possible errno values:
- *
- * - Anything FILE operation may return (fopen(), fclose(), fseek(), ...).
- * - EIO for png_read()/png_write() failure
- * - ENOSYS for not implemented bitmap format
- * - ENOMEM from malloc()
- * - EILSEQ for wrong image signature/data
- * - ECANCELED when call was aborted from callback
- */
-
-/*
- * Opens up file and checks signature. Upon successful return (zero is
- * returned) the file position would be set to eight bytes (exactly after the
- * PNG signature).
- */
-int GP_OpenPNG(const char *src_path, FILE **f);
+#include "loaders/GP_IO.h"
+#include "loaders/GP_MetaData.h"
/*
- * Reads PNG from an open FILE. Expects the file position set after the eight
- * bytes PNG signature.
+ * Reads a PNG from an IO stream.
*
- * Upon succesfull return pointer to newly allocated context is returned.
- * Otherwise NULL is returned and errno is filled.
+ * Returns newly allocated context cotaining the loaded image or in case of
+ * failure NULL and errno is set.
*/
-GP_Context *GP_ReadPNG(FILE *f, GP_ProgressCallback *callback);
+GP_Context *GP_ReadPNG(GP_IO *io, GP_ProgressCallback *callback);
/*
- * Does both GP_OpenPNG and GP_ReadPNG at once.
+ * Loads a PNG image from a file.
*/
GP_Context *GP_LoadPNG(const char *src_path, GP_ProgressCallback *callback);
@@ -80,7 +61,7 @@ int GP_SavePNG(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
/*
- * Match PNG signature.
+ * Looks for PNG file signature. Returns non-zero if found.
*/
int GP_MatchPNG(const void *buf);
diff --git a/include/loaders/GP_PNM.h b/include/loaders/GP_PNM.h
index 150ff21..4f2dd11 100644
--- a/include/loaders/GP_PNM.h
+++ b/include/loaders/GP_PNM.h
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -25,10 +25,13 @@
#include "core/GP_Context.h"
#include "core/GP_ProgressCallback.h"
+#include "loaders/GP_IO.h"
/*
* PBM Bitmap
*/
+GP_Context *GP_ReadPBM(GP_IO *io, GP_ProgressCallback *callback);
+
GP_Context *GP_LoadPBM(const char *src_path, GP_ProgressCallback *callback);
int GP_SavePBM(const GP_Context *src, const char *dst_path,
@@ -37,6 +40,8 @@ int GP_SavePBM(const GP_Context *src, const char *dst_path,
/*
* PGM Graymap
*/
+GP_Context *GP_ReadPGM(GP_IO *io, GP_ProgressCallback *callback);
+
GP_Context *GP_LoadPGM(const char *src_path,
GP_ProgressCallback *callback);
@@ -46,6 +51,8 @@ int GP_SavePGM(const GP_Context *src, const char *dst_path,
/*
* PPM Pixmap
*/
+GP_Context *GP_ReadPPM(GP_IO *io, GP_ProgressCallback *callback);
+
GP_Context *GP_LoadPPM(const char *src_path, GP_ProgressCallback *callback);
int GP_SavePPM(const GP_Context *src, const char *dst_path,
@@ -54,6 +61,8 @@ int GP_SavePPM(const GP_Context *src, const char *dst_path,
/*
* PNM Anymap (All of above)
*/
+GP_Context *GP_ReadPNM(GP_IO *io, GP_ProgressCallback *callback);
+
GP_Context *GP_LoadPNM(const char *src_path, GP_ProgressCallback *callback);
int GP_SavePNM(const GP_Context *src, const char *dst_path,
diff --git a/include/loaders/GP_PSP.h b/include/loaders/GP_PSP.h
index 3ddf75c..1109bd9 100644
--- a/include/loaders/GP_PSP.h
+++ b/include/loaders/GP_PSP.h
@@ -16,13 +16,15 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
/*
- Experimental Paint Shop Pro image loader.
+ Paint Shop Pro image loader.
+
+ Loads composite image from a PSP file.
*/
@@ -31,35 +33,23 @@
#include "core/GP_ProgressCallback.h"
#include "core/GP_Context.h"
+#include "loaders/GP_IO.h"
/*
- * The possible errno values:
+ * Reads a BMP from an IO stream.
*
- * - EIO for read/write failure
- * - ENOSYS for not implemented bitmap format
- * - ENOMEM from malloc()
- * - EILSEQ for wrong image signature/data
- * - ECANCELED when call was aborted from callback
- */
-
-/*
- * Opens up the PSP image and checks signature.
- * Returns zero on success.
- */
-int GP_OpenPSP(const char *src_path, FILE **f);
-
-/*
- * Reads image from PSP format.
+ * Returns newly allocated context cotaining the loaded image or in case of
+ * failure NULL and errno is set.
*/
-GP_Context *GP_ReadPSP(FILE *f, GP_ProgressCallback *callback);
+GP_Context *GP_ReadPSP(GP_IO *io, GP_ProgressCallback *callback);
/*
- * Does both GP_OpenPSP and GP_ReadPSP at once.
+ * Loads a PSP image from a file.
*/
GP_Context *GP_LoadPSP(const char *src_path, GP_ProgressCallback *callback);
/*
- * Match PSP signature.
+ * Looks for PSP file signature. Returns non-zero if found.
*/
int GP_MatchPSP(const void *buf);
diff --git a/include/loaders/GP_TIFF.h b/include/loaders/GP_TIFF.h
index 73acb5f..8c7c45f 100644
--- a/include/loaders/GP_TIFF.h
+++ b/include/loaders/GP_TIFF.h
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -25,39 +25,18 @@
#include "core/GP_Context.h"
#include "core/GP_ProgressCallback.h"
+#include "loaders/GP_IO.h"
/*
- * The possible errno values:
+ * Reads first image in TIFF from an IO stream.
*
- * - Anything FILE operation may return (fopen(), fclose(), fseek(), ...).
- * - EIO for fread()/fwrite() failure
- * - ENOSYS for not implemented bitmap format
- * - ENOMEM from malloc()
- * - EILSEQ for wrong image signature/data
- * - ECANCELED when call was aborted from callback
+ * Returns newly allocated context cotaining the loaded image or in case of
+ * failure NULL and errno is set.
*/
+GP_Context *GP_ReadTIFF(GP_IO *io, GP_ProgressCallback *callback);
/*
- * Opens up a bmp file, checks signature, parses metadata.
- *
- * The file, width, height and pixel type are filled upon succcessful return.
- *
- * Upon failure, non zero return value is returned and errno is filled.
- */
-int GP_OpenTIFF(const char *src_path, void **t);
-
-/*
- * Reads a TIFF from a opened file.
- *
- * Upon successful return, context to store bitmap is allocated and image is
- * loaded.
- *
- * Upon failure NULL is returned and errno is filled.
- */
-GP_Context *GP_ReadTIFF(void *t, GP_ProgressCallback *callback);
-
-/*
- * Does both GP_OpenTIFF and GP_ReadTIFF.
+ * Loads fist image in TIFF from a file.
*/
GP_Context *GP_LoadTIFF(const char *src_path, GP_ProgressCallback *callback);
@@ -68,7 +47,7 @@ int GP_SaveTIFF(const GP_Context *src, const char *dst_path,
GP_ProgressCallback *callback);
/*
- * Match TIFF signature.
+ * Looks for TIFF file signature. Returns non-zero if found.
*/
int GP_MatchTIFF(const void *buf);
diff --git a/libs/loaders/GP_BMP.c b/libs/loaders/GP_BMP.c
index d7ea61f..cc03a5e 100644
--- a/libs/loaders/GP_BMP.c
+++ b/libs/loaders/GP_BMP.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -24,7 +24,7 @@
BMP loader and writer.
- Thanks Wikipedia for the format specification.
+ Thanks Wikipedia for excellent format specification.
*/
@@ -46,12 +46,6 @@
#define BMP_HEADER_OFFSET 0x0a /* info header offset - 4 bytes */
-#define BUF_TO_4(buf, off) - (buf[off] + (buf[off+1]<<8) + (buf[off+2]<<16) + (buf[off+3]<<24))
-
-#define BUF_TO_2(buf, off) - (buf[off] + (buf[off+1]<<8))
-
struct bitmap_info_header {
/*
* Offset to image data.
@@ -155,16 +149,19 @@ static uint32_t get_palette_size(struct bitmap_info_header *header)
return (1 << header->bpp);
}
-static int read_bitfields(FILE *f, struct bitmap_info_header *header)
+static int read_bitfields(GP_IO *io, struct bitmap_info_header *header)
{
- int ret;
+ uint16_t bitfields[] = {
+ GP_IO_L4, /* red mask */
+ GP_IO_L4, /* green mask */
+ GP_IO_L4, /* blue mask */
+ GP_IO_END
+ };
- ret = GP_FRead(f, "L4 L4 L4",
+ if (GP_IOReadF(io, bitfields,
&header->R_mask,
&header->G_mask,
- &header->B_mask);
-
- if (ret != 3) {
+ &header->B_mask) != 3) {
GP_DEBUG(1, "Failed to read BITFIELDS");
return EIO;
}
@@ -177,17 +174,21 @@ static int read_bitfields(FILE *f, struct bitmap_info_header *header)
return 0;
}
-static int read_alphabitfields(FILE *f, struct bitmap_info_header *header)
+static int read_alphabitfields(GP_IO *io, struct bitmap_info_header *header)
{
- int ret;
+ uint16_t abitfields[] = {
+ GP_IO_L4, /* red mask */
+ GP_IO_L4, /* green mask */
+ GP_IO_L4, /* blue mask */
+ GP_IO_L4, /* alpha mask */
+ GP_IO_END
+ };
- ret = GP_FRead(f, "L4 L4 L4 L4",
+ if (GP_IOReadF(io, abitfields,
&header->R_mask,
&header->G_mask,
&header->B_mask,
- &header->A_mask);
-
- if (ret != 4) {
+ &header->A_mask) != 4) {
GP_DEBUG(1, "Failed to read BITFIELDS");
return EIO;
}
@@ -199,11 +200,23 @@ static int read_alphabitfields(FILE *f, struct bitmap_info_header *header)
return 0;
}
-static int read_bitmap_info_header(FILE *f, struct bitmap_info_header *header)
+static int read_bitmap_info_header(GP_IO *io, struct bitmap_info_header *header)
{
uint16_t nr_planes;
- if (GP_FRead(f, "L4 L4 L2 L2 L4 I12 L4 I4",
+ uint16_t bmp_info_header[] = {
+ GP_IO_L4, /* width */
+ GP_IO_L4, /* height */
+ GP_IO_L2, /* number of planes */
+ GP_IO_L2, /* bpp */
+ GP_IO_L4, /* compression type */
+ GP_IO_IGN | 12, /* bitmap size in bytes, resolution */
+ GP_IO_L4, /* palette colors */
+ GP_IO_I4, /* number of significant colors */
+ GP_IO_END
+ };
+
+ if (GP_IOReadF(io, bmp_info_header,
&header->w, &header->h, &nr_planes, &header->bpp,
&header->compress_type, &header->palette_colors) != 8) {
@@ -227,39 +240,46 @@ static int read_bitmap_info_header(FILE *f, struct bitmap_info_header *header)
switch (header->header_size) {
case BITMAPINFOHEADER:
case BITMAPINFOHEADER2:
- return read_bitfields(f, header);
+ return read_bitfields(io, header);
default:
/* Alpha is default in BITMAPINFOHEADER3 and newer */
- return read_alphabitfields(f, header);
+ return read_alphabitfields(io, header);
}
/* Only in BITMAPINFOHEADER */
case COMPRESS_ALPHABITFIELDS:
if (header->header_size != BITMAPINFOHEADER)
GP_DEBUG(1, "Unexpected ALPHABITFIELDS in %s",
bitmap_header_size_name(header->header_size));
- return read_alphabitfields(f, header);
+ return read_alphabitfields(io, header);
}
return 0;
}
-static int read_bitmap_core_header(FILE *f, struct bitmap_info_header *header)
+static int read_bitmap_core_header(GP_IO *io, struct bitmap_info_header *header)
{
- uint8_t buf[12];
+ int16_t nr_planes, w, h;
+
+ uint16_t bmp_core_header[] = {
+ GP_IO_L2, /* width */
+ GP_IO_L2, /* height */
+ GP_IO_L2, /* number of planes */
+ GP_IO_L2, /* bpp */
+ //GP_IO_I4,//TODO read till 12?
+ GP_IO_END
+ };
- if (fread(buf, 1, sizeof(buf), f) != sizeof(buf)) {
+ if (GP_IOReadF(io, bmp_core_header, &w, &h,
+ &nr_planes, &header->bpp) != 4) {
GP_DEBUG(1, "Failed to read bitmap core header");
return EIO;
}
- header->w = BUF_TO_2(buf, 0);
- header->h = BUF_TO_2(buf, 2);
- header->bpp = BUF_TO_2(buf, 6);
+ header->w = w;
+ header->h = h;
header->compress_type = COMPRESS_RGB;
header->palette_colors = 0;
- uint16_t nr_planes = BUF_TO_2(buf, 4);
-
/* This must be 1 according to specs */
if (nr_planes != 1)
GP_DEBUG(1, "Number of planes is %"PRId16" should be 1",
@@ -271,33 +291,32 @@ static int read_bitmap_core_header(FILE *f, struct bitmap_info_header *header)
return 0;
}
-static int read_bitmap_header(FILE *f, struct bitmap_info_header *header)
+static int read_bitmap_header(GP_IO *io, struct bitmap_info_header *header)
{
- uint8_t buf[8];
int err;
- if (fseek(f, BMP_HEADER_OFFSET, SEEK_SET)) {
- err = errno;
- GP_DEBUG(1, "fseek(f, 0x%02x) failed: '%s'",
- BMP_HEADER_OFFSET, strerror(errno));
- return err;
- }
+ uint16_t bmp_header[] = {
+ 'B',
+ 'M',
+ GP_IO_IGN | (4 + 2 + 2), /* 4 bytes filesize + 4 bytes reserved */
+ GP_IO_L4, /* offset to pixel data */
+ GP_IO_L4, /* info header size */
+ GP_IO_END,
+ };
- /* Read info header size, header size determines header type */
- if (fread(buf, 1, sizeof(buf), f) != sizeof(buf)) {
- GP_DEBUG(1, "Failed to read info header size");
+ if (GP_IOReadF(io, bmp_header, &header->pixel_offset,
+ &header->header_size) != 5) {
+ GP_DEBUG(1, "Failed to read header");
+ //TODO: EIO vs EINVAL
return EIO;
}
- header->pixel_offset = BUF_TO_4(buf, 0);
- header->header_size = BUF_TO_4(buf, 4);
-
GP_DEBUG(2, "BMP header type '%s'",
bitmap_header_size_name(header->header_size));
switch (header->header_size) {
case BITMAPCOREHEADER:
- err = read_bitmap_core_header(f, header);
+ err = read_bitmap_core_header(io, header);
break;
case BITMAPCOREHEADER2:
return ENOSYS;
@@ -306,11 +325,11 @@ static int read_bitmap_header(FILE *f, struct bitmap_info_header *header)
case BITMAPINFOHEADER2:
case BITMAPINFOHEADER3:
case BITMAPINFOHEADER4:
- err = read_bitmap_info_header(f, header);
+ err = read_bitmap_info_header(io, header);
break;
default:
GP_DEBUG(1, "Unknown header type, continuing anyway");
- err = read_bitmap_info_header(f, header);
+ err = read_bitmap_info_header(io, header);
break;
};
@@ -320,7 +339,7 @@ static int read_bitmap_header(FILE *f, struct bitmap_info_header *header)
/*
* Reads palette, the format is R G B X, each one byte.
*/
-static int read_bitmap_palette(FILE *f, struct bitmap_info_header *header,
+static int read_bitmap_palette(GP_IO *io, struct bitmap_info_header *header,
GP_Pixel *palette)
{
uint32_t palette_colors = get_palette_size(header);
@@ -342,22 +361,24 @@ static int read_bitmap_palette(FILE *f, struct bitmap_info_header *header,
"pixel size %"PRIu8"bytes",
palette_offset, palette_offset, pixel_size);
- if (fseek(f, palette_offset, SEEK_SET)) {
+ if (GP_IOSeek(io, palette_offset, GP_IO_SEEK_SET) != palette_offset) {
err = errno;
- GP_DEBUG(1, "fseek(f, 0x%02x) failed: '%s'",
+ GP_DEBUG(1, "Seek to 0x%02x failed: '%s'",
BMP_HEADER_OFFSET, strerror(errno));
return err;
}
- for (i = 0; i < palette_colors; i++) {
- uint8_t buf[4];
+ uint8_t buf[pixel_size * palette_colors];
- if (fread(buf, 1, pixel_size, f) != pixel_size) {
- GP_DEBUG(1, "Failed to read palette %"PRIu32, i);
- return EIO;
- }
+ if (GP_IOFill(io, buf, sizeof(buf))) {
+ GP_DEBUG(1, "Failed to read palette: %s", strerror(errno));
+ return EIO;
+ }
+
+ for (i = 0; i < palette_colors; i++) {
+ unsigned int j = i * pixel_size;
- palette[i] = GP_Pixel_CREATE_RGB888(buf[2], buf[1], buf[0]);
+ palette[i] = GP_Pixel_CREATE_RGB888(buf[j+2], buf[j+1], buf[j]);
GP_DEBUG(3, "Palette[%"PRIu32"] = [0x%02x, 0x%02x, 0x%02x]", i,
GP_Pixel_GET_R_RGB888(palette[i]),
@@ -368,17 +389,17 @@ static int read_bitmap_palette(FILE *f, struct bitmap_info_header *header,
return 0;
}
-static int seek_pixels_offset(struct bitmap_info_header *header, FILE *f)
+static int seek_pixels_offset(GP_IO *io, struct bitmap_info_header *header)
{
int err;
GP_DEBUG(2, "Offset to BMP pixels is 0x%x (%ubytes)",
header->pixel_offset, header->pixel_offset);
- if (fseek(f, header->pixel_offset, SEEK_SET)) {
+ if (GP_IOSeek(io, header->pixel_offset, GP_IO_SEEK_SET) != header->pixel_offset) {
err = errno;
- GP_DEBUG(1, "fseek(f, 0x%02x) failed: '%s'",
- header->pixel_offset, strerror(errno));
+ GP_DEBUG(1, "Seek to 0x%02x failed: %s",
+ header->pixel_offset, strerror(err));
return err;
}
@@ -482,17 +503,17 @@ static uint8_t get_idx(struct bitmap_info_header *header,
#include "GP_BMP_RLE.h"
-static int read_palette(FILE *f, struct bitmap_info_header *header,
+static int read_palette(GP_IO *io, struct bitmap_info_header *header,
GP_Context *context, GP_ProgressCallback *callback)
{
uint32_t palette_size = get_palette_size(header);
GP_Pixel palette[get_palette_size(header)];
int err;
- if ((err = read_bitmap_palette(f, header, palette)))
+ if ((err = read_bitmap_palette(io, header, palette)))
return err;
- if ((err = seek_pixels_offset(header, f)))
+ if ((err = seek_pixels_offset(io, header)))
return err;
uint32_t row_size = bitmap_row_size(header);
@@ -502,9 +523,11 @@ static int read_palette(FILE *f, struct bitmap_info_header *header,
int32_t x;
uint8_t row[row_size];
- if (fread(row, 1, row_size, f) != row_size) {
- GP_DEBUG(1, "Failed to read row %"PRId32, y);
- return EIO;
+ if (GP_IOFill(io, row, row_size)) {
+ err = errno;
+ GP_DEBUG(1, "Failed to read row %"PRId32": %s",
+ y, strerror(errno));
+ return err;
}
for (x = 0; x < header->w; x++) {
@@ -539,17 +562,30 @@ static int read_palette(FILE *f, struct bitmap_info_header *header,
return 0;
}
-static int read_bitfields_or_rgb(FILE *f, struct bitmap_info_header *header,
+static int read_bitfields_or_rgb(GP_IO *io, struct bitmap_info_header *header,
GP_Context *context,
GP_ProgressCallback *callback)
{
uint32_t row_size = header->w * (header->bpp / 8);
+ uint32_t row_padd = 0;
int32_t y;
int err;
- if ((err = seek_pixels_offset(header, f)))
+ if ((err = seek_pixels_offset(io, header)))
return err;
+ /* Rows are four byte aligned */
+ switch (row_size % 4) {
+ case 1:
+ row_padd++;
+ case 2:
+ row_padd++;
+ case 3:
+ row_padd++;
+ case 0:
+ break;
+ }
+
for (y = 0; y < GP_ABS(header->h); y++) {
int32_t ry;
@@ -560,21 +596,20 @@ static int read_bitfields_or_rgb(FILE *f, struct bitmap_info_header *header,
uint8_t *row = GP_PIXEL_ADDR(context, 0, ry);
- if (fread(row, 1, row_size, f) != row_size) {
- GP_DEBUG(1, "Failed to read row %"PRId32, y);
- return EIO;
+ if (GP_IOFill(io, row, row_size)) {
+ err = errno;
+ GP_DEBUG(1, "Failed to read row %"PRId32": %s",
+ y, strerror(err));
+ return err;
}
- /* Rows are four byte aligned */
- switch (row_size % 4) {
- case 1:
- fgetc(f);
- case 2:
- fgetc(f);
- case 3:
- fgetc(f);
- case 0:
- break;
+ if (row_padd) {
+ if (GP_IOSeek(io, row_padd, GP_IO_SEEK_CUR) == (off_t)-1) {
+ err = errno;
+ GP_DEBUG(1, "Failed to seek row %"PRId32": %s",
+ y, strerror(err));
+ return err;
+ }
}
if (GP_ProgressCallbackReport(callback, y,
@@ -588,11 +623,11 @@ static int read_bitfields_or_rgb(FILE *f, struct bitmap_info_header *header,
return 0;
}
-static int read_bitmap_pixels(FILE *f, struct bitmap_info_header *header,
+static int read_bitmap_pixels(GP_IO *io, struct bitmap_info_header *header,
GP_Context *context, GP_ProgressCallback *callback)
{
if (header->compress_type == COMPRESS_RLE8)
- return read_RLE8(f, header, context, callback);
+ return read_RLE8(io, header, context, callback);
switch (header->bpp) {
case 1:
@@ -600,11 +635,11 @@ static int read_bitmap_pixels(FILE *f, struct bitmap_info_header *header,
case 2:
case 4:
case 8:
- return read_palette(f, header, context, callback);
+ return read_palette(io, header, context, callback);
case 16:
case 24:
case 32:
- return read_bitfields_or_rgb(f, header, context, callback);
+ return read_bitfields_or_rgb(io, header, context, callback);
}
return ENOSYS;
@@ -615,68 +650,19 @@ int GP_MatchBMP(const void *buf)
return !memcmp(buf, "BM", 2);
}
-int GP_OpenBMP(const char *src_path, FILE **f,
- GP_Size *w, GP_Size *h, GP_PixelType *pixel_type)
-{
- int err;
-
- *f = fopen(src_path, "rb");
-
- if (*f == NULL) {
- err = errno;
- GP_DEBUG(1, "Failed to open '%s' : %s",
- src_path, strerror(errno));
- goto err2;
- }
-
- int ch1 = fgetc(*f);
- int ch2 = fgetc(*f);
-
- if (ch1 != 'B' || ch2 != 'M') {
- GP_DEBUG(1, "Unexpected bitmap header 0x%02x (%c) 0x%02x (%c)",
- ch1, isascii(ch1) ? ch1 : ' ',
- ch2, isascii(ch2) ? ch2 : ' ');
- err = EIO;
- goto err1;
- }
-
- if (w != NULL || h != NULL || pixel_type != NULL) {
- struct bitmap_info_header header;
-
- if ((err = read_bitmap_header(*f, &header)))
- goto err1;
-
- if (w != NULL)
- *w = header.w;
-
- if (h != NULL)
- *h = header.h;
-
- if (pixel_type != NULL)
- *pixel_type = match_pixel_type(&header);
- }
-
- return 0;
-err1:
- fclose(*f);
-err2:
- errno = err;
- return 1;
-}
-
-GP_Context *GP_ReadBMP(FILE *f, GP_ProgressCallback *callback)
+GP_Context *GP_ReadBMP(GP_IO *io, GP_ProgressCallback *callback)
{
struct bitmap_info_header header;
GP_PixelType pixel_type;
GP_Context *context;
int err;
- if ((err = read_bitmap_header(f, &header)))
+ if ((err = read_bitmap_header(io, &header)))
goto err1;
if (header.w <= 0 || header.h == 0) {
GP_WARN("Width and/or Height is not > 0");
- err = EIO;
+ err = EINVAL;
goto err1;
}
@@ -705,7 +691,7 @@ GP_Context *GP_ReadBMP(FILE *f, GP_ProgressCallback *callback)
goto err1;
}
- if ((err = read_bitmap_pixels(f, &header, context, callback)))
+ if ((err = read_bitmap_pixels(io, &header, context, callback)))
goto err2;
return context;
@@ -718,14 +704,19 @@ err1:
GP_Context *GP_LoadBMP(const char *src_path, GP_ProgressCallback *callback)
{
- FILE *f;
+ GP_IO *io;
GP_Context *res;
+ int err;
- if (GP_OpenBMP(src_path, &f, NULL, NULL, NULL))
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
return NULL;
- res = GP_ReadBMP(f, callback);
- fclose(f);
+ res = GP_ReadBMP(io, callback);
+
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
return res;
}
diff --git a/libs/loaders/GP_BMP_RLE.h b/libs/loaders/GP_BMP_RLE.h
index 6f7645f..4c228fb 100644
--- a/libs/loaders/GP_BMP_RLE.h
+++ b/libs/loaders/GP_BMP_RLE.h
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -57,20 +57,34 @@ struct RLE {
/* current value */
int c;
+
+ GP_IO *io;
+
+ int buf_pos;
+ int buf_end;
+ uint8_t buf[512];
};
-#define DECLARE_RLE(name, iw, ih) struct RLE name = { +#define DECLARE_RLE(name, iw, ih, iio) struct RLE name = { .state = RLE_START, - .w = iw, .h = ih, - .x = 0, .y = 0, - .rep = 0+ .w = iw, .h = ih, + .x = 0, .y = 0, + .rep = 0, + .io = io, + .buf_pos = 0, + .buf_end = 0, }
-#define GETC(f, rle) do { - rle->c = fgetc(f); - - if (rle->c == EOF) - return EIO; +#define GETC(rle) do { + if (rle->buf_pos < rle->buf_end) { + rle->c = rle->buf[rle->buf_pos++]; + } else { + rle->buf_end = GP_IORead(rle->io, rle->buf, sizeof(rle->buf));+ if (rle->buf_end <= 0) + return EIO; + rle->c = rle->buf[0]; + rle->buf_pos = 1; + } } while (0)
static void RLE8_move(struct RLE *rle)
@@ -119,9 +133,9 @@ static int RLE8_end_of_bitmap(struct RLE *rle)
return 0;
}
-static int RLE8_repeat(FILE *f, uint8_t rep, struct RLE *rle)
+static int RLE8_repeat(uint8_t rep, struct RLE *rle)
{
- GETC(f, rle);
+ GETC(rle);
GP_DEBUG(4, "RLE Repeat %i x 0x%02x", rep, rle->c);
@@ -131,12 +145,14 @@ static int RLE8_repeat(FILE *f, uint8_t rep, struct RLE *rle)
return 0;
}
-static int RLE8_offset(FILE *f, struct RLE *rle)
+static int RLE8_offset(struct RLE *rle)
{
int x, y;
- x = fgetc(f);
- y = fgetc(f);
+ GETC(rle);
+ x = rle->c;
+ GETC(rle);
+ y = rle->c;
if (x == EOF || y == EOF)
return EIO;
@@ -154,9 +170,9 @@ static int RLE8_offset(FILE *f, struct RLE *rle)
return 0;
}
-static int RLE8_next_undecoded(FILE *f, struct RLE *rle)
+static int RLE8_next_undecoded(struct RLE *rle)
{
- GETC(f, rle);
+ GETC(rle);
RLE8_move(rle);
@@ -166,7 +182,7 @@ static int RLE8_next_undecoded(FILE *f, struct RLE *rle)
rle->state = RLE_START;
/* must be padded to odd number of bytes */
if (rle->flag)
- fgetc(f);
+ GETC(rle);
}
rle->move = 1;
@@ -188,9 +204,9 @@ static int RLE8_next_repeat(struct RLE *rle)
return 0;
}
-static int RLE8_esc(FILE *f, struct RLE *rle)
+static int RLE8_esc(struct RLE *rle)
{
- GETC(f, rle);
+ GETC(rle);
GP_DEBUG(4, "RLE ESC %02x", rle->c);
@@ -200,43 +216,43 @@ static int RLE8_esc(FILE *f, struct RLE *rle)
case 0x01:
return RLE8_end_of_bitmap(rle);
case 0x02:
- return RLE8_offset(f, rle);
+ return RLE8_offset(rle);
/* Undecoded sequence */
default:
GP_DEBUG(4, "RLE Undecoded x %i", rle->c);
rle->state = RLE_UNDECODED;
- rle->rep = rle->c;
+ rle->rep = rle->c;
rle->flag = rle->c % 2;
return 0;
}
}
-static int RLE8_start(FILE *f, struct RLE *rle)
+static int RLE8_start(struct RLE *rle)
{
- GETC(f, rle);
+ GETC(rle);
switch (rle->c) {
case 0x00:
- return RLE8_esc(f, rle);
+ return RLE8_esc(rle);
default:
- return RLE8_repeat(f, rle->c, rle);
+ return RLE8_repeat(rle->c, rle);
}
}
-static int RLE8_next(FILE *f, struct RLE *rle)
+static int RLE8_next(struct RLE *rle)
{
int err;
for (;;) {
switch (rle->state) {
case RLE_START:
- if ((err = RLE8_start(f, rle)))
+ if ((err = RLE8_start(rle)))
return err;
break;
case RLE_REPEAT:
return RLE8_next_repeat(rle);
case RLE_UNDECODED:
- return RLE8_next_undecoded(f, rle);
+ return RLE8_next_undecoded(rle);
case RLE_STOP:
return 0;
default:
@@ -247,18 +263,18 @@ static int RLE8_next(FILE *f, struct RLE *rle)
}
}
-static int read_RLE8(FILE *f, struct bitmap_info_header *header,
+static int read_RLE8(GP_IO *io, struct bitmap_info_header *header,
GP_Context *context, GP_ProgressCallback *callback)
{
uint32_t palette_size = get_palette_size(header);
GP_Pixel palette[get_palette_size(header)];
- DECLARE_RLE(rle, header->w, GP_ABS(header->h));
+ DECLARE_RLE(rle, header->w, GP_ABS(header->h), io);
int err;
- if ((err = read_bitmap_palette(f, header, palette)))
+ if ((err = read_bitmap_palette(io, header, palette)))
return err;
- if ((err = seek_pixels_offset(header, f)))
+ if ((err = seek_pixels_offset(io, header)))
return err;
int cnt = 0;
@@ -272,7 +288,7 @@ static int read_RLE8(FILE *f, struct bitmap_info_header *header,
GP_Fill(context, palette[0]);
for (;;) {
- if ((err = RLE8_next(f, &rle)))
+ if ((err = RLE8_next(&rle)))
return err;
if (rle.state == RLE_STOP)
diff --git a/libs/loaders/GP_GIF.c b/libs/loaders/GP_GIF.c
index 688f914..88bddee 100644
--- a/libs/loaders/GP_GIF.c
+++ b/libs/loaders/GP_GIF.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -38,7 +38,8 @@
#include "core/GP_Fill.h"
#include "core/GP_Debug.h"
-#include "GP_GIF.h"
+#include "loaders/GP_IO.h"
+#include "loaders/GP_GIF.h"
#ifdef HAVE_GIFLIB
@@ -61,39 +62,11 @@ int GP_MatchGIF(const void *buf)
return 0;
}
-int GP_OpenGIF(const char *src_path, void **f)
+static int gif_input_func(GifFileType* gif, GifByteType* bytes, int size)
{
- GifFileType *gf;
-
- errno = 0;
-
-#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
- gf = DGifOpenFileName(src_path, NULL);
-#else
- gf = DGifOpenFileName(src_path);
-#endif
+ GP_IO *io = gif->UserData;
- if (gf == NULL) {
- /*
- * The giflib uses open() so when we got a failure and errno
- * is set => open() has failed.
- *
- * When errno is not set the file content was not valid so we
- * set errno to EIO.
- */
- if (errno == 0)
- errno = EIO;
-
- return 1;
- }
-
- GP_DEBUG(1, "Have GIF image %ix%i, %i colors, %i bpp",
- gf->SWidth, gf->SHeight, gf->SColorResolution,
- gf->SColorMap ? gf->SColorMap->BitsPerPixel : -1);
-
- *f = gf;
-
- return 0;
+ return GP_IORead(io, bytes, size);
}
static const char *rec_type_name(GifRecordType rec_type)
@@ -255,15 +228,41 @@ static inline unsigned int interlace_real_y(GifFileType *gf, unsigned int y)
return 0;
}
-GP_Context *GP_ReadGIF(void *f, GP_ProgressCallback *callback)
+GP_Context *GP_ReadGIF(GP_IO *io, GP_ProgressCallback *callback)
{
- GifFileType *gf = f;
+ GifFileType *gf;
GifRecordType rec_type;
GP_Context *res = NULL;
GP_Pixel bg;
int32_t x, y;
int err;
+ errno = 0;
+#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
+ gf = DGifOpen(io, gif_input_func, NULL);
+#else
+ gf = DGifOpen(io, gif_input_func);
+#endif
+
+ if (gf == NULL) {
+ /*
+ * The giflib uses open() so when we got a failure and errno
+ * is set => open() has failed.
+ *
+ * When errno is not set the file content was not valid so we
+ * set errno to EIO.
+ */
+ if (errno == 0)
+ errno = EIO;
+
+ return NULL;
+ }
+
+ GP_DEBUG(1, "Have GIF image %ix%i, %i colors, %i bpp",
+ gf->SWidth, gf->SHeight, gf->SColorResolution,
+ gf->SColorMap ? gf->SColorMap->BitsPerPixel : -1);
+
+
do {
if (DGifGetRecordType(gf, &rec_type) != GIF_OK) {
//TODO: error handling
@@ -361,12 +360,21 @@ err1:
GP_Context *GP_LoadGIF(const char *src_path, GP_ProgressCallback *callback)
{
- void *f;
+ GP_IO *io;
+ GP_Context *res;
+ int err;
- if (GP_OpenGIF(src_path, &f))
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
return NULL;
- return GP_ReadGIF(f, callback);
+ res = GP_ReadGIF(io, callback);
+
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
+
+ return res;
}
#else
@@ -377,14 +385,7 @@ int GP_MatchGIF(const void GP_UNUSED(*buf))
return -1;
}
-int GP_OpenGIF(const char GP_UNUSED(*src_path),
- void GP_UNUSED(**f))
-{
- errno = ENOSYS;
- return 1;
-}
-
-GP_Context *GP_ReadGIF(void GP_UNUSED(*f),
+GP_Context *GP_ReadGIF(GP_IO GP_UNUSED(*io),
GP_ProgressCallback GP_UNUSED(*callback))
{
errno = ENOSYS;
diff --git a/libs/loaders/GP_IO.c b/libs/loaders/GP_IO.c
new file mode 100644
index 0000000..a1409a6
--- /dev/null
+++ b/libs/loaders/GP_IO.c
@@ -0,0 +1,432 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdarg.h>
+
+#include <core/GP_ByteOrder.h>
+#include <core/GP_Debug.h>
+#include <core/GP_Common.h>
+
+#include "loaders/GP_IO.h"
+
+struct file_io {
+ int fd;
+};
+
+static ssize_t file_read(GP_IO *self, void *buf, size_t size)
+{
+ struct file_io *file_io = GP_IO_PRIV(self);
+
+ return read(file_io->fd, buf, size);
+}
+
+static ssize_t file_write(GP_IO *self, void *buf, size_t size)
+{
+ struct file_io *file_io = GP_IO_PRIV(self);
+
+ return write(file_io->fd, buf, size);
+}
+
+static off_t file_seek(GP_IO *self, off_t off, enum GP_IOWhence whence)
+{
+ struct file_io *file_io = GP_IO_PRIV(self);
+
+ switch (whence) {
+ case GP_IO_SEEK_SET:
+ case GP_IO_SEEK_CUR:
+ case GP_IO_SEEK_END:
+ break;
+ default:
+ GP_WARN("Invalid whence");
+ return (off_t)-1;
+ }
+
+ return lseek(file_io->fd, off, whence);
+}
+
+static int file_close(GP_IO *self)
+{
+ struct file_io *file_io = GP_IO_PRIV(self);
+ int fd;
+
+ GP_DEBUG(1, "Closing IOFile");
+
+ fd = file_io->fd;
+ free(self);
+
+ return close(fd);
+}
+
+GP_IO *GP_IOFile(const char *path, enum GP_IOFileMode mode)
+{
+ int err, flags;
+ GP_IO *io;
+ struct file_io *file_io;
+
+ GP_DEBUG(1, "Creating IOFile '%s'", path);
+
+ io = malloc(sizeof(GP_IO) + sizeof(struct file_io));
+
+ if (!io) {
+ GP_DEBUG(1, "Malloc failed :(");
+ err = ENOMEM;
+ goto err0;
+ }
+
+ switch (mode) {
+ case GP_IO_WRONLY:
+ flags = O_CREAT | O_WRONLY;
+ break;
+ case GP_IO_RDONLY:
+ flags = O_RDONLY;
+ break;
+ case GP_IO_RDWR:
+ flags = O_CREAT | O_RDWR;
+ break;
+ }
+
+ file_io = GP_IO_PRIV(io);
+ file_io->fd = open(path, flags, 0666);
+
+ if (file_io->fd < 0) {
+ err = errno;
+ GP_DEBUG(1, "Failed to open '%s': %s", path, strerror(errno));
+ goto err1;
+ }
+
+ io->mark = 0;
+
+ io->Seek = file_seek;
+ io->Read = file_read;
+ io->Write = file_write;
+
+ if (mode == GP_IO_RDONLY)
+ io->Write = NULL;
+
+ if (mode == GP_IO_WRONLY)
+ io->Read = NULL;
+
+ io->Close = file_close;
+
+ return io;
+err1:
+ free(io);
+err0:
+ errno = err;
+ return NULL;
+}
+
+struct mem_io {
+ uint8_t *buf;
+ size_t size;
+ size_t pos;
+ void (*free)(void *);
+};
+
+static ssize_t mem_read(GP_IO *io, void *buf, size_t size)
+{
+ struct mem_io *mem_io = GP_IO_PRIV(io);
+ size_t rest = mem_io->size - mem_io->pos;
+ ssize_t ret = GP_MIN(rest, size);
+
+ if (ret <= 0) {
+ errno = EIO;
+ return 0;
+ }
+
+ memcpy(buf, mem_io->buf + mem_io->pos, ret);
+ mem_io->pos += ret;
+
+ return ret;
+}
+
+static off_t mem_seek(GP_IO *io, off_t off, enum GP_IOWhence whence)
+{
+ struct mem_io *mem_io = GP_IO_PRIV(io);
+
+ switch (whence) {
+ case GP_IO_SEEK_CUR:
+ if (off + mem_io->pos > mem_io->size) {
+ errno = EINVAL;
+ return (off_t)-1;
+ }
+
+ mem_io->pos += off;
+ break;
+ case GP_IO_SEEK_SET:
+ if (off < 0 || off > (off_t)mem_io->pos) {
+ errno = EINVAL;
+ return (off_t)-1;
+ }
+ mem_io->pos = off;
+ break;
+ case GP_IO_SEEK_END:
+ if (off) {
+ errno = EINVAL;
+ return (off_t)-1;
+ }
+ mem_io->pos = mem_io->size;
+ break;
+ default:
+ GP_WARN("Invalid whence");
+ return (off_t)-1;
+ }
+
+ return mem_io->pos;
+}
+
+static int mem_close(GP_IO *io)
+{
+ struct mem_io *mem_io = GP_IO_PRIV(io);
+
+ GP_DEBUG(1, "Closing IOMem");
+
+ if (mem_io->free)
+ mem_io->free(mem_io->buf);
+
+ free(io);
+
+ return 0;
+}
+
+GP_IO *GP_IOMem(void *buf, size_t size, void (*free)(void *))
+{
+ GP_IO *io;
+ struct mem_io *mem_io;
+
+ GP_DEBUG(1, "Creating IOMem %p size=%zu", buf, size);
+
+ io = malloc(sizeof(GP_IO) + sizeof(*mem_io));
+
+ if (!io) {
+ GP_DEBUG(1, "Malloc failed :(");
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ io->Read = mem_read;
+ io->Seek = mem_seek;
+ io->Close = mem_close;
+ io->Write = NULL;
+
+ mem_io = GP_IO_PRIV(io);
+
+ mem_io->free = free;
+ mem_io->buf = buf;
+ mem_io->size = size;
+ mem_io->pos = 0;
+
+ return io;
+}
+
+int GP_IOMark(GP_IO *self, enum GP_IOMarkTypes type)
+{
+ off_t ret;
+
+ switch (type) {
+ case GP_IO_MARK:
+ ret = GP_IOSeek(self, 0, GP_IO_SEEK_CUR);
+ break;
+ case GP_IO_REWIND:
+ ret = GP_IOSeek(self, self->mark, SEEK_SET);
+ break;
+ default:
+ GP_WARN("Invalid mark type");
+ return -1;
+ }
+
+ if (ret == (off_t)-1) {
+ GP_WARN("Failed to lseek IO Stream");
+ return -1;
+ }
+
+ self->mark = ret;
+ return 0;
+}
+
+off_t GP_IOSize(GP_IO *io)
+{
+ off_t cur = GP_IOTell(io);
+ off_t ret;
+
+ ret = GP_IOSeek(io, 0, GP_IO_SEEK_END);
+
+ if (ret == (off_t)-1)
+ return ret;
+
+ GP_IOSeek(io, cur, GP_IO_SEEK_SET);
+
+ GP_DEBUG(2, "IO Size = %lli", (long long)ret);
+
+ return ret;
+}
+
+int GP_IOFill(GP_IO *io, void *buf, size_t size)
+{
+ size_t read = 0;
+ int ret;
+
+ do {
+ ret = GP_IORead(io, (char*)buf + read, size - read);
+
+ if (ret <= 0) {
+ GP_DEBUG(1, "Failed to fill buffer");
+ return 1;
+ }
+
+ read += ret;
+
+ } while (read < size);
+
+ return 0;
+}
+
+#define TYPE(x) ((x) & GP_IO_TYPE_MASK)
+#define VAL(x) ((x) & ~GP_IO_TYPE_MASK)
+
+static unsigned int readf_size(uint16_t *types)
+{
+ unsigned int size = 0;
+
+ while (*types != GP_IO_END) {
+ switch (TYPE(*types)) {
+ case GP_IO_CONST:
+ case GP_IO_BYTE:
+ size++;
+ break;
+ case GP_IO_L2:
+ case GP_IO_B2:
+ size += 2;
+ break;
+ case GP_IO_L4:
+ case GP_IO_B4:
+ size += 4;
+ break;
+ case GP_IO_ARRAY:
+ case GP_IO_IGN:
+ size+=VAL(*types);
+ break;
+ }
+ types++;
+ }
+
+ return size;
+}
+
+static int needs_swap(uint16_t type)
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ if (type == GP_IO_L2 || type == GP_IO_L4)
+ return 1;
+ return 0;
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ if (type == GP_IO_B2 || type == GP_IO_B4)
+ return 1;
+ return 0;
+#else
+# error Unknown Endianity
+#endif
+}
+
+int GP_IOReadF(GP_IO *self, uint16_t *types, ...)
+{
+ unsigned int size = readf_size(types);
+ uint8_t buffer[size], *buf = buffer;
+ int ret;
+ va_list va;
+ uint8_t *ptr;
+
+ buf[0] = 0;
+
+ if (GP_IOFill(self, buf, size))
+ return -1;
+
+ ret = 0;
+ va_start(va, types);
+
+ while (*types != GP_IO_END) {
+ switch (TYPE(*types)) {
+ case GP_IO_CONST:
+ //TODO: Seek back?
+ if (VAL(*types) != *buf) {
+ errno = EINVAL;
+ goto end;
+ }
+ buf++;
+ break;
+ case GP_IO_BYTE:
+ ptr = va_arg(va, uint8_t*);
+ *ptr = *buf;
+ buf++;
+ break;
+ case GP_IO_L2:
+ case GP_IO_B2:
+ ptr = va_arg(va, uint8_t*);
+
+ if (needs_swap(*types)) {
+ ptr[0] = buf[1];
+ ptr[1] = buf[0];
+ } else {
+ ptr[0] = buf[0];
+ ptr[1] = buf[1];
+ }
+ buf += 2;
+ break;
+ case GP_IO_L4:
+ case GP_IO_B4:
+ ptr = va_arg(va, uint8_t*);
+
+ if (needs_swap(*types)) {
+ ptr[0] = buf[3];
+ ptr[1] = buf[2];
+ ptr[2] = buf[1];
+ ptr[3] = buf[0];
+ } else {
+ ptr[0] = buf[0];
+ ptr[1] = buf[1];
+ ptr[2] = buf[2];
+ ptr[3] = buf[3];
+ }
+ buf += 4;
+ break;
+ case GP_IO_ARRAY:
+ ptr = va_arg(va, void*);
+ memcpy(ptr, buf, VAL(*types));
+ case GP_IO_IGN:
+ buf += VAL(*types);
+ break;
+ }
+
+ types++;
+ ret++;
+ }
+
+end:
+ va_end(va);
+ return ret;
+}
diff --git a/libs/loaders/GP_JP2.c b/libs/loaders/GP_JP2.c
index 2a8d11d..ef412ca 100644
--- a/libs/loaders/GP_JP2.c
+++ b/libs/loaders/GP_JP2.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -36,10 +36,6 @@
#include "GP_JP2.h"
-#ifdef HAVE_OPENJPEG
-
-#include <openjpeg-2.0/openjpeg.h>
-
#define JP2_SIG "x00x00x00x0cjPx20x20x0dx0ax87x0a"
#define JP2_SIG_LEN 12
@@ -48,24 +44,9 @@ int GP_MatchJP2(const void *buf)
return !memcmp(buf, JP2_SIG, JP2_SIG_LEN);
}
-int GP_OpenJP2(const char *src_path, FILE **f)
-{
- int err;
-
- *f = fopen(src_path, "rb");
-
- if (*f == NULL) {
- err = errno;
- GP_DEBUG(1, "Failed to open '%s' : %s",
- src_path, strerror(errno));
- errno = err;
- return 1;
- }
-
- //TODO: check signature and rewind the stream
+#ifdef HAVE_OPENJPEG
- return 0;
-}
+#include <openjpeg-2.0/openjpeg.h>
static void jp2_err_callback(const char *msg, void *priv)
{
@@ -81,11 +62,8 @@ static void jp2_warn_callback(const char *msg, void *priv)
static void jp2_info_callback(const char *msg, void *priv)
{
- GP_ProgressCallback *callback = priv;
-
+ (void) priv;
GP_DEBUG(1, "openjpeg: %s", msg);
-
- GP_ProgressCallbackReport(callback, 100, 100, 100);
}
static const char *color_space_name(OPJ_COLOR_SPACE color_space)
@@ -106,7 +84,12 @@ static const char *color_space_name(OPJ_COLOR_SPACE color_space)
}
}
-GP_Context *GP_ReadJP2(FILE *f, GP_ProgressCallback *callback)
+static OPJ_SIZE_T jp2_io_read(void *buf, OPJ_SIZE_T size, void *io)
+{
+ return GP_IORead(io, buf, size);
+}
+
+GP_Context *GP_ReadJP2(GP_IO *io, GP_ProgressCallback *callback)
{
opj_dparameters_t params;
opj_codec_t *codec;
@@ -138,7 +121,7 @@ GP_Context *GP_ReadJP2(FILE *f, GP_ProgressCallback *callback)
goto err1;
}
- stream = opj_stream_create_default_file_stream(f, OPJ_TRUE);
+ stream = opj_stream_default_create(OPJ_TRUE);
if (!stream) {
GP_DEBUG(1, "opj_stream_create_default_file_stream faled");
@@ -146,6 +129,10 @@ GP_Context *GP_ReadJP2(FILE *f, GP_ProgressCallback *callback)
goto err1;
}
+ //TODO: Do we need seek and skip?
+ opj_stream_set_read_function(stream, jp2_io_read);
+ opj_stream_set_user_data(stream, io);
+
if (!opj_read_header(stream, codec, &img)) {
GP_DEBUG(1, "opj_read_header failed");
err = EINVAL;
@@ -197,6 +184,8 @@ GP_Context *GP_ReadJP2(FILE *f, GP_ProgressCallback *callback)
goto err3;
}
+ GP_ProgressCallbackReport(callback, 0, 100, 100);
+
if (!opj_decode(codec, stream, img)) {
GP_DEBUG(1, "opj_decode failed");
err = EINVAL;
@@ -238,35 +227,27 @@ err0:
GP_Context *GP_LoadJP2(const char *src_path, GP_ProgressCallback *callback)
{
- FILE *f;
+ GP_IO *io;
GP_Context *res;
+ int err;
- if (GP_OpenJP2(src_path, &f))
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
return NULL;
- res = GP_ReadJP2(f, callback);
+ res = GP_ReadJP2(io, callback);
- fclose(f);
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
return res;
}
#else
-int GP_MatchJP2(const void GP_UNUSED(*buf))
-{
- errno = ENOSYS;
- return -1;
-}
-
-int GP_OpenJP2(const char GP_UNUSED(*src_path), FILE GP_UNUSED(**f))
-{
- errno = ENOSYS;
- return 1;
-}
-
-GP_Context *GP_ReadJP2(FILE GP_UNUSED(*f),
- GP_ProgressCallback GP_UNUSED(*callback))
+GP_Context *GP_ReadJP2(GP_IO GP_UNUSED(*io),
+ GP_ProgressCallback GP_UNUSED(*callback))
{
errno = ENOSYS;
return NULL;
diff --git a/libs/loaders/GP_JPG.c b/libs/loaders/GP_JPG.c
index aa6b1c4..8448ba0 100644
--- a/libs/loaders/GP_JPG.c
+++ b/libs/loaders/GP_JPG.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -56,25 +56,6 @@ int GP_MatchJPG(const void *buf)
return !memcmp(buf, JPEG_SIGNATURE, JPEG_SIGNATURE_LEN);
}
-int GP_OpenJPG(const char *src_path, FILE **f)
-{
- int err;
-
- *f = fopen(src_path, "rb");
-
- if (*f == NULL) {
- err = errno;
- GP_DEBUG(1, "Failed to open '%s' : %s",
- src_path, strerror(errno));
- errno = err;
- return 1;
- }
-
- //TODO: check signature and rewind the stream
-
- return 0;
-}
-
struct my_jpg_err {
struct jpeg_error_mgr error_mgr;
jmp_buf setjmp_buf;
@@ -155,11 +136,57 @@ static int load_cmyk(struct jpeg_decompress_struct *cinfo, GP_Context *ret,
return 0;
}
-GP_Context *GP_ReadJPG(FILE *f, GP_ProgressCallback *callback)
+
+struct my_source_mgr {
+ struct jpeg_source_mgr mgr;
+ void *buffer;
+ size_t size;
+ GP_IO *io;
+};
+
+static void dummy(j_decompress_ptr GP_UNUSED(cinfo))
+{
+}
+
+static boolean fill_input_buffer(struct jpeg_decompress_struct *cinfo)
+{
+ int ret;
+ struct my_source_mgr* src = (void*)cinfo->src;
+
+ ret = GP_IORead(src->io, src->buffer, src->size);
+
+ if (ret < 0) {
+ GP_WARN("Failed to fill buffer");
+ return 0;
+ }
+
+ src->mgr.next_input_byte = src->buffer;
+ src->mgr.bytes_in_buffer = src->size;
+ return 1;
+}
+
+static void skip_input_data(struct jpeg_decompress_struct *cinfo, long num_bytes)
+{
+ struct my_source_mgr* src = (void*)cinfo->src;
+
+ GP_DEBUG(3, "Skipping %li bytes", num_bytes);
+
+ if (src->mgr.bytes_in_buffer < (unsigned long)num_bytes) {
+ src->mgr.bytes_in_buffer = 0;
+ GP_IOSeek(src->io, num_bytes - src->mgr.bytes_in_buffer, GP_IO_SEEK_CUR);
+ } else {
+ src->mgr.bytes_in_buffer -= num_bytes;
+ src->mgr.next_input_byte += num_bytes;
+ }
+}
+
+GP_Context *GP_ReadJPG(GP_IO *io, GP_ProgressCallback *callback)
{
struct jpeg_decompress_struct cinfo;
+ struct my_source_mgr src;
struct my_jpg_err my_err;
GP_Context *ret = NULL;
+ uint8_t buffer[1024];
int err;
cinfo.err = jpeg_std_error(&my_err.error_mgr);
@@ -171,7 +198,19 @@ GP_Context *GP_ReadJPG(FILE *f, GP_ProgressCallback *callback)
}
jpeg_create_decompress(&cinfo);
- jpeg_stdio_src(&cinfo, f);
+
+ /* Initialize custom source manager */
+ src.mgr.init_source = dummy;
+ src.mgr.resync_to_restart = jpeg_resync_to_restart;
+ src.mgr.term_source = dummy;
+ src.mgr.fill_input_buffer = fill_input_buffer;
+ src.mgr.skip_input_data = skip_input_data;
+ src.mgr.bytes_in_buffer = 0;
+ src.mgr.next_input_byte = NULL;
+ src.io = io;
+ src.buffer = buffer;
+ src.size = sizeof(buffer);
+ cinfo.src = (void*)&src;
jpeg_read_header(&cinfo, TRUE);
@@ -245,15 +284,19 @@ err1:
GP_Context *GP_LoadJPG(const char *src_path, GP_ProgressCallback *callback)
{
- FILE *f;
+ GP_IO *io;
GP_Context *res;
+ int err;
- if (GP_OpenJPG(src_path, &f))
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
return NULL;
- res = GP_ReadJPG(f, callback);
+ res = GP_ReadJPG(io, callback);
- fclose(f);
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
return res;
}
@@ -333,15 +376,15 @@ err1:
int GP_LoadJPGMetaData(const char *src_path, GP_MetaData *data)
{
- FILE *f;
- int ret;
+ //FILE *f;
+ int ret = -1;
- if (GP_OpenJPG(src_path, &f))
- return 1;
+ //if (GP_OpenJPG(src_path, &f))
+ // return 1;
- ret = GP_ReadJPGMetaData(f, data);
+ //ret = GP_ReadJPGMetaData(f, data);
- fclose(f);
+ //fclose(f);
return ret;
}
diff --git a/libs/loaders/GP_PNG.c b/libs/loaders/GP_PNG.c
index 384d599..71812ba 100644
--- a/libs/loaders/GP_PNG.c
+++ b/libs/loaders/GP_PNG.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -49,46 +49,6 @@ int GP_MatchPNG(const void *buf)
return !png_sig_cmp(buf, 0, 8);
}
-int GP_OpenPNG(const char *src_path, FILE **f)
-{
- uint8_t sig[8];
- int err;
-
- *f = fopen(src_path, "r");
-
- if (*f == NULL) {
- err = errno;
- GP_DEBUG(1, "Failed to open '%s' : %s",
- src_path, strerror(errno));
- goto err1;
- }
-
- if (fread(sig, 1, 8, *f) <= 0) {
- err = EIO;
- GP_DEBUG(1, "Failed to read '%s' : %s",
- src_path, strerror(errno));
- goto err2;
- }
-
- if (png_sig_cmp(sig, 0, 8)) {
- GP_DEBUG(1, "Invalid file header, '%s' not a PNG image?",
- src_path);
- err = EINVAL;
- goto err2;
- }
-
- GP_DEBUG(1, "Found PNG signature in '%s'", src_path);
-
- rewind(*f);
-
- return 0;
-err2:
- fclose(*f);
-err1:
- errno = err;
- return 1;
-}
-
static const char *interlace_type_name(int interlace)
{
switch (interlace) {
@@ -101,7 +61,18 @@ static const char *interlace_type_name(int interlace)
}
}
-GP_Context *GP_ReadPNG(FILE *f, GP_ProgressCallback *callback)
+static void read_data(png_structp png_ptr, png_bytep data, png_size_t len)
+{
+ int res;
+ GP_IO *io = png_get_io_ptr(png_ptr);
+
+ res = GP_IORead(io, data, len);
+
+ if (res < 0 || (png_size_t)res != len)
+ png_error(png_ptr, "Read Error");
+}
+
+GP_Context *GP_ReadPNG(GP_IO *io, GP_ProgressCallback *callback)
{
png_structp png;
png_infop png_info = NULL;
@@ -135,7 +106,8 @@ GP_Context *GP_ReadPNG(FILE *f, GP_ProgressCallback *callback)
goto err2;
}
- png_init_io(png, f);
+ //png_init_io(png, f);
+ png_set_read_fn(png, io, read_data);
png_set_sig_bytes(png, 0);
png_read_info(png, png_info);
@@ -291,15 +263,19 @@ err1:
GP_Context *GP_LoadPNG(const char *src_path, GP_ProgressCallback *callback)
{
- FILE *f;
+ GP_IO *io;
GP_Context *res;
+ int err;
- if (GP_OpenPNG(src_path, &f))
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
return NULL;
- res = GP_ReadPNG(f, callback);
+ res = GP_ReadPNG(io, callback);
- fclose(f);
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
return res;
}
@@ -413,8 +389,8 @@ int GP_LoadPNGMetaData(const char *src_path, GP_MetaData *data)
FILE *f;
int ret;
- if (GP_OpenPNG(src_path, &f))
- return 1;
+// if (GP_OpenPNG(src_path, &f))
+// return 1;
ret = GP_ReadPNGMetaData(f, data);
@@ -636,14 +612,7 @@ int GP_MatchPNG(const void GP_UNUSED(*buf))
return -1;
}
-int GP_OpenPNG(const char GP_UNUSED(*src_path),
- FILE GP_UNUSED(**f))
-{
- errno = ENOSYS;
- return 1;
-}
-
-GP_Context *GP_ReadPNG(FILE GP_UNUSED(*f),
+GP_Context *GP_ReadPNG(GP_IO GP_UNUSED(*io),
GP_ProgressCallback GP_UNUSED(*callback))
{
errno = ENOSYS;
diff --git a/libs/loaders/GP_PNM.c b/libs/loaders/GP_PNM.c
index de81c4b..1a17e53 100644
--- a/libs/loaders/GP_PNM.c
+++ b/libs/loaders/GP_PNM.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -156,12 +156,67 @@ enum state {
S_INT,
};
-static int load_header(FILE *f, struct pnm_header *header)
+/*
+ * Simple buffer implementation on the top of the GP_IO
+ */
+struct buf {
+ uint8_t buf[100];
+ unsigned int buf_end;
+ unsigned int buf_pos;
+ GP_IO *io;
+};
+
+#define DECLARE_BUFFER(name, bio) + struct buf name = {.buf_end = 0, .buf_pos = 0, .io = bio}
+
+static int getb(struct buf *buf)
+{
+ int ret;
+
+ if (buf->buf_pos < buf->buf_end)
+ return buf->buf[buf->buf_pos++];
+
+ ret = GP_IORead(buf->io, buf->buf, sizeof(buf->buf));
+
+ if (ret <= 0)
+ return EOF;
+
+ buf->buf_pos = 1;
+ buf->buf_end = ret;
+
+ return buf->buf[0];
+}
+
+static void ungetb(struct buf *buf, uint8_t byte)
+{
+ buf->buf[--buf->buf_pos] = byte;
+}
+
+static int fillb(struct buf *buf, void *ptr, size_t size)
+{
+ unsigned int buffered = buf->buf_end - buf->buf_pos;
+
+ if (buffered) {
+ unsigned int to_copy = GP_MIN(buffered, size);
+ memcpy(ptr, buf->buf + buf->buf_pos, to_copy);
+ buf->buf_pos += to_copy;
+ }
+
+ //TODO: refill buffer if request < 128
+ if (size > buffered) {
+ return GP_IOFill(buf->io, (char*)ptr + buffered,
+ size - buffered);
+ }
+
+ return 0;
+}
+
+static int load_header(struct buf *buf, struct pnm_header *header)
{
int h1, h2, c, state = S_START, val = 0, i = 0, err;
- h1 = fgetc(f);
- h2 = fgetc(f);
+ h1 = getb(buf);
+ h2 = getb(buf);
if (h1 == EOF || h2 == EOF) {
GP_DEBUG(1, "Failed to read header");
@@ -180,7 +235,7 @@ static int load_header(FILE *f, struct pnm_header *header)
header->w = 0;
for (;;) {
- c = fgetc(f);
+ c = getb(buf);
if (c == EOF) {
err = EIO;
@@ -231,7 +286,7 @@ static int load_header(FILE *f, struct pnm_header *header)
header->depth = val;
goto out;
}
- ungetc(c, f);
+ ungetb(buf, c);
state = S_START;
break;
}
@@ -252,13 +307,13 @@ err:
/*
* ASCII data parser
*/
-static int get_ascii_int(FILE *f, int *val)
+static int get_ascii_int(struct buf *buf, int *val)
{
int c, in_number = 0;
*val = 0;
for (;;) {
- c = getc_unlocked(f);
+ c = getb(buf);
switch (c) {
case EOF:
@@ -309,7 +364,8 @@ static inline int write_ascii_byte(FILE *f, uint8_t byte)
/*
* The PBM ASCII has the values inverted
*/
-static int load_ascii_g1_inv(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
+static int load_ascii_g1_inv(struct buf *buf, GP_Context *ctx,
+ GP_ProgressCallback *cb)
{
uint32_t x, y;
int val, err;
@@ -317,7 +373,7 @@ static int load_ascii_g1_inv(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
for (y = 0; y < ctx->h; y++) {
for (x = 0; x < ctx->w; x++) {
- if ((err = get_ascii_int(f, &val)))
+ if ((err = get_ascii_int(buf, &val)))
return err;
GP_PutPixel_Raw_1BPP_LE(ctx, x, y, !val);
@@ -336,7 +392,8 @@ static int load_ascii_g1_inv(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
//TODO: This is temporary till blit works with bitendian
#include "core/GP_BitSwap.h"
-static int load_raw_g1_inv(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
+static int load_raw_g1_inv(struct buf *buf, GP_Context *ctx,
+ GP_ProgressCallback *cb)
{
uint32_t x, y;
uint8_t *addr;
@@ -345,7 +402,7 @@ static int load_raw_g1_inv(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
for (y = 0; y < ctx->h; y++) {
for (x = 0; x < ctx->w; x+=8) {
- if ((val = fgetc(f)) == EOF)
+ if ((val = getb(buf)) == EOF)
return EIO;
addr = GP_PIXEL_ADDR(ctx, x, y);
@@ -362,7 +419,8 @@ static int load_raw_g1_inv(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
return 0;
}
-static int load_ascii_g1(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
+static int load_ascii_g1(struct buf *buf, GP_Context *ctx,
+ GP_ProgressCallback *cb)
{
uint32_t x, y;
int val, err;
@@ -370,11 +428,11 @@ static int load_ascii_g1(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
for (y = 0; y < ctx->h; y++) {
for (x = 0; x < ctx->w; x++) {
- if ((err = get_ascii_int(f, &val)))
+ if ((err = get_ascii_int(buf, &val)))
return err;
if (val > 1) {
- GP_WARN("Value too large for 2BPP (%i)", val);
+ GP_WARN("Value too large for 1BPP (%i)", val);
val = 1;
}
@@ -391,7 +449,8 @@ static int load_ascii_g1(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
return 0;
}
-static int load_ascii_g2(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
+static int load_ascii_g2(struct buf *buf, GP_Context *ctx,
+ GP_ProgressCallback *cb)
{
uint32_t x, y;
int val, err;
@@ -399,7 +458,7 @@ static int load_ascii_g2(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
for (y = 0; y < ctx->h; y++) {
for (x = 0; x < ctx->w; x++) {
- if ((err = get_ascii_int(f, &val)))
+ if ((err = get_ascii_int(buf, &val)))
return err;
if (val > 3) {
@@ -420,7 +479,8 @@ static int load_ascii_g2(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
return 0;
}
-static int load_ascii_g4(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
+static int load_ascii_g4(struct buf *buf, GP_Context *ctx,
+ GP_ProgressCallback *cb)
{
uint32_t x, y;
int val, err;
@@ -428,12 +488,12 @@ static int load_ascii_g4(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
for (y = 0; y < ctx->h; y++) {
for (x = 0; x < ctx->w; x++) {
- if ((err = get_ascii_int(f, &val)))
+ if ((err = get_ascii_int(buf, &val)))
return err;
if (val > 15) {
GP_WARN("Value too large for 4BPP (%i)", val);
- val = 3;
+ val = 15;
}
GP_PutPixel_Raw_4BPP_LE(ctx, x, y, val);
@@ -449,7 +509,8 @@ static int load_ascii_g4(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
return 0;
}
-static int load_ascii_g8(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
+static int load_ascii_g8(struct buf *buf, GP_Context *ctx,
+ GP_ProgressCallback *cb)
{
uint32_t x, y;
int val, err;
@@ -457,12 +518,12 @@ static int load_ascii_g8(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
for (y = 0; y < ctx->h; y++) {
for (x = 0; x < ctx->w; x++) {
- if ((err = get_ascii_int(f, &val)))
+ if ((err = get_ascii_int(buf, &val)))
return err;
- if (val > 15) {
- GP_WARN("Value too large for 4BPP (%i)", val);
- val = 3;
+ if (val > 255) {
+ GP_WARN("Value too large for 8BPP (%i)", val);
+ val = 255;
}
GP_PutPixel_Raw_8BPP(ctx, x, y, val);
@@ -478,14 +539,15 @@ static int load_ascii_g8(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
return 0;
}
-static int load_bin_g8(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
+static int load_bin_g8(struct buf *buf, GP_Context *ctx,
+ GP_ProgressCallback *cb)
{
uint32_t y;
for (y = 0; y < ctx->h; y++) {
uint8_t *addr = GP_PIXEL_ADDR(ctx, 0, y);
- if (fread(addr, ctx->w, 1, f) != 1)
+ if (fillb(buf, addr, ctx->w))
return errno;
if (GP_ProgressCallbackReport(cb, y, ctx->h, ctx->w)) {
@@ -498,7 +560,8 @@ static int load_bin_g8(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
return 0;
}
-static int load_ascii_rgb888(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
+static int load_ascii_rgb888(struct buf *buf, GP_Context *ctx,
+ GP_ProgressCallback *cb)
{
uint32_t x, y;
int r, g, b, err;
@@ -506,7 +569,7 @@ static int load_ascii_rgb888(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
for (y = 0; y < ctx->h; y++) {
for (x = 0; x < ctx->w; x++) {
- if ((err = get_ascii_int(f, &r)))
+ if ((err = get_ascii_int(buf, &r)))
return err;
if (r > 255) {
@@ -514,7 +577,7 @@ static int load_ascii_rgb888(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
r = 255;
}
- if ((err = get_ascii_int(f, &g)))
+ if ((err = get_ascii_int(buf, &g)))
return err;
if (g > 255) {
@@ -522,7 +585,7 @@ static int load_ascii_rgb888(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
g = 255;
}
- if ((err = get_ascii_int(f, &b)))
+ if ((err = get_ascii_int(buf, &b)))
return err;
if (b > 255) {
@@ -544,14 +607,15 @@ static int load_ascii_rgb888(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
return 0;
}
-static int load_bin_rgb888(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb)
+static int load_bin_rgb888(struct buf *buf, GP_Context *ctx,
+ GP_ProgressCallback *cb)
{
uint32_t y, x;
for (y = 0; y < ctx->h; y++) {
uint8_t *addr = GP_PIXEL_ADDR(ctx, 0, y);
- if (fread(addr, ctx->w * 3, 1, f) != 1)
+ if (fillb(buf, addr, ctx->w * 3))
return errno;
for (x = 0; x < ctx->w; x++)
@@ -598,26 +662,7 @@ static int save_ascii(FILE *f, const GP_Context *ctx,
return 0;
}
-static FILE *read_header(const char *src_path, struct pnm_header *header)
-{
- FILE *f;
- int err;
-
- f = fopen(src_path, "r");
-
- if (f == NULL)
- return NULL;
-
- if ((err = load_header(f, header))) {
- fclose(f);
- errno = err;
- return NULL;
- }
-
- return f;
-}
-
-static GP_Context *read_bitmap(FILE *f, struct pnm_header *header, int flag,
+static GP_Context *read_bitmap(struct buf *buf, struct pnm_header *header,
GP_ProgressCallback *callback)
{
GP_Context *ret;
@@ -637,38 +682,53 @@ static GP_Context *read_bitmap(FILE *f, struct pnm_header *header, int flag,
}
if (header->magic == '1')
- err = load_ascii_g1_inv(f, ret, callback);
+ err = load_ascii_g1_inv(buf, ret, callback);
else
- err = load_raw_g1_inv(f, ret, callback);
+ err = load_raw_g1_inv(buf, ret, callback);
if (err)
goto err1;
- if (flag)
- fclose(f);
-
return ret;
err1:
GP_ContextFree(ret);
-
- if (flag)
- fclose(f);
err0:
errno = err;
return NULL;
}
-GP_Context *GP_LoadPBM(const char *src_path, GP_ProgressCallback *callback)
+GP_Context *GP_ReadPBM(GP_IO *io, GP_ProgressCallback *callback)
{
struct pnm_header header;
- FILE *f;
+ DECLARE_BUFFER(buf, io);
+ int err;
- f = read_header(src_path, &header);
+ err = load_header(&buf, &header);
+ if (err) {
+ errno = err;
+ return NULL;
+ }
- if (f == NULL)
+ return read_bitmap(&buf, &header, callback);
+}
+
+GP_Context *GP_LoadPBM(const char *src_path, GP_ProgressCallback *callback)
+{
+ GP_IO *io;
+ GP_Context *res;
+ int err;
+
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
return NULL;
- return read_bitmap(f, &header, 1, callback);
+ res = GP_ReadPBM(io, callback);
+
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
+
+ return res;
}
int GP_SavePBM(const GP_Context *src, const char *dst_path,
@@ -728,44 +788,44 @@ static GP_Pixel depth_to_pixel(int depth)
}
}
-static int load_ascii_graymap(FILE *f, struct pnm_header *header,
+static int load_ascii_graymap(struct buf *buf, struct pnm_header *header,
GP_Context *ret, GP_ProgressCallback *callback)
{
int err = ENOSYS;
switch (header->depth) {
case 1:
- err = load_ascii_g1(f, ret, callback);
+ err = load_ascii_g1(buf, ret, callback);
break;
case 3:
- err = load_ascii_g2(f, ret, callback);
+ err = load_ascii_g2(buf, ret, callback);
break;
case 15:
- err = load_ascii_g4(f, ret, callback);
+ err = load_ascii_g4(buf, ret, callback);
break;
case 255:
- err = load_ascii_g8(f, ret, callback);
+ err = load_ascii_g8(buf, ret, callback);
break;
}
return err;
}
-static int load_bin_graymap(FILE *f, struct pnm_header *header,
+static int load_bin_graymap(struct buf *buf, struct pnm_header *header,
GP_Context *ret, GP_ProgressCallback *callback)
{
int err = ENOSYS;
switch (header->depth) {
case 255:
- err = load_bin_g8(f, ret, callback);
+ err = load_bin_g8(buf, ret, callback);
break;
}
return err;
}
-static GP_Context *read_graymap(FILE *f, struct pnm_header *header, int flag,
+static GP_Context *read_graymap(struct buf *buf, struct pnm_header *header,
GP_ProgressCallback *callback)
{
GP_Context *ret;
@@ -792,38 +852,53 @@ static GP_Context *read_graymap(FILE *f, struct pnm_header *header, int flag,
}
if (header->magic == '5')
- err = load_bin_graymap(f, header, ret, callback);
+ err = load_bin_graymap(buf, header, ret, callback);
else
- err = load_ascii_graymap(f, header, ret, callback);
+ err = load_ascii_graymap(buf, header, ret, callback);
if (err)
goto err1;
- if (flag)
- fclose(f);
-
return ret;
err1:
GP_ContextFree(ret);
-
- if (flag)
- fclose(f);
err0:
errno = err;
return NULL;
}
-GP_Context *GP_LoadPGM(const char *src_path, GP_ProgressCallback *callback)
+GP_Context *GP_ReadPGM(GP_IO *io, GP_ProgressCallback *callback)
{
struct pnm_header header;
- FILE *f;
+ DECLARE_BUFFER(buf, io);
+ int err;
+
+ err = load_header(&buf, &header);
+ if (err) {
+ errno = err;
+ return NULL;
+ }
- f = read_header(src_path, &header);
+ return read_graymap(&buf, &header, callback);
+}
- if (f == NULL)
+GP_Context *GP_LoadPGM(const char *src_path, GP_ProgressCallback *callback)
+{
+ GP_IO *io;
+ GP_Context *res;
+ int err;
+
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
return NULL;
- return read_graymap(f, &header, 1, callback);
+ res = GP_ReadPGM(io, callback);
+
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
+
+ return res;
}
static int pixel_to_depth(GP_Pixel pixel)
@@ -891,11 +966,11 @@ err0:
return 1;
}
-static GP_Context *read_pixmap(FILE *f, struct pnm_header *header, int flag,
- GP_ProgressCallback *callback)
+static GP_Context *read_pixmap(struct buf *buf, struct pnm_header *header,
+ GP_ProgressCallback *callback)
{
GP_Context *ret;
- int err;
+ int err = 0;
if (!is_pixmap(header->magic)) {
GP_DEBUG(1, "Invalid Pixmap magic P%c", header->magic);
@@ -918,40 +993,56 @@ static GP_Context *read_pixmap(FILE *f, struct pnm_header *header, int flag,
switch (header->magic) {
case '3':
- if ((err = load_ascii_rgb888(f, ret, callback)))
- goto err1;
+ err = load_ascii_rgb888(buf, ret, callback);
break;
case '6':
- if ((err = load_bin_rgb888(f, ret, callback)))
- goto err1;
+ err = load_bin_rgb888(buf, ret, callback);
break;
}
- if (flag)
- fclose(f);
+ if (err)
+ goto err1;
return ret;
err1:
GP_ContextFree(ret);
-
- if (flag)
- fclose(f);
err0:
errno = err;
return NULL;
}
-GP_Context *GP_LoadPPM(const char *src_path, GP_ProgressCallback *callback)
+GP_Context *GP_ReadPPM(GP_IO *io, GP_ProgressCallback *callback)
{
struct pnm_header header;
- FILE *f;
+ DECLARE_BUFFER(buf, io);
+ int err;
- f = read_header(src_path, &header);
+ err = load_header(&buf, &header);
+ if (err) {
+ errno = err;
+ return NULL;
+ }
- if (f == NULL)
+ return read_pixmap(&buf, &header, callback);
+}
+
+GP_Context *GP_LoadPPM(const char *src_path, GP_ProgressCallback *callback)
+{
+ GP_IO *io;
+ GP_Context *res;
+ int err;
+
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
return NULL;
- return read_pixmap(f, &header, 1, callback);
+ res = GP_ReadPPM(io, callback);
+
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
+
+ return res;
}
static int write_binary_ppm(FILE *f, GP_Context *src)
@@ -1072,40 +1163,48 @@ err0:
return 1;
}
-GP_Context *GP_LoadPNM(const char *src_path, GP_ProgressCallback *callback)
+GP_Context *GP_ReadPNM(GP_IO *io, GP_ProgressCallback *callback)
{
- FILE *f;
- GP_Context *ret = NULL;
struct pnm_header header;
+ DECLARE_BUFFER(buf, io);
+ GP_Context *ret = NULL;
int err;
- f = fopen(src_path, "r");
-
- if (f == NULL) {
- err = errno;
- GP_DEBUG(1, "Failed to open file '%s': %s",
- src_path, strerror(errno));
- goto err0;
+ err = load_header(&buf, &header);
+ if (err) {
+ errno = err;
+ return NULL;
}
- if ((err = load_header(f, &header)))
- goto err1;
-
if (is_bitmap(header.magic))
- ret = read_bitmap(f, &header, 1, callback);
+ ret = read_bitmap(&buf, &header, callback);
if (is_graymap(header.magic))
- ret = read_graymap(f, &header, 1, callback);
+ ret = read_graymap(&buf, &header, callback);
if (is_pixmap(header.magic))
- ret = read_pixmap(f, &header, 1, callback);
+ ret = read_pixmap(&buf, &header, callback);
return ret;
-err1:
- fclose(f);
-err0:
+}
+
+GP_Context *GP_LoadPNM(const char *src_path, GP_ProgressCallback *callback)
+{
+ GP_IO *io;
+ GP_Context *res;
+ int err;
+
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
+ return NULL;
+
+ res = GP_ReadPNM(io, callback);
+
+ err = errno;
+ GP_IOClose(io);
errno = err;
- return NULL;
+
+ return res;
}
int GP_SavePNM(const GP_Context *src, const char *dst_path,
diff --git a/libs/loaders/GP_PSP.c b/libs/loaders/GP_PSP.c
index f5c6c28..d99ca03 100644
--- a/libs/loaders/GP_PSP.c
+++ b/libs/loaders/GP_PSP.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -42,17 +42,6 @@
#include "GP_JPG.h"
#include "GP_PSP.h"
-#define BUF_TO_8(buf, off) - (buf[off] + (buf[off+1]<<8) + (buf[off+2]<<16) + (buf[off+3]<<24) + - ((uint64_t)buf[off+4]<<32) + ((uint64_t)buf[off+5]<<40) + - ((uint64_t)buf[off+6]<<48) + ((uint64_t)buf[off+7]<<56))
-
-#define BUF_TO_4(buf, off) - (buf[off] + (buf[off+1]<<8) + (buf[off+2]<<16) + (buf[off+3]<<24))
-
-#define BUF_TO_2(buf, off) - (buf[off] + (buf[off+1]<<8))
-
#define PSP_SIGNATURE "Paint Shop Pro Image Filenx1a00000000"
#define PSP_SIGNATURE_LEN 32
@@ -66,49 +55,6 @@ int GP_MatchPSP(const void *buf)
return !memcmp(buf, PSP_SIGNATURE, PSP_SIGNATURE_LEN);
}
-int GP_OpenPSP(const char *src_path, FILE **f)
-{
- int err;
-
- *f = fopen(src_path, "rb");
-
- if (*f == NULL) {
- err = errno;
- GP_DEBUG(1, "Failed to open '%s' : %s",
- src_path, strerror(errno));
- goto err2;
- }
-
- char buf[36];
-
- if (fread(buf, sizeof(buf), 1, *f) < 1) {
- GP_DEBUG(1, "Failed to read file header");
- err = EIO;
- goto err1;
- }
-
- if (memcmp(buf, PSP_SIGNATURE, PSP_SIGNATURE_LEN)) {
- GP_DEBUG(1, "Invalid signature, not a PSP image?");
- err = EINVAL;
- goto err1;
- }
-
- struct psp_version version;
-
- version.major = BUF_TO_2(buf, 32);
- version.minor = BUF_TO_2(buf, 34);
-
- GP_DEBUG(1, "Have PSP image version %u.%u",
- version.major, version.minor);
-
- return 0;
-err1:
- fclose(*f);
-err2:
- errno = err;
- return 1;
-}
-
enum psp_block_id {
PSP_IMAGE_BLOCK,
PSP_CREATOR_BLOCK,
@@ -229,40 +175,46 @@ struct psp_img_attrs {
GP_Context *img;
};
-static int psp_read_general_img_attr_chunk(FILE *f,
+static int psp_read_general_img_attr_chunk(GP_IO *io,
struct psp_img_attrs *attrs)
{
- uint8_t buf[38];
+ int err;
if (attrs->is_loaded) {
GP_WARN("Found Second Image Block");
return EINVAL;
}
- //TODO SHIFT!!!
- if (fread(buf, 4, 1, f) < 1) {
- GP_DEBUG(1, "Failed to read Image block header");
- return EIO;
- }
-
- if (fread(buf, sizeof(buf), 1, f) < 1) {
- GP_DEBUG(1, "Failed to read Image chunk data");
- return EIO;
+ uint16_t general_image_info[] = {
+ GP_IO_I4, /* ??? */
+ GP_IO_L4, /* width */
+ GP_IO_L4, /* height */
+ GP_IO_ARRAY | 8, /* resolution FIXME: double */
+ GP_IO_BYTE, /* resolution metric */
+ GP_IO_L2, /* compression type */
+ GP_IO_L2, /* bit depth */
+ GP_IO_L2, /* plane count */
+ GP_IO_L2, /* color count */
+ GP_IO_BYTE, /* grayscale flag */
+ GP_IO_L4, /* total image size */
+ GP_IO_I2, /* ??? */
+ GP_IO_L4, /* active layer */
+ GP_IO_L2, /* layer count */
+ GP_IO_END
+ };
+
+ if (GP_IOReadF(io, general_image_info, &attrs->w, &attrs->h,
+ &attrs->res, &attrs->res_metric, &attrs->comp_type,
+ &attrs->bit_depth, &attrs->plane_count,
+ &attrs->color_count, &attrs->grayscale_flag,
+ &attrs->total_img_size, &attrs->active_layer,
+ &attrs->layer_count) != 14) {
+ err = errno;
+ GP_DEBUG(1, "Failed to read Image attributes: %s",
+ strerror(errno));
+ return err;
}
- attrs->w = BUF_TO_4(buf, 0);
- attrs->h = BUF_TO_4(buf, 4);
- attrs->res = BUF_TO_8(buf, 8);
- attrs->res_metric = buf[16];
- attrs->comp_type = BUF_TO_2(buf, 17);
- attrs->bit_depth = BUF_TO_2(buf, 19);
- attrs->plane_count = BUF_TO_2(buf, 21);
- attrs->color_count = BUF_TO_2(buf, 23);
- attrs->grayscale_flag = buf[25];
- attrs->total_img_size = BUF_TO_4(buf, 26);
- attrs->active_layer = BUF_TO_4(buf, 32);
- attrs->layer_count = BUF_TO_2(buf, 36);
-
GP_DEBUG(3, "Image w=%u h=%u, compress=%s, bit_depth=%u, grayscale=%u",
attrs->w, attrs->h, psp_comp_type_name(attrs->comp_type),
attrs->bit_depth, attrs->grayscale_flag);
@@ -275,10 +227,10 @@ static int psp_read_general_img_attr_chunk(FILE *f,
return 0;
}
-static int psp_next_block(FILE *f, struct psp_img_attrs *attrs,
+static int psp_next_block(GP_IO *io, struct psp_img_attrs *attrs,
GP_ProgressCallback *callback);
-static int psp_read_layer_start_block(FILE *f, struct psp_img_attrs *attrs,
+static int psp_read_layer_start_block(GP_IO *io, struct psp_img_attrs *attrs,
GP_ProgressCallback *callback)
{
int i;
@@ -292,18 +244,18 @@ static int psp_read_layer_start_block(FILE *f, struct psp_img_attrs *attrs,
attrs->subblock++;
for (i = 0; i < attrs->layer_count; i++)
- psp_next_block(f, attrs, callback);
+ psp_next_block(io, attrs, callback);
attrs->subblock--;
return 0;
}
-static int psp_read_composite_image_block(FILE *f, struct psp_img_attrs *attrs,
+static int psp_read_composite_image_block(GP_IO *io, struct psp_img_attrs *attrs,
GP_ProgressCallback *callback)
{
- uint8_t buf[8];
uint32_t i, composite_image_count;
+ int err;
/* we are allready in subblock -> error */
if (attrs->subblock) {
@@ -311,13 +263,18 @@ static int psp_read_composite_image_block(FILE *f, struct psp_img_attrs *attrs,
return EINVAL;
}
- if (fread(buf, sizeof(buf), 1, f) < 1) {
+ uint16_t composite_image[] = {
+ GP_IO_I4, /* chunk size */
+ GP_IO_L4, /* composit image count */
+ GP_IO_END,
+ };
+
+ if (GP_IOReadF(io, composite_image, &composite_image_count) != 2) {
+ err = errno;
GP_DEBUG(1, "Failed to read Composite Image Bank Info Chunk");
- return EIO;
+ return err;
}
- composite_image_count = BUF_TO_4(buf, 4);
-
//TODO: utilize chunk_size
GP_DEBUG(3, "Composite image count=%u", composite_image_count);
@@ -325,7 +282,7 @@ static int psp_read_composite_image_block(FILE *f, struct psp_img_attrs *attrs,
attrs->subblock++;
for (i = 0; i < composite_image_count; i++)
- psp_next_block(f, attrs, callback);
+ psp_next_block(io, attrs, callback);
attrs->subblock--;
@@ -359,25 +316,33 @@ struct psp_comp_img_attr_info {
uint16_t comp_img_type;
};
-static int psp_read_composite_attributes_block(FILE *f, struct psp_img_attrs *attrs,
+static int psp_read_composite_attributes_block(GP_IO *io, struct psp_img_attrs *attrs,
GP_ProgressCallback *callback)
{
- uint8_t buf[24];
struct psp_comp_img_attr_info info;
+ int err;
- if (fread(buf, sizeof(buf), 1, f) < 1) {
- GP_DEBUG(1, "Failed to read Composite Image Bank Info Chunk");
- return EIO;
+ uint16_t info_chunk[] = {
+ GP_IO_I4, /* chunk size */
+ GP_IO_L4, /* width */
+ GP_IO_L4, /* height */
+ GP_IO_L2, /* bit depth */
+ GP_IO_L2, /* compression type */
+ GP_IO_L2, /* plane count */
+ GP_IO_L4, /* color count */
+ GP_IO_L2, /* composite image type */
+ GP_IO_END
+ };
+
+ if (GP_IOReadF(io, info_chunk, &info.w, &info.h, &info.bit_depth,
+ &info.comp_type, &info.plane_count, &info.color_count,
+ &info.comp_img_type) != 8) {
+ err = errno;
+ GP_DEBUG(1, "Failed to read Composite Image Attrs Info: %s",
+ strerror(err));
+ return err;
}
- info.w = BUF_TO_4(buf, 4);
- info.h = BUF_TO_4(buf, 8);
- info.bit_depth = BUF_TO_2(buf, 12);
- info.comp_type = BUF_TO_2(buf, 14);
- info.plane_count = BUF_TO_2(buf, 16);
- info.color_count = BUF_TO_4(buf, 18);
- info.comp_img_type = BUF_TO_2(buf, 22);
-
GP_DEBUG(4, "Composite Image w=%u h=%u, bit_depth=%u, comp_type=%s, "
"comp_img_type=%s",
info.w, info.h, info.bit_depth, psp_comp_type_name(info.comp_type),
@@ -387,7 +352,7 @@ static int psp_read_composite_attributes_block(FILE *f, struct psp_img_attrs *at
attrs->subblock++;
if (info.comp_img_type == PSP_IMAGE_COMPOSITE)
- psp_next_block(f, attrs, callback);
+ psp_next_block(io, attrs, callback);
attrs->subblock--;
attrs->priv = NULL;
@@ -395,22 +360,23 @@ static int psp_read_composite_attributes_block(FILE *f, struct psp_img_attrs *at
return 0;
}
-static int psp_read_jpeg(FILE *f, struct psp_img_attrs *attrs,
+static int psp_read_jpeg(GP_IO *io, struct psp_img_attrs *attrs,
GP_ProgressCallback *callback)
{
- uint8_t buf[14];
int err;
+ GP_IOSeek(io, 14, GP_IO_SEEK_CUR);
+/*
if (fread(buf, sizeof(buf), 1, f) < 1) {
GP_DEBUG(1, "Failed to read JPEG Information Chunk");
return EIO;
}
-
+*/
//TODO: utilize chunk_size
GP_DEBUG(5, "JPEG Chunk");
- attrs->img = GP_ReadJPG(f, callback);
+ attrs->img = GP_ReadJPG(io, callback);
if (attrs->img == NULL) {
err = errno;
@@ -421,99 +387,123 @@ static int psp_read_jpeg(FILE *f, struct psp_img_attrs *attrs,
return 0;
}
-#define GEN_IMG_HEADER_ID "~BK"
-#define GEN_IMG_HEADER_ID_LEN 4
-
-static int psp_next_block(FILE *f, struct psp_img_attrs *attrs,
+static int psp_next_block(GP_IO *io, struct psp_img_attrs *attrs,
GP_ProgressCallback *callback)
{
- uint8_t buf[10];
uint16_t block_id;
uint32_t block_size;
- long offset;
+ off_t offset;
int err = 0;
- if (fread(buf, sizeof(buf), 1, f) < 1) {
- GP_DEBUG(1, "Failed to read block header");
- return EIO;
- }
+ uint16_t block_header[] = {
+ '~', 'B', 'K', 0x00,
+ GP_IO_L2, /* block id */
+ GP_IO_L4, /* block size */
+ GP_IO_END
+ };
- if (memcmp(buf, GEN_IMG_HEADER_ID, GEN_IMG_HEADER_ID_LEN)) {
- GP_DEBUG(1, "Invalid block header identifier");
- return EINVAL;
+ if (GP_IOReadF(io, block_header, &block_id, &block_size) != 6) {
+ err = errno;
+ GP_DEBUG(1, "Failed to read block header: %s", strerror(errno));
+ return err;
}
- block_id = BUF_TO_2(buf, 4);
- block_size = BUF_TO_4(buf, 6);
-
GP_DEBUG(2 + attrs->subblock, "%s Block size %u",
psp_block_id_name(block_id), block_size);
- offset = ftell(f) + block_size;
+ offset = GP_IOTell(io) + block_size;
switch (block_id) {
case PSP_IMAGE_BLOCK:
- err = psp_read_general_img_attr_chunk(f, attrs);
+ err = psp_read_general_img_attr_chunk(io, attrs);
break;
case PSP_LAYER_START_BLOCK:
- err = psp_read_layer_start_block(f, attrs, callback);
+ err = psp_read_layer_start_block(io, attrs, callback);
break;
case PSP_COMPOSITE_IMAGE_BANK_BLOCK:
- err = psp_read_composite_image_block(f, attrs, callback);
+ err = psp_read_composite_image_block(io, attrs, callback);
break;
case PSP_COMPOSITE_ATTRIBUTES_BLOCK:
- err = psp_read_composite_attributes_block(f, attrs, callback);
+ err = psp_read_composite_attributes_block(io, attrs, callback);
break;
case PSP_JPEG_BLOCK:
- err = psp_read_jpeg(f, attrs, callback);
+ err = psp_read_jpeg(io, attrs, callback);
break;
}
if (err)
return err;
- if (fseek(f, offset, SEEK_SET) == -1) {
+ if (GP_IOSeek(io, offset, GP_IO_SEEK_SET) != offset) {
err = errno;
- GP_DEBUG(1, "Failed to seek to next block");
- return errno;
+ GP_DEBUG(1, "Failed to seek to next block; %s",
+ strerror(errno));
+ return err;
}
return 0;
}
-GP_Context *GP_ReadPSP(FILE *f, GP_ProgressCallback *callback)
+GP_Context *GP_ReadPSP(GP_IO *io, GP_ProgressCallback *callback)
{
int err = 0;
struct psp_img_attrs attrs = {.is_loaded = 0, .subblock = 0,
.priv = NULL, .img = NULL};
+ struct psp_version version;
+
+ uint16_t psp_header[] = {
+ 'P', 'a', 'i', 'n', 't', ' ',
+ 'S', 'h', 'o', 'p', ' ',
+ 'P', 'r', 'o', ' ',
+ 'I', 'm', 'a', 'g', 'e', ' ',
+ 'F', 'i', 'l', 'e', 'n', 0x1a,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ GP_IO_L2, /* version major */
+ GP_IO_L2, /* version minor */
+ GP_IO_END
+ };
+
+ if (GP_IOReadF(io, psp_header, &version.major, &version.minor) != 34) {
+ GP_DEBUG(1, "Failed to read file header");
+ err = EIO;
+ goto err0;
+ }
+
+ GP_DEBUG(1, "Have PSP image version %u.%u",
+ version.major, version.minor);
while (!err) {
- err = psp_next_block(f, &attrs, callback);
+ err = psp_next_block(io, &attrs, callback);
if (err)
- goto err1;
+ goto err0;
- if (attrs.img != NULL) {
- fclose(f);
+ if (attrs.img != NULL)
return attrs.img;
- }
}
- fclose(f);
errno = ENOSYS;
return NULL;
-err1:
- fclose(f);
+err0:
errno = err;
return NULL;
}
GP_Context *GP_LoadPSP(const char *src_path, GP_ProgressCallback *callback)
{
- FILE *f;
+ GP_IO *io;
+ GP_Context *res;
+ int err;
- if (GP_OpenPSP(src_path, &f))
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
return NULL;
- return GP_ReadPSP(f, callback);
+ res = GP_ReadPSP(io, callback);
+
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
+
+ return res;
}
diff --git a/libs/loaders/GP_TIFF.c b/libs/loaders/GP_TIFF.c
index f9d32c8..93e5b42 100644
--- a/libs/loaders/GP_TIFF.c
+++ b/libs/loaders/GP_TIFF.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -58,17 +58,6 @@ int GP_MatchTIFF(const void *buf)
return 0;
}
-int GP_OpenTIFF(const char *src_path, void **t)
-{
- TIFF *tiff = TIFFOpen(src_path, "r");
-
- if (tiff == NULL)
- return 1;
-
- *t = tiff;
- return 0;
-}
-
static const char *compression_name(uint16_t compression)
{
switch (compression) {
@@ -446,17 +435,70 @@ static int tiff_read(TIFF *tiff, GP_Context *res, struct tiff_header *header,
return 0;
}
-GP_Context *GP_ReadTIFF(void *t, GP_ProgressCallback *callback)
+static tmsize_t tiff_io_read(thandle_t io, void *buf, tmsize_t size)
+{
+ return GP_IORead(io, buf, size);
+}
+
+static tmsize_t tiff_io_write(thandle_t io, void *buf, tmsize_t size)
{
+ (void) io;
+ (void) buf;
+ GP_WARN("stub called");
+ return size;
+}
+
+static toff_t tiff_io_seek(thandle_t io, toff_t offset, int whence)
+{
+ return GP_IOSeek(io, offset, whence);
+}
+
+static int tiff_io_close(thandle_t GP_UNUSED(io))
+{
+ return 0;
+}
+
+static toff_t tiff_io_size(thandle_t io)
+{
+ return GP_IOSize(io);
+}
+
+/*
+static int tiff_io_map(thandle_t io, void **base, toff_t *size)
+{
+ GP_WARN("stub called");
+ return 0;
+}
+
+static void tiff_io_unmap(thandle_t io, void *base, toff_t size)
+{
+ GP_WARN("stub called");
+ return 0;
+}
+*/
+
+GP_Context *GP_ReadTIFF(GP_IO *io, GP_ProgressCallback *callback)
+{
+ TIFF *tiff;
struct tiff_header header;
- GP_Context *res = NULL;
+ GP_Context *res;
GP_PixelType pixel_type;
int err;
- if ((err = read_header(t, &header)))
+ tiff = TIFFClientOpen("GFXprim IO", "r", io, tiff_io_read,
+ tiff_io_write, tiff_io_seek, tiff_io_close,
+ tiff_io_size, NULL, NULL);
+
+ if (!tiff) {
+ GP_DEBUG(1, "TIFFClientOpen failed");
+ err = EIO;
+ goto err0;
+ }
+
+ if ((err = read_header(tiff, &header)))
goto err1;
- pixel_type = match_pixel_type(t, &header);
+ pixel_type = match_pixel_type(tiff, &header);
if (pixel_type == GP_PIXEL_UNKNOWN) {
err = ENOSYS;
@@ -473,33 +515,42 @@ GP_Context *GP_ReadTIFF(void *t, GP_ProgressCallback *callback)
switch (header.photometric) {
case PHOTOMETRIC_PALETTE:
- err = tiff_read_palette(t, res, &header, callback);
+ err = tiff_read_palette(tiff, res, &header, callback);
break;
default:
- err = tiff_read(t, res, &header, callback);
+ err = tiff_read(tiff, res, &header, callback);
}
if (err)
- goto err1;
+ goto err2;
+
+ TIFFClose(tiff);
return res;
-err1:
+err2:
GP_ContextFree(res);
+err1:
+ TIFFClose(tiff);
+err0:
errno = err;
return NULL;
}
GP_Context *GP_LoadTIFF(const char *src_path, GP_ProgressCallback *callback)
{
- void *t;
+ GP_IO *io;
GP_Context *res;
+ int err;
- if (GP_OpenTIFF(src_path, &t))
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
return NULL;
- res = GP_ReadTIFF(t, callback);
+ res = GP_ReadTIFF(io, callback);
- TIFFClose(t);
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
return res;
}
diff --git a/libs/loaders/GP_ZIP.c b/libs/loaders/GP_ZIP.c
index c64214e..d6cbdd1 100644
--- a/libs/loaders/GP_ZIP.c
+++ b/libs/loaders/GP_ZIP.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -57,7 +57,7 @@ struct zip_chunks_table {
};
struct zip_priv {
- FILE *f;
+ GP_IO *io;
/* Current position in zip continer counted in images we found */
unsigned int cur_pos;
@@ -131,14 +131,14 @@ static const char *compress_method_name(enum compress_method comp)
return compress_method_names[comp];
}
-static int seek_bytes(FILE *f, uint32_t bytes)
+static int seek_bytes(GP_IO *io, uint32_t bytes)
{
if (bytes == 0)
return 0;
- GP_DEBUG(4, "Moving forward by %"PRIu32"bytes", bytes);
+ GP_DEBUG(4, "Moving forward by %"PRIu32" bytes", bytes);
- if (fseek(f, bytes, SEEK_CUR)) {
+ if (GP_IOSeek(io, bytes, GP_IO_SEEK_CUR) == (off_t)-1) {
int err = errno;
GP_DEBUG(1, "Failed to seek: %s", strerror(errno));
return err;
@@ -153,21 +153,21 @@ struct deflate_inbuf {
struct zip_local_header *zip_header;
uint32_t to_read;
unsigned char buf[CHUNK];
- FILE *f;
+ GP_IO *io;
};
struct deflate_outbuf {
uint32_t crc;
uint32_t size;
- FILE *f;
+ uint8_t *buf;
};
static unsigned deflate_in(void *in_desc, unsigned char **buf)
{
struct deflate_inbuf *in = in_desc;
- uint32_t chunk = in->to_read >= CHUNK ? CHUNK : in->to_read;
+ int chunk = in->to_read >= CHUNK ? CHUNK : in->to_read;
- if (fread(in->buf, chunk, 1, in->f) != 1)
+ if (GP_IORead(in->io, in->buf, chunk) != chunk)
return 0;
*buf = in->buf;
@@ -183,33 +183,25 @@ static int deflate_out(void *out_desc, unsigned char *buf, unsigned len)
out->crc = crc32(out->crc, buf, len);
out->size += len;
- if (fwrite(buf, len, 1, out->f) != 1) {
- GP_DEBUG(1, "Failed to write temp file");
- return 1;
- }
+ memcpy(out->buf + out->size, buf, len);
+ out->size += len;
return 0;
}
-static int read_deflate(FILE *f, struct zip_local_header *header, FILE **res_f)
+static int read_deflate(GP_IO *io, struct zip_local_header *header, GP_IO **rio)
{
uint8_t *window;
int err = 0, ret;
- FILE *tf;
-
- tf = tmpfile();
-
- if (!tf) {
- err = errno;
- GP_DEBUG(1, "Failed to create temp file");
- return err;
- }
+ uint8_t *buf;
window = malloc(32 * 1024);
+ //TODO: Unsafe
+ buf = malloc(header->uncomp_size);
- if (!window) {
+ if (!window || !buf) {
err = ENOMEM;
- goto err0;
+ goto err1;
}
z_stream strm = {
@@ -229,12 +221,12 @@ static int read_deflate(FILE *f, struct zip_local_header *header, FILE **res_f)
struct deflate_outbuf outbuf = {
.crc = crc32(0, NULL, 0),
.size = 0,
- .f = tf,
+ .buf = buf,
};
struct deflate_inbuf inbuf = {
.zip_header = header,
- .f = f,
+ .io = io,
.to_read = header->comp_size,
};
@@ -261,32 +253,35 @@ static int read_deflate(FILE *f, struct zip_local_header *header, FILE **res_f)
inflateBackEnd(&strm);
free(window);
- rewind(tf);
- *res_f = tf;
+ //TODO: Failure
+ *rio = GP_IOMem(outbuf.buf, outbuf.size, free);
return 0;
err2:
inflateBackEnd(&strm);
err1:
free(window);
-err0:
- fclose(tf);
+ free(buf);
return err;
}
-static int zip_load_header(FILE *f, struct zip_local_header *header)
+static int zip_load_header(GP_IO *io, struct zip_local_header *header)
{
- int ret, ch;
+ int ret;
+ uint8_t byte;
- ret = GP_FRead(f, "0x50 0x4b");
+ uint16_t zip_header[] = {
+ 'P',
+ 'K',
+ GP_IO_BYTE,
+ GP_IO_END
+ };
- if (ret != 2) {
+ if (GP_IOReadF(io, zip_header, &byte) != 3) {
GP_DEBUG(1, "Failed to read header");
return EIO;
}
- ch = fgetc(f);
-
- switch (ch) {
+ switch (byte) {
/* Central directory -> end of archive */
case 0x01:
GP_DEBUG(1, "Reached end of the archive");
@@ -296,11 +291,25 @@ static int zip_load_header(FILE *f, struct zip_local_header *header)
case 0x03:
break;
default:
- GP_DEBUG(1, "Unexpected header PK%x", ch);
+ GP_DEBUG(1, "Unexpected header PK%x", byte);
return EIO;
}
- ret = GP_FRead(f, "0x04 L2 L2 L2 I4 L4 L4 L4 L2 L2",
+ uint16_t zip_local_header[] = {
+ 0x04,
+ GP_IO_L2, /* version */
+ GP_IO_L2, /* bit flags */
+ GP_IO_L2, /* compression type */
+ GP_IO_IGN | 4,
+ GP_IO_L4, /* CRC */
+ GP_IO_L4, /* compressed size */
+ GP_IO_L4, /* uncompressed size */
+ GP_IO_L2, /* filename length */
+ GP_IO_L2, /* extra fields lenght */
+ GP_IO_END
+ };
+
+ ret = GP_IOReadF(io, zip_local_header,
&header->ver, &header->bit_flags, &header->comp_type,
&header->crc, &header->comp_size, &header->uncomp_size,
&header->fname_len, &header->extf_len);
@@ -313,14 +322,15 @@ static int zip_load_header(FILE *f, struct zip_local_header *header)
return 0;
}
-static GP_Context *zip_next_file(FILE *f, GP_ProgressCallback *callback)
+static GP_Context *zip_next_file(struct zip_priv *priv,
+ GP_ProgressCallback *callback)
{
struct zip_local_header header = {.file_name = NULL};
int err = 0;
GP_Context *ret = NULL;
- FILE *fres;
+ GP_IO *io;
- if ((err = zip_load_header(f, &header)))
+ if ((err = zip_load_header(priv->io, &header)))
goto out;
GP_DEBUG(1, "Have ZIP local header version %u.%u compression %s",
@@ -347,7 +357,7 @@ static GP_Context *zip_next_file(FILE *f, GP_ProgressCallback *callback)
header.file_name[header.fname_len] = '0';
- if (fread(header.file_name, header.fname_len, 1, f) != 1) {
+ if (GP_IORead(priv->io, header.file_name, header.fname_len) != header.fname_len) {
GP_DEBUG(1, "Failed to read filename");
err = EIO;
goto out;
@@ -359,41 +369,43 @@ static GP_Context *zip_next_file(FILE *f, GP_ProgressCallback *callback)
header.uncomp_size);
}
- seek_bytes(f, header.extf_len);
+ seek_bytes(priv->io, header.extf_len);
switch (header.comp_type) {
case COMPRESS_STORED:
/* skip directories */
- if (header.uncomp_size == 0)
+ if (header.uncomp_size == 0) {
+ GP_DEBUG(2, "Skipping directory");
goto out;
+ }
- off_t cur_off = ftell(f);
+ GP_IOMark(priv->io, GP_IO_MARK);
- ret = GP_ReadJPG(f, callback);
+ ret = GP_ReadJPG(priv->io, callback);
if (!ret) {
- fseek(f, cur_off, SEEK_SET);
- ret = GP_ReadPNG(f, callback);
+ GP_IOMark(priv->io, GP_IO_REWIND);
+ ret = GP_ReadPNG(priv->io, callback);
}
- fseek(f, cur_off + header.comp_size, SEEK_SET);
+ GP_IOSeek(priv->io, priv->io->mark + header.comp_size, GP_IO_SEEK_SET);
goto out;
break;
case COMPRESS_DEFLATE:
- if (read_deflate(f, &header, &fres)) {
+ if (read_deflate(priv->io, &header, &io)) {
err = errno;
goto out;
}
- ret = GP_ReadJPG(fres, callback);
+ ret = GP_ReadJPG(io, callback);
if (!ret) {
- rewind(fres);
- ret = GP_ReadPNG(fres, callback);
+ GP_IORewind(io);
+ ret = GP_ReadPNG(io, callback);
}
- fclose(fres);
+ GP_IOClose(io);
goto out;
break;
default:
@@ -476,8 +488,8 @@ static GP_Context *zip_load_next(GP_Container *self,
GP_DEBUG(1, "Trying to load next image from ZIP container");
do {
- offset = ftell(priv->f);
- ret = zip_next_file(priv->f, callback);
+ offset = GP_IOTell(priv->io);
+ ret = zip_next_file(priv, callback);
} while (ret == NULL && errno == 0);
if (!ret)
@@ -524,25 +536,25 @@ static void seek_cur_pos(struct zip_priv *priv)
GP_DEBUG(2, "Setting current position to %u (%li)",
priv->cur_pos, priv->cur_table->offsets[cur_pos]);
- fseek(priv->f, priv->cur_table->offsets[cur_pos], SEEK_SET);
+ GP_IOSeek(priv->io, priv->cur_table->offsets[cur_pos], GP_IO_SEEK_SET);
}
static int load_next_offset(struct zip_priv *priv)
{
struct zip_local_header header = {.file_name = NULL};
int ret;
- long offset = ftell(priv->f);
+ long offset = GP_IOTell(priv->io);
- if ((ret = zip_load_header(priv->f, &header)))
+ if ((ret = zip_load_header(priv->io, &header)))
return ret;
//TODO: Match image extension and signature
record_offset(priv, offset);
/* Seek to the next local header */
- seek_bytes(priv->f, (uint32_t)header.fname_len +
+ seek_bytes(priv->io, (uint32_t)header.fname_len +
(uint32_t)header.extf_len);
- seek_bytes(priv->f, header.comp_size);
+ seek_bytes(priv->io, header.comp_size);
return 0;
}
@@ -641,39 +653,54 @@ static void zip_close(GP_Container *self)
/* Free allocated offset tables */
for (i = priv->table.next; i != NULL; j = i, i = i->next, free(j));
- fclose(priv->f);
+ GP_IOClose(priv->io);
free(self);
}
-static int open_zip(const char *path, FILE **file)
+static GP_IO *open_zip(const char *path)
{
- FILE *f;
+ GP_IO *io;
int err = 0;
- f = fopen(path, "rb");
+ io = GP_IOFile(path, GP_IO_RDONLY);
- if (f == NULL) {
+ if (!io) {
err = errno;
GP_DEBUG(1, "Failed to open '%s': %s", path, strerror(errno));
- if (!err)
- err = EIO;
- return err;
+ goto err0;
}
/* Check zip local file header and seek back */
- if (GP_FRead(f, "0x50 0x4b 0x03 0x04") != 4) {
+ if (GP_IOMark(io, GP_IO_MARK)) {
+ err = errno;
+ goto err1;
+ }
+
+ static uint16_t zip_header[] = {
+ 'P',
+ 'K',
+ 0x03,
+ 0x04,
+ GP_IO_END
+ };
+
+ if (GP_IOReadF(io, zip_header) != 4) {
GP_DEBUG(1, "Invalid zip header");
err = EINVAL;
- goto err0;
+ goto err1;
}
- rewind(f);
+ if (GP_IOMark(io, GP_IO_REWIND)) {
+ err = errno;
+ goto err1;
+ }
- *file = f;
- return 0;
+ return io;
+err1:
+ GP_IOClose(io);
err0:
- fclose(f);
- return err;
+ errno = err;
+ return NULL;
}
static const struct GP_ContainerOps zip_ops = {
@@ -688,13 +715,13 @@ GP_Container *GP_OpenZip(const char *path)
{
struct zip_priv *priv;
GP_Container *ret;
- FILE *f;
+ GP_IO *io;
int err;
- if ((err = open_zip(path, &f))) {
- errno = err;
+ io = open_zip(path);
+
+ if (!io)
return NULL;
- }
ret = malloc(sizeof(GP_Container) + sizeof(struct zip_priv));
@@ -711,7 +738,7 @@ GP_Container *GP_OpenZip(const char *path)
priv = GP_CONTAINER_PRIV(ret);
- priv->f = f;
+ priv->io = io;
priv->table.next = NULL;
priv->table.prev = NULL;
@@ -730,16 +757,15 @@ GP_Container *GP_OpenZip(const char *path)
return ret;
err0:
- fclose(f);
+ GP_IOClose(io);
errno = err;
return NULL;
}
#else
-GP_Container *GP_OpenZip(const char *path)
+GP_Container *GP_OpenZip(const char GP_UNUSED(*path))
{
- (void) path;
GP_FATAL("zlib support not compiled in");
errno = ENOSYS;
return NULL;
diff --git a/tests/loaders/IO.c b/tests/loaders/IO.c
new file mode 100644
index 0000000..32cfa2a
--- /dev/null
+++ b/tests/loaders/IO.c
@@ -0,0 +1,274 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+
+#include <core/GP_Common.h>
+#include <loaders/GP_IO.h>
+
+#include "tst_test.h"
+
+/*
+ * Expects IO buffer filled with monotonically increasing bytes, i.e.
+ * 0x00 0x01 0x02 ...
+ */
+static int do_test(GP_IO *io)
+{
+ int ret;
+ uint8_t buf[10];
+ unsigned int i;
+
+ ret = GP_IORead(io, buf, 10);
+
+ if (ret != 10) {
+ tst_msg("First IO read failed");
+ return TST_FAILED;
+ }
+
+ for (i = 0; i < 10; i++) {
+ if (i != buf[i]) {
+ tst_msg("Read wrong data at %u", i);
+ return TST_FAILED;
+ }
+ }
+
+ ret = GP_IOTell(io);
+
+ if (ret != 10) {
+ tst_msg("Have wrong offset %u, after read 10", ret);
+ return TST_FAILED;
+ }
+
+
+ ret = GP_IORead(io, buf, 10);
+
+ if (ret != 10) {
+ tst_msg("Second IO read failed");
+ return TST_FAILED;
+ }
+
+ for (i = 0; i < 10; i++) {
+ if (i + 10 != buf[i]) {
+ tst_msg("Read wrong data at %u", i + 10);
+ return TST_FAILED;
+ }
+ }
+
+ if (GP_IORewind(io)) {
+ tst_msg("Failed to rewind to start");
+ return TST_FAILED;
+ }
+
+ ret = GP_IOTell(io);
+
+ if (ret != 0) {
+ tst_msg("Have wrong offset %u, after rewind", ret);
+ return TST_FAILED;
+ }
+
+ uint16_t header[] = {
+ 0x00,
+ 0x01,
+ GP_IO_BYTE,
+ GP_IO_IGN | 7,
+ GP_IO_L2,
+ GP_IO_END
+ };
+
+ uint8_t byte;
+ uint16_t val;
+
+ if (GP_IOReadF(io, header, &byte, &val) != 5) {
+ tst_msg("Failed to ReadF from Memory IO");
+ return TST_FAILED;
+ }
+
+ if (byte != 2) {
+ tst_msg("Read wrong value byte = %u (expected 2)", byte);
+ return TST_FAILED;
+ }
+
+ if (val != 0x0b0a) {
+ tst_msg("Read wrong value = %04x (expected 0x0b0a)", val);
+ return TST_FAILED;
+ }
+
+ return TST_SUCCESS;
+}
+
+static int test_IOMem(void)
+{
+ uint8_t buffer[128];
+ unsigned int i;
+ GP_IO *io;
+ int ret;
+
+ for (i = 0; i < sizeof(buffer); i++)
+ buffer[i] = i;
+
+ io = GP_IOMem(buffer, sizeof(buffer), NULL);
+
+ if (!io) {
+ tst_msg("Failed to initialize memory IO");
+ return TST_FAILED;
+ }
+
+ ret = do_test(io);
+ if (ret)
+ return ret;
+
+ if (GP_IOClose(io)) {
+ tst_msg("Failed to close memory IO");
+ return TST_FAILED;
+ }
+
+ return TST_SUCCESS;
+}
+
+#define TFILE "test.io"
+
+static int test_IOFile(void)
+{
+ uint8_t buffer[128];
+ unsigned int i;
+ int ret;
+ GP_IO *io;
+
+ for (i = 0; i < sizeof(buffer); i++)
+ buffer[i] = i;
+
+ io = GP_IOFile(TFILE, GP_IO_WRONLY);
+
+ if (!io) {
+ tst_msg("Failed to open file IO for writing: %s",
+ strerror(errno));
+ return TST_FAILED;
+ }
+
+ ret = GP_IOWrite(io, buffer, sizeof(buffer));
+
+ if (ret != sizeof(buffer)) {
+ tst_msg("Failed to write: %s", strerror(errno));
+ return TST_FAILED;
+ }
+
+ if (GP_IOClose(io)) {
+ tst_msg("Failed to close file IO: %s", strerror(errno));
+ return TST_FAILED;
+ }
+
+ io = GP_IOFile(TFILE, GP_IO_RDONLY);
+
+ if (!io) {
+ tst_msg("Failed to open file IO for reading: %s",
+ strerror(errno));
+ return TST_FAILED;
+ }
+
+ ret = do_test(io);
+ if (ret)
+ return ret;
+
+ if (GP_IOClose(io)) {
+ tst_msg("Failed to close file IO: %s", strerror(errno));
+ return TST_FAILED;
+ }
+
+ return TST_SUCCESS;
+}
+
+static ssize_t test_IOFill_read(GP_IO GP_UNUSED(*io), void *buf, size_t size)
+{
+ ssize_t ret = GP_MIN(7u, size);
+
+ memset(buf, 'a', ret);
+
+ return ret;
+}
+
+static int try_IOFill_and_check(GP_IO *io, unsigned int size)
+{
+ uint8_t buf[125];
+ unsigned int i, fail = 0;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (GP_IOFill(io, buf, size)) {
+ tst_msg("Failed to fill buffer size=%u: %s",
+ size, strerror(errno));
+ return TST_FAILED;
+ }
+
+ for (i = 0; i < size; i++) {
+ if (buf[i] != 'a') {
+ tst_msg("Wrong data in buffer at %u", i);
+ fail++;
+ }
+ }
+
+ for (i = size; i < sizeof(buf); i++) {
+ if (buf[i] != 0) {
+ tst_msg("Wrong data in buffer at %u", i);
+ fail++;
+ }
+ }
+
+ if (fail)
+ return TST_FAILED;
+
+ return TST_SUCCESS;
+}
+
+static int test_IOFill(void)
+{
+ GP_IO io = {.Read = test_IOFill_read};
+ int ret = 0;
+
+ ret += try_IOFill_and_check(&io, 7);
+ ret += try_IOFill_and_check(&io, 10);
+ ret += try_IOFill_and_check(&io, 43);
+ ret += try_IOFill_and_check(&io, 69);
+
+ if (ret)
+ return TST_FAILED;
+
+ return TST_SUCCESS;
+}
+
+const struct tst_suite tst_suite = {
+ .suite_name = "IO",
+ .tests = {
+ {.name = "IOMem",
+ .tst_fn = test_IOMem,
+ .flags = TST_CHECK_MALLOC},
+
+ {.name = "IOFile",
+ .tst_fn = test_IOFile,
+ .flags = TST_CHECK_MALLOC | TST_TMPDIR},
+
+ {.name = "IOFill",
+ .tst_fn = test_IOFill},
+
+ {.name = NULL},
+ }
+};
diff --git a/tests/loaders/Makefile b/tests/loaders/Makefile
index a5a14cf..6678352 100644
--- a/tests/loaders/Makefile
+++ b/tests/loaders/Makefile
@@ -1,10 +1,10 @@
TOPDIR=../..
include $(TOPDIR)/pre.mk
-CSOURCES=loaders_suite.c PNG.c PBM.c PGM.c PPM.c ZIP.c GIF.c
+CSOURCES=loaders_suite.c PNG.c PBM.c PGM.c PPM.c ZIP.c GIF.c IO.c
GENSOURCES=SaveLoad.gen.c SaveAbort.gen.c
-APPS=loaders_suite PNG PBM PGM PPM SaveLoad.gen SaveAbort.gen ZIP GIF
+APPS=loaders_suite PNG PBM PGM PPM SaveLoad.gen SaveAbort.gen ZIP GIF IO
include ../tests.mk
diff --git a/tests/loaders/data/gif/valid/100x100-white.gif b/tests/loaders/data/gif/valid/100x100-white.gif
new file mode 100644
index 0000000..11f0f8f
Binary files /dev/null and b/tests/loaders/data/gif/valid/100x100-white.gif differ
diff --git a/tests/loaders/test_list.txt b/tests/loaders/test_list.txt
index 4ff3077..add0cb3 100644
--- a/tests/loaders/test_list.txt
+++ b/tests/loaders/test_list.txt
@@ -6,5 +6,6 @@ PGM
PPM
ZIP
GIF
+IO
SaveLoad.gen
SaveAbort.gen
http://repo.or.cz/w/gfxprim.git/commit/342537c6df7ca58ca4ac35d0b6f1dae16ef6…
commit 342537c6df7ca58ca4ac35d0b6f1dae16ef6746a
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Fri Jan 3 20:48:18 2014 +0100
tests: loaders: Very basic GIF test.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/tests/loaders/GIF.c b/tests/loaders/GIF.c
new file mode 100644
index 0000000..e33847e
--- /dev/null
+++ b/tests/loaders/GIF.c
@@ -0,0 +1,68 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <core/GP_Context.h>
+#include <core/GP_GetPutPixel.h>
+#include <loaders/GP_Loaders.h>
+
+#include "tst_test.h"
+
+static int test_load_GIF(const char *path)
+{
+ GP_Context *img;
+
+ errno = 0;
+
+ img = GP_LoadGIF(path, NULL);
+
+ if (img == NULL) {
+ switch (errno) {
+ case ENOSYS:
+ tst_msg("Not Implemented");
+ return TST_SKIPPED;
+ default:
+ tst_msg("Got %s", strerror(errno));
+ return TST_FAILED;
+ }
+ }
+
+ GP_ContextFree(img);
+
+ return TST_SUCCESS;
+}
+
+const struct tst_suite tst_suite = {
+ .suite_name = "GIF",
+ .tests = {
+ {.name = "GIF Load 100x100",
+ .tst_fn = test_load_GIF,
+ .res_path = "data/gif/valid/100x100-white.gif",
+ .data = "100x100-white.gif",
+ .flags = TST_TMPDIR | TST_CHECK_MALLOC},
+
+ {.name = NULL},
+ }
+};
diff --git a/tests/loaders/Makefile b/tests/loaders/Makefile
index a592ff9..a5a14cf 100644
--- a/tests/loaders/Makefile
+++ b/tests/loaders/Makefile
@@ -1,10 +1,10 @@
TOPDIR=../..
include $(TOPDIR)/pre.mk
-CSOURCES=loaders_suite.c PNG.c PBM.c PGM.c PPM.c ZIP.c
+CSOURCES=loaders_suite.c PNG.c PBM.c PGM.c PPM.c ZIP.c GIF.c
GENSOURCES=SaveLoad.gen.c SaveAbort.gen.c
-APPS=loaders_suite PNG PBM PGM PPM SaveLoad.gen SaveAbort.gen ZIP
+APPS=loaders_suite PNG PBM PGM PPM SaveLoad.gen SaveAbort.gen ZIP GIF
include ../tests.mk
diff --git a/tests/loaders/test_list.txt b/tests/loaders/test_list.txt
index 9f52d34..4ff3077 100644
--- a/tests/loaders/test_list.txt
+++ b/tests/loaders/test_list.txt
@@ -5,5 +5,6 @@ PBM
PGM
PPM
ZIP
+GIF
SaveLoad.gen
SaveAbort.gen
http://repo.or.cz/w/gfxprim.git/commit/f36c5f6d8df50ad268711cc97c9bc369672b…
commit f36c5f6d8df50ad268711cc97c9bc369672b7fe8
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Fri Jan 3 19:23:18 2014 +0100
config: Add GA88 pixel type.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/gfxprim_config.py b/gfxprim_config.py
index b972c0e..8bb69f4 100644
--- a/gfxprim_config.py
+++ b/gfxprim_config.py
@@ -122,6 +122,10 @@ config = GfxPrimConfig(
PixelType(name='G8', pixelsize=PS_8BPP, chanslist=[
('V', 0, 8)]),
+ PixelType(name='GA88', pixelsize=PS_16BPP, chanslist=[
+ ('V', 0, 8),
+ ('A', 8, 8)]),
+
PixelType(name='G16', pixelsize=PS_16BPP, chanslist=[
('V', 0, 16)]),
]
-----------------------------------------------------------------------
Summary of changes:
build/syms/Loaders_symbols.txt | 24 +-
demos/c_simple/Makefile | 3 +-
.../{backend_timers_example.c => memory_io.c} | 102 +++---
doc/Makefile | 2 +-
doc/example_memory_io.txt | 9 +
doc/loaders.txt | 247 +++++-------
doc/loaders_io.txt | 190 +++++++++
gfxprim_config.py | 4 +
include/loaders/GP_BMP.h | 38 +--
include/loaders/GP_GIF.h | 30 +-
include/loaders/GP_IO.h | 184 +++++++++
include/loaders/GP_JP2.h | 19 +-
include/loaders/GP_JPG.h | 27 +-
include/loaders/GP_Loader.h | 2 +-
include/loaders/GP_PNG.h | 37 +--
include/loaders/GP_PNM.h | 11 +-
include/loaders/GP_PSP.h | 32 +-
include/loaders/GP_TIFF.h | 37 +--
libs/loaders/GP_BMP.c | 283 ++++++-------
libs/loaders/GP_BMP_RLE.h | 84 +++--
libs/loaders/GP_GIF.c | 93 +++--
libs/loaders/GP_IO.c | 432 ++++++++++++++++++++
libs/loaders/GP_JP2.c | 73 ++--
libs/loaders/GP_JPG.c | 107 ++++--
libs/loaders/GP_PNG.c | 83 ++---
libs/loaders/GP_PNM.c | 347 ++++++++++------
libs/loaders/GP_PSP.c | 278 ++++++-------
libs/loaders/GP_TIFF.c | 99 ++++--
libs/loaders/GP_ZIP.c | 198 +++++----
tests/{input/TimeStamp.c => loaders/GIF.c} | 58 ++--
tests/loaders/IO.c | 274 +++++++++++++
tests/loaders/Makefile | 4 +-
tests/loaders/data/gif/valid/100x100-white.gif | Bin 0 -> 169 bytes
tests/loaders/test_list.txt | 2 +
34 files changed, 2281 insertions(+), 1132 deletions(-)
copy demos/c_simple/{backend_timers_example.c => memory_io.c} (57%)
create mode 100644 doc/example_memory_io.txt
create mode 100644 doc/loaders_io.txt
create mode 100644 include/loaders/GP_IO.h
create mode 100644 libs/loaders/GP_IO.c
copy tests/{input/TimeStamp.c => loaders/GIF.c} (70%)
create mode 100644 tests/loaders/IO.c
create mode 100644 tests/loaders/data/gif/valid/100x100-white.gif
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
Hi!
> The size limitation issues are not currently that important. However
> can spiv open a BigTiff file even if it is just 20K in size?
> All the current viewers refuse to open a BigTiff file even if it very
> small.
>
GFXprim uses libtiff and accordinlgy to libtiff web pages BigTiff support
was merged in 4.0, so this much or less depends on libtiff version.
On my Linux system libtiff is new enough (4.0.3) and spiv seems to show
sample BigTiff images I've found just fine (not all of them though, there
are
still unsupported pixel types, etc. but I'm working on that...).
PS: Please use 'reply to all' next time so that the mail gets to the
mailing list too.
--
Cyril Hrubis
2
1
Hello:
Does Gfxprim handle BigTiff images;i.e., libtiff v4.x and greater?
If so can spiv show BigTiff images?
BigTiff allows tiff files to be up to 2 to power of 64 minus one in size.
regards,
west suhanic
2
1
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via 40750bfe2c6ba222376f458bb80e8e48ecf93e52 (commit)
via 19d12296f7582adeba1007e316f3a52f28a0256e (commit)
from 4ce30170690a4018166ed1e474dbbce264706958 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/40750bfe2c6ba222376f458bb80e8e48ecf9…
commit 40750bfe2c6ba222376f458bb80e8e48ecf93e52
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Fri Jan 3 19:06:45 2014 +0100
doc: Remove unused image, fix typo.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/doc/asteroids-corner.png b/doc/asteroids-corner.png
deleted file mode 100644
index 2e4cf0b..0000000
Binary files a/doc/asteroids-corner.png and /dev/null differ
diff --git a/doc/index.txt b/doc/index.txt
index cb3302b..48596e3 100644
--- a/doc/index.txt
+++ b/doc/index.txt
@@ -54,7 +54,7 @@ https://build.opensuse.org/package/show/home:metan/gfxprim[buildservice].
Or download prebuild Debian
http://gfxprim.ucw.cz/packages/debian/wheezy/[amd64 Wheezy packages].
-The GFXprim 1.0.0-rc1 has been released!
+The GFXprim 1.0.0-rc0 has been released!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Download
http://repo.or.cz/w/gfxprim.git/commit/19d12296f7582adeba1007e316f3a52f28a0…
commit 19d12296f7582adeba1007e316f3a52f28a0256e
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Fri Jan 3 19:06:20 2014 +0100
gentoo: Add initial ebuilds.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/gentoo/media-libs/gfxprim/Manifest b/gentoo/media-libs/gfxprim/Manifest
new file mode 100644
index 0000000..091cf8b
--- /dev/null
+++ b/gentoo/media-libs/gfxprim/Manifest
@@ -0,0 +1,4 @@
+AUX configure-more-compatible-with-autoconf.patch 5335 SHA256 54f7614efee554a3ce8d90835df909a3e66272896018f65c600d0d93c038513e SHA512 6e55396524c0d9ce14f4cde643d8ff09fa04bee8437e64c3701e7e6c833abe902b9abdcf02ea883f29466c10e66836b11cc26755c91594e3a56ea60dd0e6be9b WHIRLPOOL b9f7a9cb54ca5af28dcc8bd1100857b8ddc6c178cd4572977ed6a914fa8ad6f5b8e8addbed2070250bcf9c15c3e28875c80bbe3f0b94f8c98933e275634aff65
+DIST gfxprim-1.0.0_rc1.tar.bz2 326144 SHA256 0c543f45fa779a9503944723a7c9c449688e0fd66207f8adcc99cc667eed5582 SHA512 7481006d80d8ffc8302e1bc11e9b19253e37ed562ff465ac4028dcd73c6bfae073bad859204c3d7917d5eaebf38080802ef0463232eb436075addc9bd60af219 WHIRLPOOL 5cdf9008ec41752063556e98238a0cbeb1b3c8d1ef7fe899e632942b5e9d5d19955f4e097146fb385c0829137770463f1b36dd41737550de1bcfe07bdcf9f217
+EBUILD gfxprim-1.0.0_rc1.ebuild 1489 SHA256 ea09af7501316d26ef907c1f37e2329ae422202a57e470634f8a496906130c3f SHA512 d546f7f7fd0088f65993a238f0963c8ca4b5756a5fedbda57517cc49844f7e78b1675749a954e9e62dddd7e70bdb5132f4cd5f1f631b0abe8c3f321e6761576b WHIRLPOOL ac8f36b8bbf0ac71e35621c60cf7f1720d94e5574bcc40f6b20b2bb44f118e9b92571c9111f8fc57d404e95b16050261b67b193e004dbe85467b1de50940d539
+EBUILD gfxprim-9999.ebuild 1489 SHA256 ea09af7501316d26ef907c1f37e2329ae422202a57e470634f8a496906130c3f SHA512 d546f7f7fd0088f65993a238f0963c8ca4b5756a5fedbda57517cc49844f7e78b1675749a954e9e62dddd7e70bdb5132f4cd5f1f631b0abe8c3f321e6761576b WHIRLPOOL ac8f36b8bbf0ac71e35621c60cf7f1720d94e5574bcc40f6b20b2bb44f118e9b92571c9111f8fc57d404e95b16050261b67b193e004dbe85467b1de50940d539
diff --git a/gentoo/media-libs/gfxprim/files/configure-more-compatible-with-autoconf.patch b/gentoo/media-libs/gfxprim/files/configure-more-compatible-with-autoconf.patch
new file mode 100644
index 0000000..8a587cf
--- /dev/null
+++ b/gentoo/media-libs/gfxprim/files/configure-more-compatible-with-autoconf.patch
@@ -0,0 +1,166 @@
+From 4ce30170690a4018166ed1e474dbbce264706958 Mon Sep 17 00:00:00 2001
+From: Cyril Hrubis <metan(a)ucw.cz>
+Date: Fri, 3 Jan 2014 17:40:18 +0100
+Subject: [PATCH] configure: Now more compatible with autoconf
+
+* Fix prefix handling
+
+ - now setting --foodir (mandir, bindir, ...) adds the --prefix only if the
+ value does not start with slash (i.e. local path)
+
+* Add a few compatibility options, i.e. infodir, sysconfdir, etc.
+
+* Move -fPIC and -pthread to config.mk so that it's not overridden by
+ CFLAGS from the build system
+
+Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
+---
+ config.mk | 1 +
+ configure | 36 ++++++++++++++++++++++++++++++++----
+ install.mk | 8 ++++----
+ install.sh | 6 +++---
+ pyinst.mk | 2 +-
+ 5 files changed, 41 insertions(+), 12 deletions(-)
+
+diff --git a/config.mk b/config.mk
+index 9273375..82b349a 100644
+--- a/config.mk
++++ b/config.mk
+@@ -1,5 +1,6 @@
+ include $(TOPDIR)/config.gen.mk
+
++CFLAGS+=-fPIC -pthread
+ CFLAGS+=-I$(TOPDIR)/include/
+ LDFLAGS+=-L$(TOPDIR)/build/
+
+diff --git a/configure b/configure
+index 200bfc7..728a180 100755
+--- a/configure
++++ b/configure
+@@ -100,6 +100,23 @@ def check_for_python_config(cfg):
+ sys.stderr.write('Yesn')
+
+ #
++# Adds prefix to *dir vars but only if the path does not start with '/'
++#
++def cfg_get_value(cfg_key):
++ if (cfg_key.endswith('dir')):
++ value = cfg[cfg_key][0]
++ if (value.startswith('/')):
++ return value
++ else:
++ prefix = cfg['prefix'][0]
++ if (prefix.endswith('/')):
++ return prefix + value
++ else:
++ return prefix + '/' + value
++ else:
++ return cfg[cfg_key][0]
++
++#
+ # Library checking api
+ #
+ class libraries:
+@@ -116,7 +133,8 @@ class libraries:
+ sys.stderr.write("----------------------n")
+
+ for i in cfg:
+- sys.stderr.write("%14s : '%s'n" % (i, cfg[i][0]))
++ value = cfg_get_value(i)
++ sys.stderr.write("%14s : '%s'n" % (i, value))
+ sys.stderr.write(" - %snn" % cfg[i][1])
+
+ sys.stderr.write("Libraries to link againstn")
+@@ -250,8 +268,10 @@ def write_config_h(cfg, libs):
+
+ def write_config_mk(cfg, libs):
+ f = open('config.gen.mk', 'w')
++
+ for i in cfg:
+- f.write("# %sn%s=%sn" % (cfg[i][1], i, cfg[i][0]))
++ f.write("# %sn%s=%sn" % (cfg[i][1], i, cfg_get_value(i)))
++
+ libs.write_config_mk(f);
+ f.close()
+ sys.stderr.write("Config 'config.gen.mk' writtenn")
+@@ -303,7 +323,7 @@ if __name__ == '__main__':
+ # Dictionary for default configuration parameters
+ #
+ cfg = {'CC' : ['gcc', 'Path/name of the C compiler'],
+- 'CFLAGS' : ['-pthread -W -Wall -Wextra -fPIC -O2 -ggdb', 'C compiler flags'],
++ 'CFLAGS' : ['-W -Wall -Wextra -O2 -ggdb', 'C compiler flags'],
+ 'PYTHON_BIN' : ['python', 'Path/name of python interpreter'],
+ 'SWIG' : ['swig', 'Simplified Wrapper and Interface Generator'],
+ 'PYTHON_CONFIG' : ['python-config', 'Python config helper'],
+@@ -313,7 +333,15 @@ if __name__ == '__main__':
+ 'bindir' : ['bin', 'Where to install binaries'],
+ 'libdir' : ['', 'Where to install libraries'],
+ 'includedir' : ['include', 'Where to install headers'],
+- 'mandir' : ['share/man', 'Where to install man pages']}
++ 'mandir' : ['share/man', 'Where to install man pages'],
++ # Here comes autoconf compatibility cruft, not used for anything yet
++ 'infodir' : ['share/info', 'Where to install info pages'],
++ 'datadir' : ['share', 'Where to place readonly arch independend datafiles'],
++ 'sysconfdir' : ['etc', 'Where to place configuration'],
++ 'localstatedir' : ['local/var/', 'Where to place runtime modified datafiles'],
++ 'build' : ['', 'WARNING not used'],
++ 'host' : ['', 'WARNING not used'],
++ }
+
+ #
+ # Library detection/enable disable
+diff --git a/install.mk b/install.mk
+index 991247a..4b777c0 100644
+--- a/install.mk
++++ b/install.mk
+@@ -1,13 +1,13 @@
+ ifdef DESTDIR
+-BIN_DIR=$(DESTDIR)$(prefix)/$(bindir)
++BIN_DIR=$(DESTDIR)/$(bindir)
+ else
+-BIN_DIR=$(prefix)/$(bindir)
++BIN_DIR=$(bindir)
+ endif
+
+ ifdef DESTDIR
+-MAN_DIR=$(DESTDIR)$(prefix)/$(mandir)/man1
++MAN_DIR=$(DESTDIR)/$(mandir)/man1
+ else
+-MAN_DIR=$(prefix)/$(mandir)/man1
++MAN_DIR=$(mandir)/man1
+ endif
+
+ install:
+diff --git a/install.sh b/install.sh
+index a0f8d83..dbb2ca8 100755
+--- a/install.sh
++++ b/install.sh
+@@ -5,9 +5,9 @@ LIBDIR="$2"
+ BINDIR="$3"
+ INCLUDEDIR="$4"
+
+-HEADER_LOC="${DESTDIR}$PREFIX/$INCLUDEDIR"
+-LIB_LOC="${DESTDIR}$PREFIX/$LIBDIR"
+-BIN_LOC="${DESTDIR}$PREFIX/$BINDIR"
++HEADER_LOC="${DESTDIR}/$INCLUDEDIR"
++LIB_LOC="${DESTDIR}/$LIBDIR"
++BIN_LOC="${DESTDIR}/$BINDIR"
+
+ # Headers
+ echo "INSTALL headers ($HEADER_LOC)"
+diff --git a/pyinst.mk b/pyinst.mk
+index f1323b6..4a273cb 100644
+--- a/pyinst.mk
++++ b/pyinst.mk
+@@ -6,7 +6,7 @@
+ ifdef SWIG
+ ifdef PYTHON_CONFIG
+
+-PY_INSTALL_PREFIX=$(prefix)/$(libdir)/python$(PYTHON_VER)/gfxprim/$(LIBNAME)
++PY_INSTALL_PREFIX=$(libdir)/python$(PYTHON_VER)/gfxprim/$(LIBNAME)
+
+ ifdef DESTDIR
+ PY_INSTALL_PREFIX:=$(DESTDIR)$(PY_INSTALL_PREFIX)
+--
+1.8.3.2
+
diff --git a/gentoo/media-libs/gfxprim/gfxprim-1.0.0_rc1.ebuild b/gentoo/media-libs/gfxprim/gfxprim-1.0.0_rc1.ebuild
new file mode 100644
index 0000000..c748fa3
--- /dev/null
+++ b/gentoo/media-libs/gfxprim/gfxprim-1.0.0_rc1.ebuild
@@ -0,0 +1,60 @@
+# Copyright 1999-2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: $
+
+EAPI=5
+
+inherit eutils
+
+if [ "${PV}" = 9999 ]; then
+ EGIT_REPO_URI="https://github.com/gfxprim/gfxprim.git"
+ inherit git-2
+ KEYWORDS=""
+else
+ SRC_URI="http://gfxprim.ucw.cz/releases/${P}.tar.bz2"
+ KEYWORDS="~amd64 ~x86 ~arm ~ppc"
+fi
+
+DESCRIPTION="Modular 2D bitmap graphics library"
+HOMEPAGE="http://gfxprim.ucw.cz/"
+
+LICENSE="LGPL-2.1+"
+SLOT="0"
+IUSE="jpeg png gif tiff jpeg2k freetype X sdl aalib python"
+
+RDEPEND="jpeg? ( virtual/jpeg )
+ png? ( media-libs/libpng )
+ gif? ( media-libs/giflib )
+ tiff? ( media-libs/tiff )
+ jpeg2k? ( >=media-libs/openjpeg-2.0.0 )
+ freetype? ( media-libs/freetype )
+ X? ( x11-libs/libX11 )
+ sdl? ( media-libs/libsdl )
+ aalib? ( media-libs/aalib )
+"
+
+DEPEND="$RDEPEND
+ dev-python/jinja
+ python? ( dev-lang/swig )
+"
+
+src_prepare() {
+ if [ "${PV}" != 9999 ]; then
+ epatch ${FILESDIR}/configure-more-compatible-with-autoconf.patch
+ fi
+}
+
+src_configure() {
+ use !jpeg && conf="${conf} --disable=jpeg"
+ use !png && conf="${conf} --disable=libpng"
+ use !gif && conf="${conf} --disable=giflib"
+ use !tiff && conf="${conf} --disable=tiff"
+ use !jpeg2k && conf="${conf} --disable=openjpeg"
+ use !freetype && conf="${conf} --disable=freetype"
+ use !X && conf="${conf} --disable=libX11"
+ use !sdl && conf="${conf} --disable=libsdl"
+ use !aalib && conf="${conf} --disable=aalib"
+ use !python && conf="${conf} --PYTHON_CONFIG=''"
+
+ econf ${conf}
+}
diff --git a/gentoo/media-libs/gfxprim/gfxprim-9999.ebuild b/gentoo/media-libs/gfxprim/gfxprim-9999.ebuild
new file mode 120000
index 0000000..8ecb30f
--- /dev/null
+++ b/gentoo/media-libs/gfxprim/gfxprim-9999.ebuild
@@ -0,0 +1 @@
+gfxprim-1.0.0_rc1.ebuild
No newline at end of file
-----------------------------------------------------------------------
Summary of changes:
doc/asteroids-corner.png | Bin 5241 -> 0 bytes
doc/index.txt | 2 +-
gentoo/media-libs/gfxprim/Manifest | 4 +
.../configure-more-compatible-with-autoconf.patch | 166 ++++++++++++++++++++
gentoo/media-libs/gfxprim/gfxprim-1.0.0_rc1.ebuild | 60 +++++++
gentoo/media-libs/gfxprim/gfxprim-9999.ebuild | 1 +
6 files changed, 232 insertions(+), 1 deletions(-)
delete mode 100644 doc/asteroids-corner.png
create mode 100644 gentoo/media-libs/gfxprim/Manifest
create mode 100644 gentoo/media-libs/gfxprim/files/configure-more-compatible-with-autoconf.patch
create mode 100644 gentoo/media-libs/gfxprim/gfxprim-1.0.0_rc1.ebuild
create mode 120000 gentoo/media-libs/gfxprim/gfxprim-9999.ebuild
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via 4ce30170690a4018166ed1e474dbbce264706958 (commit)
from acc0e486f8637754ffdc19b5c0bd463d1317841d (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/4ce30170690a4018166ed1e474dbbce26470…
commit 4ce30170690a4018166ed1e474dbbce264706958
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Fri Jan 3 17:40:18 2014 +0100
configure: Now more compatible with autoconf
* Fix prefix handling
- now setting --foodir (mandir, bindir, ...) adds the --prefix only if the
value does not start with slash (i.e. local path)
* Add a few compatibility options, i.e. infodir, sysconfdir, etc.
* Move -fPIC and -pthread to config.mk so that it's not overridden by
CFLAGS from the build system
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/config.mk b/config.mk
index 9273375..82b349a 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,6 @@
include $(TOPDIR)/config.gen.mk
+CFLAGS+=-fPIC -pthread
CFLAGS+=-I$(TOPDIR)/include/
LDFLAGS+=-L$(TOPDIR)/build/
diff --git a/configure b/configure
index 200bfc7..728a180 100755
--- a/configure
+++ b/configure
@@ -100,6 +100,23 @@ def check_for_python_config(cfg):
sys.stderr.write('Yesn')
#
+# Adds prefix to *dir vars but only if the path does not start with '/'
+#
+def cfg_get_value(cfg_key):
+ if (cfg_key.endswith('dir')):
+ value = cfg[cfg_key][0]
+ if (value.startswith('/')):
+ return value
+ else:
+ prefix = cfg['prefix'][0]
+ if (prefix.endswith('/')):
+ return prefix + value
+ else:
+ return prefix + '/' + value
+ else:
+ return cfg[cfg_key][0]
+
+#
# Library checking api
#
class libraries:
@@ -116,7 +133,8 @@ class libraries:
sys.stderr.write("----------------------n")
for i in cfg:
- sys.stderr.write("%14s : '%s'n" % (i, cfg[i][0]))
+ value = cfg_get_value(i)
+ sys.stderr.write("%14s : '%s'n" % (i, value))
sys.stderr.write(" - %snn" % cfg[i][1])
sys.stderr.write("Libraries to link againstn")
@@ -250,8 +268,10 @@ def write_config_h(cfg, libs):
def write_config_mk(cfg, libs):
f = open('config.gen.mk', 'w')
+
for i in cfg:
- f.write("# %sn%s=%sn" % (cfg[i][1], i, cfg[i][0]))
+ f.write("# %sn%s=%sn" % (cfg[i][1], i, cfg_get_value(i)))
+
libs.write_config_mk(f);
f.close()
sys.stderr.write("Config 'config.gen.mk' writtenn")
@@ -303,7 +323,7 @@ if __name__ == '__main__':
# Dictionary for default configuration parameters
#
cfg = {'CC' : ['gcc', 'Path/name of the C compiler'],
- 'CFLAGS' : ['-pthread -W -Wall -Wextra -fPIC -O2 -ggdb', 'C compiler flags'],
+ 'CFLAGS' : ['-W -Wall -Wextra -O2 -ggdb', 'C compiler flags'],
'PYTHON_BIN' : ['python', 'Path/name of python interpreter'],
'SWIG' : ['swig', 'Simplified Wrapper and Interface Generator'],
'PYTHON_CONFIG' : ['python-config', 'Python config helper'],
@@ -313,7 +333,15 @@ if __name__ == '__main__':
'bindir' : ['bin', 'Where to install binaries'],
'libdir' : ['', 'Where to install libraries'],
'includedir' : ['include', 'Where to install headers'],
- 'mandir' : ['share/man', 'Where to install man pages']}
+ 'mandir' : ['share/man', 'Where to install man pages'],
+ # Here comes autoconf compatibility cruft, not used for anything yet
+ 'infodir' : ['share/info', 'Where to install info pages'],
+ 'datadir' : ['share', 'Where to place readonly arch independend datafiles'],
+ 'sysconfdir' : ['etc', 'Where to place configuration'],
+ 'localstatedir' : ['local/var/', 'Where to place runtime modified datafiles'],
+ 'build' : ['', 'WARNING not used'],
+ 'host' : ['', 'WARNING not used'],
+ }
#
# Library detection/enable disable
diff --git a/install.mk b/install.mk
index 991247a..4b777c0 100644
--- a/install.mk
+++ b/install.mk
@@ -1,13 +1,13 @@
ifdef DESTDIR
-BIN_DIR=$(DESTDIR)$(prefix)/$(bindir)
+BIN_DIR=$(DESTDIR)/$(bindir)
else
-BIN_DIR=$(prefix)/$(bindir)
+BIN_DIR=$(bindir)
endif
ifdef DESTDIR
-MAN_DIR=$(DESTDIR)$(prefix)/$(mandir)/man1
+MAN_DIR=$(DESTDIR)/$(mandir)/man1
else
-MAN_DIR=$(prefix)/$(mandir)/man1
+MAN_DIR=$(mandir)/man1
endif
install:
diff --git a/install.sh b/install.sh
index a0f8d83..dbb2ca8 100755
--- a/install.sh
+++ b/install.sh
@@ -5,9 +5,9 @@ LIBDIR="$2"
BINDIR="$3"
INCLUDEDIR="$4"
-HEADER_LOC="${DESTDIR}$PREFIX/$INCLUDEDIR"
-LIB_LOC="${DESTDIR}$PREFIX/$LIBDIR"
-BIN_LOC="${DESTDIR}$PREFIX/$BINDIR"
+HEADER_LOC="${DESTDIR}/$INCLUDEDIR"
+LIB_LOC="${DESTDIR}/$LIBDIR"
+BIN_LOC="${DESTDIR}/$BINDIR"
# Headers
echo "INSTALL headers ($HEADER_LOC)"
diff --git a/pyinst.mk b/pyinst.mk
index f1323b6..4a273cb 100644
--- a/pyinst.mk
+++ b/pyinst.mk
@@ -6,7 +6,7 @@
ifdef SWIG
ifdef PYTHON_CONFIG
-PY_INSTALL_PREFIX=$(prefix)/$(libdir)/python$(PYTHON_VER)/gfxprim/$(LIBNAME)
+PY_INSTALL_PREFIX=$(libdir)/python$(PYTHON_VER)/gfxprim/$(LIBNAME)
ifdef DESTDIR
PY_INSTALL_PREFIX:=$(DESTDIR)$(PY_INSTALL_PREFIX)
-----------------------------------------------------------------------
Summary of changes:
config.mk | 1 +
configure | 36 ++++++++++++++++++++++++++++++++----
install.mk | 8 ++++----
install.sh | 6 +++---
pyinst.mk | 2 +-
5 files changed, 41 insertions(+), 12 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0