nstream.h

Go to the documentation of this file.
00001 /*
00002  * nstream.h
00003  *
00004  * Copyright (c) 2009 Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Simple library for abstracting read-only hierarchies of named streams.
00032  */
00033 
00034 #ifndef WAVEPACKET_NSTREAM_H__
00035 #define WAVEPACKET_NSTREAM_H__
00036 
00037 
00038 // includes --------------------------------------------------------------------
00039 #include "common/common.h"
00040 
00041 #include <istream>
00042 
00043 #include "geometry/geometry_3d.h"
00044 #include "threadsafe/smart_ptr.h"
00045 
00046 
00047 namespace nstream {
00048 
00049 ////////////////////////////////////////////////////////////////////////////////
00050 ///
00051 /// \ingroup general
00052 /// \defgroup nstream Named Stream Management
00053 ///
00054 /// Simple library to abstract read-only hierarchies of named streams.
00055 ///
00056 /// By "hierarchy of named streams", this refers to any set of resources that
00057 /// have folder/file semantics, but may not be filesystems.  Concrete examples
00058 /// may be:
00059 ///  - a local filesystem.  The "name" of each stream is its path, relative to
00060 ///     some specific root directory.  The hierarchy is the directory structure.
00061 ///  - a remote filesystem, accessed via URL.  The "name" of each stream is its
00062 ///     URL relative to the server (or a high-level directory of the server). 
00063 ///     The hierarchy is the URL naming scheme (which often maps to a
00064 ///     local filesystem on the server, but doesn't have to).
00065 ///  - a local archive.  For instance, a large tar file or a
00066 ///     proprietary compressed archiving format.  Some object that understands
00067 ///     how to parse the
00068 ///     compressed archive format will be able to provide named streams, and
00069 ///     let clients navigate the archive directory hierarchy.
00070 ///  - and so on (remote compressed archives?  a local process?  etc.)
00071 ///
00072 /// <b>Why should code use this library?</b>  This is handy if you have code
00073 /// that needs to know about multiple streams with relative paths, but should
00074 /// be abstracted from the physical details of where the streams are.  One
00075 /// example I've hit lately is a library that parses and displays 3D models.
00076 /// You'll want that code to be able to access streams to read the data and
00077 /// display, but you wouldn't want to limit that library to only work on a
00078 /// local filesystem.
00079 ///
00080 /// <b>Why read-only?  Why can't you use this library to create and write
00081 /// new files?</b>  Allowing modifications starts getting complex.  For
00082 /// instance, creating and writing new files to a remote webserver may
00083 /// require special protocols depending on the server.  And writeable access
00084 /// to a compressed archive may not be possible at all (it could require that
00085 /// the archive be completely rebuilt).  In the future write concepts may
00086 /// be included, but for now all use cases are read-only.
00087 ///
00088 /// <b>How do you use this library?</b>  First, get or create a Manager
00089 /// object.  From there, you can either look up Entry objects by name, or
00090 /// you can start iterating over folders to discover Entry objects, starting
00091 /// with getRoot().
00092 ///
00093 ////////////////////////////////////////////////////////////////////////////////
00094 /*@{*/
00095 
00096 // forward declarations
00097 class Manager;
00098 class File;
00099 
00100 
00101 /// an instance of a read-only stream
00102 class Stream {
00103 public:
00104         // virtual destructor --------------------------------------------------
00105         virtual ~Stream(void) throw();
00106 
00107         // nstream::Stream class interface methods ----------------------------
00108 
00109         /// get access to the raw data stream
00110         virtual std::istream& getStream(void) = 0;
00111 
00112         /// get a pointer to the nstream::File object with which this Stream
00113         ///     is associated.
00114         virtual smart_ptr<File> getFile(void) = 0;
00115 
00116         /// helper method to get diagnostic information during errors etc
00117         virtual void writeDiagnostics(IO std::ostream& out);
00118 
00119         // syntactic sugar to make these more like std::istreams ---------------
00120         operator std::istream& (void) { return this->getStream(); }
00121         bool eof(void) { return this->getStream().eof(); }
00122         bool good(void) { return this->getStream().good(); }
00123         bool bad(void) { return this->getStream().bad(); }
00124 };
00125 
00126 
00127 
00128 /// a generic entry in the namespace.  This is either a Folder or File
00129 class Entry {
00130 public:
00131         // public enums --------------------------------------------------------
00132         enum eType {
00133                 eType_Folder            = 1,    ///< this is a Folder object
00134                 eType_File              = 2,    ///< this is a File object
00135 
00136                 // keep this last!
00137                 eType_Invalid           = 0
00138         };
00139 
00140         // virtual destructor --------------------------------------------------
00141         virtual ~Entry(void) throw();
00142 
00143         // nstream::Entry class interface methods -----------------------------
00144 
00145         /// what type of entry is this?
00146         virtual eType getType(void) const throw() = 0;
00147 
00148         /// this Entry's name in the namespace (that is, relative to the root of
00149         ///   the namespace).
00150         virtual const char * getName(void) const throw() =  0;
00151 
00152         /// the Manager of this namespace
00153         virtual smart_ptr<Manager> getManager(void) = 0;
00154 };
00155 
00156 
00157 
00158 /// an atom in the namespace: a File is a named object from which you can
00159 ///     request read-only streams.
00160 class File : public Entry {
00161 public:
00162         // virtual destructor --------------------------------------------------
00163         virtual ~File(void) throw();
00164 
00165         // nstream::File class interface methods ------------------------------
00166 
00167         /// creates a new instance of a read-only stream for this File's data
00168         virtual smart_ptr<Stream> openStream(void) = 0;
00169 };
00170 
00171 
00172 
00173 /// a folder in the namespace: contains other stream::Entry objects.
00174 /// <b>The iteration model for Folders is very primitive.</b>  That is
00175 /// intentional.  If you want multiple iterators for a given Folder at the
00176 /// same time, create multiple Folder objects.  Remember that you may be
00177 /// creating expensive iterators underneath (open directory handles, database
00178 /// cursors, etc.) so in general keeping multiple iterators open at the same
00179 /// time is discouraged anyway.
00180 ///
00181 /// Notes to users and implementers:
00182 ///  - Keep in mind that Folders may contain many thousands of child Entry
00183 ///     objects--or more.
00184 ///  - The iteration should visit every sub-Entry once and only once, but
00185 ///     there is no guarantee about ordering.  In particular, callers should
00186 ///     assume that child objects are NOT in lexigraphic order.
00187 ///  - A new Folder object should have its iterator already reset and ready
00188 ///     for calls to getNextChild().  That is, it is not required to call
00189 ///     resetIteration() for the first iteration loop.  resetIteration() is
00190 ///     a convenience method in case people want to iterate multiple times.
00191 ///  - There are sometimes odd semantics about iteration.  For instance,
00192 ///     native filesystem directory listings often contain "." (self) and
00193 ///     ".." (parent).  The semantics of nstream::Folder iteration are clear:
00194 ///     any and all child Entry objects should be returned.  But non-child
00195 ///     Entries will not.  And so, for instance, "." and ".." would not be
00196 ///     returned when iterating over a filesystem-based Folder.
00197 class Folder : public Entry {
00198 public:
00199         // virtual destructor --------------------------------------------------
00200         virtual ~Folder(void) throw();
00201 
00202         // nstream::Folder class interface methods ----------------------------
00203 
00204         /// get a child entry directly by its name relative to the parent
00205         ///     (returns NULL if no such child exists)
00206         virtual smart_ptr<Entry> getChildByName(IN const char * name) = 0;
00207 
00208         /// reset the Folder iteration to point to the first Entry again.
00209         virtual void resetIteration(void) = 0;
00210 
00211         /// get the next child Entry object.  Returns null when done.
00212         virtual smart_ptr<Entry> getNextChild(void) = 0;
00213 };
00214 
00215 
00216 
00217 /// the object that manages a particular space of named streams
00218 class Manager {
00219 public:
00220         // virtual destructor --------------------------------------------------
00221         virtual ~Manager(void) throw();
00222 
00223         // nstream::Manager class interface methods ---------------------------
00224 
00225         /// get the entry with the given name.  Returns NULL if there is no
00226         ///     entry with that name.
00227         virtual smart_ptr<Entry> getEntry(IN const char * name) = 0;
00228 
00229         /// get the root Folder object for this namespace
00230         virtual smart_ptr<Folder> getRoot(void) = 0;
00231 
00232         /// get the full name (absolute path, URL, ...) for this name
00233         virtual std::string getFullName(IN const char * name) = 0;
00234 };
00235 
00236 
00237 
00238 
00239 ////////////////////////////////////////////////////////////////////////////////
00240 //
00241 //      public API
00242 //
00243 ////////////////////////////////////////////////////////////////////////////////
00244 
00245 /// \ingroup nstream
00246 /// \defgroup nstream_fs Named Streams: Filesystem
00247 /// This is a reference implemenation of the nstream interface, for a local
00248 /// filesystem.
00249 /*@{*/
00250 
00251 /// A reference nstream::Manager implementation: this API provides a namespace
00252 ///   object based on the local filesystem.
00253 /// The caller must provide the local path which forms the root of this
00254 ///   namespace.
00255 smart_ptr<Manager> getFilesystemManager(IN const char * root_dir);
00256 
00257 /*@}*/  // end of nstream_fs
00258 
00259 
00260 
00261 /// Helper method: given a Stream object, and a path relative to that stream
00262 ///     path, return a stream for that.  Returns null if no such stream exists,
00263 ///     although this function does a lot so throwing is also possible in some
00264 ///     cases.
00265 smart_ptr<Stream> getStreamRelativeTo(IN Stream * startStream,
00266                                 IN const char * relativePath);
00267 
00268 
00269 
00270 /// Helper method: open a Stream for a given path on the specified Manager.
00271 ///     Throws on any error (no entry at that path, entry is not a file, etc.)
00272 ///     so the caller is guaranteed a non-NULL return value.
00273 smart_ptr<Stream> openNamedStream(IN Manager * mgr,
00274                                 IN const char * name);
00275 
00276 
00277 
00278 /// Helper method: given a Stream, return its name
00279 std::string getStreamName(IN Stream * stream);
00280 
00281 
00282 /// used by nstream::walkChildFolders() callback
00283 enum eIterationFlag {
00284         eIterate_Continue       = 1,    ///< keep iterating through entries
00285         eIterate_Stop           = 2,    ///< stop iterating
00286 
00287         // must be last!
00288         eIterate_Invalid        = 0
00289 };
00290 
00291 
00292 /// callback for nstream::walkChildFolders()
00293 typedef eIterationFlag (*visit_entry_fn)(IN Entry * entry, IN void * context);
00294 
00295 
00296 /// helper methods: given a Folder, walk all child Folders and Entries
00297 ///     recursively.  The callback (visit_entry_fn) is called per Entry.
00298 ///     If extensions is non-null then only Entries with a name with an
00299 ///     extension in the set will be visited.  If filter is non-null then
00300 ///     only Entries with the filter string somewhere in its path will
00301 ///     be visited.  Returns the final iteration flag (in other words,
00302 ///     will return eIterate_Stop if iteration halted early).
00303 eIterationFlag walkChildFolders(IN Folder * root,
00304                         IN visit_entry_fn callback,
00305                         IN void * context,
00306                         IN const SetString * extensions = NULL,
00307                         IN const char * filter = NULL,
00308                         IN bool visitHidden = false);
00309 
00310 
00311 };      // nstream namespace
00312 
00313 /*@}*/  // end of documentation block
00314 
00315 #endif  // WAVEPACKET_NSTREAM_H__
00316