Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/mpg123/src/libmpg123/lfs_wrap.c
4394 views
1
/*
2
lfs_wrap: Wrapper code for reader functions, both internal and external.
3
4
copyright 2010-2023 by the mpg123 project
5
free software under the terms of the LGPL 2.1
6
see COPYING and AUTHORS files in distribution or http://mpg123.org
7
8
initially written by Thomas Orgis, thanks to Guido Draheim for consulting
9
and later manx for stirring it all up again
10
11
This file used to wrap 32 bit off_t client API to 64 bit off_t API. Now it is
12
mapping any user API with either off_t to portable int64_t API, while also
13
providing the guts of that also via a wrapper handle. This keeps the actual
14
read and seek implementation out of readers.c.
15
16
See doc/LARGEFILE for the big picture.
17
18
Note about file descriptors: We just assume that they are generally
19
interchangeable between large and small file code... and that a large file
20
descriptor will trigger errors when accessed with small file code where it
21
may cause trouble (a really large file).
22
*/
23
24
#include "config.h"
25
26
// Only activate the explicit largefile stuff here. The rest of the code shall
27
// work with abstract 64 bit offsets, or just plain default off_t (possibly
28
// using _FILE_OFFSET_BITS magic).
29
// Note that this macro does not influence normal off_t-using code.
30
#ifdef LFS_LARGEFILE_64
31
#define _LARGEFILE64_SOURCE
32
#endif
33
34
// For correct MPG123_EXPORT.
35
#include "../common/abi_align.h"
36
37
// Need the full header with non-portable API, for the bare mpg123_open*()
38
// declarations. But no renaming shenanigans.
39
#define MPG123_NO_LARGENAME
40
#include "mpg123.h"
41
42
#include "lfs_wrap.h"
43
#include "../common/abi_align.h"
44
#include "../compat/compat.h"
45
#include <sys/stat.h>
46
#include <fcntl.h>
47
48
#ifndef OFF_MAX
49
#undef OFF_MIN
50
#if SIZEOF_OFF_T == 4
51
#define OFF_MAX INT32_MAX
52
#define OFF_MIN INT32_MIN
53
#elif SIZEOF_OFF_T == 8
54
#define OFF_MAX INT64_MAX
55
#define OFF_MIN INT64_MIN
56
#else
57
#error "Unexpected width of off_t."
58
#endif
59
#endif
60
61
// A paranoid check that someone did not define a wrong SIZEOF_OFF_T at configure time.
62
typedef unsigned char MPG123_STATIC_ASSERT[(SIZEOF_OFF_T == sizeof(off_t)) ? 1 : -1];
63
64
#include "../common/debug.h"
65
66
// We do not want to expose this publicly, but it is cleaner to have it also defined
67
// as portable API to offer the legacy function wrapper over. It's an undocumented
68
// function for int64_t arguments.
69
int attribute_align_arg mpg123_position64( mpg123_handle *fr, int64_t no, int64_t buffsize
70
, int64_t *current_frame, int64_t *frames_left
71
, double *current_seconds, double *seconds_left );
72
73
/* I see that I will need custom data storage. Main use is for the replaced I/O later, but the seek table for small file offsets needs extra storage, too. */
74
75
// The wrapper handle for descriptor and handle I/O.
76
// It is also used for storing a converted frame index.
77
// Plain portable API I/O should not need it at all.
78
#define IO_HANDLE64 0 /* no wrapping at all: client-provided callbacks */
79
#define IO_FD 1 /* default off_t callbacks */
80
#define IO_HANDLE 2 /* Wrapping over custom handle callbacks with off_t. */
81
#ifdef LFS_LARGEFILE_64
82
#define IO_FD_64 3 /* off64_t callbacks */
83
#define IO_HANDLE_64 4 /* ... with off64_t. */
84
#endif
85
#define IO_INT_FD 5 /* Internal I/O using a file descriptor and wrappers defined here. */
86
87
struct wrap_data
88
{
89
/* Storage for small offset index table. */
90
#if SIZEOF_OFF_T == 4
91
off_t *indextable;
92
// And ironically, another big offset table for mpg123_set_index_32.
93
// I wand to avoid having to change a line of code in the internals.
94
int64_t *set_indextable;
95
#endif
96
/* I/O handle stuff */
97
int iotype; // one of the above numbers
98
/* Data for IO_FD variants. */
99
int fd;
100
int my_fd; /* A descriptor that the wrapper code opened itself. */
101
#ifdef TIMEOUT_READ
102
time_t timeout_sec;
103
#endif
104
void* handle; // for IO_HANDLE variants
105
/* The actual callbacks from the outside. */
106
mpg123_ssize_t (*r_read) (int, void *, size_t);
107
off_t (*r_lseek)(int, off_t, int);
108
mpg123_ssize_t (*r_h_read)(void *, void *, size_t);
109
off_t (*r_h_lseek)(void*, off_t, int);
110
#ifdef LFS_LARGEFILE_64
111
mpg123_ssize_t (*r_read_64) (int, void *, size_t);
112
off64_t (*r_lseek_64)(int, off64_t, int);
113
mpg123_ssize_t (*r_h_read_64)(void *, void *, size_t);
114
off64_t (*r_h_lseek_64)(void*, off64_t, int);
115
#endif
116
void (*h_cleanup)(void*);
117
};
118
119
/* Cleanup I/O part of the handle handle... but not deleting the wrapper handle itself.
120
That is stored in the frame and only deleted on mpg123_delete(). */
121
static void wrap_io_cleanup(void *handle)
122
{
123
struct wrap_data *ioh = handle;
124
debug("wrapper I/O cleanup");
125
if(ioh->iotype == IO_HANDLE
126
#ifdef LFS_LARGEFILE_64
127
|| ioh->iotype == IO_HANDLE_64
128
#endif
129
){
130
if(ioh->h_cleanup != NULL && ioh->handle != NULL)
131
{
132
mdebug("calling client handle cleanup %p", ioh->handle);
133
ioh->h_cleanup(ioh->handle);
134
}
135
ioh->handle = NULL;
136
}
137
if(ioh->my_fd >= 0)
138
{
139
mdebug("closing my fd %d", ioh->my_fd);
140
#if defined(MPG123_COMPAT_MSVCRT_IO)
141
_close(ioh->my_fd);
142
#else
143
close(ioh->my_fd);
144
#endif
145
ioh->my_fd = -1;
146
}
147
}
148
149
/* Really finish off the handle... freeing all memory. */
150
void INT123_wrap_destroy(void *handle)
151
{
152
struct wrap_data *wh = handle;
153
if(!wh)
154
return;
155
wrap_io_cleanup(handle);
156
#if SIZEOF_OFF_T == 4
157
if(wh->indextable != NULL)
158
free(wh->indextable);
159
if(wh->set_indextable != NULL)
160
free(wh->set_indextable);
161
#endif
162
163
free(wh);
164
}
165
166
/* More helper code... extract the special wrapper handle, possible allocate and initialize it. */
167
static struct wrap_data* wrap_get(mpg123_handle *mh, int force_alloc)
168
{
169
struct wrap_data* whd;
170
void ** whd_ = INT123_wrap_handle(mh);
171
172
if(whd_ == NULL)
173
return NULL;
174
175
/* Access the private storage inside the mpg123 handle.
176
The real callback functions and handles are stored there. */
177
if(*whd_ == NULL && force_alloc)
178
{
179
/* Create a new one. */
180
*whd_ = malloc(sizeof(struct wrap_data));
181
if(*whd_ == NULL)
182
{
183
INT123_set_err(mh, MPG123_OUT_OF_MEM);
184
return NULL;
185
}
186
whd = *whd_;
187
#if SIZEOF_OFF_T == 4
188
whd->indextable = NULL;
189
whd->set_indextable = NULL;
190
#endif
191
whd->iotype = IO_HANDLE64; // By default, the I/O path is not affected.
192
whd->fd = -1;
193
whd->my_fd = -1;
194
whd->handle = NULL;
195
whd->r_read = NULL;
196
whd->r_lseek = NULL;
197
whd->r_h_read = NULL;
198
whd->r_h_lseek = NULL;
199
#ifdef LFS_LARGEFILE_64
200
whd->r_read_64 = NULL;
201
whd->r_lseek_64 = NULL;
202
whd->r_h_read_64 = NULL;
203
whd->r_h_lseek_64 = NULL;
204
#endif
205
whd->h_cleanup = NULL;
206
}
207
else whd = *whd_;
208
209
return whd;
210
}
211
212
/* After settling the data... start with some simple wrappers. */
213
214
// The first block of wrappers is always present, using the native off_t width.
215
// (Exception: If explicitly disabled using FORCED_OFF_64.)
216
// A second block mirrors that in case of sizeof(off_t)==4 with _32 suffix.
217
// A third block follows if 64 bit off_t is available with _64 suffix, just aliasing
218
// the int64_t functions.
219
220
#ifndef FORCED_OFF_64
221
222
#define OFF_CONV(value, variable, handle) \
223
if((value) >= OFF_MIN && (value) <= OFF_MAX) \
224
variable = (off_t)(value); \
225
else return INT123_set_err(handle, MPG123_LFS_OVERFLOW);
226
227
#define OFF_CONVP(value, varpointer, handle) \
228
if(varpointer){ OFF_CONV(value, *(varpointer), handle) }
229
230
#define OFF_RETURN(value, handle) \
231
return ((value) >= OFF_MIN && (value) <= OFF_MAX) \
232
? (off_t)(value) \
233
: INT123_set_err(handle, MPG123_LFS_OVERFLOW);
234
235
int attribute_align_arg mpg123_framebyframe_decode(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes)
236
{
237
int64_t fnum = 0;
238
int ret = mpg123_framebyframe_decode64(mh, &fnum, audio, bytes);
239
OFF_CONVP(fnum, num, mh)
240
return ret;
241
}
242
243
int attribute_align_arg mpg123_decode_frame(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes)
244
{
245
int64_t fnum = 0;
246
int ret = mpg123_decode_frame64(mh, &fnum, audio, bytes);
247
OFF_CONVP(fnum, num, mh)
248
return ret;
249
}
250
251
off_t attribute_align_arg mpg123_timeframe(mpg123_handle *mh, double seconds)
252
{
253
int64_t b = mpg123_timeframe64(mh, seconds);
254
OFF_RETURN(b, mh)
255
}
256
257
off_t attribute_align_arg mpg123_tell(mpg123_handle *mh)
258
{
259
int64_t pos = mpg123_tell64(mh);
260
OFF_RETURN(pos, mh)
261
}
262
263
off_t attribute_align_arg mpg123_tellframe(mpg123_handle *mh)
264
{
265
int64_t frame = mpg123_tellframe64(mh);
266
OFF_RETURN(frame, mh)
267
}
268
269
off_t attribute_align_arg mpg123_tell_stream(mpg123_handle *mh)
270
{
271
int64_t off = mpg123_tell_stream64(mh);
272
OFF_RETURN(off, mh)
273
}
274
275
off_t attribute_align_arg mpg123_seek(mpg123_handle *mh, off_t sampleoff, int whence)
276
{
277
int64_t ret = mpg123_seek64(mh, (int64_t)sampleoff, whence);
278
OFF_RETURN(ret, mh)
279
}
280
281
off_t attribute_align_arg mpg123_feedseek(mpg123_handle *mh, off_t sampleoff, int whence, off_t *input_offset)
282
{
283
int64_t inoff = 0;
284
int64_t ret = mpg123_feedseek64(mh, (int64_t)sampleoff, whence, &inoff);
285
OFF_CONVP(inoff, input_offset, mh)
286
OFF_RETURN(ret, mh)
287
}
288
289
off_t attribute_align_arg mpg123_seek_frame(mpg123_handle *mh, off_t offset, int whence)
290
{
291
int64_t ret = mpg123_seek_frame64(mh, (int64_t)offset, whence);
292
OFF_RETURN(ret, mh)
293
}
294
295
int attribute_align_arg mpg123_set_filesize(mpg123_handle *mh, off_t size)
296
{
297
return mpg123_set_filesize64(mh, (int64_t)size);
298
}
299
300
off_t attribute_align_arg mpg123_framelength(mpg123_handle *mh)
301
{
302
int64_t ret = mpg123_framelength64(mh);
303
OFF_RETURN(ret, mh)
304
}
305
306
off_t attribute_align_arg mpg123_length(mpg123_handle *mh)
307
{
308
int64_t ret = mpg123_length64(mh);
309
OFF_RETURN(ret, mh)
310
}
311
312
// Native off_t is either identical to int32_t or int64_t.
313
// If the former, we create a copy of the index table.
314
int attribute_align_arg mpg123_index(mpg123_handle *mh, off_t **offsets, off_t *step, size_t *fill)
315
{
316
#if SIZEOF_OFF_T == 8
317
return mpg123_index64(mh, (int64_t**)offsets, (int64_t*)step, fill);
318
#else
319
int err;
320
int64_t largestep;
321
int64_t *largeoffsets;
322
struct wrap_data *whd;
323
if(mh == NULL)
324
return MPG123_BAD_HANDLE;
325
if(offsets == NULL || step == NULL || fill == NULL)
326
return INT123_set_err(mh, MPG123_BAD_INDEX_PAR);
327
*fill = 0; // better safe than sorry
328
329
whd = wrap_get(mh, 1);
330
if(whd == NULL) return MPG123_ERR;
331
332
err = mpg123_index64(mh, &largeoffsets, &largestep, fill);
333
if(err != MPG123_OK) return err;
334
335
/* For a _very_ large file, even the step could overflow. */
336
OFF_CONV(largestep, *step, mh);
337
338
/* When there are no values stored, there is no table content to take care of.
339
Table pointer does not matter. Mission completed. */
340
if(*fill == 0) return MPG123_OK;
341
342
/* Construct a copy of the index to hand over to the small-minded client. */
343
*offsets = INT123_safe_realloc(whd->indextable, (*fill)*sizeof(int32_t));
344
if(*offsets == NULL)
345
return INT123_set_err(mh, MPG123_OUT_OF_MEM);
346
whd->indextable = *offsets;
347
/* Elaborate conversion of each index value, with overflow check. */
348
for(size_t i=0; i<*fill; ++i)
349
OFF_CONV(largeoffsets[i], whd->indextable[i], mh);
350
/* If we came that far... there should be a valid copy of the table now. */
351
return MPG123_OK;
352
#endif
353
}
354
355
int attribute_align_arg mpg123_set_index(mpg123_handle *mh, off_t *offsets, off_t step, size_t fill)
356
{
357
#if SIZEOF_OFF_T == 8
358
return mpg123_set_index64(mh, (int64_t*)offsets, (int64_t)step, fill);
359
#else
360
int err;
361
struct wrap_data *whd;
362
int64_t *indextmp;
363
if(mh == NULL) return MPG123_BAD_HANDLE;
364
365
whd = wrap_get(mh, 1);
366
if(whd == NULL) return MPG123_ERR;
367
368
if(fill > 0 && offsets == NULL)
369
return INT123_set_err(mh, MPG123_BAD_INDEX_PAR);
370
else
371
{
372
/* Expensive temporary storage... for staying outside at the API layer. */
373
indextmp = INT123_safe_realloc(whd->set_indextable, fill*sizeof(int64_t));
374
if(indextmp == NULL)
375
return INT123_set_err(mh, MPG123_OUT_OF_MEM);
376
whd->set_indextable = indextmp;
377
/* Fill the large-file copy of the provided index, then feed it to mpg123. */
378
for(size_t i=0; i<fill; ++i)
379
indextmp[i] = offsets[i];
380
err = mpg123_set_index64(mh, indextmp, (int64_t)step, fill);
381
}
382
383
return err;
384
#endif
385
}
386
387
off_t attribute_align_arg mpg123_framepos(mpg123_handle *mh)
388
{
389
int64_t pos = mpg123_framepos64(mh);
390
OFF_RETURN(pos, mh)
391
}
392
393
int attribute_align_arg mpg123_position( mpg123_handle *mh, off_t INT123_frame_offset
394
, off_t buffered_bytes, off_t *current_frame, off_t *frames_left
395
, double *current_seconds, double *seconds_left )
396
{
397
int64_t curframe, frameleft;
398
int err;
399
400
err = mpg123_position64( mh, (int64_t)INT123_frame_offset, (int64_t)buffered_bytes
401
, &curframe, &frameleft, current_seconds, seconds_left );
402
if(err != MPG123_OK) return err;
403
404
OFF_CONVP(curframe, current_frame, mh)
405
OFF_CONVP(frameleft, frames_left, mh);
406
return MPG123_OK;
407
}
408
409
#endif // FORCED_OFF_64
410
411
// _32 aliases only for native 32 bit off_t
412
// Will compilers be smart enough to optimize away the extra function call?
413
#if SIZEOF_OFF_T == 4
414
415
// The open routines are trivial now. I only have differeing symbols suffixes
416
// to keep legacy ABI.
417
418
int attribute_align_arg mpg123_open_32(mpg123_handle *mh, const char *path)
419
{
420
return mpg123_open(mh, path);
421
}
422
423
int attribute_align_arg mpg123_open_fixed_32( mpg123_handle *mh, const char *path
424
, int channels, int encoding )
425
{
426
return mpg123_open_fixed(mh, path, channels, encoding);
427
}
428
429
int attribute_align_arg mpg123_open_fd_32(mpg123_handle *mh, int fd)
430
{
431
return mpg123_open_fd(mh, fd);
432
}
433
434
int attribute_align_arg mpg123_open_handle_32(mpg123_handle *mh, void *iohandle)
435
{
436
return mpg123_open_handle(mh, iohandle);
437
}
438
439
int attribute_align_arg mpg123_framebyframe_decode_32(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes)
440
{
441
return mpg123_framebyframe_decode(mh, num, audio, bytes);
442
}
443
444
int attribute_align_arg mpg123_decode_frame_32(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes)
445
{
446
return mpg123_decode_frame(mh, num, audio, bytes);
447
}
448
449
off_t attribute_align_arg mpg123_timeframe_32(mpg123_handle *mh, double seconds)
450
{
451
return mpg123_timeframe64(mh, seconds);
452
}
453
454
off_t attribute_align_arg mpg123_tell_32(mpg123_handle *mh)
455
{
456
return mpg123_tell(mh);
457
}
458
459
off_t attribute_align_arg mpg123_tellframe_32(mpg123_handle *mh)
460
{
461
return mpg123_tellframe(mh);
462
}
463
464
off_t attribute_align_arg mpg123_tell_stream_32(mpg123_handle *mh)
465
{
466
return mpg123_tell_stream(mh);
467
}
468
469
off_t attribute_align_arg mpg123_seek_32(mpg123_handle *mh, off_t sampleoff, int whence)
470
{
471
return mpg123_seek(mh, sampleoff, whence);
472
}
473
474
off_t attribute_align_arg mpg123_feedseek_32(mpg123_handle *mh, off_t sampleoff, int whence, off_t *input_offset)
475
{
476
return mpg123_feedseek(mh, sampleoff, whence, input_offset);
477
}
478
479
off_t attribute_align_arg mpg123_seek_frame_32(mpg123_handle *mh, off_t offset, int whence)
480
{
481
return mpg123_seek_frame(mh, offset, whence);
482
}
483
484
int attribute_align_arg mpg123_set_filesize_32(mpg123_handle *mh, off_t size)
485
{
486
return mpg123_set_filesize(mh, size);
487
}
488
489
off_t attribute_align_arg mpg123_framelength_32(mpg123_handle *mh)
490
{
491
return mpg123_framelength(mh);
492
}
493
494
off_t attribute_align_arg mpg123_length_32(mpg123_handle *mh)
495
{
496
return mpg123_length(mh);
497
}
498
499
int attribute_align_arg mpg123_index_32(mpg123_handle *mh, off_t **offsets, off_t *step, size_t *fill)
500
{
501
return mpg123_index(mh, offsets, step, fill);
502
}
503
504
int attribute_align_arg mpg123_set_index_32(mpg123_handle *mh, off_t *offsets, off_t step, size_t fill)
505
{
506
return mpg123_set_index(mh, offsets, step, fill);
507
}
508
509
off_t attribute_align_arg mpg123_framepos_32(mpg123_handle *mh)
510
{
511
return mpg123_framepos(mh);
512
}
513
514
int attribute_align_arg mpg123_position_32( mpg123_handle *mh, off_t INT123_frame_offset
515
, off_t buffered_bytes, off_t *current_frame, off_t *frames_left
516
, double *current_seconds, double *seconds_left )
517
{
518
return mpg123_position( mh, INT123_frame_offset, buffered_bytes
519
, current_frame, frames_left, current_seconds, seconds_left );
520
}
521
522
#endif
523
524
// _64 aliases if we either got some off64_t to work with or
525
// if there is no explicit 64 bit API but off_t is just always
526
// 64 bits.
527
#if defined(LFS_LARGEFILE_64) || (SIZEOF_OFF_T == 8)
528
529
#ifdef LFS_LARGEFILE_64
530
#define OFF64 off64_t
531
#else
532
#define OFF64 off_t
533
#endif
534
535
#ifndef FORCED_OFF_64
536
// When 64 bit offsets are enforced, libmpg123.c defines the _64 functions directly.
537
// There is no actual wrapper work, anyway.
538
539
int attribute_align_arg mpg123_open_64(mpg123_handle *mh, const char *path)
540
{
541
return mpg123_open(mh, path);
542
}
543
544
int attribute_align_arg mpg123_open_fixed_64( mpg123_handle *mh, const char *path
545
, int channels, int encoding )
546
{
547
return mpg123_open_fixed(mh, path, channels, encoding);
548
}
549
550
int attribute_align_arg mpg123_open_fd_64(mpg123_handle *mh, int fd)
551
{
552
return mpg123_open_fd(mh, fd);
553
}
554
555
int attribute_align_arg mpg123_open_handle_64(mpg123_handle *mh, void *iohandle)
556
{
557
return mpg123_open_handle(mh, iohandle);
558
}
559
#endif
560
561
562
int attribute_align_arg mpg123_framebyframe_decode_64(mpg123_handle *mh, OFF64 *num, unsigned char **audio, size_t *bytes)
563
{
564
return mpg123_framebyframe_decode64(mh, (int64_t*)num, audio, bytes);
565
}
566
567
int attribute_align_arg mpg123_decode_frame_64(mpg123_handle *mh, OFF64 *num, unsigned char **audio, size_t *bytes)
568
{
569
return mpg123_decode_frame64(mh, (int64_t*)num, audio, bytes);
570
}
571
572
OFF64 attribute_align_arg mpg123_timeframe_64(mpg123_handle *mh, double seconds)
573
{
574
return mpg123_timeframe64(mh, seconds);
575
}
576
577
OFF64 attribute_align_arg mpg123_tell_64(mpg123_handle *mh)
578
{
579
return mpg123_tell64(mh);
580
}
581
582
OFF64 attribute_align_arg mpg123_tellframe_64(mpg123_handle *mh)
583
{
584
return mpg123_tellframe64(mh);
585
}
586
587
OFF64 attribute_align_arg mpg123_tell_stream_64(mpg123_handle *mh)
588
{
589
return mpg123_tell_stream64(mh);
590
}
591
592
OFF64 attribute_align_arg mpg123_seek_64(mpg123_handle *mh, OFF64 sampleoff, int whence)
593
{
594
return mpg123_seek64(mh, (int64_t)sampleoff, whence);
595
}
596
597
OFF64 attribute_align_arg mpg123_feedseek_64(mpg123_handle *mh, OFF64 sampleoff, int whence, OFF64 *input_offset)
598
{
599
return mpg123_feedseek64(mh, (int64_t)sampleoff, whence, (int64_t*)input_offset);
600
}
601
602
OFF64 attribute_align_arg mpg123_seek_frame_64(mpg123_handle *mh, OFF64 offset, int whence)
603
{
604
return mpg123_seek_frame64(mh, (int64_t)offset, whence);
605
}
606
607
int attribute_align_arg mpg123_set_filesize_64(mpg123_handle *mh, OFF64 size)
608
{
609
return mpg123_set_filesize64(mh, (int64_t)size);
610
}
611
612
OFF64 attribute_align_arg mpg123_framelength_64(mpg123_handle *mh)
613
{
614
return mpg123_framelength64(mh);
615
}
616
617
OFF64 attribute_align_arg mpg123_length_64(mpg123_handle *mh)
618
{
619
return mpg123_length64(mh);
620
}
621
622
int attribute_align_arg mpg123_index_64(mpg123_handle *mh, OFF64 **offsets, OFF64 *step, size_t *fill)
623
{
624
return mpg123_index64(mh, (int64_t**)offsets, (int64_t*)step, fill);
625
}
626
627
int attribute_align_arg mpg123_set_index_64(mpg123_handle *mh, OFF64 *offsets, OFF64 step, size_t fill)
628
{
629
return mpg123_set_index64(mh, (int64_t*)offsets, (int64_t)step, fill);
630
}
631
632
OFF64 attribute_align_arg mpg123_framepos_64(mpg123_handle *mh)
633
{
634
return mpg123_framepos64(mh);
635
}
636
637
int attribute_align_arg mpg123_position_64( mpg123_handle *mh, OFF64 INT123_frame_offset
638
, OFF64 buffered_bytes, OFF64 *current_frame, OFF64 *frames_left
639
, double *current_seconds, double *seconds_left )
640
{
641
return mpg123_position64( mh, (int64_t)INT123_frame_offset, (int64_t)buffered_bytes
642
, (int64_t*)current_frame, (int64_t*)frames_left, current_seconds, seconds_left );
643
}
644
645
#undef OFF64
646
#endif
647
648
/* =========================================
649
THE BOUNDARY OF SANITY
650
Behold, stranger!
651
========================================= */
652
653
// One read callback wrapping over all 4 client callback variants.
654
static int wrap_read(void* handle, void *buf, size_t count, size_t *got)
655
{
656
struct wrap_data *ioh = handle;
657
ptrdiff_t retgot = -1;
658
switch(ioh->iotype)
659
{
660
case IO_FD:
661
retgot = ioh->r_read(ioh->fd, buf, count);
662
break;
663
case IO_HANDLE:
664
retgot = ioh->r_h_read(ioh->handle, buf, count);
665
break;
666
#ifdef LFS_LARGEFILE_64
667
case IO_FD_64:
668
retgot = ioh->r_read_64(ioh->fd, buf, count);
669
break;
670
case IO_HANDLE_64:
671
retgot = ioh->r_h_read_64(ioh->handle, buf, count);
672
break;
673
#endif
674
default:
675
error("Serious breakage - bad IO type in LFS wrapper!");
676
}
677
if(got)
678
*got = retgot > 0 ? (size_t)retgot : 0;
679
return retgot >= 0 ? 0 : -1;
680
}
681
682
// One seek callback wrapping over all 4 client callback variants.
683
static int64_t wrap_lseek(void *handle, int64_t offset, int whence)
684
{
685
struct wrap_data *ioh = handle;
686
687
if( (ioh->iotype == IO_FD || ioh->iotype == IO_HANDLE) &&
688
(offset < OFF_MIN || offset > OFF_MAX) )
689
{
690
errno = EOVERFLOW;
691
return -1;
692
}
693
switch(ioh->iotype)
694
{
695
case IO_FD: return ioh->r_lseek(ioh->fd, (off_t)offset, whence);
696
case IO_HANDLE: return ioh->r_h_lseek(ioh->handle, (off_t)offset, whence);
697
#ifdef LFS_LARGEFILE_64
698
case IO_FD_64: return ioh->r_lseek_64(ioh->fd, offset, whence);
699
case IO_HANDLE_64: return ioh->r_h_lseek_64(ioh->handle, offset, whence);
700
#endif
701
}
702
error("Serious breakage - bad IO type in LFS wrapper!");
703
return -1;
704
}
705
706
// Defining a wrapper to the native read to be sure the prototype matches.
707
// There are platforms where it is read(int, void*, unsigned int).
708
// We know that we read small chunks where the difference does not matter. Could
709
// apply specific hackery, use a common compat_read() (INT123_unintr_read()?) with system
710
// specifics.
711
static mpg123_ssize_t fallback_read(int fd, void *buf, size_t count)
712
{
713
#if defined(MPG123_COMPAT_MSVCRT_IO)
714
if(count > UINT_MAX)
715
{
716
errno = EOVERFLOW;
717
return -1;
718
}
719
return _read(fd, buf, (unsigned int)count);
720
#else
721
return read(fd, buf, count);
722
#endif
723
}
724
725
static off_t fallback_lseek(int fd, off_t offset, int whence)
726
{
727
#if defined(MPG123_COMPAT_MSVCRT_IO)
728
// Off_t is 32 bit and does fit into long. We know that.
729
return _lseek(fd, (long)offset, whence);
730
#else
731
return lseek(fd, offset, whence);
732
#endif
733
}
734
735
// This is assuming an internally opened file, which usually will be
736
// using 64 bit offsets. It keeps reading on on trivial interruptions.
737
// I guess any file descriptor that matches the libc should work fine.
738
static int internal_read64(void *handle, void *buf, size_t bytes, size_t *got_bytes)
739
{
740
int ret = 0;
741
if(!handle || (!buf && bytes))
742
return -1;
743
struct wrap_data* ioh = handle;
744
int fd = ioh->fd;
745
size_t got = 0;
746
errno = 0;
747
while(bytes)
748
{
749
#ifdef TIMEOUT_READ
750
if(ioh->timeout_sec)
751
{
752
fd_set fds;
753
tv.tv_sec = ioh->timeout_sec;
754
tv.tv_usec = 0;
755
FD_ZERO(&fds);
756
FD_SET(fd, &fds);
757
int sret = select(fd+1, &fds, NULL, NULL, &tv);
758
if(sret < 1)
759
{
760
return -1; // timeout means error
761
// communicate quietness flag? if(NOQUIET) error("stream timed out");
762
}
763
}
764
#endif
765
errno = 0;
766
ptrdiff_t part = fallback_read(fd, (char*)buf+got, bytes);
767
if(part > 0) // == 0 is end of file
768
{
769
SATURATE_SUB(bytes, part, 0)
770
SATURATE_ADD(got, part, SIZE_MAX)
771
} else if(errno != EINTR && errno != EAGAIN
772
#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
773
&& errno != EWOULDBLOCK
774
#endif
775
){
776
if(part < 0)
777
ret = -1;
778
break;
779
}
780
}
781
if(got_bytes)
782
*got_bytes = got;
783
return ret;
784
}
785
786
static int64_t internal_lseek64(void *handle, int64_t offset, int whence)
787
{
788
struct wrap_data* ioh = handle;
789
#ifdef LFS_LARGEFILE_64
790
return lseek64(ioh->fd, offset, whence);
791
#elif defined(MPG123_COMPAT_MSVCRT_IO_64)
792
return _lseeki64(ioh->fd, offset, whence);
793
#else
794
if(offset < OFF_MIN || offset > OFF_MAX)
795
{
796
errno = EOVERFLOW;
797
return -1;
798
}
799
return fallback_lseek(ioh->fd, (off_t)offset, whence);
800
#endif
801
}
802
803
int INT123_wrap_open(mpg123_handle *mh, void *handle, const char *path, int fd, long timeout, int quiet)
804
{
805
int force_alloc = (path || fd >= 0) ? 1 : 0;
806
struct wrap_data *ioh = wrap_get(mh, force_alloc);
807
if(ioh == NULL && force_alloc)
808
return MPG123_ERR;
809
if(!path && fd < 0)
810
{
811
if(!ioh || ioh->iotype == IO_HANDLE64)
812
{
813
mdebug("user-supplied 64 bit I/O on user-supplied handle %p", handle);
814
return LFS_WRAP_NONE;
815
}
816
if(ioh->iotype == IO_HANDLE)
817
{
818
mdebug("wrapped user handle %p", handle);
819
ioh->handle = handle;
820
if(ioh->r_h_read && ioh->r_h_lseek)
821
return mpg123_reader64(mh, wrap_read, wrap_lseek, wrap_io_cleanup);
822
return INT123_set_err(mh, MPG123_NO_READER);
823
}
824
#ifdef LFS_LARGEFILE_64
825
if(ioh->iotype == IO_HANDLE_64)
826
{
827
mdebug("wrapped 64 bit user handle %p", handle);
828
ioh->handle = handle;
829
if(ioh->r_h_read_64 && ioh->r_h_lseek_64)
830
return mpg123_reader64(mh, wrap_read, wrap_lseek, wrap_io_cleanup);
831
return INT123_set_err(mh, MPG123_NO_READER);
832
}
833
#endif
834
}
835
if(path)
836
{
837
debug("opening path (providing fd)");
838
// Open the resource and store the descriptor for closing later.
839
int flags=O_RDONLY;
840
#ifdef O_BINARY
841
flags |= O_BINARY;
842
#endif
843
#if defined(LFS_LARGEFILE_64) && defined(HAVE_O_LARGEFILE)
844
flags |= O_LARGEFILE;
845
#endif
846
errno = 0;
847
ioh->my_fd = fd = INT123_compat_open(path, flags);
848
if(fd < 0)
849
{
850
if(!quiet)
851
error2("Cannot open file %s: %s", path, INT123_strerror(errno));
852
return INT123_set_err(mh, MPG123_BAD_FILE);
853
}
854
}
855
if(fd >= 0)
856
{
857
mdebug("working with given fd %d", fd);
858
ioh->fd = fd;
859
// Prepared I/O using external callbacks.
860
if(ioh->iotype == IO_FD)
861
{
862
debug("native fd callbacks");
863
if(ioh->r_read && ioh->r_lseek)
864
return mpg123_reader64(mh, wrap_read, wrap_lseek, wrap_io_cleanup);
865
return INT123_set_err(mh, MPG123_NO_READER);
866
}
867
#ifdef LFS_LARGEFILE_64
868
if(ioh->iotype == IO_FD_64)
869
{
870
debug("64 bit fd callbacks");
871
if(ioh->r_read_64 && ioh->r_lseek_64)
872
return mpg123_reader64(mh, wrap_read, wrap_lseek, wrap_io_cleanup);
873
return INT123_set_err(mh, MPG123_NO_READER);
874
}
875
debug("internal 64 bit I/O");
876
#else
877
debug("internal 32-behind-64 bit I/O");
878
#endif
879
// Doing our own thing using the given/just-opened descriptor.
880
ioh->iotype = IO_INT_FD;
881
#ifdef TIMEOUT_READ
882
ioh->timeout_sec = (time_t)(timeout > 0 ? timeout : 0);
883
if(ioh->timeout_sec > 0)
884
{
885
mdebug("timeout reader with %ld s", timeout);
886
int flags;
887
flags = fcntl(fd, F_GETFL);
888
flags |= O_NONBLOCK;
889
fcntl(fd, F_SETFL, flags);
890
}
891
#endif
892
return mpg123_reader64(mh, internal_read64, internal_lseek64, wrap_io_cleanup);
893
}
894
return MPG123_ERR;
895
}
896
897
// So, native off_t reader replacement.
898
899
// In forced 64 bit offset mode, the only definitions of these are
900
// the _64 ones.
901
#ifdef FORCED_OFF_64
902
#define mpg123_replace_reader mpg123_replace_reader_64
903
#define mpg123_replace_reader_handle mpg123_replace_reader_handle_64
904
#endif
905
906
/* Reader replacement prepares the hidden handle storage for next mpg123_open_fd() or plain mpg123_open(). */
907
int attribute_align_arg mpg123_replace_reader(mpg123_handle *mh, mpg123_ssize_t (*r_read) (int, void *, size_t), off_t (*r_lseek)(int, off_t, int) )
908
{
909
struct wrap_data* ioh;
910
911
if(mh == NULL) return MPG123_ERR;
912
913
mpg123_close(mh);
914
ioh = wrap_get(mh, 1);
915
if(ioh == NULL) return MPG123_ERR;
916
917
/* If both callbacks are NULL, switch totally to internal I/O, else just use fallback for at most half of them. */
918
if(r_read == NULL && r_lseek == NULL)
919
{
920
ioh->iotype = IO_INT_FD;
921
ioh->fd = -1;
922
ioh->r_read = NULL;
923
ioh->r_lseek = NULL;
924
}
925
else
926
{
927
ioh->iotype = IO_FD;
928
ioh->fd = -1; /* On next mpg123_open_fd(), this gets a value. */
929
ioh->r_read = r_read != NULL ? r_read : fallback_read;
930
ioh->r_lseek = r_lseek != NULL ? r_lseek : fallback_lseek;
931
}
932
933
/* The real reader replacement will happen while opening. */
934
return MPG123_OK;
935
}
936
937
int attribute_align_arg mpg123_replace_reader_handle(mpg123_handle *mh, mpg123_ssize_t (*r_read) (void*, void *, size_t), off_t (*r_lseek)(void*, off_t, int), void (*cleanup)(void*))
938
{
939
struct wrap_data* ioh;
940
941
if(mh == NULL) return MPG123_ERR;
942
943
mpg123_close(mh);
944
ioh = wrap_get(mh, 1);
945
if(ioh == NULL) return MPG123_ERR;
946
947
ioh->iotype = IO_HANDLE;
948
ioh->handle = NULL;
949
ioh->r_h_read = r_read;
950
ioh->r_h_lseek = r_lseek;
951
ioh->h_cleanup = cleanup;
952
953
/* The real reader replacement will happen while opening. */
954
return MPG123_OK;
955
}
956
957
#if SIZEOF_OFF_T == 4
958
int attribute_align_arg mpg123_replace_reader_32(mpg123_handle *mh, mpg123_ssize_t (*r_read) (int, void *, size_t), off_t (*r_lseek)(int, off_t, int) )
959
{
960
return mpg123_replace_reader(mh, r_read, r_lseek);
961
}
962
963
int attribute_align_arg mpg123_replace_reader_handle_32(mpg123_handle *mh, mpg123_ssize_t (*r_read) (void*, void *, size_t), off_t (*r_lseek)(void*, off_t, int), void (*cleanup)(void*))
964
{
965
return mpg123_replace_reader_handle(mh, r_read, r_lseek, cleanup);
966
}
967
968
#endif
969
970
#ifdef LFS_LARGEFILE_64
971
972
int attribute_align_arg mpg123_replace_reader_64(mpg123_handle *mh, mpg123_ssize_t (*r_read) (int, void *, size_t), off64_t (*r_lseek)(int, off64_t, int) )
973
{
974
struct wrap_data* ioh;
975
976
if(mh == NULL) return MPG123_ERR;
977
978
mpg123_close(mh);
979
ioh = wrap_get(mh, 1);
980
if(ioh == NULL) return MPG123_ERR;
981
982
/* If both callbacks are NULL, switch totally to internal I/O, else just use fallback for at most half of them. */
983
if(r_read == NULL && r_lseek == NULL)
984
{
985
ioh->iotype = IO_INT_FD;
986
ioh->fd = -1;
987
ioh->r_read_64 = NULL;
988
ioh->r_lseek_64 = NULL;
989
}
990
else
991
{
992
ioh->iotype = IO_FD_64;
993
ioh->fd = -1; /* On next mpg123_open_fd(), this gets a value. */
994
ioh->r_read_64 = r_read != NULL ? r_read : fallback_read;
995
ioh->r_lseek_64 = r_lseek != NULL ? r_lseek : lseek64;
996
}
997
998
/* The real reader replacement will happen while opening. */
999
return MPG123_OK;
1000
}
1001
1002
int attribute_align_arg mpg123_replace_reader_handle_64(mpg123_handle *mh, mpg123_ssize_t (*r_read) (void*, void *, size_t), off64_t (*r_lseek)(void*, off64_t, int), void (*cleanup)(void*))
1003
{
1004
struct wrap_data* ioh;
1005
1006
if(mh == NULL) return MPG123_ERR;
1007
1008
mpg123_close(mh);
1009
ioh = wrap_get(mh, 1);
1010
if(ioh == NULL) return MPG123_ERR;
1011
1012
ioh->iotype = IO_HANDLE_64;
1013
ioh->handle = NULL;
1014
ioh->r_h_read_64 = r_read;
1015
ioh->r_h_lseek_64 = r_lseek;
1016
ioh->h_cleanup = cleanup;
1017
1018
/* The real reader replacement will happen while opening. */
1019
return MPG123_OK;
1020
}
1021
1022
#elif SIZEOF_OFF_T == 8
1023
1024
// If 64 bit off_t is enforced, libmpg123.c already defines the _64 functions.
1025
#ifndef FORCED_OFF_64
1026
int attribute_align_arg mpg123_replace_reader_64(mpg123_handle *mh, mpg123_ssize_t (*r_read) (int, void *, size_t), off_t (*r_lseek)(int, off_t, int) )
1027
{
1028
return mpg123_replace_reader(mh, r_read, r_lseek);
1029
}
1030
1031
int attribute_align_arg mpg123_replace_reader_handle_64(mpg123_handle *mh, mpg123_ssize_t (*r_read) (void*, void *, size_t), off_t (*r_lseek)(void*, off_t, int), void (*cleanup)(void*))
1032
{
1033
return mpg123_replace_reader_handle(mh, r_read, r_lseek, cleanup);
1034
}
1035
#endif
1036
1037
#endif
1038
1039