From 804a6d73a044e1b8c6d34055bd752108a8d3b791 Mon Sep 17 00:00:00 2001
From: Allanis <allanis@saracraft.net>
Date: Tue, 26 Feb 2013 16:24:29 +0000
Subject: [PATCH] [Add] seek/tell functions to packfile. Still using "streaming
 mode" though as it works better with vorbis.

---
 src/pack.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/pack.h |  2 ++
 2 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/src/pack.c b/src/pack.c
index 28f41ad..fd89d3c 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -11,7 +11,7 @@
 
 // == Store data in a funky format. =======================
 // Format:
-//  -- Index (in 512 byte chunks).
+//  -- Index.
 //    -- Magic number (16 bytes).
 //    -- Number of files (uint32_t).
 //    -- Files in format name/location.
@@ -307,7 +307,8 @@ int pack_open(Packfile* file, const char* packfile, const char* filename) {
 
 // Read count bytes from file and put them into buf.
 ssize_t pack_read(Packfile* file, void* buf, size_t count) {
-  if(file->pos + count > file->end) count = file->end - file->pos; // Can't go past the end!
+  if(file->pos + count > file->end)
+		count = file->end - file->pos; // Can't go past the end!
   if(count == 0) return 0;
 
   int bytes;
@@ -325,6 +326,56 @@ ssize_t pack_read(Packfile* file, void* buf, size_t count) {
   return bytes;
 }
 
+// Seek in the packfile.
+off_t pack_seek(Packfile* file, off_t offset, int whence) {
+	DEBUG("Attempting to seek offset: %d, whence: %d", offset, whence);
+	off_t ret;
+	switch(whence) {
+#ifdef _POSIX_SOURCE
+		case SEEK_SET:
+			if((file->start + offset) > file->end) return -1;
+			ret = lseek(file->fd, file->start + offset, SEEK_SET);
+			if(ret != (file->start + offset)) return -1;
+			break;
+		case SEEK_CUR:
+			if((file->start + offset) > file->end) return -1;
+			ret = lseek(file->fd, file->pos + offset, SEEK_SET);
+			if(ret != (file->pos + offset)) return -1;
+			break;
+		case SEEK_END:
+			if((file->end - offset) < file->start) return -1;
+			ret = lseek(file->fd, file->end - offset - 1, SEEK_SET);
+			if(ret != (file->end - offset)) return -1;
+			break;
+#else
+		case SEEK_SET:
+			if((file->start + offset) > file->end) return -1;
+			ret = fseek(file->fd, file->start + offset, SEEK_SET);
+			if(ret != (file->start + offset)) return -1;
+			break;
+		case SEEK_CUR:
+			if((file->start + offset) > file->end) return -1;
+			ret = flseek(file->fd, file->pos + offset, SEEK_SET);
+			if(ret != (file->pos + offset)) return -1;
+			break;
+		case SEEK_END:
+			if((file->end - offset) < file->start) return -1;
+			ret = flseek(file->fd, file->end - offset - 1, SEEK_SET);
+			if(ret != (file->end - offset)) return -1;
+			break;
+#endif
+		default:
+			ERR("Whence is not one of SEEK_SET, SEEK_CUR or SEEK_END");
+			return -1;
+	}
+	return ret - file->start;
+}
+
+// Return current pointer position.
+long pack_tell(Packfile* file) {
+	return file->pos - file->start;
+}
+
 // Loads an entire file into memory and returns a pointer to it.
 void* pack_readfile(const char* packfile, const char* filename, uint32_t* filesize) {
   Packfile* file = (Packfile*)malloc(sizeof(Packfile));
diff --git a/src/pack.h b/src/pack.h
index bdfd436..1070cab 100644
--- a/src/pack.h
+++ b/src/pack.h
@@ -22,6 +22,8 @@ int pack_check(const char* filename);
 int pack_files(const char* outfile, const char** infiles, const uint32_t nfiles);
 int pack_open(Packfile* file, const char* packfile, const char* filename);
 ssize_t pack_read(Packfile* file, void* buf, const size_t count);
+off_t pack_seek(Packfile* file, off_t offset, int whence);
+long pack_tell(Packfile* file);
 int pack_close(Packfile* file);
 
 // Fancy stuff.