Subversion Repositories Kolibri OS

Rev

Rev 1905 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1905 serge 1
/* TODO: Check all read calls (in loops, especially!) for return value 0 (EOF)! */
2
 
3
/*
4
	readers.c: reading input data
5
 
6
	copyright ?-2008 by the mpg123 project - free software under the terms of the LGPL 2.1
7
	see COPYING and AUTHORS files in distribution or http://mpg123.org
8
	initially written by Michael Hipp
9
*/
10
 
11
#include "mpg123lib_intern.h"
12
#include 
13
#include 
14
#include 
3960 Serge 15
/* For select(), I need select.h according to POSIX 2001, else: sys/time.h sys/types.h unistd.h (the latter two included in compat.h already). */
1905 serge 16
#ifdef HAVE_SYS_SELECT_H
17
#include 
18
#endif
19
#ifdef HAVE_SYS_TIME_H
20
#include 
21
#endif
22
#ifdef _MSC_VER
23
#include 
24
#endif
25
 
3960 Serge 26
#include "compat.h"
1905 serge 27
#include "debug.h"
28
 
29
static int default_init(mpg123_handle *fr);
30
static off_t get_fileinfo(mpg123_handle *);
31
static ssize_t posix_read(int fd, void *buf, size_t count){ return read(fd, buf, count); }
32
static off_t   posix_lseek(int fd, off_t offset, int whence){ return lseek(fd, offset, whence); }
3960 Serge 33
static off_t     nix_lseek(int fd, off_t offset, int whence){ return -1; }
1905 serge 34
 
35
static ssize_t plain_fullread(mpg123_handle *fr,unsigned char *buf, ssize_t count);
36
 
3960 Serge 37
/* Wrapper to decide between descriptor-based and external handle-based I/O. */
38
static off_t io_seek(struct reader_data *rdat, off_t offset, int whence);
39
static ssize_t io_read(struct reader_data *rdat, void *buf, size_t count);
40
 
1905 serge 41
#ifndef NO_FEEDER
42
/* Bufferchain methods. */
43
static void bc_init(struct bufferchain *bc);
44
static void bc_reset(struct bufferchain *bc);
45
static int bc_append(struct bufferchain *bc, ssize_t size);
46
#if 0
47
static void bc_drop(struct bufferchain *bc);
48
#endif
49
static int bc_add(struct bufferchain *bc, const unsigned char *data, ssize_t size);
50
static ssize_t bc_give(struct bufferchain *bc, unsigned char *out, ssize_t size);
51
static ssize_t bc_skip(struct bufferchain *bc, ssize_t count);
52
static ssize_t bc_seekback(struct bufferchain *bc, ssize_t count);
53
static void bc_forget(struct bufferchain *bc);
54
#endif
55
 
56
/* A normal read and a read with timeout. */
57
static ssize_t plain_read(mpg123_handle *fr, void *buf, size_t count)
58
{
3960 Serge 59
	ssize_t ret = io_read(&fr->rdat, buf, count);
1905 serge 60
	if(VERBOSE3) debug2("read %li bytes of %li", (long)ret, (long)count);
61
	return ret;
62
}
63
 
3960 Serge 64
#ifdef TIMEOUT_READ
65
 
66
/* Wait for data becoming available, allowing soft-broken network connection to die
67
   This is needed for Shoutcast servers that have forgotten about us while connection was temporarily down. */
68
static ssize_t timeout_read(mpg123_handle *fr, void *buf, size_t count)
69
{
70
	struct timeval tv;
71
	ssize_t ret = 0;
72
	fd_set fds;
73
	tv.tv_sec = fr->rdat.timeout_sec;
74
	tv.tv_usec = 0;
75
	FD_ZERO(&fds);
76
	FD_SET(fr->rdat.filept, &fds);
77
	ret = select(fr->rdat.filept+1, &fds, NULL, NULL, &tv);
78
	/* This works only with "my" read function. Not user-replaced. */
79
	if(ret > 0) ret = read(fr->rdat.filept, buf, count);
80
	else
81
	{
82
		ret=-1; /* no activity is the error */
83
		if(NOQUIET) error("stream timed out");
84
	}
85
	return ret;
86
}
87
#endif
88
 
