--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore Sun Dec 27 23:14:10 2009 +0200
@@ -0,0 +1,10 @@
+syntax: regexp
+
+\.[^/]+\.sw[op]$
+
+^build/
+^bin/
+^lib/
+^doc/html
+^dist
+^Learning Diary\.pdf$
--- a/Makefile Sun Dec 27 22:01:17 2009 +0200
+++ b/Makefile Sun Dec 27 23:14:10 2009 +0200
@@ -6,22 +6,17 @@
# preprocessor flags
CPPFLAGS = -Isrc/
+# libraries to use
+LOADLIBES = -lpng
+
# output name
-DIST_NAME = 78949E-as1
+DIST_NAME = 78949E-as2
DIST_RESOURCES = README "Learning Diary.pdf"
-all: depend bin/daemon lib/libnetdaemon.so bin/client
+all: depend lib/libpngtile.so
-bin/daemon : lib/libnetdaemon.so \
- build/obj/daemon/daemon.o build/obj/daemon/service.o build/obj/daemon/client.o build/obj/daemon/commands.o \
- build/obj/daemon/process.o \
- build/obj/shared/select.o build/obj/shared/log.o build/obj/shared/util.o build/obj/shared/signal.o
-
-lib/libnetdaemon.so : \
- build/obj/lib/client.o build/obj/lib/commands.o \
- build/obj/shared/proto.o
-
-bin/client : lib/libnetdaemon.so build/obj/shared/log.o
+lib/libpngtile.so : \
+ build/obj/lib/image.o build/obj/lib/cache.o
SRC_PATHS = $(wildcard src/*/*.c)
SRC_NAMES = $(patsubst src/%,%,$(SRC_PATHS))
--- a/src/lib/cache.c Sun Dec 27 22:01:17 2009 +0200
+++ b/src/lib/cache.c Sun Dec 27 23:14:10 2009 +0200
@@ -1,55 +1,234 @@
#include "cache.h"
-static int pt_cache_new (struct pt_cache **cache_ptr)
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+
+
+static int pt_cache_new (struct pt_cache **cache_ptr, const char *path)
{
struct pt_cache *cache;
+ // alloc
if ((cache = calloc(1, sizeof(*cache))) == NULL)
return -1;
+ if ((cache->path = strdup(path)) == NULL)
+ goto error;
+
+ // init
+ cache->fd = -1;
+
+ // ok
+ *cache_ptr = cache;
+
+ return 0;
+
+error:
+ // cleanup
+ if (cache)
+ pt_cache_destroy(cache);
+
+ return -1;
+}
+
+int pt_cache_open (struct pt_cache **cache_ptr, const char *path, int mode)
+{
+ struct pt_cache *cache;
+
+ // alloc
+ if (pt_cache_new(&cache, path))
+ return -1;
+
// ok
*cache_ptr = cache;
return 0;
}
-int pt_cache_open (struct pt_cache **cache_ptr, struct pt_image *img, int mode)
-{
- struct pt_cache *cache;
-
- // alloc
- if (pt_cache_new(&cache))
- return -1;
-
-
-}
-
-bool pt_cache_fresh (struct pt_cache *cache)
+int pt_cache_stale (struct pt_cache *cache, const char *orig_path)
{
// TODO: stat + mtime
return false;
}
/**
+ * Abort any incomplete open operation, cleaning up
+ */
+static void pt_cache_abort (struct pt_cache *cache)
+{
+ if (cache->mmap != NULL) {
+ munmap(cache->mmap, cache->size);
+
+ cache->mmap = NULL;
+ }
+
+ if (cache->fd >= 0) {
+ close(cache->fd);
+
+ cache->fd = -1;
+ }
+}
+
+/**
+ * Open the cache file as an fd.
+ *
+ * XXX: needs locking
+ */
+static int pt_cache_open_fd (struct pt_cache *cache, int *fd_ptr)
+{
+ int fd;
+ int flags = 0;
+
+ // determine open flags
+ // XXX: O_RDONLY | O_WRONLY == O_RDWR?
+ if (cache->mode & PT_IMG_READ)
+ flags |= O_RDONLY;
+
+ if (cache->mode & PT_IMG_WRITE)
+ flags |= (O_WRONLY | O_CREAT);
+
+ // actual open()
+ if ((fd = open(cache->path, flags)) < 0)
+ return -1;
+
+ // ok
+ *fd_ptr = fd;
+
+ return 0;
+}
+
+/**
+ * Mmap the opened cache file from offset PT_CACHE_PAGE, using the calculated size stored in cache->size
+ */
+static int pt_cache_open_mmap (struct pt_cache *cache, void **addr_ptr)
+{
+ int prot = 0;
+ void *addr;
+
+ // determine prot
+ if (cache->mode & PT_IMG_READ)
+ prot |= PROT_READ;
+
+ if (cache->mode & PT_IMG_WRITE)
+ prot |= PROT_WRITE;
+
+ // perform mmap() from second page on
+ if ((addr = mmap(NULL, cache->size, prot, MAP_SHARED, cache->fd, PT_CACHE_PAGE)) == MAP_FAILED)
+ return -1;
+
+ // ok
+ *addr_ptr = addr;
+
+ return 0;
+}
+
+/**
+ * Write out the cache header into the opened file
+ */
+static int pt_cache_write_header (struct pt_cache *cache, const struct pt_cache_header *header)
+{
+ size_t len = sizeof(*header);
+ const char *buf = (const char *) header;
+
+ // seek to start
+ if (lseek(cache->fd, 0, SEEK_SET) != 0)
+ return -1;
+
+ // write out full header
+ while (len) {
+ ssize_t ret;
+
+ // try and write out the header
+ if ((ret = write(cache->fd, buf, len)) < 0)
+ return -1;
+
+ // update offset
+ buf += ret;
+ len -= ret;
+ }
+
+ // done
+ return 0;
+}
+
+/**
* Create a new cache file, open it, and write out the header.
*/
-static int pt_cache_create (struct pt_cache *cache, struct pt_cache_header *header)
+static int pt_cache_open_create (struct pt_cache *cache, struct pt_cache_header *header)
{
-
+ // open
+ if (pt_cache_open_fd(cache, &cache->fd))
+ return -1;
+
+ // calculate data size
+ cache->size = sizeof(*header) + header->height * header->row_bytes;
+
+ // grow file
+ if (ftruncate(cache->fd, PT_CACHE_PAGE + cache->size) < 0)
+ goto error;
+
+ // open mmap
+ if (pt_cache_open_mmap(cache, (void **) &cache->mmap))
+ goto error;
+
+ // write header
+ if (pt_cache_write_header(cache, header))
+ goto error;
+
+ // done
+ return 0;
+
+error:
+ // cleanup
+ pt_cache_abort(cache);
+
+ return -1;
}
int pt_cache_update_png (struct pt_cache *cache, png_structp png, png_infop info)
{
struct pt_cache_header header;
+
+ // XXX: check cache_mode
+ // XXX: check image doesn't use any options we don't handle
memset(&header, 0, sizeof(header));
// fill in basic info
- header->width = png_get_image_width(png, info);
- header->height = png_get_image_height(png, info);
- header->bit_depth = png_get_bit_depth(png, info);
- header->color_type = png_get_color_type(png, info);
+ header.width = png_get_image_width(png, info);
+ header.height = png_get_image_height(png, info);
+ header.bit_depth = png_get_bit_depth(png, info);
+ header.color_type = png_get_color_type(png, info);
// fill in other info
- header->row_bytes = png_get_rowbytes(png, info);
+ header.row_bytes = png_get_rowbytes(png, info);
+
+ // create and write out header
+ if (pt_cache_open_create(cache, &header))
+ return -1;
+
+ // XXX: pallette etc.
+
+ // write out raw image data a row at a time
+ for (size_t row = 0; row < header.height; row++) {
+ // read row data, non-interlaced
+ png_read_row(png, cache->mmap + row * header.row_bytes, NULL);
+ }
+
+ // done!
+ return 0;
}
+
+void pt_cache_destroy (struct pt_cache *cache)
+{
+ free(cache->path);
+
+ pt_cache_abort(cache);
+
+ free(cache);
+}
--- a/src/lib/cache.h Sun Dec 27 22:01:17 2009 +0200
+++ b/src/lib/cache.h Sun Dec 27 23:14:10 2009 +0200
@@ -8,14 +8,37 @@
*/
#include "image.h"
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <png.h>
+
/**
* State for cache access
*/
struct pt_cache {
+ /** Filesystem path to cache file */
+ char *path;
+ /** The mode we are operating in, bitmask of PT_IMG_* */
+ int mode;
+
+ /** Opened file */
+ int fd;
+
+ /** Memory-mapped file data, from the second page on */
+ uint8_t *mmap;
+
+ /** Size of the mmap'd segment in bytes */
+ size_t size;
};
/**
+ * Size of a cache file page in bytes
+ */
+#define PT_CACHE_PAGE 4096
+
+/**
* On-disk header
*/
struct pt_cache_header {
@@ -32,16 +55,21 @@
/**
* Construct the image cache info object associated with the given image.
*/
-int pt_cache_open (struct pt_cache **cache_ptr, struct pt_image *img, int mode);
+int pt_cache_open (struct pt_cache **cache_ptr, const char *path, int mode);
/**
- * Verify if the cached data is still fresh compared to the original.
+ * Verify if the cached data has become stale compared to the given original file.
*/
-bool pt_cache_fresh (struct pt_cache *cache);
+int pt_cache_stale (struct pt_cache *cache, const char *orig_path);
/**
* Update the cache data from the given PNG image.
*/
int pt_cache_update_png (struct pt_cache *cache, png_structp png, png_infop info);
+/**
+ * Release all resources associated with the given cache object without any cleanup.
+ */
+void pt_cache_destroy (struct pt_cache *cache);
+
#endif
--- a/src/lib/image.c Sun Dec 27 22:01:17 2009 +0200
+++ b/src/lib/image.c Sun Dec 27 23:14:10 2009 +0200
@@ -1,6 +1,12 @@
#include "image.h"
+#include "cache.h"
-static int pt_image_new (struct pt_image **img_ptr, struct pt_ctx *ctx, const char *png_path)
+#include <stdlib.h>
+#include <limits.h> // for _POSIX_PATH_MAX
+
+#include <png.h>
+
+static int pt_image_new (struct pt_image **img_ptr, struct pt_ctx *ctx, const char *path)
{
struct pt_image *img;
@@ -8,7 +14,7 @@
if ((img = calloc(1, sizeof(*img))) == NULL)
return -1;
- if ((img->png_path = strdup(png_path)) == NULL)
+ if ((img->path = strdup(path)) == NULL)
goto error;
// init
@@ -33,7 +39,7 @@
FILE *fp;
// open
- if (fopen(img->png_path, "rb") < 0)
+ if (fopen(img->path, "rb") < 0)
return -1;
// ok
@@ -71,6 +77,7 @@
png_init_io(png, fp);
// ok
+ // XXX: what to do with fp?
*png_ptr = png;
*info_ptr = info;
@@ -113,40 +120,68 @@
png_read_end(png, NULL);
// clean up
- png_destroy_read_struct(&png, &info);
+ png_destroy_read_struct(&png, &info, NULL);
return 0;
error:
// clean up
- png_destroy_read_struct(&png, &info);
+ png_destroy_read_struct(&png, &info, NULL);
return -1;
}
-int pt_image_open (struct pt_image **img_ptr, struct pt_ctx *ctx, const char *png_path, int cache_mode)
+/**
+ * Build a filesystem path representing the appropriate path for this image's cache entry, and store it in the given
+ * buffer.
+ */
+static int pt_image_cache_path (struct pt_image *image, char *buf, size_t len)
{
- struct pt_image *img;
+ // TODO: impl
+}
- // XXX: verify that the png_path exists and looks like a PNG file
+int pt_image_open (struct pt_image **image_ptr, struct pt_ctx *ctx, const char *path, int cache_mode)
+{
+ struct pt_image *image;
+ char cache_path[_POSIX_PATH_MAX];
+
+ // XXX: verify that the path exists and looks like a PNG file
// alloc
- if (pt_image_new(&img, ctx, png_path))
+ if (pt_image_new(&image, ctx, path))
return -1;
+
+ // compute cache file path
+ if (pt_image_cache_path(image, cache_path, sizeof(cache_path)))
+ goto error;
// open the cache object for this image
- if (pt_cache_open(&img->cache, img, mode))
+ if (pt_cache_open(&image->cache, cache_path, cache_mode))
goto error;
// update if not fresh
- if (!pt_cache_fresh(img->cache))
- pt_image_update_cache(img);
+ // XXX: check cache_mode
+ // XXX: error handling
+ if (pt_cache_stale(image->cache, image->path))
+ pt_image_update_cache(image);
// ok, ready for access
- *img_ptr = img;
+ *image_ptr = image;
return 0;
error:
- pt_image_destroy(img);
+ pt_image_destroy(image);
+
+ return -1;
}
+
+void pt_image_destroy (struct pt_image *image)
+{
+ free(image->path);
+
+ if (image->cache)
+ pt_cache_destroy(image->cache);
+
+ free(image);
+}
--- a/src/lib/image.h Sun Dec 27 22:01:17 2009 +0200
+++ b/src/lib/image.h Sun Dec 27 23:14:10 2009 +0200
@@ -13,12 +13,16 @@
struct pt_ctx *ctx;
/** Path to .png */
- char *png_path;
+ char *path;
/** Cache object */
struct pt_cache *cache;
};
+/**
+ * Release the given pt_image without any clean shutdown
+ */
+void pt_image_destroy (struct pt_image *image);
#endif