root/OpenSceneGraph/trunk/src/osgDB/ExternalFileWriter.cpp @ 13041

Revision 13041, 10.4 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#include <osgDB/ExternalFileWriter>
15#include <osgDB/FileNameUtils>
16#include <osgDB/FileUtils>
17#include <osgDB/WriteFile>
18#include <stdexcept>
19
20namespace osgDB
21{
22
23/// Counts the number of directories the given relative path goes "up" the current dir, or 0 if not.
24/// This returns 0 for absolute paths.
25/// Examples:
26///    - "../a" goes 1 level up
27///    - "../../a/b/c/d/e" goes 2
28///    - "../a/../b/../.." goes 2
29///    - "a/b/../c" goes 0
30static unsigned int countNbDirsUp(const std::string & path)
31{
32    // Algorithm:
33    //    - For each path component, count +1 for "..", 0 for ".", and -1 for anything else
34    //    - Ignore everything after  the last ".." of the path.
35    if (isAbsolutePath(path)) return 0;
36    int result(0), tempResult(0);
37    std::vector<std::string> pathElems;
38    getPathElements(path, pathElems);
39    for(std::vector<std::string>::const_iterator it(pathElems.begin()), itEnd(pathElems.end()); it!=itEnd; ++it)
40    {
41        if (*it == "..")
42        {
43            // Count +1, and "validates" temporary result
44            ++tempResult;
45            result = tempResult;
46        }
47        else if (*it != ".") --tempResult;
48    }
49    return result<=0 ? 0 : static_cast<unsigned int>(result);
50}
51
52
53/// Local hash function for a path.
54/// Does not canonize the given path, but is not confused with mixed separators.
55static unsigned int pathHash(const std::string & s)
56{
57    // This is based on the DJB hash algorithm
58    // Note: SDBM Hash initializes at 0 and is
59    //        hash = c + (hash << 6) + (hash << 16) - hash;
60    unsigned int hash = 5381;
61    for(std::string::const_iterator it=s.begin(), itEnd=s.end(); it!=itEnd; ++it)
62    {
63        std::string::value_type c = *it;
64        if (c == '\\') c = '/';        // We're processing a path and don't want to be affected by differences in separators
65        hash = ((hash << 5) + hash) + c;
66    }
67    return hash;
68}
69
70
71//virtual ReaderWriter::WriteResult writeObject(const osg::Object& obj, const std::string& fileName,const Options* options);
72//virtual ReaderWriter::WriteResult writeImage(const osg::Image& obj, const std::string& fileName,const Options* options);
73//virtual ReaderWriter::WriteResult writeHeightField(const osg::HeightField& obj, const std::string& fileName,const Options* options);
74//virtual ReaderWriter::WriteResult writeNode(const osg::Node& obj, const std::string& fileName,const Options* options);
75//virtual ReaderWriter::WriteResult writeShader(const osg::Shader& obj, const std::string& fileName,const Options* options);
76
77enum WriteType {
78    WRITE_TYPE_OBJECT,
79    WRITE_TYPE_IMAGE,
80    WRITE_TYPE_HEIGHT_FIELD,
81    WRITE_TYPE_NODE,
82    WRITE_TYPE_SHADER,
83
84    MAX_WRITE_TYPE
85};
86
87/// Default prefixes for unnamed objects.
88static const char * const FILE_PREFIX[/*MAX_WRITE_TYPE*/] = {
89    "Object_",
90    "Image_",
91    "HF_",
92    "Node_",
93    "Shader_"
94};
95
96/// Default prefixes for unnamed objects.
97static const char * const FILE_EXTENSION[/*MAX_WRITE_TYPE*/] = {
98    ".osgb",
99    ".tga",
100    ".osgb",
101    ".osgb",
102    ".glsl"
103};
104
105//.frag
106//.vert
107
108inline WriteType getType(const osg::Object & obj)
109{
110    // Is there something faster than a dynamic_cast<>?
111    if (dynamic_cast<const osg::Image       *>(&obj)) return WRITE_TYPE_IMAGE;
112    if (dynamic_cast<const osg::HeightField *>(&obj)) return WRITE_TYPE_HEIGHT_FIELD;
113    if (dynamic_cast<const osg::Node        *>(&obj)) return WRITE_TYPE_NODE;
114    if (dynamic_cast<const osg::Shader      *>(&obj)) return WRITE_TYPE_SHADER;
115    return WRITE_TYPE_OBJECT;
116}
117
118/// Returns the object filename if available, or its name otherwise.
119inline const std::string & getFileName(const osg::Object & obj, WriteType type)
120{
121    switch(type) {
122        case WRITE_TYPE_IMAGE:        return static_cast<const osg::Image       &>(obj).getFileName();
123        case WRITE_TYPE_SHADER:       return static_cast<const osg::Shader      &>(obj).getFileName();
124        default:        // WRITE_TYPE_OBJECT, WRITE_TYPE_NODE, WRITE_TYPE_HEIGHT_FIELD
125            return obj.getName();
126    }
127}
128
129
130inline bool doWrite(const osg::Object & obj, WriteType type, const std::string& fileName, const Options * options)
131{
132    switch(type) {
133        case WRITE_TYPE_IMAGE:        return writeImageFile      (static_cast<const osg::Image       &>(obj), fileName, options);
134        case WRITE_TYPE_HEIGHT_FIELD: return writeHeightFieldFile(static_cast<const osg::HeightField &>(obj), fileName, options);
135        case WRITE_TYPE_NODE:         return writeNodeFile       (static_cast<const osg::Node        &>(obj), fileName, options);
136        case WRITE_TYPE_SHADER:       return writeShaderFile     (static_cast<const osg::Shader      &>(obj), fileName, options);
137        // WRITE_TYPE_OBJECT
138        default:                      return writeObjectFile(obj, fileName, options);
139    }
140}
141
142
143
144// --------------------------------------------------------------------------------
145
146
147ExternalFileWriter::ExternalFileWriter(const std::string & srcDirectory, const std::string & destDirectory, bool keepRelativePaths, unsigned int allowUpDirs)
148    : _lastGeneratedObjectIndex(0), _srcDirectory(srcDirectory), _destDirectory(destDirectory), _keepRelativePaths(keepRelativePaths), _allowUpDirs(allowUpDirs)
149{}
150
151ExternalFileWriter::ExternalFileWriter(const std::string & destDirectory)
152    : _lastGeneratedObjectIndex(0), _destDirectory(destDirectory), _keepRelativePaths(false), _allowUpDirs(0)
153{}
154
155
156bool ExternalFileWriter::write(const osg::Object & obj, const Options * options, std::string * out_absolutePath, std::string * out_relativePath)
157{
158    ObjectsSet::iterator it( _objects.find(&obj) );
159    if (it != _objects.end())
160    {
161        // Object has already been passed to this method
162        if (out_absolutePath) *out_absolutePath = it->second.absolutePath;
163        if (out_relativePath) *out_relativePath = it->second.relativePath;
164        return it->second.written;
165    }
166
167    // Object is a new entry
168
169    // Get absolute source path
170    WriteType type( getType(obj) );
171    std::string originalFileName( getFileName(obj, type) );
172    std::string absoluteSourcePath;
173    if (_keepRelativePaths && !originalFileName.empty())        // if keepRelativePaths is false, absoluteSourcePath is not used, then we can skip this part
174    {
175        if (isAbsolutePath(originalFileName)) absoluteSourcePath = originalFileName;
176        else absoluteSourcePath = concatPaths(_srcDirectory, originalFileName);
177        absoluteSourcePath = getRealPath(convertFileNameToNativeStyle(absoluteSourcePath));      // getRealPath() here is only used to canonize the path, not to add current directory in front of relative paths, hence the "concatPaths(_srcDirectory, ...)" just above
178    }
179
180    // Compute destination paths from the source path
181    std::string relativeDestinationPath;
182    std::string absoluteDestinationPath;
183    if (absoluteSourcePath.empty())
184    {
185        // We have no name. Generate one.
186        generateObjectName(relativeDestinationPath, absoluteDestinationPath, type);
187    }
188    else
189    {
190        // We have a name.
191        if (_keepRelativePaths)
192        {
193            // We'll try to keep images relative path.
194            relativeDestinationPath = getPathRelative(_srcDirectory, absoluteSourcePath);
195            unsigned int nbDirsUp = countNbDirsUp(relativeDestinationPath);
196            // TODO if nbDirsUp>nb dirs in _destDirectory, then issue a warning, and use simple file name
197            if (nbDirsUp > _allowUpDirs) relativeDestinationPath = getSimpleFileName(absoluteSourcePath);
198        }
199        else
200        {
201            // We keep only the simple file name.
202            relativeDestinationPath = getSimpleFileName(absoluteSourcePath);
203        }
204        absoluteDestinationPath = getRealPath(convertFileNameToNativeStyle( concatPaths(_destDirectory, relativeDestinationPath) ));
205        // TODO Check for absolute paths collisions between multiple objects
206    }
207
208    // Write object
209    bool written(false);
210    if (!makeDirectoryForFile(absoluteDestinationPath))
211    {
212        OSG_NOTICE << "Can't create directory for file '" << absoluteDestinationPath << "'. May fail creating the image file." << std::endl;
213    }
214    if (!doWrite(obj, type, absoluteDestinationPath, options))
215    {
216        OSG_WARN << "Can't write file '" << absoluteDestinationPath << "'." << std::endl;
217    }
218    else written = true;
219
220    // Add entry
221    _objects.insert(ObjectsSet::value_type(&obj, ObjectData(absoluteDestinationPath, relativeDestinationPath, written)));
222    _searchMap.insert(SearchMap::value_type(pathHash(absoluteDestinationPath), &obj));
223
224    // Fill output strings
225    if (out_absolutePath) *out_absolutePath = absoluteDestinationPath;
226    if (out_relativePath) *out_relativePath = relativeDestinationPath;
227
228    return written;
229}
230
231
232bool ExternalFileWriter::absoluteObjectPathExists(const std::string & path)
233{
234    // For all paths in the search map having the same hash as 'path', check if paths correspond
235    std::pair<SearchMap::iterator, SearchMap::iterator> bounds( _searchMap.equal_range(pathHash(path)) );
236    for(SearchMap::iterator it=bounds.first; it!=bounds.second; ++it)
237    {
238        const osg::Object * img( it->second );
239        if (_objects[img].absolutePath == path) return true;
240    }
241    return false;
242}
243
244void ExternalFileWriter::generateObjectName(std::string & out_relativePath, std::string & out_absolutePath, int type)
245{
246    static const ObjectIndex MAX_NUMBER = UINT_MAX-1;        // -1 to allow doing +1 without an overflow
247    for (ObjectIndex number=_lastGeneratedObjectIndex+1; number<MAX_NUMBER; ++number)
248    {
249        std::ostringstream oss;
250        oss << FILE_PREFIX[type] << number << FILE_EXTENSION[type];
251        out_relativePath = oss.str();
252        out_absolutePath = concatPaths(_destDirectory, out_relativePath);
253
254        if (!absoluteObjectPathExists(out_absolutePath))
255        {
256            _lastGeneratedObjectIndex = number;
257            return;
258        }
259    }
260    throw std::runtime_error("Could not get a free index to write image.");
261}
262
263}
Note: See TracBrowser for help on using the browser.