Logo Search packages:      
Sourcecode: kbibtex version File versions  Download package

fileimporterbibtex.cpp

/***************************************************************************
*   Copyright (C) 2004-2006 by Thomas Fischer                             *
*   fischer@unix-ag.uni-kl.de                                             *
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
*   This program is distributed in the hope that it will be useful,       *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
*   GNU General Public License for more details.                          *
*                                                                         *
*   You should have received a copy of the GNU General Public License     *
*   along with this program; if not, write to the                         *
*   Free Software Foundation, Inc.,                                       *
*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
***************************************************************************/
#include <qiodevice.h>
#include <qregexp.h>
#include <qtextstream.h>
#include <qapplication.h>

#include <file.h>
#include <comment.h>
#include <macro.h>
#include <entry.h>
#include <element.h>
#include <encoderlatex.h>
#include <value.h>

#include "fileimporterbibtex.h"

namespace BibTeX
{
    const QString extraAlphaNumChars = QString( "?'`-_:.+/$\\\"" );

    FileImporterBibTeX::FileImporterBibTeX() : FileImporter()
    {
        cancelFlag = FALSE;
        m_textStream = NULL;
    }


    FileImporterBibTeX::~FileImporterBibTeX()
    {
        // nothing
    }

    File* FileImporterBibTeX::load( QIODevice *iodevice )
    {
        cancelFlag = FALSE;
        QTextStream rawTextStream( iodevice );
        rawTextStream.setEncoding( QTextStream::UnicodeUTF8 );
        QString rawText = rawTextStream.read();

        rawText = EncoderLaTeX::currentEncoderLaTeX() ->decode( rawText );
        unescapeLaTeXChars( rawText );
        m_textStream = new QTextStream( rawText, IO_ReadOnly );
        m_textStream->setEncoding( QTextStream::UnicodeUTF8 );

        File *result = new File();
        QIODevice *streamDevice = m_textStream->device();
        while ( !cancelFlag && !m_textStream->atEnd() )
        {
            emit progress( streamDevice->at(), streamDevice->size() );
            qApp->processEvents();
            Element * element = nextElement( result );
            if ( element != NULL )
                result->appendElement( element );
            qApp->processEvents();
        }
        emit progress( 100, 100 );

        if ( cancelFlag )
        {
            delete result;
            result = NULL;
        }

        delete m_textStream;
        return result;
    }

    bool FileImporterBibTeX::guessCanDecode( const QString & rawText )
    {
        QString text = EncoderLaTeX::currentEncoderLaTeX() ->decode( rawText );
        return text.contains( QRegExp( "@\\w+\\{.+\\}" ) );
    }


    void FileImporterBibTeX::cancel()
    {
        cancelFlag = TRUE;
    }

    Element *FileImporterBibTeX::nextElement( File *bibtexFile )
    {
        Token token = nextToken();
        while ( token != tAt && token != tPercent )
        {
            if ( token == tEOF )
                return NULL;
            token = nextToken();
        }

        if ( token == tAt )
        {
            QString elementType = readSimpleString();
            //             qDebug( "elementType = \"%s\"", elementType.latin1() );
            if ( elementType.lower() == "comment" )
                return readCommentElement();
            else if ( elementType.lower() == "string" )
                return readMacroElement();
            else if ( elementType.lower() == "preamble" )
                bibtexFile->setPreamble ( readBracketString( currentChar ) );
            else
                return readEntryElement( elementType );
        }
        else if ( token == tPercent )
            return readPercentCommentElement();


        return NULL;
    }

    Comment *FileImporterBibTeX::readCommentElement()
    {
        //         qDebug( "currentChar = %c", currentChar.latin1() );
        while ( currentChar != '{' && currentChar != '(' )
            * m_textStream >> currentChar;

        //         qDebug( "currentChar = %c", currentChar.latin1() );
        return new Comment( readBracketString( currentChar ), FALSE );
    }

    Comment *FileImporterBibTeX::readPercentCommentElement()
    {
        QString result = readLine();
        //         qDebug( "readPercentCommentElement result=%s", result.latin1() );
        *m_textStream >> currentChar;
        while ( currentChar == '%' )
        {
            result.append( '\n' );
            *m_textStream >> currentChar;
            result.append( readLine() );
            //             qDebug( "readPercentCommentElement result=%s", result.latin1() );
            *m_textStream >> currentChar;
        }
        //         qDebug( "readPercentCommentElement finally result=%s", result.latin1() );
        return new Comment( result, TRUE );
    }

    Macro *FileImporterBibTeX::readMacroElement()
    {
        Token token = nextToken();
        while ( token != tBracketOpen )
        {
            if ( token == tEOF )
                return NULL;
            token = nextToken();
        }

        QString key = readSimpleString();
        //         qDebug( "key = \"%s\"", key.latin1() );
        if ( nextToken() != tAssign )
            return NULL;

        Macro *macro = new Macro( key );
        //         token = nextToken();
        do
        {
            QString text;
            bool isStringKey = FALSE;
            text = readString( isStringKey ).replace( QRegExp( "\\s+" ), " " );
            ValueItem *item = new ValueItem( text, isStringKey );
            macro->value() ->add( item );
            token = nextToken();
        }
        while ( token == tDoublecross );

        return macro;
    }

