Coverage Report

Created: 2026-08-13 07:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/contrib/contrib-build/game-music-emu/gme/Data_Reader.cpp
Line
Count
Source
1
// File_Extractor 0.4.0. http://www.slack.net/~ant/
2
3
#include "Data_Reader.h"
4
5
#include "blargg_endian.h"
6
#include <assert.h>
7
#include <string.h>
8
#include <stdio.h>
9
#include <algorithm>
10
11
/* Copyright (C) 2005-2006 Shay Green. This module is free software; you
12
can redistribute it and/or modify it under the terms of the GNU Lesser
13
General Public License as published by the Free Software Foundation; either
14
version 2.1 of the License, or (at your option) any later version. This
15
module is distributed in the hope that it will be useful, but WITHOUT ANY
16
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
18
details. You should have received a copy of the GNU Lesser General Public
19
License along with this module; if not, write to the Free Software Foundation,
20
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
21
22
#include "blargg_source.h"
23
24
#ifdef HAVE_ZLIB_H
25
#include <zlib.h>
26
#include <stdlib.h>
27
#include <errno.h>
28
static const unsigned char gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
29
#endif /* HAVE_ZLIB_H */
30
31
using std::min;
32
using std::max;
33
34
const char Data_Reader::eof_error [] = "Unexpected end of file";
35
36
#define RETURN_VALIDITY_CHECK( cond ) \
37
2.44k
  do { if ( unlikely( !(cond) ) ) return "Corrupt file"; } while(0)
38
39
blargg_err_t Data_Reader::read( void* p, long s )
40
0
{
41
0
  RETURN_VALIDITY_CHECK( s > 0 );
42
43
0
  long result = read_avail( p, s );
44
0
  if ( result != s )
45
0
  {
46
0
    if ( result >= 0 && result < s )
47
0
      return eof_error;
48
49
0
    return "Read error";
50
0
  }
51
52
0
  return 0;
53
0
}
54
55
blargg_err_t Data_Reader::skip( long count )
56
1
{
57
1
  RETURN_VALIDITY_CHECK( count >= 0 );
58
59
1
  char buf [512];
60
1
  while ( count )
61
1
  {
62
1
    long n = sizeof buf;
63
1
    if ( n > count )
64
0
      n = count;
65
1
    count -= n;
66
1
    RETURN_ERR( read( buf, n ) );
67
1
  }
68
0
  return 0;
69
1
}
70
71
0
long File_Reader::remain() const { return size() - tell(); }
72
73
blargg_err_t File_Reader::skip( long n )
74
0
{
75
0
  RETURN_VALIDITY_CHECK( n >= 0 );
76
77
0
  if ( !n )
78
0
    return 0;
79
0
  return seek( tell() + n );
80
0
}
81
82
// Subset_Reader
83
84
Subset_Reader::Subset_Reader( Data_Reader* dr, long size )
85
0
{
86
0
  in = dr;
87
0
  remain_ = dr->remain();
88
0
  if ( remain_ > size )
89
0
    remain_ = max( 0l, size );
90
0
}
91
92
0
long Subset_Reader::remain() const { return remain_; }
93
94
long Subset_Reader::read_avail( void* p, long s )
95
0
{
96
0
  s = max( 0l, s );
97
0
  if ( s > remain_ )
98
0
    s = remain_;
99
0
  remain_ -= s;
100
0
  return in->read_avail( p, s );
101
0
}
102
103
// Remaining_Reader
104
105
Remaining_Reader::Remaining_Reader( void const* h, long size, Data_Reader* r )
106
0
{
107
0
  header = (char const*) h;
108
0
  header_end = header + max( 0l, size );
109
0
  in = r;
110
0
}
111
112
0
long Remaining_Reader::remain() const { return header_end - header + in->remain(); }
113
114
long Remaining_Reader::read_first( void* out, long count )
115
0
{
116
0
  count = max( 0l, count );
117
0
  long first = header_end - header;
118
0
  if ( first )
119
0
  {
120
0
    if ( first > count || first < 0 )
121
0
      first = count;
122
0
    void const* old = header;
123
0
    header += first;
124
0
    memcpy( out, old, (size_t) first );
125
0
  }
126
0
  return first;
127
0
}
128
129
long Remaining_Reader::read_avail( void* out, long count )
130
0
{
131
0
  count = max( 0l, count );
132
0
  long first = read_first( out, count );
133
0
  long second = max( 0l, count - first );
134
0
  if ( second )
135
0
  {
136
0
    second = in->read_avail( (char*) out + first, second );
137
0
    if ( second <= 0 )
138
0
      return second;
139
0
  }
140
0
  return first + second;
141
0
}
142
143
blargg_err_t Remaining_Reader::read( void* out, long count )
144
0
{
145
0
  count = max( 0l, count );
146
0
  long first = read_first( out, count );
147
0
  long second = max( 0l, count - first );
148
0
  if ( !second )
149
0
    return 0;
150
0
  return in->read( (char*) out + first, second );
151
0
}
152
153
// Mem_File_Reader
154
155
Mem_File_Reader::Mem_File_Reader( const void* p, long s ) :
156
0
  m_begin( (const char*) p ),
