<commit_before>/*************************************************************************
 *
 *  $RCSfile: document.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: obo $ $Date: 2004-11-16 12:20:43 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2004 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _DOCUMENT_HXX
#define _DOCUMENT_HXX

#include <list>
#include <sal/types.h>
#include <cppuhelper/implbase1.hxx>
#include <cppuhelper/implbase2.hxx>
#include <com/sun/star/uno/Reference.h>
#include <com/sun/star/uno/Exception.hpp>
#include <com/sun/star/xml/dom/XNode.hpp>
#include <com/sun/star/xml/dom/XAttr.hpp>
#include <com/sun/star/xml/dom/XElement.hpp>
#include <com/sun/star/xml/dom/XDOMImplementation.hpp>
#include <com/sun/star/xml/dom/events/XDocumentEvent.hpp>
#include <com/sun/star/xml/dom/events/XEvent.hpp>

#include "node.hxx"

#include <libxml/tree.h>

using namespace rtl;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::xml::dom;
using namespace com::sun::star::xml::dom::events;

namespace DOM
{

    typedef std::list< Reference< XNode >* > nodereflist_t;

    class CDocument : public cppu::ImplInheritanceHelper2< CNode, XDocument, XDocumentEvent >
    {
        friend class CNode;
    private:

        nodereflist_t m_aNodeRefList;

        xmlDocPtr m_aDocPtr;
        Reference< XDocumentType > m_rDocType;
        Reference< XElement > m_rDocElement;

    protected:
        CDocument(xmlDocPtr aDocPtr);

        void addnode(xmlNodePtr aNode);
    public:

        virtual ~CDocument();

        /**
        Creates an Attr of the given name.
        */
        virtual Reference< XAttr > SAL_CALL createAttribute(const OUString& name)
            throw (DOMException);

        /**
        Creates an attribute of the given qualified name and namespace URI.
        */
        virtual Reference< XAttr > SAL_CALL createAttributeNS(const OUString& namespaceURI, const OUString& qualifiedName)
            throw (DOMException);

        /**
        Creates a CDATASection node whose value is the specified string.
        */
        virtual Reference< XCDATASection > SAL_CALL createCDATASection(const OUString& data)
            throw (RuntimeException);

        /**
        Creates a Comment node given the specified string.
        */
        virtual Reference< XComment > SAL_CALL createComment(const OUString& data)
            throw (RuntimeException);

        /**
        Creates an empty DocumentFragment object.
        */
        virtual Reference< XDocumentFragment > SAL_CALL createDocumentFragment()
            throw (RuntimeException);

        /**
        Creates an element of the type specified.
        */
        virtual Reference< XElement > SAL_CALL createElement(const OUString& tagName)
            throw (DOMException);

        /**
        Creates an element of the given qualified name and namespace URI.
        */
        virtual Reference< XElement > SAL_CALL createElementNS(const OUString& namespaceURI, const OUString& qualifiedName)
            throw (DOMException);

        /**
        Creates an EntityReference object.
        */
        virtual Reference< XEntityReference > SAL_CALL createEntityReference(const OUString& name)
            throw (DOMException);

        /**
        Creates a ProcessingInstruction node given the specified name and
        data strings.
        */
        virtual Reference< XProcessingInstruction > SAL_CALL createProcessingInstruction(
                const OUString& target, const OUString& data)
            throw (DOMException);

        /**
        Creates a Text node given the specified string.
        */
        virtual Reference< XText > SAL_CALL createTextNode(const OUString& data)
            throw (RuntimeException);

        /**
        The Document Type Declaration (see DocumentType) associated with this
        document.
        */
        virtual Reference< XDocumentType > SAL_CALL getDoctype()
            throw (RuntimeException);

        /**
        This is a convenience attribute that allows direct access to the child
        node that is the root element of the document.
        */
        virtual Reference< XElement > SAL_CALL getDocumentElement()
            throw (RuntimeException);

        /**
        Returns the Element whose ID is given by elementId.
        */
        virtual Reference< XElement > SAL_CALL getElementById(const OUString& elementId)
            throw (RuntimeException);

        /**
        Returns a NodeList of all the Elements with a given tag name in the
        order in which they are encountered in a preorder traversal of the
        Document tree.
        */
        virtual Reference< XNodeList > SAL_CALL getElementsByTagName(const OUString& tagname)
            throw (RuntimeException);

        /**
        Returns a NodeList of all the Elements with a given local name and
        namespace URI in the order in which they are encountered in a preorder
        traversal of the Document tree.
        */
        virtual Reference< XNodeList > SAL_CALL getElementsByTagNameNS(const OUString& namespaceURI, const OUString& localName)
            throw (RuntimeException);

        /**
        The DOMImplementation object that handles this document.
        */
        virtual Reference< XDOMImplementation > SAL_CALL getImplementation()
            throw (RuntimeException);

        /**
        Imports a node from another document to this document.
        */
        virtual Reference< XNode > SAL_CALL importNode(const Reference< XNode >& importedNode, sal_Bool deep)
            throw (DOMException);

        // ---- resolve uno inheritance problems...
        // overrides for XNode base
        virtual OUString SAL_CALL getNodeName()
            throw (RuntimeException);
        virtual OUString SAL_CALL getNodeValue()
            throw (RuntimeException);
    // --- delegation for XNde base.
    virtual Reference< XNode > SAL_CALL appendChild(const Reference< XNode >& newChild)
        throw (DOMException)
    {
        return CNode::appendChild(newChild);
    }
    virtual Reference< XNode > SAL_CALL cloneNode(sal_Bool deep)
        throw (RuntimeException)
    {
        return CNode::cloneNode(deep);
    }
    virtual Reference< XNamedNodeMap > SAL_CALL getAttributes()
        throw (RuntimeException)
    {
        return CNode::getAttributes();
    }
    virtual Reference< XNodeList > SAL_CALL getChildNodes()
        throw (RuntimeException)
    {
        return CNode::getChildNodes();
    }
    virtual Reference< XNode > SAL_CALL getFirstChild()
        throw (RuntimeException)
    {
        return CNode::getFirstChild();
    }
    virtual Reference< XNode > SAL_CALL getLastChild()
        throw (RuntimeException)
    {
        return CNode::getLastChild();
    }
    virtual OUString SAL_CALL getLocalName()
        throw (RuntimeException)
    {
        return CNode::getLocalName();
    }
    virtual OUString SAL_CALL getNamespaceURI()
        throw (RuntimeException)
    {
        return CNode::getNamespaceURI();
    }
    virtual Reference< XNode > SAL_CALL getNextSibling()
        throw (RuntimeException)
    {
        return CNode::getNextSibling();
    }
    virtual NodeType SAL_CALL getNodeType()
        throw (RuntimeException)
    {
        return CNode::getNodeType();
    }
    virtual Reference< XDocument > SAL_CALL getOwnerDocument()
        throw (RuntimeException)
    {
        return CNode::getOwnerDocument();
    }
    virtual Reference< XNode > SAL_CALL getParentNode()
        throw (RuntimeException)
    {
        return CNode::getParentNode();
    }
    virtual OUString SAL_CALL getPrefix()
        throw (RuntimeException)
    {
       return CNode::getPrefix();
    }
    virtual Reference< XNode > SAL_CALL getPreviousSibling()
        throw (RuntimeException)
    {
        return CNode::getPreviousSibling();
    }
    virtual sal_Bool SAL_CALL hasAttributes()
        throw (RuntimeException)
    {
        return CNode::hasAttributes();
    }
    virtual sal_Bool SAL_CALL hasChildNodes()
        throw (RuntimeException)
    {
        return CNode::hasChildNodes();
    }
    virtual Reference< XNode > SAL_CALL insertBefore(
            const Reference< XNode >& newChild, const Reference< XNode >& refChild)
        throw (DOMException)
    {
        return CNode::insertBefore(newChild, refChild);
    }
    virtual sal_Bool SAL_CALL isSupported(const OUString& feature, const OUString& ver)
        throw (RuntimeException)
    {
        return CNode::isSupported(feature, ver);
    }
    virtual void SAL_CALL normalize()
        throw (RuntimeException)
    {
        CNode::normalize();
    }
    virtual Reference< XNode > SAL_CALL removeChild(const Reference< XNode >& oldChild)
        throw (DOMException)
    {
        return CNode::removeChild(oldChild);
    }
    virtual Reference< XNode > SAL_CALL replaceChild(
            const Reference< XNode >& newChild, const Reference< XNode >& oldChild)
        throw (DOMException)
    {
        return CNode::replaceChild(newChild, oldChild);
    }
    virtual void SAL_CALL setNodeValue(const OUString& nodeValue)
        throw (DOMException)
    {
        return CNode::setNodeValue(nodeValue);
    }
    virtual void SAL_CALL setPrefix(const OUString& prefix)
        throw (DOMException)
    {
        return CNode::setPrefix(prefix);
    }

    // XDocumentEvent
    virtual Reference< XEvent > SAL_CALL createEvent(const OUString& eventType) throw (RuntimeException);

    };

}

#endif<commit_msg>INTEGRATION: CWS ooo19126 (1.5.12); FILE MERGED 2005/09/05 17:19:56 rt 1.5.12.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: document.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 09:58:14 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _DOCUMENT_HXX
#define _DOCUMENT_HXX

#include <list>
#include <sal/types.h>
#include <cppuhelper/implbase1.hxx>
#include <cppuhelper/implbase2.hxx>
#include <com/sun/star/uno/Reference.h>
#include <com/sun/star/uno/Exception.hpp>
#include <com/sun/star/xml/dom/XNode.hpp>
#include <com/sun/star/xml/dom/XAttr.hpp>
#include <com/sun/star/xml/dom/XElement.hpp>
#include <com/sun/star/xml/dom/XDOMImplementation.hpp>
#include <com/sun/star/xml/dom/events/XDocumentEvent.hpp>
#include <com/sun/star/xml/dom/events/XEvent.hpp>

