<commit_before>/*
** Copyright (C) 2001-2011 <NAME> <<EMAIL>>
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation; either version 2.1 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

/*	RANT:
**	The VOC file format is the most brain damaged format I have yet had to deal
**	with. No one programmer could have bee stupid enough to put this together.
**	Instead it looks like a series of manic, dyslexic assembly language programmers
**	hacked it to fit their needs.
**	Utterly woeful.
*/

#include "sfconfig.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sndfile.h"
#include "sfendian.h"
#include "common.h"


/*------------------------------------------------------------------------------
 * Typedefs for file chunks.
*/

#define	VOC_MAX_SECTIONS	200

enum
{	VOC_TERMINATOR		= 0,
	VOC_SOUND_DATA		= 1,
	VOC_SOUND_CONTINUE	= 2,
	VOC_SILENCE			= 3,
	VOC_MARKER			= 4,
	VOC_ASCII			= 5,
	VOC_REPEAT			= 6,
	VOC_END_REPEAT		= 7,
	VOC_EXTENDED		= 8,
	VOC_EXTENDED_II		= 9
} ;

typedef struct
{	int 	samples ;
	int		offset ;	/* Offset of zero => silence. */
} SND_DATA_BLOCKS ;

typedef struct
{	unsigned int 	sections, section_types ;
	int				samplerate, channels, bitwidth ;
	SND_DATA_BLOCKS	blocks [VOC_MAX_SECTIONS] ;
} VOC_DATA ;

/*------------------------------------------------------------------------------
 * Private static functions.
*/

static	int	voc_close	(SF_PRIVATE *psf) ;
static	int voc_write_header (SF_PRIVATE *psf, int calc_length) ;
static	int voc_read_header	(SF_PRIVATE *psf) ;

static const char* voc_encoding2str (int encoding) ;

#if 0

/*	These functions would be required for files with more than one VOC_SOUND_DATA
**	segment. Not sure whether to bother implementing this.
*/

static int	voc_multi_init (SF_PRIVATE *psf, VOC_DATA *pvoc) ;

static int	voc_multi_read_uc2s		(SF_PRIVATE *psf, short *ptr, int len) ;
static int	voc_multi_read_les2s	(SF_PRIVATE *psf, short *ptr, int len) ;

static int	voc_multi_read_uc2i		(SF_PRIVATE *psf, int *ptr, int len) ;
static int	voc_multi_read_les2i	(SF_PRIVATE *psf, int *ptr, int len) ;

static int	voc_multi_read_uc2f		(SF_PRIVATE *psf, float *ptr, int len) ;
static int	voc_multi_read_les2f	(SF_PRIVATE *psf, float *ptr, int len) ;

static int	voc_multi_read_uc2d		(SF_PRIVATE *psf, double *ptr, int len) ;
static int	voc_multi_read_les2d	(SF_PRIVATE *psf, double *ptr, int len) ;
#endif

/*------------------------------------------------------------------------------
** Public function.
*/

int
voc_open	(SF_PRIVATE *psf)
{	int subformat, error = 0 ;

	if (psf->is_pipe)
		return SFE_VOC_NO_PIPE ;

	if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
	{	if ((error = voc_read_header (psf)))
			return error ;
		} ;

	subformat = SF_CODEC (psf->sf.format) ;

	if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
	{	if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_VOC)
			return	SFE_BAD_OPEN_FORMAT ;

		psf->endian = SF_ENDIAN_LITTLE ;

		if ((error = voc_write_header (psf, SF_FALSE)))
			return error ;

		psf->write_header = voc_write_header ;
		} ;

	psf->blockwidth = psf->bytewidth * psf->sf.channels ;

	psf->container_close = voc_close ;

	switch (subformat)
	{	case SF_FORMAT_PCM_U8 :
		case SF_FORMAT_PCM_16 :
				error = pcm_init (psf) ;
				break ;

		case SF_FORMAT_ALAW :
				error = alaw_init (psf) ;
				break ;

		case SF_FORMAT_ULAW :
				error = ulaw_init (psf) ;
				break ;

		default : return SFE_UNIMPLEMENTED ;
		} ;

	return error ;
} /* voc_open */

/*------------------------------------------------------------------------------
*/