157
0
  m_size( max( 0l, s ) ),
158
0
  m_pos( 0l )
159
0
{
160
0
#ifdef HAVE_ZLIB_H
161
0
  if( !m_begin )
162
0
    return;
163
164
0
  if ( gz_decompress() )
165
0
  {
166
0
    debug_printf( "Loaded compressed data\n" );
167
0
    m_ownedPtr = true;
168
0
  }
169
0
#endif /* HAVE_ZLIB_H */
170
0
}
171
172
#ifdef HAVE_ZLIB_H
173
Mem_File_Reader::~Mem_File_Reader()
174
0
{
175
0
  if ( m_ownedPtr )
176
0
    free( const_cast<char*>( m_begin ) ); // see gz_compress for the malloc
177
0
}
178
#endif
179
180
0
long Mem_File_Reader::size() const { return m_size; }
181
182
long Mem_File_Reader::read_avail( void* p, long s )
183
0
{
184
0
  long r = remain();
185
0
  if ( s > r || s < 0 )
186
0
    s = r;
187
0
  memcpy( p, m_begin + m_pos, static_cast<size_t>(s) );
188
0
  m_pos += s;
189
0
  return s;
190
0
}
191
192
0
long Mem_File_Reader::tell() const { return m_pos; }
193
194
blargg_err_t Mem_File_Reader::seek( long n )
195
0
{
196
0
  RETURN_VALIDITY_CHECK( n >= 0 );
197
0
  if ( n > m_size )
198
0
    return eof_error;
199
0
  m_pos = n;
200
0
  return 0;
201
0
}
202
203
#ifdef HAVE_ZLIB_H
204
205
bool Mem_File_Reader::gz_decompress()
206
0
{
207
0
  if ( m_size >= 2 && memcmp(m_begin, gz_magic, 2) != 0 )
208
0
  {
209
    /* Don't try to decompress non-GZ files, just assign input pointer */
210
0
    return false;
211
0
  }
212
213
0
  using vec_size = size_t;
214
0
  const vec_size full_length = static_cast<vec_size>( m_size );
215
0
  const vec_size half_length = static_cast<vec_size>( m_size / 2 );
216
217
  // We use malloc/friends here so we can realloc to grow buffer if needed
218
0
  char *raw_data = reinterpret_cast<char *> ( malloc( full_length ) );
219
0
  size_t raw_data_size = full_length;
220
0
  if ( !raw_data )
221
0
    return false;
222
223
0
  z_stream strm;
224
0
  strm.next_in   = const_cast<Bytef *>( reinterpret_cast<const Bytef *>( m_begin ) );
225
0
  strm.avail_in  = static_cast<uInt>( m_size );
226
0
  strm.total_out = 0;
227
0
  strm.zalloc    = Z_NULL;
228
0
  strm.zfree     = Z_NULL;
229
230
0
  bool done = false;
231
232
  // Adding 16 sets bit 4, which enables zlib to auto-detect the
233
  // header.
234
0
  if ( inflateInit2(&strm, (16 + MAX_WBITS)) != Z_OK )
235
0
  {
236
0
    free( raw_data );
237
0
    return false;
238
0
  }
239
240
0
  while ( !done )
241
0
  {
242
    /* If our output buffer is too small */
243
0
    if ( strm.total_out >= raw_data_size )
244
0
    {
245
0
      raw_data_size += half_length;
246
0
      raw_data = reinterpret_cast<char *>( realloc( raw_data, raw_data_size ) );
247
0
      if ( !raw_data ) {
248
0
        return false;
249
0
      }
250
0
    }
251
252
0
    strm.next_out  = reinterpret_cast<Bytef *>( raw_data + strm.total_out );
253
0
    strm.avail_out = static_cast<uInt>( static_cast<uLong>( raw_data_size ) - strm.total_out );
254
255
    /* Inflate another chunk. */
256
0
    int err = inflate( &strm, Z_SYNC_FLUSH );
257
0
    if ( err == Z_STREAM_END )
258
0
      done = true;
259
0
    else if ( err != Z_OK )
260
0
      break;
261
0
  }
262
263
0
  if ( inflateEnd(&strm) != Z_OK )
264
0
  {
265
0
    free( raw_data );
266
0
    return false;
267
0
  }
268
269
0
  m_begin = raw_data;
270
0
  m_size  = static_cast<long>( strm.total_out );
271
272
0
  return true;
273
0
}
274
275
#endif /* HAVE_ZLIB_H */
276
277
278
// Callback_Reader
279
280
Callback_Reader::Callback_Reader( callback_t c, long size, void* d ) :
281
2.44k
  callback( c ),
