#!/usr/bin/perl -w
#
# Copyright (c) 2001, 2002 Shiman Associates Inc. All Rights Reserved.
# 
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use, copy,
# modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

%ints = (8  => 8,
	 16 => 16,
	 20 => 32,
	 24 => 32 );


for $inres (8,16,20,24)
{
    for $outres (8,16,20,24)
    {
	if ($inres <= $outres)
	{
	    # signed -> signed
	    print "void s${inres}tos${outres}( char *in, char **out, uint16 *len )\n{\n";
	    print "int$ints{$inres}   *a;\nint$ints{$outres}  *b;\nuint16 i;\nuint16 length;\n\n";
	    print "length = *len;\n";
	    print "a = (int$ints{$inres}*)in;\n";

	    $mult = $ints{$outres} / $ints{$inres};
	    $mult = ($mult == 1) ? '' : "$mult * ";
	    print "*out = masc_rtalloc( ${mult}length );\n";
	    print "b = (int$ints{$outres}*) *out;\n";

	    $lth = $ints{$inres}/8; $lth = ($lth==1)? '': '/'.$lth;
	    print "for ( i=0; i<(length$lth); i++ ) {\n";
	    print "b[i] = (int$ints{$outres})a[i] << ";
	    print $outres-$inres;
	    print ";\n";
	    print "}\n";
	    unless ($mult eq '') {
		print "*len = ${mult}length;\n";
	    } 
	    print "}\n\n";

	    # unsigned -> signed
	    print "void u${inres}tos${outres}( char *in, char **out, uint16 *len )\n{\n";
	    print "uint$ints{$inres} *a;\nint$ints{$outres} *b;\nuint16 i;\nuint16 length;\n\n";
	    print "length = *len;\n";
	    print "a = (uint$ints{$inres}*)in;\n";

	    $mult = $ints{$outres} / $ints{$inres};
	    $mult = ($mult == 1) ? '' : "$mult * ";
	    print "*out = masc_rtalloc( ${mult}length );\n";
	    print "b = (int$ints{$outres}*) *out;\n";

	    $lth = $ints{$inres}/8; $lth = ($lth==1)? '': '/'.$lth;
	    print "for ( i=0; i<(length$lth); i++ ) {\n";
	    print "b[i] = (int$ints{$outres})(a[i]-";
	    print 2**($inres-1);
	    print ") << ";
	    print $outres-$inres;
	    print ";\n";
	    print "}\n";
	    unless ($mult eq '') {
		print "*len = ${mult}length;\n";
	    } 
	    print "}\n\n";
	    
	    # signed -> unsigned
	    print "void s${inres}tou${outres}( char *in, char **out, uint16 *len )\n{\n";
	    print "int$ints{$inres}   *a;\nuint$ints{$outres}  *b;\nuint$ints{$inres} c;\n uint16 i;\nuint16 length;\n\n";
	    print "length = *len;\n";
	    print "a = (int$ints{$inres}*)in;\n";

	    $mult = $ints{$outres} / $ints{$inres};
	    $mult = ($mult == 1) ? '' : "$mult * ";
	    print "*out = masc_rtalloc( ${mult}length );\n";
	    print "b = (uint$ints{$outres}*) *out;\n";

	    $lth = $ints{$inres}/8; $lth = ($lth==1)? '': '/'.$lth;
	    print "for ( i=0; i<(length$lth); i++ ) {\n";
	    print "c = a[i] + ";
	    print 2**($inres-1);
	    print ";\n";
	    print "b[i] = (uint$ints{$outres})c << ";
	    print $outres-$inres;
	    print ";\n";
	    print "}\n";
	    unless ($mult eq '') {
		print "*len = ${mult}length;\n";
	    } 
	    print "}\n\n";
	    
	    # unsigned -> unsigned
	    print "void u${inres}tou${outres}( char *in, char **out, uint16 *len )\n{\n";
	    print "uint$ints{$inres} *a;\nuint$ints{$outres} *b;\nuint16 i;\nuint16 length;\n\n";
	    print "length = *len;\n";
	    print "a = (uint$ints{$inres}*)in;\n";

	    $mult = $ints{$outres} / $ints{$inres};
	    $mult = ($mult == 1) ? '' : "$mult * ";
	    print "*out = masc_rtalloc( ${mult}length );\n";
	    print "b = (uint$ints{$outres}*) *out;\n";

	    $lth = $ints{$inres}/8; $lth = ($lth==1)? '': '/'.$lth;
	    print "for ( i=0; i<(length$lth); i++ ) {\n";
	    print "b[i] = (uint$ints{$outres})a[i] << ";
	    print $outres-$inres;
	    print ";\n";
	    print "}\n";
	    unless ($mult eq '') {
		print "*len = ${mult}length;\n";
	    } 
	    print "}\n\n";

	}


	if ($inres > $outres)
	{
	    # signed -> signed
	    print "void s${inres}tos${outres}( char *in, char **out, uint16 *len )\n{\n";
	    print "int$ints{$inres} *a;\nint$ints{$outres} *b;\nuint16 i;\n";
	    print "int$ints{$inres} tmp;\nuint$ints{$inres} utmp;\nuint16 length;\n\n";
	    print "length = *len;\n";
	    print "a = (int$ints{$inres}*)in;\n";
	    $mult = $ints{$inres} / $ints{$outres};
	    $mult = ($mult == 1) ? '' : " / $mult";
	    print "*out = masc_rtalloc( length${mult} );\n";
	    print "b = (int$ints{$outres}*) *out;\n";

	    print "for ( i=0; i<(length${mult}); i++ ) {\n";
	    print "tmp = a[i] + (1<<";
	    print $inres - $outres;
	    print ")*(0.5-(double)rand()/(double)RAND_MAX);\n";
	    print "utmp = tmp;\n";
	    print "tmp = ARITHMETIC_RIGHTSHIFT(utmp, ";
	    print $inres - $outres;
	    print ", ";
	    print $inres - 1;
	    print ");\n";
	    print "b[i] = tmp;\n}\n";

	    print "*len = length${mult};\n" unless ($mult eq '');
	    print "}\n\n";

	    # signed -> unsigned
	    print "void s${inres}tou${outres}( char *in, char **out, uint16 *len )\n{\n";
	    print "int$ints{$inres} *a;\nuint$ints{$outres} *b;\nuint16 i;\n";
	    print "int$ints{$inres} tmp;\nuint$ints{$inres} utmp;\nuint16 length;\n\n";
	    print "length = *len;\n";
	    print "a = (int$ints{$inres}*)in;\n";
	    $mult = $ints{$inres} / $ints{$outres};
	    $mult = ($mult == 1) ? '' : " / $mult";
	    print "*out = masc_rtalloc( length${mult} );\n";
	    print "b = (uint$ints{$outres}*) *out;\n";

	    print "for ( i=0; i<(length${mult}); i++ ) {\n";
	    print "tmp = a[i] + (1<<";
	    print $inres - $outres;
	    print ")*(0.5-(double)rand()/(double)RAND_MAX);\n";
	    print "utmp = tmp + ";
	    print 2**($inres-1);
	    print ";\n";
	    print "utmp = utmp >> ";
	    print $inres - $outres;
	    print ";\n";
	    print "b[i] = utmp;\n}\n";

	    print "*len = length${mult};\n" unless ($mult eq '');
	    print "}\n\n";

	    # unsigned -> signed
	    print "void u${inres}tos${outres}( char *in, char **out, uint16 *len )\n{\n";
	    print "uint$ints{$inres} *a;\nint$ints{$outres} *b;\nuint16 i;\n";
	    print "uint$ints{$inres} utmp;\nuint16 length;\n\n";
	    print "length = *len;\n";
	    print "a = (uint$ints{$inres}*)in;\n";
	    $mult = $ints{$inres} / $ints{$outres};
	    $mult = ($mult == 1) ? '' : " / $mult";
	    print "*out = masc_rtalloc( length${mult} );\n";
	    print "b = (int$ints{$outres}*) *out;\n";

	    print "for ( i=0; i<(length${mult}); i++ ) {\n";
	    print "utmp = a[i] + (1<<";
	    print $inres - $outres;
	    print ")*(0.5-(double)rand()/(double)RAND_MAX);\n";
	    print "utmp = ARITHMETIC_RIGHTSHIFT(utmp, ";
	    print $inres - $outres;
	    print ", ";
	    print $inres - 1;
	    print ");\n";
	    print "b[i] = utmp - ";
	    print 2**($outres-1);
	    print ";\n}\n";

	    print "*len = length${mult};\n" unless ($mult eq '');
	    print "}\n\n";

	    # unsigned -> unsigned
	    print "void u${inres}tou${outres}( char *in, char **out, uint16 *len )\n{\n";
	    print "uint$ints{$inres} *a;\nuint$ints{$outres} *b;\nuint16 i;\n";
	    print "uint$ints{$inres} utmp;\nuint16 length;\n\n";
	    print "length = *len;\n";
	    print "a = (uint$ints{$inres}*)in;\n";
	    $mult = $ints{$inres} / $ints{$outres};
	    $mult = ($mult == 1) ? '' : " / $mult";
	    print "*out = masc_rtalloc( length${mult} );\n";
	    print "b = (uint$ints{$outres}*) *out;\n";

	    print "for ( i=0; i<(length${mult}); i++ ) {\n";
	    print "utmp = a[i] + (1<<";
	    print $inres - $outres;
	    print ")*(0.5-(double)rand()/(double)RAND_MAX);\n";
	    print "b[i] = utmp >> ";
	    print $inres - $outres;
	    print ";\n";
	    print "}\n";

	    print "*len = length${mult};\n" unless ($mult eq '');
	    print "}\n\n";


	}
	
    }
    
}


print "\n\n /* Here comes the if statement for choosing the right function pointer:\n*/\n";

print "void choose_algorithm( struct squant_state *state )\n{\n";
for $insgnd (1,0) {
    print "if (state->insgnd == $insgnd)\n{\n";
    for $outsgnd (1,0) {
	print "if (state->outsgnd == $outsgnd)\n{\n";
	for $inres (8,16,20,24) {
	    print "if (state->inres == $inres)\n{\n";
	    for $outres (8,16,20,24) {
		print "if (state->outres == $outres)\n{\n";
	    
		print "state->requantize = \&";
		printf("%s%dto%s%d;\n", ($insgnd) ? 's':'u', $inres,
		       ($outsgnd) ? 's':'u', $outres);     
		
		print "return;\n}\n";
	    }
	    print "}\n";
	}
	print "}\n";
    }
    print "}\n";
}
print "return;\n}\n";
