xref: /reactos/sdk/lib/3rdparty/libmpg123/lfs_wrap.c (revision 34593d93)
1 /*
2 	lfs_wrap: Crappy wrapper code for supporting crappy ambiguous large file support.
3 
4 	copyright 2010-2020 by the mpg123 project - free software under the terms of the LGPL 2.1
5 	see COPYING and AUTHORS files in distribution or http://mpg123.org
6 
7 	initially written by Thomas Orgis, thanks to Guido Draheim for consulting
8 
9 	This file contains wrappers for the case that _FILE_OFFSET_BITS (or equivalent, theoretically, depends on mpg123.h) is defined and thus certain mpg123 API calls get renamed with a suffix (p.ex. _64).
10 	The renamed calls expect large off_t arguments, and possibly return large off_t values... these wrappers here provide the same functionality with long integer arguments/values.
11 
12 	Prototypical idea: There is
13 		off_t mpg123_seek_64(mpg123_handle*, off_t, int)
14 	This code provides
15 		long mpg123_seek(mpg123_handle*, long, int)
16 
17 	This is rather simple business... wouldn't mpg123 offer replacing the I/O core with callbacks. Translating the callbacks between long and off_t world is the main reason why this file contains non-trivial code.
18 
19 	Note about file descriptors: We just assume that they are generally interchangeable between large and small file code... and that a large file descriptor will trigger errors when accessed with small file code where it may cause trouble (a really large file).
20 */
21 
22 /* It mainly needs the official API ... */
23 /* ... but also some inside access (frame struct, readers). */
24 #include "mpg123lib_intern.h"
25 /* Include the system headers _after_ the implied config.h!
26    Otherwise _FILE_OFFSET_BITS is not in effect! */
27 #include <errno.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include "compat.h"
31 #include "debug.h"
32 
33 /*
34 	Now, start off easy... translate simple API calls.
35 	I need to deal with these here:
36 perl -ne '
37 if(/^\s*MPG123_EXPORT\s+(\S+)\s+(mpg123_\S+)\((.*)\);\s*$/)
38 {
39 	$type = $1;
40 	$name = $2;
41 	$args = $3;
42 	next unless ($type =~ /off_t/ or $args =~ /off_t/);
43 	print "$name\n" unless grep {$_ eq $name}
44 		("mpg123_open", "mpg123_open_fd", "mpg123_open_handle", "mpg123_replace_reader", "mpg123_replace_reader_handle");
45 }' < mpg123.h.in
46 
47 mpg123_decode_frame
48 mpg123_framebyframe_decode
49 mpg123_framepos
50 mpg123_tell
51 mpg123_tellframe
52 mpg123_tell_stream
53 mpg123_seek
54 mpg123_feedseek
55 mpg123_seek_frame
56 mpg123_timeframe
57 mpg123_index
58 mpg123_set_index
59 mpg123_position
60 mpg123_length
61 mpg123_set_filesize
62 mpg123_decode_raw  ... that's experimental.
63 
64 Let's work on them in that order.
65 */
66 
67 /* 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. */
68 
69 /* The wrapper handle for descriptor and handle I/O. */
70 
71 /* The handle is used for nothing (0), or one of these two modes of operation: */
72 #define IO_FD 1 /* Wrapping over callbacks operation on integer file descriptor. */
73 #define IO_HANDLE 2 /* Wrapping over custom handle callbacks. */
74 
75 struct wrap_data
76 {
77 	/* Storage for small offset index table. */
78 	long *indextable;
79 	/* I/O handle stuff */
80 	int iotype; /* IO_FD or IO_HANDLE */
81 	/* Data for IO_FD. */
82 	int fd;
83 	int my_fd; /* A descriptor that the wrapper code opened itself. */
84 	/* The actual callbacks from the outside. */
85 	ssize_t (*r_read) (int, void *, size_t);
86 	long (*r_lseek)(int, long, int);
87 	/* Data for IO_HANDLE. */
88 	void* handle;
89 	ssize_t (*r_h_read)(void *, void *, size_t);
90 	long (*r_h_lseek)(void*, long, int);
91 	void (*h_cleanup)(void*);
92 };
93 
94 
95 /* Cleanup I/O part of the handle handle... but not deleting the wrapper handle itself.
96    That is stored in the frame and only deleted on mpg123_delete(). */
wrap_io_cleanup(void * handle)97 static void wrap_io_cleanup(void *handle)
98 {
99 	struct wrap_data *ioh = handle;
100 	if(ioh->iotype == IO_HANDLE)
101 	{
102 		if(ioh->h_cleanup != NULL && ioh->handle != NULL)
103 		ioh->h_cleanup(ioh->handle);
104 
105 		ioh->handle = NULL;
106 	}
107 	if(ioh->my_fd >= 0)
108 	{
109 		close(ioh->my_fd);
110 		ioh->my_fd = -1;
111 	}
112 }
113 
114 /* Really finish off the handle... freeing all memory. */
wrap_destroy(void * handle)115 static void wrap_destroy(void *handle)
116 {
117 	struct wrap_data *wh = handle;
118 	wrap_io_cleanup(handle);
119 	if(wh->indextable != NULL)
120 	free(wh->indextable);
121 
122 	free(wh);
123 }
124 
125 /* More helper code... extract the special wrapper handle, possible allocate and initialize it. */
wrap_get(mpg123_handle * mh)126 static struct wrap_data* wrap_get(mpg123_handle *mh)
127 {
128 	struct wrap_data* whd;
129 	if(mh == NULL) return NULL;
130 
131 	/* Access the private storage inside the mpg123 handle.
132 	   The real callback functions and handles are stored there. */
133 	if(mh->wrapperdata == NULL)
134 	{
135 		/* Create a new one. */
136 		mh->wrapperdata = malloc(sizeof(struct wrap_data));
137 		if(mh->wrapperdata == NULL)
138 		{
139 			mh->err = MPG123_OUT_OF_MEM;
140 			return NULL;
141 		}
142 	/* When we have wrapper data present, the callback for its proper cleanup is needed. */
143 		mh->wrapperclean = wrap_destroy;
144 
145 		whd = mh->wrapperdata;
146 		whd->indextable = NULL;
147 		whd->iotype = 0;
148 		whd->fd = -1;
149 		whd->my_fd = -1;
150 		whd->r_read = NULL;
151 		whd->r_lseek = NULL;
152 		whd->handle = NULL;
153 		whd->r_h_read = NULL;
154 		whd->r_h_lseek = NULL;
155 		whd->h_cleanup = NULL;
156 	}
157 	else whd = mh->wrapperdata;
158 
159 	return whd;
160 }
161 
162 /* After settling the data... start with some simple wrappers. */
163 
164 #undef mpg123_decode_frame
165 /* int mpg123_decode_frame(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes) */
mpg123_decode_frame(mpg123_handle * mh,long * num,unsigned char ** audio,size_t * bytes)166 int attribute_align_arg mpg123_decode_frame(mpg123_handle *mh, long *num, unsigned char **audio, size_t *bytes)
167 {
168 	off_t largenum;
169 	int err;
170 
171 	err = MPG123_LARGENAME(mpg123_decode_frame)(mh, &largenum, audio, bytes);
172 	if(err == MPG123_OK && num != NULL)
173 	{
174 		*num = largenum;
175 		if(*num != largenum)
176 		{
177 			mh->err = MPG123_LFS_OVERFLOW;
178 			err = MPG123_ERR;
179 		}
180 	}
181 	return err;
182 }
183 
184 #undef mpg123_framebyframe_decode
185 /* int mpg123_framebyframe_decode(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes); */
mpg123_framebyframe_decode(mpg123_handle * mh,long * num,unsigned char ** audio,size_t * bytes)186 int attribute_align_arg mpg123_framebyframe_decode(mpg123_handle *mh, long *num, unsigned char **audio, size_t *bytes)
187 {
188 	off_t largenum;
189 	int err;
190 
191 	err = MPG123_LARGENAME(mpg123_framebyframe_decode)(mh, &largenum, audio, bytes);
192 	if(err == MPG123_OK && num != NULL)
193 	{
194 		*num = largenum;
195 		if(*num != largenum)
196 		{
197 			mh->err = MPG123_LFS_OVERFLOW;
198 			err = MPG123_ERR;
199 		}
200 	}
201 	return err;
202 }
203 
204 #undef mpg123_framepos
205 /* off_t mpg123_framepos(mpg123_handle *mh); */
mpg123_framepos(mpg123_handle * mh)206 long attribute_align_arg mpg123_framepos(mpg123_handle *mh)
207 {
208 	long val;
209 	off_t largeval;
210 
211 	largeval = MPG123_LARGENAME(mpg123_framepos)(mh);
212 	val = largeval;
213 	if(val != largeval)
214 	{
215 		mh->err = MPG123_LFS_OVERFLOW;
216 		return MPG123_ERR;
217 	}
218 	return val;
219 }
220 
221 #undef mpg123_tell
222 /* off_t mpg123_tell(mpg123_handle *mh); */
mpg123_tell(mpg123_handle * mh)223 long attribute_align_arg mpg123_tell(mpg123_handle *mh)
224 {
225 	long val;
226 	off_t largeval;
227 
228 	largeval = MPG123_LARGENAME(mpg123_tell)(mh);
229 	val = largeval;
230 	if(val != largeval)
231 	{
232 		mh->err = MPG123_LFS_OVERFLOW;
233 		return MPG123_ERR;
234 	}
235 	return val;
236 }
237 
238 #undef mpg123_tellframe
239 /* off_t mpg123_tellframe(mpg123_handle *mh); */
mpg123_tellframe(mpg123_handle * mh)240 long attribute_align_arg mpg123_tellframe(mpg123_handle *mh)
241 {
242 	long val;
243 	off_t largeval;
244 
245 	largeval = MPG123_LARGENAME(mpg123_tellframe)(mh);
246 	val = largeval;
247 	if(val != largeval)
248 	{
249 		mh->err = MPG123_LFS_OVERFLOW;
250 		return MPG123_ERR;
251 	}
252 	return val;
253 }
254 
255 #undef mpg123_tell_stream
256 /* off_t mpg123_tell_stream(mpg123_handle *mh); */
mpg123_tell_stream(mpg123_handle * mh)257 long attribute_align_arg mpg123_tell_stream(mpg123_handle *mh)
258 {
259 	long val;
260 	off_t largeval;
261 
262 	largeval = MPG123_LARGENAME(mpg123_tell_stream)(mh);
263 	val = largeval;
264 	if(val != largeval)
265 	{
266 		mh->err = MPG123_LFS_OVERFLOW;
267 		return MPG123_ERR;
268 	}
269 	return val;
270 }
271 
272 #undef mpg123_seek
273 /* off_t mpg123_seek(mpg123_handle *mh, off_t sampleoff, int whence); */
mpg123_seek(mpg123_handle * mh,long sampleoff,int whence)274 long attribute_align_arg mpg123_seek(mpg123_handle *mh, long sampleoff, int whence)
275 {
276 	long val;
277 	off_t largeval;
278 
279 	largeval = MPG123_LARGENAME(mpg123_seek)(mh, sampleoff, whence);
280 	val = largeval;
281 	if(val != largeval)
282 	{
283 		mh->err = MPG123_LFS_OVERFLOW;
284 		return MPG123_ERR;
285 	}
286 	return val;
287 }
288 
289 #undef mpg123_feedseek
290 /* off_t mpg123_feedseek(mpg123_handle *mh, off_t sampleoff, int whence, off_t *input_offset); */
mpg123_feedseek(mpg123_handle * mh,long sampleoff,int whence,long * input_offset)291 long attribute_align_arg mpg123_feedseek(mpg123_handle *mh, long sampleoff, int whence, long *input_offset)
292 {
293 	long val;
294 	off_t largeioff;
295 	off_t largeval;
296 
297 	largeval = MPG123_LARGENAME(mpg123_feedseek)(mh, sampleoff, whence, &largeioff);
298 	/* Error/message codes are small... */
299 	if(largeval < 0) return (long)largeval;
300 
301 	val = largeval;
302 	*input_offset = largeioff;
303 	if(val != largeval || *input_offset != largeioff)
304 	{
305 		mh->err = MPG123_LFS_OVERFLOW;
306 		return MPG123_ERR;
307 	}
308 	return val;
309 }
310 
311 #undef mpg123_seek_frame
312 /* off_t mpg123_seek_frame(mpg123_handle *mh, off_t frameoff, int whence); */
mpg123_seek_frame(mpg123_handle * mh,long frameoff,int whence)313 long attribute_align_arg mpg123_seek_frame(mpg123_handle *mh, long frameoff, int whence)
314 {
315 	long val;
316 	off_t largeval;
317 
318 	largeval = MPG123_LARGENAME(mpg123_seek_frame)(mh, frameoff, whence);
319 	val = largeval;
320 	if(val != largeval)
321 	{
322 		mh->err = MPG123_LFS_OVERFLOW;
323 		return MPG123_ERR;
324 	}
325 	return val;
326 }
327 
328 #undef mpg123_timeframe
329 /* off_t mpg123_timeframe(mpg123_handle *mh, double sec); */
mpg123_timeframe(mpg123_handle * mh,double sec)330 long attribute_align_arg mpg123_timeframe(mpg123_handle *mh, double sec)
331 {
332 	long val;
333 	off_t largeval;
334 
335 	largeval = MPG123_LARGENAME(mpg123_timeframe)(mh, sec);
336 	val = largeval;
337 	if(val != largeval)
338 	{
339 		mh->err = MPG123_LFS_OVERFLOW;
340 		return MPG123_ERR;
341 	}
342 	return val;
343 }
344 
345 /* Now something less simple: Index retrieval and manipulation.
346    The index is an _array_ of off_t, which means that I need to construct a copy with translated long values. */
347 #undef mpg123_index
348 /* int mpg123_index(mpg123_handle *mh, off_t **offsets, off_t *step, size_t *fill) */
mpg123_index(mpg123_handle * mh,long ** offsets,long * step,size_t * fill)349 int attribute_align_arg mpg123_index(mpg123_handle *mh, long **offsets, long *step, size_t *fill)
350 {
351 	int err;
352 	size_t i;
353 	long smallstep;
354 	size_t thefill;
355 	off_t largestep;
356 	off_t *largeoffsets;
357 	struct wrap_data *whd;
358 
359 	whd = wrap_get(mh);
360 	if(whd == NULL) return MPG123_ERR;
361 
362 	err = MPG123_LARGENAME(mpg123_index)(mh, &largeoffsets, &largestep, &thefill);
363 	if(err != MPG123_OK) return err;
364 
365 	/* For a _very_ large file, even the step could overflow. */
366 	smallstep = largestep;
367 	if(smallstep != largestep)
368 	{
369 		mh->err = MPG123_LFS_OVERFLOW;
370 		return MPG123_ERR;
371 	}
372 	if(step != NULL) *step = smallstep;
373 
374 	/* When there are no values stored, there is no table content to take care of.
375 	   Table pointer does not matter. Mission completed. */
376 	if(thefill == 0) return MPG123_OK;
377 
378 	if(fill != NULL) *fill = thefill;
379 
380 	/* Construct a copy of the index to hand over to the small-minded client. */
381 	*offsets = safe_realloc(whd->indextable, (*fill)*sizeof(long));
382 	if(*offsets == NULL)
383 	{
384 		mh->err = MPG123_OUT_OF_MEM;
385 		return MPG123_ERR;
386 	}
387 	whd->indextable = *offsets;
388 	/* Elaborate conversion of each index value, with overflow check. */
389 	for(i=0; i<*fill; ++i)
390 	{
391 		whd->indextable[i] = largeoffsets[i];
392 		if(whd->indextable[i] != largeoffsets[i])
393 		{
394 			mh->err = MPG123_LFS_OVERFLOW;
395 			return MPG123_ERR;
396 		}
397 	}
398 	/* If we came that far... there should be a valid copy of the table now. */
399 	return MPG123_OK;
400 }
401 
402 /* The writing does basically the same than the above, just the opposite.
403    Oh, and the overflow checks are not needed -- off_t is bigger than long. */
404 #undef mpg123_set_index
405 /* int mpg123_set_index(mpg123_handle *mh, off_t *offsets, off_t step, size_t fill); */
mpg123_set_index(mpg123_handle * mh,long * offsets,long step,size_t fill)406 int attribute_align_arg mpg123_set_index(mpg123_handle *mh, long *offsets, long step, size_t fill)
407 {
408 	int err;
409 	size_t i;
410 	struct wrap_data *whd;
411 	off_t *indextmp;
412 
413 	whd = wrap_get(mh);
414 	if(whd == NULL) return MPG123_ERR;
415 
416 	/* Expensive temporary storage... for staying outside at the API layer. */
417 	indextmp = malloc(fill*sizeof(off_t));
418 	if(indextmp == NULL)
419 	{
420 		mh->err = MPG123_OUT_OF_MEM;
421 		return MPG123_ERR;
422 	}
423 
424 	if(fill > 0 && offsets == NULL)
425 	{
426 		mh->err = MPG123_BAD_INDEX_PAR;
427 		err = MPG123_ERR;
428 	}
429 	else
430 	{
431 		/* Fill the large-file copy of the provided index, then feed it to mpg123. */
432 		for(i=0; i<fill; ++i)
433 		indextmp[i] = offsets[i];
434 
435 		err = MPG123_LARGENAME(mpg123_set_index)(mh, indextmp, step, fill);
436 	}
437 	free(indextmp);
438 
439 	return err;
440 }
441 
442 /* So... breathe... a couple of simple wrappers before the big mess. */
443 #undef mpg123_position
444 /* int mpg123_position( mpg123_handle *mh, off_t frame_offset, off_t buffered_bytes, off_t *current_frame, off_t *frames_left, double *current_seconds, double *seconds_left); */
mpg123_position(mpg123_handle * mh,long frame_offset,long buffered_bytes,long * current_frame,long * frames_left,double * current_seconds,double * seconds_left)445 int attribute_align_arg mpg123_position(mpg123_handle *mh, long frame_offset, long buffered_bytes, long *current_frame, long *frames_left, double *current_seconds, double *seconds_left)
446 {
447 	off_t curframe, frameleft;
448 	long small_curframe, small_frameleft;
449 	int err;
450 
451 	err = MPG123_LARGENAME(mpg123_position)(mh, frame_offset, buffered_bytes, &curframe, &frameleft, current_seconds, seconds_left);
452 	if(err != MPG123_OK) return err;
453 
454 	small_curframe = curframe;
455 	small_frameleft = frameleft;
456 	if(small_curframe != curframe || small_frameleft != frameleft)
457 	{
458 		mh->err = MPG123_LFS_OVERFLOW;
459 		return MPG123_ERR;
460 	}
461 
462 	if(current_frame != NULL) *current_frame = small_curframe;
463 
464 	if(frames_left != NULL) *frames_left = small_frameleft;
465 
466 
467 	return MPG123_OK;
468 }
469 
470 #undef mpg123_framelength
471 /* off_t mpg123_framelength(mpg123_handle *mh); */
mpg123_framelength(mpg123_handle * mh)472 long attribute_align_arg mpg123_framelength(mpg123_handle *mh)
473 {
474 	long val;
475 	off_t largeval;
476 
477 	largeval = MPG123_LARGENAME(mpg123_framelength)(mh);
478 	val = largeval;
479 	if(val != largeval)
480 	{
481 		mh->err = MPG123_LFS_OVERFLOW;
482 		return MPG123_ERR;
483 	}
484 	return val;
485 }
486 
487 #undef mpg123_length
488 /* off_t mpg123_length(mpg123_handle *mh); */
mpg123_length(mpg123_handle * mh)489 long attribute_align_arg mpg123_length(mpg123_handle *mh)
490 {
491 	long val;
492 	off_t largeval;
493 
494 	largeval = MPG123_LARGENAME(mpg123_length)(mh);
495 	val = largeval;
496 	if(val != largeval)
497 	{
498 		mh->err = MPG123_LFS_OVERFLOW;
499 		return MPG123_ERR;
500 	}
501 	return val;
502 }
503 
504 /* The simplest wrapper of all... */
505 #undef mpg123_set_filesize
506 /* int mpg123_set_filesize(mpg123_handle *mh, off_t size); */
mpg123_set_filesize(mpg123_handle * mh,long size)507 int attribute_align_arg mpg123_set_filesize(mpg123_handle *mh, long size)
508 {
509 	return MPG123_LARGENAME(mpg123_set_filesize)(mh, size);
510 }
511 
512 
513 /* =========================================
514              THE BOUNDARY OF SANITY
515                Behold, stranger!
516    ========================================= */
517 
518 
519 /*
520 	The messy part: Replacement of I/O core (actally, this is only due to lseek()).
521 	Both descriptor and handle replaced I/O are mapped to replaced handle I/O, the handle wrapping over the actual callbacks and the actual handle/descriptor.
522 	You got multiple levels of handles and callbacks to think about. Have fun reading and comprehending.
523 */
524 
525 /* Could go into compat.h ... Windows needs that flag. */
526 #ifndef O_BINARY
527 #define O_BINARY 0
528 #endif
529 
530 /* Read callback needs nothing special. */
wrap_read(void * handle,void * buf,size_t count)531 ssize_t wrap_read(void* handle, void *buf, size_t count)
532 {
533 	struct wrap_data *ioh = handle;
534 	switch(ioh->iotype)
535 	{
536 		case IO_FD: return ioh->r_read(ioh->fd, buf, count);
537 		case IO_HANDLE: return ioh->r_h_read(ioh->handle, buf, count);
538 	}
539 	error("Serious breakage - bad IO type in LFS wrapper!");
540 	return -1;
541 }
542 
543 /* Seek callback needs protection from too big offsets. */
wrap_lseek(void * handle,off_t offset,int whence)544 off_t wrap_lseek(void *handle, off_t offset, int whence)
545 {
546 	struct wrap_data *ioh = handle;
547 	long smalloff = offset;
548 	if(smalloff == offset)
549 	{
550 		switch(ioh->iotype)
551 		{
552 			case IO_FD: return ioh->r_lseek(ioh->fd, smalloff, whence);
553 			case IO_HANDLE: return ioh->r_h_lseek(ioh->handle, smalloff, whence);
554 		}
555 		return -1;
556 	}
557 	else
558 	{
559 		errno = EOVERFLOW;
560 		return -1;
561 	}
562 }
563 
564 
565 /*
566 	Now, let's replace the API dealing with replacement I/O.
567 	Start with undefining the renames...
568 */
569 
570 #undef mpg123_replace_reader
571 #undef mpg123_replace_reader_handle
572 #undef mpg123_open
573 #undef mpg123_open_fixed
574 #undef mpg123_open_fd
575 #undef mpg123_open_handle
576 
577 
578 /* Normal reader replacement needs fallback implementations. */
fallback_read(int fd,void * buf,size_t count)579 static ssize_t fallback_read(int fd, void *buf, size_t count)
580 {
581 	return read(fd, buf, count);
582 }
583 
fallback_lseek(int fd,long offset,int whence)584 static long fallback_lseek(int fd, long offset, int whence)
585 {
586 	/* Since the offset is long int already, the returned value really should fit into a long... but whatever. */
587 	long newpos_long;
588 	off_t newpos;
589 	newpos = lseek(fd, offset, whence);
590 	newpos_long = newpos;
591 	if(newpos_long == newpos)
592 	return newpos_long;
593 	else
594 	{
595 		errno = EOVERFLOW;
596 		return -1;
597 	}
598 }
599 
600 /* Reader replacement prepares the hidden handle storage for next mpg123_open_fd() or plain mpg123_open(). */
mpg123_replace_reader(mpg123_handle * mh,ssize_t (* r_read)(int,void *,size_t),long (* r_lseek)(int,long,int))601 int attribute_align_arg mpg123_replace_reader(mpg123_handle *mh, ssize_t (*r_read) (int, void *, size_t), long (*r_lseek)(int, long, int) )
602 {
603 	struct wrap_data* ioh;
604 
605 	if(mh == NULL) return MPG123_ERR;
606 
607 	mpg123_close(mh);
608 	ioh = wrap_get(mh);
609 	if(ioh == NULL) return MPG123_ERR;
610 
611 	/* If both callbacks are NULL, switch totally to internal I/O, else just use fallback for at most half of them. */
612 	if(r_read == NULL && r_lseek == NULL)
613 	{
614 		/* Only the type is actually important to disable the code. */
615 		ioh->iotype = 0;
616 		ioh->fd = -1;
617 		ioh->r_read = NULL;
618 		ioh->r_lseek = NULL;
619 	}
620 	else
621 	{
622 		ioh->iotype = IO_FD;
623 		ioh->fd = -1; /* On next mpg123_open_fd(), this gets a value. */
624 		ioh->r_read = r_read != NULL ? r_read : fallback_read;
625 		ioh->r_lseek = r_lseek != NULL ? r_lseek : fallback_lseek;
626 	}
627 
628 	/* The real reader replacement will happen while opening. */
629 	return MPG123_OK;
630 }
631 
mpg123_replace_reader_handle(mpg123_handle * mh,ssize_t (* r_read)(void *,void *,size_t),long (* r_lseek)(void *,long,int),void (* cleanup)(void *))632 int attribute_align_arg mpg123_replace_reader_handle(mpg123_handle *mh, ssize_t (*r_read) (void*, void *, size_t), long (*r_lseek)(void*, long, int), void (*cleanup)(void*))
633 {
634 	struct wrap_data* ioh;
635 
636 	if(mh == NULL) return MPG123_ERR;
637 
638 	mpg123_close(mh);
639 	ioh = wrap_get(mh);
640 	if(ioh == NULL) return MPG123_ERR;
641 
642 	ioh->iotype = IO_HANDLE;
643 	ioh->handle = NULL;
644 	ioh->r_h_read = r_read;
645 	ioh->r_h_lseek = r_lseek;
646 	ioh->h_cleanup = cleanup;
647 
648 	/* The real reader replacement will happen while opening. */
649 	return MPG123_OK;
650 }
651 
652 /*
653 	The open routines always need to watch out for a prepared wrapper handle to use replaced normal I/O.
654 	Two cases to consider:
655 	1. Plain normal open using internal I/O.
656 	2. Client called mpg123_replace_reader() before.
657 	The second case needs hackery to activate the client I/O callbacks. For that, we create a custom I/O handle and use the guts of mpg123_open_fd() on it.
658 */
mpg123_open(mpg123_handle * mh,const char * path)659 int attribute_align_arg mpg123_open(mpg123_handle *mh, const char *path)
660 {
661 	struct wrap_data* ioh;
662 
663 	if(mh == NULL) return MPG123_ERR;
664 
665 	ioh = mh->wrapperdata;
666 	/* Mimic the use of mpg123_replace_reader() functions by lower levels...
667 	   IO_HANDLE is not valid here, though. Only IO_FD. */
668 	if(ioh != NULL && ioh->iotype == IO_FD)
669 	{
670 		int err;
671 		err = MPG123_LARGENAME(mpg123_replace_reader_handle)(mh, wrap_read, wrap_lseek, wrap_io_cleanup);
672 		if(err != MPG123_OK) return MPG123_ERR;
673 
674 		/* The above call implied mpg123_close() already */
675 		/*
676 			I really need to open the file here... to be able to use the replacer handle I/O ...
677 			my_fd is used to indicate closing of the descriptor on cleanup.
678 		*/
679 		ioh->my_fd = compat_open(path, O_RDONLY|O_BINARY);
680 		if(ioh->my_fd < 0)
681 		{
682 			if(!(mh->p.flags & MPG123_QUIET)) error2("Cannot open file %s: %s", path, strerror(errno));
683 
684 			mh->err = MPG123_BAD_FILE;
685 			return MPG123_ERR;
686 		}
687 		/* Store a copy of the descriptor where it is actually used. */
688 		ioh->fd = ioh->my_fd;
689 		/* Initiate I/O operating on my handle now. */
690 		err = open_stream_handle(mh, ioh);
691 		if(err != MPG123_OK)
692 		{
693 			wrap_io_cleanup(ioh);
694 			return MPG123_ERR;
695 		}
696 		/* All fine... */
697 		return MPG123_OK;
698 	}
699 	else return MPG123_LARGENAME(mpg123_open)(mh, path);
700 }
701 
702 // This one needs to follow the logic of the original, and wrap the actual
703 // mpg123_open() here.
mpg123_open_fixed(mpg123_handle * mh,const char * path,int channels,int encoding)704 int attribute_align_arg mpg123_open_fixed( mpg123_handle *mh, const char *path
705 ,	int channels, int encoding )
706 {
707 	int err = open_fixed_pre(mh, channels, encoding);
708 	if(err == MPG123_OK)
709 		err = mpg123_open(mh, path);
710 	if(err == MPG123_OK)
711 		err = open_fixed_post(mh, channels, encoding);
712 	return err;
713 }
714 
715 /*
716 	This is in fact very similar to the above:
717 	The open routines always need to watch out for a prepared wrapper handle to use replaced normal I/O.
718 	Two cases to consider:
719 	1. Plain normal open_fd using internal I/O.
720 	2. Client called mpg123_replace_reader() before.
721 	The second case needs hackery to activate the client I/O callbacks. For that, we create a custom I/O handle and use the guts of mpg123_open_fd() on it.
722 */
723 
mpg123_open_fd(mpg123_handle * mh,int fd)724 int attribute_align_arg mpg123_open_fd(mpg123_handle *mh, int fd)
725 {
726 	struct wrap_data* ioh;
727 
728 	if(mh == NULL) return MPG123_ERR;
729 
730 	mpg123_close(mh);
731 	ioh = mh->wrapperdata;
732 	if(ioh != NULL && ioh->iotype == IO_FD)
733 	{
734 		int err;
735 		err = MPG123_LARGENAME(mpg123_replace_reader_handle)(mh, wrap_read, wrap_lseek, wrap_io_cleanup);
736 		if(err != MPG123_OK) return MPG123_ERR;
737 
738 		/* The above call implied mpg123_close() already */
739 
740 		/* Store the real file descriptor inside the handle. */
741 		ioh->fd = fd;
742 		/* Initiate I/O operating on my handle now. */
743 		err = open_stream_handle(mh, ioh);
744 		if(err != MPG123_OK)
745 		{
746 			wrap_io_cleanup(ioh);
747 			return MPG123_ERR;
748 		}
749 		/* All fine... */
750 		return MPG123_OK;
751 	}
752 	else return MPG123_LARGENAME(mpg123_open_fd)(mh, fd);
753 }
754 
mpg123_open_handle(mpg123_handle * mh,void * handle)755 int attribute_align_arg mpg123_open_handle(mpg123_handle *mh, void *handle)
756 {
757 	struct wrap_data* ioh;
758 
759 	if(mh == NULL) return MPG123_ERR;
760 
761 	mpg123_close(mh);
762 	ioh = mh->wrapperdata;
763 	if(ioh != NULL && ioh->iotype == IO_HANDLE && ioh->r_h_read != NULL)
764 	{
765 		/* Wrap the custom handle into my handle. */
766 		int err;
767 		err = MPG123_LARGENAME(mpg123_replace_reader_handle)(mh, wrap_read, wrap_lseek, wrap_io_cleanup);
768 		if(err != MPG123_OK) return MPG123_ERR;
769 
770 		ioh->handle = handle;
771 		/* No extra error handling, keep behaviour of the original open_handle. */
772 		return open_stream_handle(mh, ioh);
773 	}
774 	else
775 	{
776 		/* This is an error ... you need to prepare the I/O before using it. */
777 		mh->err = MPG123_BAD_CUSTOM_IO;
778 		return MPG123_ERR;
779 	}
780 }
781 
782