Commit message: src/ : Move to a variable length header buffer

Previously, the `psf->header` buffer was a fixed length specified by
`SF_HEADER_LEN` which was set to `12292`. This was problematic for
two reasons; this value was un-necessarily large for the majority
of files and too small for some others.

Now the size of the header buffer starts at 256 bytes and grows as
necessary up to a maximum of 100k.
CVE: CVE-2017-7586
CWE: CWE-119
Vulnerability description: In libsndfile before 1.0.28, an error in the "header_read()" function (common.c) when handling ID3 tags can be exploited to cause a stack-based buffer overflow via a specially crafted FLAC file.

Project: libsndfile
File: common.c

 header_gets (SF_PRIVATE *psf, char *ptr, int bufsize)
 {	int		k ;
 
	if (psf->header.indx + bufsize >= psf->header.len && psf_bump_header_allocation (psf, bufsize))
		return 0 ;

 	for (k = 0 ; k < bufsize - 1 ; k++)
	{	if (psf->header.indx < psf->header.end)
		{	ptr [k] = psf->header.ptr [psf->header.indx] ;
			psf->header.indx ++ ;
 			}
 		else
		{	psf->header.end += psf_fread (psf->header.ptr + psf->header.end, 1, 1, psf) ;
			ptr [k] = psf->header.ptr [psf->header.indx] ;
			psf->header.indx = psf->header.end ;
 			} ;
 
 		if (ptr [k] == '\n')
			break ;
		} ;

	ptr [k] = 0 ;

	return k ;
} /* header_gets */

Project: libsndfile
File: common.c

 header_put_be_3byte (SF_PRIVATE *psf, int x)
{	psf->header.ptr [psf->header.indx++] = (x >> 16) ;
	psf->header.ptr [psf->header.indx++] = (x >> 8) ;
	psf->header.ptr [psf->header.indx++] = x ;
 } /* header_put_be_3byte */

Project: libsndfile

header_put_be_8byte (SF_PRIVATE *psf, sf_count_t x)

Project: libsndfile
File: common.c

 header_put_be_8byte (SF_PRIVATE *psf, sf_count_t x)
{	psf->header.ptr [psf->header.indx++] = (x >> 56) ;
	psf->header.ptr [psf->header.indx++] = (x >> 48) ;
	psf->header.ptr [psf->header.indx++] = (x >> 40) ;
	psf->header.ptr [psf->header.indx++] = (x >> 32) ;
	psf->header.ptr [psf->header.indx++] = (x >> 24) ;
	psf->header.ptr [psf->header.indx++] = (x >> 16) ;
	psf->header.ptr [psf->header.indx++] = (x >> 8) ;
	psf->header.ptr [psf->header.indx++] = x ;
 } /* header_put_be_8byte */

Project: libsndfile
File: common.c

 header_put_be_int (SF_PRIVATE *psf, int x)
{	psf->header.ptr [psf->header.indx++] = (x >> 24) ;
	psf->header.ptr [psf->header.indx++] = (x >> 16) ;
	psf->header.ptr [psf->header.indx++] = (x >> 8) ;
	psf->header.ptr [psf->header.indx++] = x ;
 } /* header_put_be_int */

Project: libsndfile
File: common.c

 header_put_byte (SF_PRIVATE *psf, char x)
{	psf->header.ptr [psf->header.indx++] = x ;
 } /* header_put_byte */

Project: libsndfile

header_put_le_8byte (SF_PRIVATE *psf, sf_count_t x)

Project: libsndfile
File: common.c

 header_put_le_8byte (SF_PRIVATE *psf, sf_count_t x)
{	psf->header.ptr [psf->header.indx++] = x ;
	psf->header.ptr [psf->header.indx++] = (x >> 8) ;
	psf->header.ptr [psf->header.indx++] = (x >> 16) ;
	psf->header.ptr [psf->header.indx++] = (x >> 24) ;
	psf->header.ptr [psf->header.indx++] = (x >> 32) ;
	psf->header.ptr [psf->header.indx++] = (x >> 40) ;
	psf->header.ptr [psf->header.indx++] = (x >> 48) ;
	psf->header.ptr [psf->header.indx++] = (x >> 56) ;
 } /* header_put_le_8byte */

