1cf936e33SAndre Fischer /**************************************************************
2cf936e33SAndre Fischer *
3cf936e33SAndre Fischer * Licensed to the Apache Software Foundation (ASF) under one
4cf936e33SAndre Fischer * or more contributor license agreements.  See the NOTICE file
5cf936e33SAndre Fischer * distributed with this work for additional information
6cf936e33SAndre Fischer * regarding copyright ownership.  The ASF licenses this file
7cf936e33SAndre Fischer * to you under the Apache License, Version 2.0 (the
8cf936e33SAndre Fischer * "License"); you may not use this file except in compliance
9cf936e33SAndre Fischer * with the License.  You may obtain a copy of the License at
10cf936e33SAndre Fischer *
11cf936e33SAndre Fischer *   http://www.apache.org/licenses/LICENSE-2.0
12cf936e33SAndre Fischer *
13cf936e33SAndre Fischer * Unless required by applicable law or agreed to in writing,
14cf936e33SAndre Fischer * software distributed under the License is distributed on an
15cf936e33SAndre Fischer * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16cf936e33SAndre Fischer * KIND, either express or implied.  See the License for the
17cf936e33SAndre Fischer * specific language governing permissions and limitations
18cf936e33SAndre Fischer * under the License.
19cf936e33SAndre Fischer *
20cf936e33SAndre Fischer *************************************************************/
21cf936e33SAndre Fischer 
227d97ce35SAndre Fischer package org.apache.openoffice.ooxml.parser.attribute;
23cf936e33SAndre Fischer 
24cf936e33SAndre Fischer import java.util.HashMap;
2562886075SAndre Fischer import java.util.HashSet;
26cf936e33SAndre Fischer import java.util.Map;
2762886075SAndre Fischer import java.util.Set;
286cde7e4aSAndre Fischer import java.util.Vector;
29cf936e33SAndre Fischer 
307d97ce35SAndre Fischer import org.apache.openoffice.ooxml.parser.Log;
317d97ce35SAndre Fischer import org.apache.openoffice.ooxml.parser.NameMap;
327d97ce35SAndre Fischer import org.apache.openoffice.ooxml.parser.NamespaceMap;
337d97ce35SAndre Fischer import org.apache.openoffice.ooxml.parser.type.SimpleTypeManager;
347d97ce35SAndre Fischer 
3562886075SAndre Fischer 
3662886075SAndre Fischer /** Match a set of attributes from the document with the attribute
3762886075SAndre Fischer  *  specifications of a state.
3862886075SAndre Fischer  *
3962886075SAndre Fischer  */
40cf936e33SAndre Fischer public class AttributeManager
41cf936e33SAndre Fischer {
4262886075SAndre Fischer     /** Create a new AttributeManager for the attribute specifications that
4362886075SAndre Fischer      *  are given in the parse table.
4462886075SAndre Fischer      */
AttributeManager( final Vector<String[]> aData, final NamespaceMap aNamespaceMap, final NameMap aNameMap, final NameMap aStateNameMap, final SimpleTypeManager aSimpleTypeManager, final Vector<String> aErrorsAndWarnings)4562886075SAndre Fischer     public AttributeManager (
4662886075SAndre Fischer         final Vector<String[]> aData,
4762886075SAndre Fischer         final NamespaceMap aNamespaceMap,
487d97ce35SAndre Fischer         final NameMap aNameMap,
497d97ce35SAndre Fischer         final NameMap aStateNameMap,
50*360147c7SAndre Fischer         final SimpleTypeManager aSimpleTypeManager,
51*360147c7SAndre Fischer         final Vector<String> aErrorsAndWarnings)
52cf936e33SAndre Fischer     {
5362886075SAndre Fischer         maStateIdToAttributesMap = new HashMap<>();
5462886075SAndre Fischer         maNamespaceMap = aNamespaceMap;
5562886075SAndre Fischer         maNameMap = aNameMap;
567d97ce35SAndre Fischer         maStateNameMap = aStateNameMap;
577d97ce35SAndre Fischer         maSimpleTypeManager = aSimpleTypeManager;
58*360147c7SAndre Fischer         maErrorsAndWarnings = aErrorsAndWarnings;
597d97ce35SAndre Fischer         ParseData(aData);
607d97ce35SAndre Fischer     }
617d97ce35SAndre Fischer 
627d97ce35SAndre Fischer 
637d97ce35SAndre Fischer 
647d97ce35SAndre Fischer 
ParseData(final Vector<String[]> aData)657d97ce35SAndre Fischer     private void ParseData (final Vector<String[]> aData)
667d97ce35SAndre Fischer     {
6762886075SAndre Fischer         for (final String[] aLine : aData)
6862886075SAndre Fischer         {
6962886075SAndre Fischer             final int nStateId = Integer.parseInt(aLine[1]);
7062886075SAndre Fischer             final int nPrefixId = Integer.parseInt(aLine[2]);
7162886075SAndre Fischer             final boolean bCanBeUnqualified = aLine[3].startsWith("u");
7262886075SAndre Fischer             final int nAttributeId = Integer.parseInt(aLine[4]);
737d97ce35SAndre Fischer             final int nAttributeTypeId = aLine[5].equals("null") ? -1 : Integer.parseInt(aLine[5]);
7462886075SAndre Fischer             final boolean bIsOptional = aLine[6].startsWith("o");
757d97ce35SAndre Fischer             final String sDefault = aLine[7];
767d97ce35SAndre Fischer             // State name.
777d97ce35SAndre Fischer             final String sAttributeName = aLine[9];
787d97ce35SAndre Fischer             // Attribute type name.
7962886075SAndre Fischer 
8062886075SAndre Fischer             Map<Integer,AttributeDescriptor> aAttributesPerState = maStateIdToAttributesMap.get(nStateId);
8162886075SAndre Fischer             if (aAttributesPerState == null)
8262886075SAndre Fischer             {
8362886075SAndre Fischer                 aAttributesPerState = new HashMap<>();
8462886075SAndre Fischer                 maStateIdToAttributesMap.put(nStateId, aAttributesPerState);
8562886075SAndre Fischer             }
8662886075SAndre Fischer 
8762886075SAndre Fischer             final AttributeDescriptor aAttributeDescriptor = new AttributeDescriptor(
8862886075SAndre Fischer                 nPrefixId,
8962886075SAndre Fischer                 nAttributeId,
9062886075SAndre Fischer                 bCanBeUnqualified,
9162886075SAndre Fischer                 bIsOptional,
9262886075SAndre Fischer                 sDefault,
9362886075SAndre Fischer                 sAttributeName,
947d97ce35SAndre Fischer                 nAttributeTypeId);
9562886075SAndre Fischer 
9662886075SAndre Fischer             aAttributesPerState.put(
9762886075SAndre Fischer                 (nPrefixId<<16)|nAttributeId,
9862886075SAndre Fischer                 aAttributeDescriptor);
9962886075SAndre Fischer             if (bCanBeUnqualified)
10062886075SAndre Fischer                 aAttributesPerState.put(
10162886075SAndre Fischer                     nAttributeId,
10262886075SAndre Fischer                     aAttributeDescriptor);
10362886075SAndre Fischer         }
104cf936e33SAndre Fischer     }
105cf936e33SAndre Fischer 
106cf936e33SAndre Fischer 
107cf936e33SAndre Fischer 
108cf936e33SAndre Fischer 
10962886075SAndre Fischer     /** For the state with id nStateId, match the attributes from the document
11062886075SAndre Fischer      *  with the attribute specifications of that state.
11162886075SAndre Fischer      */
ParseAttributes( final int nStateId, final AttributeProvider aDocumentAttributes)112c0b458d0SAndre Fischer     public AttributeValues ParseAttributes (
113cf936e33SAndre Fischer         final int nStateId,
11462886075SAndre Fischer         final AttributeProvider aDocumentAttributes)
115cf936e33SAndre Fischer     {
116c0b458d0SAndre Fischer         final AttributeValues aValues = new AttributeValues();
117c0b458d0SAndre Fischer 
11862886075SAndre Fischer         final Map<Integer,AttributeDescriptor> aAttributesPerState = maStateIdToAttributesMap.get(nStateId);
11962886075SAndre Fischer         if (aAttributesPerState == null)
120cf936e33SAndre Fischer         {
12162886075SAndre Fischer             if (aDocumentAttributes.HasAttributes())
12262886075SAndre Fischer             {
12362886075SAndre Fischer                 Log.Std.printf("state has not attributes defined but document provides %d attributes\n",
12462886075SAndre Fischer                     aDocumentAttributes.GetAttributeCount());
12562886075SAndre Fischer                 for (final String[] aEntry : aDocumentAttributes)
12662886075SAndre Fischer                 {
12762886075SAndre Fischer                     Log.Dbg.printf("    %s -> %s\n", aEntry[0], aEntry[1]);
12862886075SAndre Fischer                 }
12962886075SAndre Fischer                 throw new RuntimeException();
13062886075SAndre Fischer             }
131cf936e33SAndre Fischer         }
132cf936e33SAndre Fischer         else
133cf936e33SAndre Fischer         {
13462886075SAndre Fischer             final Set<AttributeDescriptor> aUsedAttributes = new HashSet<>();
13562886075SAndre Fischer 
13662886075SAndre Fischer             // Process all attributes from the document.
13762886075SAndre Fischer             for (final String[] aEntry : aDocumentAttributes)
138cf936e33SAndre Fischer             {
1397d97ce35SAndre Fischer                 final String sRawValue = aEntry[2];
14062886075SAndre Fischer                 final AttributeDescriptor aAttributeDescriptor = ProcessAttribute(
14162886075SAndre Fischer                     aEntry[0],
14262886075SAndre Fischer                     aEntry[1],
1437d97ce35SAndre Fischer                     sRawValue,
14462886075SAndre Fischer                     aAttributesPerState);
14562886075SAndre Fischer                 aUsedAttributes.add(aAttributeDescriptor);
1467d97ce35SAndre Fischer                 final Object aProcessedValue = maSimpleTypeManager.PreprocessValue(
1477d97ce35SAndre Fischer                     sRawValue,
1487d97ce35SAndre Fischer                     aAttributeDescriptor);
1497d97ce35SAndre Fischer                 if (aProcessedValue == null)
1507d97ce35SAndre Fischer                 {
1517d97ce35SAndre Fischer                     maSimpleTypeManager.PreprocessValue(
1527d97ce35SAndre Fischer                         sRawValue,
1537d97ce35SAndre Fischer                         aAttributeDescriptor);
1547d97ce35SAndre Fischer                     throw new RuntimeException(
1557d97ce35SAndre Fischer                         String.format("value '%s' of attribute '%s' is not recognized",
1567d97ce35SAndre Fischer                             sRawValue,
1577d97ce35SAndre Fischer                             aAttributeDescriptor.GetName()));
1587d97ce35SAndre Fischer                 }
1597d97ce35SAndre Fischer                 aValues.AddAttribute(
1607d97ce35SAndre Fischer                     aAttributeDescriptor,
1617d97ce35SAndre Fischer                     sRawValue,
1627d97ce35SAndre Fischer                     aProcessedValue);
163c0b458d0SAndre Fischer 
16462886075SAndre Fischer                 if (Log.Dbg != null)
16562886075SAndre Fischer                 {
16662886075SAndre Fischer                     if (aAttributeDescriptor == null)
16762886075SAndre Fischer                         Log.Dbg.printf("attribute %s%s is not known\n",
16862886075SAndre Fischer                             aEntry[0]==null ? "" : ":"+aEntry[0],
16962886075SAndre Fischer                             aEntry[1]);
17062886075SAndre Fischer                     else
1717d97ce35SAndre Fischer                         Log.Dbg.printf("attribute %s:%s(%d:%d) has type %s(%d) and value %s('%s')\n",
17262886075SAndre Fischer                             maNamespaceMap.GetDescriptorForId(aAttributeDescriptor.GetNamespaceId()).Prefix,
17362886075SAndre Fischer                             maNameMap.GetNameForId(aAttributeDescriptor.GetNameId()),
17462886075SAndre Fischer                             aAttributeDescriptor.GetNamespaceId(),
17562886075SAndre Fischer                             aAttributeDescriptor.GetNameId(),
1767d97ce35SAndre Fischer                             maStateNameMap.GetNameForId(aAttributeDescriptor.GetTypeId()),
1777d97ce35SAndre Fischer                             aAttributeDescriptor.GetTypeId(),
1787d97ce35SAndre Fischer                             aProcessedValue,
1797d97ce35SAndre Fischer                             sRawValue);
18062886075SAndre Fischer                 }
18162886075SAndre Fischer             }
18262886075SAndre Fischer 
18362886075SAndre Fischer             // Check if all required attributes where given.
18462886075SAndre Fischer             for (final AttributeDescriptor aAttribute : aAttributesPerState.values())
18562886075SAndre Fischer             {
1867d97ce35SAndre Fischer                 if ( ! aUsedAttributes.contains(aAttribute))
18762886075SAndre Fischer                 {
1887d97ce35SAndre Fischer                     if ( ! aAttribute.IsOptional())
189*360147c7SAndre Fischer                     {
190*360147c7SAndre Fischer                         final String sMessage = String.format("attribute '"+aAttribute.GetName()+"' is not present but also not optional");
191*360147c7SAndre Fischer                         if (maErrorsAndWarnings != null)
192*360147c7SAndre Fischer                             maErrorsAndWarnings.add(sMessage);
193*360147c7SAndre Fischer                         else
194*360147c7SAndre Fischer                             throw new RuntimeException(sMessage);
195*360147c7SAndre Fischer                     }
1967d97ce35SAndre Fischer                     else
1977d97ce35SAndre Fischer                     {
1987d97ce35SAndre Fischer                         // Add an entry that gives access to the default value.
1997d97ce35SAndre Fischer                         aValues.AddAttribute(aAttribute, null, null);
2007d97ce35SAndre Fischer                     }
20162886075SAndre Fischer                 }
202cf936e33SAndre Fischer             }
203cf936e33SAndre Fischer         }
204c0b458d0SAndre Fischer 
205c0b458d0SAndre Fischer         return aValues;
206cf936e33SAndre Fischer     }
20762886075SAndre Fischer 
20862886075SAndre Fischer 
20962886075SAndre Fischer 
21062886075SAndre Fischer 
ProcessAttribute( final String sNamespace, final String sAttributeName, final String sAttributeValue, final Map<Integer,AttributeDescriptor> aAttributesPerState)21162886075SAndre Fischer     private AttributeDescriptor ProcessAttribute (
21262886075SAndre Fischer         final String sNamespace,
21362886075SAndre Fischer         final String sAttributeName,
21462886075SAndre Fischer         final String sAttributeValue,
21562886075SAndre Fischer         final Map<Integer,AttributeDescriptor> aAttributesPerState)
21662886075SAndre Fischer     {
21762886075SAndre Fischer         final AttributeDescriptor aAttributeDescriptor;
21862886075SAndre Fischer         if (sNamespace == null)
21962886075SAndre Fischer         {
22062886075SAndre Fischer             // Attribute name has no namespace.
22162886075SAndre Fischer             final int nAttributeNameId = maNameMap.GetIdForName(sAttributeName);
22262886075SAndre Fischer             aAttributeDescriptor = aAttributesPerState.get(nAttributeNameId);
22362886075SAndre Fischer         }
22462886075SAndre Fischer         else
22562886075SAndre Fischer         {
22662886075SAndre Fischer             // Attribute name has explicit namespace.
22762886075SAndre Fischer             final NamespaceMap.NamespaceDescriptor aDescriptor = maNamespaceMap.GetDescriptorForURI(sNamespace);
22862886075SAndre Fischer             final int nAttributeNameId = maNameMap.GetIdForName(sAttributeName);
22962886075SAndre Fischer             aAttributeDescriptor = aAttributesPerState.get((aDescriptor.Id<<16) | nAttributeNameId);
23062886075SAndre Fischer         }
23162886075SAndre Fischer         return aAttributeDescriptor;
23262886075SAndre Fischer     }
23362886075SAndre Fischer 
23462886075SAndre Fischer 
23562886075SAndre Fischer 
23662886075SAndre Fischer 
23762886075SAndre Fischer     /** Remove the quotes around the given string.
23862886075SAndre Fischer      *  If it has the special value null (without quotes) then the null reference
23962886075SAndre Fischer      *  is returned.
24062886075SAndre Fischer      */
UnquoteString(final String sValue)24162886075SAndre Fischer     private String UnquoteString (final String sValue)
24262886075SAndre Fischer     {
24362886075SAndre Fischer         if (sValue.equals("null"))
24462886075SAndre Fischer             return null;
24562886075SAndre Fischer         else
24662886075SAndre Fischer         {
24762886075SAndre Fischer             assert(sValue.startsWith("\""));
24862886075SAndre Fischer             assert(sValue.endsWith("\""));
24962886075SAndre Fischer             return sValue.substring(1, sValue.length()-1);
25062886075SAndre Fischer         }
25162886075SAndre Fischer     }
25262886075SAndre Fischer 
253cf936e33SAndre Fischer 
254cf936e33SAndre Fischer 
255cf936e33SAndre Fischer 
GetAttributeCount()25662886075SAndre Fischer     public int GetAttributeCount ()
257cf936e33SAndre Fischer     {
25862886075SAndre Fischer         int nCount = 0;
25962886075SAndre Fischer         for (final Map<Integer,AttributeDescriptor> aMap : maStateIdToAttributesMap.values())
26062886075SAndre Fischer             nCount += aMap.size();
26162886075SAndre Fischer         return nCount;
262cf936e33SAndre Fischer     }
263cf936e33SAndre Fischer 
264cf936e33SAndre Fischer 
265cf936e33SAndre Fischer 
266cf936e33SAndre Fischer 
26762886075SAndre Fischer     private final Map<Integer,Map<Integer,AttributeDescriptor>> maStateIdToAttributesMap;
26862886075SAndre Fischer     private final NamespaceMap maNamespaceMap;
26962886075SAndre Fischer     private final NameMap maNameMap;
2707d97ce35SAndre Fischer     private final NameMap maStateNameMap;
2717d97ce35SAndre Fischer     private final SimpleTypeManager maSimpleTypeManager;
272*360147c7SAndre Fischer     private final Vector<String> maErrorsAndWarnings;
273cf936e33SAndre Fischer }
274