cog/Frameworks/vgmstream/vgmstream/src/util/reader.c

150 lines
4.2 KiB
C

#include "reader_put.h"
#include "reader_text.h"
#include "reader_sf.h"
#include "endianness.h"
void put_8bit(uint8_t* buf, int8_t i) {
buf[0] = i;
}
void put_16bitLE(uint8_t* buf, int16_t i) {
buf[0] = (i & 0xFF);
buf[1] = i >> 8;
}
void put_32bitLE(uint8_t* buf, int32_t i) {
buf[0] = (uint8_t)(i & 0xFF);
buf[1] = (uint8_t)((i >> 8) & 0xFF);
buf[2] = (uint8_t)((i >> 16) & 0xFF);
buf[3] = (uint8_t)((i >> 24) & 0xFF);
}
void put_16bitBE(uint8_t* buf, int16_t i) {
buf[0] = i >> 8;
buf[1] = (i & 0xFF);
}
void put_32bitBE(uint8_t* buf, int32_t i) {
buf[0] = (uint8_t)((i >> 24) & 0xFF);
buf[1] = (uint8_t)((i >> 16) & 0xFF);
buf[2] = (uint8_t)((i >> 8) & 0xFF);
buf[3] = (uint8_t)(i & 0xFF);
}
/* **************************************************** */
size_t read_line(char* buf, int buf_size, off_t offset, STREAMFILE* sf, int* p_line_ok) {
int i;
off_t file_size = get_streamfile_size(sf);
int extra_bytes = 0; /* how many bytes over those put in the buffer were read */
if (p_line_ok) *p_line_ok = 0;
for (i = 0; i < buf_size-1 && offset+i < file_size; i++) {
char in_char = read_8bit(offset+i, sf);
/* check for end of line */
if (in_char == 0x0d && read_8bit(offset+i+1, sf) == 0x0a) { /* CRLF */
extra_bytes = 2;
if (p_line_ok) *p_line_ok = 1;
break;
}
else if (in_char == 0x0d || in_char == 0x0a) { /* CR or LF */
extra_bytes = 1;
if (p_line_ok) *p_line_ok = 1;
break;
}
buf[i] = in_char;
}
buf[i] = '\0';
/* did we fill the buffer? */
if (i == buf_size) {
char in_char = read_8bit(offset+i, sf);
/* did the bytes we missed just happen to be the end of the line? */
if (in_char == 0x0d && read_8bit(offset+i+1, sf) == 0x0a) { /* CRLF */
extra_bytes = 2;
if (p_line_ok) *p_line_ok = 1;
}
else if (in_char == 0x0d || in_char == 0x0a) { /* CR or LF */
extra_bytes = 1;
if (p_line_ok) *p_line_ok = 1;
}
}
/* did we hit the file end? */
if (offset+i == file_size) {
/* then we did in fact finish reading the last line */
if (p_line_ok) *p_line_ok = 1;
}
return i + extra_bytes;
}
size_t read_bom(STREAMFILE* sf) {
if (read_u16le(0x00, sf) == 0xFFFE ||
read_u16le(0x00, sf) == 0xFEFF) {
return 0x02;
}
if ((read_u32be(0x00, sf) & 0xFFFFFF00) == 0xEFBBBF00) {
return 0x03;
}
return 0x00;
}
size_t read_string(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf) {
size_t pos;
for (pos = 0; pos < buf_size; pos++) {
uint8_t byte = read_u8(offset + pos, sf);
char c = (char)byte;
if (buf) buf[pos] = c;
if (c == '\0')
return pos;
if (pos+1 == buf_size) { /* null at maxsize and don't validate (expected to be garbage) */
if (buf) buf[pos] = '\0';
return buf_size;
}
/* UTF-8 only goes to 0x7F, but allow a bunch of Windows-1252 codes that some games use */
if (byte < 0x20 || byte > 0xF0)
goto fail;
}
fail:
if (buf) buf[0] = '\0';
return 0;
}
size_t read_string_utf16(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf, int big_endian) {
size_t pos, offpos;
read_u16_t read_u16 = big_endian ? read_u16be : read_u16le;
for (pos = 0, offpos = 0; pos < buf_size; pos++, offpos += 2) {
char c = read_u16(offset + offpos, sf) & 0xFF; /* lower byte for now */
if (buf) buf[pos] = c;
if (c == '\0')
return pos;
if (pos+1 == buf_size) { /* null at maxsize and don't validate (expected to be garbage) */
if (buf) buf[pos] = '\0';
return buf_size;
}
if (c < 0x20 || (uint8_t)c > 0xA5)
goto fail;
}
fail:
if (buf) buf[0] = '\0';
return 0;
}
size_t read_string_utf16le(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf) {
return read_string_utf16(buf, buf_size, offset, sf, 0);
}
size_t read_string_utf16be(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf) {
return read_string_utf16(buf, buf_size, offset, sf, 1);
}