blob: 67ee343902c67a309a8f4da2a0f00a90fa3563c2 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
package org.apache.openoffice.ooxml.parser.attribute;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import org.apache.openoffice.ooxml.parser.Log;
import org.apache.openoffice.ooxml.parser.NameMap;
import org.apache.openoffice.ooxml.parser.NamespaceMap;
import org.apache.openoffice.ooxml.parser.type.SimpleTypeManager;
/** Match a set of attributes from the document with the attribute
* specifications of a state.
*
*/
public class AttributeManager
{
/** Create a new AttributeManager for the attribute specifications that
* are given in the parse table.
*/
public AttributeManager (
final Vector<String[]> aData,
final NamespaceMap aNamespaceMap,
final NameMap aNameMap,
final NameMap aStateNameMap,
final SimpleTypeManager aSimpleTypeManager,
final Vector<String> aErrorsAndWarnings)
{
maStateIdToAttributesMap = new HashMap<>();
maNamespaceMap = aNamespaceMap;
maNameMap = aNameMap;
maStateNameMap = aStateNameMap;
maSimpleTypeManager = aSimpleTypeManager;
maErrorsAndWarnings = aErrorsAndWarnings;
ParseData(aData);
}
private void ParseData (final Vector<String[]> aData)
{
for (final String[] aLine : aData)
{
final int nStateId = Integer.parseInt(aLine[1]);
final int nPrefixId = Integer.parseInt(aLine[2]);
final boolean bCanBeUnqualified = aLine[3].startsWith("u");
final int nAttributeId = Integer.parseInt(aLine[4]);
final int nAttributeTypeId = aLine[5].equals("null") ? -1 : Integer.parseInt(aLine[5]);
final boolean bIsOptional = aLine[6].startsWith("o");
final String sDefault = aLine[7];
// State name.
final String sAttributeName = aLine[9];
// Attribute type name.
Map<Integer,AttributeDescriptor> aAttributesPerState = maStateIdToAttributesMap.get(nStateId);
if (aAttributesPerState == null)
{
aAttributesPerState = new HashMap<>();
maStateIdToAttributesMap.put(nStateId, aAttributesPerState);
}
final AttributeDescriptor aAttributeDescriptor = new AttributeDescriptor(
nPrefixId,
nAttributeId,
bCanBeUnqualified,
bIsOptional,
sDefault,
sAttributeName,
nAttributeTypeId);
aAttributesPerState.put(
(nPrefixId<<16)|nAttributeId,
aAttributeDescriptor);
if (bCanBeUnqualified)
aAttributesPerState.put(
nAttributeId,
aAttributeDescriptor);
}
}
/** For the state with id nStateId, match the attributes from the document
* with the attribute specifications of that state.
*/
public AttributeValues ParseAttributes (
final int nStateId,
final AttributeProvider aDocumentAttributes)
{
final AttributeValues aValues = new AttributeValues();
final Map<Integer,AttributeDescriptor> aAttributesPerState = maStateIdToAttributesMap.get(nStateId);
if (aAttributesPerState == null)
{
if (aDocumentAttributes.HasAttributes())
{
Log.Std.printf("state has not attributes defined but document provides %d attributes\n",
aDocumentAttributes.GetAttributeCount());
for (final String[] aEntry : aDocumentAttributes)
{
Log.Dbg.printf(" %s -> %s\n", aEntry[0], aEntry[1]);
}
throw new RuntimeException();
}
}
else
{
final Set<AttributeDescriptor> aUsedAttributes = new HashSet<>();
// Process all attributes from the document.
for (final String[] aEntry : aDocumentAttributes)
{
final String sRawValue = aEntry[2];
final AttributeDescriptor aAttributeDescriptor = ProcessAttribute(
aEntry[0],
aEntry[1],
sRawValue,
aAttributesPerState);
aUsedAttributes.add(aAttributeDescriptor);
final Object aProcessedValue = maSimpleTypeManager.PreprocessValue(
sRawValue,
aAttributeDescriptor);
if (aProcessedValue == null)
{
maSimpleTypeManager.PreprocessValue(
sRawValue,
aAttributeDescriptor);
throw new RuntimeException(
String.format("value '%s' of attribute '%s' is not recognized",
sRawValue,
aAttributeDescriptor.GetName()));
}
aValues.AddAttribute(
aAttributeDescriptor,
sRawValue,
aProcessedValue);
if (Log.Dbg != null)
{
if (aAttributeDescriptor == null)
Log.Dbg.printf("attribute %s%s is not known\n",
aEntry[0]==null ? "" : ":"+aEntry[0],
aEntry[1]);
else
Log.Dbg.printf("attribute %s:%s(%d:%d) has type %s(%d) and value %s('%s')\n",
maNamespaceMap.GetDescriptorForId(aAttributeDescriptor.GetNamespaceId()).Prefix,
maNameMap.GetNameForId(aAttributeDescriptor.GetNameId()),
aAttributeDescriptor.GetNamespaceId(),
aAttributeDescriptor.GetNameId(),
maStateNameMap.GetNameForId(aAttributeDescriptor.GetTypeId()),
aAttributeDescriptor.GetTypeId(),
aProcessedValue,
sRawValue);
}
}
// Check if all required attributes where given.
for (final AttributeDescriptor aAttribute : aAttributesPerState.values())
{
if ( ! aUsedAttributes.contains(aAttribute))
{
if ( ! aAttribute.IsOptional())
{
final String sMessage = String.format("attribute '"+aAttribute.GetName()+"' is not present but also not optional");
if (maErrorsAndWarnings != null)
maErrorsAndWarnings.add(sMessage);
else
throw new RuntimeException(sMessage);
}
else
{
// Add an entry that gives access to the default value.
aValues.AddAttribute(aAttribute, null, null);
}
}
}
}
return aValues;
}
private AttributeDescriptor ProcessAttribute (
final String sNamespace,
final String sAttributeName,
final String sAttributeValue,
final Map<Integer,AttributeDescriptor> aAttributesPerState)
{
final AttributeDescriptor aAttributeDescriptor;
if (sNamespace == null)
{
// Attribute name has no namespace.
final int nAttributeNameId = maNameMap.GetIdForName(sAttributeName);
aAttributeDescriptor = aAttributesPerState.get(nAttributeNameId);
}
else
{
// Attribute name has explicit namespace.
final NamespaceMap.NamespaceDescriptor aDescriptor = maNamespaceMap.GetDescriptorForURI(sNamespace);
final int nAttributeNameId = maNameMap.GetIdForName(sAttributeName);
aAttributeDescriptor = aAttributesPerState.get((aDescriptor.Id<<16) | nAttributeNameId);
}
return aAttributeDescriptor;
}
/** Remove the quotes around the given string.
* If it has the special value null (without quotes) then the null reference
* is returned.
*/
private String UnquoteString (final String sValue)
{
if (sValue.equals("null"))
return null;
else
{
assert(sValue.startsWith("\""));
assert(sValue.endsWith("\""));
return sValue.substring(1, sValue.length()-1);
}
}
public int GetAttributeCount ()
{
int nCount = 0;
for (final Map<Integer,AttributeDescriptor> aMap : maStateIdToAttributesMap.values())
nCount += aMap.size();
return nCount;
}
private final Map<Integer,Map<Integer,AttributeDescriptor>> maStateIdToAttributesMap;
private final NamespaceMap maNamespaceMap;
private final NameMap maNameMap;
private final NameMap maStateNameMap;
private final SimpleTypeManager maSimpleTypeManager;
private final Vector<String> maErrorsAndWarnings;
}