Branimir Karadžić 9 years ago
parent
commit
a10f36da8b
5 changed files with 517 additions and 390 deletions
  1. 1 0
      include/bx/bx.h
  2. 85 331
      include/bx/crtimpl.h
  3. 4 59
      include/bx/debug.h
  4. 360 0
      src/crtimpl.cpp
  5. 67 0
      src/debug.cpp

+ 1 - 0
include/bx/bx.h

@@ -8,6 +8,7 @@
 
 
 #include <stdint.h> // uint32_t
 #include <stdint.h> // uint32_t
 #include <stdlib.h> // size_t
 #include <stdlib.h> // size_t
+#include <stddef.h> // ptrdiff_t
 #include <string.h> // memcpy
 #include <string.h> // memcpy
 
 
 #include "config.h"
 #include "config.h"

+ 85 - 331
include/bx/crtimpl.h

@@ -9,7 +9,6 @@
 #include "bx.h"
 #include "bx.h"
 
 
 #if BX_CONFIG_ALLOCATOR_CRT
 #if BX_CONFIG_ALLOCATOR_CRT
-#	include <malloc.h>
 #	include "allocator.h"
 #	include "allocator.h"
 #endif // BX_CONFIG_ALLOCATOR_CRT
 #endif // BX_CONFIG_ALLOCATOR_CRT
 
 
