Coverage Report

Created: 2026-01-09 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeimage-svn/FreeImage/trunk/Source/FreeImage/FreeImageIO.cpp
Line
Count
Source
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
421M
_MemoryReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle) {
78
421M
  if (!handle || !buffer || (size == 0) || (count == 0)) {
79
19.5k
    return 0;
80
19.5k
  }
81
82
421M
  FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data);
83
84
421M
  const int required_bytes = (int)(size) * count;
85
421M
  const int remaining_bytes = mem_header->file_length - mem_header->current_position;
86
87
421M
  if ((required_bytes > 0) && (remaining_bytes > 0)) {
88
360M
    if (required_bytes <= remaining_bytes) {
89
      // copy size bytes count times
90
360M
      memcpy(buffer, (char*)mem_header->data + mem_header->current_position, (size_t)required_bytes);
91
360M
      mem_header->current_position += required_bytes;
92
360M
      return count;
93
360M
    }
94
195k
    else {
95
      // if there isn't required_bytes bytes left to read, set pos to eof and return a short count
96
195k
      memcpy(buffer, (char*)mem_header->data + mem_header->current_position, (size_t)remaining_bytes);
97
195k
      mem_header->current_position = mem_header->file_length;
98
195k
      return (unsigned)(remaining_bytes / size);
99
195k
    }
100
360M
  }
101
  
102
  // if size or count is 0, _MemoryReadProc returns 0 and the buffer contents are unchanged.
103
60.9M
  return 0;
104
421M
}
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
178M
_MemorySeekProc(fi_handle handle, long offset, int origin) {
169
178M
  if (!handle) {
170
0
    return -1;
171
0
  }
172
173
178M
  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
178M
  switch (origin) { //0 to filelen-1 are 'inside' the file
179
0
    default:
180
176M
    case SEEK_SET: //can fseek() to 0-7FFFFFFF always
181
176M
      if ((offset >= 0) && (offset <= std::numeric_limits<int>::max())) {
182
        // the 64-bit long offset may overflow when casted to int
183
151M
        mem_header->current_position = offset;
184
151M
        return 0;
185
151M
      }
186
24.9M
      break;
187
188
24.9M
    case SEEK_CUR:
189
1.80M
      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
1.76M
        mem_header->current_position += offset;
192
1.76M
        return 0;
193
1.76M
      }
194
38.3k
      break;
195
196
80.6k
    case SEEK_END:
197
80.6k
      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
80.6k
        mem_header->current_position = mem_header->file_length + offset;
200
80.6k
        return 0;
201
80.6k
      }
202
0
      break;
203
178M
  }
204
205
24.9M
  return -1;
206
178M
}
207
208
long DLL_CALLCONV 
209
265M
_MemoryTellProc(fi_handle handle) {
210
265M
  if (!handle) {
211
0
    return -1;
212
0
  }
213
265M
  FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data);
214
265M
  return mem_header->current_position;
215
265M
}
216
217
// ----------------------------------------------------------
218
219
void
220
25.5k
SetMemoryIO(FreeImageIO *io) {
221
25.5k
  io->read_proc  = _MemoryReadProc;
222
25.5k
  io->seek_proc  = _MemorySeekProc;
223
25.5k
  io->tell_proc  = _MemoryTellProc;
224
25.5k
  io->write_proc = _MemoryWriteProc;
225
25.5k
}