Project: libsndfile
File: common.c

 header_put_le_short (SF_PRIVATE *psf, int x)
{	psf->header.ptr [psf->header.indx++] = x ;
	psf->header.ptr [psf->header.indx++] = (x >> 8) ;
 } /* header_put_le_short */

Project: libsndfile
File: common.c

 header_put_marker (SF_PRIVATE *psf, int x)
{	psf->header.ptr [psf->header.indx++] = x ;
	psf->header.ptr [psf->header.indx++] = (x >> 8) ;
	psf->header.ptr [psf->header.indx++] = (x >> 16) ;
	psf->header.ptr [psf->header.indx++] = (x >> 24) ;
 } /* header_put_marker */

Project: libsndfile
File: common.c

 header_read (SF_PRIVATE *psf, void *ptr, int bytes)
 {	int count = 0 ;
 
	if (psf->header.indx + bytes >= psf->header.len && psf_bump_header_allocation (psf, bytes))
		return count ;
 
	if (psf->header.indx + bytes > psf->header.end)
	{	count = psf_fread (psf->header.ptr + psf->header.end, 1, bytes - (psf->header.end - psf->header.indx), psf) ;
		if (count != bytes - (int) (psf->header.end - psf->header.indx))
 		{	psf_log_printf (psf, "Error : psf_fread returned short count.\n") ;
 			return count ;
 			} ;
		psf->header.end += count ;
 		} ;
 
	memcpy (ptr, psf->header.ptr + psf->header.indx, bytes) ;
	psf->header.indx += bytes ;
 
 	return bytes ;
 } /* header_read */

Project: libsndfile
File: common.c

header_seek (SF_PRIVATE *psf, sf_count_t position, int whence)
 {
 	switch (whence)
 	{	case SEEK_SET :
			if (psf->header.indx + position >= psf->header.len)
				psf_bump_header_allocation (psf, position) ;
			if (position > psf->header.len)
 			{	/* Too much header to cache so just seek instead. */
 				psf_fseek (psf, position, whence) ;
 				return ;
 				} ;
			if (position > psf->header.end)
				psf->header.end += psf_fread (psf->header.ptr + psf->header.end, 1, position - psf->header.end, psf) ;
			psf->header.indx = position ;
 			break ;
 
 		case SEEK_CUR :
			if (psf->header.indx + position >= psf->header.len)
				psf_bump_header_allocation (psf, position) ;

			if (psf->header.indx + position < 0)
 				break ;
 
			if (psf->header.indx >= psf->header.len)
 			{	psf_fseek (psf, position, whence) ;
 				return ;
 				} ;
 
			if (psf->header.indx + position <= psf->header.end)
			{	psf->header.indx += position ;
 				break ;
 				} ;
 
			if (psf->header.indx + position > psf->header.len)
 			{	/* Need to jump this without caching it. */
				psf->header.indx = psf->header.end ;
 				psf_fseek (psf, position, SEEK_CUR) ;
 				break ;
 				} ;
 
			psf->header.end += psf_fread (psf->header.ptr + psf->header.end, 1, position - (psf->header.end - psf->header.indx), psf) ;
			psf->header.indx = psf->header.end ;
 			break ;
 
 		case SEEK_END :
		default :
			psf_log_printf (psf, "Bad whence param in header_seek().\n") ;
			break ;
		} ;

	return ;
} /* header_seek */

Project: libsndfile
File: common.c

psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...)
{	va_list			argptr ;
	sf_count_t		*countptr, countdata ;
	unsigned char	*ucptr, sixteen_bytes [16] ;
	unsigned int 	*intptr, intdata ;
	unsigned short	*shortptr ;
	char			*charptr ;
 	float			*floatptr ;
 	double			*doubleptr ;
 	char			c ;
	int				byte_count = 0, count = 0 ;
 
 	if (! format)
 		return psf_ftell (psf) ;
 
 	va_start (argptr, format) ;
 
 	while ((c = *format++))
	{
		if (psf->header.indx + 16 >= psf->header.len && psf_bump_header_allocation (psf, 16))
			return count ;

		switch (c)
 		{	case 'e' : /* All conversions are now from LE to host. */
 					psf->rwf_endian = SF_ENDIAN_LITTLE ;
 					break ;

			case 'E' : /* All conversions are now from BE to host. */
					psf->rwf_endian = SF_ENDIAN_BIG ;
					break ;
 
 			case 'm' : /* 4 byte marker value eg 'RIFF' */
 					intptr = va_arg (argptr, unsigned int*) ;
					*intptr = 0 ;
 					ucptr = (unsigned char*) intptr ;
 					byte_count += header_read (psf, ucptr, sizeof (int)) ;
 					*intptr = GET_MARKER (ucptr) ;
 					break ;
 
 			case 'h' :
 					intptr = va_arg (argptr, unsigned int*) ;
					*intptr = 0 ;
 					ucptr = (unsigned char*) intptr ;
 					byte_count += header_read (psf, sixteen_bytes, sizeof (sixteen_bytes)) ;
 					{	int k ;
						intdata = 0 ;
						for (k = 0 ; k < 16 ; k++)
							intdata ^= sixteen_bytes [k] << k ;
						}
					*intptr = intdata ;
					break ;

			case '1' :
					charptr = va_arg (argptr, char*) ;
					*charptr = 0 ;
					byte_count += header_read (psf, charptr, sizeof (char)) ;
					break ;

			case '2' : /* 2 byte value with the current endian-ness */
					shortptr = va_arg (argptr, unsigned short*) ;
					*shortptr = 0 ;
					ucptr = (unsigned char*) shortptr ;
					byte_count += header_read (psf, ucptr, sizeof (short)) ;
					if (psf->rwf_endian == SF_ENDIAN_BIG)
						*shortptr = GET_BE_SHORT (ucptr) ;
					else
						*shortptr = GET_LE_SHORT (ucptr) ;
					break ;

			case '3' : /* 3 byte value with the current endian-ness */
					intptr = va_arg (argptr, unsigned int*) ;
					*intptr = 0 ;
					byte_count += header_read (psf, sixteen_bytes, 3) ;
					if (psf->rwf_endian == SF_ENDIAN_BIG)
						*intptr = GET_BE_3BYTE (sixteen_bytes) ;
					else
						*intptr = GET_LE_3BYTE (sixteen_bytes) ;
					break ;

			case '4' : /* 4 byte value with the current endian-ness */
					intptr = va_arg (argptr, unsigned int*) ;
					*intptr = 0 ;
					ucptr = (unsigned char*) intptr ;
					byte_count += header_read (psf, ucptr, sizeof (int)) ;
					if (psf->rwf_endian == SF_ENDIAN_BIG)
						*intptr = psf_get_be32 (ucptr, 0) ;
					else
						*intptr = psf_get_le32 (ucptr, 0) ;
					break ;

			case '8' : /* 8 byte value with the current endian-ness */
					countptr = va_arg (argptr, sf_count_t *) ;
					*countptr = 0 ;
					byte_count += header_read (psf, sixteen_bytes, 8) ;
					if (psf->rwf_endian == SF_ENDIAN_BIG)
						countdata = psf_get_be64 (sixteen_bytes, 0) ;
					else
						countdata = psf_get_le64 (sixteen_bytes, 0) ;
					*countptr = countdata ;
					break ;

			case 'f' : /* Float conversion */
					floatptr = va_arg (argptr, float *) ;
					*floatptr = 0.0 ;
					byte_count += header_read (psf, floatptr, sizeof (float)) ;
					if (psf->rwf_endian == SF_ENDIAN_BIG)
						*floatptr = float32_be_read ((unsigned char*) floatptr) ;
					else
						*floatptr = float32_le_read ((unsigned char*) floatptr) ;
					break ;

			case 'd' : /* double conversion */
					doubleptr = va_arg (argptr, double *) ;
					*doubleptr = 0.0 ;
					byte_count += header_read (psf, doubleptr, sizeof (double)) ;
					if (psf->rwf_endian == SF_ENDIAN_BIG)
						*doubleptr = double64_be_read ((unsigned char*) doubleptr) ;
					else
						*doubleptr = double64_le_read ((unsigned char*) doubleptr) ;
					break ;

			case 's' :
					psf_log_printf (psf, "Format conversion 's' not implemented yet.\n") ;
					/*
					strptr = va_arg (argptr, char *) ;
					size   = strlen (strptr) + 1 ;
 					size  += (size & 1) ;
 					longdata = H2LE_32 (size) ;
 					get_int (psf, longdata) ;
					memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size) ;
					psf->header.indx += size ;
 					*/
 					break ;
 
 			case 'b' : /* Raw bytes */
 					charptr = va_arg (argptr, char*) ;
 					count = va_arg (argptr, size_t) ;
					memset (charptr, 0, count) ;
					byte_count += header_read (psf, charptr, count) ;
 					break ;
 
 			case 'G' :
 					charptr = va_arg (argptr, char*) ;
 					count = va_arg (argptr, size_t) ;
					memset (charptr, 0, count) ;

					if (psf->header.indx + count >= psf->header.len && psf_bump_header_allocation (psf, count))
						return 0 ;

					byte_count += header_gets (psf, charptr, count) ;
 					break ;
 
 			case 'z' :
 					psf_log_printf (psf, "Format conversion 'z' not implemented yet.\n") ;
 					/*
 					size    = va_arg (argptr, size_t) ;
 					while (size)
					{	psf->header.ptr [psf->header.indx] = 0 ;
						psf->header.indx ++ ;
 						size -- ;
 						} ;
 					*/
 					break ;
 
			case 'p' :	/* Seek to position from start. */
 					count = va_arg (argptr, size_t) ;
 					header_seek (psf, count, SEEK_SET) ;
 					byte_count = count ;
 					break ;
 
			case 'j' :	/* Seek to position from current position. */
 					count = va_arg (argptr, size_t) ;
					header_seek (psf, count, SEEK_CUR) ;
					byte_count += count ;
 					break ;
 
 			default :
				psf_log_printf (psf, "*** Invalid format specifier `%c'\n", c) ;
				psf->error = SFE_INTERNAL ;
				break ;
			} ;
		} ;

	va_end (argptr) ;

	return byte_count ;
} /* psf_binheader_readf */