1905 serge 89
#ifndef NO_ICY
90
/* stream based operation  with icy meta data*/
91
static ssize_t icy_fullread(mpg123_handle *fr, unsigned char *buf, ssize_t count)
92
{
93
	ssize_t ret,cnt;
94
	cnt = 0;
95
	if(fr->rdat.flags & READER_SEEKABLE)
96
	{
97
		if(NOQUIET) error("mpg123 programmer error: I don't do ICY on seekable streams.");
98
		return -1;
99
	}
100
	/*
101
		There used to be a check for expected file end here (length value or ID3 flag).
102
		This is not needed:
103
		1. EOF is indicated by fdread returning zero bytes anyway.
104
		2. We get false positives of EOF for either files that grew or
105
		3. ... files that have ID3v1 tags in between (stream with intro).
106
	*/
107
 
108
	while(cnt < count)
109
	{
110
		/* all icy code is inside this if block, everything else is the plain fullread we know */
111
		/* debug1("read: %li left", (long) count-cnt); */
112
		if(fr->icy.next < count-cnt)
113
		{
114
			unsigned char temp_buff;
115
			size_t meta_size;
116
			ssize_t cut_pos;
117
 
118
			/* we are near icy-metaint boundary, read up to the boundary */
119
			if(fr->icy.next > 0)
120
			{
121
				cut_pos = fr->icy.next;
3960 Serge 122
				ret = fr->rdat.fdread(fr,buf+cnt,cut_pos);
1905 serge 123
				if(ret < 1)
124
				{
125
					if(ret == 0) break; /* Just EOF. */
126
					if(NOQUIET) error("icy boundary read");
127
 
128
					return READER_ERROR;
129
				}
3960 Serge 130
 
131
				if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret;
1905 serge 132
				cnt += ret;
133
				fr->icy.next -= ret;
134
				if(fr->icy.next > 0)
135
				{
136
					debug1("another try... still %li left", (long)fr->icy.next);
137
					continue;
138
				}
139
			}
140
			/* now off to read icy data */
141
 
142
			/* one byte icy-meta size (must be multiplied by 16 to get icy-meta length) */
3960 Serge 143
 
1905 serge 144
			ret = fr->rdat.fdread(fr,&temp_buff,1); /* Getting one single byte hast to suceed. */
145
			if(ret < 0){ if(NOQUIET) error("reading icy size"); return READER_ERROR; }
146
			if(ret == 0) break;
147
 
148
			debug2("got meta-size byte: %u, at filepos %li", temp_buff, (long)fr->rdat.filepos );
149
			if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret; /* 1... */
150
 
151
			if((meta_size = ((size_t) temp_buff) * 16))
152
			{
153
				/* we have got some metadata */
154
				char *meta_buff;
3960 Serge 155
				/* TODO: Get rid of this malloc ... perhaps hooking into the reader buffer pool? */
1905 serge 156
				meta_buff = malloc(meta_size+1);
157
				if(meta_buff != NULL)
158
				{
159
					ssize_t left = meta_size;
160
					while(left > 0)
161
					{
162
						ret = fr->rdat.fdread(fr,meta_buff+meta_size-left,left);
163
						/* 0 is error here, too... there _must_ be the ICY data, the server promised! */
164
						if(ret < 1){ if(NOQUIET) error("reading icy-meta"); return READER_ERROR; }
165
						left -= ret;
166
					}
167
					meta_buff[meta_size] = 0; /* string paranoia */
168
					if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret;
169
 
170
					if(fr->icy.data) free(fr->icy.data);
171
					fr->icy.data = meta_buff;
172
					fr->metaflags |= MPG123_NEW_ICY;
173
					debug2("icy-meta: %s size: %d bytes", fr->icy.data, (int)meta_size);
174
				}
175
				else
176
				{
177
					if(NOQUIET) error1("cannot allocate memory for meta_buff (%lu bytes) ... trying to skip the metadata!", (unsigned long)meta_size);
178
					fr->rd->skip_bytes(fr, meta_size);
179
				}
180
			}
181
			fr->icy.next = fr->icy.interval;
182
		}
3960 Serge 183
		else
184
		{
185
			ret = plain_fullread(fr, buf+cnt, count-cnt);
186
			if(ret < 0){ if(NOQUIET) error1("reading the rest of %li", (long)(count-cnt)); return READER_ERROR; }
187
			if(ret == 0) break;
1905 serge 188
 
3960 Serge 189
			cnt += ret;
190
			fr->icy.next -= ret;
191
		}
1905 serge 192
	}
193
	/* debug1("done reading, got %li", (long)cnt); */
194
	return cnt;
195
}
196
#else
197
#define icy_fullread NULL
198
#endif /* NO_ICY */
199
 
200
/* stream based operation */
201
static ssize_t plain_fullread(mpg123_handle *fr,unsigned char *buf, ssize_t count)
202
{
203
	ssize_t ret,cnt=0;
204
 
3960 Serge 205
#ifdef EXTRA_DEBUG
206
	debug1("plain fullread of %"SSIZE_P, (size_p)count);
207
#endif
1905 serge 208
	/*
209
		There used to be a check for expected file end here (length value or ID3 flag).
210
		This is not needed:
211
		1. EOF is indicated by fdread returning zero bytes anyway.
212
		2. We get false positives of EOF for either files that grew or
213
		3. ... files that have ID3v1 tags in between (stream with intro).
214
	*/
215
	while(cnt < count)
216
	{
217
		ret = fr->rdat.fdread(fr,buf+cnt,count-cnt);
218
		if(ret < 0) return READER_ERROR;
219
		if(ret == 0) break;
220
		if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret;
221
		cnt += ret;
222
	}
223
	return cnt;
224
}
225
 
226
static off_t stream_lseek(mpg123_handle *fr, off_t pos, int whence)
227
{
228
	off_t ret;
3960 Serge 229
	ret = io_seek(&fr->rdat, pos, whence);
1905 serge 230
	if (ret >= 0)	fr->rdat.filepos = ret;
231
	else
232
	{
233
		fr->err = MPG123_LSEEK_FAILED;
234
		ret = READER_ERROR; /* not the original value */
235
	}
236
	return ret;
237
}
238
 
239
static void stream_close(mpg123_handle *fr)
240
{
3960 Serge 241
	if(fr->rdat.flags & READER_FD_OPENED) compat_close(fr->rdat.filept);
242
 
243
	fr->rdat.filept = 0;
244
 
245
#ifndef NO_FEEDER
1905 serge 246
	if(fr->rdat.flags & READER_BUFFERED)  bc_reset(&fr->rdat.buffer);
3960 Serge 247
#endif
248
	if(fr->rdat.flags & READER_HANDLEIO)
249
	{
250
		if(fr->rdat.cleanup_handle != NULL) fr->rdat.cleanup_handle(fr->rdat.iohandle);
251
 
252
		fr->rdat.iohandle = NULL;
253
	}
1905 serge 254
}
255
 
256
static int stream_seek_frame(mpg123_handle *fr, off_t newframe)
257
{
258
	debug2("seek_frame to %"OFF_P" (from %"OFF_P")", (off_p)newframe, (off_p)fr->num);
259
	/* Seekable streams can go backwards and jump forwards.
260
	   Non-seekable streams still can go forward, just not jump. */
261
	if((fr->rdat.flags & READER_SEEKABLE) || (newframe >= fr->num))
262
	{
263
		off_t preframe; /* a leading frame we jump to */
264
		off_t seek_to;  /* the byte offset we want to reach */
265
		off_t to_skip;  /* bytes to skip to get there (can be negative) */
266
		/*
267
			now seek to nearest leading index position and read from there until newframe is reached.
268
			We use skip_bytes, which handles seekable and non-seekable streams
269
			(the latter only for positive offset, which we ensured before entering here).
270
		*/
271
		seek_to = frame_index_find(fr, newframe, &preframe);
272
		/* No need to seek to index position if we are closer already.
273
		   But I am picky about fr->num == newframe, play safe by reading the frame again.
274
		   If you think that's stupid, don't call a seek to the current frame. */
275
		if(fr->num >= newframe || fr->num < preframe)
276
		{
277
			to_skip = seek_to - fr->rd->tell(fr);
278
			if(fr->rd->skip_bytes(fr, to_skip) != seek_to)
279
			return READER_ERROR;
280
 
281
			debug2("going to %lu; just got %lu", (long unsigned)newframe, (long unsigned)preframe);
282
			fr->num = preframe-1; /* Watch out! I am going to read preframe... fr->num should indicate the frame before! */
283
		}
284
		while(fr->num < newframe)
285
		{
286
			/* try to be non-fatal now... frameNum only gets advanced on success anyway */
287
			if(!read_frame(fr)) break;
288
		}
289
		/* Now the wanted frame should be ready for decoding. */
290
		debug1("arrived at %lu", (long unsigned)fr->num);
291
 
292
		return MPG123_OK;
293
	}
294
	else
295
	{
296
		fr->err = MPG123_NO_SEEK;
297
		return READER_ERROR; /* invalid, no seek happened */
298
	}
299
}
300
 
