]> git.tdb.fi Git - ext/subsurface.git/blob - file.c
updated/corrected comment
[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 #include "file.h"
10
11 static int readfile(const char *filename, struct memblock *mem)
12 {
13         int ret, fd = open(filename, O_RDONLY);
14         struct stat st;
15         char *buf;
16
17         mem->buffer = NULL;
18         mem->size = 0;
19
20         fd = open(filename, O_RDONLY);
21         if (fd < 0)
22                 return fd;
23         ret = fstat(fd, &st);
24         if (ret < 0)
25                 goto out;
26         ret = -EINVAL;
27         if (!S_ISREG(st.st_mode))
28                 goto out;
29         ret = 0;
30         if (!st.st_size)
31                 goto out;
32         buf = malloc(st.st_size+1);
33         ret = -1;
34         errno = ENOMEM;
35         if (!buf)
36                 goto out;
37         mem->buffer = buf;
38         mem->size = st.st_size;
39         ret = read(fd, buf, mem->size);
40         if (ret < 0)
41                 goto free;
42         buf[ret] = 0;
43         if (ret == mem->size)
44                 goto out;
45         errno = EIO;
46         ret = -1;
47 free:
48         free(mem->buffer);
49         mem->buffer = NULL;
50         mem->size = 0;
51 out:
52         close(fd);
53         return ret;
54 }
55
56 #ifdef LIBZIP
57 #include <zip.h>
58
59 static void suunto_read(struct zip_file *file, GError **error)
60 {
61         int size = 1024, n, read = 0;
62         char *mem = malloc(size);
63
64         while ((n = zip_fread(file, mem+read, size-read)) > 0) {
65                 read += n;
66                 size = read * 3 / 2;
67                 mem = realloc(mem, size);
68         }
69         parse_xml_buffer("SDE file", mem, read, error);
70         free(mem);
71 }
72 #endif
73
74 static int try_to_open_suunto(const char *filename, struct memblock *mem, GError **error)
75 {
76         int success = 0;
77 #ifdef LIBZIP
78         /* Grr. libzip needs to re-open the file, it can't take a buffer */
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, struct memblock *mem, GError **error)
98 {
99         /* Suunto Dive Manager files: SDE */
100         if (!strcasecmp(fmt, "SDE"))
101                 return try_to_open_suunto(filename, mem, error);
102
103         /* Truly nasty intentionally obfuscated Cochran Anal software */
104         if (!strcasecmp(fmt, "CAN"))
105                 return try_to_open_cochran(filename, mem, error);
106
107         return 0;
108 }
109
110 static void parse_file_buffer(const char *filename, struct memblock *mem, GError **error)
111 {
112         char *fmt = strrchr(filename, '.');
113         if (fmt && open_by_filename(filename, fmt+1, mem, error))
114                 return;
115
116         parse_xml_buffer(filename, mem->buffer, mem->size, error);
117 }
118
119 void parse_file(const char *filename, GError **error)
120 {
121         struct memblock mem;
122
123         if (readfile(filename, &mem) < 0) {
124                 fprintf(stderr, "Failed to read '%s'.\n", filename);
125                 if (error) {
126                         *error = g_error_new(g_quark_from_string("subsurface"),
127                                              DIVE_ERROR_PARSE,
128                                              "Failed to read '%s'",
129                                              filename);
130                 }
131                 return;
132         }
133
134         parse_file_buffer(filename, &mem, error);
135         free(mem.buffer);
136 }