1 /*
2     Copyright (c) 2008-2009 NetAllied Systems GmbH
3 
4     This file is part of COLLADAStreamWriter.
5 
6     Licensed under the MIT Open Source License,
7     for details please see LICENSE file or the website
8     http://www.opensource.org/licenses/mit-license.php
9 */
10 
11 #include "COLLADABUStableHeaders.h"
12 #include "COLLADABUUtils.h"
13 #include "COLLADABUPlatform.h"
14 
15 #include <string.h>
16 #include <list>
17 #ifdef _WIN32
18 #include <Windows.h>
19 #endif
20 
21 namespace COLLADABU
22 {
23 
24     const String Utils::FILE_PROTOCOL = "file:///";
25     const String Utils::FILE_DELIMITER = "/";
26     const char Utils::FILE_DELIMITER_CHAR = '/';
27 
28 	const String Utils::EMPTY_STRING = String();
29 
30     // defines
31 #define MAX_FILENAME_LEN 512
32 
33     // The number of characters at the start of an absolute filename.  e.g. in DOS,
34     // absolute filenames start with "X:\" so this value should be 3, in UNIX they start
35     // with "\" so this value should be 1. A slash must set to '\\' for DOS or '/' for UNIX.
36 
37 #if defined(COLLADABU_OS_WIN)
38     #define ABSOLUTE_NAME_START 3
39     #define SLASH '\\'
40 #elif defined(COLLADABU_OS_MAC)
41     #define ABSOLUTE_NAME_START 1 // TODO Ist das so?
42     #define SLASH '/' // TODO Ist das so?
43 #else
44     #define ABSOLUTE_NAME_START 1
45     #define SLASH '/'
46 #endif
47 
48 
49 
50     //---------------------------------
checkNCName(const String & ncName)51     String Utils::checkNCName ( const String &ncName )
52     {
53         String result;
54         result.reserve ( ncName.length() );
55 
56         // check if first character is an alpha character
57         char firstCharacter = ncName[0];
58 
59         if ( isAsciiAlphaChar ( firstCharacter )  )
60             result.append ( 1, firstCharacter );
61         else
62             result.append ( 1, '_' );
63 
64         //replace all spaces and colons by underlines
65         for ( size_t i = 1; i<ncName.length(); ++i )
66         {
67             char character = ncName[i];
68 
69             if ( isIDChar ( character ) )
70                 result.append ( 1, character );
71             else
72                 result.append ( 1, '_' );
73         }
74 
75         return result;
76     }
77 
78     //---------------------------------
checkID(const String & id)79     String Utils::checkID ( const String &id )
80     {
81         return checkNCName ( id );
82     }
83 
84     //---------------------------------
translateToXML(const String & srcString)85     String Utils::translateToXML ( const String &srcString )
86     {
87         String returnString = "";
88 
89         for ( unsigned int i=0; i<srcString.length(); ++i )
90         {
91             switch ( srcString[i])
92             {
93 //             case '\r':
94 //                 returnString += "&#13";
95 //                 break;
96             case '<':
97                 returnString += "&lt;";
98                 break;
99             case '>':
100                 returnString += "&gt;";
101                 break;
102             case '&':
103                 returnString += "&amp;";
104                 break;
105             case '"':
106                 returnString += "&quot;";
107                 break;
108             case '\'':
109                 returnString += "&apos;";
110                 break;
111             default :
112                 returnString += srcString[i];
113             }
114         }
115 
116         return returnString;
117     }
118 
119 
120 
121     //---------------------------------
replaceDot(const String & text)122     String Utils::replaceDot ( const String &text )
123     {
124         std::stringstream stream;
125 
126         for ( size_t i = 0; i < text.length(); ++i )
127         {
128             if ( text[i] == '.' )
129                 stream << '_';
130             else
131                 stream << text[i];
132         }
133 
134         return stream.str();
135     }
136 
137     //---------------------------------
stringFindAndReplace(String & source,const String searchString,const String replaceString)138     void Utils::stringFindAndReplace ( String &source, const String searchString, const String replaceString )
139     {
140         size_t found = source.find ( searchString );
141         if ( found != String::npos )
142         {
143             size_t searchStrLength = searchString.length();
144             size_t replaceStrLength = replaceString.length();
145             do
146             {
147                 source.replace ( found, searchStrLength, replaceString );
148                 found = source.find (searchString, found + replaceStrLength );
149             } while ( found != String::npos );
150         }
151 
152     }
153 
154     //---------------------------------
equals(const String & str1,const String & str2)155     bool Utils::equals ( const String &str1, const String &str2 )
156     {
157         return ( strcmp ( str1.c_str(), str2.c_str() ) == 0 );
158     }
159 
160     //--------------------------------
equalsIgnoreCase(const String & s1,const String & s2)161     bool Utils::equalsIgnoreCase ( const String& s1, const String& s2 )
162     {
163         String::const_iterator it1=s1.begin();
164         String::const_iterator it2=s2.begin();
165 
166         // has the end of at least one of the strings been reached?
167         while ( (it1!=s1.end()) && (it2!=s2.end()) )
168         {
169             if(::toupper(*it1) != ::toupper(*it2)) //letters differ?
170                 // return -1 to indicate 'smaller than', 1 otherwise
171                 return false;
172             // proceed to the next character in each string
173             ++it1;
174             ++it2;
175         }
176         size_t size1=s1.size(), size2=s2.size();// cache lengths
177         //return -1,0 or 1 according to strings' lengths
178         if (size1==size2)
179             return true;
180         return false;
181     }
182 
183     //--------------------------------
getSystemType()184 	Utils::SystemType Utils::getSystemType()
185 	{
186 #ifdef COLLADABU_OS_WIN
187 		return WINDOWS;
188 #else
189 		return POSIX;
190 #endif
191 	}
192 
193     //--------------------------------
split(const String & text,const String & separators,std::vector<String> & words)194     void Utils::split ( const String& text, const String& separators, std::vector<String>& words )
195     {
196         size_t n = text.length();
197         size_t start, stop;
198 
199         start = text.find_first_not_of(separators);
200         while (start < n)
201         {
202             stop = text.find_first_of(separators, start);
203             if (stop > n) stop = n;
204             words.push_back(text.substr(start, stop - start));
205             start = text.find_first_not_of(separators, stop+1);
206         }
207     }
208 
209 #ifdef COLLADABU_OS_WIN
210 	//--------------------------------
createDirectoryIfNeeded(const WideString & pathString)211 	bool Utils::createDirectoryIfNeeded( const WideString &pathString )
212 	{
213 		bool pathExists = false;
214 
215 
216 		SystemType type = getSystemType();
217 		if( type != WINDOWS )
218 			return false;
219 
220 		const wchar_t* currentPath = _wgetcwd( 0, 0);
221 		const wchar_t* testPath = pathString.c_str();
222 
223 		pathExists = _wchdir( testPath ) == 0;
224 		if( !pathExists )
225 		{
226 			_wmkdir( testPath );
227 			pathExists = _wchdir( testPath ) == 0;
228 		}
229 
230 		_wchdir( currentPath );
231 		return pathExists;
232 
233 	}
234 #endif
235 
236 	//--------------------------------
createDirectoryIfNeeded(const String & pathString)237 	bool Utils::createDirectoryIfNeeded( const String &pathString )
238 	{
239 		bool pathExists = false;
240 
241 #ifdef COLLADABU_OS_WIN
242 		SystemType type = getSystemType();
243 		if( type != WINDOWS )
244 			return false;
245 
246 		const char* currentPath = _getcwd( 0, 0);
247 		const char* testPath = pathString.c_str();
248 
249 		pathExists = _chdir( testPath ) == 0;
250 		if( !pathExists )
251 		{
252 			_mkdir( testPath );
253 			pathExists = _chdir( testPath ) == 0;
254 		}
255 
256 		_chdir( currentPath );
257 
258 #else
259 		SystemType type = getSystemType();
260 		if( type != POSIX )
261 			return false;
262 
263 		const char* currentPath = getcwd( 0, 0);
264 		const char* testPath = pathString.c_str();
265         pathExists = chdir( testPath ) == 0;
266 		if( !pathExists )
267 		{
268             pathExists = mkdir(testPath, 0755) == false;
269         }
270         chdir( currentPath );
271 #endif
272 		return pathExists;
273 	}
274 
275 #ifdef COLLADABU_OS_WIN
276 	//--------------------------------
createDirectoryRecursive(const WideString & pathString)277 	bool Utils::createDirectoryRecursive( const WideString &pathString )
278 	{
279 		if (pathString.length() == 0)
280 			return false;
281 
282 		WideString path = pathString;
283 
284 		if (path[path.length()-1] != '/' && path[path.length()-1] != '\\')
285 			path.push_back('\\');
286 
287 		std::list<WideString> paths;
288 		size_t offset = WideString::npos;
289 		while ((offset != 0) && (offset = pathString.find_last_of(L"/\\", offset)) != WideString::npos)
290 		{
291 			paths.push_front(pathString.substr(0, offset + 1));
292 			if (offset != 0) --offset;
293 		}
294 
295 		bool pathExists = true;
296 		const wchar_t* currentPath = _wgetcwd(0, 0);
297 
298 		for (std::list<WideString>::const_iterator iPath = paths.begin(); iPath != paths.end(); ++iPath)
299 		{
300 			// if path exists
301 			if (_wchdir((*iPath).c_str()) == 0) {
302 				_wchdir(currentPath);
303 				continue;
304 			}
305 
306 			// path does not exist, try to create it
307 			_wmkdir((*iPath).c_str());
308 
309 			if (_wchdir((*iPath).c_str()) != 0)
310 			{
311 				pathExists = false;
312 				break;
313 			}
314 		}
315 
316 		// Restore current path
317 		_wchdir(currentPath);
318 		return pathExists;
319 	}
320 #endif
321 
322 	//--------------------------------
createDirectoryRecursive(const String & pathString)323 	bool Utils::createDirectoryRecursive( const String &pathString )
324 	{
325 		if (pathString.length() == 0)
326 			return false;
327 
328 		String path = pathString;
329 
330 		if (path[path.length()-1] != '/' && path[path.length()-1] != '\\')
331 			path.push_back('\\');
332 
333 		std::list<String> paths;
334 		size_t offset = String::npos;
335 		while ((offset != 0) && (offset = pathString.find_last_of("/\\", offset)) != String::npos)
336 		{
337 			paths.push_front(pathString.substr(0, offset + 1));
338 			if (offset !=0) --offset;
339 		}
340 
341 		bool pathExists = true;
342 
343 		SystemType type = getSystemType();
344 
345 #ifdef COLLADABU_OS_WIN
346 		if( type != WINDOWS )
347 			return false;
348 
349 		const char* currentPath = _getcwd(0, 0);
350 
351 		for (std::list<String>::const_iterator iPath = paths.begin(); iPath != paths.end(); ++iPath)
352 		{
353 			// if path exists
354 			if (_chdir((*iPath).c_str()) == 0) {
355 				_chdir(currentPath);
356 				continue;
357 			}
358 
359 			// path does not exist, try to create it
360 			_mkdir((*iPath).c_str());
361 
362 			if (_chdir((*iPath).c_str()) != 0)
363 			{
364 				pathExists = false;
365 				break;
366 			}
367 		}
368 
369 		// Restore current path
370 		_chdir(currentPath);
371 #else
372 		if( type != POSIX )
373 			return false;
374 
375 		const char* currentPath = getcwd(0, 0);
376 
377 		for (std::list<String>::const_iterator iPath = paths.begin(); iPath != paths.end(); ++iPath)
378 		{
379 			// if path exists
380 			if (chdir((*iPath).c_str()) == 0)
381 				continue;
382 
383 			// path does not exist, try to create it
384 			mkdir((*iPath).c_str(), 0755);
385 
386 			if (chdir((*iPath).c_str()) != 0)
387 			{
388 				pathExists = false;
389 				break;
390 			}
391 		}
392 
393 		// Restore current path
394 		chdir(currentPath);
395 #endif
396 		return pathExists;
397 	}
398 
399 #ifdef COLLADABU_OS_WIN
400 	//--------------------------------
directoryExists(const WideString & pathString)401 	bool Utils::directoryExists( const WideString &pathString )
402 	{
403 		bool pathExists = false;
404 
405 
406 		SystemType type = getSystemType();
407 		if( type != WINDOWS )
408 			return false;
409 
410 		const wchar_t* currentPath = _wgetcwd( 0, 0);
411 		const wchar_t* testPath = pathString.c_str();
412 
413 		pathExists = _wchdir( testPath ) == 0;
414 		_wchdir( currentPath );
415 		return pathExists;
416 
417 	}
418 #endif
419 
420 	//--------------------------------
directoryExists(const String & pathString)421 	bool Utils::directoryExists( const String &pathString )
422 	{
423 		bool pathExists = false;
424 
425 #ifdef COLLADABU_OS_WIN
426 		SystemType type = getSystemType();
427 		if( type != WINDOWS )
428 			return false;
429 
430 		const char* currentPath = _getcwd( 0, 0);
431 		const char* testPath = pathString.c_str();
432 
433 		pathExists = _chdir( testPath ) == 0;
434 		_chdir( currentPath );
435 		return pathExists;
436 #else
437 		SystemType type = getSystemType();
438 		if( type != POSIX )
439 			return false;
440 
441         struct stat st;
442         if(stat(pathString.c_str(),&st) == 0)
443             pathExists = true;
444 
445 #endif
446 
447 		return pathExists;
448 	}
449 
450 	//--------------------------------
copyFile(const String & source,const String & destination)451 	bool Utils::copyFile( const String &source, const String &destination )
452 	{
453 		bool copystatus = false;
454 
455 #ifdef COLLADABU_OS_WIN
456 		SystemType type = getSystemType();
457 		if( type != WINDOWS )
458 			return false;
459 
460 		char command[4097];
461 		sprintf(command,"copy \"%s\" \"%s\"", source.c_str(), destination.c_str() );
462 		size_t length = strlen(command);
463 		if( length > 4096)
464 			return false;
465 
466 		int status = system(command);
467         copystatus = (status == 0 ? true : false);
468 #else
469 		SystemType type = getSystemType();
470 		if( type != POSIX )
471 			return false;
472 
473         char command[4097];
474         sprintf(command, "/bin/cp \"%s\" \"%s\"", source.c_str(), destination.c_str());
475         size_t length = strlen(command);
476         if( length > 4096)
477             return false;
478 
479 
480         int status = system(command);
481         copystatus = (status == 0 ? true : false);
482 #endif
483 
484 		return copystatus;
485 	}
486 
487     //--------------------------------
deleteFile(const String & pathString)488     bool Utils::deleteFile(const String &pathString)
489     {
490         SystemType type = getSystemType();
491 
492 #ifdef COLLADABU_OS_WIN
493         if (type != WINDOWS)
494             return false;
495         return DeleteFileA(pathString.c_str()) != FALSE;
496 #else
497         if (type != POSIX)
498             return false;
499         char command[4097];
500         sprintf(command, "rm -f \"%s\"", pathString.c_str());
501         int status = system(command);
502         return status == 0;
503 #endif
504     }
505 
506 	//--------------------------------
fileExistsAndIsReadable(const String & pathString)507 	bool Utils::fileExistsAndIsReadable( const String &pathString )
508 	{
509 		FILE* f = fopen( pathString.c_str(), "r");
510 		bool readable = (f != 0);
511 		if( readable )
512 			fclose(f);
513 		return readable;
514 	}
515 }
516