150 lines
5.8 KiB
C
150 lines
5.8 KiB
C
#ifndef _READER_SF_H
|
|
#define _READER_SF_H
|
|
#include "../streamfile.h"
|
|
|
|
|
|
/* Sometimes you just need an int, and we're doing the buffering.
|
|
* Note, however, that if these fail to read they'll return -1,
|
|
* so that should not be a valid value or there should be some backup. */
|
|
static inline int16_t read_16bitLE(off_t offset, STREAMFILE* sf) {
|
|
uint8_t buf[2];
|
|
|
|
if (read_streamfile(buf,offset,2,sf)!=2) return -1;
|
|
return get_16bitLE(buf);
|
|
}
|
|
static inline int16_t read_16bitBE(off_t offset, STREAMFILE* sf) {
|
|
uint8_t buf[2];
|
|
|
|
if (read_streamfile(buf,offset,2,sf)!=2) return -1;
|
|
return get_16bitBE(buf);
|
|
}
|
|
static inline int32_t read_32bitLE(off_t offset, STREAMFILE* sf) {
|
|
uint8_t buf[4];
|
|
|
|
if (read_streamfile(buf,offset,4,sf)!=4) return -1;
|
|
return get_32bitLE(buf);
|
|
}
|
|
static inline int32_t read_32bitBE(off_t offset, STREAMFILE* sf) {
|
|
uint8_t buf[4];
|
|
|
|
if (read_streamfile(buf,offset,4,sf)!=4) return -1;
|
|
return get_32bitBE(buf);
|
|
}
|
|
static inline int64_t read_64bitLE(off_t offset, STREAMFILE* sf) {
|
|
uint8_t buf[8];
|
|
|
|
if (read_streamfile(buf,offset,8,sf)!=8) return -1;
|
|
return get_64bitLE(buf);
|
|
}
|
|
static inline int64_t read_64bitBE(off_t offset, STREAMFILE* sf) {
|
|
uint8_t buf[8];
|
|
|
|
if (read_streamfile(buf,offset,8,sf)!=8) return -1;
|
|
return get_64bitBE(buf);
|
|
}
|
|
static inline int8_t read_8bit(off_t offset, STREAMFILE* sf) {
|
|
uint8_t buf[1];
|
|
|
|
if (read_streamfile(buf,offset,1,sf)!=1) return -1;
|
|
return buf[0];
|
|
}
|
|
|
|
/* alias of the above */
|
|
static inline int8_t read_s8 (off_t offset, STREAMFILE* sf) { return read_8bit(offset, sf); }
|
|
static inline uint8_t read_u8 (off_t offset, STREAMFILE* sf) { return (uint8_t) read_8bit(offset, sf); }
|
|
static inline int16_t read_s16le(off_t offset, STREAMFILE* sf) { return read_16bitLE(offset, sf); }
|
|
static inline uint16_t read_u16le(off_t offset, STREAMFILE* sf) { return (uint16_t)read_16bitLE(offset, sf); }
|
|
static inline int16_t read_s16be(off_t offset, STREAMFILE* sf) { return read_16bitBE(offset, sf); }
|
|
static inline uint16_t read_u16be(off_t offset, STREAMFILE* sf) { return (uint16_t)read_16bitBE(offset, sf); }
|
|
static inline int32_t read_s32le(off_t offset, STREAMFILE* sf) { return read_32bitLE(offset, sf); }
|
|
static inline uint32_t read_u32le(off_t offset, STREAMFILE* sf) { return (uint32_t)read_32bitLE(offset, sf); }
|
|
static inline int32_t read_s32be(off_t offset, STREAMFILE* sf) { return read_32bitBE(offset, sf); }
|
|
static inline uint32_t read_u32be(off_t offset, STREAMFILE* sf) { return (uint32_t)read_32bitBE(offset, sf); }
|
|
static inline int64_t read_s64be(off_t offset, STREAMFILE* sf) { return read_64bitBE(offset, sf); }
|
|
static inline uint64_t read_u64be(off_t offset, STREAMFILE* sf) { return (uint64_t)read_64bitBE(offset, sf); }
|
|
static inline int64_t read_s64le(off_t offset, STREAMFILE* sf) { return read_64bitLE(offset, sf); }
|
|
static inline uint64_t read_u64le(off_t offset, STREAMFILE* sf) { return (uint64_t)read_64bitLE(offset, sf); }
|
|
|
|
static inline float read_f32be(off_t offset, STREAMFILE* sf) {
|
|
uint8_t buf[4];
|
|
|
|
if (read_streamfile(buf, offset, sizeof(buf), sf) != sizeof(buf))
|
|
return -1;
|
|
return get_f32be(buf);
|
|
}
|
|
static inline float read_f32le(off_t offset, STREAMFILE* sf) {
|
|
uint8_t buf[4];
|
|
|
|
if (read_streamfile(buf, offset, sizeof(buf), sf) != sizeof(buf))
|
|
return -1;
|
|
return get_f32le(buf);
|
|
}
|
|
|
|
#if 0
|
|
// on GCC, this reader will be correctly optimized out (as long as it's static/inline), would be same as declaring:
|
|
// uintXX_t (*read_uXX)(off_t,uint8_t*) = be ? get_uXXbe : get_uXXle;
|
|
// only for the functions actually used in code, and inlined if possible (like big_endian param being a constant).
|
|
// on MSVC seems all read_X in sf_reader are compiled and included in the translation unit, plus ignores constants
|
|
// so may result on bloatness?
|
|
// (from godbolt tests, test more real cases)
|
|
|
|
/* collection of callbacks for quick access */
|
|
typedef struct sf_reader {
|
|
int32_t (*read_s32)(off_t,STREAMFILE*); //maybe r.s32
|
|
float (*read_f32)(off_t,STREAMFILE*);
|
|
/* ... */
|
|
} sf_reader;
|
|
|
|
static inline void sf_reader_init(sf_reader* r, int big_endian) {
|
|
memset(r, 0, sizeof(sf_reader));
|
|
if (big_endian) {
|
|
r->read_s32 = read_s32be;
|
|
r->read_f32 = read_f32be;
|
|
}
|
|
else {
|
|
r->read_s32 = read_s32le;
|
|
r->read_f32 = read_f32le;
|
|
}
|
|
}
|
|
|
|
/* sf_reader r;
|
|
* ...
|
|
* sf_reader_init(&r, big_endian);
|
|
* val = r.read_s32; //maybe r.s32?
|
|
*/
|
|
#endif
|
|
#if 0 //todo improve + test + simplify code (maybe not inline?)
|
|
static inline int read_s4h(off_t offset, STREAMFILE* sf) {
|
|
uint8_t byte = read_u8(offset, streamfile);
|
|
return get_nibble_signed(byte, 1);
|
|
}
|
|
static inline int read_u4h(off_t offset, STREAMFILE* sf) {
|
|
uint8_t byte = read_u8(offset, streamfile);
|
|
return (byte >> 4) & 0x0f;
|
|
}
|
|
static inline int read_s4l(off_t offset, STREAMFILE* sf) {
|
|
...
|
|
}
|
|
static inline int read_u4l(off_t offset, STREAMFILE* sf) {
|
|
...
|
|
}
|
|
static inline int max_s32(int32_t a, int32_t b) { return a > b ? a : b; }
|
|
static inline int min_s32(int32_t a, int32_t b) { return a < b ? a : b; }
|
|
//align32, align16, clamp16, etc
|
|
#endif
|
|
|
|
/* fastest to compare would be read_u32x == (uint32), but should be pre-optimized (see get_id32x) */
|
|
static inline /*const*/ int is_id32be(off_t offset, STREAMFILE* sf, const char* s) {
|
|
return read_u32be(offset, sf) == get_id32be(s);
|
|
}
|
|
|
|
static inline /*const*/ int is_id32le(off_t offset, STREAMFILE* sf, const char* s) {
|
|
return read_u32le(offset, sf) == get_id32be(s);
|
|
}
|
|
|
|
static inline /*const*/ int is_id64be(off_t offset, STREAMFILE* sf, const char* s) {
|
|
return read_u64be(offset, sf) == get_id64be(s);
|
|
}
|
|
|
|
#endif
|