00001 #!/usr/bin/env python 00002 # -*- coding: euc-jp -*- 00003 00004 00005 ## 00006 # @file Properties.py 00007 # @brief Property list class (derived from Java Properties) 00008 # @date $Date: $ 00009 # @author Noriaki Ando <n-ando@aist.go.jp> and Shinji Kurihara 00010 # 00011 # Copyright (C) 2006-2008 00012 # Task-intelligence Research Group, 00013 # Intelligent Systems Research Institute, 00014 # National Institute of 00015 # Advanced Industrial Science and Technology (AIST), Japan 00016 # All rights reserved. 00017 00018 00019 import sys 00020 import string 00021 00022 import OpenRTM_aist 00023 00024 00025 ## 00026 # @if jp 00027 # 00028 # @class Properties 00029 # @brief プロパティセットを表現するクラス 00030 # 00031 # Properties クラスは、不変のプロパティセットを表す。 Properties をストリーム 00032 # に保管したり、ストリームからロードしたりすることができる。 00033 # プロパティリストの各キー、およびそれに対応する値は文字列となっている。 00034 # 00035 # プロパティリストには、その「デフォルト値」として別のプロパティリストを持つ 00036 # ことができる。元のプロパティリストでプロパティキーが見つからないと、この 00037 # 2番目のプロパティリストが検索される。 00038 # 00039 # プロパティの取得には getProperty() 、プロパティのセットには setProperty() と 00040 # いったメソッドを使用することが推奨される。 00041 # 00042 # プロパティをストリームに保存するとき、またはストリームからロードするとき 00043 # に、ISO 8859-1 文字エンコーディングが使用される。このエンコーディングに 00044 # 直接表示できない文字は、扱うことができない。 00045 # 00046 # このクラスは、Java の Properties クラス (java.util.Properties) とほぼ同様の 00047 # メソッドを持つ。また、入出力されるファイルは Java の Properties クラスが 00048 # 出力するものと互換性があるが、Unicode を含むものは扱うことができない。 00049 # 00050 # @since 0.4.0 00051 # 00052 # @else 00053 # 00054 # @class Properties 00055 # 00056 # The Properties class represents a persistent set of properties. The 00057 # Properties can be saved to a stream or loaded from a stream. Each key and 00058 # its corresponding value in the property list is a string. 00059 # 00060 # A property list can contain another property list as its "defaults"; this 00061 # second property list is searched if the property key is not found in the 00062 # original property list. 00063 # 00064 # Because Properties inherits from Hashtable, the put and putAll methods can 00065 # be applied to a Properties object. Their use is strongly discouraged as 00066 # they allow the caller to insert entries whose keys or values are not 00067 # Strings. The setProperty method should be used instead. If the store or 00068 # save method is called on a "compromised" Properties object that contains a 00069 # non-String key or value, the call will fail. 00070 # 00071 # The load and store methods load and store properties in a simple 00072 # line-oriented format specified below. This format uses the ISO 8859-1 00073 # character encoding. Characters that cannot be directly represented in this 00074 # encoding can be written using Unicode escapes ; only a single 'u' character 00075 # is allowed in an escape sequence. The native2ascii tool can be used to 00076 # convert property files to and from other character encodings. 00077 # 00078 # This class has almost same methods of Java's Properties class. Input and 00079 # Output stream of this properties are compatible each other except Unicode 00080 # encoded property file. 00081 # 00082 # @endif 00083 class Properties: 00084 """ 00085 """ 00086 00087 ## 00088 # @if jp 00089 # 00090 # @brief コンストラクタ 00091 # 00092 # 以下の順に引数をチェックし、インスタンスの生成を行う。 00093 # 00094 # 引数 prop に値が設定されている場合、 00095 # 引数に与えられた Properties のキー、値およびデフォルト値が 00096 # 全てそのままコピーされる。 00097 # 00098 # 引数 key に値が設定されている場合、 00099 # key と value のみを与えて Property のルートノードを作成する。 00100 # 値は全てデフォルト値として設定される。 00101 # 00102 # 引数 defaults_map に値が設定されている場合、 00103 # defaults_map に設定された内容をデフォルト値にもつ Properties を作成する。 00104 # 値は全てデフォルト値として設定される。 00105 # 00106 # 引数 defaults_str に値が設定されている場合、 00107 # 指定されたデフォルト値を持つ空のプロパティリストを作成する。 00108 # 値は全てデフォルト値として設定される。 00109 # デフォルト値は char* の配列により与えられ、key と value の対になって 00110 # おり、リストの終端は配列の数を表す引数 num か、空文字の key で与えらられ 00111 # なければならない。 00112 # 以下に例を示す。 00113 # 00114 # <pre> 00115 # const char* defaults = { 00116 # "key1", "value1", 00117 # "key2", "value2", 00118 # "key3", "value3", 00119 # "key4", "value4", 00120 # "key5", "value5", 00121 # "" }; 00122 # Properties p(defaults); 00123 # // もしくは 00124 # Properties p(defaults, 10); 00125 # </pre> 00126 # 00127 # @param self 00128 # @param key プロパティのキー(デフォルト値:None) 00129 # @param value プロパティの値(デフォルト値:None) 00130 # @param defaults_map デフォルト値として指定されるmap(デフォルト値:None) 00131 # @param defaults_str デフォルト値を指定する配列(デフォルト値:None) 00132 # @param num デフォルト値を設定する要素数(デフォルト値:None) 00133 # @param prop デフォルト値として指定されるproperty(デフォルト値:None) 00134 # 00135 # @else 00136 # 00137 # @brief Constructor 00138 # 00139 # All of given Properties's keys, values and default values are copied to 00140 # new Properties. 00141 # 00142 # Creates a root node of Property with root's key and value. 00143 # 00144 # Creates an Properties with default value of std::string map. 00145 # 00146 # Creates an empty property list with the specified defaults. 00147 # The default values are given by array of char*, which should be pairs 00148 # of "key" and "value". The end of list is specified by argument "num", 00149 # which specifies number of array or null character of key. 00150 # The following is an example. 00151 # 00152 # const char* defaults = { 00153 # "key1", "value1", 00154 # "key2", "value2", 00155 # "key3", "value3", 00156 # "key4", "value4", 00157 # "key5", "value5", 00158 # "" }; 00159 # Properties p(defaults); 00160 # // or 00161 # Properties p(defaults, 10); 00162 # 00163 # @endif 00164 def __init__(self, key=None, value=None, defaults_map=None, defaults_str=None, num=None, prop=None): 00165 self.default_value = "" 00166 self.root = None 00167 self.empty = "" 00168 self.leaf = [] 00169 00170 # Properties::Properties(const Properties& prop) 00171 if prop: 00172 self.name = prop.name 00173 self.value = prop.value 00174 self.default_value = prop.default_value 00175 00176 keys = prop.propertyNames() 00177 for _key in keys: 00178 node = None 00179 node = prop.getNode(_key) 00180 if node: 00181 self.setDefault(_key, node.default_value) 00182 self.setProperty(_key, node.value) 00183 00184 return 00185 00186 # Properties::Properties(const char* key, const char* value) 00187 if key: 00188 self.name = key 00189 if value is None: 00190 self.value = "" 00191 else: 00192 self.value = value 00193 return 00194 00195 self.name = "" 00196 self.value = "" 00197 00198 # Properties::Properties(std::map<std::string, std::string>& defaults) 00199 if defaults_map: 00200 #for i in range(len(defaults_map.items())): 00201 # self.setDefault(defaults_map.keys()[i], defaults_map.values()[i]) 00202 for key, value in defaults_map.items(): 00203 self.setDefault(key, value) 00204 return 00205 00206 if defaults_str: 00207 if num is None: 00208 _num = sys.maxint 00209 else: 00210 _num = num 00211 self.setDefaults(defaults_str, _num) 00212 return 00213 00214 00215 ## 00216 # @if jp 00217 # @brief 代入演算子 00218 # 00219 # 左辺値の Properties のキー、値およびデフォルト値は全て削除され、 00220 # 右辺値の Properties のキー、値およびデフォルト値が全てそのまま 00221 # コピーされる。 00222 # 00223 # @param self 00224 # @param prop OpenRTM_aist.Properties 00225 # 00226 # @else 00227 # @brief Assignment operator 00228 # @param self 00229 # @param prop OpenRTM_aist.Properties 00230 # @endif 00231 def assigmentOperator(self, prop): 00232 self.clear() 00233 self.name = prop.name 00234 self.value = prop.value 00235 self.default_value = prop.default_value 00236 00237 keys = prop.propertyNames() 00238 00239 for key in keys: 00240 node = None 00241 node = prop.getNode(key) 00242 if node: 00243 self.setDefault(key, node.default_value) 00244 self.setProperty(key, node.value) 00245 00246 return self 00247 00248 00249 ## 00250 # @if jp 00251 # 00252 # @brief デストラクタ 00253 # 00254 # @param self 00255 # 00256 # @else 00257 # 00258 # @brief Destructor 00259 # 00260 # @endif 00261 def __del__(self): 00262 self.clear() 00263 if self.root: 00264 self.root.removeNode(self.name) 00265 return 00266 00267 #============================================================ 00268 # public functions 00269 #============================================================ 00270 00271 00272 ## 00273 # @if jp 00274 # @brief Name の取得 00275 # 00276 # プロパティの名称を取得する。 00277 # 00278 # @param self 00279 # 00280 # @return プロパティ名 00281 # 00282 # @else 00283 # 00284 # @endif 00285 def getName(self): 00286 return self.name 00287 00288 00289 ## 00290 # @if jp 00291 # @brief 値の取得 00292 # 00293 # プロパティの値を取得する。 00294 # 00295 # @param self 00296 # 00297 # @return プロパティ値 00298 # 00299 # @else 00300 # 00301 # @endif 00302 def getValue(self): 00303 return self.value 00304 00305 00306 ## 00307 # @if jp 00308 # @brief デフォルト値の取得 00309 # 00310 # プロパティのデフォルト値を取得する。 00311 # 00312 # @param self 00313 # 00314 # @return プロパティデフォルト値 00315 # 00316 # @else 00317 # 00318 # @endif 00319 def getDefaultValue(self): 00320 return self.default_value 00321 00322 00323 ## 00324 # @if jp 00325 # @brief 子要素の取得 00326 # 00327 # プロパティの子要素を取得する。 00328 # 00329 # @param self 00330 # 00331 # @return 子要素 00332 # 00333 # @else 00334 # 00335 # @endif 00336 def getLeaf(self): 00337 return self.leaf 00338 00339 00340 ## 00341 # @if jp 00342 # @brief ルート要素の取得 00343 # 00344 # プロパティのルート要素を取得する。 00345 # 00346 # @param self 00347 # 00348 # @return ルート要素 00349 # 00350 # @else 00351 # 00352 # @endif 00353 def getRoot(self): 00354 return self.root 00355 00356 00357 ## 00358 # @if jp 00359 # 00360 # @brief 指定されたキーを持つプロパティを、プロパティリストから探す 00361 # 00362 # 指定されたキーを持つプロパティを、プロパティリストから探す。 00363 # そのキーがプロパティリストにない場合は、デフォルト値の引数が返される。 00364 # 00365 # @param self 00366 # @param key プロパティキー 00367 # @param default デフォルト値(デフォルト値:None) 00368 # 00369 # @return 指定されたキー値を持つこのプロパティリストの値 00370 # 00371 # @else 00372 # 00373 # @brief Searches for the property with the specified key in this property 00374 # 00375 # Searches for the property with the specified key in this property list. 00376 # The method returns the default value argument if the property is not 00377 # found. 00378 # 00379 # @param key the property key 00380 # @param defaultValue a default value. 00381 # 00382 # @return the value in this property list with the specified key value. 00383 # 00384 # @endif 00385 def getProperty(self, key, default=None): 00386 if default is None: 00387 keys = [] 00388 #keys = string.split(key, ".") 00389 self.split(key, ".", keys) 00390 00391 node = None 00392 node = self._getNode(keys, 0, self) 00393 if node: 00394 if node.value: 00395 return node.value 00396 else: 00397 return node.default_value 00398 return self.empty 00399 00400 else: 00401 value = self.getProperty(key) 00402 if value: 00403 return value 00404 else: 00405 return default 00406 00407 00408 ## 00409 # @if jp 00410 # @brief 指定されたキーに対してデフォルト値を取得する 00411 # 00412 # 指定されたキーを持つプロパティのデフォルト値を返す。 00413 # 指定されたキーを持つプロパティが存在しない場合には空文字を返す。 00414 # 00415 # @param self 00416 # @param key プロパティキー 00417 # 00418 # @return 指定されたキー値を持つプロパティのデフォルト値 00419 # 00420 # @else 00421 # @brief Set value as the default value to specified key's property 00422 # @endif 00423 def getDefault(self, key): 00424 keys = [] 00425 #keys = string.split(key, ".") 00426 self.split(key, ".", keys) 00427 node = None 00428 node = self._getNode(keys, 0, self) 00429 if node: 00430 return node.default_value 00431 00432 return self.empty 00433 00434 00435 ## 00436 # @if jp 00437 # 00438 # @brief Properties に value を key について登録する 00439 # 00440 # Properties に value を key について登録する。 00441 # すでに key に対する値を持っている場合、戻り値に古い値を返す。 00442 # 00443 # @param self 00444 # @param key プロパティリストに配置されるキー 00445 # @param value key に対応する値(デフォルト値:None) 00446 # 00447 # @return プロパティリストの指定されたキーの前の値。それがない場合は null 00448 # 00449 # @else 00450 # 00451 # @brief Sets a value associated with key in the property list 00452 # 00453 # This method sets the "value" associated with "key" in the property list. 00454 # If the property list has a value of "key", old value is returned. 00455 # 00456 # @param key the key to be placed into this property list. 00457 # @param value the value corresponding to key. 00458 # 00459 # @return the previous value of the specified key in this property list, 00460 # or null if it did not have one. 00461 # 00462 #@endif 00463 def setProperty(self, key, value=None): 00464 if value is not None: 00465 keys = [] 00466 #keys = string.split(key, ".") 00467 self.split(key, ".", keys) 00468 curr = self 00469 for _key in keys: 00470 next = curr.hasKey(_key) 00471 if next is None: 00472 next = OpenRTM_aist.Properties(key=_key) 00473 next.root = curr 00474 curr.leaf.append(next) 00475 curr = next 00476 retval = curr.value 00477 curr.value = value 00478 return retval 00479 00480 else: 00481 self.setProperty(key, self.getProperty(key)) 00482 prop = self.getNode(key) 00483 return prop.value 00484 00485 00486 ## 00487 # @if jp 00488 # @brief デフォルト値を登録する 00489 # 00490 # key で指定される要素にデフォルト値を登録する。 00491 # 00492 # @param self 00493 # @param key デフォルト値を登録するプロパティのキー 00494 # @param value 登録されるデフォルト値 00495 # 00496 # @return 指定されたデフォルト値 00497 # 00498 # @else 00499 # @brief Sets a default value associated with key in the property list 00500 # @endif 00501 def setDefault(self, key, value): 00502 keys = [] 00503 self.split(key, ".", keys) 00504 #keys = string.split(key, ".") 00505 00506 curr = self 00507 for _key in keys: 00508 next = curr.hasKey(_key) 00509 if next is None: 00510 next = OpenRTM_aist.Properties(key=_key) 00511 next.root = curr 00512 curr.leaf.append(next) 00513 curr = next 00514 if value != "" and value[-1] == "\n": 00515 value = value[0:len(value)-1] 00516 curr.default_value = value 00517 return value 00518 00519 00520 ## 00521 # @if jp 00522 # @brief Properties にデフォルト値をまとめて登録する 00523 # 00524 # 配列で指定された要素にデフォルト値をまとめて登録する。 00525 # デフォルト値は char* の配列により与えられ、key と value の対になって 00526 # おり、リストの終端は配列の数を表す引数 num か、空文字の key で与えらられ 00527 # なければならない。 00528 # 00529 # @param self 00530 # @param defaults デフォルト値を指定する配列 00531 # @param num デフォルト値を設定する要素数(デフォルト値:None) 00532 # 00533 # @else 00534 # @brief Sets a default value associated with key in the property list 00535 # @endif 00536 def setDefaults(self, defaults, num = None): 00537 if num is None: 00538 num = sys.maxint 00539 00540 i = 0 00541 len_ = len(defaults) 00542 while 1: 00543 if i > num or i > (len_ - 1) or defaults[i] == "": 00544 break 00545 00546 key = [defaults[i]] 00547 value = [defaults[i+1]] 00548 00549 OpenRTM_aist.eraseHeadBlank(key) 00550 OpenRTM_aist.eraseTailBlank(key) 00551 00552 OpenRTM_aist.eraseHeadBlank(value) 00553 OpenRTM_aist.eraseTailBlank(value) 00554 00555 self.setDefault(key[0], value[0]) 00556 00557 i +=2 00558 00559 00560 00561 #============================================================ 00562 # load and save functions 00563 #============================================================ 00564 00565 ## 00566 # @if jp 00567 # 00568 # @brief 指定された出力ストリームに、プロパティリストを出力する 00569 # 00570 # 指定された出力ストリームに、プロパティリストを出力する。 00571 # このメソッドは主にデバッグに用いられる。 00572 # 00573 # @param self 00574 # @param out 出力ストリーム 00575 # 00576 # @else 00577 # 00578 # @brief Prints this property list out to the specified output stream 00579 # 00580 # Prints this property list out to the specified output stream. 00581 # This method is useful for debugging. 00582 # 00583 # @param out an output stream. 00584 # 00585 # @endif 00586 def list(self, out): 00587 self._store(out, "", self) 00588 return 00589 00590 00591 ## 00592 # @if jp 00593 # 00594 # @brief 入力ストリームからキーと要素が対になったプロパティリストを読み込む 00595 # 00596 # 入力ストリームからキーと要素が対になったプロパティリストを読み込む。 00597 # ストリームは、ISO 8859-1 文字エンコーディングを使用しているとみなされる。 00598 # 各プロパティは、入力ストリームに行単位で登録されているものとみなされ、 00599 # 各行は行区切り文字 (\\n、\\r、または \\r\\n) で終わる。 00600 # 入力ストリームから読み込んだ行は、入力ストリームでファイルの終わりに 00601 # 達するまで処理される。 00602 # 00603 # 空白文字だけの行、または最初の非空白文字が ASCII 文字 # または ! である 00604 # 行は無視される。つまり、# または ! はコメント行を示す。 00605 # 00606 # 空白行またはコメント行以外のすべての行は、テーブルに追加されるプロパティ 00607 # を記述する。ただし、行の終わりが \ の場合は、次の行があれば継続行として 00608 # 扱われる (下記を参照)。 キーは、最初の非空白文字から、最初の ASCII 文字 00609 # =、:、または空白文字の直前までの、行内のすべての文字から構成される。 00610 # 00611 # キーの終わりを示す文字は、前に \ を付けることによりキーに含めることも 00612 # できる。キーの後ろの空白はすべてスキップされる。 00613 # キーの後ろの最初の非空白文字が = または : である場合は、これらのキーは 00614 # 無視され、そのあとの空白文字もすべてスキップされる。 00615 # 行内のそれ以外の文字はすべて、関連した要素文字列の一部となる。 00616 # 要素文字列内では、ASCII エスケープシーケンス \\t、\\n、\\r、\\\\、\\"、 00617 # \\'、\\ (円記号とスペース)、および \\uxxxx は認識され、単独の文字に変換 00618 # される。 00619 # また、行の最後の文字が \ である場合は、次の行は現在の行の継続として 00620 # 扱われる。その場合、\ と行区切り文字が破棄され、継続行の先頭に空白が 00621 # あればそれもすべて破棄され、要素文字列の一部にはならない。 00622 # 00623 # たとえば、次の 4 行はそれぞれキー Truth と関連した要素値 Beauty を表す。 00624 # 00625 # Truth = Beauty <BR> 00626 # Truth:Beauty <BR> 00627 # Truth\\t\\t\\t:Beauty <BR> 00628 # 00629 # また、次の 3 行は 1 つのプロパティを表す。 00630 # 00631 # fruits\\t\\t\\t\\tapple, banana, pear, \ <BR> 00632 # cantaloupe, watermelon, \ <BR> 00633 # kiwi, mango <BR> 00634 # キーは fruits で、次の要素に関連付けれられる。 00635 # "apple, banana, pear, cantaloupe, watermelon, kiwi, mango" 00636 # 最終的な結果でコンマのあとに必ずスペースが表示されるように、 00637 # 各 \ の前にスペースがある。行の終わりを示す \ と、継続行の先頭にある 00638 # 空白は破棄され、他の文字に置換されない。 00639 # また、次の 3 番目の例では、キーが cheeses で、関連した要素が空の文字列 00640 # であることを表す。 00641 # 00642 # cheeses <BR> 00643 # キーは、cheeses で、関連要素は空の文字列であることを指定している。 00644 # 00645 # @param self 00646 # @param inStream 入力ストリーム 00647 # 00648 # @else 00649 # 00650 # @brief Loads property list consists of key:value from input stream 00651 # 00652 # Reads a property list (key and element pairs) from the input stream. 00653 # The stream is assumed to be using the ISO 8859-1 character encoding; that 00654 # is each byte is one Latin1 character. Characters not in Latin1, and 00655 # certain special characters, can be represented in keys and elements using 00656 # escape sequences similar to those used for character and string literals 00657 # The differences from the character escape sequences used for characters 00658 # and strings are: 00659 # - Octal escapes are not recognized. 00660 # - The character sequence \b does not represent a backspace character. 00661 # - The method does not treat a backslash character, \, before a non-valid 00662 # escape character as an error; the backslash is silently dropped. For 00663 # example, in a Java string the sequence "\z" would cause a compile time 00664 # error. In contrast, this method silently drops the backslash. 00665 # Therefore, this method treats the two character sequence "\b" as 00666 # equivalent to the single character 'b'. 00667 # - Escapes are not necessary for single and double quotes; however, by the 00668 # rule above, single and double quote characters preceded by a backslash 00669 # still yield single and double quote characters, respectively. 00670 # An IllegalArgumentException is thrown if a malformed Unicode escape 00671 # appears in the input. 00672 # 00673 # This method processes input in terms of lines. A natural line of input is 00674 # terminated either by a set of line terminator characters 00675 # (\n or \r or \r\n) or by the end of the file. A natural line may be 00676 # either a blank line, a comment line, or hold some part of a key-element 00677 # pair. The logical line holding all the data for a key-element pair may 00678 # be spread out across several adjacent natural lines by escaping the line 00679 # terminator sequence with a backslash character, \. Note that a comment 00680 # line cannot be extended in this manner; every natural line that is a 00681 # comment must have its own comment indicator, as described below. If a 00682 # logical line is continued over several natural lines, the continuation 00683 # lines receive further processing, also described below. Lines are read 00684 # from the input stream until end of file is reached. 00685 # 00686 # A natural line that contains only white space characters is considered 00687 # blank and is ignored. A comment line has an ASCII '#' or '!' as its first 00688 # non-white space character; comment lines are also ignored and do not 00689 # encode key-element information. In addition to line terminators, this 00690 # method considers the characters space (' ', '\u0020'), tab 00691 # ('\t', '\u0009'), and form feed ('\f', '\u000C') to be white space. 00692 # 00693 # If a logical line is spread across several natural lines, the backslash 00694 # escaping the line terminator sequence, the line terminator sequence, and 00695 # any white space at the start the following line have no affect on the key 00696 # or element values. The remainder of the discussion of key and element 00697 # parsing will assume all the characters constituting the key and element 00698 # appear on a single natural line after line continuation characters have 00699 # been removed. Note that it is not sufficient to only examine the 00700 # character preceding a line terminator sequence to see if the line 00701 # terminator is escaped; there must be an odd number of contiguous 00702 # backslashes for the line terminator to be escaped. Since the input is 00703 # processed from left to right, a non-zero even number of 2n contiguous 00704 # backslashes before a line terminator (or elsewhere) encodes n 00705 # backslashes after escape processing. 00706 # 00707 # The key contains all of the characters in the line starting with the 00708 # first non-white space character and up to, but not including, the first 00709 # unescaped '=', ':', or white space character other than a line 00710 # terminator. All of these key termination characters may be included in 00711 # the key by escaping them with a preceding backslash character; 00712 # for example, 00713 # 00714 # \:\= 00715 # 00716 # would be the two-character key ":=". Line terminator characters can be 00717 # included using \r and \n escape sequences. Any white space after the key 00718 # is skipped; if the first non-white space character after the key is '=' 00719 # or ':', then it is ignored and any white space characters after it are 00720 # also skipped. All remaining characters on the line become part of the 00721 # associated element string; if there are no remaining characters, the 00722 # element is the empty string "". Once the raw character sequences 00723 # constituting the key and element are identified, escape processing is 00724 # performed as described above. 00725 # 00726 # As an example, each of the following three lines specifies the key 00727 # "Truth" and the associated element value "Beauty": 00728 # 00729 # Truth = Beauty <BR> 00730 # Truth:Beauty <BR> 00731 # Truth :Beauty <BR> 00732 # As another example, the following three lines specify a single 00733 # property: 00734 # 00735 # fruits apple, banana, pear, \ <BR> 00736 # cantaloupe, watermelon, \ <BR> 00737 # kiwi, mango <BR> 00738 # The key is "fruits" and the associated element is: 00739 # "apple, banana, pear, cantaloupe, watermelon, kiwi, mango"Note that a 00740 # space appears before each \ so that a space will appear after each comma 00741 # in the final result; the \, line terminator, and leading white space on 00742 # the continuation line are merely discarded and are not replaced by one or 00743 # more other characters. 00744 # As a third example, the line: 00745 # 00746 # cheeses <BR> 00747 # specifies that the key is "cheeses" and the associated element is the 00748 # empty string "". 00749 # 00750 # @param inStream the input stream. 00751 # 00752 # @endif 00753 def load(self, inStream): 00754 pline = "" 00755 for readStr in inStream: 00756 if not readStr: 00757 continue 00758 00759 tmp = [readStr] 00760 OpenRTM_aist.eraseHeadBlank(tmp) 00761 _str = tmp[0] 00762 00763 if _str[0] == "#" or _str[0] == "!" or _str[0] == "\n": 00764 continue 00765 00766 _str = _str.rstrip('\r\n') 00767 00768 if _str[len(_str)-1] == "\\" and not OpenRTM_aist.isEscaped(_str, len(_str)-1): 00769 #_str = _str[0:len(_str)-1] 00770 tmp = [_str[0:len(_str)-1]] 00771 OpenRTM_aist.eraseTailBlank(tmp) 00772 #pline += _str 00773 pline += tmp[0] 00774 continue 00775 pline += _str 00776 if pline == "": 00777 continue 00778 00779 key = [] 00780 value = [] 00781 self.splitKeyValue(pline, key, value) 00782 key[0] = OpenRTM_aist.unescape(key) 00783 OpenRTM_aist.eraseHeadBlank(key) 00784 OpenRTM_aist.eraseTailBlank(key) 00785 00786 value[0] = OpenRTM_aist.unescape(value) 00787 OpenRTM_aist.eraseHeadBlank(value) 00788 OpenRTM_aist.eraseTailBlank(value) 00789 00790 self.setProperty(key[0], value[0]) 00791 pline = "" 00792 00793 00794 ## 00795 # @if jp 00796 # 00797 # @brief プロパティリストを指定されたストリームに保存する 00798 # 00799 # プロパティリストを指定されたストリームに保存する。 00800 # このメソッドは Java Properties との互換性のために定義されている。 00801 # (内部的には store メソッドを利用している。) 00802 # 00803 # @param self 00804 # @param out 出力ストリーム 00805 # @param header プロパティリストの記述 00806 # 00807 # @else 00808 # 00809 # @brief Save the properties list to the stream 00810 # 00811 # Deprecated. 00812 # 00813 # @param out The output stream 00814 # @param header A description of the property list 00815 # 00816 # @endif 00817 def save(self, out, header): 00818 self.store(out, header) 00819 return 00820 00821 00822 ## 00823 # @if jp 00824 # 00825 # @brief プロパティリストを出力ストリームへ保存する 00826 # 00827 # Properties テーブル内のプロパティリスト (キーと要素のペア) を、load 00828 # メソッドを使って Properties テーブルにロードするのに適切なフォーマットで 00829 # 出力ストリームに書き込む。 00830 # 00831 # Properties テーブル内のプロパティリスト (キーと要素のペア) を、load 00832 # メソッドを使って Properties テーブルにロードするのに適切なフォーマットで 00833 # 出力ストリームに書き込む。ストリームは、ISO 8859-1 文字 00834 # エンコーディングを使用して書き込まれる。 00835 # Properties テーブル (存在する場合) のデフォルトテーブルからの 00836 # プロパティは、このメソッドによっては書き込まれない。 00837 # 00838 # header 引数が null でない場合は、ASCII 文字の #、header の文字列、 00839 # および行区切り文字が最初に出力ストリームに書き込まれます。このため、 00840 # header は識別コメントとして使うことができる。 00841 # 00842 # 次に、ASCII 文字の #、現在の日時 (Date の toString メソッドによって 00843 # 現在時刻が生成されるのと同様)、および Writer によって生成される行区切り 00844 # からなるコメント行が書き込まれる。 00845 # 00846 # 続いて、 Properties テーブル内のすべてのエントリが 1 行ずつ書き出される。 00847 # 各エントリのキー文字列、ASCII 文字の=、関連した要素文字列が書き込まれる。 00848 # 要素文字列の各文字は、エスケープシーケンスとして描画する必要があるか 00849 # どうか確認される。ASCII 文字の \、タブ、改行、および復帰はそれぞれ \\\\、 00850 # \\t、\\n、および \\r として書き込まれる。\\u0020 より小さい文字および 00851 # \\u007E より大きい文字は、対応する 16 進値 xxxx を使って \\uxxxx として 00852 # 書き込まれる。埋め込み空白文字でも後書き空白文字でもない先行空白文字は、 00853 # 前に \ を付けて書き込まれる。キーと値の文字 #、!、=、および : は、 00854 # 必ず正しくロードされるように、前にスラッシュを付けて書き込まれる。 00855 # 00856 # エントリが書き込まれたあとで、出力ストリームがフラッシュされる。 00857 # 出力ストリームはこのメソッドから復帰したあとも開いたままとなる。 00858 # 00859 # @param self 00860 # @param out 出力ストリーム 00861 # @param header プロパティリストの記述 00862 # 00863 # @else 00864 # 00865 # @brief Stores property list to the output stream 00866 # 00867 # Writes this property list (key and element pairs) in this Properties 00868 # table to the output stream in a format suitable for loading into a 00869 # Properties table using the load method. The stream is written using the 00870 # ISO 8859-1 character encoding. 00871 # 00872 # Properties from the defaults table of this Properties table (if any) are 00873 # not written out by this method. 00874 # 00875 # If the comments argument is not null, then an ASCII # character, the 00876 # comments string, and a line separator are first written to the output 00877 # stream. Thus, the comments can serve as an identifying comment. 00878 # 00879 # Next, a comment line is always written, consisting of an ASCII # 00880 # character, the current date and time (as if produced by the toString 00881 # method of Date for the current time), and a line separator as generated 00882 # by the Writer. 00883 # 00884 # Then every entry in this Properties table is written out, one per line. 00885 # For each entry the key string is written, then an ASCII =, then the 00886 # associated element string. Each character of the key and element strings 00887 # is examined to see whether it should be rendered as an escape sequence. 00888 # The ASCII characters \, tab, form feed, newline, and carriage return are 00889 # written as \\, \t, \f \n, and \r, respectively. Characters less than 00890 # \u0020 and characters greater than \u007E are written as \uxxxx for the 00891 # appropriate hexadecimal value xxxx. For the key, all space characters are 00892 # written with a preceding \ character. For the element, leading space 00893 # characters, but not embedded or trailing space characters, are written 00894 # with a preceding \ character. The key and element characters #, !, =, and 00895 # : are written with a preceding backslash to ensure that they are properly 00896 # loaded. 00897 # 00898 # After the entries have been written, the output stream is flushed. The 00899 # output stream remains open after this method returns. 00900 # 00901 # @param out an output stream. 00902 # @param header a description of the property list. 00903 # 00904 # @endif 00905 def store(self, out, header): 00906 out.write("#"+header+"\n") 00907 self._store(out, "", self) 00908 00909 00910 #============================================================ 00911 # other util functions 00912 #============================================================ 00913 00914 ## 00915 # @if jp 00916 # 00917 # @brief プロパティのキーのリストを vector で返す 00918 # 00919 # メインプロパティリストに同じ名前のキーが見つからない場合は、デフォルトの 00920 # プロパティリストにある個別のキーを含む、このプロパティリストにあるすべて 00921 # のキーのリストを返す。 00922 # 00923 # @param self 00924 # 00925 # @return プロパティリストにあるすべてのキーのリスト。 00926 # デフォルトのプロパティリストにあるキーを含む 00927 # 00928 # @else 00929 # 00930 # @brief Returns an vector of all the keys in this property 00931 # 00932 # Returns an enumeration of all the keys in this property list, including 00933 # distinct keys in the default property list if a key of the same name has 00934 # not already been found from the main properties list. 00935 # 00936 # @return an vector of all the keys in this property list, including the 00937 # keys in the default property list. 00938 # 00939 # @endif 00940 def propertyNames(self): 00941 names = [] 00942 for leaf in self.leaf: 00943 self._propertyNames(names, leaf.name, leaf) 00944 return names 00945 00946 00947 ## 00948 # @if jp 00949 # @brief プロパティの数を取得する 00950 # 00951 # 設定済みのプロパティ数を取得する。 00952 # 00953 # @param self 00954 # 00955 # @return プロパティ数 00956 # 00957 # @else 00958 # @brief Get number of Properties 00959 # @endif 00960 def size(self): 00961 return len(self.propertyNames()) 00962 00963 00964 ## 00965 # @if jp 00966 # @brief ノードを検索する 00967 # @else 00968 # @brief Find node of properties 00969 # @endif 00970 # Properties* const Properties::findNode(const std::string& key) const 00971 def findNode(self, key): 00972 if not key: 00973 return None 00974 00975 keys = [] 00976 self.split(key, '.', keys) 00977 return self._getNode(keys, 0, self) 00978 00979 00980 ## 00981 # @if jp 00982 # @brief ノードを取得する 00983 # 00984 # 指定したキーを持つノードを取得する。 00985 # 00986 # @param self 00987 # @param key 取得対象ノードのキー 00988 # 00989 # @return 対象ノード 00990 # 00991 # @else 00992 # @brief Get node of Properties 00993 # @endif 00994 def getNode(self, key): 00995 if not key: 00996 return self 00997 00998 leaf = self.findNode(key) 00999 if leaf: 01000 return leaf 01001 01002 self.createNode(key) 01003 return self.findNode(key) 01004 01005 01006 ## 01007 # @if jp 01008 # @brief 新規ノードを生成する 01009 # 01010 # 指定したキーを持つ新規ノードを生成する。 01011 # 既に同一キーを持つノードが登録済みの場合にはエラーを返す。 01012 # 01013 # @param self 01014 # @param key 新規ノードのキー 01015 # 01016 # @return 新規ノード生成結果 01017 # 指定したキーを持つノードが既に存在する場合にはfalse 01018 # 01019 # @else 01020 # 01021 # @endif 01022 def createNode(self, key): 01023 if not key: 01024 return False 01025 01026 if self.findNode(key): 01027 return False 01028 01029 self.setProperty(key,"") 01030 return True 01031 01032 01033 ## 01034 # @if jp 01035 # @brief ノードを削除する 01036 # 01037 # 指定した名称を持つプロパティを削除する。 01038 # 削除したプロパティを返す。 01039 # 01040 # @param self 01041 # @param leaf_name 削除対象プロパティ名称 01042 # 01043 # @return 削除したプロパティ 01044 # 01045 # @else 01046 # @brief Get node of Properties 01047 # @endif 01048 def removeNode(self, leaf_name): 01049 len_ = len(self.leaf) 01050 for i in range(len_): 01051 idx = (len_ - 1) - i 01052 if self.leaf[idx].name == leaf_name: 01053 prop = self.leaf[idx] 01054 del self.leaf[idx] 01055 return prop 01056 return None 01057 01058 01059 ## 01060 # @if jp 01061 # @brief 子ノードにkeyがあるかどうか 01062 # 01063 # 指定したキーを持つ子ノードが存在するかどうか確認する。 01064 # 存在する場合、子ノードを返す。 01065 # 01066 # @param self 01067 # @param key 確認対象のキー 01068 # 01069 # @return 子ノード 01070 # 01071 # @else 01072 # @brief If key exists in the children 01073 # @endif 01074 def hasKey(self, key): 01075 for leaf in self.leaf: 01076 if leaf.name == key: 01077 return leaf 01078 01079 return None 01080 01081 01082 ## 01083 # @if jp 01084 # @brief 子ノードを全て削除する 01085 # 01086 # @param self 01087 # 01088 # @else 01089 # @brief If key exists in the children 01090 # @endif 01091 def clear(self): 01092 len_ = len(self.leaf) 01093 for i in range(len_): 01094 if self.leaf[-1]: 01095 del self.leaf[-1] 01096 01097 return 01098 01099 01100 ## 01101 # @if jp 01102 # @brief Propertyをマージする 01103 # 01104 # 現在のプロパティに設定したプロパティをマージする。 01105 # 01106 # @param self 01107 # @param prop マージするプロパティ 01108 # 01109 # @return プロパティマージ結果 01110 # 01111 # @else 01112 # @brief Merge properties 01113 # @endif 01114 def mergeProperties(self, prop): 01115 keys = prop.propertyNames() 01116 01117 for i in range(prop.size()): 01118 self.setProperty(keys[i], prop.getProperty(keys[i])) 01119 01120 return self 01121 01122 01123 ## 01124 # @if jp 01125 # @brief 文字列をキーと値のペアに分割する 01126 # 01127 # 与えられた文字列を、設定されたデリミタでキーと値のペアに分割する。 01128 # まず最初に与えられた文字列に':'もしくは'='が含まれるかを検索し、 01129 # どちらかの文字が含まれている場合にはそれをデリミタとして使用する。 01130 # 両方とも含まれていない場合には、' '(スペース)を用いて分割を試みる。 01131 # 全てのデリミタ候補が含まれていない場合には、与えられた文字列をキーとして 01132 # 設定し、値に空の文字列を設定する。 01133 # どのデリミタ候補についてもエスケープされている(直前に'\'が設定されている) 01134 # 場合には、デリミタとして使用しない。 01135 # 01136 # @param self 01137 # @param _str 分割対象文字列 01138 # @param key 分割結果キー 01139 # @param value 分割結果値 01140 # 01141 # @else 01142 # 01143 # @endif 01144 def splitKeyValue(self, _str, key, value): 01145 i = 0 01146 length = len(_str) 01147 01148 while i < length: 01149 if (_str[i] == ":" or _str[i] == "=") and not OpenRTM_aist.isEscaped(_str, i): 01150 key.append(_str[0:i]) 01151 value.append(_str[i+1:]) 01152 return 01153 i += 1 01154 01155 # If no ':' or '=' exist, ' ' would be delimiter. 01156 i = 0 01157 while i < length: 01158 if (_str[i] == " ") and not OpenRTM_aist.isEscaped(_str, i): 01159 key.append(_str[0:i]) 01160 value.append(_str[i+1:]) 01161 return 01162 i += 1 01163 01164 key.append(_str) 01165 value.append("") 01166 return 01167 01168 01169 ## 01170 # @if jp 01171 # @brief 文字列を分割する 01172 # 01173 # 与えられた文字列を、与えられたデリミタで分割する。 01174 # 与えられた文字列が空の場合は、エラーを返す。 01175 # 与えられたデリミタがエスケープされている(直前に'\'が設定されている)場合 01176 # には、デリミタとして使用しない。 01177 # 01178 # @param self 01179 # @param _str 分割対象文字列 01180 # @param delim デリミタ 01181 # @param value 分割結果値リスト 01182 # 01183 # @return 分割処理結果 01184 # 01185 # @else 01186 # 01187 # @endif 01188 def split(self, _str, delim, value): 01189 if _str == "": 01190 return False 01191 01192 begin_it = end_it = 0 01193 01194 length = len(_str) 01195 01196 while end_it < length: 01197 if _str[end_it] == delim and not OpenRTM_aist.isEscaped(_str, end_it): 01198 value.append(_str[begin_it:end_it]) 01199 begin_it = end_it + 1 01200 end_it += 1 01201 01202 value.append(_str[begin_it:end_it]) 01203 return True 01204 01205 01206 ## 01207 # @if jp 01208 # @brief プロパティを取得する 01209 # 01210 # キーリストで指定されたプロパティを取得する。 01211 # キーリストでは、指定するキーのプロパティでの階層関係をリスト形式で表現 01212 # する。 01213 # 指定したキーリストに該当するプロパティが存在しない場合はNoneを返す。 01214 # 01215 # @param self 01216 # @param keys 取得対象プロパティのキーのリスト表現 01217 # @param index キーリストの階層数 01218 # @param curr 検索対象プロパティ 01219 # 01220 # @return 検索対象プロパティ 01221 # 01222 # @else 01223 # 01224 # @endif 01225 def _getNode(self, keys, index, curr): 01226 next = curr.hasKey(keys[index]) 01227 if next is None: 01228 return None 01229 01230 if index < (len(keys) - 1): 01231 index+=1 01232 return next._getNode(keys, index, next) 01233 else: 01234 return next 01235 01236 return None 01237 01238 01239 ## 01240 # @if jp 01241 # @brief プロパティの名称リストを取得する 01242 # 01243 # プロパティの名称を'.'区切りで表現したリストを取得する。 01244 # 01245 # @param self 01246 # @param names プロパティの名称リスト 01247 # @param curr_name 現在のプロパティ名 01248 # @param curr 対象プロパティ 01249 # 01250 # @else 01251 # 01252 # @endif 01253 def _propertyNames(self, names, curr_name, curr): 01254 if len(curr.leaf) > 0: 01255 for i in range(len(curr.leaf)): 01256 next_name = curr_name+"."+curr.leaf[i].name 01257 self._propertyNames(names, next_name, curr.leaf[i]) 01258 else: 01259 names.append(curr_name) 01260 01261 return 01262 01263 01264 ## 01265 # @if jp 01266 # @brief プロパティの名称リストを保存する 01267 # 01268 # プロパティの名称を'.'区切りで表現したリストを保存する。 01269 # 01270 # @param self 01271 # @param out プロパティの名称リスト保存先の出力ストリーム 01272 # @param curr_name 現在のプロパティ名 01273 # @param curr 対象プロパティ 01274 # 01275 # @else 01276 # 01277 # @endif 01278 def _store(self, out, curr_name, curr): 01279 if len(curr.leaf) > 0: 01280 for i in range(len(curr.leaf)): 01281 if curr_name == "": 01282 next_name = curr.leaf[i].name 01283 else: 01284 next_name = curr_name+"."+curr.leaf[i].name 01285 self._store(out, next_name, curr.leaf[i]) 01286 01287 else: 01288 val = curr.value 01289 if val == "": 01290 val = curr.default_value 01291 out.write(curr_name+": "+val+"\n") 01292 01293 return 01294 01295 01296 ## 01297 # @if jp 01298 # @brief インデントを生成する 01299 # 01300 # 指定された数字に従って生成したインデントを返す。 01301 # 返されるインデントは、指定数字×2つの空白。 01302 # 01303 # @param self 01304 # @param index インデント数の指定 01305 # 01306 # @return 生成されたインデント 01307 # 01308 # @else 01309 # 01310 # @endif 01311 def indent(self, index): 01312 space = "" 01313 01314 for i in range(index-1): 01315 space += " " 01316 01317 return space 01318 01319 01320 ## 01321 # @if jp 01322 # @brief プロパティの内容を保存する 01323 # 01324 # プロパティに設定された内容を保存する。 01325 # 保存時にはプロパティ階層の深さを表す数字が付加される。 01326 # 値が設定されていないプロパティについては、デフォルト値が出力される。 01327 # 01328 # @param self 01329 # @param out プロパティ内容保存先の出力ストリーム 01330 # @param curr 対象プロパティ 01331 # @param index 現在のプロパティ階層 01332 # 01333 # @else 01334 # 01335 # @endif 01336 def _dump(self, out, curr, index): 01337 if index != 0: 01338 #ut.write(self.indent(index)+"- "+curr.name) 01339 out[0]+=self.indent(index)+"- "+curr.name 01340 01341 if curr.leaf == []: 01342 if curr.value == "": 01343 #out.write(": "+curr.default_value+"\n") 01344 out[0]+=": "+curr.default_value+"\n" 01345 else: 01346 #out.write(": "+curr.value+"\n") 01347 out[0]+=": "+str(curr.value)+"\n" 01348 return out[0] 01349 01350 if index != 0: 01351 #out.write("\n") 01352 out[0]+="\n" 01353 01354 for i in range(len(curr.leaf)): 01355 self._dump(out, curr.leaf[i], index + 1) 01356 01357 return out[0] 01358 01359 01360 ## 01361 # @if jp 01362 # @brief プロパティの内容を出力する 01363 # 01364 # プロパティに設定された内容を出力する。<br> 01365 # friend std::ostream& operator<<(std::ostream& lhs, const Properties& rhs); 01366 # の代わりに、print objにて呼び出し可能とするためのメソッド。 01367 # 01368 # @param self 01369 # 01370 # @return 設定プロパティ文字列表示 01371 # 01372 # @else 01373 # 01374 # @endif 01375 def __str__(self): 01376 string=[""] 01377 return self._dump(string, self, 0) 01378 01379