libclammspack/test/md5_fh.h
d3699d57
 /* an mspack_system implementation which reads one or more files, and
  * only writes to one file; the file is not actually written to, but
  * an MD5 sum is computed and is available once the written-to file is
  * closed. You can use anything for the written-to filename, NULL is
  * probably the most obvious. The code is not multithreadable.
  */
 
 #include <md5.h>
 #include <stdio.h>
 #include <stdarg.h>
 
 struct md5_ctx md5_context;
 char md5_string[33];
 
 struct mspack_file_p {
     FILE *fh;
 };
 
 static struct mspack_file *m_open(struct mspack_system *self, const char *filename, int mode) {
     struct mspack_file_p *fh;
     if (mode != MSPACK_SYS_OPEN_WRITE &&
cafa0bf3
         mode != MSPACK_SYS_OPEN_READ) return NULL;
d3699d57
 
     if ((fh = (struct mspack_file_p *) malloc(sizeof(struct mspack_file_p)))) {
cafa0bf3
         if (mode == MSPACK_SYS_OPEN_WRITE) {
             fh->fh = NULL;
             md5_init_ctx(&md5_context);
             return (struct mspack_file *) fh;
         }
         else {
             if ((fh->fh = fopen(filename, "rb")))
                 return (struct mspack_file *) fh;
         }
         /* error - free file handle and return NULL */
         free(fh);
d3699d57
     }
     return NULL;
 }
 
 static void m_close(struct mspack_file *file) {
   struct mspack_file_p *self = (struct mspack_file_p *) file;
   if (self) {
       if (self->fh) fclose(self->fh);
       else {
cafa0bf3
           unsigned char md5[16];
           md5_finish_ctx(&md5_context, (void *) &md5);
           snprintf(md5_string, sizeof(md5_string),
                    "%02x%02x%02x%02x%02x%02x%02x%02x"
                    "%02x%02x%02x%02x%02x%02x%02x%02x",
                    md5[0],  md5[1],  md5[2],  md5[3],
                    md5[4],  md5[5],  md5[6],  md5[7],
                    md5[8],  md5[9],  md5[10], md5[11],
                    md5[12], md5[13], md5[14], md5[15]);
d3699d57
       }
       free(self);
   }
 }
 
 static int m_read(struct mspack_file *file, void *buffer, int bytes) {
   struct mspack_file_p *self = (struct mspack_file_p *) file;
   if (self && self->fh && buffer && bytes >= 0) {
       size_t count = fread(buffer, 1, bytes, self->fh);
       if (!ferror(self->fh)) return (int) count;
   }
   return -1;
 }
 
 static int m_write(struct mspack_file *file, void *buffer, int bytes) {
     struct mspack_file_p *self = (struct mspack_file_p *) file;
     if (!self || self->fh || !buffer || bytes < 0) return -1;
     md5_process_bytes(buffer, bytes, &md5_context);
     return bytes;
 }
 
 static int m_seek(struct mspack_file *file, off_t offset, int mode) {
     struct mspack_file_p *self = (struct mspack_file_p *) file;
     if (self && self->fh) {
cafa0bf3
         switch (mode) {
         case MSPACK_SYS_SEEK_START: mode = SEEK_SET; break;
         case MSPACK_SYS_SEEK_CUR:   mode = SEEK_CUR; break;
         case MSPACK_SYS_SEEK_END:   mode = SEEK_END; break;
         default: return -1;
         }
d3699d57
 #if HAVE_FSEEKO
cafa0bf3
         return fseeko(self->fh, offset, mode);
d3699d57
 #else
cafa0bf3
         return fseek(self->fh, offset, mode);
d3699d57
 #endif
     }
     return -1;
 }
 
 static off_t m_tell(struct mspack_file *file) {
     struct mspack_file_p *self = (struct mspack_file_p *) file;
 #if HAVE_FSEEKO
     return (self && self->fh) ? (off_t) ftello(self->fh) : 0;
 #else
     return (self && self->fh) ? (off_t) ftell(self->fh) : 0;
 #endif
 }
 
 static void m_msg(struct mspack_file *file, const char *format, ...) {
     va_list ap;
     va_start(ap, format);
     vfprintf(stderr, format, ap);
     va_end(ap);
     fputc((int) '\n', stderr);
     fflush(stderr);
 }
 static void *m_alloc(struct mspack_system *self, size_t bytes) {
     return malloc(bytes);
 }
 static void m_free(void *buffer) {
     free(buffer);
 }
 static void m_copy(void *src, void *dest, size_t bytes) {
     memcpy(dest, src, bytes);
 }
 
 static struct mspack_system read_files_write_md5 = {
     &m_open, &m_close, &m_read, &m_write, &m_seek,
     &m_tell, &m_msg, &m_alloc, &m_free, &m_copy, NULL
 };