@@ -20,374 +19,129 @@
 namespace bx
 namespace bx
 {
 {
 #if BX_CONFIG_ALLOCATOR_CRT
 #if BX_CONFIG_ALLOCATOR_CRT
+	///
 	class CrtAllocator : public AllocatorI
 	class CrtAllocator : public AllocatorI
 	{
 	{
 	public:
 	public:
-		CrtAllocator()
-		{
-		}
-
-		virtual ~CrtAllocator()
-		{
-		}
-
-		virtual void* realloc(void* _ptr, size_t _size, size_t _align, const char* _file, uint32_t _line) BX_OVERRIDE
-		{
-			if (0 == _size)
-			{
-				if (NULL != _ptr)
-				{
-					if (BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT >= _align)
-					{
-						::free(_ptr);
-						return NULL;
-					}
-
-#	if BX_COMPILER_MSVC
-					BX_UNUSED(_file, _line);
-					_aligned_free(_ptr);
-#	else
-					bx::alignedFree(this, _ptr, _align, _file, _line);
-#	endif // BX_
-				}
-
-				return NULL;
-			}
-			else if (NULL == _ptr)
-			{
-				if (BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT >= _align)
-				{
-					return ::malloc(_size);
-				}
-
-#	if BX_COMPILER_MSVC
-				BX_UNUSED(_file, _line);
-				return _aligned_malloc(_size, _align);
-#	else
-				return bx::alignedAlloc(this, _size, _align, _file, _line);
-#	endif // BX_
-			}
-
-			if (BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT >= _align)
-			{
-				return ::realloc(_ptr, _size);
-			}
-
-#	if BX_COMPILER_MSVC
-			BX_UNUSED(_file, _line);
-			return _aligned_realloc(_ptr, _size, _align);
-#	else
-			return bx::alignedRealloc(this, _ptr, _size, _align, _file, _line);
-#	endif // BX_
-		}
+		///
+		CrtAllocator();
+
+		///
+		virtual ~CrtAllocator();
+
+		///
+		virtual void* realloc(void* _ptr, size_t _size, size_t _align, const char* _file, uint32_t _line) BX_OVERRIDE;
 	};
 	};
 #endif // BX_CONFIG_ALLOCATOR_CRT
 #endif // BX_CONFIG_ALLOCATOR_CRT
 
 
 #if BX_CONFIG_CRT_FILE_READER_WRITER
 #if BX_CONFIG_CRT_FILE_READER_WRITER
-
-#	if BX_CRT_MSVC
-#		define fseeko64 _fseeki64
-#		define ftello64 _ftelli64
-#	elif 0 \
-	  || BX_PLATFORM_ANDROID \
-	  || BX_PLATFORM_BSD \
-	  || BX_PLATFORM_IOS \
-	  || BX_PLATFORM_OSX \
-	  || BX_PLATFORM_QNX
-#		define fseeko64 fseeko
-#		define ftello64 ftello
-#	elif BX_PLATFORM_PS4
-#		define fseeko64 fseek
-#		define ftello64 ftell
-#	endif // BX_
-
+	///
 	class CrtFileReader : public FileReaderI
 	class CrtFileReader : public FileReaderI
 	{
 	{
 	public:
 	public:
-		CrtFileReader()
-			: m_file(NULL)
-		{
-		}
-
-		virtual ~CrtFileReader()
-		{
-		}
-
-		virtual bool open(const char* _filePath, Error* _err) BX_OVERRIDE
-		{
-			BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
-
-			if (NULL != m_file)
-			{
-				BX_ERROR_SET(_err, BX_ERROR_READERWRITER_ALREADY_OPEN, "CrtFileReader: File is already open.");
-				return false;
-			}
-
-			m_file = fopen(_filePath, "rb");
-			if (NULL == m_file)
-			{
-				BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "CrtFileReader: Failed to open file.");
-				return false;
-			}
-
-			return true;
-		}
-
-		virtual void close() BX_OVERRIDE
-		{
-			BX_CHECK(NULL != m_file, "Reader/Writer file is not open.");
-			fclose(m_file);
-			m_file = NULL;
-		}
-
-		virtual int64_t seek(int64_t _offset = 0, Whence::Enum _whence = Whence::Current) BX_OVERRIDE
-		{
-			BX_CHECK(NULL != m_file, "Reader/Writer file is not open.");
-			fseeko64(m_file, _offset, _whence);
-			return ftello64(m_file);
-		}
-
-		virtual int32_t read(void* _data, int32_t _size, Error* _err) BX_OVERRIDE
-		{
-			BX_CHECK(NULL != m_file, "Reader/Writer file is not open.");
-			BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
-
-			int32_t size = (int32_t)fread(_data, 1, _size, m_file);
-			if (size != _size)
-			{
-				if (0 != feof(m_file) )
-				{
-					BX_ERROR_SET(_err, BX_ERROR_READERWRITER_EOF, "CrtFileReader: EOF.");
-				}
-				else if (0 != ferror(m_file) )
-				{
-					BX_ERROR_SET(_err, BX_ERROR_READERWRITER_READ, "CrtFileReader: read error.");
-				}
-
-				return size >= 0 ? size : 0;
-			}
-
-			return size;
-		}
+		///
+		CrtFileReader();
+
+		///
+		virtual ~CrtFileReader();
+
+		///
+		virtual bool open(const char* _filePath, Error* _err) BX_OVERRIDE;
+
+		///
+		virtual void close() BX_OVERRIDE;
+
+		///
+		virtual int64_t seek(int64_t _offset = 0, Whence::Enum _whence = Whence::Current) BX_OVERRIDE;
+
+		///
+		virtual int32_t read(void* _data, int32_t _size, Error* _err) BX_OVERRIDE;
 
 
 	private:
 	private:
-		FILE* m_file;
+		void* m_file;
 	};
 	};
 
 
+	///
 	class CrtFileWriter : public FileWriterI
 	class CrtFileWriter : public FileWriterI
 	{
 	{
 	public:
 	public:
-		CrtFileWriter()
-			: m_file(NULL)
-		{
-		}
-
-		virtual ~CrtFileWriter()
-		{
-		}
-
-		virtual bool open(const char* _filePath, bool _append, Error* _err) BX_OVERRIDE
-		{
-			BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
-
-			if (NULL != m_file)
-			{
-				BX_ERROR_SET(_err, BX_ERROR_READERWRITER_ALREADY_OPEN, "CrtFileReader: File is already open.");
-				return false;
-			}
-
-			m_file = fopen(_filePath, _append ? "ab" : "wb");
-
-			if (NULL == m_file)
-			{
-				BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "CrtFileWriter: Failed to open file.");
-				return false;
-			}
-
-			return true;
-		}
-
-		virtual void close() BX_OVERRIDE
-		{
-			BX_CHECK(NULL != m_file, "Reader/Writer file is not open.");
-			fclose(m_file);
-			m_file = NULL;
-		}
-
-		virtual int64_t seek(int64_t _offset = 0, Whence::Enum _whence = Whence::Current) BX_OVERRIDE
-		{
-			BX_CHECK(NULL != m_file, "Reader/Writer file is not open.");
-			fseeko64(m_file, _offset, _whence);
-			return ftello64(m_file);
-		}
-
-		virtual int32_t write(const void* _data, int32_t _size, Error* _err) BX_OVERRIDE
-		{
-			BX_CHECK(NULL != m_file, "Reader/Writer file is not open.");
-			BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
-
-			int32_t size = (int32_t)fwrite(_data, 1, _size, m_file);
-			if (size != _size)
-			{
-				BX_ERROR_SET(_err, BX_ERROR_READERWRITER_WRITE, "CrtFileWriter: write failed.");
-				return size >= 0 ? size : 0;
-			}
-
-			return size;
-		}
+		///
+		CrtFileWriter();
+
+		///
+		virtual ~CrtFileWriter();
+
+		///
+		virtual bool open(const char* _filePath, bool _append, Error* _err) BX_OVERRIDE;
+
+		///
+		virtual void close() BX_OVERRIDE;
+
+		///
+		virtual int64_t seek(int64_t _offset = 0, Whence::Enum _whence = Whence::Current) BX_OVERRIDE;
+
+		///
+		virtual int32_t write(const void* _data, int32_t _size, Error* _err) BX_OVERRIDE;
 
 
 	private:
 	private:
-		FILE* m_file;
+		void* m_file;
 	};
 	};
 #endif // BX_CONFIG_CRT_FILE_READER_WRITER
 #endif // BX_CONFIG_CRT_FILE_READER_WRITER
 
 
 #if BX_CONFIG_CRT_PROCESS
 #if BX_CONFIG_CRT_PROCESS
