#! /usr/bin/perl



;# ↑ ◎ Perl処理系の[パス]  分からない場合はプロバイダに確認。

;#

;#   画像/テキスト対応アクセスカウンタ [CGIカウンタ] ver.1.01 (Free)

;#   Copyright(C)2001 WiS. All Rights Reserved.

;#



;# gifcat.pl: GIFファイル連結ライブラリ Ver1.57

;# Copyright (c) 1997,2000 http://wakusei.cplaza.ne.jp/twn/



#-----------------------------------------------------------------------------#

# ここから初期設定（サーバーへの設置方法は同梱の'readme.txt'をご覧ください）  #

#-----------------------------------------------------------------------------#

#

#   ●印の項目は必ず変更してください。

#   ○印の項目は主にレイアウト関連です。基本的に変更不要です。

#   △印の項目は上の項目を有効にしている場合のみ設定してください。

#   ◎印の項目はサーバー環境によって変更する必要があります。（1行目も含みます）

#

#  ・ ''内に記述しますが、'を入れたい場合は 中の'は \'にしてください。

#  ・ 行の頭に"#"を付けると、その行は無効になります。(コメントアウト)

#  ・ "$"、";"、"="等は間違って消さないようにしてください。エラーになります。

#  ・ 詳しくは本サイトの解説/FAQ等を参照してください。





# ○ ファイルロック [1:使う／0:使わない]

#    * 通常は使うを設定しておく。(mkdir方式ロック)

$uselock = 1;



# ○ 同一IPから一定時間カウントしない場合の有効[時間]

#    * 同一IP排除を使わない場合は0にする

$expires = 1;



# ○ 時間帯 (GMT=英国ロンドンとの時差 日本は9時間)

$time_zone = 9;



# ○ 日計カウンタを [1:取る／0:取らない]

#    * "*.count.daily"の名前で保存されます。

$daily_count = 0;





#---<パスについて>-------------------------------------------------------------

#

#  ・ パスとはサーバー内での場所です。httpで始まるURIとは違うものです。

#  ・ 相対パスとはスクリプトの場所を基準としたパスの指定です。

#      ../ => 1つ上のディレクトリ  ./ => 同じディレクトリ

#  ・ 絶対パスとはサーバー内の一番上のディレクトリを基準としたパスの指定です。

#      /usr/lib/sendmail  /home/foo/public_html/cgi-bin/script.cgi

#  ・ 仮想アドレスとはURIの一部分(ドメイン名以降)を指します。

#     http://www.domain.com/~foo/cgi-bin/script.cgi

#                          ^ ドメイン名の後のスラッシュ"/"以降の部分

#                             (/~foo/cgi-bin/script.cgi のこと)





# ○ 画像ファイルのあるディレクトリの[パス]

$imag_dir = 'img/';



# ○ カウンタ値を保存するファイルのディレクトリの[パス]

$data_dir = 'data/';



# ○ カウンターを貼り付けるページのURLの一部

#    * 外部からの利用を防止する場合に設定します。

#    * 複数のサイトから利用する場合は、"|"で区切ります。

#$set_url = 'maruseisisyu.com';





#-----------------------------------------------------------------------------#

# 初期設定ここまで (以下、修正不要。変更した場合は動作未保証＆サポート対象外) #

#-----------------------------------------------------------------------------#



$expires *= 3600;



onError('OK') if ($ENV{'QUERY_STRING'} eq "");



#  今日の日付を取得

{

    local(@time) = gmtime(time + 3600 * $time_zone);

    $now_date = sprintf("%04d/%02d/%02d", $time[5]+1900, $time[4]+1, $time[3]);

}



#  クエリー文字列を取得

foreach (split /;/, $ENV{'QUERY_STRING'}) {

    local($key, $val) = split /=/, $_, 2;

    $STDIN{$key} = $val;

}



#  セキュリティー対策

&onError('パラメーターの値が不正です') if ($STDIN{'ID'}  =~ /(^\/|\.\.|[^\w\-\.\/])/);

&onError('パラメーターの値が不正です') if ($STDIN{'IMG'} =~ /(^\/|\.\.|[^\w\-\.\/])/);



