mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-25 18:05:12 -04:00
192 lines
5.4 KiB
C
192 lines
5.4 KiB
C
/* pst_wire.h — little-endian field cursors for portable .pst / boot_state blobs.
|
|
*
|
|
* Never memcpy whole host structs that may contain padding. Emit fixed-width
|
|
* LE primitives so Win/Linux x86_64 and macOS ARM produce identical bytes.
|
|
*/
|
|
#ifndef PSX_PST_WIRE_H
|
|
#define PSX_PST_WIRE_H
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
typedef struct PstW {
|
|
uint8_t *p;
|
|
uint8_t *end;
|
|
size_t written; /* advances even when p==NULL (size probe) */
|
|
} PstW;
|
|
|
|
typedef struct PstR {
|
|
const uint8_t *p;
|
|
const uint8_t *end;
|
|
} PstR;
|
|
|
|
static inline void pst_w_init(PstW *w, uint8_t *buf, size_t cap) {
|
|
w->p = buf;
|
|
w->end = buf ? buf + cap : NULL;
|
|
w->written = 0;
|
|
}
|
|
|
|
static inline void pst_r_init(PstR *r, const uint8_t *buf, size_t len) {
|
|
r->p = buf;
|
|
r->end = buf + len;
|
|
}
|
|
|
|
static inline int pst_w_bytes(PstW *w, const void *src, size_t n) {
|
|
if (!w) return 0;
|
|
if (w->p) {
|
|
if (!w->end || (size_t)(w->end - w->p) < n) return 0;
|
|
if (n && src) memcpy(w->p, src, n);
|
|
w->p += n;
|
|
}
|
|
w->written += n;
|
|
return 1;
|
|
}
|
|
|
|
static inline int pst_r_bytes(PstR *r, void *dst, size_t n) {
|
|
if (!r || !r->p || (size_t)(r->end - r->p) < n) return 0;
|
|
if (n && dst) memcpy(dst, r->p, n);
|
|
r->p += n;
|
|
return 1;
|
|
}
|
|
|
|
static inline int pst_w_u8(PstW *w, uint8_t v) { return pst_w_bytes(w, &v, 1); }
|
|
static inline int pst_r_u8(PstR *r, uint8_t *v) { return pst_r_bytes(r, v, 1); }
|
|
|
|
static inline int pst_w_u16(PstW *w, uint16_t v) {
|
|
uint8_t b[2] = { (uint8_t)v, (uint8_t)(v >> 8) };
|
|
return pst_w_bytes(w, b, 2);
|
|
}
|
|
static inline int pst_r_u16(PstR *r, uint16_t *v) {
|
|
uint8_t b[2];
|
|
if (!pst_r_bytes(r, b, 2)) return 0;
|
|
if (v) *v = (uint16_t)b[0] | ((uint16_t)b[1] << 8);
|
|
return 1;
|
|
}
|
|
|
|
static inline int pst_w_u32(PstW *w, uint32_t v) {
|
|
uint8_t b[4] = {
|
|
(uint8_t)v, (uint8_t)(v >> 8), (uint8_t)(v >> 16), (uint8_t)(v >> 24)
|
|
};
|
|
return pst_w_bytes(w, b, 4);
|
|
}
|
|
static inline int pst_r_u32(PstR *r, uint32_t *v) {
|
|
uint8_t b[4];
|
|
if (!pst_r_bytes(r, b, 4)) return 0;
|
|
if (v)
|
|
*v = (uint32_t)b[0] | ((uint32_t)b[1] << 8) |
|
|
((uint32_t)b[2] << 16) | ((uint32_t)b[3] << 24);
|
|
return 1;
|
|
}
|
|
|
|
static inline int pst_w_u64(PstW *w, uint64_t v) {
|
|
uint8_t b[8];
|
|
for (int i = 0; i < 8; i++) b[i] = (uint8_t)(v >> (8 * i));
|
|
return pst_w_bytes(w, b, 8);
|
|
}
|
|
static inline int pst_r_u64(PstR *r, uint64_t *v) {
|
|
uint8_t b[8];
|
|
if (!pst_r_bytes(r, b, 8)) return 0;
|
|
if (v) {
|
|
uint64_t x = 0;
|
|
for (int i = 0; i < 8; i++) x |= (uint64_t)b[i] << (8 * i);
|
|
*v = x;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static inline int pst_w_i16(PstW *w, int16_t v) { return pst_w_u16(w, (uint16_t)v); }
|
|
static inline int pst_r_i16(PstR *r, int16_t *v) {
|
|
uint16_t u;
|
|
if (!pst_r_u16(r, &u)) return 0;
|
|
if (v) *v = (int16_t)u;
|
|
return 1;
|
|
}
|
|
|
|
static inline int pst_w_i32(PstW *w, int32_t v) { return pst_w_u32(w, (uint32_t)v); }
|
|
static inline int pst_r_i32(PstR *r, int32_t *v) {
|
|
uint32_t u;
|
|
if (!pst_r_u32(r, &u)) return 0;
|
|
if (v) *v = (int32_t)u;
|
|
return 1;
|
|
}
|
|
|
|
/* bool / flag → single byte 0/1 */
|
|
static inline int pst_w_bool(PstW *w, int v) {
|
|
return pst_w_u8(w, v ? 1u : 0u);
|
|
}
|
|
static inline int pst_r_bool(PstR *r, int *v) {
|
|
uint8_t b;
|
|
if (!pst_r_u8(r, &b)) return 0;
|
|
if (v) *v = b ? 1 : 0;
|
|
return 1;
|
|
}
|
|
|
|
/* LE-encode a host POD field: 1/2/4/8-byte scalar, or array of those units. */
|
|
static inline int pst_w_pod(PstW *w, const void *src, size_t nbytes, size_t elem) {
|
|
const uint8_t *s = (const uint8_t *)src;
|
|
if (!elem || (nbytes % elem) != 0) return 0;
|
|
if (elem == 1) return pst_w_bytes(w, src, nbytes);
|
|
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
|
/* Host LE: wire bytes match native POD layout — skip per-element swizzle. */
|
|
if (elem == 2 || elem == 4 || elem == 8)
|
|
return pst_w_bytes(w, src, nbytes);
|
|
#endif
|
|
for (size_t off = 0; off < nbytes; off += elem) {
|
|
if (elem == 2) {
|
|
uint16_t v;
|
|
memcpy(&v, s + off, 2);
|
|
if (!pst_w_u16(w, v)) return 0;
|
|
} else if (elem == 4) {
|
|
uint32_t v;
|
|
memcpy(&v, s + off, 4);
|
|
if (!pst_w_u32(w, v)) return 0;
|
|
} else if (elem == 8) {
|
|
uint64_t v;
|
|
memcpy(&v, s + off, 8);
|
|
if (!pst_w_u64(w, v)) return 0;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static inline int pst_r_pod(PstR *r, void *dst, size_t nbytes, size_t elem) {
|
|
uint8_t *d = (uint8_t *)dst;
|
|
if (!elem || (nbytes % elem) != 0) return 0;
|
|
if (elem == 1) return pst_r_bytes(r, dst, nbytes);
|
|
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
|
if (elem == 2 || elem == 4 || elem == 8)
|
|
return pst_r_bytes(r, dst, nbytes);
|
|
#endif
|
|
for (size_t off = 0; off < nbytes; off += elem) {
|
|
if (elem == 2) {
|
|
uint16_t v;
|
|
if (!pst_r_u16(r, &v)) return 0;
|
|
memcpy(d + off, &v, 2);
|
|
} else if (elem == 4) {
|
|
uint32_t v;
|
|
if (!pst_r_u32(r, &v)) return 0;
|
|
memcpy(d + off, &v, 4);
|
|
} else if (elem == 8) {
|
|
uint64_t v;
|
|
if (!pst_r_u64(r, &v)) return 0;
|
|
memcpy(d + off, &v, 8);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* PSX_PST_WIRE_H */
|