/****************************************************************/
/*                                                              */
/*             Digitized Voice Programmer's Toolkit             */
/*             ------------------------------------             */
/*                                                              */
/*                  Simple Mu-Law File Decoder                  */
/*                                                              */
/*            Copyright (c) 1991, Farpoint Software             */
/*                                                              */
/****************************************************************/

/* This source file is not commented, but it is relatively easy */
/* to follow. This program is the complement to ULAW.C; it      */
/* reverses the encoding procedure by converting each nybble to */
/* a byte from a Mu-Law curve lookup table.                     */


#include <stdlib.h>
#include <fcntl.h>
#include <io.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <stdio.h>
#include <stddef.h>
#include <malloc.h>

char logo[] = "Simple Mu-Law File Decoder\r\n"
 "Copyright(c) 1991, Farpoint Software\r\n";

unsigned char *s_buffer;
unsigned char *d_buffer;
int s_handle,d_handle;

int utable[16] = { 0, 64, 96, 112, 120, 124, 126, 127,
                   128, 129, 131, 135, 143, 159, 191, 255 };

char errmsg1[] = "File read error.";
char errmsg2[] = "File write error.";
char errmsg3[] = "Unable to allocate memory.";

/*-------------------------------------------------------------------*/

void main(argc,argv)
int argc;
char **argv;

{
long s_len;
unsigned int blocks, oddblock;
unsigned int i, j;

puts(logo);

if (argc != 3)
	{
	puts("\nCommand line:");
	puts(" UNULAW <source file> <dest file>\n");
	exit(1);
	}

argv++;
s_handle = open(*argv,O_BINARY|O_RDONLY);
if (s_handle == -1)
	{
	puts(errmsg1);
	exit(1);
	}
argv++;
d_handle = open(*argv,O_BINARY|O_RDWR|O_CREAT|O_TRUNC,S_IREAD|S_IWRITE);
if (d_handle == -1)
	{
	close(s_handle);
	puts(errmsg2);
	exit(1);
	}

s_buffer = (unsigned char *)malloc(16384);
if (s_buffer == NULL)
	{
	puts(errmsg3);
	close(s_handle);
	close(d_handle);
	exit(1);
	}

d_buffer = (unsigned char *)malloc(32768U);
if (d_buffer == NULL)
	{
	puts(errmsg3);
	free(s_buffer);
	close(s_handle);
	close(d_handle);
	exit(1);
	}

s_len = filelength(s_handle);

blocks = (unsigned int)(s_len >> 14);
oddblock = (unsigned int)(s_len & 0x3FFF);

for ( i = 0 ; i < blocks ; i++ )
	{
	if ( read(s_handle, s_buffer, 16384U) != 16384U )
		{
		close(s_handle);
		close(d_handle);
		free(s_buffer);
		free(d_buffer);
		puts(errmsg1);
		exit(1);
		}
	for ( j = 0 ; j < 16384 ; j++ )
		{
		d_buffer[2*j] = (unsigned char)utable[s_buffer[j] & 0x0F];
		d_buffer[2*j+1] = (unsigned char)utable[s_buffer[j] >> 4];
		}
	if ( write(d_handle, d_buffer, 32768U) != 32768U )
		{
		close(s_handle);
		close(d_handle);
		free(s_buffer);
		free(d_buffer);
		puts(errmsg2);
		exit(1);
		}
	}
if ( oddblock )
	{
	if ( (unsigned int)read(s_handle, s_buffer, oddblock) != oddblock )
		{
		close(s_handle);
		close(d_handle);
		free(s_buffer);
		free(d_buffer);
		puts(errmsg1);
		exit(1);
		}
	for ( j = 0 ; j < oddblock ; j++ )
		{
		d_buffer[2*j] = (unsigned char)utable[s_buffer[j] & 0x0F];
		d_buffer[2*j+1] = (unsigned char)utable[s_buffer[j] >> 4];
		}
	if ( (unsigned int)write(d_handle, d_buffer, oddblock * 2) != oddblock * 2 )
		{
		close(s_handle);
		close(d_handle);
		free(s_buffer);
		free(d_buffer);
		puts(errmsg2);
		exit(1);
		}
	}

puts("File decompression complete.");
close(s_handle);
close(d_handle);
free(s_buffer);
free(d_buffer);
exit(0);
}