    Entry *FileImporterBibTeX::readEntryElement( const QString& typeString )
    {
        Token token = nextToken();
        while ( token != tBracketOpen )
        {
            if ( token == tEOF )
                return NULL;
            token = nextToken();
        }

        QString key = readSimpleString();
        //         qDebug( "key = \"%s\"", key.latin1() );
        Entry *entry = new Entry( typeString, key );

        token = nextToken();
        do
        {
            if ( token == tBracketClose || token == tEOF )
                break;
            else if ( token != tComma )
            {
                delete entry;
                return NULL;
            }

            QString fieldTypeName = readSimpleString();
            token = nextToken();
            if ( token == tBracketClose )
            {
                // entry is buggy, but we still accept it
                break;
            }
            else if ( token != tAssign )
            {
                delete entry;
                return NULL;
            }

            EntryField *entryField = new EntryField( fieldTypeName );

            do
            {
                QString text;
                bool isStringKey = FALSE;
                text = readString( isStringKey ).replace( QRegExp( "\\s+" ), " " );
                ValueItem *item = new ValueItem( text, isStringKey );
                entryField->value() ->add( item );
                token = nextToken();
            }
            while ( token == tDoublecross );

            entry->addField( entryField );
        }
        while ( TRUE );

        return entry;
    }

    FileImporterBibTeX::Token FileImporterBibTeX::nextToken()
    {
        if ( m_textStream->atEnd() )
            return tEOF;

        Token curToken = tUnknown;

        while ( curToken == tUnknown )
        {
            //             qDebug( "c=%c", currentChar.latin1() );
            switch ( currentChar.latin1() )
            {
            case '@':
                curToken = tAt;
                break;
            case '{':
            case '(':
                curToken = tBracketOpen;
                break;
            case '}':
            case ')':
                curToken = tBracketClose;
                break;
            case ',':
                curToken = tComma;
                break;
            case ';':
                curToken = tSemicolon;
                break;
            case '=':
                curToken = tAssign;
                break;
            case '%':
                curToken = tPercent;
                break;
            case '#':
                curToken = tDoublecross;
                break;
            default:
                if ( m_textStream->atEnd() )
                    return tEOF;
            }

            *m_textStream >> currentChar;
        }

        return curToken;
    }

    QString FileImporterBibTeX::readString( bool &isStringKey )
    {
        if ( currentChar.isSpace() )
        {
            m_textStream->skipWhiteSpace();
            *m_textStream >> currentChar;
        }

        //         qDebug( "currentChar = %c", currentChar.latin1() );

        isStringKey = FALSE;
        switch ( currentChar.latin1() )
        {
        case '{':
        case '(':
            return readBracketString( currentChar );
        case '"':
            return readQuotedString();
        default:
            isStringKey = TRUE;
            return readSimpleString();
        }
    }

    QString FileImporterBibTeX::readSimpleString( QChar until )
    {
        QString result;

        while ( currentChar.isSpace() )
        {
            m_textStream->skipWhiteSpace();
            *m_textStream >> currentChar;
        }

        if ( currentChar.isLetterOrNumber() || extraAlphaNumChars.contains( currentChar ) )
        {
            result.append( currentChar );
            *m_textStream >> currentChar;
        }

        while ( !m_textStream->atEnd() )
        {
            if ( until != '\0' )
            {
                if ( currentChar != until )
                    result.append( currentChar );
                else
                    break;
            }
            else
                if ( currentChar.isLetterOrNumber() || extraAlphaNumChars.contains( currentChar ) )
                    result.append( currentChar );
                else
                    break;
            *m_textStream >> currentChar;
        }
        return result;
    }

    QString FileImporterBibTeX::readQuotedString()
    {
        QString result;
        QChar lastChar = currentChar;
        *m_textStream >> currentChar;
        while ( !m_textStream->atEnd() )
        {
            if ( currentChar != '"' || lastChar == '\\' )
                result.append( currentChar );
            else
                break;
            lastChar = currentChar;
            *m_textStream >> currentChar;
        }

        return result;
    }

    QString FileImporterBibTeX::readLine()
    {
        QString result;
        while ( currentChar != '\n' )
        {
            result.append( currentChar );
            *m_textStream >> currentChar;
        }
        return result;
    }

    QString FileImporterBibTeX::readBracketString( const QChar openingBracket )
    {
        QString result;
        QChar closingBracket = '}';
        if ( openingBracket == '(' )
            closingBracket = ')';
        int counter = 1;
        *m_textStream >> currentChar;
        while ( !m_textStream->atEnd() )
        {
            //             qDebug( "%c ?= %c", currentChar.latin1(), openingBracket.latin1() );
            if ( currentChar == openingBracket )
                counter++;
            else if ( currentChar == closingBracket )
                counter--;

            if ( counter == 0 )
                break;
            else
                result.append( currentChar );
            *m_textStream >> currentChar;
        }
        *m_textStream >> currentChar;
        return result;
    }

    void FileImporterBibTeX::unescapeLaTeXChars( QString &text )
    {
        text.replace( "\\&", "&" );
    }
}

Generated by  Doxygen 1.6.0   Back to index