]> git.tdb.fi Git - ext/subsurface.git/blob - file.c
Add "native" Suunto SDE zip file reading
[ext/subsurface.git] / file.c
1 #include <unistd.h>
2 #include <fcntl.h>
3 #include <sys/stat.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <errno.h>
7
8 #include "dive.h"
9
10 struct memblock {
11         void *buffer;
12         size_t size;
13 };
14
15 static int readfile(const char *filename, struct memblock *mem)
16 {
17         int ret, fd = open(filename, O_RDONLY);
18         struct stat st;
19
20         mem->buffer = NULL;
21         mem->size = 0;
22
23         fd = open(filename, O_RDONLY);
24         if (fd < 0)
25                 return fd;
26         ret = fstat(fd, &st);
27         if (ret < 0)
28                 goto out;
29         ret = -EINVAL;
30         if (!S_ISREG(st.st_mode))
31                 goto out;
32         ret = 0;
33         if (!st.st_size)
34                 goto out;
35         mem->buffer = malloc(st.st_size);
36         ret = -1;
37         errno = ENOMEM;
38         if (!mem->buffer)
39                 goto out;
40         mem->size = st.st_size;
41         ret = read(fd, mem->buffer, mem->size);
42         if (ret < 0)
43                 goto free;
44         if (ret == mem->size)
45                 goto out;
46         errno = EIO;
47         ret = -1;
48 free:
49         free(mem->buffer);
50         mem->buffer = NULL;
51         mem->size = 0;
52 out:
53         close(fd);
54         return ret;
55 }
56
57 #ifdef LIBZIP
58 #include <zip.h>
59
60 static void suunto_read(struct zip_file *file, GError **error)
61 {
62         int size = 1024, n, read = 0;
63         char *mem = malloc(size);
64
65         while ((n = zip_fread(file, mem+read, size-read)) > 0) {
66                 read += n;
67                 size = read * 3 / 2;
68                 mem = realloc(mem, size);
69         }
70         parse_xml_buffer("SDE file", mem, read, error);
71         free(mem);
72 }
73 #endif
74
75 static int try_to_open_suundo(const char *filename, GError **error)
76 {
77         int success = 0;
78 #ifdef LIBZIP
79         struct zip *zip = zip_open(filename, ZIP_CHECKCONS, NULL);
80
81         if (zip) {
82                 int index;
83                 for (index = 0; ;index++) {
84                         struct zip_file *file = zip_fopen_index(zip, index, 0);
85                         if (!file)
86                                 break;
87                         suunto_read(file, error);
88                         zip_fclose(file);
89                         success++;
90                 }
91                 zip_close(zip);
92         }
93 #endif
94         return success;
95 }
96
97 static int open_by_filename(const char *filename, const char *fmt, GError **error)
98 {
99         /* Suunto Dive Manager files: SDE */
100         if (!strcasecmp(fmt, "SDE"))
101                 return try_to_open_suundo(filename, error);
102
103         return 0;
104 }
105
106 void parse_file(const char *filename, GError **error)
107 {
108         char *fmt;
109         struct memblock mem;
110
111         fmt = strrchr(filename, '.');
112         if (fmt && open_by_filename(filename, fmt+1, error))
113                 return;
114
115         if (readfile(filename, &mem) < 0) {
116                 fprintf(stderr, "Failed to read '%s'.\n", filename);
117                 if (error) {
118                         *error = g_error_new(g_quark_from_string("subsurface"),
119                                              DIVE_ERROR_PARSE,
120                                              "Failed to read '%s'",
121                                              filename);
122                 }
123                 return;
124         }
125
126         parse_xml_buffer(filename, mem.buffer, mem.size, error);
127         free(mem.buffer);
128 }