Symbian/SysDefToText/SysDefParser.pm
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Sat, 20 Feb 2010 00:39:01 +0200
branchRCL_3
changeset 6 c8ecf89eb77f
parent 0 beb51793110d
permissions -rw-r--r--
Revision: 201004 Kit: 201007

#
# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
# All rights reserved.
# This component and the accompanying materials are made available
# under the terms of "Eclipse Public License v1.0"
# which accompanies this distribution, and is available
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
#
# Initial Contributors:
# Nokia Corporation - initial contribution.
#
# Contributors:
#
# Description:
#
#-------------------------------------------------------------------------------
# package: SysDefParser
#
# usage: Wrapper for an XML parser to dispatch callbacks to a client object which
#    analyses the parsed XML data. The auxiliary package SysDefParser::Dispatcher
#    acts as an intermediary between the parser and the client to convert function
#    callbacks to method callbacks using perl's AUTOLOAD mechanism.
#
# public methods:
#
#    new(-client => <client reference>, [-parser => <package name>]) : creates a
#        instance. <client reference> is the instance to which the parser callbacks
#        are dispatched. <package name> is an optional alternative parser client
#        package to use instead of the default XML::Parser class.
#
#    parse(<fileh>): parse the XML data from filehandle <fileh> dispatching
#        callbacks to the client object.
#         
#-------------------------------------------------------------------------------

package SysDefParser;
use strict;

sub new
{
    my ($class, %args) = @_;
    my $self = bless {}, $class;
    $self->{client} = delete $args{-client};

    if (exists $args{-parser})
    {
        $args{Pkg} = 'SysDefParser::Dispatcher';
        require $args{-parser};
        $self->{parser} = $args{-parser}->createParser(%args);
    }
    else
    {
        $self->{parser} = $class->_createParser(%args);
    }

    return $self;
}

sub _createParser
{
    my ($class, %args) = @_;
    require XML::Parser;
    return XML::Parser->new
           (
               Style        => 'Subs',
               Pkg          => 'SysDefParser::Dispatcher',
               ErrorContext => 2
           );
}

my $PARSERCLIENT = undef;

sub _client { return $PARSERCLIENT; }

sub parse
{
    my ($self, $fileh) = @_;

    # we can't pass any context down to the underlying parser so that we can work out which
    # object any callbacks from the parser are associated with so, assuming that the parser will
    # not be called in a re-entrant fashion, we store the context at this point, so that we can
    # then dispatch the callbacks from the parsers 'parse' method to those methods of the saved
    # $PARSERCLIENT instance.

    die "Fatal: client object not set\n" if ! defined $self->{client};
    die "Fatal: parser client object already set\n" if defined $PARSERCLIENT;
    $PARSERCLIENT = $self->{client};

    # call the parser, callbacks will be dispatched to sub AUTOLOAD in SysDefParser::Dispatcher

    my $rv =$self->{parser}->parse($fileh);

    # finished parsing, unset the context

    $PARSERCLIENT = undef;

    return $rv;
}

#-------------------------------------------------------------------------------
# package SysDefParser::Dispatcher
#
# usage: Internal package. Uses AUTOLOAD mechanism to receive parser callbacks and
#    convert them to object method calls on teh client object.
#
#-------------------------------------------------------------------------------
package SysDefParser::Dispatcher;
use strict;

sub AUTOLOAD
{
    my @ARGS = @_;

    my $client = SysDefParser::_client();

    die "Fatal: parser client object not set\n" if ! defined $client;

    # translate the called back function name to the client method name
    my $clientpkg = ref($client);
    my $method = $SysDefParser::Dispatcher::AUTOLOAD;

    $method =~ s/^SysDefParser::Dispatcher/$clientpkg/;

    # dispatch the parser's callback to the client object (if implemented by client)
    $client->$method(@ARGS) if $client->can($method);
}

#-------------------------------------------------------------------------------
# -EOF-
#-------------------------------------------------------------------------------
1;