#include "node.hxx"

#include <libxml/tree.h>

using namespace rtl;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::xml::dom;
using namespace com::sun::star::xml::dom::events;

namespace DOM
{

    typedef std::list< Reference< XNode >* > nodereflist_t;

    class CDocument : public cppu::ImplInheritanceHelper2< CNode, XDocument, XDocumentEvent >
    {
        friend class CNode;
    private:

        nodereflist_t m_aNodeRefList;

        xmlDocPtr m_aDocPtr;
        Reference< XDocumentType > m_rDocType;
        Reference< XElement > m_rDocElement;

    protected:
        CDocument(xmlDocPtr aDocPtr);

        void addnode(xmlNodePtr aNode);
    public:

        virtual ~CDocument();

        /**
        Creates an Attr of the given name.
        */
        virtual Reference< XAttr > SAL_CALL createAttribute(const OUString& name)
            throw (DOMException);

        /**
        Creates an attribute of the given qualified name and namespace URI.
        */
        virtual Reference< XAttr > SAL_CALL createAttributeNS(const OUString& namespaceURI, const OUString& qualifiedName)
            throw (DOMException);

        /**
        Creates a CDATASection node whose value is the specified string.
        */
        virtual Reference< XCDATASection > SAL_CALL createCDATASection(const OUString& data)
            throw (RuntimeException);

        /**
        Creates a Comment node given the specified string.
        */
        virtual Reference< XComment > SAL_CALL createComment(const OUString& data)
            throw (RuntimeException);

        /**
        Creates an empty DocumentFragment object.
        */
        virtual Reference< XDocumentFragment > SAL_CALL createDocumentFragment()
            throw (RuntimeException);

        /**
        Creates an element of the type specified.
        */
        virtual Reference< XElement > SAL_CALL createElement(const OUString& tagName)
            throw (DOMException);

        /**
        Creates an element of the given qualified name and namespace URI.
        */
        virtual Reference< XElement > SAL_CALL createElementNS(const OUString& namespaceURI, const OUString& qualifiedName)
            throw (DOMException);

        /**
        Creates an EntityReference object.
        */
        virtual Reference< XEntityReference > SAL_CALL createEntityReference(const OUString& name)
            throw (DOMException);

        /**
        Creates a ProcessingInstruction node given the specified name and
        data strings.
        */
        virtual Reference< XProcessingInstruction > SAL_CALL createProcessingInstruction(
                const OUString& target, const OUString& data)
            throw (DOMException);

        /**
        Creates a Text node given the specified string.
        */
        virtual Reference< XText > SAL_CALL createTextNode(const OUString& data)
            throw (RuntimeException);

        /**
        The Document Type Declaration (see DocumentType) associated with this
        document.
        */
        virtual Reference< XDocumentType > SAL_CALL getDoctype()
            throw (RuntimeException);

        /**
        This is a convenience attribute that allows direct access to the child
        node that is the root element of the document.
        */
        virtual Reference< XElement > SAL_CALL getDocumentElement()
            throw (RuntimeException);

        /**
        Returns the Element whose ID is given by elementId.
        */
        virtual Reference< XElement > SAL_CALL getElementById(const OUString& elementId)
            throw (RuntimeException);

        /**
        Returns a NodeList of all the Elements with a given tag name in the
        order in which they are encountered in a preorder traversal of the
        Document tree.
        */
        virtual Reference< XNodeList > SAL_CALL getElementsByTagName(const OUString& tagname)
            throw (RuntimeException);

        /**
        Returns a NodeList of all the Elements with a given local name and
        namespace URI in the order in which they are encountered in a preorder
        traversal of the Document tree.
        */
        virtual Reference< XNodeList > SAL_CALL getElementsByTagNameNS(const OUString& namespaceURI, const OUString& localName)
            throw (RuntimeException);

        /**
        The DOMImplementation object that handles this document.
        */
        virtual Reference< XDOMImplementation > SAL_CALL getImplementation()
            throw (RuntimeException);

        /**
        Imports a node from another document to this document.
        */
        virtual Reference< XNode > SAL_CALL importNode(const Reference< XNode >& importedNode, sal_Bool deep)
            throw (DOMException);

        // ---- resolve uno inheritance problems...
        // overrides for XNode base
        virtual OUString SAL_CALL getNodeName()
            throw (RuntimeException);
        virtual OUString SAL_CALL getNodeValue()
            throw (RuntimeException);
    // --- delegation for XNde base.
    virtual Reference< XNode > SAL_CALL appendChild(const Reference< XNode >& newChild)
        throw (DOMException)
    {
        return CNode::appendChild(newChild);
    }
    virtual Reference< XNode > SAL_CALL cloneNode(sal_Bool deep)
        throw (RuntimeException)
    {
        return CNode::cloneNode(deep);
    }
    virtual Reference< XNamedNodeMap > SAL_CALL getAttributes()
        throw (RuntimeException)
    {
        return CNode::getAttributes();
    }
    virtual Reference< XNodeList > SAL_CALL getChildNodes()
        throw (RuntimeException)
    {
        return CNode::getChildNodes();
    }
    virtual Reference< XNode > SAL_CALL getFirstChild()
        throw (RuntimeException)
    {
        return CNode::getFirstChild();
    }
    virtual Reference< XNode > SAL_CALL getLastChild()
        throw (RuntimeException)
    {
        return CNode::getLastChild();
    }
    virtual OUString SAL_CALL getLocalName()
        throw (RuntimeException)
    {
        return CNode::getLocalName();
    }
    virtual OUString SAL_CALL getNamespaceURI()
        throw (RuntimeException)
    {
        return CNode::getNamespaceURI();
    }
    virtual Reference< XNode > SAL_CALL getNextSibling()
        throw (RuntimeException)
    {
        return CNode::getNextSibling();
    }
    virtual NodeType SAL_CALL getNodeType()
        throw (RuntimeException)
    {
        return CNode::getNodeType();
    }
    virtual Reference< XDocument > SAL_CALL getOwnerDocument()
        throw (RuntimeException)
    {
        return CNode::getOwnerDocument();
    }
    virtual Reference< XNode > SAL_CALL getParentNode()
        throw (RuntimeException)
    {
        return CNode::getParentNode();
    }
    virtual OUString SAL_CALL getPrefix()
        throw (RuntimeException)
    {
       return CNode::getPrefix();
    }
    virtual Reference< XNode > SAL_CALL getPreviousSibling()
        throw (RuntimeException)
    {
        return CNode::getPreviousSibling();
    }
    virtual sal_Bool SAL_CALL hasAttributes()
        throw (RuntimeException)
    {
        return CNode::hasAttributes();
    }
    virtual sal_Bool SAL_CALL hasChildNodes()
        throw (RuntimeException)
    {
        return CNode::hasChildNodes();
    }
    virtual Reference< XNode > SAL_CALL insertBefore(
            const Reference< XNode >& newChild, const Reference< XNode >& refChild)
        throw (DOMException)
    {
        return CNode::insertBefore(newChild, refChild);
    }
    virtual sal_Bool SAL_CALL isSupported(const OUString& feature, const OUString& ver)
        throw (RuntimeException)
    {
        return CNode::isSupported(feature, ver);
    }
    virtual void SAL_CALL normalize()
        throw (RuntimeException)
    {
        CNode::normalize();
    }
    virtual Reference< XNode > SAL_CALL removeChild(const Reference< XNode >& oldChild)
        throw (DOMException)
    {
        return CNode::removeChild(oldChild);
    }
    virtual Reference< XNode > SAL_CALL replaceChild(
            const Reference< XNode >& newChild, const Reference< XNode >& oldChild)
        throw (DOMException)
    {
        return CNode::replaceChild(newChild, oldChild);
    }
    virtual void SAL_CALL setNodeValue(const OUString& nodeValue)
        throw (DOMException)
    {
        return CNode::setNodeValue(nodeValue);
    }
    virtual void SAL_CALL setPrefix(const OUString& prefix)
        throw (DOMException)
    {
        return CNode::setPrefix(prefix);
    }

    // XDocumentEvent
    virtual Reference< XEvent > SAL_CALL createEvent(const OUString& eventType) throw (RuntimeException);

    };

}

#endif<|endoftext|>


<commit_before>//MIT License
//Copyright 2017 Patrick Laughrea
#include "base64.hpp"

#include <cassert>
#include <stdexcept>

#include "constants.hpp"
#include "various/stringBuilder.hpp"

using namespace std;
using namespace various;
using namespace webss;

static void readBytes(SmartIterator& it, char bytes[4]);
static void writeBytes(char bytes[4]);

static const char* ERROR_EXPECTED = "expected character";

#define DECODE_ALL_0 '_'
#define DECODE_ALL_1 '+'
#define DECODE_NUMBER '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9'
#define DECODE_UPPER 'Q': case 'W': case 'F': case 'R': case 'K': case 'Y': case 'J': case 'I': case 'O': case 'P': \
	case 'A': case 'S': case 'D': case 'T': case 'G': case 'H': case 'E': case 'U': case 'L': \
	case 'Z': case 'X': case 'C': case 'V': case 'B': case 'N': case 'M'
#define DECODE_LOWER 'q': case 'w': case 'f': case 'r': case 'k': case 'y': case 'j': case 'i': case 'o': case 'p': \
	case 'a': case 's': case 'd': case 't': case 'g': case 'h': case 'e': case 'u': case 'l': \
	case 'z': case 'x': case 'c': case 'v': case 'b': case 'n': case 'm'
