CVE-2017-7586: Improper Restriction of Operations within the Bounds of a Memory Buffer (CWE-119)
value: 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.
CWE description: The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.
CVSS v3 base score: 5.5
Published: 2017-04-07T20:59Z
Repository: https://github.com/erikd/libsndfile
Language: C
Files changed: src/common.c, src/common.h, src/sndfile.c
Commit date: 2016-11-27 16:17:06 +1100
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.

Diff: diff --git a/src/common.c b/src/common.c
index 25d4fecd..07fafea3 100644
--- a/src/common.c
+++ b/src/common.c
@@ -31,10 +31,53 @@
 #endif
 #include "sndfile.h"
 #include "sfendian.h"
 #include "common.h"
 
+#define	INITAL_HEADER_SIZE	256
+
+/* Allocate and initialize the SF_PRIVATE struct. */
+SF_PRIVATE *
+psf_allocate (void)
+{	SF_PRIVATE * psf ;
+
+	if ((psf = calloc (1, sizeof (SF_PRIVATE))) == NULL)
+		return	NULL ;
+
+	if ((psf->header.ptr = calloc (1, INITAL_HEADER_SIZE)) == NULL)
+	{	free (psf) ;
+		return	NULL ;
+		} ;
+	psf->header.len = INITAL_HEADER_SIZE ;
+
+	return psf ;
+} /* psf_allocate */
+
+static int
+psf_bump_header_allocation (SF_PRIVATE * psf, sf_count_t needed)
+{
+	sf_count_t newlen, smallest = INITAL_HEADER_SIZE ;
+	void * ptr ;
+
+	newlen = (needed > psf->header.len) ? 2 * SF_MAX (needed, smallest) : 2 * psf->header.len ;
+
+	if (newlen > 100 * 1024)
+	{	psf_log_printf (psf, "Request for header allocation of %D denined.\n", newlen) ;
+		return 1 ;
+		}
+
+	if ((ptr = realloc (psf->header.ptr, newlen)) == NULL)
+	{	psf_log_printf (psf, "realloc (%p, %D) failed\n", psf->header.ptr, newlen) ;
+		psf->error = SFE_MALLOC_FAILED ;
+		return 1 ;
+		} ;
+
+	psf->header.ptr = ptr ;
+	psf->header.len = newlen ;
+	return 0 ;
+} /* psf_bump_header_allocation */
+
 /*-----------------------------------------------------------------------------------------------
 ** psf_log_printf allows libsndfile internal functions to print to an internal parselog which
 ** can later be displayed.
 ** The format specifiers are as for printf but without the field width and other modifiers.
 ** Printing is performed to the parselog char array of the SF_PRIVATE struct.
@@ -334,22 +377,22 @@ void
 psf_asciiheader_printf (SF_PRIVATE *psf, const char *format, ...)
 {	va_list	argptr ;
 	int		maxlen ;
 	char	*start ;
 
-	maxlen = strlen ((char*) psf->header) ;
-	start	= ((char*) psf->header) + maxlen ;
-	maxlen	= sizeof (psf->header) - maxlen ;
+	maxlen = strlen ((char*) psf->header.ptr) ;
+	start	= ((char*) psf->header.ptr) + maxlen ;
+	maxlen	= psf->header.len - maxlen ;
 
 	va_start (argptr, format) ;
 	vsnprintf (start, maxlen, format, argptr) ;
 	va_end (argptr) ;
 
 	/* Make sure the string is properly terminated. */
 	start [maxlen - 1] = 0 ;
 
-	psf->headindex = strlen ((char*) psf->header) ;
+	psf->header.indx = strlen ((char*) psf->header.ptr) ;
 
 	return ;
 } /* psf_asciiheader_printf */
 
 /*-----------------------------------------------------------------------------------------------
@@ -398,157 +441,106 @@ psf_asciiheader_printf (SF_PRIVATE *psf, const char *format, ...)
 ** seg. fault when asked to write an int or short to a non-int/short aligned address.
 */
 
 static inline void
 header_put_byte (SF_PRIVATE *psf, char x)
-{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 1)
-		psf->header [psf->headindex++] = x ;
+{	psf->header.ptr [psf->header.indx++] = x ;
 } /* header_put_byte */
 
 #if (CPU_IS_BIG_ENDIAN == 1)
 static inline void
 header_put_marker (SF_PRIVATE *psf, int x)