Project: libsndfile
File: common.c

psf_binheader_writef (SF_PRIVATE *psf, const char *format, ...)
{	va_list	argptr ;
	sf_count_t 		countdata ;
	unsigned long 	longdata ;
	unsigned int 	data ;
	float			floatdata ;
	double			doubledata ;
	void			*bindata ;
	size_t			size ;
	char			c, *strptr ;
	int				count = 0, trunc_8to4 ;

	trunc_8to4 = SF_FALSE ;

 	va_start (argptr, format) ;
 
 	while ((c = *format++))
	{
		if (psf->header.indx + 16 >= psf->header.len && psf_bump_header_allocation (psf, 16))
			return count ;

		switch (c)
 		{	case ' ' : /* Do nothing. Just used to space out format string. */
 					break ;
 
			case 'e' : /* All conversions are now from LE to host. */
					psf->rwf_endian = SF_ENDIAN_LITTLE ;
					break ;

			case 'E' : /* All conversions are now from BE to host. */
					psf->rwf_endian = SF_ENDIAN_BIG ;
					break ;

			case 't' : /* All 8 byte values now get written as 4 bytes. */
					trunc_8to4 = SF_TRUE ;
					break ;

			case 'T' : /* All 8 byte values now get written as 8 bytes. */
					trunc_8to4 = SF_FALSE ;
					break ;

			case 'm' :
					data = va_arg (argptr, unsigned int) ;
					header_put_marker (psf, data) ;
					count += 4 ;
					break ;

			case '1' :
					data = va_arg (argptr, unsigned int) ;
					header_put_byte (psf, data) ;
					count += 1 ;
					break ;

			case '2' :
					data = va_arg (argptr, unsigned int) ;
					if (psf->rwf_endian == SF_ENDIAN_BIG)
					{	header_put_be_short (psf, data) ;
						}
					else
					{	header_put_le_short (psf, data) ;
						} ;
					count += 2 ;
					break ;

			case '3' : /* tribyte */
					data = va_arg (argptr, unsigned int) ;
					if (psf->rwf_endian == SF_ENDIAN_BIG)
					{	header_put_be_3byte (psf, data) ;
						}
					else
					{	header_put_le_3byte (psf, data) ;
						} ;
					count += 3 ;
					break ;

			case '4' :
					data = va_arg (argptr, unsigned int) ;
					if (psf->rwf_endian == SF_ENDIAN_BIG)
					{	header_put_be_int (psf, data) ;
						}
					else
					{	header_put_le_int (psf, data) ;
						} ;
					count += 4 ;
					break ;

			case '8' :
					countdata = va_arg (argptr, sf_count_t) ;
					if (psf->rwf_endian == SF_ENDIAN_BIG && trunc_8to4 == SF_FALSE)
					{	header_put_be_8byte (psf, countdata) ;
						count += 8 ;
						}
					else if (psf->rwf_endian == SF_ENDIAN_LITTLE && trunc_8to4 == SF_FALSE)
					{	header_put_le_8byte (psf, countdata) ;
						count += 8 ;
						}
					else if (psf->rwf_endian == SF_ENDIAN_BIG && trunc_8to4 == SF_TRUE)
					{	longdata = countdata & 0xFFFFFFFF ;
						header_put_be_int (psf, longdata) ;
						count += 4 ;
						}
					else if (psf->rwf_endian == SF_ENDIAN_LITTLE && trunc_8to4 == SF_TRUE)
					{	longdata = countdata & 0xFFFFFFFF ;
						header_put_le_int (psf, longdata) ;
						count += 4 ;
						}
					break ;

			case 'f' :
 					/* Floats are passed as doubles. Is this always true? */
 					floatdata = (float) va_arg (argptr, double) ;
 					if (psf->rwf_endian == SF_ENDIAN_BIG)
						float32_be_write (floatdata, psf->header.ptr + psf->header.indx) ;
 					else
						float32_le_write (floatdata, psf->header.ptr + psf->header.indx) ;
					psf->header.indx += 4 ;
 					count += 4 ;
 					break ;
 
 			case 'd' :
 					doubledata = va_arg (argptr, double) ;
 					if (psf->rwf_endian == SF_ENDIAN_BIG)
						double64_be_write (doubledata, psf->header.ptr + psf->header.indx) ;
 					else
						double64_le_write (doubledata, psf->header.ptr + psf->header.indx) ;
					psf->header.indx += 8 ;
 					count += 8 ;
 					break ;
 
			case 's' :
					/* Write a C string (guaranteed to have a zero terminator). */
 					strptr = va_arg (argptr, char *) ;
 					size = strlen (strptr) + 1 ;
 					size += (size & 1) ;

					if (psf->header.indx + (sf_count_t) size >= psf->header.len && psf_bump_header_allocation (psf, 16))
						return count ;

 					if (psf->rwf_endian == SF_ENDIAN_BIG)
 						header_put_be_int (psf, size) ;
 					else
 						header_put_le_int (psf, size) ;
					memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size) ;
					psf->header.indx += size ;
					psf->header.ptr [psf->header.indx - 1] = 0 ;
 					count += 4 + size ;
 					break ;
 
			case 'S' :
					/*
					**	Write an AIFF style string (no zero terminator but possibly
					**	an extra pad byte if the string length is odd).
 					*/
 					strptr = va_arg (argptr, char *) ;
 					size = strlen (strptr) ;
					if (psf->header.indx + (sf_count_t) size > psf->header.len && psf_bump_header_allocation (psf, size))
						return count ;
 					if (psf->rwf_endian == SF_ENDIAN_BIG)
 						header_put_be_int (psf, size) ;
 					else
 						header_put_le_int (psf, size) ;
					memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size + 1) ;
 					size += (size & 1) ;
					psf->header.indx += size ;
					psf->header.ptr [psf->header.indx] = 0 ;
 					count += 4 + size ;
 					break ;
 
			case 'p' :
					/* Write a PASCAL string (as used by AIFF files).
					*/
					strptr = va_arg (argptr, char *) ;
 					size = strlen (strptr) ;
 					size = (size & 1) ? size : size + 1 ;
 					size = (size > 254) ? 254 : size ;

					if (psf->header.indx + (sf_count_t) size > psf->header.len && psf_bump_header_allocation (psf, size))
						return count ;

 					header_put_byte (psf, size) ;
					memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size) ;
					psf->header.indx += size ;
 					count += 1 + size ;
 					break ;
 
 			case 'b' :
 					bindata	= va_arg (argptr, void *) ;
 					size	= va_arg (argptr, size_t) ;

					if (psf->header.indx + (sf_count_t) size > psf->header.len && psf_bump_header_allocation (psf, size))
						return count ;

					memcpy (&(psf->header.ptr [psf->header.indx]), bindata, size) ;
					psf->header.indx += size ;
					count += size ;
 					break ;
 
 			case 'z' :
 					size = va_arg (argptr, size_t) ;

					if (psf->header.indx + (sf_count_t) size > psf->header.len && psf_bump_header_allocation (psf, size))
						return count ;

 					count += size ;
 					while (size)
					{	psf->header.ptr [psf->header.indx] = 0 ;
						psf->header.indx ++ ;
 						size -- ;
 						} ;
 					break ;
 
 			case 'h' :
 					bindata = va_arg (argptr, void *) ;
					memcpy (&(psf->header.ptr [psf->header.indx]), bindata, 16) ;
					psf->header.indx += 16 ;
 					count += 16 ;
 					break ;
 
 			case 'j' :	/* Jump forwards/backwards by specified amount. */
 					size = va_arg (argptr, size_t) ;

					if (psf->header.indx + (sf_count_t) size > psf->header.len && psf_bump_header_allocation (psf, size))
						return count ;

					psf->header.indx += size ;
 					count += size ;
 					break ;
 
 			case 'o' :	/* Jump to specified offset. */
 					size = va_arg (argptr, size_t) ;

					if ((sf_count_t) size >= psf->header.len && psf_bump_header_allocation (psf, size))
						return count ;

					psf->header.indx = size ;
 					break ;
 
 			default :
				psf_log_printf (psf, "*** Invalid format specifier `%c'\n", c) ;
				psf->error = SFE_INTERNAL ;
				break ;
			} ;
		} ;

	va_end (argptr) ;
	return count ;
} /* psf_binheader_writef */