#define DECODE_CHAR_1 '-'
#define DECODE_CHAR_2 '='
#define DECODE_IGNORED ' ': case '\x7f': \
	case '\x00': case '\x01': case '\x02': case '\x03': case '\x04': case '\x05': case '\x06': case '\x07': case '\x08': case '\x09': case '\x0a': case '\x0b': case '\x0c': case '\x0d': case '\x0e': case '\x0f': \
	case '\x10': case '\x11': case '\x12': case '\x13': case '\x14': case '\x15': case '\x16': case '\x17': case '\x18': case '\x19': case '\x1a': case '\x1b': case '\x1c': case '\x1d': case '\x1e': case '\x1f'
#define PutThreeBytes(byte) { sb += byte; sb += byte; sb += byte; }

SmartIterator webss::decodeBase64(SmartIterator& it)
{
	StringBuilder sb;
	union
	{
		char bytes[4];
		int32_t bytesInt;
	};
decodeStart:
	if (!it)
		throw runtime_error(ERROR_EXPECTED);
	switch (*it)
	{
	case CHAR_END_TUPLE:
		return sb.str();
	case DECODE_ALL_0:
		PutThreeBytes('\0')
		goto decodeEnd;
	case DECODE_ALL_1:
		PutThreeBytes('\xff');
		goto decodeEnd;
	case DECODE_IGNORED:
		goto decodeEnd;
	default:
		break;
	}
	readBytes(it, bytes);
	//the 4 bytes: 00111111|00222222|00333333|00112233
	//will become: 11111111|22222222|33333333|00000000
	bytesInt |= (bytesInt & 0x30) << 26;
	bytesInt |= (bytesInt & 0x0c) << 20;
	bytesInt |= (bytesInt & 0x03) << 14;
	bytes[3] = 0;
	sb += bytes;
decodeEnd:
	++it;
	goto decodeStart;
}

static void readBytes(SmartIterator& it, char bytes[4])
{
	int i = 0;
startSwitch:
	switch (*it)
	{
	case DECODE_IGNORED:
		goto restart;
	case DECODE_NUMBER:
		bytes[i] = *it - '0';
		break;
	case DECODE_UPPER:
		bytes[i] = *it - 'A' + 10;
		break;
	case DECODE_LOWER:
		bytes[i] = *it - 'a' + 36;
		break;
	case DECODE_CHAR_1:
		bytes[i] = 62;
		break;
	case DECODE_CHAR_2:
		bytes[i] = 63;
		break;
	default:
		throw runtime_error("forbidden character in encoded binary");
	}
	if (++i == 4)
		return;
restart:
	if (!++it)
		throw runtime_error(ERROR_EXPECTED);
	goto startSwitch;
}

#define ENCODE_NUMBER 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9
#define ENCODE_UPPER 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: \
	case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: \
	case 30: case 31: case 32: case 33: case 34: case 35
#define ENCODE_LOWER 36: case 37: case 38: case 39: \
	case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: \
	case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59: \
	case 60: case 61
#define ENCODE_CHAR_1 62
#define ENCODE_CHAR_2 63

#ifndef BASE64_DISABLE_ENCODE_ALL_ZEROS
#ifndef BASE64_DISABLE_ENCODE_ALL_ONES
#define SpecialCheck(Ones, Cmd) { \
	if (bytesInt == 0) { sb += DECODE_ALL_0; Cmd; } \
	if (bytesInt == Ones) { sb += DECODE_ALL_1; Cmd; } }
#else
#define SpecialCheck(Ones, Cmd) { \
	if (bytesInt == 0) { sb += DECODE_ALL_0; Cmd; } }
#endif
#else //BASE64_DISABLE_ENCODE_ALL_ZEROS
#ifdef BASE64_DISABLE_ENCODE_ALL_ONES
#define SpecialCheck(Ones, Cmd) { \
	if (bytesInt == Ones) { sb += DECODE_ALL_1; Cmd; } }
#else
#define SpecialCheck(Ones, Cmd) ;
#endif
#endif //BASE64_DISABLE_ENCODE_ALL_ZEROS

string webss::encodeBase64(SmartIterator& it)
{
	StringBuilder sb;
	union
	{
		char bytes[5];
		int32_t bytesInt;
	};
	bytes[4] = 0;
encodeStart:
	if (!it)
		return sb;
	bytesInt = 0;
	bytes[0] = *it;
	if (!++it)
	{
		SpecialCheck(0xff000000, return sb)
		goto encodeBytes;
	}
	bytes[1] = *it;
	if (!++it)
	{
		SpecialCheck(0xffff0000, return sb)
		goto encodeBytes;
	}
	bytes[2] = *it;
	SpecialCheck(0xffffff00, ++it; goto encodeStart)
encodeBytes:
	//the 4 bytes: 11111111|22222222|33333333|00000000
	//will become: 00111111|00222222|00333333|00112233
	bytesInt |= (bytesInt & (0xc0 << 24)) >> 26;
	bytesInt |= (bytesInt & (0xc0 << 16)) >> 20;
	bytesInt |= (bytesInt & (0xc0 << 8)) >> 14;
	writeBytes(bytes);
	sb += bytes;
	++it;
	goto encodeStart;
}

static void writeBytes(char bytes[4])
{
	for (int i = 0; i < 4; ++i)
		switch (bytes[i])
		{
		case ENCODE_NUMBER:
			bytes[i] += '0';
			break;
		case ENCODE_UPPER:
			bytes[i] += 'A' - 10;
			break;
		case ENCODE_LOWER:
			bytes[i] += 'a' - 36;
			break;
		case ENCODE_CHAR_1:
			bytes[i] = DECODE_CHAR_1;
			break;
		case ENCODE_CHAR_2:
			bytes[i] = DECODE_CHAR_2;
			break;
		default:
			assert(false); throw domain_error("");
		}
}<commit_msg>Fix compiler errors<commit_after>//MIT License
//Copyright 2017 Patrick Laughrea
#include "base64.hpp"

#include <cassert>
#include <stdexcept>

#include "constants.hpp"
#include "various/stringBuilder.hpp"

using namespace std;
using namespace various;
using namespace webss;

static void readBytes(SmartIterator& it, char bytes[4]);
static void writeBytes(char bytes[4]);

static const char* ERROR_EXPECTED = "expected character";

#define DECODE_ALL_0 '_'
#define DECODE_ALL_1 '+'
#define DECODE_NUMBER '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9'
#define DECODE_UPPER 'Q': case 'W': case 'F': case 'R': case 'K': case 'Y': case 'J': case 'I': case 'O': case 'P': \
	case 'A': case 'S': case 'D': case 'T': case 'G': case 'H': case 'E': case 'U': case 'L': \
	case 'Z': case 'X': case 'C': case 'V': case 'B': case 'N': case 'M'
#define DECODE_LOWER 'q': case 'w': case 'f': case 'r': case 'k': case 'y': case 'j': case 'i': case 'o': case 'p': \
	case 'a': case 's': case 'd': case 't': case 'g': case 'h': case 'e': case 'u': case 'l': \
	case 'z': case 'x': case 'c': case 'v': case 'b': case 'n': case 'm'
#define DECODE_CHAR_1 '-'
#define DECODE_CHAR_2 '='
#define DECODE_IGNORED ' ': case '\x7f': \
	case '\x00': case '\x01': case '\x02': case '\x03': case '\x04': case '\x05': case '\x06': case '\x07': case '\x08': case '\x09': case '\x0a': case '\x0b': case '\x0c': case '\x0d': case '\x0e': case '\x0f': \
	case '\x10': case '\x11': case '\x12': case '\x13': case '\x14': case '\x15': case '\x16': case '\x17': case '\x18': case '\x19': case '\x1a': case '\x1b': case '\x1c': case '\x1d': case '\x1e': case '\x1f'
#define PutThreeBytes(byte) { sb += byte; sb += byte; sb += byte; }

SmartIterator webss::decodeBase64(SmartIterator& it)
{
	StringBuilder sb;
	union
	{
		char bytes[4];
		int32_t bytesInt;
	};
decodeStart:
	if (!it)
		throw runtime_error(ERROR_EXPECTED);
	switch (*it)
	{
	case CHAR_END_TUPLE:
		return sb.str();
	case DECODE_ALL_0:
		PutThreeBytes('\0')
		goto decodeEnd;
	case DECODE_ALL_1:
		PutThreeBytes('\xff');
		goto decodeEnd;
	case DECODE_IGNORED:
		goto decodeEnd;
	default:
		break;
	}
	readBytes(it, bytes);
	//the 4 bytes: 00111111|00222222|00333333|00112233
	//will become: 11111111|22222222|33333333|00000000
	bytesInt |= (bytesInt & 0x30) << 26;
	bytesInt |= (bytesInt & 0x0c) << 20;
	bytesInt |= (bytesInt & 0x03) << 14;
	bytes[3] = 0;
	sb += bytes;
decodeEnd:
	++it;
	goto decodeStart;
}

static void readBytes(SmartIterator& it, char bytes[4])
{
	int i = 0;
startSwitch:
	switch (*it)
	{
	case DECODE_IGNORED:
		goto restart;
	case DECODE_NUMBER:
		bytes[i] = *it - '0';
		break;
	case DECODE_UPPER:
		bytes[i] = *it - 'A' + 10;
		break;
	case DECODE_LOWER:
		bytes[i] = *it - 'a' + 36;
		break;
	case DECODE_CHAR_1:
		bytes[i] = 62;
		break;
	case DECODE_CHAR_2:
		bytes[i] = 63;
		break;
	default:
		throw runtime_error("forbidden character in encoded binary");
	}
	if (++i == 4)
		return;
restart:
	if (!++it)
		throw runtime_error(ERROR_EXPECTED);
	goto startSwitch;
}

