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