1 /* an mspack_system implementation which reads one or more files, and
2 * only writes to one file; the file is not actually written to, but
3 * an MD5 sum is computed and is available once the written-to file is
4 * closed. You can use anything for the written-to filename, NULL is
5 * probably the most obvious. The code is not multithreadable.
6 */
7
8 #include <md5.h>
9 #include <stdio.h>
10 #include <stdarg.h>
11
12 struct md5_ctx md5_context;
13 char md5_string[33];
14
15 struct mspack_file_p {
16 FILE *fh;
17 };
18
m_open(struct mspack_system * self,const char * filename,int mode)19 static struct mspack_file *m_open(struct mspack_system *self, const char *filename, int mode) {
20 struct mspack_file_p *fh;
21 if (mode != MSPACK_SYS_OPEN_WRITE &&
22 mode != MSPACK_SYS_OPEN_READ) return NULL;
23
24 if ((fh = (struct mspack_file_p *) malloc(sizeof(struct mspack_file_p)))) {
25 if (mode == MSPACK_SYS_OPEN_WRITE) {
26 fh->fh = NULL;
27 md5_init_ctx(&md5_context);
28 return (struct mspack_file *) fh;
29 }
30 else {
31 if ((fh->fh = fopen(filename, "rb")))
32 return (struct mspack_file *) fh;
33 }
34 /* error - free file handle and return NULL */
35 free(fh);
36 }
37 return NULL;
38 }
39
m_close(struct mspack_file * file)40 static void m_close(struct mspack_file *file) {
41 struct mspack_file_p *self = (struct mspack_file_p *) file;
42 if (self) {
43 if (self->fh) fclose(self->fh);
44 else {
45 unsigned char md5[16];
46 md5_finish_ctx(&md5_context, (void *) &md5);
47 snprintf(md5_string, sizeof(md5_string),
48 "%02x%02x%02x%02x%02x%02x%02x%02x"
49 "%02x%02x%02x%02x%02x%02x%02x%02x",
50 md5[0], md5[1], md5[2], md5[3],
51 md5[4], md5[5], md5[6], md5[7],
52 md5[8], md5[9], md5[10], md5[11],
53 md5[12], md5[13], md5[14], md5[15]);
54 }
55 free(self);
56 }
57 }
58
m_read(struct mspack_file * file,void * buffer,int bytes)59 static int m_read(struct mspack_file *file, void *buffer, int bytes) {
60 struct mspack_file_p *self = (struct mspack_file_p *) file;
61 if (self && self->fh && buffer && bytes >= 0) {
62 size_t count = fread(buffer, 1, bytes, self->fh);
63 if (!ferror(self->fh)) return (int) count;
64 }
65 return -1;
66 }
67
m_write(struct mspack_file * file,void * buffer,int bytes)68 static int m_write(struct mspack_file *file, void *buffer, int bytes) {
69 struct mspack_file_p *self = (struct mspack_file_p *) file;
70 if (!self || self->fh || !buffer || bytes < 0) return -1;
71 md5_process_bytes(buffer, bytes, &md5_context);
72 return bytes;
73 }
74
m_seek(struct mspack_file * file,off_t offset,int mode)75 static int m_seek(struct mspack_file *file, off_t offset, int mode) {
76 struct mspack_file_p *self = (struct mspack_file_p *) file;
77 if (self && self->fh) {
78 switch (mode) {
79 case MSPACK_SYS_SEEK_START: mode = SEEK_SET; break;
80 case MSPACK_SYS_SEEK_CUR: mode = SEEK_CUR; break;
81 case MSPACK_SYS_SEEK_END: mode = SEEK_END; break;
82 default: return -1;
83 }
84 #if HAVE_FSEEKO
85 return fseeko(self->fh, offset, mode);
86 #else
87 return fseek(self->fh, offset, mode);
88 #endif
89 }
90 return -1;
91 }
92
m_tell(struct mspack_file * file)93 static off_t m_tell(struct mspack_file *file) {
94 struct mspack_file_p *self = (struct mspack_file_p *) file;
95 #if HAVE_FSEEKO
96 return (self && self->fh) ? (off_t) ftello(self->fh) : 0;
97 #else
98 return (self && self->fh) ? (off_t) ftell(self->fh) : 0;
99 #endif
100 }
101
m_msg(struct mspack_file * file,const char * format,...)102 static void m_msg(struct mspack_file *file, const char *format, ...) {
103 va_list ap;
104 va_start(ap, format);
105 vfprintf(stderr, format, ap);
106 va_end(ap);
107 fputc((int) '\n', stderr);
108 fflush(stderr);
109 }
m_alloc(struct mspack_system * self,size_t bytes)110 static void *m_alloc(struct mspack_system *self, size_t bytes) {
111 return malloc(bytes);
112 }
m_free(void * buffer)113 static void m_free(void *buffer) {
114 free(buffer);
115 }
m_copy(void * src,void * dest,size_t bytes)116 static void m_copy(void *src, void *dest, size_t bytes) {
117 memcpy(dest, src, bytes);
118 }
119
120 static struct mspack_system read_files_write_md5 = {
121 &m_open, &m_close, &m_read, &m_write, &m_seek,
122 &m_tell, &m_msg, &m_alloc, &m_free, &m_copy, NULL
123 };
124