1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 package org.apache.openoffice.ooxml.parser.attribute; 23 24 import java.util.HashMap; 25 import java.util.HashSet; 26 import java.util.Map; 27 import java.util.Set; 28 import java.util.Vector; 29 30 import org.apache.openoffice.ooxml.parser.Log; 31 import org.apache.openoffice.ooxml.parser.NameMap; 32 import org.apache.openoffice.ooxml.parser.NamespaceMap; 33 import org.apache.openoffice.ooxml.parser.type.SimpleTypeManager; 34 35 36 /** Match a set of attributes from the document with the attribute 37 * specifications of a state. 38 * 39 */ 40 public class AttributeManager 41 { 42 /** Create a new AttributeManager for the attribute specifications that 43 * are given in the parse table. 44 */ AttributeManager( final Vector<String[]> aData, final NamespaceMap aNamespaceMap, final NameMap aNameMap, final NameMap aStateNameMap, final SimpleTypeManager aSimpleTypeManager, final Vector<String> aErrorsAndWarnings)45 public AttributeManager ( 46 final Vector<String[]> aData, 47 final NamespaceMap aNamespaceMap, 48 final NameMap aNameMap, 49 final NameMap aStateNameMap, 50 final SimpleTypeManager aSimpleTypeManager, 51 final Vector<String> aErrorsAndWarnings) 52 { 53 maStateIdToAttributesMap = new HashMap<>(); 54 maNamespaceMap = aNamespaceMap; 55 maNameMap = aNameMap; 56 maStateNameMap = aStateNameMap; 57 maSimpleTypeManager = aSimpleTypeManager; 58 maErrorsAndWarnings = aErrorsAndWarnings; 59 ParseData(aData); 60 } 61 62 63 64 ParseData(final Vector<String[]> aData)65 private void ParseData (final Vector<String[]> aData) 66 { 67 for (final String[] aLine : aData) 68 { 69 final int nStateId = Integer.parseInt(aLine[1]); 70 final int nPrefixId = Integer.parseInt(aLine[2]); 71 final boolean bCanBeUnqualified = aLine[3].startsWith("u"); 72 final int nAttributeId = Integer.parseInt(aLine[4]); 73 final int nAttributeTypeId = aLine[5].equals("null") ? -1 : Integer.parseInt(aLine[5]); 74 final boolean bIsOptional = aLine[6].startsWith("o"); 75 final String sDefault = aLine[7]; 76 // State name. 77 final String sAttributeName = aLine[9]; 78 // Attribute type name. 79 80 Map<Integer,AttributeDescriptor> aAttributesPerState = maStateIdToAttributesMap.get(nStateId); 81 if (aAttributesPerState == null) 82 { 83 aAttributesPerState = new HashMap<>(); 84 maStateIdToAttributesMap.put(nStateId, aAttributesPerState); 85 } 86 87 final AttributeDescriptor aAttributeDescriptor = new AttributeDescriptor( 88 nPrefixId, 89 nAttributeId, 90 bCanBeUnqualified, 91 bIsOptional, 92 sDefault, 93 sAttributeName, 94 nAttributeTypeId); 95 96 aAttributesPerState.put( 97 (nPrefixId<<16)|nAttributeId, 98 aAttributeDescriptor); 99 if (bCanBeUnqualified) 100 aAttributesPerState.put( 101 nAttributeId, 102 aAttributeDescriptor); 103 } 104 } 105 106 107 108 109 /** For the state with id nStateId, match the attributes from the document 110 * with the attribute specifications of that state. 111 */ ParseAttributes( final int nStateId, final AttributeProvider aDocumentAttributes)112 public AttributeValues ParseAttributes ( 113 final int nStateId, 114 final AttributeProvider aDocumentAttributes) 115 { 116 final AttributeValues aValues = new AttributeValues(); 117 118 final Map<Integer,AttributeDescriptor> aAttributesPerState = maStateIdToAttributesMap.get(nStateId); 119 if (aAttributesPerState == null) 120 { 121 if (aDocumentAttributes.HasAttributes()) 122 { 123 Log.Std.printf("state has not attributes defined but document provides %d attributes\n", 124 aDocumentAttributes.GetAttributeCount()); 125 for (final String[] aEntry : aDocumentAttributes) 126 { 127 Log.Dbg.printf(" %s -> %s\n", aEntry[0], aEntry[1]); 128 } 129 throw new RuntimeException(); 130 } 131 } 132 else 133 { 134 final Set<AttributeDescriptor> aUsedAttributes = new HashSet<>(); 135 136 // Process all attributes from the document. 137 for (final String[] aEntry : aDocumentAttributes) 138 { 139 final String sRawValue = aEntry[2]; 140 final AttributeDescriptor aAttributeDescriptor = ProcessAttribute( 141 aEntry[0], 142 aEntry[1], 143 sRawValue, 144 aAttributesPerState); 145 aUsedAttributes.add(aAttributeDescriptor); 146 final Object aProcessedValue = maSimpleTypeManager.PreprocessValue( 147 sRawValue, 148 aAttributeDescriptor); 149 if (aProcessedValue == null) 150 { 151 maSimpleTypeManager.PreprocessValue( 152 sRawValue, 153 aAttributeDescriptor); 154 throw new RuntimeException( 155 String.format("value '%s' of attribute '%s' is not recognized", 156 sRawValue, 157 aAttributeDescriptor.GetName())); 158 } 159 aValues.AddAttribute( 160 aAttributeDescriptor, 161 sRawValue, 162 aProcessedValue); 163 164 if (Log.Dbg != null) 165 { 166 if (aAttributeDescriptor == null) 167 Log.Dbg.printf("attribute %s%s is not known\n", 168 aEntry[0]==null ? "" : ":"+aEntry[0], 169 aEntry[1]); 170 else 171 Log.Dbg.printf("attribute %s:%s(%d:%d) has type %s(%d) and value %s('%s')\n", 172 maNamespaceMap.GetDescriptorForId(aAttributeDescriptor.GetNamespaceId()).Prefix, 173 maNameMap.GetNameForId(aAttributeDescriptor.GetNameId()), 174 aAttributeDescriptor.GetNamespaceId(), 175 aAttributeDescriptor.GetNameId(), 176 maStateNameMap.GetNameForId(aAttributeDescriptor.GetTypeId()), 177 aAttributeDescriptor.GetTypeId(), 178 aProcessedValue, 179 sRawValue); 180 } 181 } 182 183 // Check if all required attributes where given. 184 for (final AttributeDescriptor aAttribute : aAttributesPerState.values()) 185 { 186 if ( ! aUsedAttributes.contains(aAttribute)) 187 { 188 if ( ! aAttribute.IsOptional()) 189 { 190 final String sMessage = String.format("attribute '"+aAttribute.GetName()+"' is not present but also not optional"); 191 if (maErrorsAndWarnings != null) 192 maErrorsAndWarnings.add(sMessage); 193 else 194 throw new RuntimeException(sMessage); 195 } 196 else 197 { 198 // Add an entry that gives access to the default value. 199 aValues.AddAttribute(aAttribute, null, null); 200 } 201 } 202 } 203 } 204 205 return aValues; 206 } 207 208 209 210 ProcessAttribute( final String sNamespace, final String sAttributeName, final String sAttributeValue, final Map<Integer,AttributeDescriptor> aAttributesPerState)211 private AttributeDescriptor ProcessAttribute ( 212 final String sNamespace, 213 final String sAttributeName, 214 final String sAttributeValue, 215 final Map<Integer,AttributeDescriptor> aAttributesPerState) 216 { 217 final AttributeDescriptor aAttributeDescriptor; 218 if (sNamespace == null) 219 { 220 // Attribute name has no namespace. 221 final int nAttributeNameId = maNameMap.GetIdForName(sAttributeName); 222 aAttributeDescriptor = aAttributesPerState.get(nAttributeNameId); 223 } 224 else 225 { 226 // Attribute name has explicit namespace. 227 final NamespaceMap.NamespaceDescriptor aDescriptor = maNamespaceMap.GetDescriptorForURI(sNamespace); 228 final int nAttributeNameId = maNameMap.GetIdForName(sAttributeName); 229 aAttributeDescriptor = aAttributesPerState.get((aDescriptor.Id<<16) | nAttributeNameId); 230 } 231 return aAttributeDescriptor; 232 } 233 234 235 236 237 /** Remove the quotes around the given string. 238 * If it has the special value null (without quotes) then the null reference 239 * is returned. 240 */ UnquoteString(final String sValue)241 private String UnquoteString (final String sValue) 242 { 243 if (sValue.equals("null")) 244 return null; 245 else 246 { 247 assert(sValue.startsWith("\"")); 248 assert(sValue.endsWith("\"")); 249 return sValue.substring(1, sValue.length()-1); 250 } 251 } 252 253 254 255 GetAttributeCount()256 public int GetAttributeCount () 257 { 258 int nCount = 0; 259 for (final Map<Integer,AttributeDescriptor> aMap : maStateIdToAttributesMap.values()) 260 nCount += aMap.size(); 261 return nCount; 262 } 263 264 265 266 267 private final Map<Integer,Map<Integer,AttributeDescriptor>> maStateIdToAttributesMap; 268 private final NamespaceMap maNamespaceMap; 269 private final NameMap maNameMap; 270 private final NameMap maStateNameMap; 271 private final SimpleTypeManager maSimpleTypeManager; 272 private final Vector<String> maErrorsAndWarnings; 273 } 274