При попытке считать число в Big Endian считывается мусор
В общем, мне необходимо считать данные из бинарного файла. Насколько я знаю, данные в нем хранятся с порядком байт BE.
Проблема была обнаружена при отладке написанного мною интерфейса над файлом, для чтения данных из файла с указанным порядком байт. Для перестановки байт, я использую заголовочный файл byteswap.h из библиотеки libc. Я вот все думаю, а не проблема ли в том как я читаю эти данные, или проблема в другом?
struct vaio_stream {
FILE *file;
char *file_path;
bool is_be;
};
int64_t
vaio_stream_read(struct vaio_stream *stream,
void *buffer,
int64_t i_offset,
size_t i_count) {
if (i_offset) {
vaio_stream_seek(stream, i_offset, vaio_stream_seek_current);
}
return fread(buffer, 1, i_count, stream->file);
}
int32_t
vaio_stream_read_uint32(struct vaio_stream *stream, uint32_t *c) {
int32_t res = vaio_stream_read(stream, c, 1, sizeof(uint32_t));
if (stream->is_be) {
(*c) = bswap_32(*c);
};
return res;
}
int32_t
vaio_stream_read_int32(struct vaio_stream *stream, int32_t *c) {
int32_t res = vaio_stream_read(stream, c, 1, sizeof(int32_t));
if (stream->is_be) {
(*c) = bswap_32(*c);
};
return res;
}
Минимальный код для воспроизведения:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <byteswap.h>
enum vaio_stream_endian_e {
vaio_stream_endian_big,
vaio_stream_endian_little
};
enum vaio_stream_seek_e {
vaio_stream_seek_begin,
vaio_stream_seek_current,
vaio_stream_seek_end
};
struct vaio_stream {
FILE *file;
char *file_path;
bool is_be;
};
struct vaio_stream *
vaio_stream_alloc(char const *psz_path) {
struct vaio_stream *stream;
char *psz_path_copy;
size_t i_str_size;
i_str_size = strlen(psz_path);
stream = calloc(1, sizeof(struct vaio_stream));
psz_path_copy = malloc(i_str_size + 1);
stream->file_path = strncpy(psz_path_copy, psz_path, i_str_size);
/* ensure null terminator at the end */
psz_path_copy[i_str_size] = '\0';
return stream;
};
void
vaio_stream_free(struct vaio_stream* stream) {
free(stream->file_path);
free(stream);
};
/* open, close, flush */
struct vaio_stream *
vaio_stream_new(char const *psz_path);
struct vaio_stream *
vaio_stream_new_endian(char const *psz_path,
enum vaio_stream_endian_e e_endian) {
struct vaio_stream *stream;
stream = vaio_stream_alloc(psz_path);
stream->is_be = e_endian == vaio_stream_endian_big;
stream->file = fopen(stream->file_path, "rb");
return stream;
}
int32_t
vaio_stream_flush(struct vaio_stream *stream) {
fflush(stream->file);
}
void
vaio_stream_close(struct vaio_stream *stream) {
fclose(stream->file);
vaio_stream_free(stream);
}
char const *
vaio_stream_file_path(struct vaio_stream const *stream) {
return stream->file_path;
}
int64_t
vaio_stream_position(struct vaio_stream *stream) {
return ftell(stream->file);
};
int64_t
vaio_stream_length(struct vaio_stream *stream) {
int64_t old_pos, size;
old_pos = vaio_stream_position(stream);
vaio_stream_seek(stream, 0, vaio_stream_seek_end);
size = vaio_stream_position(stream);
vaio_stream_seek(stream, old_pos, vaio_stream_seek_begin);
return size;
}
int64_t
vaio_stream_read(struct vaio_stream *stream,
void *buffer,
int64_t i_offset,
size_t i_count) {
if (i_offset) {
vaio_stream_seek(stream, i_offset, vaio_stream_seek_current);
}
return fread(buffer, 1, i_count, stream->file);
}
int64_t
vaio_stream_write(struct vaio_stream *stream,
void *buffer,
int64_t i_offset,
size_t i_count) {
if (i_offset) {
vaio_stream_seek(stream, i_offset, vaio_stream_seek_current);
}
return fwrite(buffer, 1, i_count, stream->file);
}
int64_t
vaio_stream_seek(struct vaio_stream *stream,
int64_t i_position,
enum vaio_stream_seek_e e_seek) {
switch (e_seek)
{
case vaio_stream_seek_begin:
return fseek(stream->file, i_position, SEEK_SET);
case vaio_stream_seek_current:
return fseek(stream->file, i_position, SEEK_CUR);
case vaio_stream_seek_end:
return fseek(stream->file, i_position, SEEK_END);
default:
return INT64_MIN;
}
}
int32_t
vaio_stream_read_string(struct vaio_stream *stream, char **pp_string) {
int64_t i_pos, length;
int8_t c;
length = 0;
i_pos = vaio_stream_position(stream);
do {
if (!vaio_stream_read_int8(stream, &c)) {
break;
}
length++;
} while (c);
vaio_stream_seek(stream, i_pos, vaio_stream_seek_begin);
*pp_string = malloc(length + 1);
return vaio_stream_read(stream, *pp_string, 0, length);
}
int32_t
vaio_stream_read_uint8(struct vaio_stream *stream, uint8_t *c) {
return vaio_stream_read(stream, c, 0, sizeof(uint8_t));
};
int32_t
vaio_stream_read_int8(struct vaio_stream *stream, int8_t *c) {
return vaio_stream_read(stream, c, 0, sizeof(int8_t));
}
int32_t
vaio_stream_read_uint16(struct vaio_stream *stream, uint16_t *c) {
int32_t res = vaio_stream_read(stream, c, 0, sizeof(uint16_t));
if (stream->is_be) {
(*c) = bswap_16(*c);
};
return res;
}
int32_t
vaio_stream_read_int16(struct vaio_stream *stream, int16_t *c) {
int32_t res = vaio_stream_read(stream, c, 0, sizeof(int16_t));
if (stream->is_be) {
(*c) = bswap_16(*c);
};
return res;
}
int32_t
vaio_stream_read_uint32(struct vaio_stream *stream, uint32_t *c) {
int32_t res = vaio_stream_read(stream, c, 1, sizeof(uint32_t));
if (stream->is_be) {
(*c) = bswap_32(*c);
};
return res;
}
int32_t
vaio_stream_read_int32(struct vaio_stream *stream, int32_t *c) {
int32_t res = vaio_stream_read(stream, c, 1, sizeof(int32_t));
if (stream->is_be) {
(*c) = bswap_32(*c);
};
return res;
}
int32_t
vaio_stream_read_uint64(struct vaio_stream *stream, uint64_t *c) {
int32_t res = vaio_stream_read(stream, c, 1, sizeof(uint64_t));
if (stream->is_be) {
(*c) = bswap_64(*c);
};
return res;
}
int32_t
vaio_stream_read_int64(struct vaio_stream *stream, int64_t *c) {
int32_t res = vaio_stream_read(stream, c, 1, sizeof(uint64_t));
if (stream->is_be) {
(*c) = bswap_64(*c);
};
return res;
}
#define UNITY_RAW "UnityRaw"
#define UNITY_WEB "UnityWeb"
#define UNITY_FS "UnityFS"
char const * const
valid_signatures[] = {
UNITY_RAW,
UNITY_WEB,
UNITY_FS
};
int
is_valid_signature(char const *format) {
int res = 0;
int i;
for(i = 0; i < sizeof(valid_signatures) / sizeof(valid_signatures[0]); i++) {
if (0 != strcmp(format, valid_signatures[i])) {
continue;
}
res = 1;
break;
}
return res;
}
struct header {
char *signature;
uint32_t file_version;
char *webVersion;
char *minimumVersion;
};
void
fread_header(struct vaio_stream *stream, struct header *header) {
vaio_stream_read_string(stream, &header->signature);
if (!is_valid_signature(header->signature)) {
return;
}
vaio_stream_read_uint32(stream, &header->file_version);
vaio_stream_read_string(stream, &header->webVersion);
vaio_stream_read_string(stream, &header->minimumVersion);
};
int main(int argc, char const *argv[]) {
struct vaio_stream *stream = NULL;
struct header h = { 0 };
stream = vaio_stream_new_endian("/home/kotomi/Avatar-Sho-Za-HuNya.vrca", vaio_stream_endian_big);
fread_header(stream, &h);
vaio_stream_close(stream);
return 0;
}
Данные для чтения: https://is.gd/MQyEpo
P.S. Данные которые получаются в 010 Editor:
Данные которые получаются у меня:
Hexdump:
0000000 6e55 7469 4679 0053 0000 0700 2e35 2e78
0000010 0078 3032 3931 342e 332e 6631 0031 0000
0000020 0000 2402 af28 0000 5900 0000 9900 0000
0000030 4300 0000 0000 0000 0000 0000 0000 0000
0000040 001e 0001 00f9 1001 bf26 0248 2824 0024
0000050 0041 0000 1b02 f800 bd1c ccda 0000 0400
0000060 4143 2d42 3962 3431 3236 3661 3761 3665
0000070 6664 3835 3933 3961 3762 3531 3065 3464
0000080 3765 6430 0031 0050 680e 7ce4 0008 390f
0000090 1100 2e60 6572 5373 5d00 0000 0020 0000
00000a0 5501 78ef 9546 7cb0 5a50 9950 2d4f 3dfa
00000b0 4244 11c7 15b1 10b6 eb9f f49d 7b08 f9af
00000c0 d330 f884 6ab3 2364 1326 8326 858e d03f
00000d0
Массив байт для теста:
unsigned char ucDataBlock[208] = {
// Offset 0x00000000 to 0x00000207
0x55, 0x6E, 0x69, 0x74, 0x79, 0x46, 0x53, 0x00, 0x00, 0x00, 0x00, 0x07,
0x35, 0x2E, 0x78, 0x2E, 0x78, 0x00, 0x32, 0x30, 0x31, 0x39, 0x2E, 0x34,
0x2E, 0x33, 0x31, 0x66, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x24,
0x28, 0xAF, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00,
0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x01, 0x00, 0xF9, 0x00, 0x01, 0x10,
0x26, 0xBF, 0x48, 0x02, 0x24, 0x28, 0x24, 0x00, 0x41, 0x00, 0x00, 0x00,
0x02, 0x1B, 0x00, 0xF8, 0x1C, 0xBD, 0xDA, 0xCC, 0x00, 0x00, 0x00, 0x04,
0x43, 0x41, 0x42, 0x2D, 0x62, 0x39, 0x31, 0x34, 0x36, 0x32, 0x61, 0x36,
0x61, 0x37, 0x65, 0x36, 0x64, 0x66, 0x35, 0x38, 0x33, 0x39, 0x61, 0x39,
0x62, 0x37, 0x31, 0x35, 0x65, 0x30, 0x64, 0x34, 0x65, 0x37, 0x30, 0x64,
0x31, 0x00, 0x50, 0x00, 0x0E, 0x68, 0xE4, 0x7C, 0x08, 0x00, 0x0F, 0x39,
0x00, 0x11, 0x60, 0x2E, 0x72, 0x65, 0x73, 0x53, 0x00, 0x5D, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x01, 0x55, 0xEF, 0x78, 0x46, 0x95, 0xB0, 0x7C,
0x50, 0x5A, 0x50, 0x99, 0x4F, 0x2D, 0xFA, 0x3D, 0x44, 0x42, 0xC7, 0x11,
0xB1, 0x15, 0xB6, 0x10, 0x9F, 0xEB, 0x9D, 0xF4, 0x08, 0x7B, 0xAF, 0xF9,
0x30, 0xD3, 0x84, 0xF8, 0xB3, 0x6A, 0x64, 0x23, 0x26, 0x13, 0x26, 0x83,
0x8E, 0x85, 0x3F, 0xD0
}
Функция проверки верности данных:
void
vaio_test_header_data(struct header const *header) {
fprintf(stdout,
"Expected header info:\n"
" +----------------------------+\n"
" | Signature: UnityFS\n"
" | File Version: 7\n"
" | Unity Web Version: 5.x.x\n"
" | Unity Version: 2019.4.31f1\n"
" +----------------------------+\n");
fprintf(stdout,
"Header info:\n"
" +----------------------------+\n"
" | Signature: %s\n"
" | File Version: %d\n"
" | Unity Web Version: %s\n"
" | Unity Version: %s\n"
" +----------------------------+\n",
header->signature,
header->file_version,
header->webVersion,
header->minimumVersion);
};

