diff options
| author | Tomasz Kramkowski <tk@the-tk.com> | 2021-08-06 22:08:38 +0100 | 
|---|---|---|
| committer | Tomasz Kramkowski <tk@the-tk.com> | 2021-08-07 15:21:41 +0100 | 
| commit | 4a0fa28d61dc097b962fd96e5eded47385663716 (patch) | |
| tree | e5e3e413213ef8b3d05c3970405a799a207f8f4c /unpack.c | |
| parent | 98ef6a8510d555148528e4fffb6cfa587dbd4c46 (diff) | |
| download | pack-4a0fa28d61dc097b962fd96e5eded47385663716.tar.gz pack-4a0fa28d61dc097b962fd96e5eded47385663716.tar.xz pack-4a0fa28d61dc097b962fd96e5eded47385663716.zip | |
factor unpack core into read_fields
Diffstat (limited to 'unpack.c')
| -rw-r--r-- | unpack.c | 146 | 
1 files changed, 77 insertions, 69 deletions
| @@ -15,6 +15,18 @@  #include "pack.h"  #include "trace.h" +struct dest { +	enum pack_type type; +	union ptr { +		#define T(type, sign, c_type, va_type) sign c_type *type; +		ITYPE_MACROS +		#undef T +		float *f; +		double *d; +	} ptr; +	size_t count; +}; +  static uintmax_t read_val(const unsigned char *buf, size_t size, enum pack_endian e)  {  	uintmax_t val = 0; @@ -36,6 +48,57 @@ static intmax_t minval(size_t s)  	}  } +static void read_fields(struct dest dest, const void *src_, enum pack_endian endianness) +{ +	union { +		uintmax_t unsigned_; +		intmax_t signed_; +		float f; +		double d; +	} val; +	const unsigned char *src = src_; +	size_t s = getsize(dest.type); + +	for (size_t i = 0; i < dest.count; i++) { +		val.unsigned_ = +			read_val(&src[s * i], s, endianness); +		tr_debug("val.u: %" PRIuMAX ", at: %" PRIuSIZE, +			 val.unsigned_, s * i); + +		if (dest.type == PACK_TYPE_FLOAT) { +			float f = ieee754b32_deserialise(val.unsigned_); +			val.f = f; +			tr_debug("val.f: %f", val.f); +		} else if (dest.type == PACK_TYPE_DOUBLE) { +			double d = ieee754b64_deserialise(val.unsigned_); +			val.d = d; +			tr_debug("val.d: %f", val.d); +		} else if (islower((char)dest.type)) { +			intmax_t vals; +			if (!(val.unsigned_ & (UINTMAX_C(1) << (s * 8 - 1)))) { +				vals = val.unsigned_; +			} else { +				vals = minval(s); +				vals += val.unsigned_ ^ (UINTMAX_C(1) << (s * 8 - 1)); +			} +			val.signed_ = vals; +			tr_debug("val.s: %" PRIdMAX, val.signed_); +		} + +		switch (dest.type) { +		#define T(type, sign, c_type, va_type) \ +			case (char)PACK_TYPE_##type: \ +				dest.ptr.type[i] = val.sign##_; \ +				break; +		ITYPE_MACROS +		#undef T +		case PACK_TYPE_FLOAT: dest.ptr.f[i] = val.f; break; +		case PACK_TYPE_DOUBLE: dest.ptr.d[i] = val.d; break; +		case PACK_TYPE_PADDING: break; +		} +	} +} +  enum pack_status unpack(const void *buf_, size_t size, const char *fmt, ...)  {  	enum pack_endian endianness = PACK_ENDIAN_BIG; @@ -49,23 +112,8 @@ enum pack_status unpack(const void *buf_, size_t size, const char *fmt, ...)  	va_start(ap, fmt);  	for (int i = 0; fmt[i] != '\0'; i++) { -		bool sign; -		size_t count = 1, s; -		enum pack_type t; -		union { -			#define T(type, sign, c_type, va_type) \ -				sign c_type *type; -			ITYPE_MACROS -			#undef T -			float     *f; -			double    *d; -		} arg; -		union { -			uintmax_t unsigned_; -			intmax_t signed_; -			float f; -			double d; -		} val; +		size_t s; +		struct dest dest = { .count = 1 };  		tr_debug("i: %d, fmt[i]: %c", i, fmt[i]);  		if (isdigit(fmt[i])) {  			unsigned long long c; @@ -75,80 +123,40 @@ enum pack_status unpack(const void *buf_, size_t size, const char *fmt, ...)  			c = strtoull(&fmt[i], &end, 10);  			if ((c == ULLONG_MAX && errno == ERANGE) || c > SIZE_MAX)  				SET_AND_GOTO(ret, PACK_FMTINVAL, stop); -			count = c; +			dest.count = c;  			i += end - &fmt[i];  		} else if (fmt[i] == '*') { -			count = va_arg(ap, size_t); +			dest.count = va_arg(ap, size_t);  			i++;  		} -		sign = islower(fmt[i]); -		tr_debug("count: %" PRIuSIZE ", i: %d, fmt[i]: %c, sign: %ssigned", -			 count, i, fmt[i], sign ? "" : "un"); +		tr_debug("dest.count: %" PRIuSIZE ", i: %d, fmt[i]: %c", dest.count, i, fmt[i]);  		switch (fmt[i]) {  		case '>': endianness = PACK_ENDIAN_BIG; continue;  		case '<': endianness = PACK_ENDIAN_LITTLE; continue;  		#define T(type, sign, c_type, va_type) \  			case (char)PACK_TYPE_##type: \ -				arg.type = va_arg(ap, sign c_type *); \ +				dest.ptr.type = va_arg(ap, sign c_type *); \  				break;  		ITYPE_MACROS  		#undef T -		case PACK_TYPE_FLOAT: arg.f = va_arg(ap, float *); break; -		case PACK_TYPE_DOUBLE: arg.d = va_arg(ap, double *); break; +		case PACK_TYPE_FLOAT: dest.ptr.f = va_arg(ap, float *); break; +		case PACK_TYPE_DOUBLE: dest.ptr.d = va_arg(ap, double *); break;  		case PACK_TYPE_PADDING: break;  		default: SET_AND_GOTO(ret, PACK_FMTINVAL, stop);  		} -		t = fmt[i]; +		dest.type = fmt[i]; -		s = getsize(t); +		s = getsize(dest.type);  		tr_debug("s: %" PRIuSIZE, s);  		if (s == (size_t)-1) SET_AND_GOTO(ret, PACK_FMTINVAL, stop); -		if (size - offset < s * count) +		if (size - offset < s * dest.count)  			SET_AND_GOTO(ret, PACK_TOOSMALL, stop); -		if (t == PACK_TYPE_PADDING) goto skip; - -		for (size_t j = 0; j < count; j++) { -			val.unsigned_ = -				read_val(buf + offset + s * j, s, endianness); -			tr_debug("val.u: %" PRIuMAX ", at: %" PRIuSIZE, -			         val.unsigned_, offset + s * j); - -			if (t == PACK_TYPE_FLOAT) { -				float f = ieee754b32_deserialise(val.unsigned_); -				val.f = f; -				tr_debug("val.f: %f", val.f); -			} else if (t == PACK_TYPE_DOUBLE) { -				double d = ieee754b64_deserialise(val.unsigned_); -				val.d = d; -				tr_debug("val.d: %f", val.d); -			} else if (sign) { -				intmax_t vals; -				if (!(val.unsigned_ & (UINTMAX_C(1) << (s * 8 - 1)))) { -					vals = val.unsigned_; -				} else { -					vals = minval(s); -					vals += val.unsigned_ ^ (UINTMAX_C(1) << (s * 8 - 1)); -				} -				val.signed_ = vals; -				tr_debug("val.s: %" PRIdMAX, val.signed_); -			} +		if (dest.type != PACK_TYPE_PADDING) +			read_fields(dest, &buf[offset], endianness); -			switch (t) { -			#define T(type, sign, c_type, va_type) \ -				case (char)PACK_TYPE_##type: \ -					arg.type[j] = val.sign##_; \ -					break; -			ITYPE_MACROS -			#undef T -			case PACK_TYPE_FLOAT: arg.f[j] = val.f; break; -			case PACK_TYPE_DOUBLE: arg.d[j] = val.d; break; -			case PACK_TYPE_PADDING: break; -			} -		} -skip: -		offset += s * count; +		offset += s * dest.count;  	}  stop: | 