-{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 4)
-	{	psf->header [psf->headindex++] = (x >> 24) ;
-		psf->header [psf->headindex++] = (x >> 16) ;
-		psf->header [psf->headindex++] = (x >> 8) ;
-		psf->header [psf->headindex++] = 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_marker */
 
 #elif (CPU_IS_LITTLE_ENDIAN == 1)
 static inline void
 header_put_marker (SF_PRIVATE *psf, int x)
-{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 4)
-	{	psf->header [psf->headindex++] = x ;
-		psf->header [psf->headindex++] = (x >> 8) ;
-		psf->header [psf->headindex++] = (x >> 16) ;
-		psf->header [psf->headindex++] = (x >> 24) ;
-		} ;
+{	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 */
 
 #else
 #	error "Cannot determine endian-ness of processor."
 #endif
 
 
 static inline void
 header_put_be_short (SF_PRIVATE *psf, int x)
-{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 2)
-	{	psf->header [psf->headindex++] = (x >> 8) ;
-		psf->header [psf->headindex++] = x ;
-		} ;
+{	psf->header.ptr [psf->header.indx++] = (x >> 8) ;
+	psf->header.ptr [psf->header.indx++] = x ;
 } /* header_put_be_short */
 
 static inline void
 header_put_le_short (SF_PRIVATE *psf, int x)
-{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 2)
-	{	psf->header [psf->headindex++] = x ;
-		psf->header [psf->headindex++] = (x >> 8) ;
-		} ;
+{	psf->header.ptr [psf->header.indx++] = x ;
+	psf->header.ptr [psf->header.indx++] = (x >> 8) ;
 } /* header_put_le_short */
 
 static inline void
 header_put_be_3byte (SF_PRIVATE *psf, int x)
-{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 3)
-	{	psf->header [psf->headindex++] = (x >> 16) ;
-		psf->header [psf->headindex++] = (x >> 8) ;
-		psf->header [psf->headindex++] = 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 */
 
 static inline void
 header_put_le_3byte (SF_PRIVATE *psf, int x)
-{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 3)
-	{	psf->header [psf->headindex++] = x ;
-		psf->header [psf->headindex++] = (x >> 8) ;
-		psf->header [psf->headindex++] = (x >> 16) ;
-		} ;
+{	psf->header.ptr [psf->header.indx++] = x ;
+	psf->header.ptr [psf->header.indx++] = (x >> 8) ;
+	psf->header.ptr [psf->header.indx++] = (x >> 16) ;
 } /* header_put_le_3byte */
 
 static inline void
 header_put_be_int (SF_PRIVATE *psf, int x)
-{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 4)
-	{	psf->header [psf->headindex++] = (x >> 24) ;
-		psf->header [psf->headindex++] = (x >> 16) ;
-		psf->header [psf->headindex++] = (x >> 8) ;
-		psf->header [psf->headindex++] = 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 */
 
 static inline void
 header_put_le_int (SF_PRIVATE *psf, int x)
-{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 4)
-	{	psf->header [psf->headindex++] = x ;
-		psf->header [psf->headindex++] = (x >> 8) ;
-		psf->header [psf->headindex++] = (x >> 16) ;
-		psf->header [psf->headindex++] = (x >> 24) ;
-		} ;
+{	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_le_int */
 
-#if (SIZEOF_SF_COUNT_T == 4)
-
-static inline void
-header_put_be_8byte (SF_PRIVATE *psf, sf_count_t x)
-{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 8)
-	{	psf->header [psf->headindex++] = 0 ;
-		psf->header [psf->headindex++] = 0 ;
-		psf->header [psf->headindex++] = 0 ;
-		psf->header [psf->headindex++] = 0 ;
-		psf->header [psf->headindex++] = (x >> 24) ;
-		psf->header [psf->headindex++] = (x >> 16) ;
-		psf->header [psf->headindex++] = (x >> 8) ;
-		psf->header [psf->headindex++] = x ;
-		} ;
-} /* header_put_be_8byte */
-
-static inline void
-header_put_le_8byte (SF_PRIVATE *psf, sf_count_t x)
-{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 8)
-	{	psf->header [psf->headindex++] = x ;
-		psf->header [psf->headindex++] = (x >> 8) ;
-		psf->header [psf->headindex++] = (x >> 16) ;
-		psf->header [psf->headindex++] = (x >> 24) ;
-		psf->header [psf->headindex++] = 0 ;
-		psf->header [psf->headindex++] = 0 ;
-		psf->header [psf->headindex++] = 0 ;
-		psf->header [psf->headindex++] = 0 ;
-		} ;
-} /* header_put_le_8byte */
-
-#elif (SIZEOF_SF_COUNT_T == 8)
+#if (SIZEOF_SF_COUNT_T == 8)
 
 static inline void
 header_put_be_8byte (SF_PRIVATE *psf, sf_count_t x)
-{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 8)
-	{	psf->header [psf->headindex++] = (x >> 56) ;
-		psf->header [psf->headindex++] = (x >> 48) ;
-		psf->header [psf->headindex++] = (x >> 40) ;
-		psf->header [psf->headindex++] = (x >> 32) ;
-		psf->header [psf->headindex++] = (x >> 24) ;
-		psf->header [psf->headindex++] = (x >> 16) ;
-		psf->header [psf->headindex++] = (x >> 8) ;
-		psf->header [psf->headindex++] = 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 */
 
 static inline void
 header_put_le_8byte (SF_PRIVATE *psf, sf_count_t x)
-{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 8)
-	{	psf->header [psf->headindex++] = x ;
-		psf->header [psf->headindex++] = (x >> 8) ;
-		psf->header [psf->headindex++] = (x >> 16) ;
-		psf->header [psf->headindex++] = (x >> 24) ;
-		psf->header [psf->headindex++] = (x >> 32) ;
-		psf->header [psf->headindex++] = (x >> 40) ;
-		psf->header [psf->headindex++] = (x >> 48) ;
-		psf->header [psf->headindex++] = (x >> 56) ;
-		} ;
+{	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 */
 
 #else
-#error "SIZEOF_SF_COUNT_T is not defined."
+#error "SIZEOF_SF_COUNT_T != 8"
 #endif
 
 int
 psf_binheader_writef (SF_PRIVATE *psf, const char *format, ...)
 {	va_list	argptr ;
@@ -565,11 +557,15 @@ psf_binheader_writef (SF_PRIVATE *psf, const char *format, ...)
 	trunc_8to4 = SF_FALSE ;
 
 	va_start (argptr, format) ;
 
 	while ((c = *format++))
-	{	switch (c)
+	{
+		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 ;
@@ -656,112 +652,133 @@ psf_binheader_writef (SF_PRIVATE *psf, const char *format, ...)
 
 			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 + psf->headindex) ;
+						float32_be_write (floatdata, psf->header.ptr + psf->header.indx) ;
 					else
-						float32_le_write (floatdata, psf->header + psf->headindex) ;
-					psf->headindex += 4 ;
+						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 + psf->headindex) ;
+						double64_be_write (doubledata, psf->header.ptr + psf->header.indx) ;
 					else
-						double64_le_write (doubledata, psf->header + psf->headindex) ;
-					psf->headindex += 8 ;
+						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 [psf->headindex]), strptr, size) ;
-					psf->headindex += size ;
-					psf->header [psf->headindex - 1] = 0 ;
+					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 [psf->headindex]), strptr, size + 1) ;
+					memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size + 1) ;
 					size += (size & 1) ;
-					psf->headindex += size ;
-					psf->header [psf->headindex] = 0 ;
+					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 [psf->headindex]), strptr, size) ;
-					psf->headindex += 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->headindex + size < sizeof (psf->header))
-					{	memcpy (&(psf->header [psf->headindex]), bindata, size) ;
-						psf->headindex += size ;
-						count += size ;
-						} ;
+
+					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 [psf->headindex] = 0 ;
-						psf->headindex ++ ;
+					{	psf->header.ptr [psf->header.indx] = 0 ;
+						psf->header.indx ++ ;
 						size -- ;
 						} ;
 					break ;
 
 			case 'h' :
 					bindata = va_arg (argptr, void *) ;