301
/* return FALSE on error, TRUE on success, READER_MORE on occasion */
302
static int generic_head_read(mpg123_handle *fr,unsigned long *newhead)
303
{
304
	unsigned char hbuf[4];
305
	int ret = fr->rd->fullread(fr,hbuf,4);
306
	if(ret == READER_MORE) return ret;
307
	if(ret != 4) return FALSE;
308
 
309
	*newhead = ((unsigned long) hbuf[0] << 24) |
310
	           ((unsigned long) hbuf[1] << 16) |
311
	           ((unsigned long) hbuf[2] << 8)  |
312
	            (unsigned long) hbuf[3];
313
 
314
	return TRUE;
315
}
316
 
317
/* return FALSE on error, TRUE on success, READER_MORE on occasion */
318
static int generic_head_shift(mpg123_handle *fr,unsigned long *head)
319
{
320
	unsigned char hbuf;
321
	int ret = fr->rd->fullread(fr,&hbuf,1);
322
	if(ret == READER_MORE) return ret;
323
	if(ret != 1) return FALSE;
324
 
325
	*head <<= 8;
326
	*head |= hbuf;
327
	*head &= 0xffffffff;
328
	return TRUE;
329
}
330
 
331
/* returns reached position... negative ones are bad... */
332
static off_t stream_skip_bytes(mpg123_handle *fr,off_t len)
333
{
334
	if(fr->rdat.flags & READER_SEEKABLE)
335
	{
336
		off_t ret = stream_lseek(fr, len, SEEK_CUR);
337
		return (ret < 0) ? READER_ERROR : ret;
338
	}
339
	else if(len >= 0)
340
	{
341
		unsigned char buf[1024]; /* ThOr: Compaq cxx complained and it makes sense to me... or should one do a cast? What for? */
342
		ssize_t ret;
343
		while (len > 0)
344
		{
345
			ssize_t num = len < (off_t)sizeof(buf) ? (ssize_t)len : (ssize_t)sizeof(buf);
346
			ret = fr->rd->fullread(fr, buf, num);
347
			if (ret < 0) return ret;
348
			else if(ret == 0) break; /* EOF... an error? interface defined to tell the actual position... */
349
			len -= ret;
350
		}
351
		return fr->rd->tell(fr);
352
	}
3960 Serge 353
#ifndef NO_FEEDER
1905 serge 354
	else if(fr->rdat.flags & READER_BUFFERED)
355
	{ /* Perhaps we _can_ go a bit back. */
356
		if(fr->rdat.buffer.pos >= -len)
357
		{
358
			fr->rdat.buffer.pos += len;
359
			return fr->rd->tell(fr);
360
		}
361
		else
362
		{
363
			fr->err = MPG123_NO_SEEK;
364
			return READER_ERROR;
365
		}
366
	}
3960 Serge 367
#endif
1905 serge 368
	else
369
	{
370
		fr->err = MPG123_NO_SEEK;
371
		return READER_ERROR;
372
	}
373
}
374
 
375
/* Return 0 on success... */
376
static int stream_back_bytes(mpg123_handle *fr, off_t bytes)
377
{
378
	off_t want = fr->rd->tell(fr)-bytes;
379
	if(want < 0) return READER_ERROR;
380
	if(stream_skip_bytes(fr,-bytes) != want) return READER_ERROR;
381
 
382
	return 0;
383
}
384
 
385
 
386
/* returns size on success... */
387
static int generic_read_frame_body(mpg123_handle *fr,unsigned char *buf, int size)
388
{
389
	long l;
390
 
391
	if((l=fr->rd->fullread(fr,buf,size)) != size)
392
	{
393
		long ll = l;
394
		if(ll <= 0) ll = 0;
3960 Serge 395
		return READER_MORE;
1905 serge 396
	}
397
	return l;
398
}
399
 
400
static off_t generic_tell(mpg123_handle *fr)
401
{
3960 Serge 402
#ifndef NO_FEEDER
1905 serge 403
	if(fr->rdat.flags & READER_BUFFERED)
404
	fr->rdat.filepos = fr->rdat.buffer.fileoff+fr->rdat.buffer.pos;
3960 Serge 405
#endif
1905 serge 406
 
407
	return fr->rdat.filepos;
408
}
409
 
410
/* This does not (fully) work for non-seekable streams... You have to check for that flag, pal! */
411
static void stream_rewind(mpg123_handle *fr)
412
{
413
	if(fr->rdat.flags & READER_SEEKABLE)
3960 Serge 414
	{
415
		fr->rdat.filepos = stream_lseek(fr,0,SEEK_SET);
416
#ifndef NO_FEEDER
417
		fr->rdat.buffer.fileoff = fr->rdat.filepos;
418
#endif
419
	}
420
#ifndef NO_FEEDER
1905 serge 421
	if(fr->rdat.flags & READER_BUFFERED)
422
	{
423
		fr->rdat.buffer.pos      = 0;
424
		fr->rdat.buffer.firstpos = 0;
425
		fr->rdat.filepos = fr->rdat.buffer.fileoff;
426
	}
3960 Serge 427
#endif
1905 serge 428
}
429
 
430
/*
431
 * returns length of a file (if filept points to a file)
432
 * reads the last 128 bytes information into buffer
433
 * ... that is not totally safe...
434
 */
435
static off_t get_fileinfo(mpg123_handle *fr)
436
{
437
	off_t len;
438
 
3960 Serge 439
	if((len=io_seek(&fr->rdat,0,SEEK_END)) < 0)	return -1;
1905 serge 440
 
3960 Serge 441
	if(io_seek(&fr->rdat,-128,SEEK_END) < 0) return -1;
1905 serge 442
 
443
	if(fr->rd->fullread(fr,(unsigned char *)fr->id3buf,128) != 128)	return -1;
444
 
445
	if(!strncmp((char*)fr->id3buf,"TAG",3))	len -= 128;
446
 
3960 Serge 447
	if(io_seek(&fr->rdat,0,SEEK_SET) < 0)	return -1;
1905 serge 448
 
449
	if(len <= 0)	return -1;
450
 
451
	return len;
452
}
453
 
