Files
psxrecomp/runtime/include/pst_wire.h
T
Alex Vanderveen fbad0be1b9 launcher performance, load state performance, game launch performance
it stops checking the entire PSX disc for full hash check every time the launcher runs, assuming the user's hash checked it when selecting the disc the first time and saving it to settings, so it just validates the file name and size instead, then it shares lifecycle with the launcher and the game to load the game faster, and several optimizations were made to loadstate paths which I think in the end relied on reanchoring host timings to the restored clock that came with the state
2026-07-27 11:03:10 -04:00

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 */