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;
23 
24 import java.io.File;
25 import java.util.Stack;
26 import java.util.Vector;
27 
28 import javax.xml.stream.Location;
29 
30 import org.apache.openoffice.ooxml.parser.action.ActionManager;
31 import org.apache.openoffice.ooxml.parser.action.ActionTrigger;
32 import org.apache.openoffice.ooxml.parser.action.IAction;
33 import org.apache.openoffice.ooxml.parser.attribute.AttributeManager;
34 import org.apache.openoffice.ooxml.parser.attribute.AttributeProvider;
35 import org.apache.openoffice.ooxml.parser.attribute.AttributeValues;
36 import org.apache.openoffice.ooxml.parser.type.SimpleTypeManager;
37 
38 /** The state machine is initialized at creation from the data tables
39  *  created previously by a stack automaton.
40  */
41 public class StateMachine
42 {
StateMachine( final File aParseTableFile, final Vector<String> aErrorsAndWarnings)43     public StateMachine (
44         final File aParseTableFile,
45         final Vector<String> aErrorsAndWarnings)
46     {
47         if (Log.Dbg != null)
48             Log.Dbg.printf("reading parse tables from %s\n", aParseTableFile.toString());
49 
50         final ParseTableReader aReader = new ParseTableReader(aParseTableFile);
51         maNamespaceMap = new NamespaceMap(aReader.GetSection("namespace"));
52         maNameMap = new NameMap(aReader.GetSection("name"));
53         maStateNameMap = new NameMap(aReader.GetSection("state-name"));
54         maTransitions = new TransitionTable(aReader.GetSection("transition"));
55         maSkipStates = new SkipStateTable(aReader.GetSection("skip"));
56         maAttributeValueMap = new NameMap(aReader.GetSection("attribute-value"));
57         maAcceptingStates = new AcceptingStateTable(aReader.GetSection("accepting-state"));
58         maSimpleTypeManager = new SimpleTypeManager(
59             aReader.GetSection("simple-type"),
60             maAttributeValueMap);
61         maAttributeManager = new AttributeManager(
62             aReader.GetSection("attribute"),
63             maNamespaceMap,
64             maNameMap,
65             maStateNameMap,
66             maSimpleTypeManager,
67             aErrorsAndWarnings);
68         mnStartStateId = Integer.parseInt(aReader.GetSection("start-state").firstElement()[1]);
69         mnEndStateId = Integer.parseInt(aReader.GetSection("end-state").firstElement()[1]);
70 
71         mnCurrentStateId = mnStartStateId;
72         maStateStack = new Stack<>();
73         maElementContextStack = new Stack<>();
74         maActionManager = new ActionManager(maStateNameMap);
75         maErrorsAndWarnings  = aErrorsAndWarnings;
76 
77         if (Log.Dbg != null)
78         {
79             Log.Dbg.printf("read %d namespace, %d names, %d states (%d skip, %d accept), %d transitions and %d attributes\n",
80                 maNamespaceMap.GetNamespaceCount(),
81                 maNameMap.GetNameCount(),
82                 maStateNameMap.GetNameCount(),
83                 maSkipStates.GetSkipStateCount(),
84                 maAcceptingStates.GetAcceptingStateCount(),
85                 maTransitions.GetTransitionCount(),
86                 maAttributeManager.GetAttributeCount());
87             Log.Dbg.printf("starting in state _start_ (%d)\n", mnCurrentStateId);
88         }
89     }
90 
91 
92 
93 
ProcessStartElement( final String sNamespaceURI, final String sElementName, final Location aStartLocation, final Location aEndLocation, final AttributeProvider aAttributes)94     public boolean ProcessStartElement (
95         final String sNamespaceURI,
96         final String sElementName,
97         final Location aStartLocation,
98         final Location aEndLocation,
99         final AttributeProvider aAttributes)
100     {
101         boolean bResult = false;
102 
103         try
104         {
105             final NamespaceMap.NamespaceDescriptor aNamespaceDescriptor = maNamespaceMap.GetDescriptorForURI(sNamespaceURI);
106             final int nElementNameId = maNameMap.GetIdForName(sElementName);
107             if (Log.Dbg != null)
108                 Log.Dbg.printf("%s:%s(%d:%d) L%dC%d\n",
109                     aNamespaceDescriptor.Prefix,
110                     sElementName,
111                     aNamespaceDescriptor.Id,
112                     nElementNameId,
113                     aStartLocation.getLineNumber(),
114                     aStartLocation.getColumnNumber());
115 
116             final Transition aTransition = maTransitions.GetTransition(
117                 mnCurrentStateId,
118                 aNamespaceDescriptor.Id,
119                 nElementNameId);
120             if (aTransition == null)
121             {
122                 final String sText = String.format(
123                     "can not find transition for state %s(%d) and element %s:%s(%d:%d) at L%dC%d\n",
124                     maStateNameMap.GetNameForId(mnCurrentStateId),
125                     mnCurrentStateId,
126                     aNamespaceDescriptor.Prefix,
127                     maNameMap.GetNameForId(nElementNameId),
128                     aNamespaceDescriptor.Id,
129                     nElementNameId,
130                     aStartLocation.getLineNumber(),
131                     aStartLocation.getColumnNumber());
132                 Log.Err.printf(sText);
133                 if (Log.Dbg != null)
134                     Log.Dbg.printf(sText);
135             }
136             else
137             {
138                 if (Log.Dbg != null)
139                 {
140                     Log.Dbg.printf(" %s(%d) -> %s(%d) via %s(%d)",
141                         maStateNameMap.GetNameForId(mnCurrentStateId),
142                         mnCurrentStateId,
143                         maStateNameMap.GetNameForId(aTransition.GetEndStateId()),
144                         aTransition.GetEndStateId(),
145                         maStateNameMap.GetNameForId(aTransition.GetActionId()),
146                         aTransition.GetActionId());
147                     Log.Dbg.printf("\n");
148                 }
149 
150                 // Follow the transition to its end state but first process its
151                 // content.  We do that by
152 
153                 if (Log.Dbg != null)
154                     Log.Dbg.IncreaseIndentation();
155 
156                 // a) pushing the end state to the state stack so that on the
157                 // end tag that corresponds to the current start tag it will become the current state.
158                 maStateStack.push(aTransition.GetEndStateId());
159 
160                 // b) entering the state that corresponds to start tag that
161                 // we are currently processing.
162                 mnCurrentStateId = aTransition.GetActionId();
163 
164                 // c) Prepare the attributes and store them in the new element context.
165                 final AttributeValues aAttributeValues = maAttributeManager.ParseAttributes(
166                     mnCurrentStateId,
167                     aAttributes);
168 
169                 // d) creating a new ElementContext for the element that just starts.
170                 maElementContextStack.push(maCurrentElementContext);
171                 final ElementContext aPreviousElementContext = maCurrentElementContext;
172                 maCurrentElementContext = new ElementContext(
173                     sElementName,
174                     maStateNameMap.GetNameForId(aTransition.GetActionId()),
175                     false,
176                     aAttributeValues,
177                     aPreviousElementContext);
178 
179                 // e) and run all actions that are bound to the current start tag.
180                 ExecuteActions(
181                     mnCurrentStateId,
182                     maCurrentElementContext,
183                     ActionTrigger.ElementStart,
184                     null,
185                     aStartLocation,
186                     aEndLocation);
187 
188                 bResult = true;
189             }
190         }
191         catch (RuntimeException aException)
192         {
193             Log.Err.printf("error at line %d and column %d\n",
194                 aStartLocation.getLineNumber(),
195                 aStartLocation.getColumnNumber());
196             throw aException;
197         }
198         return bResult;
199     }
200 
201 
202 
203 
ProcessEndElement( final String sNamespaceURI, final String sElementName, final Location aStartLocation, final Location aEndLocation)204     public void ProcessEndElement (
205         final String sNamespaceURI,
206         final String sElementName,
207         final Location aStartLocation,
208         final Location aEndLocation)
209     {
210         if ( ! maAcceptingStates.Contains(mnCurrentStateId)
211             && mnCurrentStateId!=-1)
212         {
213             if (Log.Dbg != null)
214                 Log.Dbg.printf("current state %s(%d) is not an accepting state\n",
215                     maStateNameMap.GetNameForId(mnCurrentStateId),
216                     mnCurrentStateId);
217             throw new RuntimeException("not expecting end element "+sElementName);
218         }
219 
220         final NamespaceMap.NamespaceDescriptor aDescriptor = maNamespaceMap.GetDescriptorForURI(sNamespaceURI);
221 
222         // Leave the current element.
223 
224         final int nPreviousStateId = mnCurrentStateId;
225         mnCurrentStateId = maStateStack.pop();
226         if (mnCurrentStateId == mnEndStateId)
227             mnCurrentStateId = mnStartStateId;
228 
229         final ElementContext aPreviousElementContext = maCurrentElementContext;
230         maCurrentElementContext = maElementContextStack.pop();
231 
232         ExecuteActions(
233             nPreviousStateId,
234             aPreviousElementContext,
235             ActionTrigger.ElementEnd,
236             null,
237             aStartLocation,
238             aEndLocation);
239 
240         if (Log.Dbg != null)
241         {
242             Log.Dbg.DecreaseIndentation();
243             Log.Dbg.printf("/%s:%s L%d%d\n",
244                 aDescriptor.Prefix,
245                 sElementName,
246                 aStartLocation.getLineNumber(),
247                 aStartLocation.getColumnNumber());
248             Log.Dbg.printf(" %s(%d) <- %s(%d)\n",
249                 maStateNameMap.GetNameForId(nPreviousStateId),
250                 nPreviousStateId,
251                 maStateNameMap.GetNameForId(mnCurrentStateId),
252                 mnCurrentStateId);
253         }
254     }
255 
256 
257 
258 
ProcessCharacters( final String sText, final Location aStartLocation, final Location aEndLocation)259     public void ProcessCharacters (
260         final String sText,
261         final Location aStartLocation,
262         final Location aEndLocation)
263     {
264         if (Log.Dbg != null)
265             Log.Dbg.printf("text [%s]\n", sText.replace("\n", "\\n"));
266 
267         ExecuteActions(
268             mnCurrentStateId,
269             maCurrentElementContext,
270             ActionTrigger.Text,
271             sText,
272             aStartLocation,
273             aEndLocation);
274 
275     }
276 
277 
278 
279 
IsInSkipState()280     public boolean IsInSkipState ()
281     {
282         return maSkipStates.Contains(mnCurrentStateId);
283     }
284 
285 
286 
287 
GetActionManager()288     public ActionManager GetActionManager ()
289     {
290         return maActionManager;
291     }
292 
293 
294 
295 
ExecuteActions( final int nStateId, final ElementContext aElementContext, final ActionTrigger eTrigger, final String sText, final Location aStartLocation, final Location aEndLocation)296     private void ExecuteActions (
297         final int nStateId,
298         final ElementContext aElementContext,
299         final ActionTrigger eTrigger,
300         final String sText,
301         final Location aStartLocation,
302         final Location aEndLocation)
303     {
304         final Iterable<IAction> aActions = maActionManager.GetActions(nStateId, eTrigger);
305         if (aActions != null)
306             for (final IAction aAction : aActions)
307                 aAction.Run(eTrigger, aElementContext, sText, aStartLocation, aEndLocation);
308     }
309 
310 
311 
312 
313     private final NamespaceMap maNamespaceMap;
314     private final NameMap maNameMap;
315     private final NameMap maStateNameMap;
316     private final TransitionTable maTransitions;
317     private final SimpleTypeManager maSimpleTypeManager;
318     private final AttributeManager maAttributeManager;
319     private final NameMap maAttributeValueMap;
320     private int mnCurrentStateId;
321     private Stack<Integer> maStateStack;
322     private ElementContext maCurrentElementContext;
323     private Stack<ElementContext> maElementContextStack;
324     private final int mnStartStateId;
325     private final int mnEndStateId;
326     private SkipStateTable maSkipStates;
327     private AcceptingStateTable maAcceptingStates;
328     private final ActionManager maActionManager;
329     private final Vector<String> maErrorsAndWarnings;
330 }
331