vrshoot
view libs/assimp/DefaultLogger.cpp @ 1:e7ca128b8713
looks nice :)
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 02 Feb 2014 00:35:22 +0200 |
parents | |
children |
line source
1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
6 Copyright (c) 2006-2012, assimp team
8 All rights reserved.
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the following
12 conditions are met:
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
18 * Redistributions in binary form must reproduce the above
19 copyright notice, this list of conditions and the
20 following disclaimer in the documentation and/or other
21 materials provided with the distribution.
23 * Neither the name of the assimp team, nor the names of its
24 contributors may be used to endorse or promote products
25 derived from this software without specific prior
26 written permission of the assimp team.
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 ---------------------------------------------------------------------------
40 */
42 /** @file DefaultLogger.cpp
43 * @brief Implementation of DefaultLogger (and Logger)
44 */
46 #include "AssimpPCH.h"
47 #include "DefaultIOSystem.h"
49 // Default log streams
50 #include "Win32DebugLogStream.h"
51 #include "StdOStreamLogStream.h"
52 #include "FileLogStream.h"
54 #ifndef ASSIMP_BUILD_SINGLETHREADED
55 # include <boost/thread/thread.hpp>
56 # include <boost/thread/mutex.hpp>
58 boost::mutex loggerMutex;
59 #endif
61 namespace Assimp {
63 // ----------------------------------------------------------------------------------
64 NullLogger DefaultLogger::s_pNullLogger;
65 Logger *DefaultLogger::m_pLogger = &DefaultLogger::s_pNullLogger;
67 static const unsigned int SeverityAll = Logger::Info | Logger::Err | Logger::Warn | Logger::Debugging;
69 // ----------------------------------------------------------------------------------
70 // Represents a log-stream + its error severity
71 struct LogStreamInfo
72 {
73 unsigned int m_uiErrorSeverity;
74 LogStream *m_pStream;
76 // Constructor
77 LogStreamInfo( unsigned int uiErrorSev, LogStream *pStream ) :
78 m_uiErrorSeverity( uiErrorSev ),
79 m_pStream( pStream )
80 {
81 // empty
82 }
84 // Destructor
85 ~LogStreamInfo()
86 {
87 delete m_pStream;
88 }
89 };
91 // ----------------------------------------------------------------------------------
92 // Construct a default log stream
93 LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams,
94 const char* name /*= "AssimpLog.txt"*/,
95 IOSystem* io /*= NULL*/)
96 {
97 switch (streams)
98 {
99 // This is a platform-specific feature
100 case aiDefaultLogStream_DEBUGGER:
101 #ifdef WIN32
102 return new Win32DebugLogStream();
103 #else
104 return NULL;
105 #endif
107 // Platform-independent default streams
108 case aiDefaultLogStream_STDERR:
109 return new StdOStreamLogStream(std::cerr);
110 case aiDefaultLogStream_STDOUT:
111 return new StdOStreamLogStream(std::cout);
112 case aiDefaultLogStream_FILE:
113 return (name && *name ? new FileLogStream(name,io) : NULL);
114 default:
115 // We don't know this default log stream, so raise an assertion
116 ai_assert(false);
118 };
120 // For compilers without dead code path detection
121 return NULL;
122 }
124 // ----------------------------------------------------------------------------------
125 // Creates the only singleton instance
126 Logger *DefaultLogger::create(const char* name /*= "AssimpLog.txt"*/,
127 LogSeverity severity /*= NORMAL*/,
128 unsigned int defStreams /*= aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_FILE*/,
129 IOSystem* io /*= NULL*/)
130 {
131 // enter the mutex here to avoid concurrency problems
132 #ifndef ASSIMP_BUILD_SINGLETHREADED
133 boost::mutex::scoped_lock lock(loggerMutex);
134 #endif
136 if (m_pLogger && !isNullLogger() )
137 delete m_pLogger;
139 m_pLogger = new DefaultLogger( severity );
141 // Attach default log streams
142 // Stream the log to the MSVC debugger?
143 if (defStreams & aiDefaultLogStream_DEBUGGER)
144 m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_DEBUGGER));
146 // Stream the log to COUT?
147 if (defStreams & aiDefaultLogStream_STDOUT)
148 m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_STDOUT));
150 // Stream the log to CERR?
151 if (defStreams & aiDefaultLogStream_STDERR)
152 m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_STDERR));
154 // Stream the log to a file
155 if (defStreams & aiDefaultLogStream_FILE && name && *name)
156 m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_FILE,name,io));
158 return m_pLogger;
159 }
161 // ----------------------------------------------------------------------------------
162 void Logger::debug(const char* message) {
164 // SECURITY FIX: otherwise it's easy to produce overruns since
165 // sometimes importers will include data from the input file
166 // (i.e. node names) in their messages.
167 if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
168 ai_assert(false);
169 return;
170 }
171 return OnDebug(message);
172 }
174 // ----------------------------------------------------------------------------------
175 void Logger::info(const char* message) {
177 // SECURITY FIX: see above
178 if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
179 ai_assert(false);
180 return;
181 }
182 return OnInfo(message);
183 }
185 // ----------------------------------------------------------------------------------
186 void Logger::warn(const char* message) {
188 // SECURITY FIX: see above
189 if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
190 ai_assert(false);
191 return;
192 }
193 return OnWarn(message);
194 }
196 // ----------------------------------------------------------------------------------
197 void Logger::error(const char* message) {
199 // SECURITY FIX: see above
200 if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
201 ai_assert(false);
202 return;
203 }
204 return OnError(message);
205 }
207 // ----------------------------------------------------------------------------------
208 void DefaultLogger::set( Logger *logger )
209 {
210 // enter the mutex here to avoid concurrency problems
211 #ifndef ASSIMP_BUILD_SINGLETHREADED
212 boost::mutex::scoped_lock lock(loggerMutex);
213 #endif
215 if (!logger)logger = &s_pNullLogger;
216 if (m_pLogger && !isNullLogger() )
217 delete m_pLogger;
219 DefaultLogger::m_pLogger = logger;
220 }
222 // ----------------------------------------------------------------------------------
223 bool DefaultLogger::isNullLogger()
224 {
225 return m_pLogger == &s_pNullLogger;
226 }
228 // ----------------------------------------------------------------------------------
229 // Singleton getter
230 Logger *DefaultLogger::get()
231 {
232 return m_pLogger;
233 }
235 // ----------------------------------------------------------------------------------
236 // Kills the only instance
237 void DefaultLogger::kill()
238 {
239 // enter the mutex here to avoid concurrency problems
240 #ifndef ASSIMP_BUILD_SINGLETHREADED
241 boost::mutex::scoped_lock lock(loggerMutex);
242 #endif
244 if (m_pLogger == &s_pNullLogger)return;
245 delete m_pLogger;
246 m_pLogger = &s_pNullLogger;
247 }
249 // ----------------------------------------------------------------------------------
250 // Debug message
251 void DefaultLogger::OnDebug( const char* message )
252 {
253 if ( m_Severity == Logger::NORMAL )
254 return;
256 char msg[MAX_LOG_MESSAGE_LENGTH*2];
257 ::sprintf(msg,"Debug, T%i: %s", GetThreadID(), message );
259 WriteToStreams( msg, Logger::Debugging );
260 }
262 // ----------------------------------------------------------------------------------
263 // Logs an info
264 void DefaultLogger::OnInfo( const char* message )
265 {
266 char msg[MAX_LOG_MESSAGE_LENGTH*2];
267 ::sprintf(msg,"Info, T%i: %s", GetThreadID(), message );
269 WriteToStreams( msg , Logger::Info );
270 }
272 // ----------------------------------------------------------------------------------
273 // Logs a warning
274 void DefaultLogger::OnWarn( const char* message )
275 {
276 char msg[MAX_LOG_MESSAGE_LENGTH*2];
277 ::sprintf(msg,"Warn, T%i: %s", GetThreadID(), message );
279 WriteToStreams( msg, Logger::Warn );
280 }
282 // ----------------------------------------------------------------------------------
283 // Logs an error
284 void DefaultLogger::OnError( const char* message )
285 {
286 char msg[MAX_LOG_MESSAGE_LENGTH*2];
287 ::sprintf(msg,"Error, T%i: %s", GetThreadID(), message );
289 WriteToStreams( msg, Logger::Err );
290 }
292 // ----------------------------------------------------------------------------------
293 // Will attach a new stream
294 bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity )
295 {
296 if (!pStream)
297 return false;
299 if (0 == severity) {
300 severity = Logger::Info | Logger::Err | Logger::Warn | Logger::Debugging;
301 }
303 for ( StreamIt it = m_StreamArray.begin();
304 it != m_StreamArray.end();
305 ++it )
306 {
307 if ( (*it)->m_pStream == pStream )
308 {
309 (*it)->m_uiErrorSeverity |= severity;
310 return true;
311 }
312 }
314 LogStreamInfo *pInfo = new LogStreamInfo( severity, pStream );
315 m_StreamArray.push_back( pInfo );
316 return true;
317 }
319 // ----------------------------------------------------------------------------------
320 // Detatch a stream
321 bool DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity )
322 {
323 if (!pStream)
324 return false;
326 if (0 == severity) {
327 severity = SeverityAll;
328 }
330 for ( StreamIt it = m_StreamArray.begin();
331 it != m_StreamArray.end();
332 ++it )
333 {
334 if ( (*it)->m_pStream == pStream )
335 {
336 (*it)->m_uiErrorSeverity &= ~severity;
337 if ( (*it)->m_uiErrorSeverity == 0 )
338 {
339 // don't delete the underlying stream 'cause the caller gains ownership again
340 (**it).m_pStream = NULL;
341 delete *it;
342 m_StreamArray.erase( it );
343 break;
344 }
345 return true;
346 }
347 }
348 return false;
349 }
351 // ----------------------------------------------------------------------------------
352 // Constructor
353 DefaultLogger::DefaultLogger(LogSeverity severity)
355 : Logger ( severity )
356 , noRepeatMsg (false)
357 , lastLen( 0 )
358 {
359 lastMsg[0] = '\0';
360 }
362 // ----------------------------------------------------------------------------------
363 // Destructor
364 DefaultLogger::~DefaultLogger()
365 {
366 for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) {
367 // also frees the underlying stream, we are its owner.
368 delete *it;
369 }
370 }
372 // ----------------------------------------------------------------------------------
373 // Writes message to stream
374 void DefaultLogger::WriteToStreams(const char *message,
375 ErrorSeverity ErrorSev )
376 {
377 ai_assert(NULL != message);
379 // Check whether this is a repeated message
380 if (! ::strncmp( message,lastMsg, lastLen-1))
381 {
382 if (!noRepeatMsg)
383 {
384 noRepeatMsg = true;
385 message = "Skipping one or more lines with the same contents\n";
386 }
387 else return;
388 }
389 else
390 {
391 // append a new-line character to the message to be printed
392 lastLen = ::strlen(message);
393 ::memcpy(lastMsg,message,lastLen+1);
394 ::strcat(lastMsg+lastLen,"\n");
396 message = lastMsg;
397 noRepeatMsg = false;
398 ++lastLen;
399 }
400 for ( ConstStreamIt it = m_StreamArray.begin();
401 it != m_StreamArray.end();
402 ++it)
403 {
404 if ( ErrorSev & (*it)->m_uiErrorSeverity )
405 (*it)->m_pStream->write( message);
406 }
407 }
409 // ----------------------------------------------------------------------------------
410 // Returns thread id, if not supported only a zero will be returned.
411 unsigned int DefaultLogger::GetThreadID()
412 {
413 // fixme: we can get this value via boost::threads
414 #ifdef WIN32
415 return (unsigned int)::GetCurrentThreadId();
416 #else
417 return 0; // not supported
418 #endif
419 }
421 // ----------------------------------------------------------------------------------
423 } // !namespace Assimp