if ($set_url && $ENV{'HTTP_USER_AGENT'} !~ /^DoCoMo/) {

    $set_url =~ s/\./\\./g;

    $SENV{'HTTP_REFERER'} = $ENV{'HTTP_REFERER'};

    $SENV{'HTTP_REFERER'} =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

    if ($SENV{'HTTP_REFERER'} !~ /$set_url/i) {

        &onError('HTTP_REFERERの値が不正です');

    }

}



$STDIN{'ID'} = 'default' if ($STDIN{'ID'} eq "");

$file = $data_dir . $STDIN{'ID'} . ".count";

$imag_dir .= $STDIN{'IMG'};



#  クッキー取得

foreach (split /;/o, $ENV{'HTTP_COOKIE'}) {

    local($key, $val) = split /=/o, $_, 2;

    $key =~ s/ //g;

    if ($key eq $STDIN{'ID'}) {

        $visit = $val;

        last;

    }

}



count: {



    last count if ($STDIN{'TYPE'} eq 'visit');

    if (-f $file) {



        if ($STDIN{'TYPE'} eq 'today' || $STDIN{'TYPE'} eq 'ysday') {

            onError('busy') if (!&lockCheck($file, $uselock));

        } elsif (!&lock($file, $uselock)) {

            onError('busy');

        }

        onError('ファイルの読み込みに失敗しました') if (!open(IN, $file));

        ($total, $today, $ysday, $save_date) = split /\t/, <IN>;



        last count if ($STDIN{'TYPE'} eq 'today' || $STDIN{'TYPE'} eq 'ysday');



        if ($expires) {

            last count if (!&logicalLock("$file.adr", $expires, $ENV{'REMOTE_ADDR'}, $ENV{'HTTP_USER_AGENT'}));

        }



        #  カウント

        $total ++;

        if ($save_date ne $now_date) {

            $ysday = $today;

            $today = 1;

            if ($daily_count) {

                if (open(OUT, ">>$file.daily")) {

                    print OUT "$save_date\t$ysday\n";

                    close(OUT);

                }

            }

        } else {

            $today ++;

        }



    #  初めてのカウント

    } else {

        $total = $today = 1;

        $ysday = 0;



        onError('busy') if (!&lock($file, $uselock));

    }



    #  ファイル更新

    onError('ファイルの書き込みに失敗しました') if (!open(OUT, ">$file"));

    print OUT "$total\t$today\t$ysday\t$now_date";

    close(OUT);



}



&unlock($uselock);



if ($visit =~ /\d+/ || $visit < 0 || $visit > 1000000) {

    $visit ++ if ($STDIN{'TYPE'} ne 'today' && $STDIN{'TYPE'} ne 'ysday' && $STDIN{'TYPE'} ne 'visit')

} else {

    $visit = 1;

}





if ($STDIN{'TYPE'} eq 'today') {

    $count = $today;

} elsif ($STDIN{'TYPE'} eq 'ysday') {

    $count = $ysday;

} elsif ($STDIN{'TYPE'} eq 'visit') {

    $count = $visit;

} else {

    $count = $total;

}



$count = sprintf("%0$STDIN{'FIG'}d", $count) if ($STDIN{'FIG'} > 4 && $STDIN{'FIG'} < 12);



if ($STDIN{'IMG'} eq 'text') {

    if ($STDIN{'FIG'} == -1) { 1 while $count =~ s/(\d+)(\d{3})/$1,$2/; }

    print "Content-Type: application/x-javascript\n";

    print "Set-Cookie: $STDIN{'ID'}=$visit; expires=" . gmtime(time + 86400 * 30) . " GMT; \n";

    print "\n";

    print qq|document.write('$count');|;

    exit(0);

} elsif (!-d $imag_dir) {

    &onError('画像ディレクトリが存在しません');

}



if ($STDIN{'FIG'} == -1) { 1 while $count =~ s/(\d+)(\d{3})/$1c$2/; }

foreach (split //, $count) {

    push(@img, "$imag_dir$_.gif") if (-f "$imag_dir$_.gif");

}



$gifdata = &gifcat'gifcat(@img);



binmode(STDOUT);

print "Content-Type: image/gif\n";

print "Content-Length: " . length($gifdata) . "\n";

print "Set-Cookie: $STDIN{'ID'}=$visit; expires=" . gmtime(time + 86400 * 30) . " GMT; \n";

print "\n";

print $gifdata;



exit(0);





sub onError #($_)

