View Javadoc

1   /*
2    * "Peko" Visual Novel System
3    *
4    * All Rights Reserved.
5    * Copyright (c) 1999-2003 Tsukuba Bunko.
6    *
7    * $Id: PSMLUtil.java,v 1.1 2005/07/11 12:49:18 ppoi Exp $
8    */
9   package tsukuba_bunko.peko.scenario;
10  
11  import	java.util.StringTokenizer;
12  
13  import	org.xml.sax.Attributes;
14  
15  import	tsukuba_bunko.peko.Logger;
16  
17  import	tsukuba_bunko.peko.scenario.SceneContext;
18  
19  
20  /***
21   * PSML の処理に必要なユーティリティメソッドを提供します。
22   * @author	$Author: ppoi $
23   * @version	$Revision: 1.1 $
24   */
25  public final class PSMLUtil	{
26  
27  	/***
28  	 * <code>PSMLUtil</code> のインスタンスは生成できません。
29  	 */
30  	private PSMLUtil()
31  	{
32  	}
33  
34  
35  	/***
36  	 * ISO 制御文字を除去します。
37  	 * @param	string	除去対象の文字列
38  	 * @return	除去処理後の文字列
39  	 */
40  	public static String removeISOControlChar( String string )
41  	{
42  		if( (string == null) || (string.length() == 0) )	{
43  			return string;
44  		}
45  
46  		int	beginIndex = -1;
47  		boolean	isISOControlCharSequence = false;
48  
49  		int	length = string.length();
50  		StringBuffer	buffer = null;
51  		for( int current = 0; current < length; ++current )	{
52  			if( Character.isISOControl(string.charAt(current)) )	{
53  				if( !isISOControlCharSequence )	{
54  					if( buffer == null )	{
55  						if( current == 0 )	{
56  							buffer = new StringBuffer();
57  						}
58  						else	{
59  							buffer = new StringBuffer( string.substring(0, current) );
60  						}
61  					}
62  					else	{
63  						buffer.append( string.substring(beginIndex, current) );
64  					}
65  					isISOControlCharSequence = true;
66  					beginIndex = -1;
67  				}
68  			}
69  			else	{
70  				if( isISOControlCharSequence )	{
71  					beginIndex = current;
72  					isISOControlCharSequence = false;
73  				}
74  			}
75  		}
76  		if( beginIndex != -1 )	{
77  			buffer.append( string.substring(beginIndex) );
78  		}
79  
80  		if( buffer != null )	{
81  			return new String( buffer );
82  		}
83  		else	{
84  			return string;
85  		}
86  	}
87  
88  
89  	/***
90  	 * PSML 1.0 "Scene" ネームスペース、ローカルネームスペースの順で属性値を検索します。
91  	 * @param	localName	属性名のローカル名
92  	 * @return	属性値。属性が定義されていない場合は <code>null</code>
93  	 */
94  	public static String getAttributeValue( Attributes attrs, String localName )
95  	{
96  		String	value = attrs.getValue( ElementHandler.NAMESPACE_SCENE, localName );
97  		if( value == null )	{
98  			value = attrs.getValue( localName );
99  		}
100 
101 		if( (value == null) || (value.length() == 0) )	{
102 			return null;
103 		}
104 		else	{
105 			value = PSMLUtil.removeISOControlChar(value).trim();
106 			if( value.length() == 0 )	{
107 				Logger.warn( MessageIDs.SCN0011W, new Object[]{localName} );
108 				return null;
109 			}
110 			else	{
111 				return value;
112 			}
113 		}
114 	}
115 
116 	/***
117 	 * <code>attrs</code> からテストを取り出し、シナリオ文脈 <code>context</code> で評価可能かどうかを判定します。
118 	 * @param	attrs	要素の属性セット
119 	 * @param	context	現在のシナリオ文脈
120 	 * @return	評価可能の場合 <code>true</code>、評価不可の場合 <code>false</code>
121 	 */
122 	public static final boolean isEvaluatable( Attributes attrs, SceneContext context )
123 	{
124 		return isEvaluatable( PSMLUtil.getAttributeValue(attrs, "test"), context );
125 	}
126 
127 	/***
128 	 * <code>target</code> で指定されるテストを使用し、シナリオ文脈 <code>context</code> で評価可能かどうかを判定します。
129 	 * @param	target	テスト
130 	 * @param	context	現在のシナリオ文脈
131 	 * @return	評価可能の場合 <code>true</code>、評価不可の場合 <code>false</code>
132 	 */
133 	public static final boolean isEvaluatable( String target, SceneContext context )
134 	{
135 		if( (target == null) || (target.length() == 0) )	{
136 			return true;
137 		}
138 		else if( context == null )	{
139 			return false;
140 		}
141 		else	{
142 			boolean	result = false;
143 	
144 			boolean	multiple = (target.charAt(0) == '[');
145 			boolean	inBracket = false;
146 			boolean	individualResult = true;
147 	
148 			StringTokenizer	st = new StringTokenizer( target, "[],", true );
149 			String	token = null;
150 			String	lastToken = null;
151 			int	position = 0;
152 			while( st.hasMoreTokens() )	{
153 				lastToken = token;
154 				token = st.nextToken();
155 				position += token.length();
156 				token = token.trim();
157 	
158 				if( !multiple )	{
159 					if( "[".equals(token) || "]".equals(token) )	{
160 						Logger.warn( MessageIDs.SCN0008W, new Object[]{String.valueOf(position), token} );
161 						return false;
162 					}
163 					else if( !",".equals(token) )	{
164 						if( token.charAt(0) == '!' )	{
165 							if( token.length() == 1 )	{
166 								Logger.warn( MessageIDs.SCN0008W, new Object[]{String.valueOf(position), token} );
167 								return false;
168 							}
169 							token = token.substring( 1 );
170 							individualResult = individualResult && !context.isDeclaredFlag(token);
171 						}
172 						else	{
173 							individualResult = individualResult && context.isDeclaredFlag(token);
174 						}
175 					}
176 				}
177 				else	{
178 					if( inBracket )	{
179 						if( "]".equals(token) )	{
180 							if( (lastToken != null) && ",".equals(lastToken) )	{
181 								Logger.warn( MessageIDs.SCN0008W, new Object[]{String.valueOf(position), token} );
182 								return false;
183 							}
184 							else	{
185 								result = result || individualResult;
186 								individualResult = true;
187 								inBracket = false;
188 							}
189 						}
190 						else if( !",".equals(token) )	{
191 							if( token.charAt(0) == '!' )	{
192 								if( token.length() == 1 )	{
193 									Logger.warn( MessageIDs.SCN0008W, new Object[]{String.valueOf(position), token} );
194 									return false;
195 								}
196 								token = token.substring( 1 );
197 								individualResult = individualResult && !context.isDeclaredFlag(token);
198 							}
199 							else	{
200 								individualResult = individualResult && context.isDeclaredFlag(token);
201 							}
202 						}
203 					}
204 					else	{
205 						if( "[".equals(token) )	{
206 							inBracket = true;
207 						}
208 						else	{
209 							Logger.warn( MessageIDs.SCN0008W, new Object[]{String.valueOf(position), token} );
210 							return false;
211 						}
212 					}
213 				}
214 			}
215 	
216 			if( multiple )	{
217 				if( !"]".equals(token) )	{
218 					Logger.warn( MessageIDs.SCN0008W, new Object[]{String.valueOf(position), token} );
219 					return false;
220 				}
221 			}
222 			else	{
223 				if( ",".equals(token) )	{
224 					Logger.warn( MessageIDs.SCN0008W, new Object[]{String.valueOf(position), token} );
225 					return false;
226 				}
227 				else	{
228 					result = individualResult;
229 				}
230 			}
231 			return result;
232 		}
233 	}
234 }