-
-#if BX_CRT_MSVC
-#	define popen  _popen
-#	define pclose _pclose
-#endif // BX_CRT_MSVC
-
+	///
 	class ProcessReader : public ReaderOpenI, public CloserI, public ReaderI
 	class ProcessReader : public ReaderOpenI, public CloserI, public ReaderI
 	{
 	{
 	public:
 	public:
-		ProcessReader()
-			: m_file(NULL)
-		{
-		}
-
-		~ProcessReader()
-		{
-			BX_CHECK(NULL == m_file, "Process not closed!");
-		}
-
-		virtual bool open(const char* _command, Error* _err) BX_OVERRIDE
-		{
-			BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
-
-			if (NULL != m_file)
-			{
-				BX_ERROR_SET(_err, BX_ERROR_READERWRITER_ALREADY_OPEN, "ProcessReader: File is already open.");
-				return false;
-			}
-
-			m_file = popen(_command, "r");
-			if (NULL == m_file)
-			{
-				BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "ProcessReader: Failed to open process.");
-				return false;
-			}
-
-			return true;
-		}
-
-		virtual void close() BX_OVERRIDE
-		{
-			BX_CHECK(NULL != m_file, "Process not open!");
-			m_exitCode = pclose(m_file);
-			m_file = NULL;
-		}
-
-		virtual int32_t read(void* _data, int32_t _size, Error* _err) BX_OVERRIDE
-		{
-			BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors."); BX_UNUSED(_err);
-
-			int32_t size = (int32_t)fread(_data, 1, _size, m_file);
-			if (size != _size)
-			{
-				if (0 != feof(m_file) )
-				{
-					BX_ERROR_SET(_err, BX_ERROR_READERWRITER_EOF, "ProcessReader: EOF.");
-				}
-				else if (0 != ferror(m_file) )
-				{
-					BX_ERROR_SET(_err, BX_ERROR_READERWRITER_READ, "ProcessReader: read error.");
-				}
-
-				return size >= 0 ? size : 0;
-			}
-
-			return size;
-		}
-
-		int32_t getExitCode() const
-		{
-			return m_exitCode;
-		}
+		///
+		ProcessReader();
+
+		///
+		~ProcessReader();
+
+		///
+		virtual bool open(const char* _command, Error* _err) BX_OVERRIDE;
+
+		///
+		virtual void close() BX_OVERRIDE;
+
+		///
+		virtual int32_t read(void* _data, int32_t _size, Error* _err) BX_OVERRIDE;
+
+		///
+		int32_t getExitCode() const;
 
 
 	private:
 	private:
-		FILE* m_file;
+		void* m_file;
 		int32_t m_exitCode;
 		int32_t m_exitCode;
 	};
 	};
 
 