Project: libsndfile
File: sndfile.c

psf_close (SF_PRIVATE *psf)
{	uint32_t k ;
	int	error = 0 ;

	if (psf->codec_close)
	{	error = psf->codec_close (psf) ;
		/* To prevent it being called in psf->container_close(). */
		psf->codec_close = NULL ;
		} ;

	if (psf->container_close)
		error = psf->container_close (psf) ;

	error = psf_fclose (psf) ;
 	psf_close_rsrc (psf) ;
 
 	/* For an ISO C compliant implementation it is ok to free a NULL pointer. */
	free (psf->header.ptr) ;
 	free (psf->container_data) ;
 	free (psf->codec_data) ;
 	free (psf->interleave) ;
	free (psf->dither) ;
	free (psf->peak_info) ;
	free (psf->broadcast_16k) ;
	free (psf->loop_info) ;
	free (psf->instrument) ;
	free (psf->cues) ;
	free (psf->channel_map) ;
	free (psf->format_desc) ;
	free (psf->strings.storage) ;

	if (psf->wchunks.chunks)
		for (k = 0 ; k < psf->wchunks.used ; k++)
			free (psf->wchunks.chunks [k].data) ;
	free (psf->rchunks.chunks) ;
	free (psf->wchunks.chunks) ;
	free (psf->iterator) ;
	free (psf->cart_16k) ;

	memset (psf, 0, sizeof (SF_PRIVATE)) ;
	free (psf) ;

	return error ;
} /* psf_close */