-					memcpy (&(psf->header [psf->headindex]), bindata, 16) ;
-					psf->headindex += 16 ;
+					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) ;
-					psf->headindex += size ;
+
+					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 (size < sizeof (psf->header))
-					{	psf->headindex = size ;
-						count = 0 ;
-						} ;
+
+					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 ;
@@ -822,77 +839,71 @@ psf_binheader_writef (SF_PRIVATE *psf, const char *format, ...)
 
 static int
 header_read (SF_PRIVATE *psf, void *ptr, int bytes)
 {	int count = 0 ;
 
-	if (psf->headindex >= SIGNED_SIZEOF (psf->header))
-		return psf_fread (ptr, 1, bytes, psf) ;
-
-	if (psf->headindex + bytes > SIGNED_SIZEOF (psf->header))
-	{	int most ;
+	if (psf->header.indx + bytes >= psf->header.len && psf_bump_header_allocation (psf, bytes))
+		return count ;
 
-		most = SIGNED_SIZEOF (psf->header) - psf->headend ;
-		psf_fread (psf->header + psf->headend, 1, most, psf) ;
-		memcpy (ptr, psf->header + psf->headend, most) ;
-		psf->headend = psf->headindex += most ;
-		psf_fread ((char *) ptr + most, bytes - most, 1, psf) ;
-		return bytes ;
-		} ;
-
-	if (psf->headindex + bytes > psf->headend)
-	{	count = psf_fread (psf->header + psf->headend, 1, bytes - (psf->headend - psf->headindex), psf) ;
-		if (count != bytes - (int) (psf->headend - psf->headindex))
+	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->headend += count ;
+		psf->header.end += count ;
 		} ;
 
-	memcpy (ptr, psf->header + psf->headindex, bytes) ;
-	psf->headindex += bytes ;
+	memcpy (ptr, psf->header.ptr + psf->header.indx, bytes) ;
+	psf->header.indx += bytes ;
 
 	return bytes ;
 } /* header_read */
 
 static void
 header_seek (SF_PRIVATE *psf, sf_count_t position, int whence)
 {
 	switch (whence)
 	{	case SEEK_SET :
-			if (position > SIGNED_SIZEOF (psf->header))
+			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->headend)
-				psf->headend += psf_fread (psf->header + psf->headend, 1, position - psf->headend, psf) ;
-			psf->headindex = position ;
+			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->headindex + position < 0)
+			if (psf->header.indx + position >= psf->header.len)
+				psf_bump_header_allocation (psf, position) ;
+
+			if (psf->header.indx + position < 0)
 				break ;
 