282
2.44k
  data( d )
283
2.44k
{
284
2.44k
  remain_ = max( 0l, size );
285
2.44k
}
286
287
2.44k
long Callback_Reader::remain() const { return remain_; }
288
289
long Callback_Reader::read_avail( void* out, long count )
290
0
{
291
0
  if ( count > remain_ )
292
0
    count = remain_;
293
0
  if ( count < 0 || Callback_Reader::read( out, count ) )
294
0
    count = -1;
295
0
  return count;
296
0
}
297
298
blargg_err_t Callback_Reader::read( void* out, long count )
299
2.44k
{
300
2.44k
  RETURN_VALIDITY_CHECK( count >= 0 );
301
2.44k
  if ( count > remain_ )
302
2
    return eof_error;
303
2.44k
  return callback( data, out, (int) count );
304
2.44k
}
305
306
// Std_File_Reader
307
308
#ifdef HAVE_ZLIB_H
309
310
static const char* get_gzip_eof( const char* path, long* eof )
311
0
{
312
0
  FILE* file = fopen( path, "rb" );
313
0
  if ( !file )
314
0
    return "Couldn't open file";
315
316
0
  unsigned char buf [4];
317
0
  bool found_eof = false;
318
0
  if ( fread( buf, 2, 1, file ) > 0 && buf [0] == 0x1F && buf [1] == 0x8B )
319
0
  {
320
0
    fseek( file, -4, SEEK_END );
321
0
    if ( fread( buf, 4, 1, file ) > 0 ) {
322
0
      *eof = get_le32( buf );
323
0
      found_eof = true;
324
0
    }
325
0
  }
326
0
  if ( !found_eof )
327
0
  {
328
0
    fseek( file, 0, SEEK_END );
329
0
    *eof = ftell( file );
330
0
  }
331
0
  const char* err = (ferror( file ) || feof( file )) ? "Couldn't get file size" : nullptr;
332
0
  fclose( file );
333
0
  return err;
334
0
}
335
#endif
336
337
338
Std_File_Reader::Std_File_Reader() :
339
0
  file_( nullptr )
340
#ifdef HAVE_ZLIB_H
341
0
  , size_( 0 )
