1 // ==========================================================
2 // Input/Output functions
3 //
4 // Design and implementation by
5 // - Floris van den Berg (flvdberg@wxs.nl)
6 //
7 // This file is part of FreeImage 3
8 //
9 // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
10 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
11 // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
12 // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
13 // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
14 // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
15 // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
16 // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
17 // THIS DISCLAIMER.
18 //
19 // Use at your own risk!
20 // ==========================================================
21 
22 #include "FreeImage.h"
23 #include "Utilities.h"
24 #include "FreeImageIO.h"
25 
26 // =====================================================================
27 // File IO functions
28 // =====================================================================
29 
30 unsigned DLL_CALLCONV
_ReadProc(void * buffer,unsigned size,unsigned count,fi_handle handle)31 _ReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle) {
32 	return (unsigned)fread(buffer, size, count, (FILE *)handle);
33 }
34 
35 unsigned DLL_CALLCONV
_WriteProc(void * buffer,unsigned size,unsigned count,fi_handle handle)36 _WriteProc(void *buffer, unsigned size, unsigned count, fi_handle handle) {
37 	return (unsigned)fwrite(buffer, size, count, (FILE *)handle);
38 }
39 
40 int DLL_CALLCONV
_SeekProc(fi_handle handle,long offset,int origin)41 _SeekProc(fi_handle handle, long offset, int origin) {
42 	return fseek((FILE *)handle, offset, origin);
43 }
44 
45 long DLL_CALLCONV
_TellProc(fi_handle handle)46 _TellProc(fi_handle handle) {
47 	return ftell((FILE *)handle);
48 }
49 
50 // ----------------------------------------------------------
51 
52 void
SetDefaultIO(FreeImageIO * io)53 SetDefaultIO(FreeImageIO *io) {
54 	io->read_proc  = _ReadProc;
55 	io->seek_proc  = _SeekProc;
56 	io->tell_proc  = _TellProc;
57 	io->write_proc = _WriteProc;
58 }
59 
60 // =====================================================================
61 // Memory IO functions
62 // =====================================================================
63 
64 unsigned DLL_CALLCONV
_MemoryReadProc(void * buffer,unsigned size,unsigned count,fi_handle handle)65 _MemoryReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle) {
66 	unsigned x;
67 
68 	FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data);
69 
70 	for(x = 0; x < count; x++) {
71 		long remaining_bytes = mem_header->file_length - mem_header->current_position;
72 		//if there isn't size bytes left to read, set pos to eof and return a short count
73 		if( remaining_bytes < (long)size ) {
74 			if(remaining_bytes > 0) {
75 				memcpy( buffer, (char *)mem_header->data + mem_header->current_position, remaining_bytes );
76 			}
77 			mem_header->current_position = mem_header->file_length;
78 			break;
79 		}
80 		//copy size bytes count times
81 		memcpy( buffer, (char *)mem_header->data + mem_header->current_position, size );
82 		mem_header->current_position += size;
83 		buffer = (char *)buffer + size;
84 	}
85 	return x;
86 }
87 
88 unsigned DLL_CALLCONV
_MemoryWriteProc(void * buffer,unsigned size,unsigned count,fi_handle handle)89 _MemoryWriteProc(void *buffer, unsigned size, unsigned count, fi_handle handle) {
90 	void *newdata;
91 	long newdatalen;
92 
93 	FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data);
94 
95 	//double the data block size if we need to
96 	while( (mem_header->current_position + (long)(size * count)) >= mem_header->data_length ) {
97 		//if we are at or above 1G, we cant double without going negative
98 		if( mem_header->data_length & 0x40000000 ) {
99 			//max 2G
100 			if( mem_header->data_length == 0x7FFFFFFF ) {
101 				return 0;
102 			}
103 			newdatalen = 0x7FFFFFFF;
104 		} else if( mem_header->data_length == 0 ) {
105 			//default to 4K if nothing yet
106 			newdatalen = 4096;
107 		} else {
108 			//double size
109 			newdatalen = mem_header->data_length << 1;
110 		}
111 		newdata = realloc( mem_header->data, newdatalen );
112 		if( !newdata ) {
113 			return 0;
114 		}
115 		mem_header->data = newdata;
116 		mem_header->data_length = newdatalen;
117 	}
118 	memcpy( (char *)mem_header->data + mem_header->current_position, buffer, size * count );
119 	mem_header->current_position += size * count;
120 	if( mem_header->current_position > mem_header->file_length ) {
121 		mem_header->file_length = mem_header->current_position;
122 	}
123 	return count;
124 }
125 
126 int DLL_CALLCONV
_MemorySeekProc(fi_handle handle,long offset,int origin)127 _MemorySeekProc(fi_handle handle, long offset, int origin) {
128 	FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data);
129 
130 	// you can use _MemorySeekProc to reposition the pointer anywhere in a file
131 	// the pointer can also be positioned beyond the end of the file
132 
133 	switch(origin) { //0 to filelen-1 are 'inside' the file
134 		default:
135 		case SEEK_SET: //can fseek() to 0-7FFFFFFF always
136 			if( offset >= 0 ) {
137 				mem_header->current_position = offset;
138 				return 0;
139 			}
140 			break;
141 
142 		case SEEK_CUR:
143 			if( mem_header->current_position + offset >= 0 ) {
144 				mem_header->current_position += offset;
145 				return 0;
146 			}
147 			break;
148 
149 		case SEEK_END:
150 			if( mem_header->file_length + offset >= 0 ) {
151 				mem_header->current_position = mem_header->file_length + offset;
152 				return 0;
153 			}
154 			break;
155 	}
156 
157 	return -1;
158 }
159 
160 long DLL_CALLCONV
_MemoryTellProc(fi_handle handle)161 _MemoryTellProc(fi_handle handle) {
162 	FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data);
163 
164 	return mem_header->current_position;
165 }
166 
167 // ----------------------------------------------------------
168 
169 void
SetMemoryIO(FreeImageIO * io)170 SetMemoryIO(FreeImageIO *io) {
171 	io->read_proc  = _MemoryReadProc;
172 	io->seek_proc  = _MemorySeekProc;
173 	io->tell_proc  = _MemoryTellProc;
174 	io->write_proc = _MemoryWriteProc;
175 }
176