#!/usr/bin/perl

    require 5.8.8;

    use strict;
    use Encode qw/ encode decode /;

    sub utf8_to_cp932 { encode( "cp932" , decode( "utf8" ,  $_[0] ) ) }
    sub cp932_to_utf8 { encode( "utf8" ,  decode( "cp932" , $_[0] ) ) }

    sub msg { print map { "$_\x0a" } @_ }
    sub err { msg( @_ ) , exit( 1 ) }

    msg( 'zip_u2s' );
    @ARGV || err( '  no input' ) ;
    my $zfn ; { # input file
        $zfn = $ARGV[0] ;
        ( $zfn =~ /^(?:\\|[\00-\x7f\xa0-\xdf]|..)*\\([^\\]+)(?:[.]zip)?$/i ||
          $zfn =~ /\/([^\/]+)(?:[.]zip)?$/i ) && msg( '  input  : '.$1 ) ;
        -f $zfn || err( '  input not exists' ) ;
        open( zfh, '<'.$zfn ) || err( '  input open error' ) ;
        binmode( zfh );
    }
    my $ofn ; { # output file
        $ofn = $zfn ; $ofn =~ s,([.]zip)?$,_sj$&,i ;
        ( $ofn =~ /^(?:\\|[\00-\x7f\xa0-\xdf]|..)*\\([^\\]+)(?:[.]zip)?$/i ||
          $ofn =~ /\/([^\/]+)(?:[.]zip)?$/i ) && msg( '  output : '.$1 ) ;
        open( ofh, '>'.$ofn ) || ( close( zfh ) , err( '  output open error' ) ) ;
        binmode( ofh );
    }
    my ( $buf , $buf_length , %offset ) ; { # buffer
        $buf = "" , $buf_length = 4096 , %offset = () ;
    }

    my ( $fd_size , $fn_size , $ex_size , $cm_size , $dn_fa , $off , $d_size ) ;
    while( ! eof( zfh ) ) {
        $offset{ tell( zfh ) } = tell( ofh ) ;
        read( zfh, $buf,  4 ); print ofh $buf;
        unpack( 'L', $buf ) == 0x04034b50 || last;
        read( zfh, $buf,  2 ); print ofh $buf;
        read( zfh, $buf,  2 ); print ofh $buf;
        unpack( 'S', $buf ) == 0 || err( '  zip format error 1' ) ;
        read( zfh, $buf, 10 ); print ofh $buf;
        read( zfh, $buf,  4 ); print ofh $buf;
        $fd_size = unpack( 'L', $buf );
        read( zfh, $buf,  4 ); print ofh $buf;
        read( zfh, $buf,  2 );
        $fn_size = unpack( 'S', $buf );
        read( zfh, $buf,  2 );
        $ex_size = unpack( 'S', $buf );
        $fn_size < $buf_length || err( '  zip buffer overflow fn 1' ) ;
        $ex_size < $buf_length || err( '  zip buffer overflow ex 1' ) ;
        read( zfh, $buf, $fn_size );
        $buf = utf8_to_cp932( $buf ) ; $fn_size = length( $buf ) ;
        print ofh pack( 'S' , $fn_size ) , pack( 'S' , $ex_size ) , $buf ;
        read( zfh, $buf, $ex_size ); print ofh $buf;
        while( $buf_length < $fd_size && ! eof( zfh ) ) {
            read( zfh, $buf, $buf_length ); print ofh $buf;
            $fd_size -= $buf_length;
        }
        read( zfh, $buf, $fd_size ); print ofh $buf;
    }
    $d_size = - tell( ofh ) ;
    while( ! eof( zfh ) ) {
        unpack( 'L', $buf ) == 0x02014b50 || last;
        read( zfh, $buf, 1 ); print ofh $buf; 
        read( zfh, $buf, 1 );
        unpack( 'C', $buf ) == 10 || unpack( 'C', $buf ) == 3 ||
            err( '  zip format error 2' ) ;
        print ofh pack( 'C', 10 ); 
        read( zfh, $buf, 22 ); print ofh $buf;
        read( zfh, $buf,  2 );
        $fn_size = unpack( 'S', $buf );
        read( zfh, $buf,  2 );
        $ex_size = unpack( 'S', $buf );
        read( zfh, $buf,  2 );
        $cm_size = unpack( 'S', $buf );
        $fn_size < $buf_length || err( '  zip buffer overflow fn 2' ) ;
        $ex_size < $buf_length || err( '  zip buffer overflow ex 2' ) ;
        $cm_size < $buf_length || err( '  zip buffer overflow cm 1' ) ;
        read( zfh, $buf,  8 );
        $dn_fa = $buf ;
        read( zfh, $buf,  4 );
        $off = unpack( 'L', $buf );
        read( zfh, $buf, $fn_size );
        $buf = utf8_to_cp932( $buf ) ; $fn_size = length( $buf ) ;
        $off = $offset{ $off } ;
        print ofh pack( 'S' , $fn_size ) , pack( 'S' , $ex_size ) ;
        print ofh pack( 'S' , $cm_size ) , $dn_fa , pack( 'L' , $off ) , $buf ;
        read( zfh, $buf, $ex_size ); print ofh $buf;
        read( zfh, $buf, $cm_size ); print ofh $buf;
        read( zfh, $buf,  4 ); print ofh $buf;
    }
    $d_size += tell( ofh ) ;
    unpack( 'L', $buf ) == 0x06054b50 || err( '  zip format error eof 1' ) ;
    read( zfh, $buf,  8 ); print ofh $buf;
    read( zfh, $buf,  4 ); print ofh pack( 'L' , $d_size ) ;
    read( zfh, $buf,  4 );
    $off = unpack( 'L', $buf );
    $off = $offset{ $off } ;
    print ofh pack( 'L' , $off ) ;
    read( zfh, $buf,  2 ); print ofh $buf;
    $cm_size = unpack( 'S', $buf );
    $cm_size < $buf_length || err( '  zip buffer overflow cm 2' ) ;
    read( zfh, $buf, $cm_size ); print ofh $buf;
    eof( zfh ) || err( '  zip format error eof 2' ) ;
    close( ofh );
    close( zfh );
    msg( '  finished' );

