/src/freeimage-svn/FreeImage/trunk/Source/FreeImage/FreeImageIO.cpp
Line | Count | Source (jump to first uncovered line) |
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 |
31 | 0 | _ReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle) { |
32 | 0 | return (unsigned)fread(buffer, size, count, (FILE *)handle); |
33 | 0 | } |
34 | | |
35 | | unsigned DLL_CALLCONV |
36 | 0 | _WriteProc(void *buffer, unsigned size, unsigned count, fi_handle handle) { |
37 | 0 | return (unsigned)fwrite(buffer, size, count, (FILE *)handle); |
38 | 0 | } |
39 | | |
40 | | int DLL_CALLCONV |
41 | 0 | _SeekProc(fi_handle handle, long offset, int origin) { |
42 | 0 | return fseek((FILE *)handle, offset, origin); |
43 | 0 | } |
44 | | |
45 | | long DLL_CALLCONV |
46 | 0 | _TellProc(fi_handle handle) { |
47 | 0 | return ftell((FILE *)handle); |
48 | 0 | } |
49 | | |
50 | | // ---------------------------------------------------------- |
51 | | |
52 | | void |
53 | 0 | SetDefaultIO(FreeImageIO *io) { |
54 | 0 | io->read_proc = _ReadProc; |
55 | 0 | io->seek_proc = _SeekProc; |
56 | 0 | io->tell_proc = _TellProc; |
57 | 0 | io->write_proc = _WriteProc; |
58 | 0 | } |
59 | | |
60 | | // ===================================================================== |
61 | | // Memory IO functions |
62 | | // ===================================================================== |
63 | | |
64 | | /** |
65 | | The _MemoryReadProc function reads up to count items of size bytes from the input stream and stores them in buffer. |
66 | | _MemoryReadProc returns the number of full items actually read, |
67 | | which may be less than count if an error occurs or if the end of the file is encountered before reaching count. |
68 | | If size or count is 0, _MemoryReadProc returns 0 and the buffer contents are unchanged |
69 | | |
70 | | @param buffer |
71 | | @param size |
72 | | @param count |
73 | | @param handle |
74 | | @return |
75 | | */ |
76 | | unsigned DLL_CALLCONV |
77 | 400M | _MemoryReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle) { |
78 | 400M | if (!handle || !buffer || (size == 0) || (count == 0)) { |
79 | 26.4k | return 0; |
80 | 26.4k | } |
81 | | |
82 | 400M | FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data); |
83 | | |
84 | 400M | const int required_bytes = (int)(size) * count; |
85 | 400M | const int remaining_bytes = mem_header->file_length - mem_header->current_position; |
86 | | |
87 | 400M | if ((required_bytes > 0) && (remaining_bytes > 0)) { |
88 | 373M | if (required_bytes <= remaining_bytes) { |
89 | | // copy size bytes count times |
90 | 372M | memcpy(buffer, (char*)mem_header->data + mem_header->current_position, (size_t)required_bytes); |
91 | 372M | mem_header->current_position += required_bytes; |
92 | 372M | return count; |
93 | 372M | } |
94 | 683k | else { |
95 | | // if there isn't required_bytes bytes left to read, set pos to eof and return a short count |
96 | 683k | memcpy(buffer, (char*)mem_header->data + mem_header->current_position, (size_t)remaining_bytes); |
97 | 683k | mem_header->current_position = mem_header->file_length; |
98 | 683k | return (unsigned)(remaining_bytes / size); |
99 | 683k | } |
100 | 373M | } |
101 | | |
102 | | // if size or count is 0, _MemoryReadProc returns 0 and the buffer contents are unchanged. |
103 | 26.9M | return 0; |
104 | 400M | } |
105 | | |
106 | | unsigned DLL_CALLCONV |
107 | 0 | _MemoryWriteProc(void *buffer, unsigned size, unsigned count, fi_handle handle) { |
108 | 0 | if (!handle || !buffer) { |
109 | 0 | return 0; |
110 | 0 | } |
111 | | |
112 | 0 | FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data); |
113 | |
|
114 | 0 | const long required_bytes = (long)(size * count); |
115 | | |
116 | | // double the data block size if we need to |
117 | 0 | while( (mem_header->current_position + required_bytes) >= mem_header->data_length ) { |
118 | 0 | long newdatalen = 0; |
119 | | |
120 | | // if we are at or above 1G, we cant double without going negative |
121 | 0 | if( mem_header->data_length & 0x40000000 ) { |
122 | | // max 2G |
123 | 0 | if( mem_header->data_length == 0x7FFFFFFF ) { |
124 | 0 | return 0; |
125 | 0 | } |
126 | 0 | newdatalen = 0x7FFFFFFF; |
127 | 0 | } else if( mem_header->data_length == 0 ) { |
128 | | // default to 4K if nothing yet |
129 | 0 | newdatalen = 4096; |
130 | 0 | } else { |
131 | | // double size |
132 | 0 | newdatalen = mem_header->data_length << 1; |
133 | 0 | } |
134 | 0 | void *newdata = realloc(mem_header->data, newdatalen); |
135 | 0 | if(!newdata) { |
136 | 0 | return 0; |
137 | 0 | } |
138 | 0 | mem_header->data = newdata; |
139 | 0 | mem_header->data_length = newdatalen; |
140 | 0 | } |
141 | | |
142 | 0 | memcpy((char *)mem_header->data + mem_header->current_position, buffer, required_bytes); |
143 | 0 | mem_header->current_position += required_bytes; |
144 | |
|
145 | 0 | if( mem_header->current_position > mem_header->file_length ) { |
146 | 0 | mem_header->file_length = mem_header->current_position; |
147 | 0 | } |
148 | |
|
149 | 0 | return count; |
150 | 0 | } |
151 | | |
152 | | /** |
153 | | The _MemorySeekProc function moves the file pointer (if any) associated with stream to a new location that is offset bytes from origin. |
154 | | The next operation on the stream takes place at the new location. On a stream open for update, the next operation can be either a read or a write. |
155 | | The argument origin must be one of the following constants, defined in STDIO.H: |
156 | | SEEK_CUR Current position of file pointer. |
157 | | SEEK_END End of file. |
158 | | SEEK_SET Beginning of file. |
159 | | You can use _MemorySeekProc to reposition the pointer anywhere in a file. |
160 | | The pointer can also be positioned beyond the end of the file. |
161 | | |
162 | | @param handle |
163 | | @param offset |
164 | | @param origin |
165 | | @return If successful, returns 0. Otherwise, returns -1. |
166 | | */ |
167 | | int DLL_CALLCONV |
168 | 183M | _MemorySeekProc(fi_handle handle, long offset, int origin) { |
169 | 183M | if (!handle) { |
170 | 0 | return -1; |
171 | 0 | } |
172 | | |
173 | 183M | FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data); |
174 | | |
175 | | // you can use _MemorySeekProc to reposition the pointer anywhere in a file |
176 | | // the pointer can also be positioned beyond the end of the file |
177 | | |
178 | 183M | switch (origin) { //0 to filelen-1 are 'inside' the file |
179 | 0 | default: |
180 | 180M | case SEEK_SET: //can fseek() to 0-7FFFFFFF always |
181 | 180M | if ((offset >= 0) && (offset <= std::numeric_limits<int>::max())) { |
182 | | // the 64-bit long offset may overflow when casted to int |
183 | 156M | mem_header->current_position = offset; |
184 | 156M | return 0; |
185 | 156M | } |
186 | 24.0M | break; |
187 | | |
188 | 24.0M | case SEEK_CUR: |
189 | 2.73M | if (((mem_header->current_position + offset) >= 0) && ((mem_header->current_position + offset) <= std::numeric_limits<int>::max())) { |
190 | | // the 64-bit result may overflow when casted to int |
191 | 2.70M | mem_header->current_position += offset; |
192 | 2.70M | return 0; |
193 | 2.70M | } |
194 | 26.9k | break; |
195 | | |
196 | 96.5k | case SEEK_END: |
197 | 96.5k | if (((mem_header->file_length + offset) >= 0) && ((mem_header->file_length + offset) <= std::numeric_limits<int>::max())) { |
198 | | // the 64-bit result may overflow when casted to int |
199 | 96.5k | mem_header->current_position = mem_header->file_length + offset; |
200 | 96.5k | return 0; |
201 | 96.5k | } |
202 | 0 | break; |
203 | 183M | } |
204 | | |
205 | 24.1M | return -1; |
206 | 183M | } |
207 | | |
208 | | long DLL_CALLCONV |
209 | 269M | _MemoryTellProc(fi_handle handle) { |
210 | 269M | if (!handle) { |
211 | 0 | return -1; |
212 | 0 | } |
213 | 269M | FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data); |
214 | 269M | return mem_header->current_position; |
215 | 269M | } |
216 | | |
217 | | // ---------------------------------------------------------- |
218 | | |
219 | | void |
220 | 30.0k | SetMemoryIO(FreeImageIO *io) { |
221 | 30.0k | io->read_proc = _MemoryReadProc; |
222 | 30.0k | io->seek_proc = _MemorySeekProc; |
223 | 30.0k | io->tell_proc = _MemoryTellProc; |
224 | 30.0k | io->write_proc = _MemoryWriteProc; |
225 | 30.0k | } |