{

    local($_) = $_[0];

    

    print "Content-Type: text/plain\n";

    print "\n";

    print;



    exit(0);

}



sub lockCheck #($file_name, $use_lock)

{

    local($file_name, $use_lock) = @_;

    local($lockFlag) = $file_name . ".lock";

    local($i) = 0;



    return 1 if (!$use_lock);

    rmdir($lockFlag) if (-d $lockFlag && time - (stat($lockFlag))[9] > 60);

    while (-d $lockFlag) {

        select(undef, undef, undef, 1);

        return 0 if (++ $i >= 3);

    }

    return 1;

}



sub lock #($file_name, $use_lock)

{

    local($file_name, $use_lock) = @_;

    local($lock_flag) = $file_name . ".lock";



    if ($use_lock) {

        local($i) = 0;

        return -1 if (!-d $file_name);

        rmdir($lock_flag) if (-d $lock_flag && time - (stat($lock_flag))[9] > 60);

        while(!mkdir($lock_flag, 0755)) {

            select(undef, undef, undef, 1);

            return 0 if (++ $i >= 3);

        }

        return 1;

    }

    return 1;

}



sub unlock

{

    rmdir("$_[0].lock") if (-d "$_[0].lock");

}



sub logicalLock #($file_name, $timeout, @recode)

{

    local($file_name, $timeout, @record) = @_;

    local($flag) = 1;

    local(@array);



    if (!-s $file_name || time - (stat($file_name))[9] > $timeout) {

        $flag = 1;

    } elsif (-s $file_name && open(IN, $file_name)) {

        while (<IN>) {

            s/\r\n|\r|\n//;

            local($time, @field) = split /\t/o;

            if ($flag) {

                for (0 .. $#record) {

                    if ($record[$_] eq $field[$_]){

                        $flag = 0;

                    } else {

                        $flag = 1;

                        last;

                    }

                }

                if (!$flag && time - $time > $timeout) {

                    $flag = 1;

                }

            } elsif (time - $time > $timeout) {

                $timeout = 1;

                next;

            }

            push(@array, "$_\n");

        }

        close(IN);

    }

    unshift(@array, time . "\t" . join("\t", @record) . "\n") if ($flag);

    if ($flag || $timeout) {

        return -1 if (!open(OUT, ">$file_name"));

        print OUT join "", @array;

        close(OUT);

    }

    return $flag;

}





;# ====================================================================

;#

;# gifcat.pl: GIFファイル連結ライブラリ Ver1.57

;#

;# Copyright (c) 1997,2000 http://wakusei.cplaza.ne.jp/twn/

;#

;# 著作権は放棄しませんが、自由に使用・改造・再配布可能です。

;#

;# 基本的な使い方

;#    require "gifcat.pl";

;#    open(OUT, "> out.gif");

;#    binmode(OUT);    # MS-DOS や Windows の場合に必要です。

;#    print OUT &gifcat'gifcat("xx.gif", "yy.gif", "zz.gif");

;#    close(OUT);

;#

;# デバッグ用(GIFの解析出力)

;#    require "gifcat.pl";

;#    &gifcat'gifprint("xx.gif", "yy.gif", "zz.gif");

;#

;# 制限事項

;#    アニメGIF同士を連結することはできません。

;#    アニメGIF対応のブラウザでなければ、最初の画像しか表示されません。

;#    高さの異なるGIFファイルは連結できません。

;#

;# 最新版入手先

;#    http://wakusei.cplaza.ne.jp/twn/cgi-bin/gifcat.txt

;#

;# 更新履歴:

;#    1997.05.03 初版。

;#    1997.05.10 スペルミス修正。

;#    1997.05.29 サイズの異なるカラーテーブルに対応。

;#    1997.07.07 エラー発生時にexit()しないように修正。

;#    1998.05.05 Trailerを持たないGIFファイルを連結できないバグを修正。

;#    1998.05.05 横幅が256を超えるGIFの出力ができないバグを修正。

;#    1998.05.05 gifprint()で連結結果を出力しないように修正。

;#    1998.05.10 連結できないGIF画像があるというバグを修正。

;#    1998.08.20 Ver1.50 変数の初期化を行うように修正。

;#    1998.08.20 Ver1.50 透過GIFに対応。

;#    1999.05.30 Ver1.51 動作には関係ないタイプミス修正。

