279 lines
7.5 KiB
C
279 lines
7.5 KiB
C
|
#ifndef __KOLIBRI_FILE_H_INCLUDED_
|
||
|
#define __KOLIBRI_FILE_H_INCLUDED_
|
||
|
|
||
|
#include "kolibri.h"
|
||
|
#include "kos_heap.h"
|
||
|
|
||
|
// Kolibri file interface.
|
||
|
|
||
|
namespace Kolibri // All kolibri functions, types and data are nested in the (Kolibri) namespace.
|
||
|
{
|
||
|
struct _FileDataStruct;
|
||
|
typedef _FileDataStruct *TFileData;
|
||
|
|
||
|
TFileData FileOpen(const char *name, unsigned int buffer_length = 1024);
|
||
|
int FileClose(TFileData file_data);
|
||
|
bool FileEof(TFileData file_data);
|
||
|
unsigned int FileGetPosition(TFileData file_data);
|
||
|
void FileSetPosition(TFileData file_data, unsigned int pos);
|
||
|
void FileReset(TFileData file_data);
|
||
|
unsigned int FileGetLength(TFileData file_data);
|
||
|
int FileTestRead(TFileData file_data);
|
||
|
int FileRead(TFileData file_data, void *mem, int size);
|
||
|
}
|
||
|
|
||
|
#ifdef __KOLIBRI__
|
||
|
|
||
|
namespace Kolibri
|
||
|
{
|
||
|
// Define the file data structure.
|
||
|
|
||
|
struct _FileDataStruct
|
||
|
{
|
||
|
unsigned int length;
|
||
|
unsigned int position;
|
||
|
unsigned int *buffer;
|
||
|
unsigned int access_param[5];
|
||
|
|
||
|
enum {PosName = (unsigned int)(((_FileDataStruct*)0)->access_param + 5)};
|
||
|
};
|
||
|
|
||
|
// Inline functions.
|
||
|
|
||
|
inline bool FileEof(TFileData file_data)
|
||
|
{
|
||
|
return file_data && file_data->position >= file_data->length;
|
||
|
}
|
||
|
|
||
|
inline unsigned int FileGetPosition(TFileData file_data)
|
||
|
{
|
||
|
return file_data ? file_data->position : 0;
|
||
|
}
|
||
|
|
||
|
inline void FileReset(TFileData file_data)
|
||
|
{
|
||
|
if (!file_data) return;
|
||
|
file_data->length = -1;
|
||
|
file_data->position = 0;
|
||
|
if (file_data->buffer) file_data->buffer[1] = 0;
|
||
|
}
|
||
|
|
||
|
// Functions.
|
||
|
|
||
|
int _FileAccess(void *file_access_param);
|
||
|
|
||
|
TFileData FileOpen(const char *name, unsigned int buffer_length)
|
||
|
{
|
||
|
if (!name || !name[0]) return 0;
|
||
|
unsigned int name_len = StrLen(name) + 1;
|
||
|
unsigned int data_len = (_FileDataStruct::PosName + name_len + 3) & ~3;
|
||
|
buffer_length = (buffer_length / KOLIBRI_FILE_BLOCK_SIZE) * KOLIBRI_FILE_BLOCK_SIZE;
|
||
|
if (buffer_length) data_len += buffer_length + 2*sizeof(unsigned int);
|
||
|
TFileData file = (TFileData)Alloc(_FileDataStruct::PosName + data_len);
|
||
|
if (!file) return 0;
|
||
|
file->length = -1;
|
||
|
file->position = 0;
|
||
|
if (buffer_length)
|
||
|
{
|
||
|
file->buffer = (unsigned int*)((char*)file + data_len) - 2;
|
||
|
file->buffer[0] = buffer_length;
|
||
|
file->buffer[1] = 0;
|
||
|
}
|
||
|
MemCopy(file->access_param + 5, name, name_len);
|
||
|
unsigned int attr[40/4];
|
||
|
file->access_param[0] = 5;
|
||
|
file->access_param[1] = 0;
|
||
|
file->access_param[2] = 0;
|
||
|
file->access_param[3] = 0;
|
||
|
file->access_param[4] = (int)attr;
|
||
|
_FileAccess(file->access_param);
|
||
|
file->length = attr[32/4];
|
||
|
return file;
|
||
|
}
|
||
|
|
||
|
int FileClose(TFileData file_data)
|
||
|
{
|
||
|
if (!file_data) return -1;
|
||
|
Free(file_data);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void FileSetPosition(TFileData file_data, unsigned int pos)
|
||
|
{
|
||
|
if (!file_data) return;
|
||
|
if (file_data->buffer && file_data->buffer[1])
|
||
|
{
|
||
|
if (pos >= file_data->position && pos < file_data->position + file_data->buffer[1])
|
||
|
{
|
||
|
file_data->buffer[1] -= pos - file_data->position;
|
||
|
}
|
||
|
else file_data->buffer[1] = 0;
|
||
|
}
|
||
|
file_data->position = pos;
|
||
|
}
|
||
|
|
||
|
int _FileReadBuffer(TFileData file_data, void *mem, int size, void *temp_mem = 0)
|
||
|
{
|
||
|
unsigned int *buffer;
|
||
|
if (!file_data || !mem || size <= 0) return -1;
|
||
|
if (file_data->buffer) buffer = file_data->buffer;
|
||
|
else if (temp_mem)
|
||
|
{
|
||
|
buffer = (unsigned int*)((char*)temp_mem + KOLIBRI_FILE_BLOCK_SIZE);
|
||
|
}
|
||
|
else return 0;
|
||
|
if (!buffer[1]) return 0;
|
||
|
if (file_data->position >= file_data->length)
|
||
|
{
|
||
|
buffer[1] = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
unsigned int buf_size = file_data->length - file_data->position;
|
||
|
if (buf_size > buffer[1]) buf_size = buffer[1];
|
||
|
if ((unsigned int)size >= buf_size) size = buf_size;
|
||
|
MemCopy(mem, (char*)buffer - buffer[1], size);
|
||
|
file_data->position += size;
|
||
|
if ((unsigned int)size >= buf_size) buffer[1] = 0;
|
||
|
else buffer[1] -= size;
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
int _FileReadSystem(TFileData file_data, void *mem, int size)
|
||
|
{
|
||
|
int res;
|
||
|
unsigned int len0, len1;
|
||
|
size /= KOLIBRI_FILE_BLOCK_SIZE;
|
||
|
if (!file_data || !mem || size <= 0) return -1;
|
||
|
file_data->access_param[0] = 0;
|
||
|
file_data->access_param[1] = (file_data->position / KOLIBRI_FILE_BLOCK_SIZE) * KOLIBRI_FILE_BLOCK_SIZE;
|
||
|
file_data->access_param[2] = 0;
|
||
|
file_data->access_param[3] = size * KOLIBRI_FILE_BLOCK_SIZE;
|
||
|
file_data->access_param[4] = (unsigned int)mem;
|
||
|
res = _FileAccess(file_data->access_param);
|
||
|
if (res != 0 && res != 6) return (res & 255) - 1024;
|
||
|
if (file_data->length <= file_data->position) return 0;
|
||
|
len0 = file_data->length - file_data->position;
|
||
|
len1 = size * KOLIBRI_FILE_BLOCK_SIZE - (file_data->position % KOLIBRI_FILE_BLOCK_SIZE);
|
||
|
return (len0 <= len1) ? len0 : len1;
|
||
|
}
|
||
|
|
||
|
int _FileBufferSystem(TFileData file_data, void *&temp_mem)
|
||
|
{
|
||
|
int res;
|
||
|
unsigned int *buffer;
|
||
|
if (!file_data) return -1;
|
||
|
if (file_data->buffer) buffer = file_data->buffer;
|
||
|
else
|
||
|
{
|
||
|
if (!temp_mem)
|
||
|
{
|
||
|
temp_mem = Alloc(KOLIBRI_FILE_BLOCK_SIZE + 2*sizeof(unsigned int));
|
||
|
if (!temp_mem) return -10;
|
||
|
}
|
||
|
buffer = (unsigned int*)((char*)temp_mem + KOLIBRI_FILE_BLOCK_SIZE);
|
||
|
buffer[0] = KOLIBRI_FILE_BLOCK_SIZE;
|
||
|
}
|
||
|
buffer[1] = buffer[0];
|
||
|
res = _FileReadSystem(file_data, (char*)buffer - buffer[1], buffer[1]);
|
||
|
if (res < 0) buffer[1] = 0;
|
||
|
else buffer[1] -= file_data->position % KOLIBRI_FILE_BLOCK_SIZE;
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
int FileTestRead(TFileData file_data)
|
||
|
{
|
||
|
int res;
|
||
|
void *temp_mem = 0;
|
||
|
if (!file_data) return -1;
|
||
|
if (file_data->buffer && file_data->buffer[1]) return 0;
|
||
|
res = _FileBufferSystem(file_data, temp_mem);
|
||
|
if (temp_mem) Free(temp_mem);
|
||
|
return (res < 0) ? res : 0;
|
||
|
}
|
||
|
|
||
|
int FileRead(TFileData file_data, void *mem, int size)
|
||
|
{
|
||
|
int tlen, res, read_len;
|
||
|
void *temp_mem = 0;
|
||
|
res = _FileReadBuffer(file_data, mem, size);
|
||
|
if (res < 0 || res >= size) return res;
|
||
|
read_len = res;
|
||
|
mem = (char*)mem + res;
|
||
|
size -= res;
|
||
|
tlen = file_data->position % KOLIBRI_FILE_BLOCK_SIZE;
|
||
|
if (tlen)
|
||
|
{
|
||
|
res = _FileBufferSystem(file_data, temp_mem);
|
||
|
if (res < 0)
|
||
|
{
|
||
|
if (temp_mem) Free(temp_mem);
|
||
|
return read_len ? read_len : res;
|
||
|
}
|
||
|
res = _FileReadBuffer(file_data, mem, size);
|
||
|
read_len += res;
|
||
|
if (res >= size || file_data->length <= file_data->position ||
|
||
|
file_data->length - file_data->position <= res)
|
||
|
{
|
||
|
if (temp_mem) Free(temp_mem);
|
||
|
return read_len;
|
||
|
}
|
||
|
mem = (char*)mem + res;
|
||
|
size -= res;
|
||
|
}
|
||
|
if (size >= (file_data->buffer ? file_data->buffer[0] : KOLIBRI_FILE_BLOCK_SIZE))
|
||
|
{
|
||
|
res = _FileReadSystem(file_data, mem, size);
|
||
|
if (res < 0)
|
||
|
{
|
||
|
if (temp_mem) Free(temp_mem);
|
||
|
return read_len ? read_len : res;
|
||
|
}
|
||
|
file_data->position += res;
|
||
|
read_len += res;
|
||
|
if (res < (size / KOLIBRI_FILE_BLOCK_SIZE) * KOLIBRI_FILE_BLOCK_SIZE)
|
||
|
{
|
||
|
if (temp_mem) Free(temp_mem);
|
||
|
return read_len;
|
||
|
}
|
||
|
mem = (char*)mem + res;
|
||
|
size -= res;
|
||
|
}
|
||
|
if (size)
|
||
|
{
|
||
|
res = _FileBufferSystem(file_data, temp_mem);
|
||
|
if (res < 0)
|
||
|
{
|
||
|
if (temp_mem) Free(temp_mem);
|
||
|
return read_len ? read_len : res;
|
||
|
}
|
||
|
read_len += _FileReadBuffer(file_data, mem, size, temp_mem);
|
||
|
}
|
||
|
if (temp_mem) Free(temp_mem);
|
||
|
return read_len;
|
||
|
}
|
||
|
|
||
|
// Inline functions.
|
||
|
|
||
|
inline unsigned int FileGetLength(TFileData file_data)
|
||
|
{
|
||
|
if (!file_data) return -1;
|
||
|
if (file_data->length == -1) FileTestRead(file_data);
|
||
|
return file_data->length;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#else // def __KOLIBRI__
|
||
|
|
||
|
namespace Kolibri
|
||
|
{
|
||
|
struct _FileDataStruct
|
||
|
{
|
||
|
unsigned int data;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
#endif // else: def __KOLIBRI__
|
||
|
|
||
|
#endif // ndef __KOLIBRI_FILE_H_INCLUDED_
|
||
|
|