+	///
 	class ProcessWriter : public WriterOpenI, public CloserI, public WriterI
 	class ProcessWriter : public WriterOpenI, public CloserI, public WriterI
 	{
 	{
 	public:
 	public:
-		ProcessWriter()
-			: m_file(NULL)
-		{
-		}
-
-		~ProcessWriter()
-		{
-			BX_CHECK(NULL == m_file, "Process not closed!");
-		}
-
-		virtual bool open(const char* _command, bool, Error* _err) BX_OVERRIDE
-		{
-			BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
-
-			if (NULL != m_file)
-			{
-				BX_ERROR_SET(_err, BX_ERROR_READERWRITER_ALREADY_OPEN, "ProcessWriter: File is already open.");
-				return false;
-			}
-
-			m_file = popen(_command, "w");
-			if (NULL == m_file)
-			{
-				BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "ProcessWriter: Failed to open process.");
-				return false;
-			}
-
-			return true;
-		}
-
-		virtual void close() BX_OVERRIDE
-		{
-			BX_CHECK(NULL != m_file, "Process not open!");
-			m_exitCode = pclose(m_file);
-			m_file = NULL;
-		}
-
-		virtual int32_t write(const void* _data, int32_t _size, Error* _err) BX_OVERRIDE
-		{
-			BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors."); BX_UNUSED(_err);
-
-			int32_t size = (int32_t)fwrite(_data, 1, _size, m_file);
-			if (size != _size)
-			{
-				if (0 != ferror(m_file) )
-				{
-					BX_ERROR_SET(_err, BX_ERROR_READERWRITER_WRITE, "ProcessWriter: write error.");
-				}
-
-				return size >= 0 ? size : 0;
-			}
-
-			return size;
-		}
-
-		int32_t getExitCode() const
-		{
-			return m_exitCode;
-		}
+		///
+		ProcessWriter();
+
+		///
+		~ProcessWriter();
+
+		///
+		virtual bool open(const char* _command, bool, Error* _err) BX_OVERRIDE;
+
+		///
+		virtual void close() BX_OVERRIDE;
+
+		///
+		virtual int32_t write(const void* _data, int32_t _size, Error* _err) BX_OVERRIDE;
+
+		///
+		int32_t getExitCode() const;
 
 
 	private:
 	private:
-		FILE* m_file;
+		void* m_file;
 		int32_t m_exitCode;
 		int32_t m_exitCode;
 	};
 	};
-
 #endif // BX_CONFIG_CRT_PROCESS
 #endif // BX_CONFIG_CRT_PROCESS
 
 
 } // namespace bx
 } // namespace bx

+ 4 - 59
include/bx/debug.h

@@ -8,68 +8,13 @@
 
 
 #include "bx.h"
 #include "bx.h"
 
 
