LTI-Lib latest version v1.9 - last update 10 Apr 2010

ltiLispStreamHandler.h

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

Generated on Sat Apr 10 15:25:45 2010 for LTI-Lib by Doxygen 1.6.1