diff -r b685c59de105 -r fe49e33862e2 themeinstaller/source/src/com/nokia/tools/themeinstaller/odtconverter/DOMExternalizer.java --- a/themeinstaller/source/src/com/nokia/tools/themeinstaller/odtconverter/DOMExternalizer.java Thu Aug 19 09:43:47 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,718 +0,0 @@ -/* -* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). -* All rights reserved. -* This component and the accompanying materials are made available -* under the terms of "Eclipse Public License v1.0" -* which accompanies this distribution, and is available -* at the URL "http://www.eclipse.org/legal/epl-v10.html". -* -* Initial Contributors: -* Nokia Corporation - initial contribution. -* -* Contributors: -* -* Description: Externalizes a DOM Document to a byte array. - * -*/ - - -package com.nokia.tools.themeinstaller.odtconverter; - -import java.awt.Color; -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import com.nokia.tools.themeinstaller.cssparser.CSSDOMProcessor; -import com.nokia.tools.themeinstaller.cssparser.CSSHandler; -import com.nokia.tools.themeinstaller.cssparser.PseudoClassResolver; - -/** - * Externalizes DOM Document to a byte array. - */ -public class DOMExternalizer - { - - // CONSTANTS - // Text elements according to CXnDomVisitor::KXnElementVisitorTable and - // CXnODTParser - private static final String TEXT_ELEMENT = "text"; - private static final String DESC_ELEMENT = "desc"; - private static final String MARQUEE_ELEMENT = "marquee"; - private static final String OBJECT_ELEMENT = "object"; - private static final String NEWSTICKER_ELEMENT = "newsticker"; - - // Attribute name if node is refnode - private static final String REF_NODE = "ref"; - - // List types - private static final int UNKNOWN = -1; - private static final int NODE = 0; - private static final int ATTRIBUTE = 1; - private static final int PROPERTY = 2; - - // The Constant COLOR_TABLE_SIZE - private static final int COLOR_TABLE_SIZE = 3; - - // Pseudo class resolver - private PseudoClassResolver iPseudoResolver; - - // The value type resolver - private ValueTypeResolver iValueTypeResolver; - - // String pool - private StringPool iStringPool; - - // DOM Document - private Document iDocument; - - // Byte output stream for delivering the externalized data - private ByteArrayOutputStream iBaos; - - // Data output stream for writing to the baos - private ODTDataOutputStream iODTDos; - - // Node id and counter - private int iCurrentNodeId = 0; - - /** CSSDOMProsessor for checking property's inheritance value. */ - private CSSDOMProcessor iCSSDOMProsessor; - - /** - * Constructor. - * @param aDocument DOM Document to externalize - */ - public DOMExternalizer( Document aDocument ) - { - iPseudoResolver = new PseudoClassResolver(); - iValueTypeResolver = new ValueTypeResolver(); - iCSSDOMProsessor = new CSSDOMProcessor(); - iStringPool = new StringPool(); - iDocument = aDocument; - iBaos = new ByteArrayOutputStream(); - iODTDos = new ODTDataOutputStream( iBaos ); - } - - /* (non-Javadoc) - * @see java.lang.Object#finalize() - */ - protected void finalize() throws Throwable - { - iODTDos.close(); - iBaos.close(); - } - - /** - * Externalizes the DOM document and string pool to a byte array. - * @return Byte array containing the document - * @throws IOException if writing to a stream fails - * @throws ODTException - */ - public byte[] getByteArray() throws IOException, ODTException - { - ByteArrayOutputStream result = new ByteArrayOutputStream(); - byte[] resultArray = null; - - try - { - // Externalize the DOM - doExternalize(); - - // Externalize the string pool - result.write( iStringPool.toByteArray() ); - - // Write the dom contents to the result baos - result.write( iBaos.toByteArray() ); - - resultArray = result.toByteArray(); - } - finally - { - if( result != null ) - { - result.close(); - } - } - - return resultArray; - } - - /** - * Do the externalization process. - * @throws IOException if data output stream can not be written - * @throws ODTException if there is an error with property value externalization - */ - private void doExternalize() throws IOException, ODTException - { - Node rootElement = iDocument.getDocumentElement(); - - if( rootElement != null ) - { - // Root node exists - iODTDos.writeBoolean( true ); - externalizeNode( ( Node )rootElement, true ); - } - else - { - // No root node - iODTDos.writeBoolean( false ); - } - } - - /** - * Externalizes a node in the DOM tree. - * @param aNode Node to externalize - * @param aRootNode true, if this is the root node of the tree - * @throws IOException if data output stream can not be written - * @throws ODTException if there is an error with property value externalization - */ - private void externalizeNode( Node aNode, boolean aRootNode ) - throws IOException, ODTException - { - // Write name - String name = aNode.getNodeName(); - int nameRef = iStringPool.addString( name ); - iODTDos.writeInt16( nameRef ); - - // Write name space - String ns = aNode.getNamespaceURI(); - int nsRef = iStringPool.addString( ns ); - iODTDos.writeInt16( nsRef ); - - // Check and write refnode boolean - iODTDos.writeBoolean( checkRefNode( aNode ) ); - - boolean textNodeFound = false; - - // Write parsed character data - StringBuffer pcData = new StringBuffer(); - if( TEXT_ELEMENT.equals( name ) || - DESC_ELEMENT.equals( name ) || - MARQUEE_ELEMENT.equals( name ) || - OBJECT_ELEMENT.equals( name ) || - NEWSTICKER_ELEMENT.equals( name ) ) - { - NodeList list = aNode.getChildNodes(); - - for( int i = 0; i < list.getLength() ; i++ ) - { - Node nod = list.item( i ); - if( nod.getNodeType() == Node.TEXT_NODE ) - { - textNodeFound = true; - String textNodeValue = nod.getNodeValue(); - - pcData.append( textNodeValue ); - } - } - } - - // Write data length and the data - iODTDos.writeBoolean( textNodeFound ); - if( textNodeFound ) - { - // Write text length - iODTDos.writeInt16( pcData.length() ); - - // Write text node value - iODTDos.writeString8( pcData.toString() ); - } - // Update the counter and write node id - iODTDos.writeInt32( iCurrentNodeId++ ); - - // Externalize the child list - externalizeNodeList( aNode ); - - // Externalize the attribute list - externalizeAttributeList( aNode ); - - // Externalize the property list - externalizePropertyList( aNode ); - } - - /** - * Checks if node is refnode. - * Node is refnode if some of node's attributes name is "ref". - * @param aNode Node containing the attributes - * @return boolean true if node is refnode, otherwise false - */ - private boolean checkRefNode( Node aNode ) - { - boolean refNode = false; - NamedNodeMap list = aNode.getAttributes(); - for ( int i = 0; i < list.getLength(); i++ ) - { - Node node = list.item( i ); - if ( nodeType( node ) == ATTRIBUTE ) - { - if( node.getNodeName().equals( REF_NODE ) ) - { - refNode = true; - } - } - } - return refNode; - } - - /** - * Externalizes attributes of a node. - * @param aNode Node containing the attributes - * @throws IOException if writing to a stream fails - * @throws ODTException - */ - private void externalizeAttributeNode( Node aNode ) - throws IOException, ODTException - { - // Write name - String name = aNode.getNodeName(); - int nameRef = iStringPool.addString( name ); - iODTDos.writeInt16( nameRef ); - - // Write value - String value = aNode.getNodeValue(); - int valueRef = iStringPool.addString( value ); - iODTDos.writeInt16( valueRef ); - } - - /** - * Externalizes a property node. - * - * @param aNode Node containing the properties - * @param aParentNode Node's parent node - * - * @throws IOException if data output stream can not be written - * @throws ODTException if there is an error with property - * value externalization - */ - private void externalizePropertyNode( Node aParentNode, Node aNode ) - throws IOException, ODTException - { - // Get property node attributes: property name, values and pseudo class - NamedNodeMap list = aNode.getAttributes(); - - // Property value list - boolean isInherited = externalizePropertyValueList( aParentNode, list ); - - iODTDos.writeBoolean( isInherited ); - - // Resolve pseudo class - int pseudoClass = PseudoClassResolver.NONE; - - int count = list.getLength(); - for( int i = 0; i < count; i++ ) - { - // Browse through all attributes of the style property element and - // seek for a pseudo class - Node item = list.item( i ); - if( item.getNodeName().equals( CSSDOMProcessor.STRING_PSEUDOCLASS ) ) - { - pseudoClass = iPseudoResolver.getKey( item.getNodeValue() ); - if( pseudoClass == UNKNOWN ) - { - throw new ODTException( "Error externalizing ODT/styles: " + - "unknown pseudo class" ); - } - break; - } - } - - // Pseudo class -> int8 - iODTDos.writeByte( pseudoClass ); - } - - /** - * Externalize a list of nodes. - * @param aParentNode Parent node - * @throws IOException if data output stream can not be written - * @throws ODTException if there is an error with property value externalization - */ - private void externalizeNodeList( Node aParentNode ) throws IOException, ODTException - { - // Write list type - iODTDos.writeByte( NODE ); - - NodeList list = aParentNode.getChildNodes(); - - // Count element nodes - int count = countNodes( list ); - - // Write element node count - iODTDos.writeInt32( count ); - - for ( int i = 0; i < list.getLength(); i++ ) - { - Node node = list.item( i ); - - if ( nodeType( node ) == NODE ) - { - externalizeNode( node, false ); - } - } - } - - /** - * Externalize a list of attributes. - * @param aParentNode Node containing the attributes. - * @throws IOException if writing to a stream fails - * @throws ODTException - */ - private void externalizeAttributeList( Node aParentNode ) - throws IOException, ODTException - { - // Write list type - iODTDos.writeByte( ATTRIBUTE ); - - NamedNodeMap list = aParentNode.getAttributes(); - - // Count element nodes - int count = countAttributes( list ); - - // Write element node count - iODTDos.writeInt32( count ); - - for ( int i = 0; i < list.getLength(); i++ ) - { - Node node = list.item( i ); - - if ( nodeType( node ) == ATTRIBUTE ) - { - externalizeAttributeNode( node ); - } - } - } - - /** - * Externalize a list of properties. - * @param aParentNode Node containing the properties - * @throws IOException if data output stream can not be written - * @throws ODTException if there is an error with property value externalization - */ - private void externalizePropertyList( Node aParentNode ) throws IOException, ODTException - { - // Write list type - iODTDos.writeByte( PROPERTY ); - - NodeList list = aParentNode.getChildNodes(); - - // Count element nodes - int count = countProperties( list ); - - // Write element node count - iODTDos.writeInt32( count ); - - for ( int i = 0; i < list.getLength(); i++ ) - { - Node node = list.item( i ); - - if ( nodeType( node ) == PROPERTY ) - { - externalizePropertyNode( aParentNode, node ); - } - } - } - - /** - * Parses a Color from string. - * - * @param aColor Color values in String made by CSSHandler - * - * @return The color - * - * @throws ODTException the ODT exception - */ - private Color parseColorFromString( String aColor ) throws ODTException - { - String sx[] = aColor.split( CSSHandler.COMMA ); - int ix[] = new int[ sx.length ]; - - // LexicalUnit.SAC_RGBCOLOR knows color values with format - // rgb(0, 0, 0) and #000. That is, with three parameters - if ( sx.length != COLOR_TABLE_SIZE ) - { - throw new ODTException( "Error in DOM/style data externalization: " - + "RGB Values: parameter amount" ); - } - - for ( int i = 0; i < sx.length; i++ ) - { - if ( sx[ i ].contains( CSSHandler.SEPARATOR ) ) - { - // Check if single color's value is integer - Short valueType = iValueTypeResolver.getValue( Short - .valueOf( sx[ i ].substring( 0, sx[ i ] - .indexOf( CSSHandler.SEPARATOR ) ) ) ); - - if ( valueType.intValue() != ValueTypeResolver.E_NUMBER ) - { - throw new ODTException( - "Error in DOM/style data externalization: " - + "RGB Values: R, G or B not interger" ); - } - String redGreenBlue = sx[ i ].substring( sx[ i ] - .indexOf( CSSHandler.SEPARATOR ) + 1, sx[ i ] - .length() ); - Integer rgbValue = Integer.valueOf( redGreenBlue ); - ix[ i ] = rgbValue.intValue(); - } - else - { - throw new ODTException( - "Error in DOM/style data externalization: " - + "RGB Values: can't resolve value type" ); - } - } - return new Color( ix[ 0 ], ix[ 1 ], ix[ 2 ] ); - } - - /** - * Parses the Value Type from Value. - * - * @param aAttrValue The attribute value - * - * @return Parsed value as a string - * - * @throws IOException Signals that an I/O exception has occurred. - * @throws ODTException - */ - private String parseAttrValue( String aAttrValue, PropertyValue aPropValue ) - throws IOException, ODTException - { - if ( aAttrValue.length() > 0 ) - { - if ( aAttrValue.contains( "|" ) ) - { - String type = aAttrValue - .substring( 0, aAttrValue.indexOf( '|' ) ); - String value = aAttrValue.substring( - aAttrValue.indexOf( '|' ) + 1, aAttrValue.length() ); - - Short lexicalUnit = Short.valueOf( type ); - Short primitiveValueType = - iValueTypeResolver.getValue( lexicalUnit ); - - switch ( primitiveValueType.intValue() ) - { - case ValueTypeResolver.E_NUMBER: - double doubleValueInteger = Double.valueOf( value ).doubleValue(); - aPropValue.setRealValue( doubleValueInteger, - primitiveValueType.shortValue() ); - break; - case ValueTypeResolver.E_UNIT_VALUE: - case ValueTypeResolver.E_PERCENTAGE: - case ValueTypeResolver.E_EMS: - case ValueTypeResolver.E_EXS: - case ValueTypeResolver.E_PX: - case ValueTypeResolver.E_CM: - case ValueTypeResolver.E_MM: - case ValueTypeResolver.E_IN: - case ValueTypeResolver.E_PT: - case ValueTypeResolver.E_PC: - case ValueTypeResolver.E_DEG: - case ValueTypeResolver.E_RAD: - case ValueTypeResolver.E_GRAD: - case ValueTypeResolver.E_MS: - case ValueTypeResolver.E_S: - case ValueTypeResolver.E_HZ: - case ValueTypeResolver.E_KHZ: - double doubleValuePercentage = Double.valueOf( value ).doubleValue(); - aPropValue.setRealValue( doubleValuePercentage, - primitiveValueType.shortValue() ); - break; - case ValueTypeResolver.E_IDENT: - case ValueTypeResolver.E_STRING: - case ValueTypeResolver.E_URI: - case ValueTypeResolver.E_ATTR: - aPropValue.setString( new String( value ), - primitiveValueType.shortValue() ); - break; - case ValueTypeResolver.E_RGB_COLOR: - Color color = parseColorFromString(value); - aPropValue.setRgbValue( color ); - break; - default: - break; - } - - return value; - } - return aAttrValue; - } - return aAttrValue; - } - - /** - * Externalize a list of property values. - * - * @param aNode the a node - * @param aAttrList the a attr list - * - * @return true, if property is inherited - * - * @throws IOException if data output stream can not be written - * @throws ODTException if there is an error with externalizing property values - */ - private boolean externalizePropertyValueList( Node aNode, NamedNodeMap aAttrList ) - throws IOException, ODTException - { - PropertyValueList valueList = new PropertyValueList( iStringPool ); - - boolean isInherited = false; - String name = null; - String value = null; - - for ( int i = 0; i < aAttrList.getLength(); i++ ) - { - Node node = aAttrList.item( i ); - - if ( nodeType( node ) == ATTRIBUTE && - !node.getNodeName().equals( CSSDOMProcessor.STRING_PSEUDOCLASS ) ) - { - String attrName = node.getNodeName(); - String attrValue = node.getNodeValue(); - - if( attrName.equals( CSSDOMProcessor.STRING_NAME ) && - name == null ) - { - name = attrValue; - } - else if( attrName.startsWith( CSSDOMProcessor.STRING_VALUE ) ) - { - value = attrValue; - - // Checking if property is inherited. - // This emulates the behavior of the Symbian side implementation - // where this is true in following cases: - // 1. Value equals "inherited" - // 2. Property is inheritable and the element can inherit properties - // - // This means that also some properties that aren't actually - // inherited, are also set with value isIherited == "true" - isInherited = iCSSDOMProsessor.canInherit( (Element) aNode, name, value ); - - PropertyValue propValue = valueList.newItem(); - parseAttrValue( value, propValue ); - } - else - { - throw new ODTException( "Error in DOM/style data externalization: " + - "Property values" ); - } - } - } - - if( name != null && - value != null ) - { - // Write property name - int nameRef = iStringPool.addString( name ); - iODTDos.writeInt16( nameRef ); - - // Externalize the property value list to the stream - valueList.externalize( iODTDos ); - } - else - { - throw new ODTException( "Error in DOM/style data externalization: " + - "Property values" ); - } - return isInherited; - } - - /** - * Count element nodes in a node list. - * @param aList Node list - * @param aNodeType Node type to count - * @return Count of found nodes - */ - private static int countNodes( NodeList aList ) - { - int count = 0; - for( int i = 0; i < aList.getLength(); i++ ) - { - // Exclude elements that are style properties - if( nodeType( aList.item( i ) ) == NODE ) - { - count++; - } - } - - return count; - } - - /** - * Count attributes in a named node map. - * @param aList Node map - * @param aNodeType Node type to count - * @return Count of found nodes - */ - private static int countAttributes( NamedNodeMap aList ) - { - int count = 0; - for( int i = 0; i < aList.getLength(); i++ ) - { - if( nodeType( aList.item( i ) ) == ATTRIBUTE ) - { - count++; - } - } - - return count; - } - - /** - * Count properties in a node list. - * @param aList Node list - * @param aNodeType Node type to count - * @return Count of found nodes - */ - private static int countProperties( NodeList aList ) - { - int count = 0; - for( int i = 0; i < aList.getLength(); i++ ) - { - // Include only elements that are style properties - if( nodeType( aList.item( i ) ) == PROPERTY ) - { - count++; - } - } - - return count; - } - - /** - * Resolve node type. Possible types: NODE, ATTRIBUTE or PROPERTY - * @param aItem Node to resolve - * @return Type of the node. If the type can not be determined, UNKNOWN is returned - */ - private static int nodeType( Node aItem ) - { - int type = UNKNOWN; - - // Element that is not a style property element - if( aItem.getNodeType() == Node.ELEMENT_NODE && - !aItem.getNodeName().equals( CSSDOMProcessor.STRING_PROPERTY ) ) - { - type = NODE; - } - // Attribute nodes - else if( aItem.getNodeType() == Node.ATTRIBUTE_NODE ) - { - type = ATTRIBUTE; - } - // Style property element - else if( aItem.getNodeType() == Node.ELEMENT_NODE && - aItem.getNodeName().equals( CSSDOMProcessor.STRING_PROPERTY ) ) - { - type = PROPERTY; - } - - return type; - } - - }