libsigrok  unreleased development snapshot
sigrok hardware access and backend library
session_file.c
Go to the documentation of this file.
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 /** @cond PRIVATE */
47 extern SR_PRIV struct sr_dev_driver session_driver;
48 /** @endcond */
49 static int session_driver_initialized = 0;
50 
51 #if !HAVE_ZIP_DISCARD
52 /* Replacement for zip_discard() if it isn't available. */
53 /** @private */
54 SR_PRIV void sr_zip_discard(struct zip *archive)
55 {
56  if (zip_unchange_all(archive) < 0 || zip_close(archive) < 0)
57  sr_err("Failed to discard ZIP archive: %s", zip_strerror(archive));
58 }
59 #endif
60 
61 /**
62  * Read metadata entries from a session archive.
63  *
64  * @param[in] archive An open ZIP archive.
65  * @param[in] entry Stat buffer filled in for the metadata archive member.
66  *
67  * @return A new key/value store containing the session metadata.
68  *
69  * @private
70  */
71 SR_PRIV GKeyFile *sr_sessionfile_read_metadata(struct zip *archive,
72  const struct zip_stat *entry)
73 {
74  GKeyFile *keyfile;
75  GError *error;
76  struct zip_file *zf;
77  char *metabuf;
78  int metalen;
79 
80  if (entry->size > G_MAXINT || !(metabuf = g_try_malloc(entry->size))) {
81  sr_err("Metadata buffer allocation failed.");
82  return NULL;
83  }
84  zf = zip_fopen_index(archive, entry->index, 0);
85  if (!zf) {
86  sr_err("Failed to open metadata: %s", zip_strerror(archive));
87  g_free(metabuf);
88  return NULL;
89  }
90  metalen = zip_fread(zf, metabuf, entry->size);
91  if (metalen < 0) {
92  sr_err("Failed to read metadata: %s", zip_file_strerror(zf));
93  zip_fclose(zf);
94  g_free(metabuf);
95  return NULL;
96  }
97  zip_fclose(zf);
98 
99  keyfile = g_key_file_new();
100  error = NULL;
101  g_key_file_load_from_data(keyfile, metabuf, metalen,
102  G_KEY_FILE_NONE, &error);
103  g_free(metabuf);
104 
105  if (error) {
106  sr_err("Failed to parse metadata: %s", error->message);
107  g_error_free(error);
108  g_key_file_free(keyfile);
109  return NULL;
110  }
111  return keyfile;
112 }
113 
114 /** @private */
115 SR_PRIV int sr_sessionfile_check(const char *filename)
116 {
117  struct zip *archive;
118  struct zip_file *zf;
119  struct zip_stat zs;
120  uint64_t version;
121  int ret;
122  char s[11];
123 
124  if (!filename)
125  return SR_ERR_ARG;
126 
127  if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) {
128  sr_err("Not a regular file: %s.", filename);
129  return SR_ERR;
130  }
131 
132  if (!(archive = zip_open(filename, 0, NULL)))
133  /* No logging: this can be used just to check if it's
134  * a sigrok session file or not. */
135  return SR_ERR;
136 
137  /* check "version" */
138  if (!(zf = zip_fopen(archive, "version", 0))) {
139  sr_dbg("Not a sigrok session file: no version found.");
140  zip_discard(archive);
141  return SR_ERR;
142  }
143  ret = zip_fread(zf, s, sizeof(s) - 1);
144  if (ret < 0) {
145  sr_err("Failed to read version file: %s",
146  zip_file_strerror(zf));
147  zip_fclose(zf);
148  zip_discard(archive);
149  return SR_ERR;
150  }
151  zip_fclose(zf);
152  s[ret] = '\0';
153  version = g_ascii_strtoull(s, NULL, 10);
154  if (version == 0 || version > 2) {
155  sr_dbg("Cannot handle sigrok session file version %" PRIu64 ".",
156  version);
157  zip_discard(archive);
158  return SR_ERR;
159  }
160  sr_spew("Detected sigrok session file version %" PRIu64 ".", version);
161 
162  /* read "metadata" */
163  if (zip_stat(archive, "metadata", 0, &zs) < 0) {
164  sr_dbg("Not a valid sigrok session file.");
165  zip_discard(archive);
166  return SR_ERR;
167  }
168  zip_discard(archive);
169 
170  return SR_OK;
171 }
172 
173 /** @private */
174 SR_PRIV struct sr_dev_inst *sr_session_prepare_sdi(const char *filename, struct sr_session **session)
175 {
176  struct sr_dev_inst *sdi = NULL;
177 
178  sdi = g_malloc0(sizeof(struct sr_dev_inst));
179  sdi->driver = &session_driver;
180  sdi->status = SR_ST_INACTIVE;
181  if (!session_driver_initialized) {
182  /* first device, init the driver */
183  session_driver_initialized = 1;
184  sdi->driver->init(sdi->driver, NULL);
185  }
186  sr_dev_open(sdi);
187  sr_session_dev_add(*session, sdi);
188  (*session)->owned_devs = g_slist_append((*session)->owned_devs, sdi);
190  g_variant_new_string(filename));
191 
192  return sdi;
193 }
194 
195 /**
196  * Load the session from the specified filename.
197  *
198  * @param ctx The context in which to load the session.
199  * @param filename The name of the session file to load.
200  * @param session The session to load the file into.
201  *
202  * @retval SR_OK Success
203  * @retval SR_ERR_MALLOC Memory allocation error
204  * @retval SR_ERR_DATA Malformed session file
205  * @retval SR_ERR This is not a session file
206  */
207 SR_API int sr_session_load(struct sr_context *ctx, const char *filename,
208  struct sr_session **session)
209 {
210  GKeyFile *kf;
211  GError *error;
212  struct zip *archive;
213  struct zip_stat zs;
214  struct sr_dev_inst *sdi;
215  struct sr_channel *ch;
216  int ret, i, j;
217  uint64_t tmp_u64;
218  int total_channels, total_analog, k;
219  GSList *l;
220  int unitsize;
221  char **sections, **keys, *val;
222  char channelname[SR_MAX_CHANNELNAME_LEN + 1];
223  gboolean file_has_logic;
224 
225  if ((ret = sr_sessionfile_check(filename)) != SR_OK)
226  return ret;
227 
228  if (!(archive = zip_open(filename, 0, NULL)))
229  return SR_ERR;
230 
231  if (zip_stat(archive, "metadata", 0, &zs) < 0) {
232  zip_discard(archive);
233  return SR_ERR;
234  }
235  kf = sr_sessionfile_read_metadata(archive, &zs);
236  zip_discard(archive);
237  if (!kf)
238  return SR_ERR_DATA;
239 
240  if ((ret = sr_session_new(ctx, session)) != SR_OK) {
241  g_key_file_free(kf);
242  return ret;
243  }
244 
245  total_channels = 0;
246 
247  error = NULL;
248  ret = SR_OK;
249  file_has_logic = FALSE;
250  sections = g_key_file_get_groups(kf, NULL);
251  for (i = 0; sections[i] && ret == SR_OK; i++) {
252  if (!strcmp(sections[i], "global"))
253  /* nothing really interesting in here yet */
254  continue;
255  if (!strncmp(sections[i], "device ", 7)) {
256  /* device section */
257  sdi = NULL;
258  keys = g_key_file_get_keys(kf, sections[i], NULL, NULL);
259 
260  /* File contains analog data if there are analog channels. */
261  total_analog = g_key_file_get_integer(kf, sections[i],
262  "total analog", &error);
263  if (total_analog > 0 && !error)
264  sdi = sr_session_prepare_sdi(filename, session);
265  g_clear_error(&error);
266 
267  /* File contains logic data if a capturefile is set. */
268  val = g_key_file_get_string(kf, sections[i],
269  "capturefile", &error);
270  if (val && !error) {
271  if (!sdi)
272  sdi = sr_session_prepare_sdi(filename, session);
274  g_variant_new_string(val));
275  g_free(val);
276  file_has_logic = TRUE;
277  }
278  g_clear_error(&error);
279 
280  for (j = 0; keys[j]; j++) {
281  if (!strcmp(keys[j], "samplerate")) {
282  val = g_key_file_get_string(kf, sections[i],
283  keys[j], &error);
284  if (!sdi || !val || sr_parse_sizestring(val,
285  &tmp_u64) != SR_OK) {
286  g_free(val);
287  ret = SR_ERR_DATA;
288  break;
289  }
290  g_free(val);
292  g_variant_new_uint64(tmp_u64));
293  } else if (!strcmp(keys[j], "unitsize") && file_has_logic) {
294  unitsize = g_key_file_get_integer(kf, sections[i],
295  keys[j], &error);
296  if (!sdi || unitsize <= 0 || error) {
297  ret = SR_ERR_DATA;
298  break;
299  }
301  g_variant_new_uint64(unitsize));
302  } else if (!strcmp(keys[j], "total probes")) {
303  total_channels = g_key_file_get_integer(kf,
304  sections[i], keys[j], &error);
305  if (!sdi || total_channels < 0 || error) {
306  ret = SR_ERR_DATA;
307  break;
308  }
310  g_variant_new_int32(total_channels));
311  for (k = 0; k < total_channels; k++) {
312  g_snprintf(channelname, sizeof(channelname),
313  "%d", k);
314  sr_channel_new(sdi, k, SR_CHANNEL_LOGIC,
315  FALSE, channelname);
316  }
317  } else if (!strcmp(keys[j], "total analog")) {
318  total_analog = g_key_file_get_integer(kf,
319  sections[i], keys[j], &error);
320  if (!sdi || total_analog < 0 || error) {
321  ret = SR_ERR_DATA;
322  break;
323  }
325  g_variant_new_int32(total_analog));
326  for (k = total_channels; k < (total_channels + total_analog); k++) {
327  g_snprintf(channelname, sizeof(channelname),
328  "%d", k);
329  sr_channel_new(sdi, k, SR_CHANNEL_ANALOG,
330  FALSE, channelname);
331  }
332  } else if (!strncmp(keys[j], "probe", 5)) {
333  tmp_u64 = g_ascii_strtoull(keys[j] + 5, NULL, 10);
334  if (!sdi || tmp_u64 == 0 || tmp_u64 > G_MAXINT) {
335  ret = SR_ERR_DATA;
336  break;
337  }
338  ch = g_slist_nth_data(sdi->channels, tmp_u64 - 1);
339  if (!ch) {
340  ret = SR_ERR_DATA;
341  break;
342  }
343  val = g_key_file_get_string(kf, sections[i],
344  keys[j], &error);
345  if (!val) {
346  ret = SR_ERR_DATA;
347  break;
348  }
349  /* sr_session_save() */
350  sr_dev_channel_name_set(ch, val);
351  g_free(val);
352  sr_dev_channel_enable(ch, TRUE);
353  } else if (!strncmp(keys[j], "analog", 6)) {
354  tmp_u64 = g_ascii_strtoull(keys[j]+6, NULL, 10);
355  if (!sdi || tmp_u64 == 0 || tmp_u64 > G_MAXINT) {
356  ret = SR_ERR_DATA;
357  break;
358  }
359  ch = NULL;
360  for (l = sdi->channels; l; l = l->next) {
361  ch = l->data;
362  if ((guint64)ch->index == tmp_u64 - 1)
363  break;
364  else
365  ch = NULL;
366  }
367  if (!ch) {
368  ret = SR_ERR_DATA;
369  break;
370  }
371  val = g_key_file_get_string(kf, sections[i],
372  keys[j], &error);
373  if (!val) {
374  ret = SR_ERR_DATA;
375  break;
376  }
377  /* sr_session_save() */
378  sr_dev_channel_name_set(ch, val);
379  g_free(val);
380  sr_dev_channel_enable(ch, TRUE);
381  }
382  }
383  g_strfreev(keys);
384  }
385  }
386  g_strfreev(sections);
387  g_key_file_free(kf);
388 
389  if (error) {
390  sr_err("Failed to parse metadata: %s", error->message);
391  g_error_free(error);
392  }
393  return ret;
394 }
395 
396 /** @} */
Data is invalid.
Definition: libsigrok.h:77
Information on single channel.
Definition: libsigrok.h:639
int sr_dev_open(struct sr_dev_inst *sdi)
Open the specified device instance.
Definition: device.c:726
No error.
Definition: libsigrok.h:67
#define SR_API
Definition: libsigrok.h:128
int sr_config_set(const struct sr_dev_inst *sdi, const struct sr_channel_group *cg, uint32_t key, GVariant *data)
Set value of a configuration key in a device instance.
Definition: hwdriver.c:859
Channel type is analog channel.
Definition: libsigrok.h:635
Session filename.
Definition: libsigrok.h:1145
int sr_dev_channel_enable(struct sr_channel *channel, gboolean state)
Enable or disable a channel.
Definition: device.c:144
#define SR_MAX_CHANNELNAME_LEN
Definition: libsigrok.h:90
The device supports specifying a capturefile to inject.
Definition: libsigrok.h:1148
The device instance is live, but not in use.
Definition: libsigrok.h:1246
int index
The index of this channel, starting at 0.
Definition: libsigrok.h:644
int sr_dev_channel_name_set(struct sr_channel *channel, const char *name)
Set the name of the specified channel.
Definition: device.c:118
Channel type is logic channel.
Definition: libsigrok.h:633
The device supports setting its samplerate, in Hz.
Definition: libsigrok.h:838
Generic/unspecified error.
Definition: libsigrok.h:68
The device supports setting the number of logic channels.
Definition: libsigrok.h:928
The device supports specifying the capturefile unit size.
Definition: libsigrok.h:1151
Opaque structure representing a libsigrok session.
Definition: libsigrok.h:474
Opaque structure representing a libsigrok context.
int sr_session_dev_add(struct sr_session *session, struct sr_dev_inst *sdi)
Add a device instance to a session.
Definition: session.c:318
int sr_session_new(struct sr_context *ctx, struct sr_session **new_session)
Create a new session.
Definition: session.c:215
Function argument error.
Definition: libsigrok.h:70
The public libsigrok header file to be used by frontends.
#define SR_PRIV
Definition: libsigrok.h:135
int sr_session_load(struct sr_context *ctx, const char *filename, struct sr_session **session)
Load the session from the specified filename.
Definition: session_file.c:207
The device supports setting the number of analog channels.
Definition: libsigrok.h:931
Device driver data.
Definition: libsigrok.h:1254
int sr_parse_sizestring(const char *sizestring, uint64_t *size)
Convert a "natural" string representation of a size value to uint64_t.
Definition: strutil.c:1146