#define ENCODE_NUMBER 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9
#define ENCODE_UPPER 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: \
	case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: \
	case 30: case 31: case 32: case 33: case 34: case 35
#define ENCODE_LOWER 36: case 37: case 38: case 39: \
	case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: \
	case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59: \
	case 60: case 61
#define ENCODE_CHAR_1 62
#define ENCODE_CHAR_2 63

#ifndef BASE64_DISABLE_ENCODE_ALL_ZEROS
#ifndef BASE64_DISABLE_ENCODE_ALL_ONES
#define SpecialCheck(Ones, Cmd) { \
	if (bytesInt == 0) { sb += DECODE_ALL_0; Cmd; } \
	if (bytesInt == Ones) { sb += DECODE_ALL_1; Cmd; } }
#else
#define SpecialCheck(Ones, Cmd) { \
	if (bytesInt == 0) { sb += DECODE_ALL_0; Cmd; } }
#endif
#else //BASE64_DISABLE_ENCODE_ALL_ZEROS
#ifdef BASE64_DISABLE_ENCODE_ALL_ONES
#define SpecialCheck(Ones, Cmd) { \
	if (bytesInt == Ones) { sb += DECODE_ALL_1; Cmd; } }
#else
#define SpecialCheck(Ones, Cmd) ;
#endif
#endif //BASE64_DISABLE_ENCODE_ALL_ZEROS

string webss::encodeBase64(SmartIterator& it)
{
	StringBuilder sb;
	union
	{
		char bytes[5];
		uint32_t bytesInt;
	};
	bytes[4] = 0;
encodeStart:
	if (!it)
		return sb;
	bytesInt = 0;
	bytes[0] = *it;
	if (!++it)
	{
		SpecialCheck(0xff000000, return sb)
		goto encodeBytes;
	}
	bytes[1] = *it;
	if (!++it)
	{
		SpecialCheck(0xffff0000, return sb)
		goto encodeBytes;
	}
	bytes[2] = *it;
	SpecialCheck(0xffffff00, ++it; goto encodeStart)
encodeBytes:
	//the 4 bytes: 11111111|22222222|33333333|00000000
	//will become: 00111111|00222222|00333333|00112233
	bytesInt |= (bytesInt & (0xc0 << 24)) >> 26;
	bytesInt |= (bytesInt & (0xc0 << 16)) >> 20;
	bytesInt |= (bytesInt & (0xc0 << 8)) >> 14;
	writeBytes(bytes);
	sb += bytes;
	++it;
	goto encodeStart;
}

static void writeBytes(char bytes[4])
{
	for (int i = 0; i < 4; ++i)
		switch (bytes[i])
		{
		case ENCODE_NUMBER:
			bytes[i] += '0';
			break;
		case ENCODE_UPPER:
			bytes[i] += 'A' - 10;
			break;
		case ENCODE_LOWER:
			bytes[i] += 'a' - 36;
			break;
		case ENCODE_CHAR_1:
			bytes[i] = DECODE_CHAR_1;
			break;
		case ENCODE_CHAR_2:
			bytes[i] = DECODE_CHAR_2;
			break;
		default:
			assert(false); throw domain_error("");
		}
}<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#if ! defined INCLUDED_DP_COMPBACKENDDB_HXX
#define INCLUDED_DP_COMPBACKENDDB_HXX

#include "rtl/ustring.hxx"
#include "rtl/string.hxx"
#include <vector>
#include <list>
#include "dp_backenddb.hxx"

namespace css = ::com::sun::star;

namespace com { namespace sun { namespace star {
        namespace uno {
        class XComponentContext;
        }
        namespace xml { namespace dom {
            class XDocument;
            class XNode;
        }}
        namespace xml { namespace xpath {
            class XXPathAPI;
        }}
}}}

namespace dp_registry {
namespace backend {
namespace component {

/* The XML file stores the extensions which are currently registered.
   They will be removed when they are revoked.
   The format looks like this:

<?xml version="1.0"?>
<component-backend-db xmlns="http://openoffice.org/extensionmanager/component-registry/2010">
  <component url="vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/uno_packages/5CD5.tmp_/leaves1.oxt/extensionoptions.jar">
    <name>FileName</name>
    <java-type-library>true</java-type-library>
    <implementation-names>
      <name>com.sun.star.comp.extensionoptions.OptionsEventHandler$_OptionsEventHandler</name>
      ...
    </implementation-names>
    <singletons>
      <item>
        <key>com.sun.star.java.theJavaVirtualMachine</key>
        <value>com.sun.star.java.JavaVirtualMachine</value>
      </item>
      ...
    </singletons>
  </component>

  <component ...>
  ...
</component-backend-db>
 */
class ComponentBackendDb: public dp_registry::backend::BackendDb
{
protected:
    virtual ::rtl::OUString getDbNSName();
    virtual ::rtl::OUString getNSPrefix();
    virtual ::rtl::OUString getRootElementName();
    virtual ::rtl::OUString getKeyElementName();

public:
    struct Data
    {
        Data(): javaTypeLibrary(false) {};

        ::std::list< ::rtl::OUString> implementationNames;
        /* every singleton has a key and a value
         */
        ::std::vector< ::std::pair< ::rtl::OUString, ::rtl::OUString> >singletons;
        bool javaTypeLibrary;
    };

public:

    ComponentBackendDb( css::uno::Reference<css::uno::XComponentContext> const &  xContext,
                        ::rtl::OUString const & url);

    void addEntry(::rtl::OUString const & url, Data const & data);

    Data getEntry(::rtl::OUString const & url);

};

}
}
}
#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Improved comment<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#if ! defined INCLUDED_DP_COMPBACKENDDB_HXX
#define INCLUDED_DP_COMPBACKENDDB_HXX

#include "rtl/ustring.hxx"
#include "rtl/string.hxx"
#include <vector>
#include <list>
#include "dp_backenddb.hxx"

namespace css = ::com::sun::star;

namespace com { namespace sun { namespace star {
        namespace uno {
        class XComponentContext;
        }
        namespace xml { namespace dom {
            class XDocument;
            class XNode;
        }}
        namespace xml { namespace xpath {
            class XXPathAPI;
        }}
}}}

namespace dp_registry {
namespace backend {
namespace component {

/* The XML file stores the extensions which are currently registered.
   They will be removed when they are revoked.
   The format looks like this:

<?xml version="1.0"?>
<component-backend-db xmlns="http://openoffice.org/extensionmanager/component-registry/2010">
  <component url="vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/uno_packages/5CD5.tmp_/leaves1.oxt/extensionoptions.jar">
    <name>FileName</name>
    <java-type-library>true</java-type-library>
    <implementation-names>
      <name>com.sun.star.comp.extensionoptions.OptionsEventHandler$_OptionsEventHandler</name>
      ...
    </implementation-names>
    <singletons>
      <item>
        <key>com.sun.star.java.theJavaVirtualMachine</key>
        <value>com.sun.star.java.JavaVirtualMachine</value>
      </item>
      ...
    </singletons>
  </component>

  <component ...>
  ...
</component-backend-db>
 */
class ComponentBackendDb: public dp_registry::backend::BackendDb
{
protected:
    virtual ::rtl::OUString getDbNSName();
    virtual ::rtl::OUString getNSPrefix();
    virtual ::rtl::OUString getRootElementName();
    virtual ::rtl::OUString getKeyElementName();

public:
    struct Data
    {
        Data(): javaTypeLibrary(false) {};

        ::std::list< ::rtl::OUString> implementationNames;
        ::std::vector< ::std::pair< ::rtl::OUString, ::rtl::OUString> >singletons;
            // map from singleton names to implementation names
        bool javaTypeLibrary;
    };

public:

    ComponentBackendDb( css::uno::Reference<css::uno::XComponentContext> const &  xContext,
                        ::rtl::OUString const & url);

    void addEntry(::rtl::OUString const & url, Data const & data);

    Data getEntry(::rtl::OUString const & url);

};

}
}
}
#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>
/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrSoftwarePathRenderer.h"
#include "GrPaint.h"
#include "SkPaint.h"
#include "GrRenderTarget.h"
#include "GrContext.h"
#include "SkDraw.h"
#include "SkRasterClip.h"

////////////////////////////////////////////////////////////////////////////////
bool GrSoftwarePathRenderer::canDrawPath(const SkPath& path,
                                         GrPathFill fill,
                                         const GrDrawTarget* target,
                                         bool antiAlias) const {
    if (!antiAlias || NULL == fContext) {
        // TODO: We could allow the SW path to also handle non-AA paths but
        // this would mean that GrDefaultPathRenderer would never be called
        // (since it appears after the SW renderer in the path renderer
        // chain). Some testing would need to be done r.e. performance
        // and consistency of the resulting images before removing
        // the "!antiAlias" clause from the above test
        return false;
    }

    return true;
}

namespace {

////////////////////////////////////////////////////////////////////////////////
SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) {
    switch (fill) {
        case kWinding_GrPathFill:
            return SkPath::kWinding_FillType;
        case kEvenOdd_GrPathFill:
            return SkPath::kEvenOdd_FillType;
        case kInverseWinding_GrPathFill:
            return SkPath::kInverseWinding_FillType;
        case kInverseEvenOdd_GrPathFill:
            return SkPath::kInverseEvenOdd_FillType;
        default:
            GrCrash("Unexpected fill.");
            return SkPath::kWinding_FillType;
    }
}

