From 96d77f7d518b30cbbcee93e28d1da188b26caa3f Mon Sep 17 00:00:00 2001
From: Sam Hocevar <sam@hocevar.net>
Date: Sun, 15 Jun 2008 13:50:02 +0000
Subject: [PATCH]   * Export cucul_file_t operations in the public header.   *
 Implement cucul_file_read() and cucul_file_write().

---
 cucul/cucul.h           |  13 ++++++
 cucul/cucul_internals.h |   6 ---
 cucul/figfont.c         |  24 +++++-----
 cucul/file.c            | 101 ++++++++++++++++++++++++++--------------
 4 files changed, 92 insertions(+), 52 deletions(-)

diff --git a/cucul/cucul.h b/cucul/cucul.h
index e8378b8..3e24c4b 100644
--- a/cucul/cucul.h
+++ b/cucul/cucul.h
@@ -278,6 +278,19 @@ __extern int cucul_canvas_set_figfont(cucul_canvas_t *, char const *);
 __extern int cucul_put_figchar(cucul_canvas_t *, uint32_t);
 /*  @} */
 
+/** \defgroup cucul_file libcucul file IO
+ *
+ *  These functions allow to read and write files in a platform-independent
+ *  way.
+ *  @{ */
+__extern cucul_file_t *cucul_file_open(char const *, const char *);
+__extern int cucul_file_close(cucul_file_t *);
+__extern size_t cucul_file_read(cucul_file_t *, void *, size_t);
+__extern size_t cucul_file_write(cucul_file_t *, const void *, size_t);
+__extern char * cucul_file_gets(cucul_file_t *, char *, int);
+__extern int cucul_file_eof(cucul_file_t *);
+/*  @} */
+
 /** \defgroup cucul_importexport libcucul importers/exporters from/to various
  *  formats
  *
diff --git a/cucul/cucul_internals.h b/cucul/cucul_internals.h
index cd34214..da7a0c2 100644
--- a/cucul/cucul_internals.h
+++ b/cucul/cucul_internals.h
@@ -77,10 +77,4 @@ extern uint32_t _cucul_attr_to_rgb24bg(uint32_t);
 extern void _cucul_save_frame_info(cucul_canvas_t *);
 extern void _cucul_load_frame_info(cucul_canvas_t *);
 
-/* File functions */
-extern cucul_file_t *_cucul_file_open(const char *, const char *);
-extern int _cucul_file_close(cucul_file_t *);
-extern int _cucul_file_eof(cucul_file_t *);
-extern char *_cucul_file_gets(char *, int, cucul_file_t *);
-
 #endif /* __CUCUL_INTERNALS_H__ */
diff --git a/cucul/figfont.c b/cucul/figfont.c
index 81873a7..64d216f 100644
--- a/cucul/figfont.c
+++ b/cucul/figfont.c
@@ -301,7 +301,7 @@ cucul_figfont_t * open_figfont(char const *path)
     }
 
     /* Open font: if not found, try .tlf, then .flf */
-    f = _cucul_file_open(path, "r");
+    f = cucul_file_open(path, "r");
 #if !defined __KERNEL__ && defined HAVE_SNPRINTF
 
 #if (! defined(snprintf)) && ( defined(_WIN32) || defined(WIN32) ) && (! defined(__CYGWIN__))
@@ -312,13 +312,13 @@ cucul_figfont_t * open_figfont(char const *path)
     {
         snprintf(altpath, 2047, "%s.tlf", path);
         altpath[2047] = '\0';
-        f = _cucul_file_open(altpath, "r");
+        f = cucul_file_open(altpath, "r");
     }
     if(!f)
     {
         snprintf(altpath, 2047, "%s.flf", path);
         altpath[2047] = '\0';
-        f = _cucul_file_open(altpath, "r");
+        f = cucul_file_open(altpath, "r");
     }
 #endif
     if(!f)
@@ -332,14 +332,14 @@ cucul_figfont_t * open_figfont(char const *path)
     ff->print_direction = 0;
     ff->full_layout = 0;
     ff->codetag_count = 0;