;#    1999.10.11 Ver1.52 コメントの修正

;#    2000.05.21 Ver1.53 幅の異なるGIFの連結に対応

;#    2000.06.04 Ver1.54 perl -wcのwarning対応

;#    2000.06.04 Ver1.55 インタレースGIF部のコードミスを修正。

;#    2000.09.17 Ver1.56 連続呼び出しの際のバグ修正

;#    2000.11.28 Ver1.57 インタレースGIF部のコードミスを修正。

;#

;# ====================================================================



package gifcat;



$pflag = 0;

$LeftPos = 0;

$logicalScreenWidth = 0;

$logicalScreenHeight = 0;



;# =====================================================

;# gifcat'gifprint() - print out GIF diagnostics.

;# =====================================================

sub gifprint {

    $pflag = 1;

    &gifcat(@_);

}



;# =====================================================

;# gifcat'gifcat() - get a concatenated GIF image.

;# =====================================================

sub gifcat {

    @files = @_;

    $Gif = 0;

    $useLocalColorTable = 0;

    for $file (@files) {

        $size = -s $file;

        open(IN, "$file");

        binmode(IN);

        sysread(IN, $buf, $size);

        close(IN);



        $cnt = 0;

        &GifHeader();

        while (1) {

            $x1 = ord(substr($buf, $cnt, 1));

            if ($x1 == 0x2c) {

                &ImageBlock();

            } elsif ($x1 == 0x21) {

                $x2 = ord(substr($buf, $cnt + 1, 1));

                if ($x2 == 0xf9) {

                    &GraphicControlExtension();

                } elsif ($x2 == 0xfe) {

                    &CommentExtension();

                } elsif ($x2 == 0x01) {

                    &PlainTextExtension();

                } elsif ($x2 == 0xff) {

                    &ApplicationExtension();

                } else {

                    return("ERROR");

                }

            } elsif ($x1 == 0x3b) {

                &Trailer();

                last;

            } elsif ($cnt == $size) {

                last;

            } else {

                return("ERROR");

            }

        }



        undef($buf);

        $Gif++;

    }

    if ($pflag == 1) {

        return;

    }



    $GifImage = "GIF89a";

    $GifImage .= pack("C", $logicalScreenWidth & 0x00ff);

    $GifImage .= pack("C", ($logicalScreenWidth & 0xff00) >> 8);

    $GifImage .= pack("C", $logicalScreenHeight & 0x00ff);

    $GifImage .= pack("C", ($logicalScreenHeight & 0xff00) >> 8);

    if ($useLocalColorTable) {

        $PackedFields18[0] &= ~0x80;

    }

    $GifImage .= pack("C", $PackedFields18[0]);

    $GifImage .= pack("C", $BackgroundColorIndex);

    $GifImage .= pack("C", $PixelAspectRatio);

    if ($useLocalColorTable == 0) {

        $GifImage .= $globalColorTable[0];

    }

    for ($i = 0; $i < $Gif; $i++) {

        $GifImage .= pack("CCC", 0x21, 0xf9, 0x04);

        $GifImage .= pack("C", $PackedFields23 | $TransparentColorFlag[$i]);

        $GifImage .= pack("CC", 0x00, 0x00);

        $GifImage .= pack("C", $TransparentColorIndex[$i]);

        $GifImage .= pack("C", 0x00);

        $GifImage .= pack("C", 0x2c);

        $n = $LeftPos;

        $LeftPos += $ImageWidth[$i];

        $GifImage .= pack("C", $n & 0x00ff);

        $GifImage .= pack("C", ($n & 0xff00) >> 8);

        $GifImage .= pack("CC", 0x00, 0x00);

        $GifImage .= pack("C", $ImageWidth[$i] & 0x00ff);

        $GifImage .= pack("C", ($ImageWidth[$i] & 0xff00) >> 8);

        $GifImage .= pack("C", $ImageHeight & 0x00ff);

        $GifImage .= pack("C", ($ImageHeight & 0xff00) >> 8);

        if ($useLocalColorTable) {

            $PackedFields20[$i] |= 0x80;

            $PackedFields20[$i] &= ~0x07;

            $PackedFields20[$i] |= ($PackedFields18[$i] & 0x07);

            $GifImage .= pack("C", $PackedFields20[$i]);

            $GifImage .= $globalColorTable[$i];

        } else {

            $GifImage .= pack("C", $PackedFields20[$i]);

        }

        $GifImage .= pack("C", $LzwMinimumCodeSize[$i]);

        $GifImage .= $ImageData[$i];

    }

    $GifImage .= pack("C", 0x3b);



}