342
#endif
343
0
{ }
344
345
0
Std_File_Reader::~Std_File_Reader() { close(); }
346
347
blargg_err_t Std_File_Reader::open( const char* path )
348
0
{
349
0
#ifdef HAVE_ZLIB_H
350
  // zlib transparently handles uncompressed data if magic header
351
  // not present but we still need to grab size
352
0
  RETURN_ERR( get_gzip_eof( path, &size_ ) );
353
0
  file_ = gzopen( path, "rb" );
354
#else
355
  file_ = fopen( path, "rb" );
356
#endif
357
358
0
  if ( !file_ )
359
0
    return "Couldn't open file";
360
0
  return nullptr;
361
0
}
362
363
long Std_File_Reader::size() const
364
0
{
365
0
  if ( !file_ )
366
0
    return -1L;
367
0
#ifdef HAVE_ZLIB_H
368
0
  return size_; // Set for both compressed and uncompressed modes
369
#else
370
  long pos = tell();
371
  fseek( (FILE*) file_, 0, SEEK_END );
372
  long result = tell();
373
  fseek( (FILE*) file_, pos, SEEK_SET );
374
  return result;
375
#endif
376
0
}
377
378
long Std_File_Reader::read_avail( void* p, long s )
379
0
{
380
0
#ifdef HAVE_ZLIB_H
381
0
  if ( file_ && s > 0 && static_cast<unsigned long>(s) <= UINT_MAX ) {
382
0
    return gzread( reinterpret_cast<gzFile>(file_),
383
0
      p, static_cast<unsigned>(s) );
384
0
  }
385
0
  return 0l;
386
#else
387
  const size_t readLength = static_cast<size_t>( max( 0l, s ) );
388
  const auto result = fread( p, 1, readLength, reinterpret_cast<FILE*>(file_) );
389
  return static_cast<long>( result );
390
#endif /* HAVE_ZLIB_H */
391
0
}
392
393
blargg_err_t Std_File_Reader::read( void* p, long s )
394
0
{
395
0
  if ( !file_ )
396
0
    return "NULL FILE pointer";
397
398
0
  RETURN_VALIDITY_CHECK( s > 0 && static_cast<unsigned long>(s) <= UINT_MAX );
399
0
#ifdef HAVE_ZLIB_H
400
0
  const auto &gzfile = reinterpret_cast<gzFile>( file_ );
401
0
  if ( s == gzread( gzfile, p, static_cast<unsigned>( s ) ) )
402
0
    return nullptr;
403
0
  if ( gzeof( gzfile ) )
404
0
    return eof_error;
405
0
  return "Couldn't read from GZ file";
406
#else
407
  const auto &file = reinterpret_cast<FILE*>( file_ );
408
  if ( s == static_cast<long>( fread( p, 1, static_cast<size_t>(s), file ) ) )
409
    return 0;
410
  if ( feof( file ) )
411
    return eof_error;
412
  return "Couldn't read from file";
413
#endif
414
0
}
415
416
long Std_File_Reader::tell() const
417
0
{
418
0
  if ( !file_ )
419
0
    return -1L;
420
0
#ifdef HAVE_ZLIB_H
421
0
  return gztell( reinterpret_cast<gzFile>( file_ ) );
422
#else
423
  return ftell( reinterpret_cast<FILE*>( file_ ) );
424
#endif
425
0
}
426
427
blargg_err_t Std_File_Reader::seek( long n )
428
0
{
429
0
  if ( !file_ )
430
0
    return "NULL FILE pointer";
431
0
#ifdef HAVE_ZLIB_H
432
0
  if ( gzseek( reinterpret_cast<gzFile>( file_ ), n, SEEK_SET ) >= 0 )
433
0
    return nullptr;
434
0
  if ( n > size_ )
435
0
    return eof_error;
436
0
  return "Error seeking in GZ file";
437
#else
438
  if ( !fseek( reinterpret_cast<FILE*>( file_ ), n, SEEK_SET ) )
439
    return nullptr;
440
  if ( n > size() )
441
    return eof_error;
442
  return "Error seeking in file";
443
#endif
444
0
}
445
446
void Std_File_Reader::close()
447
0
{
448
0
  if ( file_ )
449
0
  {
450
0
#ifdef HAVE_ZLIB_H
451
0
    gzclose( reinterpret_cast<gzFile>( file_ ) );
452
#else
453
    fclose( reinterpret_cast<FILE*>( file_ ) );
454
#endif
455
0
    file_ = nullptr;
456
0
  }
457
0
}