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