-#if BX_PLATFORM_ANDROID
-#	include <android/log.h>
-#elif BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT || BX_PLATFORM_XBOX360 || BX_PLATFORM_XBOXONE
-extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char* _str);
-#elif BX_PLATFORM_IOS || BX_PLATFORM_OSX
-#	if defined(__OBJC__)
-#		import <Foundation/NSObjCRuntime.h>
-#	else
-#		include <CoreFoundation/CFString.h>
-extern "C" void NSLog(CFStringRef _format, ...);
-#	endif // defined(__OBJC__)
-#elif 0 // BX_PLATFORM_EMSCRIPTEN
-#	include <emscripten.h>
-#else
-#	include <stdio.h>
-#endif // BX_PLATFORM_WINDOWS
-
 namespace bx
 namespace bx
 {
 {
-#if BX_COMPILER_CLANG_ANALYZER
-	inline __attribute__((analyzer_noreturn)) void debugBreak();
-#endif // BX_COMPILER_CLANG_ANALYZER
-
-	inline void debugBreak()
-	{
-#if BX_COMPILER_MSVC
-		__debugbreak();
-#elif BX_CPU_ARM
-		__builtin_trap();
-//		asm("bkpt 0");
-#elif !BX_PLATFORM_NACL && BX_CPU_X86 && (BX_COMPILER_GCC || BX_COMPILER_CLANG)
-		// NaCl doesn't like int 3:
-		// NativeClient: NaCl module load failed: Validation failure. File violates Native Client safety rules.
-		__asm__ ("int $3");
-#else // cross platform implementation
-		int* int3 = (int*)3L;
-		*int3 = 3;
-#endif // BX
-	}
+	///
+	void debugBreak();
 
 
-	inline void debugOutput(const char* _out)
-	{
-#if BX_PLATFORM_ANDROID
-#	ifndef BX_ANDROID_LOG_TAG
-#		define BX_ANDROID_LOG_TAG ""
-#	endif // BX_ANDROID_LOG_TAG
-		__android_log_write(ANDROID_LOG_DEBUG, BX_ANDROID_LOG_TAG, _out);
-#elif BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT || BX_PLATFORM_XBOX360 || BX_PLATFORM_XBOXONE
-		OutputDebugStringA(_out);
-#elif BX_PLATFORM_IOS || BX_PLATFORM_OSX
-#	if defined(__OBJC__)
-		NSLog(@"%s", _out);
-#	else
-		NSLog(__CFStringMakeConstantString("%s"), _out);
-#	endif // defined(__OBJC__)
-#elif 0 // BX_PLATFORM_EMSCRIPTEN
-		emscripten_log(EM_LOG_CONSOLE, "%s", _out);
-#else
-		fputs(_out, stdout);
-		fflush(stdout);
-#endif // BX_PLATFORM_
-	}
+	///
+	void debugOutput(const char* _out);
 
 
 } // namespace bx
 } // namespace bx
 
 

+ 360 - 0
src/crtimpl.cpp