static int
voc_read_header	(SF_PRIVATE *psf)
{	VOC_DATA	*pvoc ;
	char	creative [20] ;
	unsigned char block_type, rate_byte ;
	short	version, checksum, encoding, dataoffset ;
	int		offset ;

	/* Set position to start of file to begin reading header. */
	offset = psf_binheader_readf (psf, "pb", 0, creative, SIGNED_SIZEOF (creative)) ;

	if (creative [sizeof (creative) - 1] != 0x1A)
		return SFE_VOC_NO_CREATIVE ;

	/* Terminate the string. */
	creative [sizeof (creative) - 1] = 0 ;

	if (strcmp ("Creative Voice File", creative))
		return SFE_VOC_NO_CREATIVE ;

	psf_log_printf (psf, "%s\n", creative) ;

	offset += psf_binheader_readf (psf, "e222", &dataoffset, &version, &checksum) ;

	psf->dataoffset = dataoffset ;

	psf_log_printf (psf, 	"dataoffset : %d\n"
							"version    : 0x%X\n"
							"checksum   : 0x%X\n", psf->dataoffset, version, checksum) ;

	if (version != 0x010A && version != 0x0114)
		return SFE_VOC_BAD_VERSION ;

	if (! (psf->codec_data = malloc (sizeof (VOC_DATA))))
		return SFE_MALLOC_FAILED ;

	pvoc = (VOC_DATA*) psf->codec_data ;

	memset (pvoc, 0, sizeof (VOC_DATA)) ;

	/* Set the default encoding now. */
	psf->sf.format = SF_FORMAT_VOC ; /* Major format */
	encoding = SF_FORMAT_PCM_U8 ; /* Minor format */
	psf->endian = SF_ENDIAN_LITTLE ;

	while (1)
	{	unsigned size ;
		short count ;

		block_type = 0 ;
		offset += psf_binheader_readf (psf, "1", &block_type) ;

		switch (block_type)
		{	case VOC_ASCII :
					offset += psf_binheader_readf (psf, "e3", &size) ;

					psf_log_printf (psf, " ASCII : %d\n", size) ;

					if (size < sizeof (psf->header) - 1)
					{	offset += psf_binheader_readf (psf, "b", psf->header, size) ;
						psf->header [size] = 0 ;
						psf_log_printf (psf, "  text : %s\n", psf->header) ;
						continue ;
						}

					offset += psf_binheader_readf (psf, "j", size) ;
					continue ;

			case VOC_REPEAT :
					offset += psf_binheader_readf (psf, "e32", &size, &count) ;
					psf_log_printf (psf, " Repeat : %d\n", count) ;
					continue ;

			case VOC_SOUND_DATA :
			case VOC_EXTENDED :
			case VOC_EXTENDED_II :
					break ;
<commit_msg>src/voc.c : Fix overlapping memcpy.<commit_after>/*
** Copyright (C) 2001-2015 <NAME> <<EMAIL>>
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation; either version 2.1 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

/*	RANT:
**	The VOC file format is the most brain damaged format I have yet had to deal
**	with. No one programmer could have bee stupid enough to put this together.
**	Instead it looks like a series of manic, dyslexic assembly language programmers
**	hacked it to fit their needs.
**	Utterly woeful.
*/

#include "sfconfig.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sndfile.h"
#include "sfendian.h"
#include "common.h"


/*------------------------------------------------------------------------------
 * Typedefs for file chunks.
*/

#define	VOC_MAX_SECTIONS	200

enum
{	VOC_TERMINATOR		= 0,
	VOC_SOUND_DATA		= 1,
	VOC_SOUND_CONTINUE	= 2,
	VOC_SILENCE			= 3,
	VOC_MARKER			= 4,
	VOC_ASCII			= 5,
	VOC_REPEAT			= 6,
	VOC_END_REPEAT		= 7,
	VOC_EXTENDED		= 8,
	VOC_EXTENDED_II		= 9
} ;

typedef struct
{	int 	samples ;
	int		offset ;	/* Offset of zero => silence. */
} SND_DATA_BLOCKS ;

typedef struct
{	unsigned int 	sections, section_types ;
	int				samplerate, channels, bitwidth ;
	SND_DATA_BLOCKS	blocks [VOC_MAX_SECTIONS] ;
} VOC_DATA ;

/*------------------------------------------------------------------------------
 * Private static functions.
*/

static	int	voc_close	(SF_PRIVATE *psf) ;
static	int voc_write_header (SF_PRIVATE *psf, int calc_length) ;
static	int voc_read_header	(SF_PRIVATE *psf) ;

static const char* voc_encoding2str (int encoding) ;

#if 0

/*	These functions would be required for files with more than one VOC_SOUND_DATA
**	segment. Not sure whether to bother implementing this.
*/

static int	voc_multi_init (SF_PRIVATE *psf, VOC_DATA *pvoc) ;

static int	voc_multi_read_uc2s		(SF_PRIVATE *psf, short *ptr, int len) ;
static int	voc_multi_read_les2s	(SF_PRIVATE *psf, short *ptr, int len) ;

static int	voc_multi_read_uc2i		(SF_PRIVATE *psf, int *ptr, int len) ;
static int	voc_multi_read_les2i	(SF_PRIVATE *psf, int *ptr, int len) ;

static int	voc_multi_read_uc2f		(SF_PRIVATE *psf, float *ptr, int len) ;
static int	voc_multi_read_les2f	(SF_PRIVATE *psf, float *ptr, int len) ;

static int	voc_multi_read_uc2d		(SF_PRIVATE *psf, double *ptr, int len) ;
static int	voc_multi_read_les2d	(SF_PRIVATE *psf, double *ptr, int len) ;
#endif

/*------------------------------------------------------------------------------
** Public function.
*/

int
voc_open	(SF_PRIVATE *psf)
{	int subformat, error = 0 ;

	if (psf->is_pipe)
		return SFE_VOC_NO_PIPE ;

	if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
	{	if ((error = voc_read_header (psf)))
			return error ;
		} ;

	subformat = SF_CODEC (psf->sf.format) ;

	if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
	{	if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_VOC)
			return	SFE_BAD_OPEN_FORMAT ;

		psf->endian = SF_ENDIAN_LITTLE ;

		if ((error = voc_write_header (psf, SF_FALSE)))
			return error ;

		psf->write_header = voc_write_header ;
		} ;

	psf->blockwidth = psf->bytewidth * psf->sf.channels ;

	psf->container_close = voc_close ;

	switch (subformat)
	{	case SF_FORMAT_PCM_U8 :
		case SF_FORMAT_PCM_16 :
				error = pcm_init (psf) ;
				break ;

		case SF_FORMAT_ALAW :
				error = alaw_init (psf) ;
				break ;

		case SF_FORMAT_ULAW :
				error = ulaw_init (psf) ;
				break ;

		default : return SFE_UNIMPLEMENTED ;
		} ;

	return error ;
} /* voc_open */

/*------------------------------------------------------------------------------
*/

static int
voc_read_header	(SF_PRIVATE *psf)
{	VOC_DATA	*pvoc ;
	char	creative [20] ;
	unsigned char block_type, rate_byte ;
	short	version, checksum, encoding, dataoffset ;
	int		offset ;

	/* Set position to start of file to begin reading header. */
	offset = psf_binheader_readf (psf, "pb", 0, creative, SIGNED_SIZEOF (creative)) ;

	if (creative [sizeof (creative) - 1] != 0x1A)
		return SFE_VOC_NO_CREATIVE ;

	/* Terminate the string. */
	creative [sizeof (creative) - 1] = 0 ;

	if (strcmp ("Creative Voice File", creative))
		return SFE_VOC_NO_CREATIVE ;

	psf_log_printf (psf, "%s\n", creative) ;

	offset += psf_binheader_readf (psf, "e222", &dataoffset, &version, &checksum) ;

	psf->dataoffset = dataoffset ;

	psf_log_printf (psf, 	"dataoffset : %d\n"
							"version    : 0x%X\n"
							"checksum   : 0x%X\n", psf->dataoffset, version, checksum) ;

	if (version != 0x010A && version != 0x0114)
		return SFE_VOC_BAD_VERSION ;

	if (! (psf->codec_data = malloc (sizeof (VOC_DATA))))
		return SFE_MALLOC_FAILED ;

	pvoc = (VOC_DATA*) psf->codec_data ;

	memset (pvoc, 0, sizeof (VOC_DATA)) ;

	/* Set the default encoding now. */
	psf->sf.format = SF_FORMAT_VOC ; /* Major format */
	encoding = SF_FORMAT_PCM_U8 ; /* Minor format */
	psf->endian = SF_ENDIAN_LITTLE ;

	while (1)
	{	char header [256] ;
		unsigned size ;
		short count ;

		block_type = 0 ;
		offset += psf_binheader_readf (psf, "1", &block_type) ;

		switch (block_type)
		{	case VOC_ASCII :
					offset += psf_binheader_readf (psf, "e3", &size) ;

					psf_log_printf (psf, " ASCII : %d\n", size) ;

					if (size < sizeof (header) - 1)
					{	offset += psf_binheader_readf (psf, "b", header, size) ;
						header [size] = 0 ;
						psf_log_printf (psf, "  text : %s\n", header) ;
						continue ;
						}

					offset += psf_binheader_readf (psf, "j", size) ;
					continue ;

			case VOC_REPEAT :
					offset += psf_binheader_readf (psf, "e32", &size, &count) ;
					psf_log_printf (psf, " Repeat : %d\n", count) ;
					continue ;

			case VOC_SOUND_DATA :
			case VOC_EXTENDED :
			case VOC_EXTENDED_II :
					break ;

{'fraction_non_alphanumeric': 0.16113035264483627, 'fraction_numerical': 0.013460327455919395, 'mean_word_length': 2.957943925233645, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 63, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5639822', 'n_tokens_mistral': 5162, 'n_tokens_neox': 4672, 'n_words': 1306}