CVR-Lib last update 20 Sep 2009

cvrLispStreamHandler.h

Go to the documentation of this file.
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 

Generated on Sun Sep 20 22:07:59 2009 for CVR-Lib by Doxygen 1.5.8