#ifndef __KOLIBRI_FILE_H_INCLUDED_ #define __KOLIBRI_FILE_H_INCLUDED_ #include #include // 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 __MENUET__ 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 __MENUET__ namespace Kolibri { struct _FileDataStruct { unsigned int data; }; } #endif // else: def __MENUET__ #endif // ndef __KOLIBRI_FILE_H_INCLUDED_