454
#ifndef NO_FEEDER
455
/* Methods for the buffer chain, mainly used for feed reader, but not just that. */
456
 
3960 Serge 457
 
458
static struct buffy* buffy_new(size_t size, size_t minsize)
459
{
460
	struct buffy *newbuf;
461
	newbuf = malloc(sizeof(struct buffy));
462
	if(newbuf == NULL) return NULL;
463
 
464
	newbuf->realsize = size > minsize ? size : minsize;
465
	newbuf->data = malloc(newbuf->realsize);
466
	if(newbuf->data == NULL)
467
	{
468
		free(newbuf);
469
		return NULL;
470
	}
471
	newbuf->size = 0;
472
	newbuf->next = NULL;
473
	return newbuf;
474
}
475
 
476
static void buffy_del(struct buffy* buf)
477
{
478
	if(buf)
479
	{
480
		free(buf->data);
481
		free(buf);
482
	}
483
}
484
 
485
/* Delete this buffy and all following buffies. */
486
static void buffy_del_chain(struct buffy* buf)
487
{
488
	while(buf)
489
	{
490
		struct buffy* next = buf->next;
491
		buffy_del(buf);
492
		buf = next;
493
	}
494
}
495
 
496
void bc_prepare(struct bufferchain *bc, size_t pool_size, size_t bufblock)
497
{
498
	bc_poolsize(bc, pool_size, bufblock);
499
	bc->pool = NULL;
500
	bc->pool_fill = 0;
501
	bc_init(bc); /* Ensure that members are zeroed for read-only use. */
502
}
503
 
504
size_t bc_fill(struct bufferchain *bc)
505
{
506
	return (size_t)(bc->size - bc->pos);
507
}
508
 
509
void bc_poolsize(struct bufferchain *bc, size_t pool_size, size_t bufblock)
510
{
511
	bc->pool_size = pool_size;
512
	bc->bufblock = bufblock;
513
}
514
 
515
void bc_cleanup(struct bufferchain *bc)
516
{
517
	buffy_del_chain(bc->pool);
518
	bc->pool = NULL;
519
	bc->pool_fill = 0;
520
}
521
 
522
/* Fetch a buffer from the pool (if possible) or create one. */
523
static struct buffy* bc_alloc(struct bufferchain *bc, size_t size)
524
{
525
	/* Easy route: Just try the first available buffer.
526
	   Size does not matter, it's only a hint for creation of new buffers. */
527
	if(bc->pool)
528
	{
529
		struct buffy *buf = bc->pool;
530
		bc->pool = buf->next;
531
		buf->next = NULL; /* That shall be set to a sensible value later. */
532
		buf->size = 0;
533
		--bc->pool_fill;
534
		debug2("bc_alloc: picked %p from pool (fill now %"SIZE_P")", (void*)buf, (size_p)bc->pool_fill);
535
		return buf;
536
	}
537
	else return buffy_new(size, bc->bufblock);
538
}
539
 
540
/* Either stuff the buffer back into the pool or free it for good. */
541
static void bc_free(struct bufferchain *bc, struct buffy* buf)
542
{
543
	if(!buf) return;
544
 
545
	if(bc->pool_fill < bc->pool_size)
546
	{
547
		buf->next = bc->pool;
548
		bc->pool = buf;
549
		++bc->pool_fill;
550
	}
551
	else buffy_del(buf);
552
}
553
 
554
/* Make the buffer count in the pool match the pool size. */
555
static int bc_fill_pool(struct bufferchain *bc)
556
{
557
	/* Remove superfluous ones. */
558
	while(bc->pool_fill > bc->pool_size)
559
	{
560
		/* Lazyness: Just work on the front. */
561
		struct buffy* buf = bc->pool;
562
		bc->pool = buf->next;
563
		buffy_del(buf);
564
		--bc->pool_fill;
565
	}
566
 
567
	/* Add missing ones. */
568
	while(bc->pool_fill < bc->pool_size)
569
	{
570
		/* Again, just work on the front. */
571
		struct buffy* buf;
572
		buf = buffy_new(0, bc->bufblock); /* Use default block size. */
573
		if(!buf) return -1;
574
 
575
		buf->next = bc->pool;
576
		bc->pool = buf;
577
		++bc->pool_fill;
578
	}
579
 
580
	return 0;
581
}
582
 
583
 
1905 serge 584
static void bc_init(struct bufferchain *bc)
585
{
586
	bc->first = NULL;
587
	bc->last  = bc->first;
588
	bc->size  = 0;
589
	bc->pos   = 0;
590
	bc->firstpos = 0;
591
	bc->fileoff  = 0;
592
}
593
 
594
static void bc_reset(struct bufferchain *bc)
595
{
3960 Serge 596
	/* Free current chain, possibly stuffing back into the pool. */
597
	while(bc->first)
1905 serge 598
	{
3960 Serge 599
		struct buffy* buf = bc->first;
600
		bc->first = buf->next;
601
		bc_free(bc, buf);
1905 serge 602
	}
3960 Serge 603
	bc_fill_pool(bc); /* Ignoring an error here... */
1905 serge 604
	bc_init(bc);
605
}
606
 
607
/* Create a new buffy at the end to be filled. */
608
static int bc_append(struct bufferchain *bc, ssize_t size)
609
{
610
	struct buffy *newbuf;
611
	if(size < 1) return -1;
612
 
3960 Serge 613
	newbuf = bc_alloc(bc, size);
1905 serge 614
	if(newbuf == NULL) return -2;
615
 
616
	if(bc->last != NULL)  bc->last->next = newbuf;
617
	else if(bc->first == NULL) bc->first = newbuf;
618
 
619
	bc->last  = newbuf;
3960 Serge 620
	debug3("bc_append: new last buffer %p with %"SSIZE_P" B (really %"SSIZE_P")", (void*)bc->last, (ssize_p)bc->last->size, (ssize_p)bc->last->realsize);
1905 serge 621
	return 0;
622
}
623
 