////////////////////////////////////////////////////////////////////////////////
// gets device coord bounds of path (not considering the fill) and clip. The
// path bounds will be a subset of the clip bounds. returns false if
// path bounds would be empty.
bool get_path_and_clip_bounds(const GrDrawTarget* target,
                              const SkPath& path,
                              const GrVec* translate,
                              GrIRect* pathBounds,
                              GrIRect* clipBounds) {
    // compute bounds as intersection of rt size, clip, and path
    const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
    if (NULL == rt) {
        return false;
    }
    *pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
    const GrClip& clip = target->getClip();
    if (clip.hasConservativeBounds()) {
        clip.getConservativeBounds().roundOut(clipBounds);
        if (!pathBounds->intersect(*clipBounds)) {
            return false;
        }
    } else {
        // pathBounds is currently the rt extent, set clip bounds to that rect.
        *clipBounds = *pathBounds;
    }
    GrRect pathSBounds = path.getBounds();
    if (!pathSBounds.isEmpty()) {
        if (NULL != translate) {
            pathSBounds.offset(*translate);
        }
        target->getDrawState().getViewMatrix().mapRect(&pathSBounds,
                                                        pathSBounds);
        GrIRect pathIBounds;
        pathSBounds.roundOut(&pathIBounds);
        if (!pathBounds->intersect(pathIBounds)) {
            return false;
        }
    } else {
        return false;
    }
    return true;
}

/*
 * Convert a boolean operation into a transfer mode code
 */
SkXfermode::Mode op_to_mode(SkRegion::Op op) {

    static const SkXfermode::Mode modeMap[] = {
        SkXfermode::kDstOut_Mode,   // kDifference_Op
        SkXfermode::kMultiply_Mode, // kIntersect_Op
        SkXfermode::kSrcOver_Mode,  // kUnion_Op
        SkXfermode::kXor_Mode,      // kXOR_Op
        SkXfermode::kClear_Mode,    // kReverseDifference_Op
        SkXfermode::kSrc_Mode,      // kReplace_Op
    };

    return modeMap[op];
}

}

/**
 * Draw a single rect element of the clip stack into the accumulation bitmap
 */
void GrSWMaskHelper::draw(const GrRect& clientRect, SkRegion::Op op,
                          bool antiAlias, GrColor color) {
    SkPaint paint;

    SkXfermode* mode = SkXfermode::Create(op_to_mode(op));

    paint.setXfermode(mode);
    paint.setAntiAlias(antiAlias);
    paint.setColor(color);

    fDraw.drawRect(clientRect, paint);

    SkSafeUnref(mode);
}

/**
 * Draw a single path element of the clip stack into the accumulation bitmap
 */
void GrSWMaskHelper::draw(const SkPath& clientPath, SkRegion::Op op,
                          GrPathFill fill, bool antiAlias, GrColor color) {

    SkPaint paint;
    SkPath tmpPath;
    const SkPath* pathToDraw = &clientPath;
    if (kHairLine_GrPathFill == fill) {
        paint.setStyle(SkPaint::kStroke_Style);
        paint.setStrokeWidth(SK_Scalar1);
    } else {
        paint.setStyle(SkPaint::kFill_Style);
        SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
        if (skfill != pathToDraw->getFillType()) {
            tmpPath = *pathToDraw;
            tmpPath.setFillType(skfill);
            pathToDraw = &tmpPath;
        }
    }
    SkXfermode* mode = SkXfermode::Create(op_to_mode(op));

    paint.setXfermode(mode);
    paint.setAntiAlias(antiAlias);
    paint.setColor(color);

    fDraw.drawPath(*pathToDraw, paint);

    SkSafeUnref(mode);
}

bool GrSWMaskHelper::init(const GrIRect& pathDevBounds,
                          const GrPoint* translate,
                          bool useMatrix) {
    if (useMatrix) {
        fMatrix = fContext->getMatrix();
    } else {
        fMatrix.setIdentity();
    }

    if (NULL != translate) {
        fMatrix.postTranslate(translate->fX, translate->fY);
    }

    fMatrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
                          -pathDevBounds.fTop * SK_Scalar1);
    GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
                                     pathDevBounds.height());

    fBM.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
    if (!fBM.allocPixels()) {
        return false;
    }
    sk_bzero(fBM.getPixels(), fBM.getSafeSize());

    sk_bzero(&fDraw, sizeof(fDraw));
    fRasterClip.setRect(bounds);
    fDraw.fRC    = &fRasterClip;
    fDraw.fClip  = &fRasterClip.bwRgn();
    fDraw.fMatrix = &fMatrix;
    fDraw.fBitmap = &fBM;
    return true;
}

/**
 * Get a texture (from the texture cache) of the correct size & format
 */
bool GrSWMaskHelper::getTexture(GrAutoScratchTexture* tex) {
    GrTextureDesc desc;
    desc.fWidth = fBM.width();
    desc.fHeight = fBM.height();
    desc.fConfig = kAlpha_8_GrPixelConfig;

    tex->set(fContext, desc);
    GrTexture* texture = tex->texture();

    if (NULL == texture) {
        return false;
    }

    return true;
}

/**
 * Move the result of the software mask generation back to the gpu
 */
void GrSWMaskHelper::toTexture(GrTexture *texture) {
    SkAutoLockPixels alp(fBM);
    texture->writePixels(0, 0, fBM.width(), fBM.height(),
                         kAlpha_8_GrPixelConfig,
                         fBM.getPixels(), fBM.rowBytes());
}

namespace {
////////////////////////////////////////////////////////////////////////////////
/**
 * sw rasterizes path to A8 mask using the context's matrix and uploads to a
 * scratch texture.
 */
bool sw_draw_path_to_mask_texture(const SkPath& clientPath,
                                  const GrIRect& pathDevBounds,
                                  GrPathFill fill,
                                  GrContext* context,
                                  const GrPoint* translate,
                                  GrAutoScratchTexture* tex,
                                  bool antiAlias) {
    GrSWMaskHelper helper(context);

    if (!helper.init(pathDevBounds, translate, true)) {
        return false;
    }

    helper.draw(clientPath, SkRegion::kReplace_Op,
                fill, antiAlias, SK_ColorWHITE);

    if (!helper.getTexture(tex)) {
        return false;
    }

    helper.toTexture(tex->texture());

    return true;
}

////////////////////////////////////////////////////////////////////////////////
void draw_around_inv_path(GrDrawTarget* target,
                          GrDrawState::StageMask stageMask,
                          const GrIRect& clipBounds,
                          const GrIRect& pathBounds) {
    GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
    GrRect rect;
    if (clipBounds.fTop < pathBounds.fTop) {
        rect.iset(clipBounds.fLeft, clipBounds.fTop,
                    clipBounds.fRight, pathBounds.fTop);
        target->drawSimpleRect(rect, NULL, stageMask);
    }
    if (clipBounds.fLeft < pathBounds.fLeft) {
        rect.iset(clipBounds.fLeft, pathBounds.fTop,
                    pathBounds.fLeft, pathBounds.fBottom);
        target->drawSimpleRect(rect, NULL, stageMask);
    }
    if (clipBounds.fRight > pathBounds.fRight) {
        rect.iset(pathBounds.fRight, pathBounds.fTop,
                    clipBounds.fRight, pathBounds.fBottom);
        target->drawSimpleRect(rect, NULL, stageMask);
    }
    if (clipBounds.fBottom > pathBounds.fBottom) {
        rect.iset(clipBounds.fLeft, pathBounds.fBottom,
                    clipBounds.fRight, clipBounds.fBottom);
        target->drawSimpleRect(rect, NULL, stageMask);
    }
}

}

////////////////////////////////////////////////////////////////////////////////
// return true on success; false on failure
bool GrSoftwarePathRenderer::onDrawPath(const SkPath& path,
                                        GrPathFill fill,
                                        const GrVec* translate,
                                        GrDrawTarget* target,
                                        GrDrawState::StageMask stageMask,
                                        bool antiAlias) {

    if (NULL == fContext) {
        return false;
    }

    GrAutoScratchTexture ast;
    GrIRect pathBounds, clipBounds;
    if (!get_path_and_clip_bounds(target, path, translate,
                                  &pathBounds, &clipBounds)) {
        return true;    // path is empty so there is nothing to do
    }
    if (sw_draw_path_to_mask_texture(path, pathBounds,
                                     fill, fContext,
                                     translate, &ast, antiAlias)) {
        GrTexture* texture = ast.texture();
        GrAssert(NULL != texture);
        GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
        enum {
            // the SW path renderer shares this stage with glyph
            // rendering (kGlyphMaskStage in GrBatchedTextContext)
            kPathMaskStage = GrPaint::kTotalStages,
        };
        GrAssert(NULL == target->drawState()->getTexture(kPathMaskStage));
        target->drawState()->setTexture(kPathMaskStage, texture);
        target->drawState()->sampler(kPathMaskStage)->reset();
        GrScalar w = GrIntToScalar(pathBounds.width());
        GrScalar h = GrIntToScalar(pathBounds.height());
        GrRect maskRect = GrRect::MakeWH(w / texture->width(),
                                         h / texture->height());
        const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
        srcRects[kPathMaskStage] = &maskRect;
        stageMask |= 1 << kPathMaskStage;
        GrRect dstRect = GrRect::MakeLTRB(
                              SK_Scalar1* pathBounds.fLeft,
                              SK_Scalar1* pathBounds.fTop,
                              SK_Scalar1* pathBounds.fRight,
                              SK_Scalar1* pathBounds.fBottom);
        target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
        target->drawState()->setTexture(kPathMaskStage, NULL);
        if (GrIsFillInverted(fill)) {
            draw_around_inv_path(target, stageMask,
                                 clipBounds, pathBounds);
        }
        return true;
    }

    return false;
}
<commit_msg>fix incorrect GPU rendering for path inverse fill when path is outside the clip<commit_after>
/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrSoftwarePathRenderer.h"
#include "GrPaint.h"
#include "SkPaint.h"
#include "GrRenderTarget.h"
#include "GrContext.h"
#include "SkDraw.h"
#include "SkRasterClip.h"

