diff options
Diffstat (limited to 'jpg')
-rw-r--r-- | jpg/Makefile | 16 | ||||
-rwxr-xr-x | jpg/conv1 | 65 | ||||
-rwxr-xr-x | jpg/conv2 | 1319 | ||||
-rwxr-xr-x | jpg/conv3 | 41 | ||||
-rw-r--r-- | jpg/getword | 7 | ||||
-rw-r--r-- | jpg/jpg.c | 948 | ||||
-rw-r--r-- | jpg/jpg.h | 2 | ||||
-rw-r--r-- | jpg/test1.jpg | bin | 0 -> 26277 bytes | |||
-rw-r--r-- | jpg/test2.jpg | bin | 0 -> 120169 bytes | |||
-rw-r--r-- | jpg/test3.jpg | bin | 0 -> 107826 bytes | |||
-rw-r--r-- | jpg/test4.jpg | bin | 0 -> 61909 bytes | |||
-rw-r--r-- | jpg/z2.c | 160 |
12 files changed, 2558 insertions, 0 deletions
diff --git a/jpg/Makefile b/jpg/Makefile new file mode 100644 index 0000000..c7ea63e --- /dev/null +++ b/jpg/Makefile @@ -0,0 +1,16 @@ +all: z2 jpeg.S + +z2: z2.c jpg.o + gcc -O2 -Wall z2.c jpg.o -o z2 + +jpg.o: jpg.c + gcc -O2 -Wall -c jpg.c + +jpeg.S jpeg.inc: jpg.c + gcc -fomit-frame-pointer -S -Os -Wall -c jpg.c + ./conv1 jpg.s >jpeg1.s + ./conv2 -o jpeg2.s jpeg1.s + ./conv3 jpeg2.s >jpeg.S 2>jpeg.inc + +clean: + rm -f *~ *.o *.i *.s *.S *.inc *.pnm z2 diff --git a/jpg/conv1 b/jpg/conv1 new file mode 100755 index 0000000..933cb85 --- /dev/null +++ b/jpg/conv1 @@ -0,0 +1,65 @@ +#! /usr/bin/perl + +# gcc -save-temps -fomit-frame-pointer -Os -Wall -c jpg.c +# convert: .data -> .text +# ## add: .code16gcc +# convert: .local/.comm foo,bar,??? -> foo: .space bar,0 +# remove: .size, .type, .align +# remove .section .note... +# remove .ident +# replace getword + +sub fix_getword; + +@f = (<>); + +$getword = `cat getword`; + +for (@f) { + undef $_ if /^\s*\.(size|align|p2align|text|section|ident|local|data|file)/; + $_ = "\n" if /^\s*\.type/; + if(/^\s*\.globl/) { + push @globl, "\t$_"; + undef $_; + } + + if(/^\s*\.comm\s+(\S+),(\d+),\d+\s*$/) { + push @comm, ( "\n", "$1:\n", "\t.space\t$2,0\n" ); + undef $_; + } +} + +unshift @globl, ( "\t.file\t\"jpeg.S\"\n", "\t.text\n", + # "\t\.code16gcc\n", + "\n" +); + +fix_getword; + +$_ = join '', @globl, @comm, @f; s/\n{3,}/\n\n/g; @f = split /\n/; + +print "$_\n" for @f; + +for (qw ( getword )) { + if($fixes{$_} != 1) { + print STDERR "error: fix failed: $_\n" + } +} + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +sub fix_getword +{ + for (@f) { + if(/^getword:/ .. /^\s*ret\b/) { + if(/^getword:/) { + $_ = $getword; + $fixes{getword}++; + } + else { + undef $_; + } + } + } +} + diff --git a/jpg/conv2 b/jpg/conv2 new file mode 100755 index 0000000..9d42fc3 --- /dev/null +++ b/jpg/conv2 @@ -0,0 +1,1319 @@ +#! /usr/bin/perl + +# tack pointer usage and assign proper segment registers + +use Getopt::Long; +Getopt::Long::Configure("bundling"); + +sub add_prefix; +sub get_arg; +sub decode_instr; +sub decode_arg; +sub trace_it; + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +sub is_ref; +sub is_reg; +sub is_num; +sub is_sym; +sub const_add; +sub const_eval; +sub const_eval_addr; +sub push_on_stack; +sub pop_from_stack; +sub start_trace; +sub trace_it; +sub clone_state; +sub show_state; +sub start_trace; +sub set_state; +sub del_state_context; + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +$re_reg = '%[a-z]+'; +$re_symbol = '[._a-zA-Z][\._a-zA-Z0-9]*'; +$re_num = '[\-\+]?\d+'; + +%full_reg = ( + '%al' => '%eax', + '%ah' => '%eax', + '%ax' => '%eax', + '%bl' => '%ebx', + '%bh' => '%ebx', + '%bx' => '%ebx', + '%cl' => '%ecx', + '%ch' => '%ecx', + '%cx' => '%ecx', + '%dl' => '%edx', + '%dh' => '%edx', + '%dx' => '%edx', + '%si' => '%esi', + '%di' => '%edi', + '%bp' => '%ebp', + '%sp' => '%esp', +); + + +$opt_verbose = 0; +$opt_out_file = '-'; + +GetOptions( + 'v' => sub { $opt_verbose++ }, + 'q' => sub { $opt_verbose-- }, + 'o=s' => \$opt_out_file, +); + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +$static_data_seg = 'fs'; +# see trace_it() for more configs + +while(<>) { + chomp; + + $text{$.}{orig} = $_; + + if(s/^\s*($re_symbol)://) { + $symbol{$1}{line} = $.; + $c = $1; + $context = $c unless $1 =~ /^\.L/; + $ofs = 0; + } + + s/\s*#.*//; + s/^\s*//; + + if(/^.globl\s+(\S+)$/) { + $global{$1} = $.; + undef $_; + } + + if(defined($ofs) && /^\.(long|byte)\s+(\d+)$/) { + $ofs += 1 if $1 eq 'byte'; + $ofs += 4 if $1 eq 'long'; + if($context) { + $symbol{$context}{size} = $ofs; + $seg = $symbol{$context}{seg}; + if($seg && $seg ne 'cs') { + warn "$.: moving $context from \"$seg\" to \"cs\"\n" + } + $symbol{$context}{seg} = "cs"; + } + undef $_; + } + else { + undef $ofs unless /^\s*$/; + } + + if(/^\.space\s+(\d+)\s*\,\s*(\d+)$/) { + if($2) { + warn "$.: $context has nonzero data\n"; + } + if($context) { + $symbol{$context}{size} = $1; + $seg = $symbol{$context}{seg}; + if($seg && $seg ne $static_data_seg) { + warn "$.: moving $context from \"$seg\" to \"$static_data_seg\"\n" + } + $symbol{$context}{seg} = $static_data_seg; + } + undef $_; + } + + $text{$.}{op} = $_; + $text{$.}{context} = $context; +} + +for (sort { $a <=> $b } keys %text) { + decode_instr $_; +} + +trace_it; + + +for (keys %text) { + add_prefix $_; +} + +open F, ">$opt_out_file"; + +for (sort { $a <=> $b } keys %text) { + if($text{$_}{new}) { + print F "\t# $text{$_}{new_comment}\n" if $opt_verbose >= 0 && $text{$_}{new_comment}; + printf F "%s\n", $text{$_}{new}; + } + else { + printf F "%s\n", $text{$_}{orig}; + } + if($opt_verbose >= 2 && $text{$_}{instr}) { + + if($opt_verbose >= 3) { + $state = $text{$_}{state}; + print F "\t # $state->{'..ilog'}\n" if $state->{'..ilog'}; + if($state->{'..addr'}) { + print F "\t # mem ref: " . join(', ', @{$state->{'..addr'}}) . "\n"; + } + print F show_state("\t #"); + } + } +} + +if($opt_verbose >= 2) { + print F "\n# symbols:\n"; + for (sort { $symbol{$a}{line} <=> $symbol{$b}{line} } keys %symbol) { + printf F "# %s (%sseg = %s, size %d)\n", + $_, + $global{$_} ? "global, " : "", + $symbol{$_}{seg}, + $symbol{$_}{size}; + } +} + +close F; + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +sub add_prefix +{ + local $_; + my ($l, $state, $seg, $s, @i, $n, @a, $i, @c, $d); + + $l = shift; + + return if !($state = $text{$l}{state}); + + return unless $text{$l}{instr}; + + for (@{$state->{'..addr'}}) { + undef $s; + @i = split /\+/; + next if !$i[0]; + $s = $symbol{$i[0]}{seg} if is_sym($i[0]) && $symbol{$i[0]}{seg}; + + if(!$s || ($seg && $s ne $seg)) { + warn "$l: can't determine segment\n" + } + $seg = $s if $s; + } + + for ($i = 0; $i < @{$text{$l}{arg}}; $i++) { + if($seg && $state->{'..addr'}[$i]) { + $d = $text{$l}{arg}[$i]{seg}; + $d = 'ds' unless $d; + $a[$i] = "%$seg:" if $seg ne $d; + push @c, "$text{$l}{arg}[$i]{orig} = %$seg:$state->{'..addr'}[$i]"; + } + $a[$i] .= $text{$l}{arg}[$i]{orig}; + } + + $n = "\t$text{$l}{instr}"; + $n .= "\t" . join(', ', @a) if @a; + + $text{$l}{new_comment} = join(', ', @c) if @c; + $text{$l}{new} = $n; +} + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +sub get_arg +{ + local $_; + + $_ = shift; + + if(/^([^,()]*(\(.*?\))?[^,()]*)/) { + return $1; + } + + return undef; +} + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +sub decode_instr +{ + local $_; + my ($l, $op, $instr, $arg1, $arg2, $arg3, @arg, $arg, $is_branch); + + $l = shift; + + $op = $text{$l}{op}; + + return unless $op =~ s/^(\S+)\s*//; + + $instr = $1; + + return if $instr =~ /^\.(file|text|code16gcc)$/; + + $is_branch = 1 if $instr =~ /^(call|j)/; + + $arg1 = get_arg $op; + substr($op, 0, length($arg1)) = ""; + $op =~ s/^,\s*//; + + $arg2 = get_arg $op; + substr($op, 0, length($arg2)) = ""; + $op =~ s/^,\s*//; + + $arg3 = get_arg $op; + substr($op, 0, length($arg3)) = ""; + $op =~ s/^,\s*//; + + if($op) { + warn "$l: error splitting args\n" + } + +# print "[$instr] [$arg1] [$arg2] [$arg3]\n"; + + $text{$l}{instr} = $instr; + + $. = $l; + + if($arg1) { + $arg = decode_arg $arg1, $is_branch; + push @arg, $arg; + } + + if($arg2) { + $arg = decode_arg $arg2, $is_branch; + push @arg, $arg; + } + + if($arg3) { + $arg = decode_arg $arg3, $is_branch; + push @arg, $arg; + } + + $text{$l}{arg} = [ @arg ]; + +# for $arg (@arg) { +# print "$arg->{orig},\tval = $arg->{val}\n"; +# } + +# print "$text{$l}{arg}[0]{orig}\n"; +} + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +sub decode_arg +{ + local $_; + my ($is_branch, $arg, $p, $v, $seg, $l, @i); + + $_ = shift; + $is_branch = shift; + + $arg->{orig} = $_; + + if(/^(\*?)($re_reg)$/o) { + $arg->{val} = $2; + + if($1) { + warn "$.: arg with \"*\"?\n" unless $is_branch; + } + + return $arg; + } + + if(s/^([*\$]?)([^*,:%()]+)//) { + $p = $1; + $v = $2; + if($v =~ s/^($re_symbol)([\+\-])?//i) { + $v = "-$v" if $2 eq '-'; + $l = $1; + } + + if($v && $v !~ /^$re_num$/o) { + warn "$.: $v is not a number\n"; + } + + if($l) { + warn "$.: unknown symbol $l\n" unless $symbol{$l}; + $v = "+$v" if $v; + $arg->{val} = "$l$v"; + } + else { + $arg->{val} = $v; + } + + if($is_branch) { + warn "$.: arg with \"$p\"?\n" if $p eq '$'; + $arg->{val} = "*$arg->{val}" if $p eq '*'; + } + else { + warn "$.: arg with \"$p\"?\n" if $p eq '*'; + $arg->{val} = "*$arg->{val}" unless $p eq '$'; + } + } + + if(/^\(.+\)$/) { + s/(^\(|\)$)//g; + @i = split /\s*,\s*/; + $i[2] = 1 unless $i[2]; + if($i[0] eq '%esp' || $i[0] eq '%ebp') { + $arg->{seg} = 'ss'; + } + if($i[1] && $i[1] eq $i[0]) { + $i[0] = undef; + $i[2]++; + } + + $arg->{val} = '*' unless $arg->{val}; + + $arg->{val} .= "+$i[0]" if $i[0]; + $arg->{val} .= "+$i[1]" if $i[1]; + $arg->{val} .= "*$i[2]" if $i[2] > 1; + + $arg->{val} =~ s/^\*\+/*/; + + return $arg; + } + + warn "$.: don't understand \"$arg->{orig}\"\n" if $_; + + return $arg; +} + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +sub is_ref +{ + return $_[0] =~ /^\*/o; +} + + +sub is_reg +{ + return $_[0] =~ /^$re_reg$/o; +} + + +sub is_num +{ + return $_[0] =~ /^$re_num$/o; +} + + +sub is_sym +{ + return $symbol{$_[0]}; +} + + +sub const_add +{ + local $_; + my (@i, $i, $ok, $arg1, $arg2); + + ($arg1, $arg2) = @_; + + if($arg1 eq '?') { + ($arg2, $arg1) = ($arg1, $arg2); + } + + if($symbol{$arg1}) { + ($arg2, $arg1) = ($arg1, $arg2); + } + + if(is_num($arg1)) { + ($arg2, $arg1) = ($arg1, $arg2); + } + + @i = split /\+/, $arg1; + + if(is_num $arg2) { + for (@i) { + if(/^$re_num$/o) { + $_ += $arg2; + $ok = 1; + last; + } + elsif($_ eq '?') { + $ok = 1; + last; + } + } + push @i, $arg2 unless $ok; + } + elsif(is_sym $arg2) { + if(is_num $arg1) { + @i = ( $arg2 ); + push @i, $arg1 if $arg1 != 0; + } + elsif($arg1 eq '?') { + @i = ( $arg2, '?' ); + } + else { + @i = ( '?' ); + } + } + elsif($arg2 eq '?') { + for (@i) { + if(/^$re_num$/o || $_ eq '?') { + $_ = '?'; + $ok = 1; + last; + } + } + @i = ( '?' ) unless $ok; + } + else { + @i = ( '?' ); + } + + $i = join '+', @i; + + # print ">>$arg1 + $arg2 = $i<<\n"; + + return $i; +} + + +sub const_eval +{ + local $_; + my ($arg, @i, @j, $sym, $val, $nosym, $ref, $i, $fact); + + $arg = shift; + + $val = 0; + + $ref = 1 if $arg =~ s/^\*//; + + @i = split /\+/, $arg; + + for (@i) { + undef $fact; + if(/^%/ && s/\*(\d+)$//) { + $fact = $1; + undef $fact if $fact == 1; + } + if(is_reg($_) && defined($state->{$_})) { + if(is_num($state->{$_}) && defined($fact)) { + $fact *= $state->{$_}; + push @j, "$fact"; + } + elsif(!defined($fact)) { + push @j, split(/\+/, $state->{$_}); + } + else { + push @j, '?'; + } + } + else { + push @j, $_; + } + } + + for (@j) { + if($symbol{$_}) { + $nosym = 1 if $sym; + $sym = $_; + next; + } + + if(/^$re_num$/o) { + $val += $_ unless $val eq '?'; + next; + } + + $val = '?'; + } + + $i = '?'; + + if(!$nosym) { + if($sym && $val) { + $i = "$sym+$val"; + } + elsif($sym) { + $i = $sym; + } + elsif(defined($val)) { + $i = "$val"; + } + } + + if($ref) { + if($state->{$i}) { + $i = $state->{$i}; + } + else { + $i = '?'; + } + } + + return $i; +} + + +sub const_eval_addr +{ + local $_; + + $_ = shift; + + return $_ if /^${re_reg}$/; + + $_ =~ s/^\*//; + + return const_eval $_; +} + + +sub push_on_stack +{ + my ($new_sp); + + $new_sp = const_add $state->{"%esp"}, -4; + + $state->{"%esp"} = $new_sp; + $state->{"$new_sp"} = $_[0]; +} + + +sub pop_from_stack +{ + my ($new_sp, $i); + + $new_sp = const_add $state->{"%esp"}, 4; + + $i = $state->{$state->{"%esp"}}; + + delete $state->{$state->{"%esp"}}; + $state->{"%esp"} = $new_sp; + + return $i; +} + + +sub trace_it +{ + undef @branch_states; + + $symbol{stack}{size} = 1000; + $symbol{stack}{seg} = 'ss'; + + $symbol{jpg}{seg} = 'es'; + $symbol{pic}{seg} = 'es'; + + $state->{"%esp"} = "stack+1000"; + push_on_stack "jpg"; + push_on_stack "0+%cs"; + $state->{"%eip"} = "$symbol{jpeg_get_size}{line}+%cs"; + push @branch_states, clone_state($state); + + $state->{"%esp"} = "stack+1000"; + push_on_stack "32"; + push_on_stack "111"; + push_on_stack "11"; + push_on_stack "222"; + push_on_stack "22"; + push_on_stack "pic"; + push_on_stack "jpg"; + push_on_stack "0+%cs"; + $state->{"%eip"} = "$symbol{jpeg_decode}{line}+%cs"; + push @branch_states, clone_state($state); + + undef $state; + + while($state = pop @branch_states) { + start_trace; + } +} + + +sub clone_state +{ + my ($new_state); + + $new_state->{$_} = $state->{$_} for keys %{$state}; + + return $new_state; +} + + +sub show_state +{ + local $_; + my ($s); + + for (sort keys %{$state}) { + $s .= "$_[0] $_ = $state->{$_}\n" unless /^\.\./; + } + + return $s; +} + + +sub start_trace +{ + local $_; + my ($op, $c, $ok, $opc, $br); + + $pc = 0; + + $br = @branch_states; + + # print "starting at: $state->{'%eip'} ($br)\n"; + + $state->{'..stop'} = undef; + + do { + $state->{'..addr'} = undef; + $state->{'..ilog'} = undef; + + if($state->{"%eip"} =~ /^(${re_num})\+%cs$/) { + $pc = $1; + } + else { + warn "$state->{'%eip'}: oops, got lost\n"; + return; + } + + return if !$pc; + + if(!exists($text{"$pc"})) { + warn "$state->{'%eip'}: oops, got lost\n"; + return; + } + + if($state->{"..%oeip"} =~ /^(${re_num})\+%cs$/) { + $opc = $1; + } + else { + $opc = 0; + } + + $loc = "$opc->$pc"; + + $op = $text{"$pc"}; + + print "# $loc: $op->{orig}\n" if $opt_verbose >= 2; + + $ok = 0; + + $state->{"..%oeip"} = $state->{"%eip"}; + + $state->{"%eip"} = const_add $state->{"%eip"}, 1; + + if($op->{instr}) { + if($c = $opcodes{$op->{instr}}) { + &$c($op); + $ok = 1; + } + else { + warn "$pc: unknown opcode: $op->{instr}\n"; + } + } + + $text{"$pc"}{state} = clone_state; + + print "# $state->{'..ilog'}\n" if $opt_verbose >= 1; + + if($opt_verbose >= 3) { + print show_state if $ok; + } + + } while(!$state->{'..stop'}); +} + + +sub set_state +{ + $state->{$_[0]} = "$_[1]"; +} + + +sub del_state_context +{ + local $_; + + return unless $_[0]; + + for (keys %text) { + undef $text{$_}{state} if $text{$_}{context} eq $_[0]; + } +} + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +BEGIN { + %opcodes = ( + pushl => \&op_pushl, + popl => \&op_popl, + movl => \&op_movl, + movzbl => \&op_movl, + movzwl => \&op_movl, + movl => \&op_movl, + movw => \&op_movl, + movb => \&op_movl, + xchgb => \&op_xchgb, + leal => \&op_leal, + xorl => \&op_alu2, + sall => \&op_alu2, + sarl => \&op_alu2, + shll => \&op_alu2, + shrl => \&op_alu2, + addl => \&op_alu2, + subl => \&op_alu2, + incl => \&op_alu1, + decl => \&op_alu1, + negl => \&op_alu1, + notl => \&op_alu1, + setg => \&op_alu1, + setge => \&op_alu1, + setl => \&op_alu1, + setle => \&op_alu1, + sete => \&op_alu1, + setne => \&op_alu1, + incb => \&op_alu1, + decb => \&op_alu1, + testl => \&op_alu2, + cmpl => \&op_alu2, + orl => \&op_alu2, + andl => \&op_alu2, + orb => \&op_alu2, + subb => \&op_alu2, + addb => \&op_alu2, + cmpb => \&op_alu2, + testb => \&op_alu2, + imull => \&op_imull, + ret => \&op_ret, + call => \&op_jmp, + jmp => \&op_jmp, + je => \&op_jmp, + jne => \&op_jmp, + jg => \&op_jmp, + jng => \&op_jmp, + jl => \&op_jmp, + jnl => \&op_jmp, + js => \&op_jmp, + jns => \&op_jmp, + ja => \&op_jmp, + jna => \&op_jmp, + jb => \&op_jmp, + jnb => \&op_jmp, + jbe => \&op_jmp, + jle => \&op_jmp, + jge => \&op_jmp, + cltd => \&op_cltd, + idivl => \&op_idivl, + ); +} + + +sub op_pushl +{ + my ($op, $args, $val1, $arg1); + + $op = shift; + + $args = @{$op->{arg}}; + + if($args != 1) { + warn "$pc: invalid number of arguments\n"; + return; + } + + $arg1 = $op->{arg}[0]->{val}; + + $val1 = const_eval $arg1; + + $state->{'..addr'}[0] = const_eval_addr $arg1 if is_ref $arg1; + + $state->{'..ilog'} = "$loc: $op->{instr} $arg {$val1}"; + + push_on_stack $val1; +} + + +sub op_popl +{ + my ($op, $args, $val1, $arg1); + + $op = shift; + + $args = @{$op->{arg}}; + + if($args != 1) { + warn "$pc: invalid number of arguments\n"; + return; + } + + $arg1 = $op->{arg}[0]->{val}; + + $val1 = const_eval_addr $arg1; + + $state->{'..addr'}[0] = $val1 if is_ref $arg1; + + set_state $val1, pop_from_stack; + + $state->{'..ilog'} = "$loc: $op->{instr} $arg {$val1}"; +} + + +sub op_movl +{ + my ($op, $args, $val1, $val2, $arg1, $arg2, $val3); + + $op = shift; + + $args = @{$op->{arg}}; + + if($args != 2) { + warn "$pc: invalid number of arguments\n"; + return; + } + + $arg1 = $op->{arg}[0]->{val}; + $arg2 = $op->{arg}[1]->{val}; + + if($full_reg{$arg1}) { + $arg1 = $full_reg{$arg1}; + } + + if($full_reg{$arg2}) { + $arg2 = $full_reg{$arg2}; + } + + $val1 = const_eval $arg1; + $val2 = const_eval_addr $arg2; + + $val3 = $val1; + + if( + $op->{instr} eq 'movzbl' || + $op->{instr} eq 'movzwl' || + $op->{instr} eq 'movb' || + $op->{instr} eq 'movw' + ) { + $val3 = '?'; + } + + $state->{'..addr'}[0] = const_eval_addr $arg1 if is_ref $arg1; + $state->{'..addr'}[1] = $val2 if is_ref $arg2; + + set_state $val2, $val3; + + $state->{'..ilog'} = "$loc: $op->{instr} $arg1 {$val1}, $arg2 {$val2}"; +} + + +sub op_leal +{ + my ($op, $args, $val1, $val2, $arg1, $arg2); + + $op = shift; + + $args = @{$op->{arg}}; + + if($args != 2) { + warn "$pc: invalid number of arguments\n"; + return; + } + + $arg1 = $op->{arg}[0]->{val}; + $arg2 = $op->{arg}[1]->{val}; + + $val1 = const_eval_addr $arg1; + $val2 = const_eval_addr $arg2; + + set_state $val2, $val1; + + # $state->{'..addr'}[0] = $val1; + + $state->{'..ilog'} = "$loc: $op->{instr} $arg1 {$val1}, $arg2 {$val2}"; +} + + +sub op_xchgb +{ + my ($op, $args, $val1, $val2, $arg1, $arg2, $val3); + + $op = shift; + + $args = @{$op->{arg}}; + + if($args != 2) { + warn "$pc: invalid number of arguments\n"; + return; + } + + $arg1 = $op->{arg}[0]->{val}; + $arg2 = $op->{arg}[1]->{val}; + + if($full_reg{$arg1}) { + $arg1 = $full_reg{$arg1}; + } + + if($full_reg{$arg2}) { + $arg2 = $full_reg{$arg2}; + } + + $val1 = const_eval_addr $arg1; + $val2 = const_eval_addr $arg2; + + $val3 = '?'; + + $state->{'..addr'}[0] = $val1 if is_ref $arg1; + $state->{'..addr'}[1] = $val2 if is_ref $arg2; + + set_state $val1, $val3; + set_state $val2, $val3; + + $state->{'..ilog'} = "$loc: $op->{instr} $arg1 {$val1}, $arg2 {$val2}"; +} + + +sub op_alu2 +{ + my ($op, $args, $val1, $val2, $val3, $arg1, $arg2, $arg3, $no_change); + + $op = shift; + + $args = @{$op->{arg}}; + + if($args != 2) { + warn "$pc: invalid number of arguments\n"; + return; + } + + $arg1 = $op->{arg}[0]->{val}; + $arg2 = $op->{arg}[1]->{val}; + + if($full_reg{$arg1}) { + $arg1 = $full_reg{$arg1}; + } + + if($full_reg{$arg2}) { + $arg2 = $full_reg{$arg2}; + } + + $val1 = const_eval $arg1; + $val2 = const_eval $arg2; + $arg3 = const_eval_addr $arg2; + + $val3 = '?'; + + if($op->{instr} eq 'sall' || $op->{instr} eq 'shll') { + if(is_num($val1) && is_num($val2)) { + $val3 = $val2 << $val1; + } + elsif($arg1 eq '0') { + $val3 = $val2; + } + } + elsif($op->{instr} eq 'sarl' || $op->{instr} eq 'shrl') { + if(is_num($val1) && is_num($val2)) { + if($val1 >= 1 && $op->{instr} eq 'shrl') { + $val3 = ($val2 & (1 << 31)) >> $val1; + } + else { + $val3 = $val2 >> $val1; + } + } + elsif($arg1 eq '0') { + $val3 = $val2; + } + } + elsif($op->{instr} eq 'xorl') { + if(is_num($val1) && is_num($val2)) { + $val3 = ($val1 + 0) ^ ($val2 + 0); + $val3 = $val3; + } + elsif($arg1 eq $arg2) { + $val3 = '0'; + } + } + elsif($op->{instr} eq 'addl') { + if(is_num($val1) || is_num($val2)) { + $val3 = const_add $val1, $val2; + } + elsif($symbol{$val1} || $symbol{$val2}) { + $val3 = const_add $val1, $val2; + } + elsif($val1 eq '?' || $val2 eq '?') { + $val3 = const_add $val1, $val2; + } + } + elsif($op->{instr} eq 'subl') { + if(is_num($val1)) { + $val3 = const_add $val2, -$val1; + } + } + elsif($op->{instr} eq 'orl') { + if(is_num($val1) && is_num($val2)) { + $val3 = $val1 | $val2; + } + elsif($arg1 eq $arg2) { + $val3 = $val2; + } + } + elsif($op->{instr} eq 'andl') { + if(is_num($val1) && is_num($val2)) { + $val3 = $val1 & $val2; + } + elsif($arg1 eq $arg2) { + $val3 = $val2; + } + } + elsif($op->{instr} eq 'orb' || $op->{instr} eq 'subb' || $op->{instr} eq 'addb') { + } + elsif( + $op->{instr} eq 'cmpl' || $op->{instr} eq 'testl' || + $op->{instr} eq 'cmpb' || $op->{instr} eq 'testb' + ) { + $no_change = 1; + } + + $state->{'..addr'}[0] = const_eval_addr $arg1 if is_ref $arg1; + $state->{'..addr'}[1] = $arg3 if is_ref $arg2; + + set_state $arg3, $val3 unless $no_change; + + $state->{'..ilog'} = "$loc: $op->{instr} $arg1 {$val1}, $arg2 {$val2}"; +} + + +sub op_alu1 +{ + my ($op, $args, $val1, $val2, $arg1, $arg2); + + $op = shift; + + $args = @{$op->{arg}}; + + if($args != 1) { + warn "$pc: invalid number of arguments\n"; + return; + } + + $arg1 = $op->{arg}[0]->{val}; + + if($full_reg{$arg1}) { + $arg1 = $full_reg{$arg1}; + } + + $val1 = const_eval $arg1; + $arg2 = const_eval_addr $arg1; + + $val2 = '?'; + + if($op->{instr} eq 'incl') { + $val2 = const_add $val1, 1; + } + elsif($op->{instr} eq 'decl') { + $val2 = const_add $val1, -1; + } + elsif( + $op->{instr} eq 'negl' || + $op->{instr} eq 'notl' || + $op->{instr} eq 'incb' || + $op->{instr} eq 'decb' || + $op->{instr} =~ /^set/ + ) { + $val2 = '?'; + } + + $state->{'..addr'}[0] = $arg2 if is_ref $arg1; + + set_state $arg2, $val2; + + $state->{'..ilog'} = "$loc: $op->{instr} $arg1 {$val1}"; +} + + +sub op_imull +{ + my ($op, $args, $val1, $val2, $val3, $arg1, $arg2, $arg3, $arg4, $fact); + + $op = shift; + + $args = @{$op->{arg}}; + + if($args != 2 && $args != 3) { + warn "$pc: invalid number of arguments\n"; + return; + } + + if($args == 2) { + $arg1 = $op->{arg}[0]->{val}; + $arg2 = $op->{arg}[1]->{val}; + } + else { + $arg1 = $op->{arg}[0]->{val}; + $arg2 = $op->{arg}[1]->{val}; + $arg3 = $op->{arg}[2]->{val}; + } + + if($full_reg{$arg1}) { + $arg1 = $full_reg{$arg1}; + } + + if($full_reg{$arg2}) { + $arg2 = $full_reg{$arg2}; + } + + $val1 = const_eval $arg1; + $val2 = const_eval $arg2; + + if($args == 2) { + $arg4 = const_eval_addr $arg2; + } + else { + $arg4 = const_eval_addr $arg3; + } + + $val3 = '?'; + + if(is_num($val1) && is_num($val2)) { + $val3 = $val1 * $val2; + } + + if($args == 2) { + $state->{'..addr'}[0] = const_eval_addr $arg1 if is_ref $arg1; + $state->{'..addr'}[1] = $arg4 if is_ref $arg2; + } + else { + $state->{'..addr'}[0] = const_eval_addr $arg1 if is_ref $arg1; + $state->{'..addr'}[1] = const_eval_addr $arg2 if is_ref $arg2; + $state->{'..addr'}[1] = $arg4 if is_ref $arg3; + } + + set_state $arg4, $val3; + + $state->{'..ilog'} = "$loc: $op->{instr} $arg1 {$val1}, $arg2 {$val2}"; +} + + +sub op_cltd +{ + my ($op, $args); + + $op = shift; + + $args = @{$op->{arg}}; + + if($args != 0) { + warn "$pc: invalid number of arguments\n"; + return; + } + + set_state "%edx", '?'; + + $state->{'..ilog'} = "$loc: $op->{instr}"; +} + + +sub op_idivl +{ + my ($op, $args, $val1, $val2, $arg1, $arg2); + + $op = shift; + + $args = @{$op->{arg}}; + + if($args != 1) { + warn "$pc: invalid number of arguments\n"; + return; + } + + $arg1 = $op->{arg}[0]->{val}; + + $val1 = const_eval $arg1; + $arg2 = const_eval_addr $arg1; + + $state->{'..addr'}[0] = $arg2 if is_ref $arg1; + + set_state "%eax", '?'; + set_state "%edx", '?'; + + $state->{'..ilog'} = "$loc: $op->{instr} $arg1 {$val1}"; +} + + +sub op_ret +{ + my ($op, $args, $i); + + $op = shift; + + $args = @{$op->{arg}}; + + # no 'ret n' support + if($args != 0) { + warn "$pc: invalid number of arguments\n"; + return; + } + + $state->{'%eip'} = pop_from_stack; + + $state->{'..ilog'} = "$loc: $op->{instr}"; +} + + +sub op_jmp +{ + my ($op, $args, $val1, $arg1, $ns, $taken); + + $op = shift; + + $args = @{$op->{arg}}; + + if($args != 1) { + warn "$pc: invalid number of arguments\n"; + return; + } + + $arg1 = $op->{arg}[0]->{val}; + + $val1 = const_eval $arg1; + + if($symbol{$val1}) { + $val1 = "$symbol{$val1}{line}+%cs"; + } + + $state->{'..ilog'} = "$loc: $op->{instr} $arg {$val1}"; + + if($op->{instr} eq 'call') { + if($val1 =~ /^(${re_num})\+%cs$/ && $text{$1}{state}) { + $taken = 1; + } + + # del_state_context $arg1; + + # print ">> $loc: call $arg1\n"; + + # evil hack to avoid loops + if(!$taken) { + push_on_stack $state->{'%eip'}; + $state->{'%eip'} = $val1; + } + } + else { + if($val1 =~ /^(${re_num})\+%cs$/ && $text{$1}{state}) { + $taken = 1; + } + + if($op->{instr} eq 'jmp') { + # unconditional braches + if($taken) { + $state->{'..stop'} = 1; + # print "** $loc: stopped\n"; + } + $state->{'%eip'} = $val1; + } + else { + # conditional branches + + if(!$taken) { + $ns = clone_state; + $ns->{'%eip'} = $val1; + + push @branch_states, $ns; + } + } + } +} + + diff --git a/jpg/conv3 b/jpg/conv3 new file mode 100755 index 0000000..43e4422 --- /dev/null +++ b/jpg/conv3 @@ -0,0 +1,41 @@ +#! /usr/bin/perl + +@f = (<>); + +$ofs = 0; + +for (@f) { + if(/^(\S*):/) { + $symbol = $1; + next; + } + + if(/^\s*\.space\s+(\d+),\s*(\d+)/) { + $symbol{$symbol} = $ofs; + $ofs += $1; + undef $_; + } +} + + +for (@f) { + if(/^(\S*):/) { + $symbol = $1; + + if(defined $symbol{$symbol}) { + undef $_; + + if(!$datasize) { + $datasize = 1; + $size = "\t\tjpg_data_size\tequ $ofs\n"; + } + + $_ = "\t.equ\t$symbol, $symbol{$symbol}\n" + } + next; + } +} + +print @f; + +print STDERR $size; diff --git a/jpg/getword b/jpg/getword new file mode 100644 index 0000000..50ad07f --- /dev/null +++ b/jpg/getword @@ -0,0 +1,7 @@ +getword: + movl datap, %edx + movzwl (%edx), %eax + addl $2, %edx + xchgb %al, %ah + movl %edx, datap + ret diff --git a/jpg/jpg.c b/jpg/jpg.c new file mode 100644 index 0000000..c4a9bac --- /dev/null +++ b/jpg/jpg.c @@ -0,0 +1,948 @@ +#include "jpg.h" + +#define ERR_NO_SOI 1 +#define ERR_NOT_8BIT 2 +#define ERR_HEIGHT_MISMATCH 3 +#define ERR_WIDTH_MISMATCH 4 +#define ERR_BAD_WIDTH_OR_HEIGHT 5 +#define ERR_TOO_MANY_COMPPS 6 +#define ERR_ILLEGAL_HV 7 +#define ERR_QUANT_TABLE_SELECTOR 8 +#define ERR_NOT_YCBCR_221111 9 +#define ERR_UNKNOWN_CID_IN_SCAN 10 +#define ERR_NOT_SEQUENTIAL_DCT 11 +#define ERR_WRONG_MARKER 12 +#define ERR_NO_EOI 13 +#define ERR_BAD_TABLES 14 +#define ERR_DEPTH_MISMATCH 15 + +#define ISHIFT 11 + +#define IFIX(a) ((int)((a) * (1 << ISHIFT) + .5)) +#define IMULT(a, b) (((a) * (b)) >> ISHIFT) +#define ITOINT(a) ((a) >> ISHIFT) + +#ifndef __P +# define __P(x) x +#endif + +/* special markers */ +#define M_BADHUFF -1 +#define M_EOF 0x80 + +struct in { + unsigned int bits; + int left; + int marker; + void *data; +}; + +/*********************************/ +struct dec_hufftbl; +struct enc_hufftbl; + +union hufftblp { + struct dec_hufftbl *dhuff; + struct enc_hufftbl *ehuff; +}; + +struct scan { + int dc; /* old dc value */ + + union hufftblp hudc; + union hufftblp huac; + int next; /* when to switch to next scan */ + + int cid; /* component id */ + int hv; /* horiz/vert, copied from comp */ + int tq; /* quant tbl, copied from comp */ +}; + +/*********************************/ + +#define DECBITS 8 /* seems to be the optimum */ + +struct dec_hufftbl { + int maxcode[17]; + int valptr[16]; + unsigned char vals[256]; + unsigned int llvals[1 << DECBITS]; +}; + +struct jpeg_decdata { + int dcts[6 * 64 + 16]; + int out[64 * 6]; + int dquant[3][64]; +}; + +static void decode_mcus __P((struct in *, int *, int, struct scan *, int *)); +static void dec_makehuff __P((struct dec_hufftbl *, int *, unsigned char *)); + +static void setinput __P((struct in *)); +/*********************************/ + +#undef PREC +#define PREC int + +static void idctqtab __P((unsigned char *, PREC *)); +static void idct __P((int *, int *, PREC *, PREC, int)); +static void scaleidctqtab __P((PREC *, PREC)); + +/*********************************/ + +static void initcol __P((PREC[][64])); + +static void col221111(int *out, unsigned char *pic, int width, int bits); +static unsigned char tmp_img[16*16*4]; /* 16 x 16, 32 bit color */ + +/*********************************/ + +#define M_SOI 0xd8 +#define M_APP0 0xe0 +#define M_DQT 0xdb +#define M_SOF0 0xc0 +#define M_DHT 0xc4 +#define M_DRI 0xdd +#define M_SOS 0xda +#define M_RST0 0xd0 +#define M_EOI 0xd9 +#define M_COM 0xfe + +static unsigned char *datap; +static struct jpeg_decdata decdata; + +static void memset(void *p, int c, int n) +{ + unsigned char *x = p; + + while(n--) *x++ = c; +} + + +static int getbyte(void) +{ + return *datap++; +} + +static int getword(void) +{ + int c1, c2; + c1 = *datap; + c2 = datap[1]; + datap += 2; + return c1 << 8 | c2; +} + +struct comp { + int cid; + int hv; + int tq; +}; + +#define MAXCOMP 4 +struct jpginfo { + int nc; /* number of components */ + int ns; /* number of scans */ + int dri; /* restart interval */ +}; + +static struct jpginfo info; +static struct comp comps[MAXCOMP]; + +static struct scan dscans[MAXCOMP]; + +static unsigned char quant[4][64]; + +static struct dec_hufftbl dhuff[4]; + +#define dec_huffdc (dhuff + 0) +#define dec_huffac (dhuff + 2) + +static struct in in; + +static int readtables(int till) +{ + int m, l, i, j, lq, pq, tq; + int tc, th, tt; + + for (;;) { + if (getbyte() != 0xff) + return -1; + if ((m = getbyte()) == till) + break; + + switch (m) { + case 0xc2: + return 0; + + case M_DQT: + lq = getword(); + while (lq > 2) { + pq = getbyte(); + tq = pq & 15; + if (tq > 3) + return -1; + pq >>= 4; + if (pq != 0) + return -1; + for (i = 0; i < 64; i++) + quant[tq][i] = getbyte(); + lq -= 64 + 1; + } + break; + + case M_DHT: + l = getword(); + while (l > 2) { + int hufflen[16], k; + unsigned char huffvals[256]; + + tc = getbyte(); + th = tc & 15; + tc >>= 4; + tt = tc * 2 + th; + if (tc > 1 || th > 1) + return -1; + for (i = 0; i < 16; i++) + hufflen[i] = getbyte(); + l -= 1 + 16; + k = 0; + for (i = 0; i < 16; i++) { + for (j = 0; j < hufflen[i]; j++) + huffvals[k++] = getbyte(); + l -= hufflen[i]; + } + dec_makehuff(dhuff + tt, hufflen, + huffvals); + } + break; + + case M_DRI: + l = getword(); + info.dri = getword(); + break; + + default: + l = getword(); + while (l-- > 2) + getbyte(); + break; + } + } + return 0; +} + +static void dec_initscans(void) +{ + int i; + + for (i = 0; i < info.ns; i++) + dscans[i].dc = 0; +} + +int jpeg_decode(unsigned char *buf, unsigned char *pic, int x0, int x1, int y0, int y1, int color_bits) +{ + int i, j, m, tac, tdc; + int mcusx, mcusy, mx, my; + int max[6]; + int width, height; + int mx0, mx1, my0, my1; + + datap = buf; + if (getbyte() != 0xff) + return ERR_NO_SOI; + if (getbyte() != M_SOI) + return ERR_NO_SOI; + if (readtables(M_SOF0)) + return ERR_BAD_TABLES; + if(info.dri) return ERR_WRONG_MARKER; + + getword(); + i = getbyte(); + if (i != 8) + return ERR_NOT_8BIT; + + height = getword(); + width = getword(); + + info.nc = getbyte(); + if (info.nc > MAXCOMP) + return ERR_TOO_MANY_COMPPS; + for (i = 0; i < info.nc; i++) { + int h, v; + comps[i].cid = getbyte(); + comps[i].hv = getbyte(); + v = comps[i].hv & 15; + h = comps[i].hv >> 4; + comps[i].tq = getbyte(); + if (h > 3 || v > 3) + return ERR_ILLEGAL_HV; + if (comps[i].tq > 3) + return ERR_QUANT_TABLE_SELECTOR; + } + if (readtables(M_SOS)) + return ERR_BAD_TABLES; + getword(); + info.ns = getbyte(); + if (info.ns != 3) + return ERR_NOT_YCBCR_221111; + for (i = 0; i < 3; i++) { + dscans[i].cid = getbyte(); + tdc = getbyte(); + tac = tdc & 15; + tdc >>= 4; + if (tdc > 1 || tac > 1) + return ERR_QUANT_TABLE_SELECTOR; + for (j = 0; j < info.nc; j++) + if (comps[j].cid == dscans[i].cid) + break; + if (j == info.nc) + return ERR_UNKNOWN_CID_IN_SCAN; + dscans[i].hv = comps[j].hv; + dscans[i].tq = comps[j].tq; + dscans[i].hudc.dhuff = dec_huffdc + tdc; + dscans[i].huac.dhuff = dec_huffac + tac; + } + + i = getbyte(); + j = getbyte(); + m = getbyte(); + + if (i != 0 || j != 63 || m != 0) + return ERR_NOT_SEQUENTIAL_DCT; + + if (dscans[0].cid != 1 || dscans[1].cid != 2 || dscans[2].cid != 3) + return ERR_NOT_YCBCR_221111; + + if (dscans[0].hv != 0x22 || dscans[1].hv != 0x11 || dscans[2].hv != 0x11) + return ERR_NOT_YCBCR_221111; + + mcusx = (width + 15) >> 4; + mcusy = (height + 15) >> 4; + + mx0 = x0 >> 4; + my0 = y0 >> 4; + + /* inclusive! */ + mx1 = ((x1 + 15) >> 4) - 1; + my1 = ((y1 + 15) >> 4) - 1; + + if(my1 < mcusy) mcusy = my1 + 1; + + idctqtab(quant[dscans[0].tq], decdata.dquant[0]); + idctqtab(quant[dscans[1].tq], decdata.dquant[1]); + idctqtab(quant[dscans[2].tq], decdata.dquant[2]); + initcol(decdata.dquant); + setinput(&in); + + dec_initscans(); + + dscans[0].next = 6 - 4; + dscans[1].next = 6 - 4 - 1; + dscans[2].next = 6 - 4 - 1 - 1; /* 411 encoding */ + for (my = 0; my < mcusy; my++) { + for (mx = 0; mx < mcusx; mx++) { + decode_mcus(&in, decdata.dcts, 6, dscans, max); + + if( + my >= my0 && my <= my1 && + mx >= mx0 && mx <= mx1 + ) { + int i0, i1, j0, j1, yofs; + + idct(decdata.dcts, decdata.out, decdata.dquant[0], IFIX(128.5), max[0]); + idct(decdata.dcts + 64, decdata.out + 64, decdata.dquant[0], IFIX(128.5), max[1]); + idct(decdata.dcts + 128, decdata.out + 128, decdata.dquant[0], IFIX(128.5), max[2]); + idct(decdata.dcts + 192, decdata.out + 192, decdata.dquant[0], IFIX(128.5), max[3]); + idct(decdata.dcts + 256, decdata.out + 256, decdata.dquant[1], IFIX(0.5), max[4]); + idct(decdata.dcts + 320, decdata.out + 320, decdata.dquant[2], IFIX(0.5), max[5]); + + // color_bits * 2: actually 16 * (color_bits / 8) + col221111(decdata.out, tmp_img, color_bits * 2, color_bits); + + j0 = my == my0 ? y0 - 16 * my : 0; + j1 = my == my1 ? y1 - 16 * my : 16; + for(j = j0; j < j1; j++) { + yofs = (16 * my - y0 + j) * (x1 - x0); + i0 = mx == mx0 ? x0 - 16 * mx : 0; + i1 = mx == mx1 ? x1 - 16 * mx : 16; + + switch(color_bits) { + case 8: + for(i = i0; i < i1; i++) { + *((unsigned char *) pic + 16 * mx - x0 + i + yofs) = + *((unsigned char *) tmp_img + 16 * j + i); + } + break; + + case 16: + for(i = i0; i < i1; i++) { + *((unsigned short *) pic + 16 * mx - x0 + i + yofs) = + *((unsigned short *) tmp_img + 16 * j + i); + } + break; + + case 32: + for(i = i0; i < i1; i++) { + *((unsigned *) pic + 16 * mx - x0 + i + yofs) = + *((unsigned *) tmp_img + 16 * j + i); + } + break; + } + } + } + } + } + + return 0; +} + +/****************************************************************/ +/************** huffman decoder ***************/ +/****************************************************************/ + +static int fillbits __P((struct in *, int, unsigned int)); +static int dec_rec2 +__P((struct in *, struct dec_hufftbl *, int *, int, int)); + +static void setinput(in) +struct in *in; +{ + in->left = 0; + in->bits = 0; + in->marker = 0; +} + +static int fillbits(in, le, bi) +struct in *in; +int le; +unsigned int bi; +{ + int b, m; + + if (in->marker) { + if (le <= 16) + in->bits = bi << 16, le += 16; + return le; + } + while (le <= 24) { + b = getbyte(); + if (b == 0xff && (m = getbyte()) != 0) { + in->marker = m; + if (le <= 16) + bi = bi << 16, le += 16; + break; + } + bi = bi << 8 | b; + le += 8; + } + in->bits = bi; /* tmp... 2 return values needed */ + return le; +} + +#define LEBI_DCL int le, bi +#define LEBI_GET(in) (le = in->left, bi = in->bits) +#define LEBI_PUT(in) (in->left = le, in->bits = bi) + +#define GETBITS(in, n) ( \ + (le < (n) ? le = fillbits(in, le, bi), bi = in->bits : 0), \ + (le -= (n)), \ + bi >> le & ((1 << (n)) - 1) \ +) + +#define UNGETBITS(in, n) ( \ + le += (n) \ +) + + +static int dec_rec2(in, hu, runp, c, i) +struct in *in; +struct dec_hufftbl *hu; +int *runp; +int c, i; +{ + LEBI_DCL; + + LEBI_GET(in); + if (i) { + UNGETBITS(in, i & 127); + *runp = i >> 8 & 15; + i >>= 16; + } else { + for (i = DECBITS; (c = ((c << 1) | GETBITS(in, 1))) >= (hu->maxcode[i]); i++); + if (i >= 16) { + in->marker = M_BADHUFF; + return 0; + } + i = hu->vals[hu->valptr[i] + c - hu->maxcode[i - 1] * 2]; + *runp = i >> 4; + i &= 15; + } + if (i == 0) { /* sigh, 0xf0 is 11 bit */ + LEBI_PUT(in); + return 0; + } + /* receive part */ + c = GETBITS(in, i); + if (c < (1 << (i - 1))) + c += (-1 << i) + 1; + LEBI_PUT(in); + return c; +} + +#define DEC_REC(in, hu, r, i) ( \ + r = GETBITS(in, DECBITS), \ + i = hu->llvals[r], \ + i & 128 ? \ + ( \ + UNGETBITS(in, i & 127), \ + r = i >> 8 & 15, \ + i >> 16 \ + ) \ + : \ + ( \ + LEBI_PUT(in), \ + i = dec_rec2(in, hu, &r, r, i), \ + LEBI_GET(in), \ + i \ + ) \ +) + +static void decode_mcus(in, dct, n, sc, maxp) +struct in *in; +int *dct; +int n; +struct scan *sc; +int *maxp; +{ + struct dec_hufftbl *hu; + int i, r, t; + LEBI_DCL; + + memset(dct, 0, n * 64 * sizeof(*dct)); + LEBI_GET(in); + while (n-- > 0) { + hu = sc->hudc.dhuff; + *dct++ = (sc->dc += DEC_REC(in, hu, r, t)); + + hu = sc->huac.dhuff; + i = 63; + while (i > 0) { + t = DEC_REC(in, hu, r, t); + if (t == 0 && r == 0) { + dct += i; + break; + } + dct += r; + *dct++ = t; + i -= r + 1; + } + *maxp++ = 64 - i; + if (n == sc->next) + sc++; + } + LEBI_PUT(in); +} + +static void dec_makehuff(hu, hufflen, huffvals) +struct dec_hufftbl *hu; +int *hufflen; +unsigned char *huffvals; +{ + int code, k, i, j, d, x, c, v; + for (i = 0; i < (1 << DECBITS); i++) + hu->llvals[i] = 0; + +/* + * llvals layout: + * + * value v already known, run r, backup u bits: + * vvvvvvvvvvvvvvvv 0000 rrrr 1 uuuuuuu + * value unknown, size b bits, run r, backup u bits: + * 000000000000bbbb 0000 rrrr 0 uuuuuuu + * value and size unknown: + * 0000000000000000 0000 0000 0 0000000 + */ + code = 0; + k = 0; + for (i = 0; i < 16; i++, code <<= 1) { /* sizes */ + hu->valptr[i] = k; + for (j = 0; j < hufflen[i]; j++) { + hu->vals[k] = *huffvals++; + if (i < DECBITS) { + c = code << (DECBITS - 1 - i); + v = hu->vals[k] & 0x0f; /* size */ + for (d = 1 << (DECBITS - 1 - i); --d >= 0;) { + if (v + i < DECBITS) { /* both fit in table */ + x = d >> (DECBITS - 1 - v - + i); + if (v && x < (1 << (v - 1))) + x += (-1 << v) + 1; + x = x << 16 | (hu-> vals[k] & 0xf0) << 4 | + (DECBITS - (i + 1 + v)) | 128; + } else + x = v << 16 | (hu-> vals[k] & 0xf0) << 4 | + (DECBITS - (i + 1)); + hu->llvals[c | d] = x; + } + } + code++; + k++; + } + hu->maxcode[i] = code; + } + hu->maxcode[16] = 0x20000; /* always terminate decode */ +} + +/****************************************************************/ +/************** idct ***************/ +/****************************************************************/ + +#define ONE ((PREC)IFIX(1.)) +#define S2 ((PREC)IFIX(0.382683432)) +#define C2 ((PREC)IFIX(0.923879532)) +#define C4 ((PREC)IFIX(0.707106781)) + +#define S22 ((PREC)IFIX(2 * 0.382683432)) +#define C22 ((PREC)IFIX(2 * 0.923879532)) +#define IC4 ((PREC)IFIX(1 / 0.707106781)) + +#define C3IC1 ((PREC)IFIX(0.847759065)) /* c3/c1 */ +#define C5IC1 ((PREC)IFIX(0.566454497)) /* c5/c1 */ +#define C7IC1 ((PREC)IFIX(0.198912367)) /* c7/c1 */ + +#define XPP(a,b) (t = a + b, b = a - b, a = t) +#define XMP(a,b) (t = a - b, b = a + b, a = t) +#define XPM(a,b) (t = a + b, b = b - a, a = t) + +#define ROT(a,b,s,c) ( t = IMULT(a + b, s), \ + a = IMULT(a, c - s) + t, \ + b = IMULT(b, c + s) - t) + +#define IDCT \ +( \ + XPP(t0, t1), \ + XMP(t2, t3), \ + t2 = IMULT(t2, IC4) - t3, \ + XPP(t0, t3), \ + XPP(t1, t2), \ + XMP(t4, t7), \ + XPP(t5, t6), \ + XMP(t5, t7), \ + t5 = IMULT(t5, IC4), \ + ROT(t4, t6, S22, C22),\ + t6 -= t7, \ + t5 -= t6, \ + t4 -= t5, \ + XPP(t0, t7), \ + XPP(t1, t6), \ + XPP(t2, t5), \ + XPP(t3, t4) \ +) + +static unsigned char zig2[64] = { + 0, 2, 3, 9, 10, 20, 21, 35, + 14, 16, 25, 31, 39, 46, 50, 57, + 5, 7, 12, 18, 23, 33, 37, 48, + 27, 29, 41, 44, 52, 55, 59, 62, + 15, 26, 30, 40, 45, 51, 56, 58, + 1, 4, 8, 11, 19, 22, 34, 36, + 28, 42, 43, 53, 54, 60, 61, 63, + 6, 13, 17, 24, 32, 38, 47, 49 +}; + +void idct(in, out, quant, off, max) +int *in; +int *out; +PREC *quant; +PREC off; +int max; +{ + PREC t0, t1, t2, t3, t4, t5, t6, t7, t; + PREC tmp[64], *tmpp; + int i, j; + unsigned char *zig2p; + + t0 = off; + if (max == 1) { + t0 += in[0] * quant[0]; + for (i = 0; i < 64; i++) + out[i] = ITOINT(t0); + return; + } + zig2p = zig2; + tmpp = tmp; + for (i = 0; i < 8; i++) { + j = *zig2p++; + t0 += in[j] * quant[j]; + j = *zig2p++; + t5 = in[j] * quant[j]; + j = *zig2p++; + t2 = in[j] * quant[j]; + j = *zig2p++; + t7 = in[j] * quant[j]; + j = *zig2p++; + t1 = in[j] * quant[j]; + j = *zig2p++; + t4 = in[j] * quant[j]; + j = *zig2p++; + t3 = in[j] * quant[j]; + j = *zig2p++; + t6 = in[j] * quant[j]; + IDCT; + tmpp[0 * 8] = t0; + tmpp[1 * 8] = t1; + tmpp[2 * 8] = t2; + tmpp[3 * 8] = t3; + tmpp[4 * 8] = t4; + tmpp[5 * 8] = t5; + tmpp[6 * 8] = t6; + tmpp[7 * 8] = t7; + tmpp++; + t0 = 0; + } + for (i = 0; i < 8; i++) { + t0 = tmp[8 * i + 0]; + t1 = tmp[8 * i + 1]; + t2 = tmp[8 * i + 2]; + t3 = tmp[8 * i + 3]; + t4 = tmp[8 * i + 4]; + t5 = tmp[8 * i + 5]; + t6 = tmp[8 * i + 6]; + t7 = tmp[8 * i + 7]; + IDCT; + out[8 * i + 0] = ITOINT(t0); + out[8 * i + 1] = ITOINT(t1); + out[8 * i + 2] = ITOINT(t2); + out[8 * i + 3] = ITOINT(t3); + out[8 * i + 4] = ITOINT(t4); + out[8 * i + 5] = ITOINT(t5); + out[8 * i + 6] = ITOINT(t6); + out[8 * i + 7] = ITOINT(t7); + } +} + +static unsigned char zig[64] = { + 0, 1, 5, 6, 14, 15, 27, 28, + 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, + 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, + 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, + 35, 36, 48, 49, 57, 58, 62, 63 +}; + +static PREC aaidct[8] = { + IFIX(0.3535533906), IFIX(0.4903926402), + IFIX(0.4619397663), IFIX(0.4157348062), + IFIX(0.3535533906), IFIX(0.2777851165), + IFIX(0.1913417162), IFIX(0.0975451610) +}; + + +static void idctqtab(qin, qout) +unsigned char *qin; +PREC *qout; +{ + int i, j; + + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + qout[zig[i * 8 + j]] = qin[zig[i * 8 + j]] * + IMULT(aaidct[i], aaidct[j]); +} + +static void scaleidctqtab(q, sc) +PREC *q; +PREC sc; +{ + int i; + + for (i = 0; i < 64; i++) + q[i] = IMULT(q[i], sc); +} + +/****************************************************************/ +/************** color decoder ***************/ +/****************************************************************/ + +/* + * YCbCr Color transformation: + * + * y:0..255 Cb:-128..127 Cr:-128..127 + * + * R = Y + 1.40200 * Cr + * G = Y - 0.34414 * Cb - 0.71414 * Cr + * B = Y + 1.77200 * Cb + * + * => + * Cr *= 1.40200; + * Cb *= 1.77200; + * Cg = 0.19421 * Cb + .50937 * Cr; + * R = Y + Cr; + * G = Y - Cg; + * B = Y + Cb; + * + * => + * Cg = (50 * Cb + 130 * Cr + 128) >> 8; + */ + +static void initcol(q) +PREC q[][64]; +{ + scaleidctqtab(q[1], IFIX(1.77200)); + scaleidctqtab(q[2], IFIX(1.40200)); +} + +/* This is optimized for the stupid sun SUNWspro compiler. */ +#define STORECLAMP(a,x) \ +( \ + (a) = (x), \ + (unsigned int)(x) >= 256 ? \ + ((a) = (x) < 0 ? 0 : 255) \ + : \ + 0 \ +) + +#define CLAMP(x) ((unsigned int)(x) >= 256 ? ((x) < 0 ? 0 : 255) : (x)) + +#define CBCRCG(xin) \ +( \ + cb = outc[0 + xin], \ + cr = outc[64 + xin], \ + cg = (50 * cb + 130 * cr + 128) >> 8 \ +) + +#define PIC(yin, xin, p, xout) \ +( \ + y = outy[(yin) * 8 + xin], \ + STORECLAMP(p[(xout) * 4 + 0], y + cb), \ + STORECLAMP(p[(xout) * 4 + 1], y - cg), \ + STORECLAMP(p[(xout) * 4 + 2], y + cr) \ +) + +#define PIC221111x(xin, xin_4, xin_3) \ +( \ + CBCRCG(xin), \ + PIC(xin_4 + 0, xin_3 + 0, pic0, xin * 2 + 0), \ + PIC(xin_4 + 0, xin_3 + 1, pic0, xin * 2 + 1), \ + PIC(xin_4 + 1, xin_3 + 0, pic1, xin * 2 + 0), \ + PIC(xin_4 + 1, xin_3 + 1, pic1, xin * 2 + 1) \ +) + +#define PIC_16(yin, xin, p, xout, add) \ +( \ + y = outy[(yin) * 8 + xin], \ + *(unsigned short *) (p + (xout) * 2) = store_16(CLAMP(y + cr), CLAMP(y - cg), CLAMP(y + cb), add) \ +) + +#define PIC221111_16x(xin, xin_4, xin_3) \ +( \ + CBCRCG(xin), \ + PIC_16(xin_4 + 0, xin_3 + 0, pic0, xin * 2 + 0, 3 * 0x55), \ + PIC_16(xin_4 + 0, xin_3 + 1, pic0, xin * 2 + 1, 0 * 0x55), \ + PIC_16(xin_4 + 1, xin_3 + 0, pic1, xin * 2 + 0, 1 * 0x55), \ + PIC_16(xin_4 + 1, xin_3 + 1, pic1, xin * 2 + 1, 2 * 0x55) \ +) + +#define PIC_8(yin, xin, p, xout, add) \ +( \ + y = outy[(yin) * 8 + xin], \ + p[(xout)] = store_8(CLAMP(y + cr), CLAMP(y - cg), CLAMP(y + cb), add) \ +) + +#define PIC221111_8x(xin, xin_4, xin_3) \ +( \ + CBCRCG(xin), \ + PIC_8(xin_4 + 0, xin_3 + 0, pic0, xin * 2 + 0, 3 * 0x55), \ + PIC_8(xin_4 + 0, xin_3 + 1, pic0, xin * 2 + 1, 0 * 0x55), \ + PIC_8(xin_4 + 1, xin_3 + 0, pic1, xin * 2 + 0, 1 * 0x55), \ + PIC_8(xin_4 + 1, xin_3 + 1, pic1, xin * 2 + 1, 2 * 0x55) \ +) + + +static unsigned store_16(unsigned r, unsigned g, unsigned b, unsigned add) +{ + unsigned rgb; + + rgb = (((r << 5) - r + add) >> 8) << 11; + rgb += (((g << 6) - g + add) >> 8) << 5; + rgb += ((b << 5) - b + add) >> 8; + + return rgb; +} + +static unsigned store_8(unsigned r, unsigned g, unsigned b, unsigned add) +{ + unsigned rgb; + +#if 0 + r = ((r << 2) - r + add) >> 8; + g = ((g << 3) - g + add) >> 8; + b = ((b << 3) - b + add) >> 8; + + rgb = (r << 6) + (g << 3) + b; +#endif + + rgb = (((r << 2) - r + add) >> 8) << 6; + rgb += (((g << 3) - g + add) >> 8) << 3; + rgb += ((b << 3) - b + add) >> 8; + + return rgb; +} + +static void col221111(int *out, unsigned char *pic, int width, int bits) +{ + int i, j, k, k_4, k_3; + unsigned char *pic0, *pic1; + int *outy, *outc; + int cr, cg, cb, y; + + pic0 = pic; + pic1 = pic + width; + outy = out; + outc = out + 64 * 4; + for(i = 2; i > 0; i--) { + for(j = 4; j > 0; j--) { + for(k = 0; k < 8; k++) { + k_4 = (k >> 2) << 3; + k_3 = (k & 3) << 1; + switch(bits) { + case 8: + PIC221111_8x(k, k_4, k_3); + break; + case 16: + PIC221111_16x(k, k_4, k_3); + break; + case 32: + PIC221111x(k, k_4, k_3); + break; + } + } + outc += 8; + outy += 16; + pic0 += 2 * width; + pic1 += 2 * width; + } + outy += 64 * 2 - 16 * 4; + } +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +unsigned jpeg_get_size(unsigned char *buf) +{ + unsigned u; + + datap = buf; + getbyte(); getbyte(); + if(readtables(M_SOF0)) return 0; + getword(); getbyte(); + + u = getword() << 16; + u += getword(); + + return u; +} + diff --git a/jpg/jpg.h b/jpg/jpg.h new file mode 100644 index 0000000..b730943 --- /dev/null +++ b/jpg/jpg.h @@ -0,0 +1,2 @@ +int jpeg_decode(unsigned char *jpg, unsigned char *img, int x_0, int x_1, int y_0, int y_1, int color_bits); +unsigned jpeg_get_size(unsigned char *buf); diff --git a/jpg/test1.jpg b/jpg/test1.jpg Binary files differnew file mode 100644 index 0000000..1a69e73 --- /dev/null +++ b/jpg/test1.jpg diff --git a/jpg/test2.jpg b/jpg/test2.jpg Binary files differnew file mode 100644 index 0000000..650bfaf --- /dev/null +++ b/jpg/test2.jpg diff --git a/jpg/test3.jpg b/jpg/test3.jpg Binary files differnew file mode 100644 index 0000000..28c2773 --- /dev/null +++ b/jpg/test3.jpg diff --git a/jpg/test4.jpg b/jpg/test4.jpg Binary files differnew file mode 100644 index 0000000..c889f3b --- /dev/null +++ b/jpg/test4.jpg diff --git a/jpg/z2.c b/jpg/z2.c new file mode 100644 index 0000000..a7c7741 --- /dev/null +++ b/jpg/z2.c @@ -0,0 +1,160 @@ +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "jpg.h" + +int main(int argc, char **argv) +{ + int fd, i, width, height; + unsigned char *jpg = malloc(1 << 20); + unsigned char *img, *p; + unsigned char pixel[3]; + unsigned x, z; + unsigned x0, x1, y0, y1; + unsigned bits = 0; + + if(argc < 4) return 1; + + if(!strcmp(argv[1], "--8")) { + bits = 8; + } + + if(!strcmp(argv[1], "--16")) { + bits = 16; + } + + if(!strcmp(argv[1], "--24")) { + bits = 24; + } + + if(!strcmp(argv[1], "--32")) { + bits = 32; + } + + if(!bits) return 10; + + fd = open(argv[2], O_RDONLY); + + if(fd == -1) return 2; + + i = read(fd, jpg, 1 << 20); + + if(i < 0) return 3; + + close(fd); + + jpg = realloc(jpg, i); + + x = jpeg_get_size(jpg); + + width = x & 0xffff; + height = x >> 16; + + fprintf(stderr, "size = %d bytes, width = %d, height = %d\n", i, width, height); + + img = malloc(width * height * 4); + + x0 = 0; + x1 = width; + y0 = 0; + y1 = height; + + i = jpeg_decode(jpg, img, x0, x1, y0, y1, bits); + + width = x1 - x0; + height = y1 - y0; + + fprintf(stderr, "decode = %d\n", i); + + fprintf(stderr, + "%02x %02x %02x %02x %02x %02x %02x %02x\n", + img[0], img[1], img[2], img[3], + img[4], img[5], img[6], img[7] + ); + + if(argc >= 3) { + + fd = open(argv[3], O_WRONLY | O_CREAT | O_TRUNC, 0644); + + if(fd >= 0) { + char *s = NULL; + + i = asprintf(&s, "P6\n%d %d\n255\n", width, height); + if(i > 0) write(fd, s, i); + + free(s); + + switch(bits) { + case 8: + for(i = 0, p = img; i < width * height; i++) { + x = *p++; + // 2 3 3 + + z = x >> (4 + 2); + pixel[0] = z * 0x55; + + z = (x >> 3) & 0x07; + pixel[1] = z * 0x24 + (z >> 1); + + z = x & 0x7; + pixel[2] = z * 0x24 + (z >> 1); + + write(fd, &pixel, 3); + } + break; + + case 16: + for(i = 0, p = img; i < width * height; i++) { + x = p[0] + (p[1] << 8); + p += 2; + + // 5 6 5 + + pixel[0] = ((x >> 11) & 0x1f) << 3; + pixel[0] += pixel[0] >> 5; + pixel[1] = ((x >> 5) & 0x3f) << 2; + pixel[1] += pixel[1] >> 6; + pixel[2] = (x & 0x1f) << 3; + pixel[2] += pixel[2] >> 5; + + write(fd, &pixel, 3); + } + break; + + case 24: + for(i = 0, p = img; i < width * height; i++) { + pixel[2] = *p++; + pixel[1] = *p++; + pixel[0] = *p++; + + write(fd, &pixel, 3); + } + break; + + case 32: + for(i = 0, p = img; i < width * height; i++) { + pixel[2] = *p++; + pixel[1] = *p++; + pixel[0] = *p++; + p++; + + write(fd, &pixel, 3); + } + break; + + } + + close(fd); + } + } + + return 0; +} + + |