blob: 83394f049c5fc625323d11be6677f644e74ef913 [file] [log] [blame]
// ==========================================================
// Input/Output functions
//
// Design and implementation by
// - Floris van den Berg (flvdberg@wxs.nl)
//
// This file is part of FreeImage 3
//
// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
// THIS DISCLAIMER.
//
// Use at your own risk!
// ==========================================================
#include "FreeImage.h"
#include "Utilities.h"
#include "FreeImageIO.h"
// =====================================================================
// File IO functions
// =====================================================================
unsigned DLL_CALLCONV
_ReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle) {
return (unsigned)fread(buffer, size, count, (FILE *)handle);
}
unsigned DLL_CALLCONV
_WriteProc(void *buffer, unsigned size, unsigned count, fi_handle handle) {
return (unsigned)fwrite(buffer, size, count, (FILE *)handle);
}
int DLL_CALLCONV
_SeekProc(fi_handle handle, long offset, int origin) {
return fseek((FILE *)handle, offset, origin);
}
long DLL_CALLCONV
_TellProc(fi_handle handle) {
return ftell((FILE *)handle);
}
// ----------------------------------------------------------
void
SetDefaultIO(FreeImageIO *io) {
io->read_proc = _ReadProc;
io->seek_proc = _SeekProc;
io->tell_proc = _TellProc;
io->write_proc = _WriteProc;
}
// =====================================================================
// Memory IO functions
// =====================================================================
unsigned DLL_CALLCONV
_MemoryReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle) {
unsigned x;
FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data);
for(x = 0; x < count; x++) {
long remaining_bytes = mem_header->file_length - mem_header->current_position;
//if there isn't size bytes left to read, set pos to eof and return a short count
if( remaining_bytes < (long)size ) {
if(remaining_bytes > 0) {
memcpy( buffer, (char *)mem_header->data + mem_header->current_position, remaining_bytes );
}
mem_header->current_position = mem_header->file_length;
break;
}
//copy size bytes count times
memcpy( buffer, (char *)mem_header->data + mem_header->current_position, size );
mem_header->current_position += size;
buffer = (char *)buffer + size;
}
return x;
}
unsigned DLL_CALLCONV
_MemoryWriteProc(void *buffer, unsigned size, unsigned count, fi_handle handle) {
void *newdata;
long newdatalen;
FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data);
//double the data block size if we need to
while( (mem_header->current_position + (long)(size * count)) >= mem_header->data_length ) {
//if we are at or above 1G, we cant double without going negative
if( mem_header->data_length & 0x40000000 ) {
//max 2G
if( mem_header->data_length == 0x7FFFFFFF ) {
return 0;
}
newdatalen = 0x7FFFFFFF;
} else if( mem_header->data_length == 0 ) {
//default to 4K if nothing yet
newdatalen = 4096;
} else {
//double size
newdatalen = mem_header->data_length << 1;
}
newdata = realloc( mem_header->data, newdatalen );
if( !newdata ) {
return 0;
}
mem_header->data = newdata;
mem_header->data_length = newdatalen;
}
memcpy( (char *)mem_header->data + mem_header->current_position, buffer, size * count );
mem_header->current_position += size * count;
if( mem_header->current_position > mem_header->file_length ) {
mem_header->file_length = mem_header->current_position;
}
return count;
}
int DLL_CALLCONV
_MemorySeekProc(fi_handle handle, long offset, int origin) {
FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data);
// you can use _MemorySeekProc to reposition the pointer anywhere in a file
// the pointer can also be positioned beyond the end of the file
switch(origin) { //0 to filelen-1 are 'inside' the file
default:
case SEEK_SET: //can fseek() to 0-7FFFFFFF always
if( offset >= 0 ) {
mem_header->current_position = offset;
return 0;
}
break;
case SEEK_CUR:
if( mem_header->current_position + offset >= 0 ) {
mem_header->current_position += offset;
return 0;
}
break;
case SEEK_END:
if( mem_header->file_length + offset >= 0 ) {
mem_header->current_position = mem_header->file_length + offset;
return 0;
}
break;
}
return -1;
}
long DLL_CALLCONV
_MemoryTellProc(fi_handle handle) {
FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data);
return mem_header->current_position;
}
// ----------------------------------------------------------
void
SetMemoryIO(FreeImageIO *io) {
io->read_proc = _MemoryReadProc;
io->seek_proc = _MemorySeekProc;
io->tell_proc = _MemoryTellProc;
io->write_proc = _MemoryWriteProc;
}