ref: b190c3d473a96a48c27c01186b1740ecd6753b87
parent: 79f515914c96e04a3be3b20bbc5c71459e4b8915
author: Mans Rullgard <mans@mansr.com>
date: Sat Aug 8 07:19:39 EDT 2020
formats: add lsx_read_fields() function Add a function for reading multiple fields according to a spec string with size checking, aborting on read error. This simplifies error checking, which is sorely lacking, in format handlers.
--- a/src/formats_i.c
+++ b/src/formats_i.c
@@ -409,6 +409,66 @@
return SOX_EOF;
}
+int lsx_read_fields(sox_format_t *ft, uint32_t *len, const char *spec, ...)
+{
+ int err = SOX_SUCCESS;
+ va_list ap;
+
+#define do_read(type, f, n) do { \
+ size_t nr; \
+ if (*len < n * sizeof(type)) { \
+ err = SOX_EOF; \
+ goto end; \
+ } \
+ nr = lsx_read_##f##_buf(ft, va_arg(ap, type *), r); \
+ if (nr != n) \
+ err = SOX_EOF; \
+ *len -= nr * sizeof(type); \
+ } while (0)
+
+ va_start(ap, spec);
+
+ while (*spec) {
+ unsigned long r = 1;
+ char c = *spec;
+
+ if (c >= '0' && c <= '9') {
+ char *next;
+ r = strtoul(spec, &next, 10);
+ spec = next;
+ c = *spec;
+ } else if (c == '*') {
+ r = va_arg(ap, int);
+ c = *++spec;
+ }
+
+ switch (c) {
+ case 'b': do_read(uint8_t, b, r); break;
+ case 'h': do_read(uint16_t, w, r); break;
+ case 'i': do_read(uint32_t, dw, r); break;
+ case 'q': do_read(uint64_t, qw, r); break;
+ case 'x': err = lsx_skipbytes(ft, r); break;
+
+ default:
+ lsx_fail("lsx_read_fields: invalid format character '%c'", c);
+ err = SOX_EOF;
+ break;
+ }
+
+ if (err)
+ break;
+
+ spec++;
+ }
+
+end:
+ va_end(ap);
+
+#undef do_read
+
+ return err;
+}
+
/* N.B. This macro doesn't work for unaligned types (e.g. 3-byte
types). */
#define WRITE_FUNC(type, size, ctype, twiddle) \
--- a/src/sox_i.h
+++ b/src/sox_i.h
@@ -183,6 +183,8 @@
#define lsx_readsw(ft, sw) lsx_readb(ft, (uint16_t *)sw)
#endif
+int lsx_read_fields(sox_format_t *ft, uint32_t *len, const char *spec, ...);
+
int lsx_write3(sox_format_t * ft, unsigned u3);
int lsx_writeb(sox_format_t * ft, unsigned ub);
int lsx_writedf(sox_format_t * ft, double d);