;# =====================================

;# GifHeader

;# =====================================

sub GifHeader {

    $Signature = substr($buf, $cnt, 3); $cnt += 3;

    $Version   = substr($buf, $cnt, 3); $cnt += 3;

    $LogicalScreenWidth

            = ord(substr($buf, $cnt + 0, 1))

            + ord(substr($buf, $cnt + 1, 1)) * 256; $cnt += 2;

    $LogicalScreenHeight

            = ord(substr($buf, $cnt + 0, 1))

            + ord(substr($buf, $cnt + 1, 1)) * 256; $cnt += 2;

    $PackedFields18[$Gif]   = ord(substr($buf, $cnt, 1)); $cnt++;

    $GlobalColorTableFlag   = ($PackedFields18[$Gif] & 0x80) >> 7;

    $ColorResolution    = (($PackedFields18[$Gif] & 0x70) >> 4) + 1;

    $SortFlag       = ($PackedFields18[$Gif] & 0x08) >> 3;

    $SizeOfGlobalColorTable = 2 ** (($PackedFields18[$Gif] & 0x07) + 1);

    $BackgroundColorIndex   = ord(substr($buf, $cnt, 1)); $cnt++;

    $PixelAspectRatio   = ord(substr($buf, $cnt, 1)); $cnt++;

    if ($GlobalColorTableFlag) {

        $GlobalColorTable 

            = substr($buf, $cnt, $SizeOfGlobalColorTable * 3);

        $cnt += $SizeOfGlobalColorTable * 3;

    }



    $logicalScreenWidth += $LogicalScreenWidth;

    if ($logicalScreenHeight < $LogicalScreenHeight) {

        $logicalScreenHeight = $LogicalScreenHeight;

    }

    if ($GlobalColorTableFlag) {

        $globalColorTable[$Gif] = $GlobalColorTable;

        if ($Gif > 0) {

            if ($GlobalColorTable ne $globalColorTable[$Gif - 1]) {

                $useLocalColorTable = 1;

            }

        }

    }



    if ($pflag) {

        printf("=====================================\n");

        printf("GifHeader\n");

        printf("=====================================\n");

        printf("Signature:                     %s\n", $Signature);

        printf("Version:                       %s\n", $Version);

        printf("Logical Screen Width:          %d\n", $LogicalScreenWidth);

        printf("Logical Screen Height:         %d\n", $LogicalScreenHeight);

        printf("Global Color Table Flag:       %d\n", $GlobalColorTableFlag);

        printf("Color Resolution:              %d\n", $ColorResolution);

        printf("Sort Flag:                     %d\n", $SortFlag);

        printf("Size of Global Color Table:    %d\n", $SizeOfGlobalColorTable);

        printf("Background Color Index:        %d\n", $BackgroundColorIndex);

        printf("Pixel Aspect Ratio:            %d\n", $PixelAspectRatio);

        printf("Global Color Table:            ...\n");

    }

}



;# =====================================

;# Image Block

;# =====================================

