last update 20 Sep 2009 |
00001 /* 00002 * Copyright (C) 1998 - 2005 00003 * Lehrstuhl fuer Technische Informatik, RWTH-Aachen, Germany 00004 * 00005 * 00006 * This file is part of the Computer Vision and Robotics Library (CVR-Lib) 00007 * 00008 * The CVR-Lib is free software; you can redistribute it and/or 00009 * modify it under the terms of the BSD License. 00010 * 00011 * All rights reserved. 00012 * 00013 * Redistribution and use in source and binary forms, with or without 00014 * modification, are permitted provided that the following conditions are met: 00015 * 00016 * 1. Redistributions of source code must retain the above copyright notice, 00017 * this list of conditions and the following disclaimer. 00018 * 00019 * 2. Redistributions in binary form must reproduce the above copyright notice, 00020 * this list of conditions and the following disclaimer in the documentation 00021 * and/or other materials provided with the distribution. 00022 * 00023 * 3. Neither the name of the authors nor the names of its contributors may be 00024 * used to endorse or promote products derived from this software without 00025 * specific prior written permission. 00026 * 00027 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00028 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00029 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00030 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00031 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00032 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00033 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00034 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00035 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00036 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00037 * POSSIBILITY OF SUCH DAMAGE. 00038 */ 00039 00040 00041 00042 /** 00043 * \file cvrLispStreamHandler.h 00044 * Contains cvr::lispStreamHandler a lisp-like ASCII ioHandler 00045 * \author Pablo Alvarado 00046 * \date 07.12.2000 00047 * 00048 * $Id: cvrLispStreamHandler.h,v 1.2 2005/07/22 15:59:21 doerfler Exp $ 00049 */ 00050 00051 #ifndef _CVR_LISP_STREAM_HANDLER_H_ 00052 #define _CVR_LISP_STREAM_HANDLER_H_ 00053 00054 00055 #include "cvrObject.h" 00056 #include "cvrIoHandler.h" 00057 #include <string> 00058 #include <map> 00059 #include <list> 00060 00061 #include <iostream> 00062 00063 namespace cvr { 00064 /** 00065 * The lispStreamHandler class offers an interface for the functor parameters 00066 * and other classes to read() and write() them in a LISP-like format. 00067 * This is the CVR-Lib standard ioHandler. 00068 * 00069 * If the standard functions atof() and operator<< for numbers 00070 * consider the locale settings (this occurs in MS-VC++ or newer 00071 * glibc and gcc with Linux), then the read() and write() methods 00072 * will also be localed. A typical problem with this "feature" is 00073 * that if you have a file saved with "LANG=C", the decimal 00074 * point is a point (e.g. 1.532), and when you try to read it in 00075 * another locale (for example LANG=de_DE.ISO-8859-1), then all numbers with 00076 * a decimal point won't be read correctly, because the method will be 00077 * expecting a decimal comma (e.g. 1,532). 00078 * 00079 * See also the read and write methods for the basic types for more 00080 * information 00081 * 00082 * \warning The given streams must be "ASCII" streams. If they are 00083 * created with the binary flag, some weird effects can be expected. 00084 * 00085 * Example: 00086 * \code 00087 * // the lisp stream formatting object 00088 * cvr::lispStreamHandler lsh; 00089 * 00090 * // Write example: 00091 * 00092 * // open a stream in text mode 00093 * std::ofstream out("testfile.bin"); 00094 * 00095 * // tell the lisp stream handler to use the given stream 00096 * lsh.use(out); 00097 * 00098 * cvr::write(lsh,"anInteger",5); 00099 * cvr::write(lsh,"aString","hello world"); 00100 * 00101 * out.close(); 00102 * 00103 * // Read example 00104 * 00105 * // Open a stream in lisp mode 00106 * std::ifstream in("testfile.bin"); 00107 * 00108 * lsh.use(in); 00109 * int i; 00110 * cvr::read(lsh,"anInteger",i); 00111 * 00112 * std::string str; 00113 * cvr::read(lsh,"aString",str); 00114 * 00115 * in.close(); 00116 * \endcode 00117 * 00118 * @ingroup gStorable 00119 */ 00120 class lispStreamHandler : public ioHandler { 00121 public: 00122 /** 00123 * default constructor 00124 */ 00125 lispStreamHandler(); 00126 00127 /** 00128 * default constructor 00129 * 00130 * \warning The given stream must be an "ASCII" stream. If it is 00131 * created with the binary flag, some weird effects can be expected. 00132 */ 00133 lispStreamHandler(std::ostream& aStream); 00134 00135 /** 00136 * default constructor 00137 * 00138 * \warning The given stream must be an "ASCII" stream. If it is 00139 * created with the binary flag, some weird effects can be expected. 00140 */ 00141 lispStreamHandler(std::istream& aStream); 00142 00143 00144 /** 00145 * default constructor. 00146 * This constructor uses the given string as input, as if read from a 00147 * stread. 00148 * 00149 * \warning Note that the given string is NOT a filename, but a 00150 * string containing the data "stream". This is useful especially 00151 * for the JNI (java native interface). You can of course also use 00152 * the std::ostringstream and std::istringstream with the other 00153 * constructors or with the method use(). 00154 */ 00155 lispStreamHandler(const char *aStream); 00156 00157 /** 00158 * copy constructor 00159 */ 00160 lispStreamHandler(const lispStreamHandler& other); 00161 00162 /** 00163 * destructor 00164 */ 00165 virtual ~lispStreamHandler(); 00166 00167 /** 00168 * indicate the output stream to be used 00169 * 00170 * Calling this method you will reinitialize the state of the 00171 * parser (see also clear()). 00172 */ 00173 void use(std::ostream& aStream); 00174 00175 /** 00176 * indicate the input stream to be used 00177 * 00178 * Calling this method you will reinitialize the state of the 00179 * parser (see also clear()). 00180 */ 00181 void use(std::istream& aStream); 00182 00183 /** 00184 * This method resets all internal state variables (for input and 00185 * output streams as well) in a way that the next operations 00186 * behave as if this handler were used for the first time. This 00187 * allows the use of the same handler instance after reopening a 00188 * stream. Alternativelly, you can just call the 00189 * use(std::istream&) or use(std::ostream&) members to clear the 00190 * input or output state variables only. If you use this method 00191 * "within" a read/write process, the behaviour will be 00192 * unpredictable. 00193 */ 00194 void clear(); 00195 00196 /** 00197 * copy data of "other" functor. 00198 * @param other the functor to be copied 00199 * @return a reference to this functor object 00200 */ 00201 lispStreamHandler& copy(const lispStreamHandler& other); 00202 00203 /** 00204 * copy data of "other" functor. 00205 * @param other the functor to be copied 00206 * @return a reference to this functor object 00207 */ 00208 lispStreamHandler& operator=(const lispStreamHandler& other); 00209 00210 /** 00211 * Returns the name of this class. 00212 */ 00213 virtual const std::string& name() const; 00214 00215 /** 00216 * returns a pointer to a clone of this functor. 00217 */ 00218 virtual lispStreamHandler* clone() const; 00219 00220 /** 00221 * returns a pointer to a new instance of this functor. 00222 */ 00223 virtual lispStreamHandler* newInstance() const; 00224 00225 /** 00226 * the begin token or tokens: here a "(". 00227 * 00228 */ 00229 virtual bool writeBegin(); 00230 00231 /** 00232 * the end token or tokens: here a ")". 00233 */ 00234 virtual bool writeEnd(); 00235 00236 /** 00237 * the begin token or tokens: here a "(" 00238 */ 00239 virtual bool readBegin(); 00240 00241 /** 00242 * the end token or tokens: here a ")" 00243 */ 00244 virtual bool readEnd(); 00245 00246 /** @name write members 00247 */ 00248 //@{ 00249 /** 00250 * write a std::string. 00251 * This method will write just the string if it does not contain spaces. 00252 * Otherwise the string will be enclosed by quotes. 00253 */ 00254 virtual bool write(const std::string& data); 00255 00256 /** 00257 * write a character string. 00258 * This method will write just the string if it does not contain spaces. 00259 * Otherwise the string will be enclosed by quotes. 00260 */ 00261 virtual bool write(const char* data); 00262 00263 /** 00264 * write a double value. 00265 * 00266 * \warning Be aware of the locale you are using. The number must be 00267 * read with the same locale used when it was written 00268 */ 00269 virtual bool write(const double& data); 00270 00271 /** 00272 * write a float value 00273 * 00274 * \warning Be aware of the locale you are using. The number must be 00275 * read with the same locale used when it was written 00276 */ 00277 virtual bool write(const float& data); 00278 00279 /** 00280 * write an integer value 00281 * 00282 * \warning Be aware of the locale you are using. The number must be 00283 * read with the same locale used when it was written 00284 */ 00285 virtual bool write(const int data); 00286 00287 /** 00288 * write an unsigned integer value 00289 * 00290 * \warning Be aware of the locale you are using. The number must be 00291 * read with the same locale used when it was written 00292 */ 00293 virtual bool write(const unsigned int& data); 00294 00295 /** 00296 * write a char 00297 * 00298 * The char is writen as numerical code if there is no standard ASCII 00299 * representation. If there is an ASCII representation (i.e. its value is 00300 * greater or equal 32 (' ') and smaller or equal 127 ('~'), then the 00301 * ASCII character will be writen enclosed in single quotes. 00302 */ 00303 virtual bool write(const char& data); 00304 00305 /** 00306 * write an 8-bit signed value 00307 */ 00308 virtual bool write(const byte& data); 00309 00310 /** 00311 * write a unsigned 8-bit value 00312 */ 00313 virtual bool write(const ubyte& data); 00314 00315 /** 00316 * write a boolean 00317 */ 00318 virtual bool write(const bool data); 00319 00320 /** 00321 * write a long 00322 * 00323 * \warning Be aware of the locale you are using. The number must be 00324 * read with the same locale used when it was written 00325 */ 00326 virtual bool write(const long& data); 00327 00328 /** 00329 * write an unsigned long 00330 * 00331 * \warning Be aware of the locale you are using. The number must be 00332 * read with the same locale used when it was written 00333 */ 00334 virtual bool write(const unsigned long& data); 00335 00336 /** 00337 * write a short 00338 * 00339 * \warning Be aware of the locale you are using. The number must be 00340 * read with the same locale used when it was written 00341 */ 00342 virtual bool write(const short& data); 00343 00344 /** 00345 * write an unsigned short 00346 * 00347 * \warning Be aware of the locale you are using. The number must be 00348 * read with the same locale used when it was written 00349 */ 00350 virtual bool write(const unsigned short& data); 00351 //@} 00352 00353 /** @name read members 00354 */ 00355 //@{ 00356 /** 00357 * read a std::string 00358 * 00359 * The string should be quoted (i.e. between '"' and '"'), expect 00360 * if its a single word. The two-char sequences '\"' and '\\' will 00361 * be replaced by '"' and '\' respectivelly. 00362 */ 00363 virtual bool read(std::string& data); 00364 00365 /** 00366 * read a double value 00367 * 00368 * \warning Be aware of the locale you are using. The number must be 00369 * read with the same locale used when it was written 00370 */ 00371 virtual bool read(double& data); 00372 00373 /** 00374 * read a float value 00375 * 00376 * \warning Be aware of the locale you are using. The number must be 00377 * read with the same locale used when it was written 00378 */ 00379 virtual bool read(float& data); 00380 00381 /** 00382 * read an integer value 00383 * 00384 * \warning Be aware of the locale you are using. The number must be 00385 * read with the same locale used when it was written 00386 */ 00387 virtual bool read(int& data); 00388 00389 /** 00390 * read an unsigned int value 00391 * 00392 * \warning Be aware of the locale you are using. The number must be 00393 * read with the same locale used when it was written 00394 */ 00395 virtual bool read(unsigned int& data); 00396 00397 /** 00398 * Read a char value. 00399 * 00400 * The char can be given in two ways: 00401 * - a numerical representation in decimal code (e.g. 65 represents 'A'). 00402 * - a character representation enclosed in sigle quotes (e.g. 'A') 00403 * 00404 * \warning Be aware of the locale you are using. The number must be 00405 * read with the same locale used when it was written 00406 */ 00407 virtual bool read(char& data); 00408 00409 /** 00410 * read a signed byte value 00411 * 00412 * \warning Be aware of the locale you are using. The number must be 00413 * read with the same locale used when it was written 00414 */ 00415 virtual bool read(byte& data); 00416 00417 00418 /** 00419 * read an unsigned byte value 00420 * 00421 * \warning Be aware of the locale you are using. The number must be 00422 * read with the same locale used when it was written 00423 */ 00424 virtual bool read(ubyte& data); 00425 00426 /** 00427 * read a boolan 00428 */ 00429 virtual bool read(bool& data); 00430 00431 /** 00432 * read a long 00433 * 00434 * \warning Be aware of the locale you are using. The number must be 00435 * read with the same locale used when it was written 00436 */ 00437 virtual bool read(long& data); 00438 00439 /** 00440 * read an unsigned long 00441 * 00442 * \warning Be aware of the locale you are using. The number must be 00443 * read with the same locale used when it was written 00444 */ 00445 virtual bool read(unsigned long& data); 00446 00447 /** 00448 * read a short 00449 * 00450 * \warning Be aware of the locale you are using. The number must be 00451 * read with the same locale used when it was written 00452 */ 00453 virtual bool read(short& data); 00454 00455 /** 00456 * read an unsigned short 00457 * 00458 * \warning Be aware of the locale you are using. The number must be 00459 * read with the same locale used when it was written 00460 */ 00461 virtual bool read(unsigned short& data); 00462 //@} 00463 00464 /** 00465 * write a std::string 00466 */ 00467 virtual bool writeSymbol(const std::string& data); 00468 00469 /** 00470 * read a symbol in the given std::string 00471 */ 00472 virtual bool readSymbol(std::string& data); 00473 00474 /** 00475 * try to read the given symbol from the handler. 00476 * If present, returns true and the token is removed from the 00477 * handler, if not present returns false and leaves the stream as 00478 * is... 00479 * @param data the symbol to be readed 00480 */ 00481 virtual bool trySymbol(const std::string& data); 00482 00483 /** 00484 * write comment writes the input data without any preprocessing, 00485 * just ensuring that the comment format is given 00486 */ 00487 virtual bool writeComment(const std::string& data); 00488 00489 /** 00490 * write comment writes the input data without any preprocessing, 00491 * just ensuring that the comment format is given 00492 */ 00493 virtual bool writeComment(const char* data); 00494 00495 /** 00496 * try to read the begin token from the handler. 00497 * If present, returns true and the token is removed from the 00498 * handler, if not present returns false and leaves the handle as 00499 * it was before calling this member... 00500 * This is useful in trees or other complicated data structures. 00501 */ 00502 virtual bool tryBegin(); 00503 00504 /** 00505 * try to read the end token from the handler. 00506 * If present, returns true and the token is removed from the 00507 * handler, if not present returns false and leaves the handle as 00508 * it was before calling this member... 00509 * This is usually used when reading lists of data, where the number of 00510 * elements is unknown. 00511 */ 00512 virtual bool tryEnd(); 00513 00514 /** 00515 * write spaces (default value 1). 00516 * A space-token is a char with value 32. 00517 */ 00518 virtual bool writeSpaces(const int s=1); 00519 00520 /** 00521 * write end of line 00522 */ 00523 virtual bool writeEOL(); 00524 00525 /** 00526 * write key/value separator. 00527 * In this case the key/value separator is a space 00528 */ 00529 virtual bool writeKeyValueSeparator(); 00530 00531 /** 00532 * write key/value separator. 00533 * In this case the data separator is a space 00534 */ 00535 virtual bool writeDataSeparator(); 00536 00537 /** 00538 * write key/value separator 00539 * A space is expected 00540 */ 00541 virtual bool readKeyValueSeparator(); 00542 00543 /** 00544 * write key/value separator 00545 * A space is expected 00546 */ 00547 virtual bool readDataSeparator(); 00548 00549 /** 00550 * if the input stream is at the end of file return true, otherwise false 00551 * if the stream hasn't been set yet, this function also returns true. 00552 */ 00553 virtual bool eof(); 00554 00555 /** 00556 * restore all the information in the handler taken in the actual 00557 * level. If "complete" is true, the begin-token is also restored 00558 */ 00559 virtual bool restoreLevel(); 00560 00561 /** 00562 * Overload of context status information. 00563 * 00564 * This function should help the users to find errors in their files. 00565 * It just inserts some contextual information into the status string 00566 * to help localizing wrong data. 00567 * 00568 * It is useful for streams that can be edited by hand, because the 00569 * users will make errors! 00570 */ 00571 virtual void appendContextStatus() const; 00572 00573 00574 protected: 00575 00576 /** 00577 * pointer to the input stream 00578 */ 00579 std::istream* inStream; 00580 00581 /** 00582 * the input stream will be cached into this string 00583 */ 00584 std::string inString; 00585 00586 /** 00587 * actual reading position in the input string 00588 */ 00589 std::string::size_type inStringPos; 00590 00591 /** 00592 * pointer to the output stream 00593 */ 00594 std::ostream* outStream; 00595 00596 /** 00597 * flag to control spaces supression (for example, there is no need for 00598 * spaces between parenthesis) 00599 */ 00600 bool supressSpaces; 00601 00602 /** 00603 * flag to indicate if an EOL is needed 00604 */ 00605 bool tryEOL; 00606 00607 /** 00608 * opening char. Usually "(" 00609 */ 00610 static const char openChar; 00611 00612 /** 00613 * closing char. Usually ")" 00614 */ 00615 static const char closeChar; 00616 00617 /** 00618 * separator char. Usually a space 00619 */ 00620 static const char separator; 00621 00622 /** 00623 * comment char. Usually ';' 00624 */ 00625 static const char commentChar; 00626 00627 /** 00628 * string char. Usually '"' 00629 */ 00630 static const char stringChar; 00631 00632 /** 00633 * quote char. Usually "'" 00634 */ 00635 static const char quoteChar; 00636 00637 /** 00638 * type for the cache of each level, where the value for each symbol 00639 * is stored 00640 */ 00641 typedef std::map<std::string,std::string> cacheType; 00642 00643 /** 00644 * type for each element of the stack 00645 */ 00646 struct stackElement { 00647 /** 00648 * default constructor 00649 */ 00650 stackElement(); 00651 /** 00652 * contains the symbol/value table 00653 */ 00654 cacheType cache; 00655 00656 /** 00657 * specify if the input stream contains no more data for this 00658 * level 00659 */ 00660 bool complete; 00661 00662 /** 00663 * level for the cache 00664 */ 00665 int level; 00666 }; 00667 00668 /** 00669 * the data stack. 00670 * All readed symbols and their values are stored here temporarly 00671 * to allow different sorting of the symbols in the stream 00672 */ 00673 std::list<stackElement> stack; 00674 00675 /** 00676 * Types of tokens 00677 */ 00678 enum eTokenId { 00679 BeginToken, /**< Denotes begin of a level */ 00680 EndToken, /**< Denotes end of a level */ 00681 SymbolToken,/**< Some atomic token */ 00682 StringToken,/**< A string token */ 00683 ErrorToken /**< Unrecognized token */ 00684 }; 00685 00686 /** 00687 * read next token from the input string or from the input stream 00688 * @see getNextTokenFromString. 00689 */ 00690 eTokenId getNextToken(std::string& token,const bool justTry = false); 00691 00692 /** 00693 * read next token from the given string 00694 * this member get the next token into the given string 00695 * 00696 * Following tokens are recognized: 00697 * 00698 * beginToken := '(' 00699 * 00700 * endToken := ')' 00701 * 00702 * symbolToken := {alpha | digit} | float 00703 * 00704 * stringToken := quote {alpha | digit | other | escape quote} quote 00705 * 00706 * ErrorToken 00707 * 00708 * where 00709 * 00710 * alpha = "A" | "B" | ... "Z" | "a" | "b" | ... "z" 00711 * 00712 * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | 00713 * 00714 * other = "!" | "," | "$" | "%" | "&" | "/" | "[" | "]" | "{" | "}" | 00715 * "?" | "'" | "#" | "+" | "*" | "-" | "." | "," | ":" | ";" 00716 * 00717 * quote = '"' 00718 * 00719 * escape = '\' 00720 * 00721 * float = ['+' | '-'] {digit} '.' {digit} [exponent] 00722 * 00723 * exponent = eid ['+' | '-'] digit {digit} 00724 * 00725 * eid = 'E' | 'e' 00726 * 00727 * comments will be ignored! They begin with a ';' 00728 * The ErrorToken is not a real token. This is the way to signalized that 00729 * no other token could be readed! 00730 * If justTry = true the source string will remain untouched 00731 */ 00732 eTokenId getNextTokenFromString(std::string& src, 00733 std::string::size_type& srcPos, 00734 std::string& token, 00735 const bool justTry = false); 00736 00737 00738 /** 00739 * get the next "garbageThreshold" characters from the given 00740 * stream, and ensures that the last readed character is a delimiter 00741 */ 00742 void getNextLine(std::string& newline); 00743 00744 /** 00745 * this filter eliminates all comments at the beginning of inString 00746 */ 00747 bool commentFilter(); 00748 00749 /** 00750 * returns true if the given char can indicate the end of a token 00751 */ 00752 inline bool isTokenDelimiter(const char& c); 00753 00754 /** 00755 * complete actual level reads the data from the input string and 00756 * input stream until the actual level has been readed. 00757 */ 00758 bool completeLevel(std::string& restOfLevel); 00759 00760 private: 00761 /** 00762 * look-up-table to accellerate the check for a delimiter 00763 */ 00764 static const bool* delimiters; 00765 00766 /** 00767 * initialize LUT for delimiters 00768 */ 00769 static void initializeDelimiters(); 00770 00771 /** 00772 * the size of the garbage size allowed before the data is really deleted! 00773 */ 00774 static const int garbageThreshold; 00775 00776 /** 00777 * a buffer of the garbageThreshold size used to read lines 00778 */ 00779 char* buffer; 00780 }; 00781 } 00782 00783 #endif 00784 00785