#!/usr/bin/perl

use strict;

use Getopt::Std;
use XML::SAX::Writer;
use WAP::SAXDriver::wbxml;

my %opts;
getopts('b', \%opts);

my $path = $INC{'WAP/SAXDriver/wbxml.pm'};
$path =~ s/wbxml\.pm$//i;
$path .= 'syncml.wbrules2.pl';

my $consumer = new XML::SAX::Writer::StringConsumer();
my $handler = new XML::SAX::Writer(Writer => 'MyWriterXML', Output => $consumer);
my $error = new MyErrorHandler();
my $parser = new WAP::SAXDriver::wbxml(Handler => $handler, ErrorHandler => $error, RulesPath => $path);

my $file = $ARGV[0];
die "No input.\n"
		unless ($file);
my $io = new IO::File($file,"r");
die "Can't open $file ($!).\n"
		unless (defined $io);
binmode $io, ":raw";
my $out = $ARGV[1];
if ($out) {
	open STDOUT, "> $out"
			or die "can't open $out ($!).\n";
}

my $doc = $parser->parse(
		Source		=> {ByteStream => $io}
);

if ($opts{b}) {
	print beautify(${$consumer->finalize()});
} else {
	print ${$consumer->finalize()};
}

sub beautify {
	my $out = '';
	my @tab;
	foreach (split /(<[^>']*(?:'[^']*'[^>']*)*>)/, shift) {
		next unless ($_);
		pop @tab if (/^<\//);
		$out .= "@tab$_\n";
		push @tab,'  ' if (/^<[^\/?!]/ and /[^\/]>$/);
	}
	return $out;
}

package MyErrorHandler;

sub new {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    return bless {}, $class;
}

sub fatal_error {
	my $self = shift;
	my ($hash) = @_;
	die __PACKAGE__,": Fatal error\n\tat position $hash->{BytePosition}.\n";
}

sub error {
	my $self = shift;
	my ($hash) = @_;
	warn __PACKAGE__,": Error: $hash->{Message}\n\tat position $hash->{BytePosition}\n";
}

sub warning {
	my $self = shift;
	my ($hash) = @_;
	warn __PACKAGE__,": Warning: $hash->{Message}\n\tat position $hash->{BytePosition}\n";
}

package MyWriterXML;

use base qw(XML::SAX::Writer::XML);

sub characters {
	my $self = shift;
	my $data = shift;
	$self->_output_element;

	my $char = $data->{Data};
	my $first = ord $char;
	if ($first <= 03) {
		# WBXML inner
		my $consumer = new XML::SAX::Writer::StringConsumer();
		my $handler = new XML::SAX::Writer(Output => $consumer);
		my $error = new MyErrorHandler();
		my $parser = new WAP::SAXDriver::wbxml(Handler => $handler, ErrorHandler => $error, RulesPath => $main::path);

		my $doc = $parser->parse(
				Source		=> {String => $char}
		);

		if ($main::opts{b}) {
			$char = '<![CDATA[' . main::beautify(${$consumer->finalize()}) . ']]>';
		} else {
			$char = '<![CDATA[' . ${$consumer->finalize()} . ']]>';
		}
	} else {
		if ($self->{InCDATA}) {
			# we must scan for ]]> in the CDATA and escape it if it
			# is present by close--opening
			# we need to have buffer text in front of this...
			$char = join ']]>]]&lt;<![CDATA[', split ']]>', $char;
		}
		else {
			$char = $self->escape($char);
		}
	}
	$char = $self->{Encoder}->convert($char);
	$self->{Consumer}->output($char);
}

__END__

=head1 NAME

syncmld - SyncML Disassembler

=head1 SYNOPSYS

syncmld [B<-b>] I<file>

=head1 OPTIONS

=over 8

=item -b

Beautify

=back

=head1 DESCRIPTION

B<syncmld> is derived from B<wbxmld>.

WAP Specifications, including Binary XML Content Format (WBXML)
 are available on E<lt>http://www.wapforum.org/E<gt>.

SyncML Specifications are available on E<lt>http://www.syncml.org/E<gt>.

=head1 SEE ALSO

WAP::SAXDriver::wbxml, WAP::wbxml, wbxmlc, wbxmld

=head1 AUTHOR

Francois PERRAD, francois.perrad@gadz.org

=cut
