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