
// http://conus.info/utils/demux/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

void dump_bufs(char* buf, int size, char* fname, FILE* h)
{
	if (fwrite (buf, 1, size, h)!=size)
	{
		printf ("unable to write to file %s\n", fname);
		exit(1);
	};
};

int main (int argc, char* argv[])
{
	int i, red, pat_len;
	FILE* in;
	FILE* out[10];
	int bufsize;
	char* buf=NULL;
	char* bufs[10];
	int bufsptr[10];

	for (i=0; i<10; i++)
	{
		out[i]=NULL;
		bufs[i]=NULL;
		bufsptr[i]=0;
	};

	if (argc<3)
	{
		printf ("file demux 0.1 <dennix@conus.info>\n");
		printf ("usage: demux input_file <pattern> <output_file1> <output_file2> ...\n");
		printf ("pattern examples:\n");
		printf (" \"12\" - put all odd bytes into file1 and even bytes to file2\n");
		printf (" \"1.\" - put all odd bytes into file1 and ignore even bytes\n");
		printf (" \"11.\" - collect all 1st and 2nd bytes and ignore 3rd bytes in byte triplet\n");
		printf (" \"112233445566\" - demux 5.1 raw audio file into 6 files (one per channel)\n");
		printf (" \"1111........\" - get front left/right channels and put into stereo raw file\n");
		return 0;
	};

	pat_len=strlen (argv[2]);
	in=fopen (argv[1], "rb");
	if (in==NULL)
	{
		printf ("unable to open %s\n", argv[1]);
		exit(1);
	};

	// chk pattern

	for (i=0; i<pat_len; i++)
	{
		if (isdigit (argv[2][i])==0 && argv[2][i]!='.')
		{
			printf ("pattern may contain only digits or dot\n");
			exit(1);
		};

		if (argv[2][i]!='.')
		{
			int no=argv[2][i]-'0';

			if ((argc-3) < no)
			{
				printf ("file #%d was not mentioned in arguments\n", no);
				exit(1);
			};
			assert (argv[2+no]!=NULL);
		};
	};

	bufsize=pat_len*0x100000; // one MiB
	buf=(char*)malloc (bufsize);
	if (buf==NULL)
	{
		bufsize=pat_len*10240;
		buf=(char*)malloc (bufsize);
		if (buf==NULL)
		{
			printf ("cannot allocate memory\n");
			exit(1);
		};
	};

	do
	{
		int rem;
		int bufptr=0;

		red=rem=fread (buf, 1, bufsize, in);

		do
		{
			for (i=0; i < (rem < pat_len ? rem : pat_len); i++)
			{
				char n=argv[2][i];

				if (n!='.')
				{
					int no=n-'0';

					if (out[no]==NULL)
					{
						out[no]=fopen(argv[2+no], "wb");
						if (out[no]==NULL)
						{
							printf ("unable to open file %s for writing\n", argv[2+no]);
							exit(1);
						};
						bufs[no]=(char*)malloc (bufsize);
						if (bufs[no]==NULL)
						{
							printf ("cannot allocate memory\n");
							exit(1);
						};
					};

					bufs[no][bufsptr[no]]=buf[bufptr];
					bufsptr[no]++;
					if (bufsptr[no]==bufsize) // bufsptr filled
					{
						dump_bufs(bufs[no], bufsptr[no], argv[2+no], out[no]);
						bufsptr[no]=0;
					};
				};
				bufptr++;

			};
			rem=rem-pat_len;
		}
		while (rem>=pat_len);
	}
	while (red==bufsize);

	fclose (in);

	for (i=0; i<10; i++)
		if (out[i]!=NULL)
		{
			if (bufsptr[i]>0)
			{
				dump_bufs(bufs[i], bufsptr[i], argv[2+i], out[i]);
				bufsptr[i]=0; // not necessary
			};

			free (bufs[i]);
			fclose (out[i]);
		};

	free (buf);

	return 0;
};