-			if (psf->headindex >= SIGNED_SIZEOF (psf->header))
+			if (psf->header.indx >= psf->header.len)
 			{	psf_fseek (psf, position, whence) ;
 				return ;
 				} ;
 
-			if (psf->headindex + position <= psf->headend)
-			{	psf->headindex += position ;
+			if (psf->header.indx + position <= psf->header.end)
+			{	psf->header.indx += position ;
 				break ;
 				} ;
 
-			if (psf->headindex + position > SIGNED_SIZEOF (psf->header))
+			if (psf->header.indx + position > psf->header.len)
 			{	/* Need to jump this without caching it. */
-				psf->headindex = psf->headend ;
+				psf->header.indx = psf->header.end ;
 				psf_fseek (psf, position, SEEK_CUR) ;
 				break ;
 				} ;
 
-			psf->headend += psf_fread (psf->header + psf->headend, 1, position - (psf->headend - psf->headindex), psf) ;
-			psf->headindex = psf->headend ;
+			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") ;
@@ -904,19 +915,22 @@ header_seek (SF_PRIVATE *psf, sf_count_t position, int whence)
 
 static int
 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->headindex < psf->headend)
-		{	ptr [k] = psf->header [psf->headindex] ;
-			psf->headindex ++ ;
+	{	if (psf->header.indx < psf->header.end)
+		{	ptr [k] = psf->header.ptr [psf->header.indx] ;
+			psf->header.indx ++ ;
 			}
 		else
-		{	psf->headend += psf_fread (psf->header + psf->headend, 1, 1, psf) ;
-			ptr [k] = psf->header [psf->headindex] ;
-			psf->headindex = psf->headend ;
+		{	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 ;
 		} ;
@@ -935,36 +949,42 @@ psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...)
 	unsigned short	*shortptr ;
 	char			*charptr ;
 	float			*floatptr ;
 	double			*doubleptr ;
 	char			c ;
-	int				byte_count = 0, count ;
+	int				byte_count = 0, count = 0 ;
 
 	if (! format)
 		return psf_ftell (psf) ;
 
 	va_start (argptr, format) ;
 
 	while ((c = *format++))
-	{	switch (c)
+	{
+		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++)
@@ -1048,55 +1068,55 @@ psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...)
 					strptr = va_arg (argptr, char *) ;
 					size   = strlen (strptr) + 1 ;
 					size  += (size & 1) ;
 					longdata = H2LE_32 (size) ;
 					get_int (psf, longdata) ;
-					memcpy (&(psf->header [psf->headindex]), strptr, size) ;
-					psf->headindex += size ;
+					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) ;
-					if (count > 0)
-						byte_count += header_read (psf, charptr, count) ;
+					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) ;
-					if (count > 0)
-						byte_count += header_gets (psf, charptr, count) ;
+					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 [psf->headindex] = 0 ;
-						psf->headindex ++ ;
+					{	psf->header.ptr [psf->header.indx] = 0 ;
+						psf->header.indx ++ ;
 						size -- ;
 						} ;
 					*/
 					break ;
 
-			case 'p' :
-					/* Get the seek position first. */
+			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' :
-					/* Get the seek position first. */
+			case 'j' :	/* Seek to position from current position. */
 					count = va_arg (argptr, size_t) ;
-					if (count)
-					{	header_seek (psf, count, SEEK_CUR) ;
-						byte_count += count ;
-						} ;
+					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 ;
diff --git a/src/common.h b/src/common.h
index dd159928..4ef4dc17 100644
--- a/src/common.h
+++ b/src/common.h
@@ -77,11 +77,10 @@
 
 #define	SF_BUFFER_LEN			(8192)
 #define	SF_FILENAME_LEN			(1024)
 #define SF_SYSERR_LEN			(256)
 #define SF_MAX_STRINGS			(32)
-#define	SF_HEADER_LEN			(12292)
 #define	SF_PARSELOG_LEN			(2048)
 
 #define	PSF_SEEK_ERROR			((sf_count_t) -1)
 
 #define	BITWIDTH2BYTES(x)	(((x) + 7) / 8)
