]> sigrok.org Git - libsigrok.git/blob - src/session_file.c
session-file: Remove old session save API
[libsigrok.git] / src / session_file.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <zip.h>
24 #include <errno.h>
25 #include <glib.h>
26 #include <glib/gstdio.h>
27 #include <libsigrok/libsigrok.h>
28 #include "libsigrok-internal.h"
29
30 /** @cond PRIVATE */
31 #define LOG_PREFIX "session-file"
32 /** @endcond */
33
34 /**
35  * @file
36  *
37  * Loading and saving libsigrok session files.
38  */
39
40 /**
41  * @addtogroup grp_session
42  *
43  * @{
44  */
45
46 extern SR_PRIV struct sr_dev_driver session_driver;
47 static int session_driver_initialized = 0;
48
49 /** Read metadata entries from a session archive.
50  * @param[in] archive An open ZIP archive.
51  * @param[in] entry Stat buffer filled in for the metadata archive member.
52  * @return A new key/value store containing the session metadata.
53  */
54 SR_PRIV GKeyFile *sr_sessionfile_read_metadata(struct zip *archive,
55                         const struct zip_stat *entry)
56 {
57         GKeyFile *keyfile;
58         GError *error;
59         struct zip_file *zf;
60         char *metabuf;
61         int metalen;
62
63         if (entry->size > G_MAXINT || !(metabuf = g_try_malloc(entry->size))) {
64                 sr_err("Metadata buffer allocation failed.");
65                 return NULL;
66         }
67         zf = zip_fopen_index(archive, entry->index, 0);
68         if (!zf) {
69                 sr_err("Failed to open metadata: %s", zip_strerror(archive));
70                 g_free(metabuf);
71                 return NULL;
72         }
73         metalen = zip_fread(zf, metabuf, entry->size);
74         if (metalen < 0) {
75                 sr_err("Failed to read metadata: %s", zip_file_strerror(zf));
76                 zip_fclose(zf);
77                 g_free(metabuf);
78                 return NULL;
79         }
80         zip_fclose(zf);
81
82         keyfile = g_key_file_new();
83         error = NULL;
84         g_key_file_load_from_data(keyfile, metabuf, metalen,
85                         G_KEY_FILE_NONE, &error);
86         g_free(metabuf);
87
88         if (error) {
89                 sr_err("Failed to parse metadata: %s", error->message);
90                 g_error_free(error);
91                 g_key_file_free(keyfile);
92                 return NULL;
93         }
94         return keyfile;
95 }
96
97 /** @private */
98 SR_PRIV int sr_sessionfile_check(const char *filename)
99 {
100         struct zip *archive;
101         struct zip_file *zf;
102         struct zip_stat zs;
103         uint64_t version;
104         int ret;
105         char s[11];
106
107         if (!filename)
108                 return SR_ERR_ARG;
109
110         if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) {
111                 sr_err("Not a regular file: %s.", filename);
112                 return SR_ERR;
113         }
114
115         if (!(archive = zip_open(filename, 0, NULL)))
116                 /* No logging: this can be used just to check if it's
117                  * a sigrok session file or not. */
118                 return SR_ERR;
119
120         /* check "version" */
121         if (!(zf = zip_fopen(archive, "version", 0))) {
122                 sr_dbg("Not a sigrok session file: no version found.");
123                 zip_discard(archive);
124                 return SR_ERR;
125         }
126         ret = zip_fread(zf, s, sizeof(s) - 1);
127         if (ret < 0) {
128                 sr_err("Failed to read version file: %s",
129                         zip_file_strerror(zf));
130                 zip_fclose(zf);
131                 zip_discard(archive);
132                 return SR_ERR;
133         }
134         zip_fclose(zf);
135         s[ret] = '\0';
136         version = g_ascii_strtoull(s, NULL, 10);
137         if (version == 0 || version > 2) {
138                 sr_dbg("Cannot handle sigrok session file version %" PRIu64 ".",
139                         version);
140                 zip_discard(archive);
141                 return SR_ERR;
142         }
143         sr_spew("Detected sigrok session file version %" PRIu64 ".", version);
144
145         /* read "metadata" */
146         if (zip_stat(archive, "metadata", 0, &zs) < 0) {
147                 sr_dbg("Not a valid sigrok session file.");
148                 zip_discard(archive);
149                 return SR_ERR;
150         }
151         zip_discard(archive);
152
153         return SR_OK;
154 }
155
156 /**
157  * Load the session from the specified filename.
158  *
159  * @param ctx The context in which to load the session.
160  * @param filename The name of the session file to load.
161  * @param session The session to load the file into.
162  *
163  * @retval SR_OK Success
164  * @retval SR_ERR_MALLOC Memory allocation error
165  * @retval SR_ERR_DATA Malformed session file
166  * @retval SR_ERR This is not a session file
167  */
168 SR_API int sr_session_load(struct sr_context *ctx, const char *filename,
169                 struct sr_session **session)
170 {
171         GKeyFile *kf;
172         GError *error;
173         struct zip *archive;
174         struct zip_stat zs;
175         struct sr_dev_inst *sdi;
176         struct sr_channel *ch;
177         int ret, i, j;
178         uint64_t tmp_u64;
179         int total_channels, k;
180         int unitsize;
181         char **sections, **keys, *val;
182         char channelname[SR_MAX_CHANNELNAME_LEN + 1];
183
184         if ((ret = sr_sessionfile_check(filename)) != SR_OK)
185                 return ret;
186
187         if (!(archive = zip_open(filename, 0, NULL)))
188                 return SR_ERR;
189
190         if (zip_stat(archive, "metadata", 0, &zs) < 0) {
191                 zip_discard(archive);
192                 return SR_ERR;
193         }
194         kf = sr_sessionfile_read_metadata(archive, &zs);
195         zip_discard(archive);
196         if (!kf)
197                 return SR_ERR_DATA;
198
199         if ((ret = sr_session_new(ctx, session)) != SR_OK) {
200                 g_key_file_free(kf);
201                 return ret;
202         }
203
204         error = NULL;
205         ret = SR_OK;
206         sections = g_key_file_get_groups(kf, NULL);
207         for (i = 0; sections[i] && ret == SR_OK; i++) {
208                 if (!strcmp(sections[i], "global"))
209                         /* nothing really interesting in here yet */
210                         continue;
211                 if (!strncmp(sections[i], "device ", 7)) {
212                         /* device section */
213                         sdi = NULL;
214                         keys = g_key_file_get_keys(kf, sections[i], NULL, NULL);
215                         for (j = 0; keys[j]; j++) {
216                                 if (!strcmp(keys[j], "capturefile")) {
217                                         val = g_key_file_get_string(kf, sections[i],
218                                                         keys[j], &error);
219                                         if (!val) {
220                                                 ret = SR_ERR_DATA;
221                                                 break;
222                                         }
223                                         sdi = g_malloc0(sizeof(struct sr_dev_inst));
224                                         sdi->driver = &session_driver;
225                                         sdi->status = SR_ST_ACTIVE;
226                                         if (!session_driver_initialized) {
227                                                 /* first device, init the driver */
228                                                 session_driver_initialized = 1;
229                                                 sdi->driver->init(sdi->driver, NULL);
230                                         }
231                                         sr_dev_open(sdi);
232                                         sr_session_dev_add(*session, sdi);
233                                         (*session)->owned_devs = g_slist_append(
234                                                         (*session)->owned_devs, sdi);
235                                         sr_config_set(sdi, NULL, SR_CONF_SESSIONFILE,
236                                                         g_variant_new_string(filename));
237                                         sr_config_set(sdi, NULL, SR_CONF_CAPTUREFILE,
238                                                         g_variant_new_string(val));
239                                         g_free(val);
240                                 } else if (!strcmp(keys[j], "samplerate")) {
241                                         val = g_key_file_get_string(kf, sections[i],
242                                                         keys[j], &error);
243                                         if (!sdi || !val || sr_parse_sizestring(val,
244                                                                 &tmp_u64) != SR_OK) {
245                                                 g_free(val);
246                                                 ret = SR_ERR_DATA;
247                                                 break;
248                                         }
249                                         g_free(val);
250                                         sr_config_set(sdi, NULL, SR_CONF_SAMPLERATE,
251                                                         g_variant_new_uint64(tmp_u64));
252                                 } else if (!strcmp(keys[j], "unitsize")) {
253                                         unitsize = g_key_file_get_integer(kf, sections[i],
254                                                         keys[j], &error);
255                                         if (!sdi || unitsize <= 0 || error) {
256                                                 ret = SR_ERR_DATA;
257                                                 break;
258                                         }
259                                         sr_config_set(sdi, NULL, SR_CONF_CAPTURE_UNITSIZE,
260                                                         g_variant_new_uint64(unitsize));
261                                 } else if (!strcmp(keys[j], "total probes")) {
262                                         total_channels = g_key_file_get_integer(kf,
263                                                         sections[i], keys[j], &error);
264                                         if (!sdi || total_channels < 0 || error) {
265                                                 ret = SR_ERR_DATA;
266                                                 break;
267                                         }
268                                         sr_config_set(sdi, NULL, SR_CONF_NUM_LOGIC_CHANNELS,
269                                                         g_variant_new_uint64(total_channels));
270                                         for (k = 0; k < total_channels; k++) {
271                                                 g_snprintf(channelname, sizeof channelname,
272                                                                 "%d", k);
273                                                 sr_channel_new(sdi, k, SR_CHANNEL_LOGIC,
274                                                                 FALSE, channelname);
275                                         }
276                                 } else if (!strncmp(keys[j], "probe", 5)) {
277                                         tmp_u64 = g_ascii_strtoull(keys[j]+5, NULL, 10);
278                                         if (!sdi || tmp_u64 == 0 || tmp_u64 > G_MAXINT) {
279                                                 ret = SR_ERR_DATA;
280                                                 break;
281                                         }
282                                         ch = g_slist_nth_data(sdi->channels, tmp_u64 - 1);
283                                         if (!ch) {
284                                                 ret = SR_ERR_DATA;
285                                                 break;
286                                         }
287                                         val = g_key_file_get_string(kf, sections[i],
288                                                         keys[j], &error);
289                                         if (!val) {
290                                                 ret = SR_ERR_DATA;
291                                                 break;
292                                         }
293                                         /* sr_session_save() */
294                                         sr_dev_channel_name_set(ch, val);
295                                         g_free(val);
296                                         sr_dev_channel_enable(ch, TRUE);
297                                 }
298                         }
299                         g_strfreev(keys);
300                 }
301         }
302         g_strfreev(sections);
303         g_key_file_free(kf);
304
305         if (error) {
306                 sr_err("Failed to parse metadata: %s", error->message);
307                 g_error_free(error);
308         }
309         return ret;
310 }
311
312 /** @} */