Project: libsndfile
File: sndfile.c

sf_open	(const char *path, int mode, SF_INFO *sfinfo)
{	SF_PRIVATE 	*psf ;

 	/* Ultimate sanity check. */
 	assert (sizeof (sf_count_t) == 8) ;
 
	if ((psf = psf_allocate ()) == NULL)
 	{	sf_errno = SFE_MALLOC_FAILED ;
 		return	NULL ;
 		} ;

	psf_init_files (psf) ;

	psf_log_printf (psf, "File : %s\n", path) ;

	if (copy_filename (psf, path) != 0)
	{	sf_errno = psf->error ;
		return	NULL ;
		} ;

	psf->file.mode = mode ;
	if (strcmp (path, "-") == 0)
		psf->error = psf_set_stdio (psf) ;
	else
		psf->error = psf_fopen (psf) ;

	return psf_open_file (psf, sfinfo) ;
} /* sf_open */

Project: libsndfile
File: sndfile.c

sf_open_fd	(int fd, int mode, SF_INFO *sfinfo, int close_desc)
{	SF_PRIVATE 	*psf ;

	if ((SF_CONTAINER (sfinfo->format)) == SF_FORMAT_SD2)
	{	sf_errno = SFE_SD2_FD_DISALLOWED ;
 		return	NULL ;
 		} ;
 
	if ((psf = psf_allocate ()) == NULL)
 	{	sf_errno = SFE_MALLOC_FAILED ;
 		return	NULL ;
 		} ;

	psf_init_files (psf) ;
	copy_filename (psf, "") ;

	psf->file.mode = mode ;
	psf_set_file (psf, fd) ;
	psf->is_pipe = psf_is_pipe (psf) ;
	psf->fileoffset = psf_ftell (psf) ;

	if (! close_desc)
		psf->file.do_not_close_descriptor = SF_TRUE ;

	return psf_open_file (psf, sfinfo) ;
} /* sf_open_fd */