////////////////////////////////////////////////////////////////////////////////
bool GrSoftwarePathRenderer::canDrawPath(const SkPath& path,
                                         GrPathFill fill,
                                         const GrDrawTarget* target,
                                         bool antiAlias) const {
    if (!antiAlias || NULL == fContext) {
        // TODO: We could allow the SW path to also handle non-AA paths but
        // this would mean that GrDefaultPathRenderer would never be called
        // (since it appears after the SW renderer in the path renderer
        // chain). Some testing would need to be done r.e. performance
        // and consistency of the resulting images before removing
        // the "!antiAlias" clause from the above test
        return false;
    }

    return true;
}

namespace {

////////////////////////////////////////////////////////////////////////////////
SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) {
    switch (fill) {
        case kWinding_GrPathFill:
            return SkPath::kWinding_FillType;
        case kEvenOdd_GrPathFill:
            return SkPath::kEvenOdd_FillType;
        case kInverseWinding_GrPathFill:
            return SkPath::kInverseWinding_FillType;
        case kInverseEvenOdd_GrPathFill:
            return SkPath::kInverseEvenOdd_FillType;
        default:
            GrCrash("Unexpected fill.");
            return SkPath::kWinding_FillType;
    }
}

////////////////////////////////////////////////////////////////////////////////
// gets device coord bounds of path (not considering the fill) and clip. The
// path bounds will be a subset of the clip bounds. returns false if
// path bounds would be empty.
bool get_path_and_clip_bounds(const GrDrawTarget* target,
                              const SkPath& path,
                              const GrVec* translate,
                              GrIRect* pathBounds,
                              GrIRect* clipBounds) {
    // compute bounds as intersection of rt size, clip, and path
    const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
    if (NULL == rt) {
        return false;
    }
    *pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
    const GrClip& clip = target->getClip();
    if (clip.hasConservativeBounds()) {
        clip.getConservativeBounds().roundOut(clipBounds);
        if (!pathBounds->intersect(*clipBounds)) {
            return false;
        }
    } else {
        // pathBounds is currently the rt extent, set clip bounds to that rect.
        *clipBounds = *pathBounds;
    }
    GrRect pathSBounds = path.getBounds();
    if (!pathSBounds.isEmpty()) {
        if (NULL != translate) {
            pathSBounds.offset(*translate);
        }
        target->getDrawState().getViewMatrix().mapRect(&pathSBounds,
                                                        pathSBounds);
        GrIRect pathIBounds;
        pathSBounds.roundOut(&pathIBounds);
        if (!pathBounds->intersect(pathIBounds)) {
            // set the correct path bounds, as this would be used later.
            *pathBounds = pathIBounds;
            return false;
        }
    } else {
        *pathBounds = GrIRect::EmptyIRect();
        return false;
    }
    return true;
}

/*
 * Convert a boolean operation into a transfer mode code
 */
SkXfermode::Mode op_to_mode(SkRegion::Op op) {

    static const SkXfermode::Mode modeMap[] = {
        SkXfermode::kDstOut_Mode,   // kDifference_Op
        SkXfermode::kMultiply_Mode, // kIntersect_Op
        SkXfermode::kSrcOver_Mode,  // kUnion_Op
        SkXfermode::kXor_Mode,      // kXOR_Op
        SkXfermode::kClear_Mode,    // kReverseDifference_Op
        SkXfermode::kSrc_Mode,      // kReplace_Op
    };

    return modeMap[op];
}

}

/**
 * Draw a single rect element of the clip stack into the accumulation bitmap
 */
void GrSWMaskHelper::draw(const GrRect& clientRect, SkRegion::Op op,
                          bool antiAlias, GrColor color) {
    SkPaint paint;

    SkXfermode* mode = SkXfermode::Create(op_to_mode(op));

    paint.setXfermode(mode);
    paint.setAntiAlias(antiAlias);
    paint.setColor(color);

    fDraw.drawRect(clientRect, paint);

    SkSafeUnref(mode);
}

/**
 * Draw a single path element of the clip stack into the accumulation bitmap
 */
void GrSWMaskHelper::draw(const SkPath& clientPath, SkRegion::Op op,
                          GrPathFill fill, bool antiAlias, GrColor color) {

    SkPaint paint;
    SkPath tmpPath;
    const SkPath* pathToDraw = &clientPath;
    if (kHairLine_GrPathFill == fill) {
        paint.setStyle(SkPaint::kStroke_Style);
        paint.setStrokeWidth(SK_Scalar1);
    } else {
        paint.setStyle(SkPaint::kFill_Style);
        SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
        if (skfill != pathToDraw->getFillType()) {
            tmpPath = *pathToDraw;
            tmpPath.setFillType(skfill);
            pathToDraw = &tmpPath;
        }
    }
    SkXfermode* mode = SkXfermode::Create(op_to_mode(op));

    paint.setXfermode(mode);
    paint.setAntiAlias(antiAlias);
    paint.setColor(color);

    fDraw.drawPath(*pathToDraw, paint);

    SkSafeUnref(mode);
}

bool GrSWMaskHelper::init(const GrIRect& pathDevBounds,
                          const GrPoint* translate,
                          bool useMatrix) {
    if (useMatrix) {
        fMatrix = fContext->getMatrix();
    } else {
        fMatrix.setIdentity();
    }

    if (NULL != translate) {
        fMatrix.postTranslate(translate->fX, translate->fY);
    }

    fMatrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
                          -pathDevBounds.fTop * SK_Scalar1);
    GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
                                     pathDevBounds.height());

    fBM.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
    if (!fBM.allocPixels()) {
        return false;
    }
    sk_bzero(fBM.getPixels(), fBM.getSafeSize());

    sk_bzero(&fDraw, sizeof(fDraw));
    fRasterClip.setRect(bounds);
    fDraw.fRC    = &fRasterClip;
    fDraw.fClip  = &fRasterClip.bwRgn();
    fDraw.fMatrix = &fMatrix;
    fDraw.fBitmap = &fBM;
    return true;
}

/**
 * Get a texture (from the texture cache) of the correct size & format
 */
bool GrSWMaskHelper::getTexture(GrAutoScratchTexture* tex) {
    GrTextureDesc desc;
    desc.fWidth = fBM.width();
    desc.fHeight = fBM.height();
    desc.fConfig = kAlpha_8_GrPixelConfig;

    tex->set(fContext, desc);
    GrTexture* texture = tex->texture();

    if (NULL == texture) {
        return false;
    }

    return true;
}

/**
 * Move the result of the software mask generation back to the gpu
 */
void GrSWMaskHelper::toTexture(GrTexture *texture) {
    SkAutoLockPixels alp(fBM);
    texture->writePixels(0, 0, fBM.width(), fBM.height(),
                         kAlpha_8_GrPixelConfig,
                         fBM.getPixels(), fBM.rowBytes());
}

namespace {
////////////////////////////////////////////////////////////////////////////////
/**
 * sw rasterizes path to A8 mask using the context's matrix and uploads to a
 * scratch texture.
 */
bool sw_draw_path_to_mask_texture(const SkPath& clientPath,
                                  const GrIRect& pathDevBounds,
                                  GrPathFill fill,
                                  GrContext* context,
                                  const GrPoint* translate,
                                  GrAutoScratchTexture* tex,
                                  bool antiAlias) {
    GrSWMaskHelper helper(context);

    if (!helper.init(pathDevBounds, translate, true)) {
        return false;
    }

    helper.draw(clientPath, SkRegion::kReplace_Op,
                fill, antiAlias, SK_ColorWHITE);

    if (!helper.getTexture(tex)) {
        return false;
    }

    helper.toTexture(tex->texture());

    return true;
}

////////////////////////////////////////////////////////////////////////////////
void draw_around_inv_path(GrDrawTarget* target,
                          GrDrawState::StageMask stageMask,
                          const GrIRect& clipBounds,
                          const GrIRect& pathBounds) {
    GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
    GrRect rect;
    if (clipBounds.fTop < pathBounds.fTop) {
        rect.iset(clipBounds.fLeft, clipBounds.fTop,
                    clipBounds.fRight, pathBounds.fTop);
        target->drawSimpleRect(rect, NULL, stageMask);
    }
    if (clipBounds.fLeft < pathBounds.fLeft) {
        rect.iset(clipBounds.fLeft, pathBounds.fTop,
                    pathBounds.fLeft, pathBounds.fBottom);
        target->drawSimpleRect(rect, NULL, stageMask);
    }
    if (clipBounds.fRight > pathBounds.fRight) {
        rect.iset(pathBounds.fRight, pathBounds.fTop,
                    clipBounds.fRight, pathBounds.fBottom);
        target->drawSimpleRect(rect, NULL, stageMask);
    }
    if (clipBounds.fBottom > pathBounds.fBottom) {
        rect.iset(clipBounds.fLeft, pathBounds.fBottom,
                    clipBounds.fRight, clipBounds.fBottom);
        target->drawSimpleRect(rect, NULL, stageMask);
    }
}

}

