Jabber-Lite
view release on metacpan or search on metacpan
lib/Jabber/Lite.pm view on Meta::CPAN
}
}
}
=head2 toStr
Returns the object in a single string. Takes an optional hash consisting
of 'FH', being a filehandle reference to send output to instead (useful if
you aren't wanting to copy the object into a local variable), and
'GenClose', which defaults to 1 and ensures that the first tag has the
proper '/' character when closing the tag.
If set to '0', '<stream>' will be output instead of '<stream/>', a highly
important distinction when first connecting to Jabber servers (remember that
a Jabber connection is really one long '<stream>' tag ).
=cut
# Note - since this is a recursive call, there are probably too many
# tests to see whether we have a filehandle. A slight performance
# increase could probably be gained by duplicating the code in
# a seperate function, but that means that two locations for output
# need to be maintained.
sub toStr {
my $self = shift;
my %args = ( FH => undef,
GenClose => 1,
@_, );
my $fh = $args{"FH"};
my $doend = 0;
my $dval = $self->_check_val( '_debug' );
if( $dval ){
$dval = $self->{'_debug'};
}
if( ! $args{"GenClose"} ){
$doend = 1;
}
# Return a string representation of this object.
my $retstr = "";
my $usefh = 0;
my $mustend = 0;
if( defined( $fh ) ){
$usefh = 1;
}
# $self->debug( "toStr starting\n") if( $dval );
if( ! $usefh ){
$retstr = "<" . $self->name();
}else{
print $fh "<" . $self->name();
}
# See if this is actually processing instructions etc.
if( $self->name() =~ /^\[CDATA\[/ ){
if( ! $usefh ){
$retstr .= $self->{'_cdata'} . "]]";
}else{
print $fh $self->{'_cdata'} . "]]";
}
$doend = 1;
}elsif( $self->name() =~ /^\!/ ){
$mustend = 1;
# doctype stuff is special. When we see the
# pattern '\[\s*\]' within, that means that we
# insert, at that point, the 'next' subtag object,
# and so forth. Annoying stuff.
my $tstr = "";
my $tloop = -1;
my $tstrlength = -1;
my $stillgoing = 0;
if( defined( $self->{'_doctype'} ) ){
$tstrlength = length( $self->{'_doctype'} );
$stillgoing = 1;
}
my $nexttag = 0;
my $foundopen = -5;
while( $tloop < $tstrlength && $stillgoing ){
$tloop++;
my $thischar = substr( $self->{'_doctype'}, $tloop, 1 );
if( $thischar eq '[' ){
$tstr .= $thischar;
$foundopen = $tloop;
# Find the next subtag offset.
if( defined( $self->{'_curobjs'} ) ){
if( defined( ${$self->{'_curobjs'}}[$nexttag] ) ){
$tstr .= ${$self->{'_curobjs'}}[$nexttag]->toStr();
$nexttag++;
}
}
}elsif( $foundopen >= 0 && $thischar !~ /^(\s*|\])$/ ){
$tstr .= "]";
$foundopen = -5;
$tstr .= $thischar;
}elsif( $foundopen >= 0 && $thischar eq ']' ){
$foundopen = -5;
$tstr .= $thischar;
}elsif( $foundopen < 0 ){
$tstr .= $thischar;
}
}
if( ! $usefh ){
$retstr .= $tstr;
}else{
print $fh $tstr;
}
$doend = 1;
}elsif( $self->name() =~ /^\?/ ){
if( defined( $self->{'_processinginstructions'} ) ){
if( ! $usefh ){
$retstr .= " " . $self->{'_processinginstructions'};
}else{
print $fh " " . $self->{'_processinginstructions'};
}
}
$mustend = 1;
lib/Jabber/Lite.pm view on Meta::CPAN
# Keep looping until we run out of text.
my $pmloop = 5;
while( $pmloop > 0 && length( $str ) > 0 ){
$pmloop--;
$self->debug( " $pmloop status of $curstatus\n" ) if( $dval );
# First possible - adding to the name. The text received
# is a continuation of the name.
if( $curstatus eq "name" ){
if( $str =~ /^(\S+)(\s+.*)?$/s ){
my $namefurther = $1;
$str = $2;
# Deal with 'dfgdg><dljgdlgj>', which could be
# read as a continuation of the name.
if( $namefurther =~ /^([^\/]*\/>)(.*)$/s ){
$namefurther = $1;
# This juggling is to avoid a warning.
my $r2 = $2;
my $ostr = $str;
$str = "";
if( defined( $r2 ) ){
$str = $r2;
}
if( defined( $ostr ) ){
$str .= $ostr;
}
}elsif( $namefurther =~ /^([^>]*>)(.*)$/s ){
$namefurther = $1;
# This juggling is to avoid a warning.
my $r2 = $2;
my $ostr = $str;
$str = "";
if( defined( $r2 ) ){
$str = $r2;
}
if( defined( $ostr ) ){
$str .= $ostr;
}
}
# Add it to the current name.
$self->{'_name'} .= $namefurther;
# See if we've incorporated a possible end tag into
# this. We do the test on the completed name instead
# of the string received in case we received the
# '/' during the previous call.
# We send it back if we did.
if( $self->{'_name'} =~ /^\!\-\-(.*)$/s ){
# Start processing a comment.
$curstatus = "comment";
$self->{'_name'} = '!--';
$str = $1 . $str;
}elsif( $self->{'_name'} =~ /^(\!\[CDATA\[)(.*)$/ ){
$curstatus = "cdata";
$self->{'_name'} = $1;
$str = $2 . $str;
}elsif( $self->{'_name'} =~ /\/$/s ){
# Possible start of '/>' . Send it back.
# If its actually 'sdlfk//sdf', it'll be
# properly parsed next time.
chop( $self->{'_name'} );
$str = '/' . $str;
$curstatus = "name";
}elsif( $self->{'_name'} =~ /\/>$/s ){
# Definitely bad. Chop off the last
# two characters.
chop( $self->{'_name'} );
chop( $self->{'_name'} );
# Then mark ourselves as being complete.
$self->{'_is_complete'} = 1;
$retval = 1;
$curstatus = "complete";
}elsif( $self->{'_name'} =~ /\?>$/s && $self->{'_name'} =~ /^\?/ ){
# This is 'processing instructions'.
chop( $self->{'_name'} );
chop( $self->{'_name'} );
$curstatus = "complete";
}elsif( $self->{'_name'} =~ />$/s ){
# name is 'sdfj>'. Means that we've reached
# the end of the tag name, but not the end
# of the tag. Remove the '>', and indicate
# what we've got.
chop( $self->{'_name'} );
$curstatus = "subtag";
if( $self->{'_name'} =~ /^\!/ ){
$curstatus = "complete";
}
# This point is good for checking
# whether this name matches the
# one specified as 'expect-incomplete'.
if( defined( $self->{'_expect-incomplete'} ) ){
if( defined( $self->{'_expect-incomplete'}{$self->{'_name'}} ) ){
$curstatus = "complete";
}
}
}elsif( defined( $str ) ){
# We've got a space. The name has been
# completed.
$curstatus = "attribs";
# See if this is special stuff.
if( $self->{'_name'} =~ /^\!/ ){
$curstatus = "doctype";
}elsif( $self->{'_name'} =~ /^\?/s ){
$curstatus = "processinginstructions";
}elsif( $self->{'_name'} =~ /^(\!\[CDATA\[)(.*)$/ ){
$curstatus = "cdata";
$self->{'_name'} = $1;
$str = $2 . $str;
}
}elsif( ! defined( $str ) ){
$str = "";
}
$self->debug( " ($curstatus) Remaining is $str X\n" ) if( $dval );
# A space, indicating the end of the name tag, and onto the
# attributes.
}elsif( $str =~ /^\s+(\S+.*)$/s ){
$str = $1;
$curstatus = "attribs";
}
# Check for comments. Second check in case we missed
# something.
if( $curstatus eq "attribs" ){
if( $self->{'_name'} =~ /^\!\-\-(.*)$/s ){
# Start processing a comment.
$curstatus = "comment";
$str = $1 . $str;
}elsif( $self->{'_name'} =~ /^\!/ ){
$curstatus = "doctype";
}elsif( $self->{'_name'} =~ /^\?/s ){
$curstatus = "processinginstructions";
}elsif( $self->{'_name'} =~ /^(\!\[CDATA\[)(.*)$/ ){
$curstatus = "cdata";
$self->{'_name'} = $1;
$str = $2 . $str;
}
}
# Finally, check for a valid name.
if( $curstatus ne "name" ){
if( $self->{'_name'} !~ /^[A-Za-z][A-Za-z0-9\-\_\:\.]*$/ ){
if( $self->{'_name'} !~ /^(\?|\!)(\S+)/ ){
# Invalid XML!
$retval = -2;
$retstr = $str;
return( $retval, $retstr );
}
}
}
}
# The string is (or is now) text that is stuff with the doctype
# declaration.
if( $curstatus =~ /^(doctype|processinginstructions|cdata)/ ){
my $strlength = ( length( $str ) - 1 );
my $loop = -1;
my $stillgoing = 1;
my $prevquery = -5;
while( $loop < $strlength && $stillgoing ){
$loop++;
my $thischar = substr( $str, $loop, 1 );
if( $curstatus eq "doctype" ){
if( $thischar eq '[' ){
$curstatus = "subtag";
$stillgoing = 0;
$self->{'_doctype'} .= $thischar;
next;
}elsif( $thischar eq '>' ){
$curstatus = "complete";
$stillgoing = 0;
next;
}else{
$self->{'_doctype'} .= $thischar;
next;
}
}elsif( $curstatus eq "processinginstructions" ){
if( $thischar eq '>' ){
$self->{'_processinginstructions'} .= $thischar;
# See if this is the end pattern?
if( $self->{'_processinginstructions'} =~ /\?>$/s ){
$self->{'_processinginstructions'} =~ s/\?>$//sg;
# chomp( $self->{'_processinginstructions'} );
$self->debug( " PI is " . $self->{'_processinginstructions'} . " X " . $str . " X\n" ) if( $dval );
# $loop++;
$curstatus = "complete";
$stillgoing = 0;
}
next;
}elsif( $thischar eq '?' ){
$prevquery = '?';
$self->{'_processinginstructions'} .= $thischar;
}else{
$self->{'_processinginstructions'} .= $thischar;
}
}elsif( $curstatus eq "cdata" ){
if( $thischar eq '>' ){
$self->{'_cdata'} .= $thischar;
# See if this is the end pattern?
if( $self->{'_cdata'} =~ /\]\]>$/s ){
chomp( $self->{'_processinginstructions'} );
chomp( $self->{'_processinginstructions'} );
chomp( $self->{'_processinginstructions'} );
$curstatus = "complete";
$stillgoing = 0;
}
}else{
$self->{'_cdata'} .= $thischar;
}
}
}
# Supply the remaining text to return.
if( $loop < $strlength ){
# Remember that $loop is the character that we
# have read, and $strlength has been decremented
# already. So adding 1 to $loop is ok.
$str = substr( $str, ( $loop + 1 ) );
}else{
$str = "";
}
}
# The string is (or is now) text that is possibly attribute text.
# It gets split up based on spaces.
if( $curstatus =~ /^attrib/ ){
# The attribute text looks like 'dsfkl="dfg dg" dlgkj="dg"',
# with a possible end character as well. At first glance,
# we can split between seperate attribute name=value pairs
# by using whitespace, however whitespace within the
# attribute value is possibly significant. We _must_ keep
# it in place. The next method of doing this is character
# by character, which is a royal pain in the ass to do.
# Since we don't know how big the string is, using
# split( // ) simply duplicates the string. Ugg.
# So we continually use substr to peek at each character
# in turn.
my $strlength = ( length( $str ) - 1 );
my $loop = -1;
my $stillgoing = 1;
my $prevforslash = -5; # Need for a numeric comparison.
my $prevbacslash = -5; # Need for a numeric comparison.
my $whitestart = -5; # Need for a numeric comparison.
my $prevquery = -5; # Need for a numeric comparison.
while( $loop < $strlength && $stillgoing ){
$loop++;
# What are we currently doing? Adding to a current
# attribute or just waiting for a new attribute?
# $curstatus is one of:
# attribs - toss out whitespace, wait for
# next attribute or end marker.
# attrib-n - Finishing up a name, stored in
# '_cur_attrib_name'. Look for '='.
# attrib-s-fooble - Looking for a seperator
# character to save in
# '_cur_attrib_end'
# attrib-v-fooble - Adding data to an attribute,
# saving everything except for
# the value in '_cur_attrib_end'
#
my $thischar = substr( $str, $loop, 1 );
if( $curstatus eq "attribs" ){
( run in 1.690 second using v1.01-cache-2.11-cpan-6aa56a78535 )