https://github.com/shader-slang/slang
Raw File
Tip revision: 4f979d74acf2800d7bd2b38155d2bdc47b57d54b authored by Tim Foley on 25 September 2018, 02:17:12 UTC
Fixes around atomic operations (#652)
Tip revision: 4f979d7
stream.cpp
#include "stream.h"
#ifdef _WIN32
#include <share.h>
#endif
#include "slang-io.h"

namespace Slang
{
	FileStream::FileStream(const Slang::String & fileName, FileMode fileMode)
	{
		Init(fileName, fileMode, fileMode==FileMode::Open?FileAccess::Read:FileAccess::Write, FileShare::None);
	}
	FileStream::FileStream(const Slang::String & fileName, FileMode fileMode, FileAccess access, FileShare share)
	{
		Init(fileName, fileMode, access, share);
	}
	void FileStream::Init(const Slang::String & fileName, FileMode fileMode, FileAccess access, FileShare share)
	{
		const wchar_t * mode = L"rt";
		const char* modeMBCS = "rt";
		switch (fileMode)
		{
		case Slang::FileMode::Create:
			if (access == FileAccess::Read)
				throw ArgumentException("Read-only access is incompatible with Create mode.");
			else if (access == FileAccess::ReadWrite)
			{
				mode = L"w+b";
				modeMBCS = "w+b";
				this->fileAccess = FileAccess::ReadWrite;
			}
			else
			{
				mode = L"wb";
				modeMBCS = "wb";
				this->fileAccess = FileAccess::Write;
			}
			break;
		case Slang::FileMode::Open:
			if (access == FileAccess::Read)
			{
				mode = L"rb";
				modeMBCS = "rb";
				this->fileAccess = FileAccess::Read;
			}
			else if (access == FileAccess::ReadWrite)
			{
				mode = L"r+b";
				modeMBCS = "r+b";
				this->fileAccess = FileAccess::ReadWrite;
			}
			else
			{
				mode = L"wb";
				modeMBCS = "wb";
				this->fileAccess = FileAccess::Write;
			}
			break;
		case Slang::FileMode::CreateNew:
			if (File::Exists(fileName))
			{
				throw IOException("Failed opening '" + fileName + "', file already exists.");
			}
			if (access == FileAccess::Read)
				throw ArgumentException("Read-only access is incompatible with Create mode.");
			else if (access == FileAccess::ReadWrite)
			{
				mode = L"w+b";
				this->fileAccess = FileAccess::ReadWrite;
			}
			else
			{
				mode = L"wb";
				this->fileAccess = FileAccess::Write;
			}
			break;
		case Slang::FileMode::Append:
			if (access == FileAccess::Read)
				throw ArgumentException("Read-only access is incompatible with Append mode.");
			else if (access == FileAccess::ReadWrite)
			{
				mode = L"a+b";
				this->fileAccess = FileAccess::ReadWrite;
			}
			else
			{
				mode = L"ab";
				this->fileAccess = FileAccess::Write;
			}
			break;
		default:
			break;
		}
		int shFlag;
#ifdef _WIN32
		switch (share)
		{
		case Slang::FileShare::None:
			shFlag = _SH_DENYRW;
			break;
		case Slang::FileShare::ReadOnly:
			shFlag = _SH_DENYWR;
			break;
		case Slang::FileShare::WriteOnly:
			shFlag = _SH_DENYRD;
			break;
		case Slang::FileShare::ReadWrite:
			shFlag = _SH_DENYNO;
			break;
		default:
			throw ArgumentException("Invalid file share mode.");
			break;
		}
        if (share == Slang::FileShare::None)
#pragma warning(suppress:4996)
            handle = _wfopen(fileName.ToWString(), mode);
        else
			handle = _wfsopen(fileName.ToWString(), mode, shFlag);
#else
		handle = fopen(fileName.Buffer(), modeMBCS);
#endif
		if (!handle)
		{
			throw IOException("Cannot open file '" + fileName + "'");
		}
	}
	FileStream::~FileStream()
	{
		Close();
	}
	Int64 FileStream::GetPosition()
	{
#ifdef _WIN32
		fpos_t pos;
		fgetpos(handle, &pos);
		return pos;
#else
		fpos64_t pos;
		fgetpos64(handle, &pos);
		return *(Int64*)(&pos);
#endif
	}
	void FileStream::Seek(SeekOrigin origin, Int64 offset)
	{
		int _origin;
		switch (origin)
		{
		case Slang::SeekOrigin::Start:
			_origin = SEEK_SET;
			endReached = false;
			break;
		case Slang::SeekOrigin::End:
			_origin = SEEK_END;
			endReached = true;
			break;
		case Slang::SeekOrigin::Current:
			_origin = SEEK_CUR;
			endReached = false;
			break;
		default:
			throw NotSupportedException("Unsupported seek origin.");
			break;
		}
#ifdef _WIN32
		int rs = _fseeki64(handle, offset, _origin);
#else
		int rs = fseek(handle, (int)offset, _origin);
#endif
		if (rs != 0)
		{
			throw IOException("FileStream seek failed.");
		}
	}
	Int64 FileStream::Read(void * buffer, Int64 length)
	{
		auto bytes = fread_s(buffer, (size_t)length, 1, (size_t)length, handle);
		if (bytes == 0 && length > 0)
		{
			if (!feof(handle))
				throw IOException("FileStream read failed.");
			else if (endReached)
				throw EndOfStreamException("End of file is reached.");
			endReached = true;
		}
		return (int)bytes;
	}
	Int64 FileStream::Write(const void * buffer, Int64 length)
	{
		auto bytes = (Int64)fwrite(buffer, 1, (size_t)length, handle);
		if (bytes < length)
		{
			throw IOException("FileStream write failed.");
		}
		return bytes;
	}
	bool FileStream::CanRead()
	{
		return ((int)fileAccess & (int)FileAccess::Read) != 0;
	}
	bool FileStream::CanWrite()
	{
		return ((int)fileAccess & (int)FileAccess::Write) != 0;
	}
	void FileStream::Close()
	{
		if (handle)
		{
			fclose(handle);
			handle = 0;
		}
	}
	bool FileStream::IsEnd()
	{
		return endReached;
	}
}
back to top