-    _cucul_file_gets(buf, 2048, f);
+    cucul_file_gets(f, buf, 2048);
     if(sscanf(buf, "%*[ft]lf2a%6s %u %u %u %i %u %u %u %u\n", hardblank,
               &ff->height, &ff->baseline, &ff->max_length,
               &ff->old_layout, &comment_lines, &ff->print_direction,
               &ff->full_layout, &ff->codetag_count) < 6)
     {
         debug("figfont error: `%s' has invalid header: %s", path, buf);
-        _cucul_file_close(f);
+        cucul_file_close(f);
         free(ff);
         seterrno(EINVAL);
         return NULL;
@@ -351,7 +351,7 @@ cucul_figfont_t * open_figfont(char const *path)
     {
         debug("figfont error: `%s' has invalid layout %i/%u",
                 path, ff->old_layout, ff->full_layout);
-        _cucul_file_close(f);
+        cucul_file_close(f);
         free(ff);
         seterrno(EINVAL);
         return NULL;
@@ -361,14 +361,14 @@ cucul_figfont_t * open_figfont(char const *path)
 
     /* Skip comment lines */
     for(i = 0; i < comment_lines; i++)
-        _cucul_file_gets(buf, 2048, f);
+        cucul_file_gets(f, buf, 2048);
 
     /* Read mandatory characters (32-127, 196, 214, 220, 228, 246, 252, 223)
      * then read additional characters. */
     ff->glyphs = 0;
     ff->lookup = NULL;
 
-    for(i = 0, size = 0; !_cucul_file_eof(f); ff->glyphs++)
+    for(i = 0, size = 0; !cucul_file_eof(f); ff->glyphs++)
     {
         if((ff->glyphs % 2048) == 0)
             ff->lookup = realloc(ff->lookup,
@@ -385,7 +385,7 @@ cucul_figfont_t * open_figfont(char const *path)
         }
         else
         {
-            if(_cucul_file_gets(buf, 2048, f) == NULL)
+            if(cucul_file_gets(f, buf, 2048) == NULL)
                 break;
 
             /* Ignore blank lines, as in jacky.flf */
@@ -396,7 +396,7 @@ cucul_figfont_t * open_figfont(char const *path)
             if(buf[0] == '-')
             {
                 for(j = 0; j < ff->height; j++)
-                    _cucul_file_gets(buf, 2048, f);
+                    cucul_file_gets(f, buf, 2048);
                 continue;
             }
 
@@ -423,12 +423,12 @@ cucul_figfont_t * open_figfont(char const *path)
             if(i + 2048 >= size)
                 data = realloc(data, size += 2048);
 
-            _cucul_file_gets(data + i, 2048, f);
+            cucul_file_gets(f, data + i, 2048);
             i = (uintptr_t)strchr(data + i, 0) - (uintptr_t)data;
         }
     }
 
-    _cucul_file_close(f);
+    cucul_file_close(f);
 
     if(ff->glyphs < EXT_GLYPHS)
     {
diff --git a/cucul/file.c b/cucul/file.c
index 8553e40..b6f1ab1 100644
--- a/cucul/file.c
+++ b/cucul/file.c
@@ -46,21 +46,24 @@ struct cucul_file
     int eof, zip;
 #   endif
     FILE *f;
+    int readonly;
 };
 #endif
 
-cucul_file_t *_cucul_file_open(char const *path, const char *mode)
+cucul_file_t *cucul_file_open(char const *path, const char *mode)
 {
 #if defined __KERNEL__
     return NULL;
 #else
     cucul_file_t *fp = malloc(sizeof(*fp));
 
+    fp->readonly = !strchr(mode, 'r');
+
 #   if defined HAVE_ZLIB_H
     uint8_t buf[4];
     unsigned int skip_size = 0;
 
-    fp->gz = gzopen(path, "rb");
+    fp->gz = gzopen(path, fp->readonly ? "rb" : "wb");
     if(!fp->gz)
     {
         free(fp);
@@ -70,41 +73,44 @@ cucul_file_t *_cucul_file_open(char const *path, const char *mode)
     fp->eof = 0;
     fp->zip = 0;
 
-    /* Parse ZIP file and go to start of first file */
-    gzread(fp->gz, buf, 4);
-    if(memcmp(buf, "PK\3\4", 4))
+    if(fp->readonly)
     {
-        gzseek(fp->gz, 0, SEEK_SET);
-        return fp;
-    }
+        /* Parse ZIP file and go to start of first file */
+        gzread(fp->gz, buf, 4);
+        if(memcmp(buf, "PK\3\4", 4))
+        {
+            gzseek(fp->gz, 0, SEEK_SET);
+            return fp;
+        }
 
-    fp->zip = 1;
+        fp->zip = 1;
 
-    gzseek(fp->gz, 22, SEEK_CUR);
+        gzseek(fp->gz, 22, SEEK_CUR);
 
-    gzread(fp->gz, buf, 2); /* Filename size */
-    skip_size += (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
-    gzread(fp->gz, buf, 2); /* Extra field size */
-    skip_size += (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
+        gzread(fp->gz, buf, 2); /* Filename size */
+        skip_size += (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
+        gzread(fp->gz, buf, 2); /* Extra field size */
+        skip_size += (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
 
-    gzseek(fp->gz, skip_size, SEEK_CUR);
+        gzseek(fp->gz, skip_size, SEEK_CUR);
 
-    /* Initialise inflate stream */
-    fp->stream.total_out = 0;
-    fp->stream.zalloc = NULL;
-    fp->stream.zfree = NULL;
-    fp->stream.opaque = NULL;
-    fp->stream.next_in = NULL;
-    fp->stream.avail_in = 0;
+        /* Initialise inflate stream */
+        fp->stream.total_out = 0;
+        fp->stream.zalloc = NULL;
+        fp->stream.zfree = NULL;
+        fp->stream.opaque = NULL;
+        fp->stream.next_in = NULL;
+        fp->stream.avail_in = 0;
 
-    if(inflateInit2(&fp->stream, -MAX_WBITS))
-    {
-        free(fp);
-        gzclose(fp->gz);
-        return NULL;
+        if(inflateInit2(&fp->stream, -MAX_WBITS))
+        {
+            free(fp);
+            gzclose(fp->gz);
+            return NULL;
+        }
     }
 #   else
-    fp->f = fopen(path, mode);
+    fp->f = fopen(path, fmode);
 
     if(!fp->f)
     {
@@ -117,7 +123,7 @@ cucul_file_t *_cucul_file_open(char const *path, const char *mode)
 #endif
 }
 
-int _cucul_file_close(cucul_file_t *fp)
+int cucul_file_close(cucul_file_t *fp)
 {
 #if defined __KERNEL__
     return 0;
@@ -134,18 +140,34 @@ int _cucul_file_close(cucul_file_t *fp)
 #endif
 }
 
-int _cucul_file_eof(cucul_file_t *fp)
+size_t cucul_file_read(cucul_file_t *fp, void *ptr, size_t size)
 {
 #if defined __KERNEL__
-    return 1;
+    return 0;
 #elif defined HAVE_ZLIB_H
-    return fp->zip ? fp->eof : gzeof(fp->gz);
+    if(fp->zip)
+        return zipread(fp, ptr, size);
+    return gzread(fp->gz, ptr, size);
 #else
-    return feof(fp->f);
+    return fread(ptr, 1, size, fp->f);
+#endif
+}
+
+size_t cucul_file_write(cucul_file_t *fp, const void *ptr, size_t size)
+{
+    if(fp->readonly)
+        return 0;
+
+#if defined __KERNEL__
+    return 0;
+#elif defined HAVE_ZLIB_H
+    return gzwrite(fp->gz, ptr, size);
+#else
+    return fwrite(ptr, 1, size, fp->f);
 #endif
 }
 
-char *_cucul_file_gets(char *s, int size, cucul_file_t *fp)
+char *cucul_file_gets(cucul_file_t *fp, char *s, int size)
 {
 #if defined __KERNEL__
     return NULL;
@@ -178,6 +200,17 @@ char *_cucul_file_gets(char *s, int size, cucul_file_t *fp)
 #endif
 }
 
+int cucul_file_eof(cucul_file_t *fp)
+{
+#if defined __KERNEL__
+    return 1;
+#elif defined HAVE_ZLIB_H
+    return fp->zip ? fp->eof : gzeof(fp->gz);
+#else
+    return feof(fp->f);
+#endif
+}
+
 #if !defined __KERNEL__ && defined HAVE_ZLIB_H
 static int zipread(cucul_file_t *fp, void *buf, unsigned int len)
 {