@@ -380,11 +379,16 @@ typedef struct sf_private_tag
 	struct
 	{	char			buf	[SF_PARSELOG_LEN] ;
 		int				indx ;
 	} parselog ;
 
-	unsigned char	header		[SF_HEADER_LEN] ; /* Must be unsigned */
+
+	struct
+	{	unsigned char	* ptr ;
+		sf_count_t		indx, end, len ;
+	} header ;
+
 	int				rwf_endian ;	/* Header endian-ness flag. */
 
 	/* Storage and housekeeping data for adding/reading strings from
 	** sound files.
 	*/
@@ -399,14 +403,10 @@ typedef struct sf_private_tag
 	/* Guard value. If this changes the buffers above have overflowed. */
 	int				Magick ;
 
 	unsigned		unique_id ;
 
-	/* Index variables for maintaining parselog and header above. */
-	int				headindex, headend ;
-	int				has_text ;
-
 	int				error ;
 
 	int				endian ;		/* File endianness : SF_ENDIAN_LITTLE or SF_ENDIAN_BIG. */
 	int				data_endswap ;	/* Need to endswap data? */
 
@@ -734,10 +734,13 @@ enum
 	SFE_FILENAME_TOO_LONG,
 
 	SFE_MAX_ERROR			/* This must be last in list. */
 } ;
 
+/* Allocate and initialize the SF_PRIVATE struct. */
+SF_PRIVATE * psf_allocate (void) ;
+
 int subformat_to_bytewidth (int format) ;
 int s_bitwidth_to_subformat (int bits) ;
 int u_bitwidth_to_subformat (int bits) ;
 
 /*  Functions for reading and writing floats and doubles on processors
diff --git a/src/sndfile.c b/src/sndfile.c
index 07eb05c3..bee408f1 100644
--- a/src/sndfile.c
+++ b/src/sndfile.c
@@ -265,11 +265,11 @@ ErrorStruct SndfileErrors [] =
 	{	SFE_UNKNOWN_CHUNK		, "Error : Unknown chunk marker." },
 	{	SFE_BAD_CHUNK_FORMAT	, "Error : Reading/writing chunks from this file format is not supported." },
 	{	SFE_BAD_CHUNK_MARKER	, "Error : Bad chunk marker." },
 	{	SFE_BAD_CHUNK_DATA_PTR	, "Error : Bad data pointer in SF_CHUNK_INFO struct." },
 	{	SFE_FILENAME_TOO_LONG	, "Error : Supplied filename too long." },
-
+	{	SFE_BAD_HEADER_ALLOC 	, "Error : Required header allocation is too large." },
 
 	{	SFE_MAX_ERROR			, "Maximum error number." },
 	{	SFE_MAX_ERROR + 1		, NULL }
 } ;
 
@@ -324,11 +324,11 @@ sf_open	(const char *path, int mode, SF_INFO *sfinfo)
 {	SF_PRIVATE 	*psf ;
 
 	/* Ultimate sanity check. */
 	assert (sizeof (sf_count_t) == 8) ;
 
-	if ((psf = calloc (1, sizeof (SF_PRIVATE))) == NULL)
+	if ((psf = psf_allocate ()) == NULL)
 	{	sf_errno = SFE_MALLOC_FAILED ;
 		return	NULL ;
 		} ;
 
 	psf_init_files (psf) ;
@@ -356,11 +356,11 @@ sf_open_fd	(int fd, int mode, SF_INFO *sfinfo, int close_desc)
 	if ((SF_CONTAINER (sfinfo->format)) == SF_FORMAT_SD2)
 	{	sf_errno = SFE_SD2_FD_DISALLOWED ;
 		return	NULL ;
 		} ;
 
-	if ((psf = calloc (1, sizeof (SF_PRIVATE))) == NULL)
+	if ((psf = psf_allocate ()) == NULL)
 	{	sf_errno = SFE_MALLOC_FAILED ;
 		return	NULL ;
 		} ;
 
 	psf_init_files (psf) ;
@@ -398,11 +398,11 @@ sf_open_virtual	(SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user
 	{	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 = calloc (1, sizeof (SF_PRIVATE))) == NULL)
+	if ((psf = psf_allocate ()) == NULL)
 	{	sf_errno = SFE_MALLOC_FAILED ;
 		return	NULL ;
 		} ;
 
 	psf_init_files (psf) ;
@@ -2686,10 +2686,11 @@ psf_close (SF_PRIVATE *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) ;