624
/* Append a new buffer and copy content to it. */
625
static int bc_add(struct bufferchain *bc, const unsigned char *data, ssize_t size)
626
{
627
	int ret = 0;
3960 Serge 628
	ssize_t part = 0;
629
	debug2("bc_add: adding %"SSIZE_P" bytes at %"OFF_P, (ssize_p)size, (off_p)(bc->fileoff+bc->size));
630
	if(size >=4) debug4("first bytes: %02x %02x %02x %02x", data[0], data[1], data[2], data[3]);
1905 serge 631
 
3960 Serge 632
	while(size > 0)
633
	{
634
		/* Try to fill up the last buffer block. */
635
		if(bc->last != NULL && bc->last->size < bc->last->realsize)
636
		{
637
			part = bc->last->realsize - bc->last->size;
638
			if(part > size) part = size;
639
 
640
			debug2("bc_add: adding %"SSIZE_P" B to existing block %p", (ssize_p)part, (void*)bc->last);
641
			memcpy(bc->last->data+bc->last->size, data, part);
642
			bc->last->size += part;
643
			size -= part;
644
			bc->size += part;
645
			data += part;
646
		}
647
 
648
		/* If there is still data left, put it into a new buffer block. */
649
		if(size > 0 && (ret = bc_append(bc, size)) != 0)
650
		break;
651
	}
652
 
1905 serge 653
	return ret;
654
}
655
 
3960 Serge 656
/* Common handler for "You want more than I can give." situation. */
657
static ssize_t bc_need_more(struct bufferchain *bc)
658
{
659
	debug3("hit end, back to beginning (%li - %li < %li)", (long)bc->size, (long)bc->pos, (long)bc->size);
660
	/* go back to firstpos, undo the previous reads */
661
	bc->pos = bc->firstpos;
662
	return READER_MORE;
663
}
664
 
1905 serge 665
/* Give some data, advancing position but not forgetting yet. */
666
static ssize_t bc_give(struct bufferchain *bc, unsigned char *out, ssize_t size)
667
{
668
	struct buffy *b = bc->first;
669
	ssize_t gotcount = 0;
670
	ssize_t offset = 0;
3960 Serge 671
	if(bc->size - bc->pos < size) return bc_need_more(bc);
672
 
1905 serge 673
	/* find the current buffer */
674
	while(b != NULL && (offset + b->size) <= bc->pos)
675
	{
676
		offset += b->size;
677
		b = b->next;
678
	}
679
	/* now start copying from there */
680
	while(gotcount < size && (b != NULL))
681
	{
682
		ssize_t loff = bc->pos - offset;
683
		ssize_t chunk = size - gotcount; /* amount of bytes to get from here... */
684
		if(chunk > b->size - loff) chunk = b->size - loff;
685
 
686
#ifdef EXTRA_DEBUG
3960 Serge 687
		debug3("copying %liB from %p+%li",(long)chunk, b->data, (long)loff);
1905 serge 688
#endif
689
 
690
		memcpy(out+gotcount, b->data+loff, chunk);
691
		gotcount += chunk;
692
		bc->pos  += chunk;
693
		offset += b->size;
694
		b = b->next;
695
	}
696
#ifdef EXTRA_DEBUG
697
	debug2("got %li bytes, pos advanced to %li", (long)gotcount, (long)bc->pos);
698
#endif
699
 
700
	return gotcount;
701
}
702
 
703
/* Skip some bytes and return the new position.
704
   The buffers are still there, just the read pointer is moved! */
705
static ssize_t bc_skip(struct bufferchain *bc, ssize_t count)
706
{
707
	if(count >= 0)
708
	{
3960 Serge 709
		if(bc->size - bc->pos < count) return bc_need_more(bc);
1905 serge 710
		else return bc->pos += count;
711
	}
712
	else return READER_ERROR;
713
}
714
 
715
static ssize_t bc_seekback(struct bufferchain *bc, ssize_t count)
716
{
717
	if(count >= 0 && count <= bc->pos) return bc->pos -= count;
718
	else return READER_ERROR;
719
}
720
 
721
/* Throw away buffies that we passed. */
722
static void bc_forget(struct bufferchain *bc)
723
{
724
	struct buffy *b = bc->first;
725
	/* free all buffers that are def'n'tly outdated */
726
	/* we have buffers until filepos... delete all buffers fully below it */
727
	if(b) debug2("bc_forget: block %lu pos %lu", (unsigned long)b->size, (unsigned long)bc->pos);
728
	else debug("forget with nothing there!");
3960 Serge 729
 
1905 serge 730
	while(b != NULL && bc->pos >= b->size)
731
	{
732
		struct buffy *n = b->next; /* != NULL or this is indeed the end and the last cycle anyway */
733
		if(n == NULL) bc->last = NULL; /* Going to delete the last buffy... */
734
		bc->fileoff += b->size;
735
		bc->pos  -= b->size;
736
		bc->size -= b->size;
3960 Serge 737
 
1905 serge 738
		debug5("bc_forget: forgot %p with %lu, pos=%li, size=%li, fileoff=%li", (void*)b->data, (long)b->size, (long)bc->pos,  (long)bc->size, (long)bc->fileoff);
3960 Serge 739
 
740
		bc_free(bc, b);
1905 serge 741
		b = n;
742
	}
743
	bc->first = b;
744
	bc->firstpos = bc->pos;
745
}
746
 
747
/* reader for input via manually provided buffers */
748
 
749
static int feed_init(mpg123_handle *fr)
750
{
751
	bc_init(&fr->rdat.buffer);
3960 Serge 752
	bc_fill_pool(&fr->rdat.buffer);
1905 serge 753
	fr->rdat.filelen = 0;
754
	fr->rdat.filepos = 0;
755
	fr->rdat.flags |= READER_BUFFERED;
756
	return 0;
757
}
758
 
759
/* externally called function, returns 0 on success, -1 on error */
760
int feed_more(mpg123_handle *fr, const unsigned char *in, long count)
761
{
762
	int ret = 0;
763
	if(VERBOSE3) debug("feed_more");
764
	if((ret = bc_add(&fr->rdat.buffer, in, count)) != 0)
765
	{
766
		ret = READER_ERROR;
767
		if(NOQUIET) error1("Failed to add buffer, return: %i", ret);
768
	}
769
	else /* Not talking about filelen... that stays at 0. */
770
 
771
	if(VERBOSE3) debug3("feed_more: %p %luB bufsize=%lu", fr->rdat.buffer.last->data,
772
		(unsigned long)fr->rdat.buffer.last->size, (unsigned long)fr->rdat.buffer.size);
773
	return ret;
774
}
775
 
