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 }