sub ImageBlock {

    $ImageSeparator    = ord(substr($buf, $cnt, 1)); $cnt++;

    $ImageLeftPosition = ord(substr($buf, $cnt, 1))

               + ord(substr($buf, $cnt + 1, 1)) * 256; $cnt += 2;

    $ImageTopPosition  = ord(substr($buf, $cnt, 1))

               + ord(substr($buf, $cnt + 1, 1)) * 256; $cnt += 2;

    $ImageWidth[$Gif]  = ord(substr($buf, $cnt, 1))

               + ord(substr($buf, $cnt + 1, 1)) * 256; $cnt += 2;

    $ImageHeight       = ord(substr($buf, $cnt, 1))

               + ord(substr($buf, $cnt + 1, 1)) * 256; $cnt += 2;

    $PackedFields20[$Gif]  = ord(substr($buf, $cnt, 1)); $cnt++;

    $LocalColorTableFlag   = ($PackedFields20[$Gif] & 0x80) >> 7;

    $InterlaceFlag     = ($PackedFields20[$Gif] & 0x40) >> 6;

    $SortFlag          = ($PackedFields20[$Gif] & 0x20) >> 5;

    $Reserved          = ($PackedFields20[$Gif] & 0x18) >> 3;

    $SizeOfLocalColorTable = 2 ** (($PackedFields20[$Gif] & 0x07) + 1);

    if ($LocalColorTableFlag) {

        $cnt += $SizeOfLocalColorTable * 3;

    }

    $LzwMinimumCodeSize[$Gif] = ord(substr($buf, $cnt, 1)); $cnt++;

    $ImageData[$Gif] = &DataSubBlock();



    if ($pflag) {

        printf("=====================================\n");

        printf("Image Block\n");

        printf("=====================================\n");

        printf("Image Separator:               0x%02x\n", $ImageSeparator);

        printf("Image Left Position:           %d\n", $ImageLeftPosition);

        printf("Image Top Position:            %d\n", $ImageTopPosition);

        printf("Image Width:                   %d\n", $ImageWidth[$Gif]);

        printf("Image Height:                  %d\n", $ImageHeight);

        printf("Local Color Table Flag:        %d\n", $LocalColorTableFlag);

        printf("Interlace Flag:                %d\n", $InterlaceFlag);

        printf("Sort Flag:                     %d\n", $SortFlag);

        printf("Reserved:                      --\n");

        printf("Size of Local Color Table:     %d\n", $SizeOfLocalColorTable);

        printf("Local Color Table:             ...\n");

        printf("LZW Minimum Code Size:         %d\n", $LzwMinimumCodeSize[$Gif]);

        printf("Image Data:                    ...\n");

        printf("Block Terminator:              0x00\n");

    }

}



;# =====================================

;# Graphic Control Extension

;# =====================================

sub GraphicControlExtension {

    $ExtensionIntroducer   = ord(substr($buf, $cnt, 1)); $cnt++;

    $GraphicControlLabel   = ord(substr($buf, $cnt, 1)); $cnt++;

    $BlockSize         = ord(substr($buf, $cnt, 1)); $cnt++;

    $PackedFields23        = ord(substr($buf, $cnt, 1)); $cnt++;

    $Reserved          = ($PackedFields23 & 0xe0) >> 5;

    $DisposalMethod        = ($PackedFields23 & 0x1c) >> 5;

    $UserInputFlag     = ($PackedFields23 & 0x02) >> 1;

    $TransparentColorFlag[$Gif]  = $PackedFields23 & 0x01;

    $DelayTime         = ord(substr($buf, $cnt, 1))

                   + ord(substr($buf, $cnt+1, 1)) * 256; $cnt += 2;

    $TransparentColorIndex[$Gif] = ord(substr($buf, $cnt, 1)); $cnt++;

    $BlockTerminator       = ord(substr($buf, $cnt, 1)); $cnt++;



    if ($pflag) {

        printf("=====================================\n");

        printf("Graphic Control Extension\n");

        printf("=====================================\n");

        printf("Extension Introducer:          0x%02x\n", $ExtensionIntroducer);

        printf("Graphic Control Label:         0x%02x\n", $GraphicControlLabel);

        printf("Block Size:                    %d\n", $BlockSize);

        printf("Reserved:                      --\n");

        printf("Disposal Method:               %d\n", $DisposalMethod);

        printf("User Input Flag:               %d\n", $UserInputFlag);

        printf("Transparent Color Flag:        %d\n", $TransparentColorFlag[$Gif]);

        printf("Delay Time:                    %d\n", $DelayTime);

        printf("Transparent Color Index:       %d\n", $TransparentColorIndex[$Gif]);

        printf("Block Terminator:              0x00\n");

    }

}



;# =====================================

;# Comment Extension

;# =====================================

sub CommentExtension {

    $ExtensionIntroducer   = ord(substr($buf, $cnt, 1)); $cnt++;

    $CommentLabel      = ord(substr($buf, $cnt, 1)); $cnt++;

    &DataSubBlock();



    if ($pflag) {

        printf("=====================================\n");

        printf("Comment Extension\n");

        printf("=====================================\n");

        printf("Extension Introducer:          0x%02x\n", $ExtensionIntroducer);

        printf("Comment Label:                 0x%02x\n", $CommentLabel);

        printf("Comment Data:                  ...\n");

        printf("Block Terminator:              0x%02x\n", $BlockTerminator);

    }

}