Project: libsndfile
File: sndfile.c

sf_open_virtual	(SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user_data)
{	SF_PRIVATE 	*psf ;

	/* Make sure we have a valid set ot virtual pointers. */
	if (sfvirtual->get_filelen == NULL || sfvirtual->seek == NULL || sfvirtual->tell == NULL)
	{	sf_errno = SFE_BAD_VIRTUAL_IO ;
		snprintf (sf_parselog, sizeof (sf_parselog), "Bad vio_get_filelen / vio_seek / vio_tell in SF_VIRTUAL_IO struct.\n") ;
		return NULL ;
		} ;

	if ((mode == SFM_READ || mode == SFM_RDWR) && sfvirtual->read == NULL)
	{	sf_errno = SFE_BAD_VIRTUAL_IO ;
		snprintf (sf_parselog, sizeof (sf_parselog), "Bad vio_read in SF_VIRTUAL_IO struct.\n") ;
		return NULL ;
		} ;

	if ((mode == SFM_WRITE || mode == SFM_RDWR) && sfvirtual->write == NULL)
	{	sf_errno = SFE_BAD_VIRTUAL_IO ;
		snprintf (sf_parselog, sizeof (sf_parselog), "Bad vio_write in SF_VIRTUAL_IO struct.\n") ;
 		return NULL ;
 		} ;
 
	if ((psf = psf_allocate ()) == NULL)
 	{	sf_errno = SFE_MALLOC_FAILED ;
 		return	NULL ;
 		} ;

	psf_init_files (psf) ;

	psf->virtual_io = SF_TRUE ;
	psf->vio = *sfvirtual ;
	psf->vio_user_data = user_data ;

	psf->file.mode = mode ;

	return psf_open_file (psf, sfinfo) ;
} /* sf_open_virtual */