nstream.cpp

Go to the documentation of this file.
00001 /*
00002  * nstream.cpp
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  * Basic nstream object implementations.  see nstream.h
00032  */
00033 
00034 // includes --------------------------------------------------------------------
00035 #include "nstream.h"            // always include our own header first
00036 
00037 #include "common/wave_ex.h"
00038 #include "perf/perf.h"
00039 #include "util/file.h"          // pathname manipulations
00040 
00041 
00042 
00043 namespace nstream {
00044 
00045 // interface destructors
00046 Stream::~Stream(void) throw() { }
00047 Entry::~Entry(void) throw() { }
00048 File::~File(void) throw() { }
00049 Folder::~Folder(void) throw() { }
00050 Manager::~Manager(void) throw() { }
00051 
00052 
00053 
00054 ////////////////////////////////////////////////////////////////////////////////
00055 //
00056 //      static helper methods
00057 //
00058 ////////////////////////////////////////////////////////////////////////////////
00059 
00060 static eIterationFlag
00061 maybeVisit
00062 (
00063 IN Entry * entry,
00064 IN visit_entry_fn callback,
00065 IN void * context,
00066 IN const SetString * extensions,
00067 IN const char * filter,
00068 IN bool visitHidden
00069 )
00070 {
00071         ASSERT(entry, "null");
00072         ASSERT(callback, "null");
00073         // ASSERT(context) -- we don't care
00074         // ASSERT(extensions) -- can be null
00075         // ASSERT(filter) -- can be null
00076 
00077         const char * name = entry->getName();
00078         ASSERT(name, "null");
00079 
00080         // do we need to check extension?
00081         if (extensions) {
00082                 const char * ext = GetExtension(name);
00083                 if (!ext ||
00084                     extensions->end() == extensions->find(ext)) {
00085                         // no extension, or doesn't match
00086                         // don't visit, but keep iterating
00087                         return eIterate_Continue;
00088                 }
00089         }
00090 
00091         // do we need to check path?
00092         if (filter) {
00093                 if (!strstr(name, filter)) {
00094                         // path (name) does not contain filter as substring
00095                         // don't visit, but keep iterating
00096                         return eIterate_Continue;
00097                 }
00098         }
00099 
00100         // okay, visit
00101         return callback(entry, context);
00102 }
00103 
00104 
00105 
00106 ////////////////////////////////////////////////////////////////////////////////
00107 //
00108 //      Public APIs
00109 //
00110 ////////////////////////////////////////////////////////////////////////////////
00111 
00112 void
00113 Stream::writeDiagnostics
00114 (
00115 IO std::ostream& out
00116 )
00117 {
00118         // this is helpful for debugging
00119         // we do NOT write the full stream!
00120         // just some diagnostic information
00121 
00122         smart_ptr<File> file = this->getFile();
00123         if (file) {
00124                 const char * filename = file->getName();
00125                 out << "read-only stream from file: '" << filename << "'";
00126         } else {
00127                 out << "(stream from unknown file)";
00128         }
00129 }
00130 
00131 
00132 
00133 smart_ptr<Stream>
00134 getStreamRelativeTo
00135 (
00136 IN Stream * startStream,
00137 IN const char * relativePath
00138 )
00139 {
00140         perf::Timer timer("getStreamRelativeTo");
00141         ASSERT(startStream, "null");
00142         ASSERT(relativePath, "null");
00143 
00144 //      DPRINTF("In getStreamRelativeTo()...");
00145 //      DPRINTF("  relative path: %s", relativePath);
00146 
00147         smart_ptr<File> file = startStream->getFile();
00148         THROW(file, "failed to get File for Stream");
00149 
00150         const char * name = file->getName();
00151         ASSERT(name, "File contains null name");
00152 
00153         std::string relName = getPathRelativeTo(name, relativePath);
00154 //      DPRINTF("  relative path as resolved: %s", relName.c_str());
00155 
00156         smart_ptr<Manager> mgr = file->getManager();
00157         THROW(mgr, "File returned null manager");
00158 
00159         smart_ptr<File> newFile = mgr->getEntry(relName.c_str());
00160         if (!newFile) {
00161                 DPRINTF("No such entry, or not a file: %s", relName.c_str());
00162                 return NULL;
00163         }
00164 
00165         // open a stream!
00166         return newFile->openStream();
00167 }
00168 
00169 
00170 
00171 smart_ptr<Stream>
00172 openNamedStream
00173 (
00174 IN Manager * mgr,
00175 IN const char * name
00176 )
00177 {
00178         ASSERT(mgr, "null");
00179         ASSERT(name, "null");
00180 
00181         smart_ptr<File> file = mgr->getEntry(name);
00182         THROW(file,
00183             "Could not get File at path (does not exist, or is folder): "
00184             << name);
00185 
00186         smart_ptr<Stream> stream = file->openStream();
00187         THROW(stream, "Failed to open stream for File: " << name);
00188 
00189         return stream;
00190 }
00191 
00192 
00193 
00194 std::string
00195 getStreamName
00196 (
00197 IN Stream * stream
00198 )
00199 {
00200         ASSERT(stream, "null");
00201 
00202         smart_ptr<File> file = stream->getFile();
00203         THROW(file, "failed to retrieve File for Stream");
00204 
00205         return file->getName();
00206 }
00207 
00208 
00209 
00210 eIterationFlag
00211 walkChildFolders
00212 (
00213 IN Folder * root,
00214 IN visit_entry_fn callback,
00215 IN void * context,
00216 IN const SetString * extensions,
00217 IN const char * filter,
00218 IN bool visitHidden
00219 )
00220 {
00221         ASSERT(root, "null");
00222         ASSERT(callback, "null");
00223         // ASSERT(context) -- can be null
00224         // ASSERT(extensions) -- can be null
00225         // ASSERT(filter) -- can be null
00226 
00227         root->resetIteration();         // just to be safe
00228         while (smart_ptr<Entry> entry = root->getNextChild()) {
00229                 const char * name = entry->getName();
00230                 ASSERT(name, "null");
00231                 name = GetFilename(name);
00232 
00233 //              DPRINTF("name='%s', visitHidden='%s'", name,
00234 //                  (visitHidden) ? "true" : "false");
00235 
00236                 // does this begin with a dot?  (note: safe check for UTF-8)
00237                 if ('.' == name[0] && !visitHidden) {
00238 //                      DPRINTF("Skipping entry: '%s'", name);
00239                         // yes, begins with a dot and we're supposed to skip
00240                         continue;
00241                 }
00242 
00243                 // visit first (if matches criteria)
00244                 if (eIterate_Stop ==
00245                     maybeVisit(entry, callback, context, extensions, filter,
00246                                 visitHidden)) {
00247                         return eIterate_Stop;
00248                 }
00249 
00250                 // is this is a folder object?  recurse
00251                 Folder * child = dynamic_cast<Folder *>((Entry *) entry);
00252                 if (!child)
00253                         continue;       // not a folder, go to next child
00254                 if (eIterate_Stop == walkChildFolders(child, callback,
00255                                               context, extensions, filter,
00256                                               visitHidden))
00257                         return eIterate_Stop;
00258         }
00259 
00260         return eIterate_Continue;
00261 }
00262 
00263 
00264 
00265 };      // nstream namespace
00266