;# =====================================

;# Plain Text Extension

;# =====================================

sub PlainTextExtension {

    $ExtensionIntroducer  = ord(substr($buf, $cnt, 1)); $cnt++;

    $PlainTextLabel       = ord(substr($buf, $cnt, 1)); $cnt++;

    $BlockSize        = ord(substr($buf, $cnt, 1)); $cnt++;

    $TextGridLeftPosition = ord(substr($buf, $cnt, 1))

                  + ord(substr($buf, $cnt + 1, 1)) * 256; $cnt += 2;

    $TextGridTopPosition  = ord(substr($buf, $cnt, 1))

                  + ord(substr($buf, $cnt + 1, 1)) * 256; $cnt += 2;

    $TextGridWidth    = ord(substr($buf, $cnt, 1))

                  + ord(substr($buf, $cnt + 1, 1)) * 256; $cnt += 2;

    $TextGridHeight       = ord(substr($buf, $cnt, 1))

                  + ord(substr($buf, $cnt + 1, 1)) * 256; $cnt += 2;

    $CharacterCellWidth   = ord(substr($buf, $cnt, 1)); $cnt++;

    $CharacterCellHeight  = ord(substr($buf, $cnt, 1)); $cnt++;

    $TextForegroundColorIndex = ord(substr($buf, $cnt, 1)); $cnt++;

    $TextBackgroundColorIndex = ord(substr($buf, $cnt, 1)); $cnt++;

    &DataSubBlock();



    if ($pflag) {

        printf("=====================================\n");

        printf("Plain Text Extension\n");

        printf("=====================================\n");

        printf("Extension Introducer:        0x%02x\n", $ExtensionIntroducer);

        printf("Plain Text Label:            0x%02x\n", $PlainTextLabel);

        printf("Block Size:                  0x%02x\n", $BlockSize);

        printf("Text Grid Left Position:     %d\n", $TextGridLeftPosition);

        printf("Text Grid Top Position:      %d\n", $TextGridTopPosition);

        printf("Text Grid Width:             %d\n", $TextGridWidth);

        printf("Text Grid Height:            %d\n", $TextGridHeight);

        printf("Text Foreground Color Index: %d\n", $TextForegroundColorIndex);

        printf("Text Background Color Index: %d\n", $TextBackgroundColorIndex);

        printf("Plain Text Data:             ...\n");

        printf("Block Terminator:            0x00\n");

    }

}



;# =====================================

;# Application Extension

;# =====================================

sub ApplicationExtension {

    $ExtensionIntroducer       = ord(substr($buf, $cnt, 1)); $cnt++;

    $ExtentionLabel            = ord(substr($buf, $cnt, 1)); $cnt++;

    $BlockSize             = ord(substr($buf, $cnt, 1)); $cnt++;

    $ApplicationIdentifire     = substr($buf, $cnt, 8); $cnt += 8;

    $ApplicationAuthenticationCode = substr($buf, $cnt, 3); $cnt += 3;

    &DataSubBlock();



    if ($pflag) {

        printf("=====================================\n");

        printf("Application Extension\n");

        printf("=====================================\n");

        printf("Extension Introducer:          0x%02x\n",

            $ExtensionIntroducer);

        printf("Extension Label:               0x%02x\n",

            $PlainTextLabel);

        printf("Block Size:                    0x%02x\n",

            $BlockSize);

        printf("Application Identifire:        ...\n");

        printf("ApplicationAuthenticationCode: ...\n");

        printf("Block Terminator:              0x00\n");

    }

}



;# =====================================

;# Trailer

;# =====================================

sub Trailer {

    $cnt++;



    if ($pflag) {

        printf("=====================================\n");

        printf("Trailer\n");

        printf("=====================================\n");

        printf("Trailer:                       0x3b\n");

        printf("\n");

    }

}



;# =====================================

;# Data Sub Block

;# =====================================

sub DataSubBlock {

    local($n, $from);

    $from = $cnt;

    while ($n = ord(substr($buf, $cnt, 1))) {

        $cnt++;

        $cnt += $n;

    }

    $cnt++;

    return(substr($buf, $from, $cnt - $from));

}