776
static ssize_t feed_read(mpg123_handle *fr, unsigned char *out, ssize_t count)
777
{
778
	ssize_t gotcount = bc_give(&fr->rdat.buffer, out, count);
779
	if(gotcount >= 0 && gotcount != count) return READER_ERROR;
780
	else return gotcount;
781
}
782
 
783
/* returns reached position... negative ones are bad... */
784
static off_t feed_skip_bytes(mpg123_handle *fr,off_t len)
785
{
3960 Serge 786
	/* This is either the new buffer offset or some negative error value. */
787
	off_t res = bc_skip(&fr->rdat.buffer, (ssize_t)len);
788
	if(res < 0) return res;
789
 
790
	return fr->rdat.buffer.fileoff+res;
1905 serge 791
}
792
 
793
static int feed_back_bytes(mpg123_handle *fr, off_t bytes)
794
{
795
	if(bytes >=0)
796
	return bc_seekback(&fr->rdat.buffer, (ssize_t)bytes) >= 0 ? 0 : READER_ERROR;
797
	else
798
	return feed_skip_bytes(fr, -bytes) >= 0 ? 0 : READER_ERROR;
799
}
800
 
801
static int feed_seek_frame(mpg123_handle *fr, off_t num){ return READER_ERROR; }
802
 
803
/* Not just for feed reader, also for self-feeding buffered reader. */
804
static void buffered_forget(mpg123_handle *fr)
805
{
806
	bc_forget(&fr->rdat.buffer);
807
	fr->rdat.filepos = fr->rdat.buffer.fileoff + fr->rdat.buffer.pos;
808
}
809
 
810
off_t feed_set_pos(mpg123_handle *fr, off_t pos)
811
{
812
	struct bufferchain *bc = &fr->rdat.buffer;
813
	if(pos >= bc->fileoff && pos-bc->fileoff < bc->size)
814
	{ /* We have the position! */
815
		bc->pos = (ssize_t)(pos - bc->fileoff);
3960 Serge 816
		debug1("feed_set_pos inside, next feed from %"OFF_P, (off_p)(bc->fileoff+bc->size));
817
		return bc->fileoff+bc->size; /* Next input after end of buffer... */
1905 serge 818
	}
819
	else
820
	{ /* I expect to get the specific position on next feed. Forget what I have now. */
821
		bc_reset(bc);
822
		bc->fileoff = pos;
3960 Serge 823
		debug1("feed_set_pos outside, buffer reset, next feed from %"OFF_P, (off_p)pos);
1905 serge 824
		return pos; /* Next input from exactly that position. */
825
	}
826
}
827
 
828
/* The specific stuff for buffered stream reader. */
829
 
830
static ssize_t buffered_fullread(mpg123_handle *fr, unsigned char *out, ssize_t count)
831
{
832
	struct bufferchain *bc = &fr->rdat.buffer;
833
	ssize_t gotcount;
834
	if(bc->size - bc->pos < count)
835
	{ /* Add more stuff to buffer. If hitting end of file, adjust count. */
3960 Serge 836
		unsigned char readbuf[4096];
1905 serge 837
		ssize_t need = count - (bc->size-bc->pos);
838
		while(need>0)
839
		{
840
			int ret;
3960 Serge 841
			ssize_t got = fr->rdat.fullread(fr, readbuf, sizeof(readbuf));
1905 serge 842
			if(got < 0)
843
			{
844
				if(NOQUIET) error("buffer reading");
845
				return READER_ERROR;
846
			}
847
 
848
			if(VERBOSE3) debug1("buffered_fullread: buffering %li bytes from stream (if > 0)", (long)got);
849
			if(got > 0 && (ret=bc_add(bc, readbuf, got)) != 0)
850
			{
851
				if(NOQUIET) error1("unable to add to chain, return: %i", ret);
852
				return READER_ERROR;
853
			}
854
 
855
			need -= got; /* May underflow here... */
3960 Serge 856
			if(got < sizeof(readbuf)) /* That naturally catches got == 0, too. */
1905 serge 857
			{
858
				if(VERBOSE3) fprintf(stderr, "Note: Input data end.\n");
859
				break; /* End. */
860
			}
861
		}
862
		if(bc->size - bc->pos < count)
863
		count = bc->size - bc->pos; /* We want only what we got. */
864
	}
865
	gotcount = bc_give(bc, out, count);
866
 
867
	if(VERBOSE3) debug2("wanted %li, got %li", (long)count, (long)gotcount);
868
 
869
	if(gotcount != count){ if(NOQUIET) error("gotcount != count"); return READER_ERROR; }
870
	else return gotcount;
871
}
872
#else
873
int feed_more(mpg123_handle *fr, const unsigned char *in, long count)
874
{
875
	fr->err = MPG123_MISSING_FEATURE;
876
	return -1;
877
}
878
off_t feed_set_pos(mpg123_handle *fr, off_t pos)
879
{
880
	fr->err = MPG123_MISSING_FEATURE;
881
	return -1;
882
}
883
#endif /* NO_FEEDER */
884
 
885
/*****************************************************************
886
 * read frame helper
887
 */
888
 
889
#define bugger_off { mh->err = MPG123_NO_READER; return MPG123_ERR; }
3960 Serge 890
static int bad_init(mpg123_handle *mh) bugger_off
891
static void bad_close(mpg123_handle *mh){}
892
static ssize_t bad_fullread(mpg123_handle *mh, unsigned char *data, ssize_t count) bugger_off
893
static int bad_head_read(mpg123_handle *mh, unsigned long *newhead) bugger_off
894
static int bad_head_shift(mpg123_handle *mh, unsigned long *head) bugger_off
895
static off_t bad_skip_bytes(mpg123_handle *mh, off_t len) bugger_off
896
static int bad_read_frame_body(mpg123_handle *mh, unsigned char *data, int size) bugger_off
897
static int bad_back_bytes(mpg123_handle *mh, off_t bytes) bugger_off
898
static int bad_seek_frame(mpg123_handle *mh, off_t num) bugger_off
899
static off_t bad_tell(mpg123_handle *mh) bugger_off
900
static void bad_rewind(mpg123_handle *mh){}
1905 serge 901
#undef bugger_off
902
 