Vulnerable code: 	maxlen = strlen ((char*) psf->header) ;
	start	= ((char*) psf->header) + maxlen ;
	maxlen	= sizeof (psf->header) - maxlen ;
	psf->headindex = strlen ((char*) psf->header) ;
{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 1)
		psf->header [psf->headindex++] = x ;
{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 4)
	{	psf->header [psf->headindex++] = (x >> 24) ;
		psf->header [psf->headindex++] = (x >> 16) ;
		psf->header [psf->headindex++] = (x >> 8) ;
		psf->header [psf->headindex++] = x ;
		} ;
{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 4)
	{	psf->header [psf->headindex++] = x ;
		psf->header [psf->headindex++] = (x >> 8) ;
		psf->header [psf->headindex++] = (x >> 16) ;
		psf->header [psf->headindex++] = (x >> 24) ;
		} ;
{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 2)
	{	psf->header [psf->headindex++] = (x >> 8) ;
		psf->header [psf->headindex++] = x ;
		} ;
{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 2)
	{	psf->header [psf->headindex++] = x ;
		psf->header [psf->headindex++] = (x >> 8) ;
		} ;
{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 3)
	{	psf->header [psf->headindex++] = (x >> 16) ;
		psf->header [psf->headindex++] = (x >> 8) ;
		psf->header [psf->headindex++] = x ;
		} ;
{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 3)
	{	psf->header [psf->headindex++] = x ;
		psf->header [psf->headindex++] = (x >> 8) ;
		psf->header [psf->headindex++] = (x >> 16) ;
		} ;
{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 4)
	{	psf->header [psf->headindex++] = (x >> 24) ;
		psf->header [psf->headindex++] = (x >> 16) ;
		psf->header [psf->headindex++] = (x >> 8) ;
		psf->header [psf->headindex++] = x ;
		} ;
{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 4)
	{	psf->header [psf->headindex++] = x ;
		psf->header [psf->headindex++] = (x >> 8) ;
		psf->header [psf->headindex++] = (x >> 16) ;
		psf->header [psf->headindex++] = (x >> 24) ;
		} ;
#if (SIZEOF_SF_COUNT_T == 4)

static inline void
header_put_be_8byte (SF_PRIVATE *psf, sf_count_t x)
{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 8)
	{	psf->header [psf->headindex++] = 0 ;
		psf->header [psf->headindex++] = 0 ;
		psf->header [psf->headindex++] = 0 ;
		psf->header [psf->headindex++] = 0 ;
		psf->header [psf->headindex++] = (x >> 24) ;
		psf->header [psf->headindex++] = (x >> 16) ;
		psf->header [psf->headindex++] = (x >> 8) ;
		psf->header [psf->headindex++] = x ;
		} ;
} /* header_put_be_8byte */

static inline void
header_put_le_8byte (SF_PRIVATE *psf, sf_count_t x)
{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 8)
	{	psf->header [psf->headindex++] = x ;
		psf->header [psf->headindex++] = (x >> 8) ;
		psf->header [psf->headindex++] = (x >> 16) ;
		psf->header [psf->headindex++] = (x >> 24) ;
		psf->header [psf->headindex++] = 0 ;
		psf->header [psf->headindex++] = 0 ;
		psf->header [psf->headindex++] = 0 ;
		psf->header [psf->headindex++] = 0 ;
		} ;
} /* header_put_le_8byte */