////////////////////////////////////////////////////////////////////////////////
// return true on success; false on failure
bool GrSoftwarePathRenderer::onDrawPath(const SkPath& path,
                                        GrPathFill fill,
                                        const GrVec* translate,
                                        GrDrawTarget* target,
                                        GrDrawState::StageMask stageMask,
                                        bool antiAlias) {

    if (NULL == fContext) {
        return false;
    }

    GrAutoScratchTexture ast;
    GrIRect pathBounds, clipBounds;
    if (!get_path_and_clip_bounds(target, path, translate,
                                  &pathBounds, &clipBounds)) {
        if (GrIsFillInverted(fill)) {
            draw_around_inv_path(target, stageMask,
                                 clipBounds, pathBounds);
        }
        return true;
    }
    if (sw_draw_path_to_mask_texture(path, pathBounds,
                                     fill, fContext,
                                     translate, &ast, antiAlias)) {
        GrTexture* texture = ast.texture();
        GrAssert(NULL != texture);
        GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
        enum {
            // the SW path renderer shares this stage with glyph
            // rendering (kGlyphMaskStage in GrBatchedTextContext)
            kPathMaskStage = GrPaint::kTotalStages,
        };
        GrAssert(NULL == target->drawState()->getTexture(kPathMaskStage));
        target->drawState()->setTexture(kPathMaskStage, texture);
        target->drawState()->sampler(kPathMaskStage)->reset();
        GrScalar w = GrIntToScalar(pathBounds.width());
        GrScalar h = GrIntToScalar(pathBounds.height());
        GrRect maskRect = GrRect::MakeWH(w / texture->width(),
                                         h / texture->height());
        const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
        srcRects[kPathMaskStage] = &maskRect;
        stageMask |= 1 << kPathMaskStage;
        GrRect dstRect = GrRect::MakeLTRB(
                              SK_Scalar1* pathBounds.fLeft,
                              SK_Scalar1* pathBounds.fTop,
                              SK_Scalar1* pathBounds.fRight,
                              SK_Scalar1* pathBounds.fBottom);
        target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
        target->drawState()->setTexture(kPathMaskStage, NULL);
        if (GrIsFillInverted(fill)) {
            draw_around_inv_path(target, stageMask,
                                 clipBounds, pathBounds);
        }
        return true;
    }

    return false;
}
<|endoftext|>


<commit_before>/***********************************************************************************************************************
 * Copyright (C) 2016 Andrew Zonenberg and contributors                                                                *
 *                                                                                *
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General   *
 * Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for     *
 * more details.                                                                                *
 *                                                                                *
 * You should have received a copy of the GNU Lesser General Public License along with this program; if not, you may   *
 * find one here:                                                                                *
 * https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt                                                              *
 * or you may search the http://www.gnu.org website for the version 2.1 license, or you may write to the Free Software *
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA                                      *
 **********************************************************************************************************************/

#include "Greenpak4.h"
#include <stdio.h>
#include <stdlib.h>

using namespace std;

Greenpak4NetlistEntity::~Greenpak4NetlistEntity()
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Construction / destruction

Greenpak4Netlist::Greenpak4Netlist(std::string fname)
	: m_topModule(NULL)
	, m_parseOK(true)
{
	//Read the netlist
	FILE* fp = fopen(fname.c_str(), "rb");
	if(fp == NULL)
	{
		LogError("Failed to open netlist file %s\n", fname.c_str());
		m_parseOK = false;
		return;
	}
	if(0 != fseek(fp, 0, SEEK_END))
	{
		LogError("Failed to seek to end of netlist file %s\n", fname.c_str());
		m_parseOK = false;
		return;
	}
	size_t len = ftell(fp);
	if(0 != fseek(fp, 0, SEEK_SET))
	{
		LogError("Failed to seek to start of netlist file %s\n", fname.c_str());
		m_parseOK = false;
		return;
	}
	char* json_string = new char[len + 1];
	json_string[len] = '\0';
	if(len != fread(json_string, 1, len, fp))
	{
		LogError("Failed read contents of netlist file %s\n", fname.c_str());
		m_parseOK = false;
		return;
	}
	fclose(fp);

	//Parse the JSON
	json_tokener* tok = json_tokener_new();
	if(!tok)
	{
		LogError("Failed to create JSON tokenizer object\n");
		m_parseOK = false;
		return;
	}
	json_tokener_error err;
	json_object* object = json_tokener_parse_verbose(json_string, &err);
	if(NULL == object)
	{
		const char* desc = json_tokener_error_desc(err);
		LogError("JSON parsing failed (err = %s)\n", desc);
		m_parseOK = false;
		return;
	}

	//Read stuff from it
	Load(object);

	//Clean up
	json_object_put(object);
	json_tokener_free(tok);
	delete[] json_string;
}