@@ -0,0 +1,360 @@
+/*
+ * Copyright 2010-2017 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ */
+
+#include <bx/crtimpl.h>
+
+#if BX_CONFIG_ALLOCATOR_CRT
+#	include <malloc.h>
+#endif // BX_CONFIG_ALLOCATOR_CRT
+
+namespace bx
+{
+#if BX_CONFIG_ALLOCATOR_CRT
+	CrtAllocator::CrtAllocator()
+	{
+	}
+
+	CrtAllocator::~CrtAllocator()
+	{
+	}
+
+	void* CrtAllocator::realloc(void* _ptr, size_t _size, size_t _align, const char* _file, uint32_t _line)
+	{
+		if (0 == _size)
+		{
+			if (NULL != _ptr)
+			{
+				if (BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT >= _align)
+				{
+					::free(_ptr);
+					return NULL;
+				}
+
+#	if BX_COMPILER_MSVC
+				BX_UNUSED(_file, _line);
+				_aligned_free(_ptr);
+#	else
+				bx::alignedFree(this, _ptr, _align, _file, _line);
+#	endif // BX_
+			}
+
+			return NULL;
+		}
+		else if (NULL == _ptr)
+		{
+			if (BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT >= _align)
+			{
+				return ::malloc(_size);
+			}
+
+#	if BX_COMPILER_MSVC
+			BX_UNUSED(_file, _line);
+			return _aligned_malloc(_size, _align);
+#	else
+			return bx::alignedAlloc(this, _size, _align, _file, _line);
+#	endif // BX_
+		}
+
+		if (BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT >= _align)
+		{
+			return ::realloc(_ptr, _size);
+		}
+
+#	if BX_COMPILER_MSVC
+		BX_UNUSED(_file, _line);
+		return _aligned_realloc(_ptr, _size, _align);
+#	else
+		return bx::alignedRealloc(this, _ptr, _size, _align, _file, _line);
+#	endif // BX_
+	}
+#endif // BX_CONFIG_ALLOCATOR_CRT
+
+#if BX_CONFIG_CRT_FILE_READER_WRITER
+
+#	if BX_CRT_MSVC
+#		define fseeko64 _fseeki64
+#		define ftello64 _ftelli64
+#	elif 0 \
+	  || BX_PLATFORM_ANDROID \
+	  || BX_PLATFORM_BSD \
+	  || BX_PLATFORM_IOS \
+	  || BX_PLATFORM_OSX \
+	  || BX_PLATFORM_QNX
+#		define fseeko64 fseeko
+#		define ftello64 ftello
+#	elif BX_PLATFORM_PS4
+#		define fseeko64 fseek
+#		define ftello64 ftell
+#	endif // BX_
+
+	CrtFileReader::CrtFileReader()
+		: m_file(NULL)
+	{
+	}
+
+	CrtFileReader::~CrtFileReader()
+	{
+	}
+
+	bool CrtFileReader::open(const char* _filePath, Error* _err)
+	{
+		BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+
+		if (NULL != m_file)
+		{
+			BX_ERROR_SET(_err, BX_ERROR_READERWRITER_ALREADY_OPEN, "CrtFileReader: File is already open.");
+			return false;
+		}
+
+		m_file = fopen(_filePath, "rb");
+		if (NULL == m_file)
+		{
+			BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "CrtFileReader: Failed to open file.");
+			return false;
+		}
+
+		return true;
+	}
+
+	void CrtFileReader::close()
+	{
+		BX_CHECK(NULL != m_file, "Reader/Writer file is not open.");
+		FILE* file = (FILE*)m_file;
+		fclose(file);
+		m_file = NULL;
+	}
+
+	int64_t CrtFileReader::seek(int64_t _offset, Whence::Enum _whence)
+	{
+		BX_CHECK(NULL != m_file, "Reader/Writer file is not open.");
+		FILE* file = (FILE*)m_file;
+		fseeko64(file, _offset, _whence);
+		return ftello64(file);
+	}
+
+	int32_t CrtFileReader::read(void* _data, int32_t _size, Error* _err)
+	{
+		BX_CHECK(NULL != m_file, "Reader/Writer file is not open.");
+		BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+
+		FILE* file = (FILE*)m_file;
+		int32_t size = (int32_t)fread(_data, 1, _size, file);
+		if (size != _size)
+		{
+			if (0 != feof(file) )
+			{
+				BX_ERROR_SET(_err, BX_ERROR_READERWRITER_EOF, "CrtFileReader: EOF.");
+			}
+			else if (0 != ferror(file) )
+			{
+				BX_ERROR_SET(_err, BX_ERROR_READERWRITER_READ, "CrtFileReader: read error.");
+			}
+
+			return size >= 0 ? size : 0;
+		}
+
+		return size;
+	}
+
+	CrtFileWriter::CrtFileWriter()
+		: m_file(NULL)
+	{
+	}
+
+	CrtFileWriter::~CrtFileWriter()
+	{
+	}
+
+	bool CrtFileWriter::open(const char* _filePath, bool _append, Error* _err)
+	{
+		BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+
+		if (NULL != m_file)
+		{
+			BX_ERROR_SET(_err, BX_ERROR_READERWRITER_ALREADY_OPEN, "CrtFileReader: File is already open.");
+			return false;
+		}
+
+		m_file = fopen(_filePath, _append ? "ab" : "wb");
+
+		if (NULL == m_file)
+		{
+			BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "CrtFileWriter: Failed to open file.");
+			return false;
+		}
+
+		return true;
+	}
+
+	void CrtFileWriter::close()
+	{
+		BX_CHECK(NULL != m_file, "Reader/Writer file is not open.");
+		FILE* file = (FILE*)m_file;
+		fclose(file);
+		m_file = NULL;
+	}
+
+	int64_t CrtFileWriter::seek(int64_t _offset, Whence::Enum _whence)
+	{
+		BX_CHECK(NULL != m_file, "Reader/Writer file is not open.");
+		FILE* file = (FILE*)m_file;
+		fseeko64(file, _offset, _whence);
+		return ftello64(file);
+	}
+
+	int32_t CrtFileWriter::write(const void* _data, int32_t _size, Error* _err)
+	{
+		BX_CHECK(NULL != m_file, "Reader/Writer file is not open.");
+		BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+
+		FILE* file = (FILE*)m_file;
+		int32_t size = (int32_t)fwrite(_data, 1, _size, file);
+		if (size != _size)
+		{
+			BX_ERROR_SET(_err, BX_ERROR_READERWRITER_WRITE, "CrtFileWriter: write failed.");
+			return size >= 0 ? size : 0;
+		}
+
+		return size;
+	}
+#endif // BX_CONFIG_CRT_FILE_READER_WRITER
+
+#if BX_CONFIG_CRT_PROCESS
+
+#if BX_CRT_MSVC
+#	define popen  _popen
+#	define pclose _pclose
+#endif // BX_CRT_MSVC
+
+	ProcessReader::ProcessReader()
+		: m_file(NULL)
+	{
+	}
+
+	ProcessReader::~ProcessReader()
+	{
+		BX_CHECK(NULL == m_file, "Process not closed!");
+	}
+
+	bool ProcessReader::open(const char* _command, Error* _err)
+	{
+		BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+
+		if (NULL != m_file)
+		{
+			BX_ERROR_SET(_err, BX_ERROR_READERWRITER_ALREADY_OPEN, "ProcessReader: File is already open.");
+			return false;
+		}
+
+		m_file = popen(_command, "r");
+		if (NULL == m_file)
+		{
+			BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "ProcessReader: Failed to open process.");
+			return false;
+		}
+
+		return true;
+	}
+
+	void ProcessReader::close()
+	{
+		BX_CHECK(NULL != m_file, "Process not open!");
+		FILE* file = (FILE*)m_file;
+		m_exitCode = pclose(file);
+		m_file = NULL;
+	}
+
+	int32_t ProcessReader::read(void* _data, int32_t _size, Error* _err)
+	{
+		BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors."); BX_UNUSED(_err);
+
+		FILE* file = (FILE*)m_file;
+		int32_t size = (int32_t)fread(_data, 1, _size, file);
+		if (size != _size)
+		{
+			if (0 != feof(file) )
+			{
+				BX_ERROR_SET(_err, BX_ERROR_READERWRITER_EOF, "ProcessReader: EOF.");
+			}
+			else if (0 != ferror(file) )
+			{
+				BX_ERROR_SET(_err, BX_ERROR_READERWRITER_READ, "ProcessReader: read error.");
+			}
+
+			return size >= 0 ? size : 0;
+		}
+
+		return size;
+	}
+
+	int32_t ProcessReader::getExitCode() const
+	{
+		return m_exitCode;
+	}
+
+	ProcessWriter::ProcessWriter()
+		: m_file(NULL)
+	{
+	}
+
+	ProcessWriter::~ProcessWriter()
+	{
+		BX_CHECK(NULL == m_file, "Process not closed!");
+	}
+
+	bool ProcessWriter::open(const char* _command, bool, Error* _err)
+	{
+		BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+
+		if (NULL != m_file)
+		{
+			BX_ERROR_SET(_err, BX_ERROR_READERWRITER_ALREADY_OPEN, "ProcessWriter: File is already open.");
+			return false;
+		}
+
+		m_file = popen(_command, "w");
+		if (NULL == m_file)
+		{
+			BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "ProcessWriter: Failed to open process.");
+			return false;
+		}
+
+		return true;
+	}
+
+	void ProcessWriter::close()
+	{
+		BX_CHECK(NULL != m_file, "Process not open!");
+		FILE* file = (FILE*)m_file;
+		m_exitCode = pclose(file);
+		m_file = NULL;
+	}
+
+	int32_t ProcessWriter::write(const void* _data, int32_t _size, Error* _err)
+	{
+		BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors."); BX_UNUSED(_err);
+
+		FILE* file = (FILE*)m_file;
+		int32_t size = (int32_t)fwrite(_data, 1, _size, file);
+		if (size != _size)
+		{
+			if (0 != ferror(file) )
+			{
+				BX_ERROR_SET(_err, BX_ERROR_READERWRITER_WRITE, "ProcessWriter: write error.");
+			}
+
+			return size >= 0 ? size : 0;
+		}
+
+		return size;
+	}
+
+	int32_t ProcessWriter::getExitCode() const
+	{
+		return m_exitCode;
+	}
+#endif // BX_CONFIG_CRT_PROCESS
+
+} // namespace bx