#elif (SIZEOF_SF_COUNT_T == 8)
{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 8)
	{	psf->header [psf->headindex++] = (x >> 56) ;
		psf->header [psf->headindex++] = (x >> 48) ;
		psf->header [psf->headindex++] = (x >> 40) ;
		psf->header [psf->headindex++] = (x >> 32) ;
		psf->header [psf->headindex++] = (x >> 24) ;
		psf->header [psf->headindex++] = (x >> 16) ;
		psf->header [psf->headindex++] = (x >> 8) ;
		psf->header [psf->headindex++] = x ;
		} ;
{	if (psf->headindex < SIGNED_SIZEOF (psf->header) - 8)
	{	psf->header [psf->headindex++] = x ;
		psf->header [psf->headindex++] = (x >> 8) ;
		psf->header [psf->headindex++] = (x >> 16) ;
		psf->header [psf->headindex++] = (x >> 24) ;
		psf->header [psf->headindex++] = (x >> 32) ;
		psf->header [psf->headindex++] = (x >> 40) ;
		psf->header [psf->headindex++] = (x >> 48) ;
		psf->header [psf->headindex++] = (x >> 56) ;
		} ;
#error "SIZEOF_SF_COUNT_T is not defined."
	{	switch (c)
						float32_be_write (floatdata, psf->header + psf->headindex) ;
						float32_le_write (floatdata, psf->header + psf->headindex) ;
					psf->headindex += 4 ;
						double64_be_write (doubledata, psf->header + psf->headindex) ;
						double64_le_write (doubledata, psf->header + psf->headindex) ;
					psf->headindex += 8 ;
					memcpy (&(psf->header [psf->headindex]), strptr, size) ;
					psf->headindex += size ;
					psf->header [psf->headindex - 1] = 0 ;
					memcpy (&(psf->header [psf->headindex]), strptr, size + 1) ;
					psf->headindex += size ;
					psf->header [psf->headindex] = 0 ;
					memcpy (&(psf->header [psf->headindex]), strptr, size) ;
					psf->headindex += size ;
					if (psf->headindex + size < sizeof (psf->header))
					{	memcpy (&(psf->header [psf->headindex]), bindata, size) ;
						psf->headindex += size ;
						count += size ;
						} ;
					{	psf->header [psf->headindex] = 0 ;
						psf->headindex ++ ;
					memcpy (&(psf->header [psf->headindex]), bindata, 16) ;
					psf->headindex += 16 ;
					psf->headindex += size ;
					if (size < sizeof (psf->header))
					{	psf->headindex = size ;
						count = 0 ;
						} ;
	if (psf->headindex >= SIGNED_SIZEOF (psf->header))
		return psf_fread (ptr, 1, bytes, psf) ;

	if (psf->headindex + bytes > SIGNED_SIZEOF (psf->header))
	{	int most ;
		most = SIGNED_SIZEOF (psf->header) - psf->headend ;
		psf_fread (psf->header + psf->headend, 1, most, psf) ;
		memcpy (ptr, psf->header + psf->headend, most) ;
		psf->headend = psf->headindex += most ;
		psf_fread ((char *) ptr + most, bytes - most, 1, psf) ;
		return bytes ;
		} ;

	if (psf->headindex + bytes > psf->headend)
	{	count = psf_fread (psf->header + psf->headend, 1, bytes - (psf->headend - psf->headindex), psf) ;
		if (count != bytes - (int) (psf->headend - psf->headindex))
		psf->headend += count ;
	memcpy (ptr, psf->header + psf->headindex, bytes) ;
	psf->headindex += bytes ;
			if (position > SIGNED_SIZEOF (psf->header))
			if (position > psf->headend)
				psf->headend += psf_fread (psf->header + psf->headend, 1, position - psf->headend, psf) ;
			psf->headindex = position ;
			if (psf->headindex + position < 0)
			if (psf->headindex >= SIGNED_SIZEOF (psf->header))
			if (psf->headindex + position <= psf->headend)
			{	psf->headindex += position ;
			if (psf->headindex + position > SIGNED_SIZEOF (psf->header))
				psf->headindex = psf->headend ;
			psf->headend += psf_fread (psf->header + psf->headend, 1, position - (psf->headend - psf->headindex), psf) ;
			psf->headindex = psf->headend ;
	{	if (psf->headindex < psf->headend)
		{	ptr [k] = psf->header [psf->headindex] ;
			psf->headindex ++ ;
		{	psf->headend += psf_fread (psf->header + psf->headend, 1, 1, psf) ;
			ptr [k] = psf->header [psf->headindex] ;
			psf->headindex = psf->headend ;
	int				byte_count = 0, count ;
	{	switch (c)
					memcpy (&(psf->header [psf->headindex]), strptr, size) ;
					psf->headindex += size ;
					if (count > 0)
						byte_count += header_read (psf, charptr, count) ;
					if (count > 0)
						byte_count += header_gets (psf, charptr, count) ;
					{	psf->header [psf->headindex] = 0 ;
						psf->headindex ++ ;
			case 'p' :
					/* Get the seek position first. */
			case 'j' :
					/* Get the seek position first. */
					if (count)
					{	header_seek (psf, count, SEEK_CUR) ;
						byte_count += count ;
						} ;
#define	SF_HEADER_LEN			(12292)
	unsigned char	header		[SF_HEADER_LEN] ; /* Must be unsigned */
	/* Index variables for maintaining parselog and header above. */
	int				headindex, headend ;
	int				has_text ;


	if ((psf = calloc (1, sizeof (SF_PRIVATE))) == NULL)
	if ((psf = calloc (1, sizeof (SF_PRIVATE))) == NULL)
	if ((psf = calloc (1, sizeof (SF_PRIVATE))) == NULL)
Fixed code: #define	INITAL_HEADER_SIZE	256

/* Allocate and initialize the SF_PRIVATE struct. */
SF_PRIVATE *
psf_allocate (void)
{	SF_PRIVATE * psf ;

	if ((psf = calloc (1, sizeof (SF_PRIVATE))) == NULL)
		return	NULL ;

	if ((psf->header.ptr = calloc (1, INITAL_HEADER_SIZE)) == NULL)
	{	free (psf) ;
		return	NULL ;
		} ;
	psf->header.len = INITAL_HEADER_SIZE ;

	return psf ;
} /* psf_allocate */

static int
psf_bump_header_allocation (SF_PRIVATE * psf, sf_count_t needed)
{
	sf_count_t newlen, smallest = INITAL_HEADER_SIZE ;
	void * ptr ;

	newlen = (needed > psf->header.len) ? 2 * SF_MAX (needed, smallest) : 2 * psf->header.len ;

	if (newlen > 100 * 1024)
	{	psf_log_printf (psf, "Request for header allocation of %D denined.\n", newlen) ;
		return 1 ;
		}

	if ((ptr = realloc (psf->header.ptr, newlen)) == NULL)
	{	psf_log_printf (psf, "realloc (%p, %D) failed\n", psf->header.ptr, newlen) ;
		psf->error = SFE_MALLOC_FAILED ;
		return 1 ;
		} ;

	psf->header.ptr = ptr ;
	psf->header.len = newlen ;
	return 0 ;
} /* psf_bump_header_allocation */

	maxlen = strlen ((char*) psf->header.ptr) ;
	start	= ((char*) psf->header.ptr) + maxlen ;
	maxlen	= psf->header.len - maxlen ;
	psf->header.indx = strlen ((char*) psf->header.ptr) ;
{	psf->header.ptr [psf->header.indx++] = 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 ;
{	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 >> 8) ;
	psf->header.ptr [psf->header.indx++] = 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 >> 8) ;
	psf->header.ptr [psf->header.indx++] = 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 >> 16) ;
	psf->header.ptr [psf->header.indx++] = (x >> 8) ;
	psf->header.ptr [psf->header.indx++] = 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) ;
#if (SIZEOF_SF_COUNT_T == 8)
{	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 ;
{	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) ;
#error "SIZEOF_SF_COUNT_T != 8"
	{
		if (psf->header.indx + 16 >= psf->header.len && psf_bump_header_allocation (psf, 16))
			return count ;

		switch (c)
						float32_be_write (floatdata, psf->header.ptr + psf->header.indx) ;
						float32_le_write (floatdata, psf->header.ptr + psf->header.indx) ;
					psf->header.indx += 4 ;
						double64_be_write (doubledata, psf->header.ptr + psf->header.indx) ;
						double64_le_write (doubledata, psf->header.ptr + psf->header.indx) ;
					psf->header.indx += 8 ;

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

					memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size) ;
					psf->header.indx += size ;
					psf->header.ptr [psf->header.indx - 1] = 0 ;
					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]), strptr, size + 1) ;
					psf->header.indx += size ;
					psf->header.ptr [psf->header.indx] = 0 ;

					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]), strptr, size) ;
					psf->header.indx += size ;

					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 ;

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

					{	psf->header.ptr [psf->header.indx] = 0 ;
						psf->header.indx ++ ;
					memcpy (&(psf->header.ptr [psf->header.indx]), bindata, 16) ;
					psf->header.indx += 16 ;

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

					psf->header.indx += size ;

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

					psf->header.indx = size ;
	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->header.end += count ;
	memcpy (ptr, psf->header.ptr + psf->header.indx, bytes) ;
	psf->header.indx += bytes ;
			if (psf->header.indx + position >= psf->header.len)
				psf_bump_header_allocation (psf, position) ;
			if (position > psf->header.len)
			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 ;
			if (psf->header.indx + position >= psf->header.len)
				psf_bump_header_allocation (psf, position) ;

			if (psf->header.indx + position < 0)
			if (psf->header.indx >= psf->header.len)
			if (psf->header.indx + position <= psf->header.end)
			{	psf->header.indx += position ;
			if (psf->header.indx + position > psf->header.len)
				psf->header.indx = psf->header.end ;
			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 ;
	if (psf->header.indx + bufsize >= psf->header.len && psf_bump_header_allocation (psf, bufsize))
		return 0 ;

	{	if (psf->header.indx < psf->header.end)
		{	ptr [k] = psf->header.ptr [psf->header.indx] ;
			psf->header.indx ++ ;
		{	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 ;
	int				byte_count = 0, count = 0 ;
	{
		if (psf->header.indx + 16 >= psf->header.len && psf_bump_header_allocation (psf, 16))
			return count ;

		switch (c)
					*intptr = 0 ;
					*intptr = 0 ;
					memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size) ;
					psf->header.indx += size ;
					memset (charptr, 0, count) ;
					byte_count += header_read (psf, charptr, count) ;
					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) ;
					{	psf->header.ptr [psf->header.indx] = 0 ;
						psf->header.indx ++ ;
			case 'p' :	/* Seek to position from start. */
			case 'j' :	/* Seek to position from current position. */
					header_seek (psf, count, SEEK_CUR) ;
					byte_count += count ;

	struct
	{	unsigned char	* ptr ;
		sf_count_t		indx, end, len ;
	} header ;

/* Allocate and initialize the SF_PRIVATE struct. */
SF_PRIVATE * psf_allocate (void) ;

	{	SFE_BAD_HEADER_ALLOC 	, "Error : Required header allocation is too large." },
	if ((psf = psf_allocate ()) == NULL)
	if ((psf = psf_allocate ()) == NULL)
	if ((psf = psf_allocate ()) == NULL)
	free (psf->header.ptr) ;