#include "pqp.h"
#include <stdlib.h>
#include <string.h>

typedef _layout pq_array {
	int32_t nonempty, nullable, ty, nelts, resv;
	char body [];
} pq_array;

typedef _layout pq_array_elt {
	uint32_t sz; /* -1 for null */
	char body [];
} pq_array_elt;

struct pqp_array*
pqp_array_read(const void* pqary) {
	const pq_array* pqa = pqary;
	pqp_array* r = calloc(1, sizeof(pqp_array)
		+ (sizeof(pqp_array_elt) * pqa -> nelts));
	*r = (pqp_array) {
		.ty       = ntohl(pqa -> ty),
		.nullable = ntohl(pqa -> nullable),
		.sz       = ntohl(pqa -> nelts),
	};
	const char* p = pqa -> body;
	for(size_t i = 0; i < r -> sz; ++ i) {
		const pq_array_elt* e = (void*)p;
		r -> elts[i] = (pqp_array_elt) {
			.sz = ntohl(e -> sz),
			.data = (e -> sz == pq_null ? null : e -> body),
		};
		if (e -> sz == pq_null) p += 4; /* null */
		                   else p += 4 + r->elts[i].sz;
	}
	return r;
}

bool pqp_inet_read(const void* pqinet, struct sockaddr* d) {
	if(memcmp(pqinet,"\x02\x20\x00\x04",4) == 0) {
		uint32_t ip = 0;
		for(uint8_t i = 0; i<4; ++i) {
			ip |= (uint32_t)(((uint8_t*)pqinet)[4 + i]) << 8*i;
		}
		struct sockaddr_in* dd = (void*)d;
		_zero(*dd);
		dd -> sin_family = AF_INET;
		dd -> sin_port = 0;
		dd -> sin_addr = (struct in_addr){ip};
	} else if(memcmp(pqinet,"\x03\x80\x00\x10",4) == 0) {
		struct sockaddr_in6* dd = (void*)d;
		_zero(*dd);
		dd -> sin6_family = AF_INET6;
		dd -> sin6_port = 0;
		memcpy(&(dd->sin6_addr), pqinet+4, 16);
	} else return false;
	return true;
}