Greenpak4Netlist::~Greenpak4Netlist()
{
	//Delete modules
	for(auto x : m_modules)
		delete x.second;
	m_modules.clear();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Parsing stuff

/**
	@brief Top-level parsing routine

	Should only have creator and modules
 */
void Greenpak4Netlist::Load(json_object* object)
{
	json_object_iterator end = json_object_iter_end(object);
	for(json_object_iterator it = json_object_iter_begin(object);
		!json_object_iter_equal(&it, &end);
		json_object_iter_next(&it))
	{
		//See what we got
		string name = json_object_iter_peek_name(&it);
		json_object* child = json_object_iter_peek_value(&it);

		//Creator of the file (expecting a string)
		if(name == "creator")
		{
			if(!json_object_is_type(child, json_type_string))
			{
				LogError("netlist creator should be of type string but isn't\n");
				m_parseOK = false;
				return;
			}
			m_creator = json_object_get_string(child);
			LogNotice("Netlist creator: %s\n", m_creator.c_str());
		}

		//Modules in the file (expecting an object)
		else if(name == "modules")
		{
			if(!json_object_is_type(child, json_type_object))
			{
				LogError("netlist modules should be of type object but isn't\n");
				m_parseOK = false;
				return;
			}

			//Load them
			LoadModules(child);
		}

		//Something bad
		else
		{
			LogError("Unknown top-level JSON object \"%s\"\n", name.c_str());
			m_parseOK = false;
			return;
		}
	}

	IndexNets(true);
}

/**
	@brief Destroy all index data.
 */
void Greenpak4Netlist::ClearIndexes()
{
	for(auto node : m_nodes)
	{
		node->m_nodeports.clear();
		node->m_ports.clear();
	}

	m_nodes.clear();
}

/**
	@brief Force a re-index after changing the netlist (by PAR-level optimizations etc)
 */
void Greenpak4Netlist::Reindex(bool verbose)
{
	ClearIndexes();
	IndexNets(verbose);
}

/**
	@brief Index the nets so that each net has a list of cell ports it connects to.

	Has to be done as a second pass because there may be cycles in the netlist preventing us from resolving names
	as we parse the JSON
 */
void Greenpak4Netlist::IndexNets(bool verbose)
{
	if(verbose)
		LogNotice("Indexing...\n");

	LogIndenter li;

	//Loop over all of our ports and add them to the associated nets
	for(auto it = m_topModule->port_begin(); it != m_topModule->port_end(); it ++)
	{
		Greenpak4NetlistPort* port = it->second;
		if(verbose)
			LogDebug("Port %s connects to:\n", it->first.c_str());
		LogIndenter li;

		for(unsigned int i=0; i<port->m_nodes.size(); i++)
		{
			auto x = port->m_nodes[i];

			if(verbose)
				LogDebug("bit %u: node %s\n", i, port->m_nodes[i]->m_name.c_str());
			x->m_ports.push_back(port);
		}
	}

	//Loop over all of our cells and add their connections
	for(auto it = m_topModule->cell_begin(); it != m_topModule->cell_end(); it ++)
	{
		Greenpak4NetlistCell* cell = it->second;
		if(verbose)
			LogDebug("Cell %s connects to:\n", it->first.c_str());
		LogIndenter li;
		for(auto jt : cell->m_connections)
		{
			string cellname = jt.first;
			auto net = jt.second;
			bool vector = false;
			if(net.size() != 1)
				vector = true;
			for(unsigned int i=0; i<net.size(); i++)
			{
				Greenpak4NetlistNode* node = net[i];
				if(verbose)
				{
					if(vector)
						LogDebug("%s[%u]: net %s\n", cellname.c_str(), i, node->m_name.c_str());
					else
						LogDebug("%s: net %s\n", cellname.c_str(), node->m_name.c_str());
				}
				node->m_nodeports.push_back(Greenpak4NetlistNodePoint(cell, cellname, i, vector));
			}
		}
	}

	//Make a set of the nodes to avoid duplication.
	//Note that NULL is legal in vector nets if some bits were optimized out
	for(auto it = m_topModule->net_begin(); it != m_topModule->net_end(); it ++)
	{
		if(it->second != NULL)
			m_nodes.insert(it->second);
	}

	//Print them out
	if(verbose)
	{
		for(auto node : m_nodes)
		{
			LogDebug("Node %s connects to:\n", node->m_name.c_str());
			LogIndenter li;
			for(auto p : node->m_ports)
				LogDebug("port %s\n", p->m_name.c_str());
			for(auto c : node->m_nodeports)
				LogDebug("cell %s port %s\n", c.m_cell->m_name.c_str(), c.m_portname.c_str());
		}
	}
}

/**
	@brief Module parsing routine

	Loads all of the modules in the netlist
 */
void Greenpak4Netlist::LoadModules(json_object* object)
{
	LogNotice("\nLoading modules...\n");
	LogIndenter li;

	json_object_iterator end = json_object_iter_end(object);
	for(json_object_iterator it = json_object_iter_begin(object);
		!json_object_iter_equal(&it, &end);
		json_object_iter_next(&it))
	{
		//See what we got
		string name = json_object_iter_peek_name(&it);
		json_object* child = json_object_iter_peek_value(&it);

		//Verify it's an object
		if(!json_object_is_type(child, json_type_object))
		{
			LogError("netlist module entry should be of type object but isn't\n");
			m_parseOK = false;
			return;
		}

		//TODO: If the child object is a standard library cell, don't bother parsing it?

		//Load it
		Greenpak4NetlistModule *module = new Greenpak4NetlistModule(this, name, child);
		if(!module->Validate())
		{
			m_parseOK = false;
			return;
		}
		m_modules[name] = module;

		//Did we get a top-level module?
		if(module->m_attributes.find("top") != module->m_attributes.end())
		{
			if(m_topModule)
			{
				LogError("More than one top-level module in netlist\n");
				m_parseOK = false;
				return;
			}
			m_topModule = module;
		}
	}

	//Verify we got the top-level module we expected
	if(m_topModule == NULL)
	{
		LogError("Unable to find a top-level module in netlist\n");
		m_parseOK = false;
		return;
	}
}
<commit_msg>greenpak4: Fixed memory leak found by asan<commit_after>/***********************************************************************************************************************
 * Copyright (C) 2016 Andrew Zonenberg and contributors                                                                *
 *                                                                                *
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General   *
 * Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for     *
 * more details.                                                                                *
 *                                                                                *
 * You should have received a copy of the GNU Lesser General Public License along with this program; if not, you may   *
 * find one here:                                                                                *
 * https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt                                                              *
 * or you may search the http://www.gnu.org website for the version 2.1 license, or you may write to the Free Software *
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA                                      *
 **********************************************************************************************************************/

#include "Greenpak4.h"
#include <stdio.h>
#include <stdlib.h>

using namespace std;

Greenpak4NetlistEntity::~Greenpak4NetlistEntity()
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Construction / destruction

Greenpak4Netlist::Greenpak4Netlist(std::string fname)
	: m_topModule(NULL)
	, m_parseOK(true)
{
	//Read the netlist
	FILE* fp = fopen(fname.c_str(), "rb");
	if(fp == NULL)
	{
		LogError("Failed to open netlist file %s\n", fname.c_str());
		m_parseOK = false;
		return;
	}
	if(0 != fseek(fp, 0, SEEK_END))
	{
		LogError("Failed to seek to end of netlist file %s\n", fname.c_str());
		m_parseOK = false;
		return;
	}
	size_t len = ftell(fp);
	if(0 != fseek(fp, 0, SEEK_SET))
	{
		LogError("Failed to seek to start of netlist file %s\n", fname.c_str());
		m_parseOK = false;
		return;
	}
	char* json_string = new char[len + 1];
	json_string[len] = '\0';
	if(len != fread(json_string, 1, len, fp))
	{
		LogError("Failed read contents of netlist file %s\n", fname.c_str());
		m_parseOK = false;
		return;
	}
	fclose(fp);

	//Parse the JSON
	json_tokener* tok = json_tokener_new();
	if(!tok)
	{
		LogError("Failed to create JSON tokenizer object\n");
		m_parseOK = false;
		return;
	}
	json_tokener_error err;
	json_object* object = json_tokener_parse_verbose(json_string, &err);
	if(NULL == object)
	{
		const char* desc = json_tokener_error_desc(err);
		LogError("JSON parsing failed (err = %s)\n", desc);
		m_parseOK = false;
		return;
	}

	//Read stuff from it
	Load(object);

	//Clean up
	json_object_put(object);
	json_tokener_free(tok);
	delete[] json_string;
}

Greenpak4Netlist::~Greenpak4Netlist()
{
	//Delete modules
	for(auto x : m_modules)
		delete x.second;
	m_modules.clear();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Parsing stuff

/**
	@brief Top-level parsing routine

	Should only have creator and modules
 */
void Greenpak4Netlist::Load(json_object* object)
{
	json_object_iterator end = json_object_iter_end(object);
	for(json_object_iterator it = json_object_iter_begin(object);
		!json_object_iter_equal(&it, &end);
		json_object_iter_next(&it))
	{
		//See what we got
		string name = json_object_iter_peek_name(&it);
		json_object* child = json_object_iter_peek_value(&it);

		//Creator of the file (expecting a string)
		if(name == "creator")
		{
			if(!json_object_is_type(child, json_type_string))
			{
				LogError("netlist creator should be of type string but isn't\n");
				m_parseOK = false;
				return;
			}
			m_creator = json_object_get_string(child);
			LogNotice("Netlist creator: %s\n", m_creator.c_str());
		}

		//Modules in the file (expecting an object)
		else if(name == "modules")
		{
			if(!json_object_is_type(child, json_type_object))
			{
				LogError("netlist modules should be of type object but isn't\n");
				m_parseOK = false;
				return;
			}

			//Load them
			LoadModules(child);
		}

		//Something bad
		else
		{
			LogError("Unknown top-level JSON object \"%s\"\n", name.c_str());
			m_parseOK = false;
			return;
		}
	}

	IndexNets(true);
}

/**
	@brief Destroy all index data.
 */
void Greenpak4Netlist::ClearIndexes()
{
	for(auto node : m_nodes)
	{
		node->m_nodeports.clear();
		node->m_ports.clear();
	}

	m_nodes.clear();
}

/**
	@brief Force a re-index after changing the netlist (by PAR-level optimizations etc)
 */
void Greenpak4Netlist::Reindex(bool verbose)
{
	ClearIndexes();
	IndexNets(verbose);
}

/**
	@brief Index the nets so that each net has a list of cell ports it connects to.

	Has to be done as a second pass because there may be cycles in the netlist preventing us from resolving names
	as we parse the JSON
 */
void Greenpak4Netlist::IndexNets(bool verbose)
{
	if(verbose)
		LogNotice("Indexing...\n");

	LogIndenter li;

	//Loop over all of our ports and add them to the associated nets
	for(auto it = m_topModule->port_begin(); it != m_topModule->port_end(); it ++)
	{
		Greenpak4NetlistPort* port = it->second;
		if(verbose)
			LogDebug("Port %s connects to:\n", it->first.c_str());
		LogIndenter li;

		for(unsigned int i=0; i<port->m_nodes.size(); i++)
		{
			auto x = port->m_nodes[i];

			if(verbose)
				LogDebug("bit %u: node %s\n", i, port->m_nodes[i]->m_name.c_str());
			x->m_ports.push_back(port);
		}
	}

	//Loop over all of our cells and add their connections
	for(auto it = m_topModule->cell_begin(); it != m_topModule->cell_end(); it ++)
	{
		Greenpak4NetlistCell* cell = it->second;
		if(verbose)
			LogDebug("Cell %s connects to:\n", it->first.c_str());
		LogIndenter li;
		for(auto jt : cell->m_connections)
		{
			string cellname = jt.first;
			auto net = jt.second;
			bool vector = false;
			if(net.size() != 1)
				vector = true;
			for(unsigned int i=0; i<net.size(); i++)
			{
				Greenpak4NetlistNode* node = net[i];
				if(verbose)
				{
					if(vector)
						LogDebug("%s[%u]: net %s\n", cellname.c_str(), i, node->m_name.c_str());
					else
						LogDebug("%s: net %s\n", cellname.c_str(), node->m_name.c_str());
				}
				node->m_nodeports.push_back(Greenpak4NetlistNodePoint(cell, cellname, i, vector));
			}
		}
	}

	//Make a set of the nodes to avoid duplication.
	//Note that NULL is legal in vector nets if some bits were optimized out
	for(auto it = m_topModule->net_begin(); it != m_topModule->net_end(); it ++)
	{
		if(it->second != NULL)
			m_nodes.insert(it->second);
	}

	//Print them out
	if(verbose)
	{
		for(auto node : m_nodes)
		{
			LogDebug("Node %s connects to:\n", node->m_name.c_str());
			LogIndenter li;
			for(auto p : node->m_ports)
				LogDebug("port %s\n", p->m_name.c_str());
			for(auto c : node->m_nodeports)
				LogDebug("cell %s port %s\n", c.m_cell->m_name.c_str(), c.m_portname.c_str());
		}
	}
}

/**
	@brief Module parsing routine

	Loads all of the modules in the netlist
 */
void Greenpak4Netlist::LoadModules(json_object* object)
{
	LogNotice("\nLoading modules...\n");
	LogIndenter li;

	json_object_iterator end = json_object_iter_end(object);
	for(json_object_iterator it = json_object_iter_begin(object);
		!json_object_iter_equal(&it, &end);
		json_object_iter_next(&it))
	{
		//See what we got
		string name = json_object_iter_peek_name(&it);
		json_object* child = json_object_iter_peek_value(&it);

		//Verify it's an object
		if(!json_object_is_type(child, json_type_object))
		{
			LogError("netlist module entry should be of type object but isn't\n");
			m_parseOK = false;
			return;
		}

		//TODO: If the child object is a standard library cell, don't bother parsing it?

		//Load it
		Greenpak4NetlistModule *module = new Greenpak4NetlistModule(this, name, child);
		if(!module->Validate())
		{
			delete module;
			m_parseOK = false;
			return;
		}
		m_modules[name] = module;

		//Did we get a top-level module?
		if(module->m_attributes.find("top") != module->m_attributes.end())
		{
			if(m_topModule)
			{
				LogError("More than one top-level module in netlist\n");
				m_parseOK = false;
				return;
			}
			m_topModule = module;
		}
	}

	//Verify we got the top-level module we expected
	if(m_topModule == NULL)
	{
		LogError("Unable to find a top-level module in netlist\n");
		m_parseOK = false;
		return;
	}
}
<|endoftext|>