+ 67 - 0
src/debug.cpp

@@ -0,0 +1,67 @@
+/*
+ * Copyright 2010-2017 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ */
+
+#include <bx/bx.h>
+
+#if BX_PLATFORM_ANDROID
+#	include <android/log.h>
+#elif BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT || BX_PLATFORM_XBOX360 || BX_PLATFORM_XBOXONE
+extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char* _str);
+#elif BX_PLATFORM_IOS || BX_PLATFORM_OSX
+#	if defined(__OBJC__)
+#		import <Foundation/NSObjCRuntime.h>
+#	else
+#		include <CoreFoundation/CFString.h>
+extern "C" void NSLog(CFStringRef _format, ...);
+#	endif // defined(__OBJC__)
+#elif 0 // BX_PLATFORM_EMSCRIPTEN
+#	include <emscripten.h>
+#else
+#	include <stdio.h>
+#endif // BX_PLATFORM_WINDOWS
+
+namespace bx
+{
+	void debugBreak()
+	{
+#if BX_COMPILER_MSVC
+		__debugbreak();
+#elif BX_CPU_ARM
+		__builtin_trap();
+//		asm("bkpt 0");
+#elif !BX_PLATFORM_NACL && BX_CPU_X86 && (BX_COMPILER_GCC || BX_COMPILER_CLANG)
+		// NaCl doesn't like int 3:
+		// NativeClient: NaCl module load failed: Validation failure. File violates Native Client safety rules.
+		__asm__ ("int $3");
+#else // cross platform implementation
+		int* int3 = (int*)3L;
+		*int3 = 3;
+#endif // BX
+	}
+
+	void debugOutput(const char* _out)
+	{
+#if BX_PLATFORM_ANDROID
+#	ifndef BX_ANDROID_LOG_TAG
+#		define BX_ANDROID_LOG_TAG ""
+#	endif // BX_ANDROID_LOG_TAG
+		__android_log_write(ANDROID_LOG_DEBUG, BX_ANDROID_LOG_TAG, _out);
+#elif BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT || BX_PLATFORM_XBOX360 || BX_PLATFORM_XBOXONE
+		OutputDebugStringA(_out);
+#elif BX_PLATFORM_IOS || BX_PLATFORM_OSX
+#	if defined(__OBJC__)
+		NSLog(@"%s", _out);
+#	else
+		NSLog(__CFStringMakeConstantString("%s"), _out);
+#	endif // defined(__OBJC__)
+#elif 0 // BX_PLATFORM_EMSCRIPTEN
+		emscripten_log(EM_LOG_CONSOLE, "%s", _out);
+#else
+		fputs(_out, stdout);
+		fflush(stdout);
+#endif // BX_PLATFORM_
+	}
+
+} // namespace bx