903
#define READER_STREAM 0
904
#define READER_ICY_STREAM 1
905
#define READER_FEED       2
906
#define READER_BUF_STREAM 3
907
#define READER_BUF_ICY_STREAM 4
3960 Serge 908
static struct reader readers[] =
1905 serge 909
{
910
	{ /* READER_STREAM */
911
		default_init,
912
		stream_close,
913
		plain_fullread,
914
		generic_head_read,
915
		generic_head_shift,
916
		stream_skip_bytes,
917
		generic_read_frame_body,
918
		stream_back_bytes,
919
		stream_seek_frame,
920
		generic_tell,
921
		stream_rewind,
922
		NULL
923
	} ,
924
	{ /* READER_ICY_STREAM */
925
		default_init,
926
		stream_close,
927
		icy_fullread,
928
		generic_head_read,
929
		generic_head_shift,
930
		stream_skip_bytes,
931
		generic_read_frame_body,
932
		stream_back_bytes,
933
		stream_seek_frame,
934
		generic_tell,
935
		stream_rewind,
936
		NULL
937
	},
938
#ifdef NO_FEEDER
939
#define feed_init NULL
940
#define feed_read NULL
941
#define buffered_fullread NULL
942
#define feed_seek_frame NULL
943
#define feed_back_bytes NULL
944
#define feed_skip_bytes NULL
945
#define buffered_forget NULL
946
#endif
947
	{ /* READER_FEED */
948
		feed_init,
949
		stream_close,
950
		feed_read,
951
		generic_head_read,
952
		generic_head_shift,
953
		feed_skip_bytes,
954
		generic_read_frame_body,
955
		feed_back_bytes,
956
		feed_seek_frame,
957
		generic_tell,
958
		stream_rewind,
959
		buffered_forget
960
	},
961
	{ /* READER_BUF_STREAM */
962
		default_init,
963
		stream_close,
964
		buffered_fullread,
965
		generic_head_read,
966
		generic_head_shift,
967
		stream_skip_bytes,
968
		generic_read_frame_body,
969
		stream_back_bytes,
970
		stream_seek_frame,
971
		generic_tell,
972
		stream_rewind,
973
		buffered_forget
974
	} ,
975
	{ /* READER_BUF_ICY_STREAM */
976
		default_init,
977
		stream_close,
978
		buffered_fullread,
979
		generic_head_read,
980
		generic_head_shift,
981
		stream_skip_bytes,
982
		generic_read_frame_body,
983
		stream_back_bytes,
984
		stream_seek_frame,
985
		generic_tell,
986
		stream_rewind,
987
		buffered_forget
988
	},
989
#ifdef READ_SYSTEM
990
	,{
991
		system_init,
992
		NULL,	/* filled in by system_init() */
993
		fullread,
994
		NULL,
995
		NULL,
996
		NULL,
997
		NULL,
998
		NULL,
999
		NULL,
1000
		NULL,
1001
		NULL,
1002
		NULL,
1003
	}
1004
#endif
1005
};
1006
 
3960 Serge 1007
static struct reader bad_reader =
1905 serge 1008
{
1009
	bad_init,
1010
	bad_close,
1011
	bad_fullread,
1012
	bad_head_read,
1013
	bad_head_shift,
1014
	bad_skip_bytes,
1015
	bad_read_frame_body,
1016
	bad_back_bytes,
1017
	bad_seek_frame,
1018
	bad_tell,
1019
	bad_rewind,
1020
	NULL
1021
};
1022
 
1023
static int default_init(mpg123_handle *fr)
1024
{
3960 Serge 1025
#ifdef TIMEOUT_READ
1026
	if(fr->p.timeout > 0)
1027
	{
1028
		int flags;
1029
		if(fr->rdat.r_read != NULL)
1030
		{
1031
			error("Timeout reading does not work with user-provided read function. Implement it yourself!");
1032
			return -1;
1033
		}
1034
		flags = fcntl(fr->rdat.filept, F_GETFL);
1035
		flags |= O_NONBLOCK;
1036
		fcntl(fr->rdat.filept, F_SETFL, flags);
1037
		fr->rdat.fdread = timeout_read;
1038
		fr->rdat.timeout_sec = fr->p.timeout;
1039
		fr->rdat.flags |= READER_NONBLOCK;
1040
	}
1041
	else
1042
#endif
1043
	fr->rdat.fdread = plain_read;
1905 serge 1044
 
1045
	fr->rdat.read  = fr->rdat.r_read  != NULL ? fr->rdat.r_read  : posix_read;
1046
	fr->rdat.lseek = fr->rdat.r_lseek != NULL ? fr->rdat.r_lseek : posix_lseek;
3960 Serge 1047
#ifndef NO_ICY
1048
	/* ICY streams of any sort shall not be seekable. */
1049
	if(fr->p.icy_interval > 0) fr->rdat.lseek = nix_lseek;
1050
#endif
1051
 
1905 serge 1052
	fr->rdat.filelen = get_fileinfo(fr);
1053
	fr->rdat.filepos = 0;
3960 Serge 1054
	/*
1055
		Don't enable seeking on ICY streams, just plain normal files.
1056
		This check is necessary since the client can enforce ICY parsing on files that would otherwise be seekable.
1057
		It is a task for the future to make the ICY parsing safe with seeks ... or not.
1058
	*/
1905 serge 1059
	if(fr->rdat.filelen >= 0)
1060
	{
1061
		fr->rdat.flags |= READER_SEEKABLE;
1062
		if(!strncmp((char*)fr->id3buf,"TAG",3))
1063
		{
1064
			fr->rdat.flags |= READER_ID3TAG;
1065
			fr->metaflags  |= MPG123_NEW_ID3;
1066
		}
1067
	}
1068
	/* Switch reader to a buffered one, if allowed. */
1069
	else if(fr->p.flags & MPG123_SEEKBUFFER)
1070
	{
1071
#ifdef NO_FEEDER
1072
		error("Buffered readers not supported in this build.");
1073
		fr->err = MPG123_MISSING_FEATURE;
1074
		return -1;
1075
#else
1076
		if     (fr->rd == &readers[READER_STREAM])
1077
		{
1078
			fr->rd = &readers[READER_BUF_STREAM];
1079
			fr->rdat.fullread = plain_fullread;
1080
		}
1081
#ifndef NO_ICY
1082
		else if(fr->rd == &readers[READER_ICY_STREAM])
1083
		{
1084
			fr->rd = &readers[READER_BUF_ICY_STREAM];
1085
			fr->rdat.fullread = icy_fullread;
1086
		}
1087
#endif
1088
		else
1089
		{
1090
			if(NOQUIET) error("mpg123 Programmer's fault: invalid reader");
1091
			return -1;
1092
		}
1093
		bc_init(&fr->rdat.buffer);
1094
		fr->rdat.filelen = 0; /* We carry the offset, but never know how big the stream is. */
1095
		fr->rdat.flags |= READER_BUFFERED;
1096
#endif /* NO_FEEDER */
1097
	}
1098
	return 0;
1099
}
1100
 
