mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 01:58:19 +00:00
Add io_read_all
, io_read_all_str
and mem_has_null
:
- `io_read_all` reads all bytes from a file handle into a new buffer. It should only need one allocation per file in cases where the actual file size matches the expected file size. Otherwise it falls back to doubling the buffer size if the actual file size is larger than expected to avoid TOCTOU problems. - `io_read_all_str` reads all bytes from a file handle into a new buffer and also ensures that the buffer is null-terminated and contains no other null-characters. - `mem_has_null` is a utility used by `io_read_all_str` to ensure that no null-characters exist in the bytes read from the file.
This commit is contained in:
parent
d6d3b2d392
commit
c7fb013607
|
@ -266,6 +266,51 @@ unsigned io_read(IOHANDLE io, void *buffer, unsigned size)
|
||||||
return fread(buffer, 1, size, (FILE *)io);
|
return fread(buffer, 1, size, (FILE *)io);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void io_read_all(IOHANDLE io, void **result, unsigned *result_len)
|
||||||
|
{
|
||||||
|
long signed_len = io_length(io);
|
||||||
|
unsigned len = signed_len < 0 ? 1024 : (unsigned)signed_len; // use default initial size if we couldn't get the length
|
||||||
|
char *buffer = (char *)malloc(len + 1);
|
||||||
|
unsigned read = io_read(io, buffer, len + 1); // +1 to check if the file size is larger than expected
|
||||||
|
if(read < len)
|
||||||
|
{
|
||||||
|
buffer = (char *)realloc(buffer, read + 1);
|
||||||
|
len = read;
|
||||||
|
}
|
||||||
|
else if(read > len)
|
||||||
|
{
|
||||||
|
unsigned cap = 2 * read;
|
||||||
|
len = read;
|
||||||
|
buffer = (char *)realloc(buffer, cap);
|
||||||
|
while((read = io_read(io, buffer + len, cap - len)) != 0)
|
||||||
|
{
|
||||||
|
len += read;
|
||||||
|
if(len == cap)
|
||||||
|
{
|
||||||
|
cap *= 2;
|
||||||
|
buffer = (char *)realloc(buffer, cap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer = (char *)realloc(buffer, len + 1);
|
||||||
|
}
|
||||||
|
buffer[len] = 0;
|
||||||
|
*result = buffer;
|
||||||
|
*result_len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *io_read_all_str(IOHANDLE io)
|
||||||
|
{
|
||||||
|
void *buffer;
|
||||||
|
unsigned len;
|
||||||
|
io_read_all(io, &buffer, &len);
|
||||||
|
if(mem_has_null(buffer, len))
|
||||||
|
{
|
||||||
|
free(buffer);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return (char *)buffer;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned io_skip(IOHANDLE io, int size)
|
unsigned io_skip(IOHANDLE io, int size)
|
||||||
{
|
{
|
||||||
fseek((FILE *)io, size, SEEK_CUR);
|
fseek((FILE *)io, size, SEEK_CUR);
|
||||||
|
@ -3244,6 +3289,20 @@ int mem_comp(const void *a, const void *b, int size)
|
||||||
return memcmp(a, b, size);
|
return memcmp(a, b, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mem_has_null(const void *block, unsigned size)
|
||||||
|
{
|
||||||
|
const unsigned char *bytes = (const unsigned char *)block;
|
||||||
|
unsigned i;
|
||||||
|
for(i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
if(bytes[i] == 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void net_stats(NETSTATS *stats_inout)
|
void net_stats(NETSTATS *stats_inout)
|
||||||
{
|
{
|
||||||
*stats_inout = network_stats;
|
*stats_inout = network_stats;
|
||||||
|
|
|
@ -163,6 +163,19 @@ void mem_zero(void *block, unsigned size);
|
||||||
*/
|
*/
|
||||||
int mem_comp(const void *a, const void *b, int size);
|
int mem_comp(const void *a, const void *b, int size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a block of memory contains null bytes.
|
||||||
|
*
|
||||||
|
* @ingroup Memory
|
||||||
|
*
|
||||||
|
* @param block Pointer to the block to check for nulls.
|
||||||
|
* @param size Size of the block.
|
||||||
|
*
|
||||||
|
* @return 1 - The block has a null byte.
|
||||||
|
* @return 0 - The block does not have a null byte.
|
||||||
|
*/
|
||||||
|
int mem_has_null(const void *block, unsigned size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @defgroup File-IO
|
* @defgroup File-IO
|
||||||
*
|
*
|
||||||
|
@ -217,6 +230,36 @@ IOHANDLE io_open(const char *filename, int flags);
|
||||||
*/
|
*/
|
||||||
unsigned io_read(IOHANDLE io, void *buffer, unsigned size);
|
unsigned io_read(IOHANDLE io, void *buffer, unsigned size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the rest of the file into a buffer.
|
||||||
|
*
|
||||||
|
* @ingroup File-IO
|
||||||
|
*
|
||||||
|
* @param io Handle to the file to read data from.
|
||||||
|
* @param result Receives the file's remaining contents.
|
||||||
|
* @param result_len Receives the file's remaining length.
|
||||||
|
*
|
||||||
|
* @remark Does NOT guarantee that there are no internal null bytes.
|
||||||
|
* @remark The result must be freed after it has been used.
|
||||||
|
*/
|
||||||
|
void io_read_all(IOHANDLE io, void **result, unsigned *result_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the rest of the file into a zero-terminated buffer with
|
||||||
|
* no internal null bytes.
|
||||||
|
*
|
||||||
|
* @ingroup File-IO
|
||||||
|
*
|
||||||
|
* @param io Handle to the file to read data from.
|
||||||
|
*
|
||||||
|
* @return The file's remaining contents or null on failure.
|
||||||
|
*
|
||||||
|
* @remark Guarantees that there are no internal null bytes.
|
||||||
|
* @remark Guarantees that result will contain zero-termination.
|
||||||
|
* @remark The result must be freed after it has been used.
|
||||||
|
*/
|
||||||
|
char *io_read_all_str(IOHANDLE io);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Skips data in a file.
|
* Skips data in a file.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in a new issue