Source code: com/trapezium/vrml/grammar/ScriptGutRule.java
1 /*
2 * @(#)ScriptGutRule.java
3 *
4 * Copyright (c) 1998 by Trapezium Development LLC. All Rights Reserved.
5 *
6 * The information in this file is the property of Trapezium Development LLC
7 * and may be used only in accordance with the terms of the license granted
8 * by Trapezium.
9 *
10 */
11 package com.trapezium.vrml.grammar;
12
13 import com.trapezium.parse.TokenEnumerator;
14 import com.trapezium.vrml.node.Node;
15 import com.trapezium.vrml.node.PROTO;
16 import com.trapezium.vrml.Scene;
17 import com.trapezium.vrml.FieldId;
18 import com.trapezium.vrml.fields.Field;
19 import com.trapezium.vrml.fields.ISField;
20
21 /**
22 * Creates the scene graph component for the internals of a Script node.
23 *
24 * This is much different than other built in nodes because Script
25 * nodes allow user defined interface (field) extensions.
26 *
27 * Grammar handled by "Build" method:
28 * <PRE>
29 * scriptGut:
30 * nodeGut
31 * restrictedInterfaceDeclaration
32 * eventIn fieldType eventInId IS eventInId
33 * eventOut fieldType eventOutId IS eventOutId
34 * field fieldType fieldId IS fieldId
35 * </PRE>
36 * @author Johannes N. Johannsen
37 * @version 1.12, 9 April 1998, made public
38 * @version 1.1, 19 Jan 1998
39 *
40 * @since 1.0
41 */
42 public class ScriptGutRule {
43 PROTORule protoRule;
44 ROUTERule routeRule = new ROUTERule();
45 RestrictedInterfaceDeclarationRule restrictedInterfaceDeclarationRule;
46 FieldFactory fieldFactory;
47 NodeBodyRule nodeBodyRule;
48
49 /** Constructor for grammar rule that creates a Script field */
50 public ScriptGutRule( NodeRule nodeRule ) {
51 fieldFactory = new FieldFactory( nodeRule );
52 restrictedInterfaceDeclarationRule = new ScriptRestrictedInterfaceDeclarationRule( nodeRule );
53 nodeBodyRule = new NodeBodyRule( nodeRule );
54 protoRule = nodeRule.getPROTORule();
55 }
56
57 /** Build onto a Node by adding on individual NodeGuts */
58 public void Build( int tokenOffset, TokenEnumerator v, Scene scene, Node parent,
59 PROTO protoParent ) {
60 GrammarRule.Enter( "ScriptGutRule.Build" );
61 if ( v.sameAs( tokenOffset, "PROTO" )) {
62 protoRule.Build( tokenOffset, v, scene, parent );
63 } else if ( v.sameAs( tokenOffset, "ROUTE" )) {
64 routeRule.Build( tokenOffset, v, scene, parent );
65 } else {
66 String fieldName = v.toString( tokenOffset );
67 if (( fieldName.compareTo( "eventIn" ) == 0 ) ||
68 ( fieldName.compareTo( "eventOut" ) == 0 ) ||
69 ( fieldName.compareTo( "field" ) == 0 )) {
70 restrictedInterfaceDeclarationRule.Build( tokenOffset, v, scene, parent );
71 } else if ( fieldName.compareTo( "exposedField" ) == 0 ) {
72 FieldId fieldId = new FieldId( tokenOffset, v );
73 parent.addChild( fieldId );
74 fieldId.setError( "Script nodes cannot have exposedFields." );
75 } else {
76 nodeBodyRule.Build( tokenOffset, v, scene, parent );
77 if ( fieldName.compareTo( "url" ) == 0 ) {
78 if ( javascript( tokenOffset, v )) {
79 addScriptFunctions( parent, tokenOffset, v );
80 }
81 }
82 }
83 }
84 GrammarRule.Exit( "ScriptGutRule.Build" );
85 }
86
87 //
88 // This needs some work, not detecting javascript correctly.
89 // Bug is when url [ "url1", "url2" ]
90 // In this case, have to check each url for javascript functions.
91 // Similarly "addScriptFunctions" has to handle this case.
92 // UrlVisitor probably has to deal with this as well. Need a different design
93 // in this case.
94 //
95 boolean javascript( int tokenOffset, TokenEnumerator v ) {
96 int state = v.getState();
97 v.setState( tokenOffset );
98 tokenOffset = v.getNextToken();
99 if ( tokenOffset != -1 ) {
100 if ( v.isLeftBracket( tokenOffset )) {
101 // partial fix, if we have: url [ "url1", ... ]
102 // here we just check "url1" for javascript
103 tokenOffset = v.getNextToken();
104 if ( tokenOffset != -1 ) {
105 if ( v.isQuotedString( tokenOffset )) {
106 String tokString = v.toString( tokenOffset );
107 if ( tokString.indexOf( "javascript: " ) > 0 ) {
108 v.setState( state );
109 return( true );
110 } else if ( tokString.indexOf( "vrmlscript:" ) > 0 ) {
111 v.setState( state );
112 return( true );
113 }
114 }
115 }
116 } else {
117 String qs = v.toString( tokenOffset );
118 if ( v.isQuotedString( tokenOffset )) {
119 String tokString = v.toString( tokenOffset );
120 if ( tokString.indexOf( "javascript:" ) > 0 ) {
121 v.setState( state );
122 return( true );
123 } else if ( tokString.indexOf( "vrmlscript:" ) > 0 ) {
124 v.setState( state );
125 return( true );
126 }
127 }
128 }
129 }
130 v.setState( state );
131 return( false );
132 }
133
134
135 /** add Javascript functions direcly from token stream.
136 *
137 * This is used when the Javascript is embedded directly in the VRML file
138 * as part of the url string, using the "javascript: ..." format.
139 *
140 * The tokens are examined one by noe until a token is found that
141 * is not part of a quoted string. As tokens are examined, any functions
142 * fuond are added to the parent node.
143 *
144 * @param parent script node parent
145 * @param firstTokenOffset start of the javascript url
146 */
147 void addScriptFunctions( Node parent, int firstTokenOffset, TokenEnumerator v ) {
148 int state = v.getState();
149 v.setState( firstTokenOffset );
150 int scannerOffset = v.getNextToken();
151 while ( scannerOffset != -1 ) {
152 if ( v.isQuotedString( scannerOffset ) || v.isContinuationString( scannerOffset )) {
153 String s = v.toString( scannerOffset );
154 VRML97.addFunction( s, parent );
155 } else {
156 break;
157 }
158 scannerOffset = v.getNextToken();
159 }
160 v.setState( state );
161 }
162 }