1101
 
1102
void open_bad(mpg123_handle *mh)
1103
{
3960 Serge 1104
	debug("open_bad");
1905 serge 1105
#ifndef NO_ICY
1106
	clear_icy(&mh->icy);
1107
#endif
1108
	mh->rd = &bad_reader;
1109
	mh->rdat.flags = 0;
3960 Serge 1110
#ifndef NO_FEEDER
1905 serge 1111
	bc_init(&mh->rdat.buffer);
3960 Serge 1112
#endif
1113
	mh->rdat.filelen = -1;
1905 serge 1114
}
1115
 
1116
int open_feed(mpg123_handle *fr)
1117
{
1118
	debug("feed reader");
1119
#ifdef NO_FEEDER
1120
	error("Buffered readers not supported in this build.");
1121
	fr->err = MPG123_MISSING_FEATURE;
1122
	return -1;
1123
#else
1124
#ifndef NO_ICY
1125
	if(fr->p.icy_interval > 0)
1126
	{
1127
		if(NOQUIET) error("Feed reader cannot do ICY parsing!");
1128
 
1129
		return -1;
1130
	}
1131
	clear_icy(&fr->icy);
1132
#endif
1133
	fr->rd = &readers[READER_FEED];
1134
	fr->rdat.flags = 0;
1135
	if(fr->rd->init(fr) < 0) return -1;
3960 Serge 1136
 
1137
	debug("feed reader init successful");
1905 serge 1138
	return 0;
1139
#endif /* NO_FEEDER */
1140
}
1141
 
3960 Serge 1142
/* Final code common to open_stream and open_stream_handle. */
1143
static int open_finish(mpg123_handle *fr)
1144
{
1145
#ifndef NO_ICY
1146
	if(fr->p.icy_interval > 0)
1147
	{
1148
		debug("ICY reader");
1149
		fr->icy.interval = fr->p.icy_interval;
1150
		fr->icy.next = fr->icy.interval;
1151
		fr->rd = &readers[READER_ICY_STREAM];
1152
	}
1153
	else
1154
#endif
1155
	{
1156
		fr->rd = &readers[READER_STREAM];
1157
		debug("stream reader");
1158
	}
1159
 
1160
	if(fr->rd->init(fr) < 0) return -1;
1161
 
1162
	return MPG123_OK;
1163
}
1164
 
1905 serge 1165
int open_stream(mpg123_handle *fr, const char *bs_filenam, int fd)
1166
{
1167
	int filept_opened = 1;
1168
	int filept; /* descriptor of opened file/stream */
1169
 
1170
	clear_icy(&fr->icy); /* can be done inside frame_clear ...? */
3960 Serge 1171
 
1905 serge 1172
	if(!bs_filenam) /* no file to open, got a descriptor (stdin) */
1173
	{
1174
		filept = fd;
1175
		filept_opened = 0; /* and don't try to close it... */
1176
	}
1177
	#ifndef O_BINARY
1178
	#define O_BINARY (0)
1179
	#endif
3960 Serge 1180
	else if((filept = compat_open(bs_filenam, O_RDONLY|O_BINARY)) < 0) /* a plain old file to open... */
1905 serge 1181
	{
1182
		if(NOQUIET) error2("Cannot open file %s: %s", bs_filenam, strerror(errno));
1183
		fr->err = MPG123_BAD_FILE;
1184
		return MPG123_ERR; /* error... */
1185
	}
1186
 
1187
	/* now we have something behind filept and can init the reader */
1188
	fr->rdat.filelen = -1;
1189
	fr->rdat.filept  = filept;
1190
	fr->rdat.flags = 0;
1191
	if(filept_opened)	fr->rdat.flags |= READER_FD_OPENED;
1192
 
3960 Serge 1193
	return open_finish(fr);
1194
}
1195
 
1196
int open_stream_handle(mpg123_handle *fr, void *iohandle)
1197
{
1198
	clear_icy(&fr->icy); /* can be done inside frame_clear ...? */
1199
	fr->rdat.filelen = -1;
1200
	fr->rdat.filept  = -1;
1201
	fr->rdat.iohandle = iohandle;
1202
	fr->rdat.flags = 0;
1203
	fr->rdat.flags |= READER_HANDLEIO;
1204
 
1205
	return open_finish(fr);
1206
}
1207
 
1208
/* Wrappers for actual reading/seeking... I'm full of wrappers here. */
1209
static off_t io_seek(struct reader_data *rdat, off_t offset, int whence)
1210
{
1211
	if(rdat->flags & READER_HANDLEIO)
1905 serge 1212
	{
3960 Serge 1213
		if(rdat->r_lseek_handle != NULL)
1214
		{
1215
			return rdat->r_lseek_handle(rdat->iohandle, offset, whence);
1216
		}
1217
		else return -1;
1905 serge 1218
	}
1219
	else
3960 Serge 1220
	return rdat->lseek(rdat->filept, offset, whence);
1221
}
1222
 
1223
static ssize_t io_read(struct reader_data *rdat, void *buf, size_t count)
1224
{
1225
	if(rdat->flags & READER_HANDLEIO)
1905 serge 1226
	{
3960 Serge 1227
		if(rdat->r_read_handle != NULL)
1228
		{
1229
			return rdat->r_read_handle(rdat->iohandle, buf, count);
1230
		}
1231
		else return -1;
1905 serge 1232
	}
3960 Serge 1233
	else
1234
	return rdat->read(rdat->filept, buf, count);
1905 serge 1235
}