restream.cpp

Go to the documentation of this file.
00001 /*
00002  * restream.cpp
00003  *
00004  * Copyright (c) 2009,2011 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  * Resource-based named streams.  See resources.h and nstream.h
00032  */
00033 
00034 // includes --------------------------------------------------------------------
00035 #include "restream.h"           // always include our own header first
00036 
00037 #include "common/wave_ex.h"
00038 #include "wave-crypto/wave-crypto.h"
00039 #include "perf/perf.h"
00040 #include "resources/resources.h"
00041 #include "util/file.h"
00042 
00043 
00044 namespace nstream {
00045 
00046 
00047 ////////////////////////////////////////////////////////////////////////////////
00048 //
00049 //      static helper methods
00050 //
00051 ////////////////////////////////////////////////////////////////////////////////
00052 
00053 // declaration only
00054 static smart_ptr<Entry> getEntryForName(IN const char * name);
00055 
00056 
00057 
00058 ////////////////////////////////////////////////////////////////////////////////
00059 //
00060 //      ResStream -- class that implements the nstream::Stream interface for a
00061 //              local filesystem.
00062 //
00063 ////////////////////////////////////////////////////////////////////////////////
00064 
00065 class ResStream : public Stream {
00066 public:
00067         // constructor, destructor ---------------------------------------------
00068         ~ResStream(void) throw() { }
00069 
00070         // nstream::Stream class interface methods ----------------------------
00071         std::istream& getStream(void) { return m_stream; }
00072         smart_ptr<File> getFile(void);
00073 
00074         // static factory methods ----------------------------------------------
00075         static smart_ptr<Stream> create(IN const char * nameSpace,
00076                                 IN const char * name);
00077 
00078 private:
00079         // private helper methods ----------------------------------------------
00080         ResStream(void) throw() { }
00081 
00082         // private member data -------------------------------------------------
00083         std::istringstream      m_stream;       // raw stringstream
00084         std::string             m_name;
00085         std::string             m_nameSpace;
00086 };
00087 
00088 
00089 
00090 smart_ptr<File>
00091 ResStream::getFile
00092 (
00093 void
00094 )
00095 {
00096         std::string fullPath = m_nameSpace;
00097         fullPath += "/";
00098         fullPath += m_name;
00099 
00100         // we create entry and rely on auto-upcast
00101         return getEntryForName(fullPath.c_str());
00102 }
00103 
00104 
00105 
00106 smart_ptr<Stream>
00107 ResStream::create
00108 (
00109 IN const char * nameSpace,
00110 IN const char * name
00111 )
00112 {
00113         ASSERT(nameSpace, "null");
00114         ASSERT(name, "null");
00115 
00116         //DPRINTF("Creating stream for namespace='%s', name='%s'",
00117         //    nameSpace, name);
00118 
00119         smart_ptr<ResStream> local = new ResStream;
00120         ASSERT(local, "out of memory");
00121 
00122         local->m_nameSpace = nameSpace;
00123         local->m_name = name;
00124 
00125         int bytes = getResourceSize(nameSpace, name);
00126         ASSERT_THROW(bytes > 0,
00127             "No such resource: namespace='" << nameSpace << "', name='" <<
00128             name);
00129 
00130         const byte_t * value = getResourceData(nameSpace, name);
00131         ASSERT_THROW(value > 0,
00132             "No such resource: namespace='" << nameSpace << "', name='" <<
00133             name);
00134 
00135         // string which is the source of our string
00136         std::string source;
00137         source.assign((const char *) value, bytes);
00138 
00139         // reset stream
00140         local->m_stream.str(source);
00141         ASSERT_THROW(local->m_stream.good(),
00142             "Failed to open resouce for reading: namespace='" << nameSpace <<
00143             "', name='" << name << "'");
00144 
00145         // all good
00146         return local;
00147 }
00148 
00149 
00150 
00151 ////////////////////////////////////////////////////////////////////////////////
00152 //
00153 //      ResFile -- class that implements the nstream::File interface for a
00154 //              local filesystem.
00155 //
00156 ////////////////////////////////////////////////////////////////////////////////
00157 
00158 class ResFile : public File {
00159 public:
00160         // constructor, destructor ---------------------------------------------
00161         ~ResFile(void) throw() { }
00162 
00163         // nstream::Entry class interface methods -----------------------------
00164         eType getType(void) const throw() { return eType_File; }
00165         const char * getName(void) const throw() { return m_name.c_str(); }
00166         smart_ptr<Manager> getManager(void) {
00167                         return getResourceStreamManager();
00168                 }
00169 
00170         // nstream::File class interface methods ------------------------------
00171         smart_ptr<Stream> openStream(void);
00172 
00173         // static factory methods ----------------------------------------------
00174         static smart_ptr<File> create(IN const char * nameSpace,
00175                                 IN const char * name);
00176 
00177 private:
00178         // private helper methods ----------------------------------------------
00179         ResFile(void) throw() { }
00180 
00181         // private member data -------------------------------------------------
00182         std::string             m_name;
00183         std::string             m_nameSpace;
00184 };
00185 
00186 
00187 
00188 smart_ptr<Stream>
00189 ResFile::openStream
00190 (
00191 void
00192 )
00193 {
00194         return ResStream::create(m_nameSpace.c_str(), m_name.c_str());
00195 }
00196 
00197 
00198 
00199 smart_ptr<File>
00200 ResFile::create
00201 (
00202 IN const char * nameSpace,
00203 IN const char * name
00204 )
00205 {
00206         ASSERT(nameSpace, "null");
00207         ASSERT(name, "null");
00208 
00209         smart_ptr<ResFile> local = new ResFile;
00210         ASSERT(local, "out of memory");
00211 
00212         local->m_nameSpace = nameSpace;
00213         local->m_name = name;
00214 
00215         return local;
00216 }
00217 
00218 
00219 
00220 ////////////////////////////////////////////////////////////////////////////////
00221 //
00222 //      ResFolder -- class that implements the nstream::Folder interface for a
00223 //              local filesystem.
00224 //
00225 //      NOTE: this is built with an iterative model.  This is to handle the
00226 //      (extreme) cases where a filesystem contains thousands of entries per
00227 //      directory.
00228 //
00229 ////////////////////////////////////////////////////////////////////////////////
00230 
00231 class ResFolder : public Folder {
00232 public:
00233         // constructor, destructor ---------------------------------------------
00234         ~ResFolder(void) throw();
00235 
00236         // nstream::Entry class interface methods -----------------------------
00237         eType getType(void) const throw() { return eType_Folder; }
00238         const char * getName(void) const throw() { return m_name.c_str(); }
00239         smart_ptr<Manager> getManager(void) {
00240                         return getResourceStreamManager();
00241                 }
00242 
00243         // nstream::Folder class interface methods ----------------------------
00244         smart_ptr<Entry> getChildByName(IN const char * name);
00245         void resetIteration(void);
00246         smart_ptr<Entry> getNextChild(void);
00247 
00248         // static factory methods ----------------------------------------------
00249         static smart_ptr<Folder> create(IN const char * name);
00250 
00251 private:
00252         // private helper methods ----------------------------------------------
00253         ResFolder(void) throw();
00254 
00255         // private member data -------------------------------------------------
00256         std::string     m_name;
00257         int             m_index;
00258 };
00259 
00260 
00261 
00262 ResFolder::ResFolder(void)
00263 throw()
00264 {
00265         m_index = 0;
00266 }
00267 
00268 
00269 
00270 ResFolder::~ResFolder(void)
00271 throw()
00272 {
00273 }
00274 
00275 
00276 
00277 smart_ptr<Entry>
00278 ResFolder::getChildByName
00279 (
00280 IN const char * name
00281 )
00282 {
00283         ASSERT(name, "null");
00284 
00285         if ("" == m_name) {
00286                 return ResFolder::create(name);
00287         } else {
00288                 return ResFile::create(m_name.c_str(), name);
00289         }
00290 }
00291 
00292 
00293 
00294 void
00295 ResFolder::resetIteration
00296 (
00297 void
00298 )
00299 {
00300         m_index = 0;
00301 }
00302 
00303 
00304 
00305 smart_ptr<Entry>
00306 ResFolder::getNextChild
00307 (
00308 void
00309 )
00310 {
00311         if ("" == m_name) {
00312                 // we are the root, so iterate namespaces instead of resources
00313                 int nMax = getResourceNamespaceCount();
00314                 if (m_index >= nMax) {
00315                         // we are at max!
00316                         return NULL;
00317                 }
00318 
00319                 // use this namespace
00320                 return ResFolder::create(getResourceNamespaceName(m_index++));
00321         }
00322 
00323         // we are a namespace, so iterate resources in this namespace
00324         const char * name = getResourceName(m_name.c_str(), m_index);
00325         if (!name) {
00326                 return NULL;    // our index is (no longer) valid
00327         }
00328 
00329         // increment index
00330         ++m_index;
00331 
00332         // return this child
00333         return this->getChildByName(name);
00334 }
00335 
00336 
00337 
00338 smart_ptr<Folder>
00339 ResFolder::create
00340 (
00341 IN const char * name
00342 )
00343 {
00344         ASSERT(name, "null");
00345 
00346         //DPRINTF("Creating folder for name: '%s'", name);
00347 
00348         smart_ptr<ResFolder> local = new ResFolder();
00349         ASSERT(local, "out of memory");
00350 
00351         local->m_name = name;
00352 
00353         return local;
00354 }
00355 
00356 
00357 
00358 ////////////////////////////////////////////////////////////////////////////////
00359 //
00360 //      ResMgr -- class that implements the nstream::Manager interface for
00361 //              built-in resources (see the resources library)
00362 //
00363 ////////////////////////////////////////////////////////////////////////////////
00364 
00365 class ResMgr : public Manager {
00366 public:
00367         // constructor, destructor ---------------------------------------------
00368         ~ResMgr(void) throw() { }
00369 
00370         // public class methods ------------------------------------------------
00371         void initialize(void);
00372 
00373         // nstream::Manager class interface methods ---------------------------
00374         smart_ptr<Entry> getEntry(IN const char * name);
00375         smart_ptr<Folder> getRoot(void);
00376         std::string getFullName(IN const char * name);
00377 
00378 private:
00379         // private member data -------------------------------------------------
00380 };
00381 
00382 
00383 
00384 void
00385 ResMgr::initialize
00386 (
00387 void
00388 )
00389 {
00390 }
00391 
00392 
00393 
00394 smart_ptr<Entry>
00395 ResMgr::getEntry
00396 (
00397 IN const char * name
00398 )
00399 {
00400         ASSERT(name, "null");
00401 
00402         return getEntryForName(name);
00403 }
00404 
00405 
00406 
00407 smart_ptr<Folder>
00408 ResMgr::getRoot
00409 (
00410 void
00411 )
00412 {
00413         return ResFolder::create("");
00414 }
00415 
00416 
00417 
00418 std::string
00419 ResMgr::getFullName
00420 (
00421 IN const char * name
00422 )
00423 {
00424         ASSERT(name, "null");
00425         return name;
00426 }
00427 
00428 
00429 
00430 ////////////////////////////////////////////////////////////////////////////////
00431 //
00432 //      static methods needed by the above
00433 //
00434 ////////////////////////////////////////////////////////////////////////////////
00435 
00436 static smart_ptr<Entry>
00437 getEntryForName
00438 (
00439 IN const char * name
00440 )
00441 {
00442         ASSERT(name, "null");
00443 
00444         DPRINTF("Creating entry for name: %s", name);
00445 
00446         // parse name: skip any leading slashes
00447         while (*name && '/' == *name) {
00448                 ++name;
00449         }
00450 
00451         // is this a folder (namespace) or a resource?
00452         std::string parentDir;
00453         GetParentDirectory(name, parentDir);
00454         const char * resname = GetFilename(name);
00455 
00456         if ("" == parentDir || !*resname) {
00457                 DPRINTF("  ...namespace!");
00458 
00459                 const char * nameSpace = NULL;
00460                 if (!*resname) {
00461                         // this was a name with a trailing slash
00462                         nameSpace = parentDir.c_str();
00463                 } else {
00464                         // this was a bare name
00465                         nameSpace = resname;
00466                 }
00467 
00468                 // create folder for namespace (or empty for root)
00469                 return ResFolder::create(nameSpace);
00470         }
00471 
00472         // this is a namespace + resource name
00473         DPRINTF("   ...namespace + resource name");
00474         DPRINTF("   namespace: '%s'", parentDir.c_str());
00475         DPRINTF("   resource:  '%s'", resname);
00476 
00477         // assume file
00478         return ResFile::create(parentDir.c_str(), resname);
00479 }
00480 
00481 
00482 
00483 ////////////////////////////////////////////////////////////////////////////////
00484 //
00485 //      Public APIs
00486 //
00487 ////////////////////////////////////////////////////////////////////////////////
00488 
00489 smart_ptr<Manager>
00490 getResourceStreamManager
00491 (
00492 void
00493 )
00494 {
00495         smart_ptr<ResMgr> local = new ResMgr;
00496         local->initialize();
00497         return local;
00498 }
00499 
00500 
00501 
00502 };      // nstream namespace
00503