<commit_before>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"
#include "libtorrent/config.hpp"

#include <boost/scoped_ptr.hpp>
#ifdef TORRENT_WINDOWS
// windows part
#include "libtorrent/utf8.hpp"

#include <windows.h>
#include <winioctl.h>

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#else
// posix part
#define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include <boost/static_assert.hpp>
// make sure the _FILE_OFFSET_BITS define worked
// on this platform
BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);

#endif

#include <boost/filesystem/operations.hpp>
#include "libtorrent/file.hpp"
#include <sstream>
#include <cstring>
#include <vector>

#ifndef O_BINARY
#define O_BINARY 0
#endif

#ifndef O_RANDOM
#define O_RANDOM 0
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#include "libtorrent/assert.hpp"

namespace
{
#ifdef TORRENT_WINDOWS
	std::string utf8_native(std::string const& s)
	{
		try
		{
			std::wstring ws;
			libtorrent::utf8_wchar(s, ws);
			std::size_t size = wcstombs(0, ws.c_str(), 0);
			if (size == std::size_t(-1)) return s;
			std::string ret;
			ret.resize(size);
			size = wcstombs(&ret[0], ws.c_str(), size + 1);
			if (size == wchar_t(-1)) return s;
			ret.resize(size);
			return ret;
		}
		catch(std::exception)
		{
			return s;
		}
	}
#else

	enum { mode_in = 1, mode_out = 2 };

	mode_t map_open_mode(int m)
	{
		if (m == (mode_in | mode_out)) return O_RDWR | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
		TORRENT_ASSERT(false);
		return 0;
	}
#endif

}

namespace libtorrent
{
	namespace fs = boost::filesystem;

#ifdef TORRENT_WINDOWS
	const file::open_mode file::in(GENERIC_READ);
	const file::open_mode file::out(GENERIC_WRITE);
	const file::seek_mode file::begin(FILE_BEGIN);
	const file::seek_mode file::end(FILE_END);
#else
	const file::open_mode file::in(mode_in);
	const file::open_mode file::out(mode_out);
	const file::seek_mode file::begin(SEEK_SET);
	const file::seek_mode file::end(SEEK_END);
#endif

	file::file()
#ifdef TORRENT_WINDOWS
		: m_file_handle(INVALID_HANDLE_VALUE)
#else
		: m_fd(-1)
#endif
#ifndef NDEBUG
		, m_open_mode(0)
#endif
	{}

	file::file(fs::path const& path, open_mode mode, error_code& ec)
#ifdef TORRENT_WINDOWS
		: m_file_handle(INVALID_HANDLE_VALUE)
#else
		: m_fd(-1)
#endif
#ifndef NDEBUG
		, m_open_mode(0)
#endif
	{
		open(path, mode, ec);
	}

	file::~file()
	{
		close();
	}

	bool file::open(fs::path const& path, open_mode mode, error_code& ec)
	{
		close();
#ifdef TORRENT_WINDOWS

#ifdef UNICODE
		std::wstring file_path(safe_convert(path.native_file_string()));
#else
		std::string file_path = utf8_native(path.native_file_string());
#endif

		m_file_handle = CreateFile(
			file_path.c_str()
			, mode.m_mask
			, FILE_SHARE_READ
			, 0
			, (mode & out)?OPEN_ALWAYS:OPEN_EXISTING
			, FILE_ATTRIBUTE_NORMAL
			, 0);

		if (m_file_handle == INVALID_HANDLE_VALUE)
		{
			ec = error_code(GetLastError(), get_system_category());
			return false;
		}

		// try to make the file sparse if supported
		if (mode & out)
		{
			DWORD temp;
			::DeviceIoControl(m_file_handle, FSCTL_SET_SPARSE, 0, 0
				, 0, 0, &temp, 0);
		}
#else
		// rely on default umask to filter x and w permissions
		// for group and others
		m_fd = ::open(path.native_file_string().c_str()
			, map_open_mode(mode.m_mask), S_IRWXU | S_IRWXG | S_IRWXO);

		if (m_fd == -1)
		{
			ec = error_code(errno, get_posix_category());
			return false;
		}
#endif
#ifndef NDEBUG
		m_open_mode = mode;
#endif
		TORRENT_ASSERT(is_open());
		return true;
	}

	bool file::is_open() const
	{
#ifdef TORRENT_WINDOWS
		return m_file_handle != INVALID_HANDLE_VALUE;
#else
		return m_fd != -1;
#endif
	}

	void file::close()
	{
#ifdef TORRENT_WINDOWS
		if (m_file_handle == INVALID_HANDLE_VALUE) return;
		CloseHandle(m_file_handle);
		m_file_handle = INVALID_HANDLE_VALUE;
#else
		if (m_fd == -1) return;
		::close(m_fd);
		m_fd = -1;
#endif
#ifndef NDEBUG
		m_open_mode = 0;
#endif
	}

	size_type file::read(char* buf, size_type num_bytes, error_code& ec)
	{
		TORRENT_ASSERT((m_open_mode & in) == in);
		TORRENT_ASSERT(buf);
		TORRENT_ASSERT(num_bytes >= 0);
		TORRENT_ASSERT(is_open());

#ifdef TORRENT_WINDOWS

		TORRENT_ASSERT(DWORD(num_bytes) == num_bytes);
		DWORD ret = 0;
		if (num_bytes != 0)
		{
			if (ReadFile(m_file_handle, buf, (DWORD)num_bytes, &ret, 0) == FALSE)
			{
				ec = error_code(GetLastError(), get_system_category());
				return -1;
			}
		}
#else
		size_type ret = ::read(m_fd, buf, num_bytes);
		if (ret == -1) ec = error_code(errno, get_posix_category());
#endif
		return ret;
	}

	size_type file::write(const char* buf, size_type num_bytes, error_code& ec)
	{
		TORRENT_ASSERT((m_open_mode & out) == out);
		TORRENT_ASSERT(buf);
		TORRENT_ASSERT(num_bytes >= 0);
		TORRENT_ASSERT(is_open());

#ifdef TORRENT_WINDOWS

		DWORD ret = 0;
		if (num_bytes != 0)
		{
			if (WriteFile(m_file_handle, buf, (DWORD)num_bytes, &ret, 0) == FALSE)
			{
				ec = error_code(GetLastError(), get_system_category());
				return -1;
			}
		}
#else
		size_type ret = ::write(m_fd, buf, num_bytes);
		if (ret == -1) ec = error_code(errno, get_posix_category());
#endif
		return ret;
	}

  	bool file::set_size(size_type s, error_code& ec)
  	{
  		TORRENT_ASSERT(is_open());
  		TORRENT_ASSERT(s >= 0);

#ifdef TORRENT_WINDOWS
		size_type pos = tell(ec);
		if (ec) return false;
		seek(s, begin, ec);
		if (ec) return false;
		if (::SetEndOfFile(m_file_handle) == FALSE)
		{
			ec = error_code(GetLastError(), get_system_category());
			return false;
		}
#else
		if (ftruncate(m_fd, s) < 0)
		{
			ec = error_code(errno, get_posix_category());
			return false;
		}
#endif
		return true;
	}

	size_type file::seek(size_type offset, seek_mode m, error_code& ec)
	{
		TORRENT_ASSERT(is_open());

#ifdef TORRENT_WINDOWS
		LARGE_INTEGER offs;
		offs.QuadPart = offset;
		if (SetFilePointerEx(m_file_handle, offs, &offs, m.m_val) == FALSE)
		{
			ec = error_code(GetLastError(), get_system_category());
			return -1;
		}
		return offs.QuadPart;
#else
		size_type ret = lseek(m_fd, offset, m.m_val);
		if (ret < 0) ec = error_code(errno, get_posix_category());
		return ret;
#endif
	}

	size_type file::tell(error_code& ec)
	{
		TORRENT_ASSERT(is_open());

#ifdef TORRENT_WINDOWS
		LARGE_INTEGER offs;
		offs.QuadPart = 0;

		// is there any other way to get offset?
		if (SetFilePointerEx(m_file_handle, offs, &offs
			, FILE_CURRENT) == FALSE)
		{
			ec = error_code(GetLastError(), get_system_category());
			return -1;
		}

		return offs.QuadPart;
#else
		size_type ret;
		ret = lseek(m_fd, 0, SEEK_CUR);
		if (ret < 0) ec = error_code(errno, get_posix_category());
		return ret;
#endif
	}
}

<commit_msg>don't set executable permission of files<commit_after>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"
#include "libtorrent/config.hpp"

#include <boost/scoped_ptr.hpp>
#ifdef TORRENT_WINDOWS
// windows part
#include "libtorrent/utf8.hpp"

#include <windows.h>
#include <winioctl.h>

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#else
// posix part
#define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include <boost/static_assert.hpp>
// make sure the _FILE_OFFSET_BITS define worked
// on this platform
BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);

#endif

#include <boost/filesystem/operations.hpp>
#include "libtorrent/file.hpp"
#include <sstream>
#include <cstring>
#include <vector>

#ifndef O_BINARY
#define O_BINARY 0
#endif

#ifndef O_RANDOM
#define O_RANDOM 0
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#include "libtorrent/assert.hpp"

namespace
{
#ifdef TORRENT_WINDOWS
	std::string utf8_native(std::string const& s)
	{
		try
		{
			std::wstring ws;
			libtorrent::utf8_wchar(s, ws);
			std::size_t size = wcstombs(0, ws.c_str(), 0);
			if (size == std::size_t(-1)) return s;
			std::string ret;
			ret.resize(size);
			size = wcstombs(&ret[0], ws.c_str(), size + 1);
			if (size == wchar_t(-1)) return s;
			ret.resize(size);
			return ret;
		}
		catch(std::exception)
		{
			return s;
		}
	}
#else

	enum { mode_in = 1, mode_out = 2 };

	mode_t map_open_mode(int m)
	{
		if (m == (mode_in | mode_out)) return O_RDWR | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
		TORRENT_ASSERT(false);
		return 0;
	}
#endif

}

namespace libtorrent
{
	namespace fs = boost::filesystem;

#ifdef TORRENT_WINDOWS
	const file::open_mode file::in(GENERIC_READ);
	const file::open_mode file::out(GENERIC_WRITE);
	const file::seek_mode file::begin(FILE_BEGIN);
	const file::seek_mode file::end(FILE_END);
#else
	const file::open_mode file::in(mode_in);
	const file::open_mode file::out(mode_out);
	const file::seek_mode file::begin(SEEK_SET);
	const file::seek_mode file::end(SEEK_END);
#endif

	file::file()
#ifdef TORRENT_WINDOWS
		: m_file_handle(INVALID_HANDLE_VALUE)
#else
		: m_fd(-1)
#endif
#ifndef NDEBUG
		, m_open_mode(0)
#endif
	{}

	file::file(fs::path const& path, open_mode mode, error_code& ec)
#ifdef TORRENT_WINDOWS
		: m_file_handle(INVALID_HANDLE_VALUE)
#else
		: m_fd(-1)
#endif
#ifndef NDEBUG
		, m_open_mode(0)
#endif
	{
		open(path, mode, ec);
	}

	file::~file()
	{
		close();
	}

	bool file::open(fs::path const& path, open_mode mode, error_code& ec)
	{
		close();
#ifdef TORRENT_WINDOWS

#ifdef UNICODE
		std::wstring file_path(safe_convert(path.native_file_string()));
#else
		std::string file_path = utf8_native(path.native_file_string());
#endif

		m_file_handle = CreateFile(
			file_path.c_str()
			, mode.m_mask
			, FILE_SHARE_READ
			, 0
			, (mode & out)?OPEN_ALWAYS:OPEN_EXISTING
			, FILE_ATTRIBUTE_NORMAL
			, 0);

		if (m_file_handle == INVALID_HANDLE_VALUE)
		{
			ec = error_code(GetLastError(), get_system_category());
			return false;
		}

		// try to make the file sparse if supported
		if (mode & out)
		{
			DWORD temp;
			::DeviceIoControl(m_file_handle, FSCTL_SET_SPARSE, 0, 0
				, 0, 0, &temp, 0);
		}
#else
		// rely on default umask to filter x and w permissions
		// for group and others
		int permissions = S_IRUSR | S_IWUSR
			| S_IRGRP | S_IWGRP
			| S_IROTH | S_IWOTH;

		m_fd = ::open(path.native_file_string().c_str()
			, map_open_mode(mode.m_mask), permissions);

		if (m_fd == -1)
		{
			ec = error_code(errno, get_posix_category());
			return false;
		}
#endif
#ifndef NDEBUG
		m_open_mode = mode;
#endif
		TORRENT_ASSERT(is_open());
		return true;
	}

	bool file::is_open() const
	{
#ifdef TORRENT_WINDOWS
		return m_file_handle != INVALID_HANDLE_VALUE;
#else
		return m_fd != -1;
#endif
	}

	void file::close()
	{
#ifdef TORRENT_WINDOWS
		if (m_file_handle == INVALID_HANDLE_VALUE) return;
		CloseHandle(m_file_handle);
		m_file_handle = INVALID_HANDLE_VALUE;
#else
		if (m_fd == -1) return;
		::close(m_fd);
		m_fd = -1;
#endif
#ifndef NDEBUG
		m_open_mode = 0;
#endif
	}

	size_type file::read(char* buf, size_type num_bytes, error_code& ec)
	{
		TORRENT_ASSERT((m_open_mode & in) == in);
		TORRENT_ASSERT(buf);
		TORRENT_ASSERT(num_bytes >= 0);
		TORRENT_ASSERT(is_open());

#ifdef TORRENT_WINDOWS

		TORRENT_ASSERT(DWORD(num_bytes) == num_bytes);
		DWORD ret = 0;
		if (num_bytes != 0)
		{
			if (ReadFile(m_file_handle, buf, (DWORD)num_bytes, &ret, 0) == FALSE)
			{
				ec = error_code(GetLastError(), get_system_category());
				return -1;
			}
		}
#else
		size_type ret = ::read(m_fd, buf, num_bytes);
		if (ret == -1) ec = error_code(errno, get_posix_category());
#endif
		return ret;
	}

	size_type file::write(const char* buf, size_type num_bytes, error_code& ec)
	{
		TORRENT_ASSERT((m_open_mode & out) == out);
		TORRENT_ASSERT(buf);
		TORRENT_ASSERT(num_bytes >= 0);
		TORRENT_ASSERT(is_open());

#ifdef TORRENT_WINDOWS

		DWORD ret = 0;
		if (num_bytes != 0)
		{
			if (WriteFile(m_file_handle, buf, (DWORD)num_bytes, &ret, 0) == FALSE)
			{
				ec = error_code(GetLastError(), get_system_category());
				return -1;
			}
		}
#else
		size_type ret = ::write(m_fd, buf, num_bytes);
		if (ret == -1) ec = error_code(errno, get_posix_category());
#endif
		return ret;
	}

  	bool file::set_size(size_type s, error_code& ec)
  	{
  		TORRENT_ASSERT(is_open());
  		TORRENT_ASSERT(s >= 0);

#ifdef TORRENT_WINDOWS
		size_type pos = tell(ec);
		if (ec) return false;
		seek(s, begin, ec);
		if (ec) return false;
		if (::SetEndOfFile(m_file_handle) == FALSE)
		{
			ec = error_code(GetLastError(), get_system_category());
			return false;
		}
#else
		if (ftruncate(m_fd, s) < 0)
		{
			ec = error_code(errno, get_posix_category());
			return false;
		}
#endif
		return true;
	}

	size_type file::seek(size_type offset, seek_mode m, error_code& ec)
	{
		TORRENT_ASSERT(is_open());

#ifdef TORRENT_WINDOWS
		LARGE_INTEGER offs;
		offs.QuadPart = offset;
		if (SetFilePointerEx(m_file_handle, offs, &offs, m.m_val) == FALSE)
		{
			ec = error_code(GetLastError(), get_system_category());
			return -1;
		}
		return offs.QuadPart;
#else
		size_type ret = lseek(m_fd, offset, m.m_val);
		if (ret < 0) ec = error_code(errno, get_posix_category());
		return ret;
#endif
	}

	size_type file::tell(error_code& ec)
	{
		TORRENT_ASSERT(is_open());

#ifdef TORRENT_WINDOWS
		LARGE_INTEGER offs;
		offs.QuadPart = 0;

		// is there any other way to get offset?
		if (SetFilePointerEx(m_file_handle, offs, &offs
			, FILE_CURRENT) == FALSE)
		{
			ec = error_code(GetLastError(), get_system_category());
			return -1;
		}

		return offs.QuadPart;
#else
		size_type ret;
		ret = lseek(m_fd, 0, SEEK_CUR);
		if (ret < 0) ec = error_code(errno, get_posix_category());
		return ret;
#endif
	}
}

<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include <boost/scoped_ptr.hpp>
#ifdef _WIN32
// windows part
#include "libtorrent/utf8.hpp"

#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifndef _MODE_T_
typedef int mode_t;
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#else
// unix part
#define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include <boost/static_assert.hpp>
// make sure the _FILE_OFFSET_BITS define worked
// on this platform
BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);

#endif

#include <boost/filesystem/operations.hpp>
#include "libtorrent/file.hpp"
#include <sstream>
#include <cstring>
#include <vector>

#ifndef O_BINARY
#define O_BINARY 0
#endif

#ifndef O_RANDOM
#define O_RANDOM 0
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#include "libtorrent/assert.hpp"

namespace
{
	enum { mode_in = 1, mode_out = 2 };

	mode_t map_open_mode(int m)
	{
		if (m == (mode_in | mode_out)) return O_RDWR | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
		TORRENT_ASSERT(false);
		return 0;
	}

#ifdef WIN32
	std::string utf8_native(std::string const& s)
	{
		try
		{
			std::wstring ws;
			libtorrent::utf8_wchar(s, ws);
			std::size_t size = wcstombs(0, ws.c_str(), 0);
			if (size == std::size_t(-1)) return s;
			std::string ret;
			ret.resize(size);
			size = wcstombs(&ret[0], ws.c_str(), size + 1);
			if (size == wchar_t(-1)) return s;
			ret.resize(size);
			return ret;
		}
		catch(std::exception)
		{
			return s;
		}
	}
#else
	std::string utf8_native(std::string const& s)
	{
		return s;
	}
#endif

}

namespace libtorrent
{
	namespace fs = boost::filesystem;

	const file::open_mode file::in(mode_in);
	const file::open_mode file::out(mode_out);

	const file::seek_mode file::begin(1);
	const file::seek_mode file::end(2);

	struct file::impl
	{
		impl()
			: m_fd(-1)
			, m_open_mode(0)
		{}

		impl(fs::path const& path, int mode)
			: m_fd(-1)
			, m_open_mode(0)
		{
			open(path, mode);
		}

		~impl()
		{
			close();
		}

		bool open(fs::path const& path, int mode)
		{
			close();
#if defined(_WIN32) && defined(UNICODE)
			std::wstring wpath(safe_convert(path.native_file_string()));
			m_fd = ::_wopen(
				wpath.c_str()
				, map_open_mode(mode)
				, S_IREAD | S_IWRITE);
#else
#ifdef _WIN32
			m_fd = ::_open(
#else
			m_fd = ::open(
#endif
				utf8_native(path.native_file_string()).c_str()
				, map_open_mode(mode)
#ifdef _WIN32
				, S_IREAD | S_IWRITE);
#else
				, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
#endif
#endif
			if (m_fd == -1)
			{
				std::stringstream msg;
				msg << "open failed: '" << path.native_file_string() << "'. "
					<< std::strerror(errno);
				if (!m_error) m_error.reset(new std::string);
				*m_error = msg.str();
				return false;
			}
			m_open_mode = mode;
			return true;
		}

		void close()
		{
			if (m_fd == -1) return;

#ifdef _WIN32
			::_close(m_fd);
#else
			::close(m_fd);
#endif
			m_fd = -1;
			m_open_mode = 0;
		}

		size_type read(char* buf, size_type num_bytes)
		{
			TORRENT_ASSERT(m_open_mode & mode_in);
			TORRENT_ASSERT(m_fd != -1);

#ifdef _WIN32
			size_type ret = ::_read(m_fd, buf, num_bytes);
#else
			size_type ret = ::read(m_fd, buf, num_bytes);
#endif
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "read failed: " << std::strerror(errno);
				if (!m_error) m_error.reset(new std::string);
				*m_error = msg.str();
			}
			return ret;
		}

		size_type write(const char* buf, size_type num_bytes)
		{
			TORRENT_ASSERT(m_open_mode & mode_out);
			TORRENT_ASSERT(m_fd != -1);

			// TODO: Test this a bit more, what happens with random failures in
			// the files?
//			if ((rand() % 100) > 80)
//				throw file_error("debug");

#ifdef _WIN32
			size_type ret = ::_write(m_fd, buf, num_bytes);
#else
			size_type ret = ::write(m_fd, buf, num_bytes);
#endif
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "write failed: " << std::strerror(errno);
				if (!m_error) m_error.reset(new std::string);
				*m_error = msg.str();
			}
			return ret;
		}

		bool set_size(size_type s)
		{
#ifdef _WIN32
#error file.cpp is for posix systems only. use file_win.cpp on windows
#else
			if (ftruncate(m_fd, s) < 0)
			{
				std::stringstream msg;
				msg << "ftruncate failed: '" << std::strerror(errno);
				if (!m_error) m_error.reset(new std::string);
				*m_error = msg.str();
				return false;
			}
			return true;
#endif
		}

		size_type seek(size_type offset, int m = 1)
		{
			TORRENT_ASSERT(m_open_mode);
			TORRENT_ASSERT(m_fd != -1);

			int seekdir = (m == 1)?SEEK_SET:SEEK_END;
#ifdef _WIN32
			size_type ret = _lseeki64(m_fd, offset, seekdir);
#else
			size_type ret = lseek(m_fd, offset, seekdir);
#endif

			// For some strange reason this fails
			// on win32. Use windows specific file
			// wrapper instead.
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "seek failed: '" << std::strerror(errno)
					<< "' fd: " << m_fd
					<< " offset: " << offset
					<< " seekdir: " << seekdir;
				if (!m_error) m_error.reset(new std::string);
				*m_error = msg.str();
				return -1;
			}
			return ret;
		}

		size_type tell()
		{
			TORRENT_ASSERT(m_open_mode);
			TORRENT_ASSERT(m_fd != -1);

#ifdef _WIN32
			return _telli64(m_fd);
#else
			return lseek(m_fd, 0, SEEK_CUR);
#endif
		}

		std::string const& error() const
		{
			if (!m_error) m_error.reset(new std::string);
			return *m_error;
		}

		int m_fd;
		int m_open_mode;
		mutable boost::scoped_ptr<std::string> m_error;
	};

	// pimpl forwardings

	file::file() : m_impl(new impl()) {}

	file::file(fs::path const& p, file::open_mode m)
		: m_impl(new impl(p, m.m_mask))
	{}

	file::~file() {}

	bool file::open(fs::path const& p, file::open_mode m)
	{
		return m_impl->open(p, m.m_mask);
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buf, size_type num_bytes)
	{
		return m_impl->write(buf, num_bytes);
	}

	size_type file::read(char* buf, size_type num_bytes)
	{
		return m_impl->read(buf, num_bytes);
	}

	bool file::set_size(size_type s)
	{
		return m_impl->set_size(s);
	}

	size_type file::seek(size_type pos, file::seek_mode m)
	{
		return m_impl->seek(pos, m.m_val);
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}

	std::string const& file::error() const
	{
		return m_impl->error();
	}

}
<commit_msg>removed hard coded file permission bits<commit_after>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include <boost/scoped_ptr.hpp>
#ifdef _WIN32
// windows part
#include "libtorrent/utf8.hpp"

#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifndef _MODE_T_
typedef int mode_t;
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#else
// unix part
#define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include <boost/static_assert.hpp>
// make sure the _FILE_OFFSET_BITS define worked
// on this platform
BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);

#endif

#include <boost/filesystem/operations.hpp>
#include "libtorrent/file.hpp"
#include <sstream>
#include <cstring>
#include <vector>

#ifndef O_BINARY
#define O_BINARY 0
#endif

#ifndef O_RANDOM
#define O_RANDOM 0
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#include "libtorrent/assert.hpp"

namespace
{
	enum { mode_in = 1, mode_out = 2 };

	mode_t map_open_mode(int m)
	{
		if (m == (mode_in | mode_out)) return O_RDWR | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
		TORRENT_ASSERT(false);
		return 0;
	}

#ifdef WIN32
	std::string utf8_native(std::string const& s)
	{
		try
		{
			std::wstring ws;
			libtorrent::utf8_wchar(s, ws);
			std::size_t size = wcstombs(0, ws.c_str(), 0);
			if (size == std::size_t(-1)) return s;
			std::string ret;
			ret.resize(size);
			size = wcstombs(&ret[0], ws.c_str(), size + 1);
			if (size == wchar_t(-1)) return s;
			ret.resize(size);
			return ret;
		}
		catch(std::exception)
		{
			return s;
		}
	}
#else
	std::string utf8_native(std::string const& s)
	{
		return s;
	}
#endif

}

namespace libtorrent
{
	namespace fs = boost::filesystem;

	const file::open_mode file::in(mode_in);
	const file::open_mode file::out(mode_out);

	const file::seek_mode file::begin(1);
	const file::seek_mode file::end(2);

	struct file::impl
	{
		impl()
			: m_fd(-1)
			, m_open_mode(0)
		{}

		impl(fs::path const& path, int mode)
			: m_fd(-1)
			, m_open_mode(0)
		{
			open(path, mode);
		}

		~impl()
		{
			close();
		}

		bool open(fs::path const& path, int mode)
		{
			close();
#if defined _WIN32 && defined UNICODE
			std::wstring wpath(safe_convert(path.native_file_string()));
			m_fd = ::_wopen(
				wpath.c_str()
				, map_open_mode(mode));
#elif defined _WIN32
			m_fd = ::_open(
				utf8_native(path.native_file_string()).c_str()
				, map_open_mode(mode));
#else
			m_fd = ::open(
				utf8_native(path.native_file_string()).c_str()
				, map_open_mode(mode));
#endif
			if (m_fd == -1)
			{
				std::stringstream msg;
				msg << "open failed: '" << path.native_file_string() << "'. "
					<< std::strerror(errno);
				if (!m_error) m_error.reset(new std::string);
				*m_error = msg.str();
				return false;
			}
			m_open_mode = mode;
			return true;
		}

		void close()
		{
			if (m_fd == -1) return;

#ifdef _WIN32
			::_close(m_fd);
#else
			::close(m_fd);
#endif
			m_fd = -1;
			m_open_mode = 0;
		}

		size_type read(char* buf, size_type num_bytes)
		{
			TORRENT_ASSERT(m_open_mode & mode_in);
			TORRENT_ASSERT(m_fd != -1);

#ifdef _WIN32
			size_type ret = ::_read(m_fd, buf, num_bytes);
#else
			size_type ret = ::read(m_fd, buf, num_bytes);
#endif
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "read failed: " << std::strerror(errno);
				if (!m_error) m_error.reset(new std::string);
				*m_error = msg.str();
			}
			return ret;
		}

		size_type write(const char* buf, size_type num_bytes)
		{
			TORRENT_ASSERT(m_open_mode & mode_out);
			TORRENT_ASSERT(m_fd != -1);

			// TODO: Test this a bit more, what happens with random failures in
			// the files?
//			if ((rand() % 100) > 80)
//				throw file_error("debug");

#ifdef _WIN32
			size_type ret = ::_write(m_fd, buf, num_bytes);
#else
			size_type ret = ::write(m_fd, buf, num_bytes);
#endif
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "write failed: " << std::strerror(errno);
				if (!m_error) m_error.reset(new std::string);
				*m_error = msg.str();
			}
			return ret;
		}

		bool set_size(size_type s)
		{
#ifdef _WIN32
#error file.cpp is for posix systems only. use file_win.cpp on windows
#else
			if (ftruncate(m_fd, s) < 0)
			{
				std::stringstream msg;
				msg << "ftruncate failed: '" << std::strerror(errno);
				if (!m_error) m_error.reset(new std::string);
				*m_error = msg.str();
				return false;
			}
			return true;
#endif
		}

		size_type seek(size_type offset, int m = 1)
		{
			TORRENT_ASSERT(m_open_mode);
			TORRENT_ASSERT(m_fd != -1);

			int seekdir = (m == 1)?SEEK_SET:SEEK_END;
#ifdef _WIN32
			size_type ret = _lseeki64(m_fd, offset, seekdir);
#else
			size_type ret = lseek(m_fd, offset, seekdir);
#endif

			// For some strange reason this fails
			// on win32. Use windows specific file
			// wrapper instead.
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "seek failed: '" << std::strerror(errno)
					<< "' fd: " << m_fd
					<< " offset: " << offset
					<< " seekdir: " << seekdir;
				if (!m_error) m_error.reset(new std::string);
				*m_error = msg.str();
				return -1;
			}
			return ret;
		}

		size_type tell()
		{
			TORRENT_ASSERT(m_open_mode);
			TORRENT_ASSERT(m_fd != -1);

#ifdef _WIN32
			return _telli64(m_fd);
#else
			return lseek(m_fd, 0, SEEK_CUR);
#endif
		}

		std::string const& error() const
		{
			if (!m_error) m_error.reset(new std::string);
			return *m_error;
		}

		int m_fd;
		int m_open_mode;
		mutable boost::scoped_ptr<std::string> m_error;
	};

	// pimpl forwardings

	file::file() : m_impl(new impl()) {}

	file::file(fs::path const& p, file::open_mode m)
		: m_impl(new impl(p, m.m_mask))
	{}

	file::~file() {}

	bool file::open(fs::path const& p, file::open_mode m)
	{
		return m_impl->open(p, m.m_mask);
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buf, size_type num_bytes)
	{
		return m_impl->write(buf, num_bytes);
	}

	size_type file::read(char* buf, size_type num_bytes)
	{
		return m_impl->read(buf, num_bytes);
	}

	bool file::set_size(size_type s)
	{
		return m_impl->set_size(s);
	}

	size_type file::seek(size_type pos, file::seek_mode m)
	{
		return m_impl->seek(pos, m.m_val);
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}

	std::string const& file::error() const
	{
		return m_impl->error();
	}

}
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#ifdef _WIN32
// windows part
#include "libtorrent/utf8.hpp"

#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifndef _MODE_T_
typedef int mode_t;
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#else
// unix part
#define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include <boost/static_assert.hpp>
// make sure the _FILE_OFFSET_BITS define worked
// on this platform
BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);

#endif

#include <boost/filesystem/operations.hpp>
#include "libtorrent/file.hpp"
#include <sstream>

#ifndef O_BINARY
#define O_BINARY 0
#endif

#ifndef O_RANDOM
#define O_RANDOM 0
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

namespace
{
	enum { mode_in = 1, mode_out = 2 };

	mode_t map_open_mode(int m)
	{
		if (m == (mode_in | mode_out)) return O_RDWR | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
		assert(false);
		return 0;
	}

#ifdef WIN32
	std::string utf8_native(std::string const& s)
	{
		try
		{
			std::wstring ws;
			libtorrent::utf8_wchar(s, ws);
			std::size_t size = wcstombs(0, ws.c_str(), 0);
			if (size == std::size_t(-1)) return s;
			std::string ret;
			ret.resize(size);
			size = wcstombs(&ret[0], ws.c_str(), size + 1);
			if (size == wchar_t(-1)) return s;
			ret.resize(size);
			return ret;
		}
		catch(std::exception)
		{
			return s;
		}
	}
#else
	std::string utf8_native(std::string const& s)
	{
		return s;
	}
#endif

}

namespace libtorrent
{

	namespace fs = boost::filesystem;

	const file::open_mode file::in(mode_in);
	const file::open_mode file::out(mode_out);

	const file::seek_mode file::begin(1);
	const file::seek_mode file::end(2);

	struct file::impl
	{
		impl()
			: m_fd(-1)
			, m_open_mode(0)
		{}

		impl(fs::path const& path, int mode)
			: m_fd(-1)
			, m_open_mode(0)
		{
			open(path, mode);
		}

		~impl()
		{
			close();
		}

		void open(fs::path const& path, int mode)
		{
			assert(path.is_complete());
			close();
#if defined(_WIN32) && defined(UNICODE)
			std::wstring wpath(safe_convert(path.native_file_string()));
			m_fd = ::_wopen(
				wpath.c_str()
				, map_open_mode(mode)
				, S_IREAD | S_IWRITE);
#else
#ifdef _WIN32
			m_fd = ::_open(
#else
			m_fd = ::open(
#endif
				utf8_native(path.native_file_string()).c_str()
				, map_open_mode(mode)
#ifdef _WIN32
				, S_IREAD | S_IWRITE);
#else
				, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
#endif
#endif
			if (m_fd == -1)
			{
				std::stringstream msg;
				msg << "open failed: '" << path.native_file_string() << "'. "
					<< strerror(errno);
				throw file_error(msg.str());
			}
			m_open_mode = mode;
		}

		void close()
		{
			if (m_fd == -1) return;

#ifdef _WIN32
			::_close(m_fd);
#else
			::close(m_fd);
#endif
			m_fd = -1;
			m_open_mode = 0;
		}

		size_type read(char* buf, size_type num_bytes)
		{
			assert(m_open_mode & mode_in);
			assert(m_fd != -1);

#ifdef _WIN32
			size_type ret = ::_read(m_fd, buf, num_bytes);
#else
			size_type ret = ::read(m_fd, buf, num_bytes);
#endif
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "read failed: " << strerror(errno);
				throw file_error(msg.str());
			}
			return ret;
		}

		size_type write(const char* buf, size_type num_bytes)
		{
			assert(m_open_mode & mode_out);
			assert(m_fd != -1);

			// TODO: Test this a bit more, what happens with random failures in
			// the files?
//			if ((rand() % 100) > 80)
//				throw file_error("debug");

#ifdef _WIN32
			size_type ret = ::_write(m_fd, buf, num_bytes);
#else
			size_type ret = ::write(m_fd, buf, num_bytes);
#endif
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "write failed: " << strerror(errno);
				throw file_error(msg.str());
			}
			return ret;
		}

		void set_size(size_type s)
		{
			size_type pos = tell();
			seek(s - 1);
			char dummy = 0;
			read(&dummy, 1);
			seek(s - 1);
			write(&dummy, 1);
			seek(pos);
		}

		size_type seek(size_type offset, int m = 1)
		{
			assert(m_open_mode);
			assert(m_fd != -1);

			int seekdir = (m == 1)?SEEK_SET:SEEK_END;
#ifdef _WIN32
			size_type ret = _lseeki64(m_fd, offset, seekdir);
#else
			size_type ret = lseek(m_fd, offset, seekdir);
#endif

			// For some strange reason this fails
			// on win32. Use windows specific file
			// wrapper instead.
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "seek failed: '" << strerror(errno)
					<< "' fd: " << m_fd
					<< " offset: " << offset
					<< " seekdir: " << seekdir;
				throw file_error(msg.str());
			}
			return ret;
		}

		size_type tell()
		{
			assert(m_open_mode);
			assert(m_fd != -1);

#ifdef _WIN32
			return _telli64(m_fd);
#else
			return lseek(m_fd, 0, SEEK_CUR);
#endif
		}

		int m_fd;
		int m_open_mode;
	};

	// pimpl forwardings

	file::file() : m_impl(new impl()) {}

	file::file(fs::path const& p, file::open_mode m)
		: m_impl(new impl(p, m.m_mask))
	{}

	file::~file() {}

	void file::open(fs::path const& p, file::open_mode m)
	{
		m_impl->open(p, m.m_mask);
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buf, size_type num_bytes)
	{
		return m_impl->write(buf, num_bytes);
	}

	size_type file::read(char* buf, size_type num_bytes)
	{
		return m_impl->read(buf, num_bytes);
	}

	void file::set_size(size_type s)
	{
		m_impl->set_size(s);
	}

	size_type file::seek(size_type pos, file::seek_mode m)
	{
		return m_impl->seek(pos, m.m_val);
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}

}
<commit_msg>fixed issue where file::set_size would update the file modification date even when the size was not changed (fixes #105)<commit_after>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#ifdef _WIN32
// windows part
#include "libtorrent/utf8.hpp"

#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifndef _MODE_T_
typedef int mode_t;
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#else
// unix part
#define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include <boost/static_assert.hpp>
// make sure the _FILE_OFFSET_BITS define worked
// on this platform
BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);

#endif

#include <boost/filesystem/operations.hpp>
#include "libtorrent/file.hpp"
#include <sstream>

#ifndef O_BINARY
#define O_BINARY 0
#endif

#ifndef O_RANDOM
#define O_RANDOM 0
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

namespace
{
	enum { mode_in = 1, mode_out = 2 };

	mode_t map_open_mode(int m)
	{
		if (m == (mode_in | mode_out)) return O_RDWR | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
		assert(false);
		return 0;
	}

#ifdef WIN32
	std::string utf8_native(std::string const& s)
	{
		try
		{
			std::wstring ws;
			libtorrent::utf8_wchar(s, ws);
			std::size_t size = wcstombs(0, ws.c_str(), 0);
			if (size == std::size_t(-1)) return s;
			std::string ret;
			ret.resize(size);
			size = wcstombs(&ret[0], ws.c_str(), size + 1);
			if (size == wchar_t(-1)) return s;
			ret.resize(size);
			return ret;
		}
		catch(std::exception)
		{
			return s;
		}
	}
#else
	std::string utf8_native(std::string const& s)
	{
		return s;
	}
#endif

}

namespace libtorrent
{

	namespace fs = boost::filesystem;

	const file::open_mode file::in(mode_in);
	const file::open_mode file::out(mode_out);

	const file::seek_mode file::begin(1);
	const file::seek_mode file::end(2);

	struct file::impl
	{
		impl()
			: m_fd(-1)
			, m_open_mode(0)
		{}

		impl(fs::path const& path, int mode)
			: m_fd(-1)
			, m_open_mode(0)
		{
			open(path, mode);
		}

		~impl()
		{
			close();
		}

		void open(fs::path const& path, int mode)
		{
			assert(path.is_complete());
			close();
#if defined(_WIN32) && defined(UNICODE)
			std::wstring wpath(safe_convert(path.native_file_string()));
			m_fd = ::_wopen(
				wpath.c_str()
				, map_open_mode(mode)
				, S_IREAD | S_IWRITE);
#else
#ifdef _WIN32
			m_fd = ::_open(
#else
			m_fd = ::open(
#endif
				utf8_native(path.native_file_string()).c_str()
				, map_open_mode(mode)
#ifdef _WIN32
				, S_IREAD | S_IWRITE);
#else
				, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
#endif
#endif
			if (m_fd == -1)
			{
				std::stringstream msg;
				msg << "open failed: '" << path.native_file_string() << "'. "
					<< strerror(errno);
				throw file_error(msg.str());
			}
			m_open_mode = mode;
		}

		void close()
		{
			if (m_fd == -1) return;

#ifdef _WIN32
			::_close(m_fd);
#else
			::close(m_fd);
#endif
			m_fd = -1;
			m_open_mode = 0;
		}

		size_type read(char* buf, size_type num_bytes)
		{
			assert(m_open_mode & mode_in);
			assert(m_fd != -1);

#ifdef _WIN32
			size_type ret = ::_read(m_fd, buf, num_bytes);
#else
			size_type ret = ::read(m_fd, buf, num_bytes);
#endif
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "read failed: " << strerror(errno);
				throw file_error(msg.str());
			}
			return ret;
		}

		size_type write(const char* buf, size_type num_bytes)
		{
			assert(m_open_mode & mode_out);
			assert(m_fd != -1);

			// TODO: Test this a bit more, what happens with random failures in
			// the files?
//			if ((rand() % 100) > 80)
//				throw file_error("debug");

#ifdef _WIN32
			size_type ret = ::_write(m_fd, buf, num_bytes);
#else
			size_type ret = ::write(m_fd, buf, num_bytes);
#endif
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "write failed: " << strerror(errno);
				throw file_error(msg.str());
			}
			return ret;
		}

		void set_size(size_type s)
		{
			size_type pos = tell();
			// Only set size if current file size not equals s.
			// 2 as "m" argument is to be sure seek() sets SEEK_END on
			// all compilers.
			if(s != seek(0, 2))
			{
				seek(s - 1);
				char dummy = 0;
				read(&dummy, 1);
				seek(s - 1);
				write(&dummy, 1);
			}
			seek(pos);
		}

		size_type seek(size_type offset, int m = 1)
		{
			assert(m_open_mode);
			assert(m_fd != -1);

			int seekdir = (m == 1)?SEEK_SET:SEEK_END;
#ifdef _WIN32
			size_type ret = _lseeki64(m_fd, offset, seekdir);
#else
			size_type ret = lseek(m_fd, offset, seekdir);
#endif

			// For some strange reason this fails
			// on win32. Use windows specific file
			// wrapper instead.
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "seek failed: '" << strerror(errno)
					<< "' fd: " << m_fd
					<< " offset: " << offset
					<< " seekdir: " << seekdir;
				throw file_error(msg.str());
			}
			return ret;
		}

		size_type tell()
		{
			assert(m_open_mode);
			assert(m_fd != -1);

#ifdef _WIN32
			return _telli64(m_fd);
#else
			return lseek(m_fd, 0, SEEK_CUR);
#endif
		}

		int m_fd;
		int m_open_mode;
	};

	// pimpl forwardings

	file::file() : m_impl(new impl()) {}

	file::file(fs::path const& p, file::open_mode m)
		: m_impl(new impl(p, m.m_mask))
	{}

	file::~file() {}

	void file::open(fs::path const& p, file::open_mode m)
	{
		m_impl->open(p, m.m_mask);
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buf, size_type num_bytes)
	{
		return m_impl->write(buf, num_bytes);
	}

	size_type file::read(char* buf, size_type num_bytes)
	{
		return m_impl->read(buf, num_bytes);
	}

	void file::set_size(size_type s)
	{
		m_impl->set_size(s);
	}

	size_type file::seek(size_type pos, file::seek_mode m)
	{
		return m_impl->seek(pos, m.m_val);
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}

}
<|endoftext|>


<commit_before>#include "flake.h"

#include <sys/time.h>

using namespace emilir;

// Assumes big endian input
static void bitmemcpy(uint8_t *out,
                      size_t outBitOffset,
                      const uint8_t *in,
                      size_t inBitOffset,
                      size_t bitLength) {
  // This could be optimized.
  for (size_t i=0; i<bitLength; i++) {
    size_t inBytePos =     (i+inBitOffset)/8;
    size_t inBitPos  = 7 - (i+inBitOffset)%8;

    bool inBit = in[inBytePos] & (1 << inBitPos);

    size_t outBytePos =     (i+outBitOffset)/8;
    size_t outBitPos  = 7 - (i+outBitOffset)%8;

    if (inBit) {
      out[outBytePos] |= (1<<outBitPos);
    }
    else {
      out[outBytePos] &= ~(1<<outBitPos);
    }
  }
}

static uint64_t make_timestamp(uint64_t offset) {
  struct timeval tv;
  gettimeofday(&tv, NULL);

  return ((tv.tv_sec - offset/1000)*1000 +
          tv.tv_usec/1000);
}

static uint64_t htonll(uint64_t value) {
  // See http://stackoverflow.com/questions/3022552/is-there-any-standard-htonl-like-function-for-64-bits-integers-in-c

  // The answer is 42
  static const int num = 42;

  // Check the endianness
  if (*reinterpret_cast<const char*>(&num) == num) {
    const uint32_t high_part = htonl(static_cast<uint32_t>(value >> 32));
    const uint32_t low_part = htonl(static_cast<uint32_t>(value & 0xFFFFFFFFLL));

    return (static_cast<uint64_t>(low_part) << 32) | high_part;
  }
  else {
    return value;
  }
}

flake::flake(const uint8_t *machineNumber,
             size_t machineNumberLength,
             size_t sequenceNumberLength,
             size_t timestampLength,
             uint64_t timeOffset) :
_machineNumber(machineNumber, machineNumber+((machineNumberLength+7)/8)),
_machineNumberLength(machineNumberLength),
_sequenceNumberLength(sequenceNumberLength),
_timestampLength(timestampLength),
_timeOffset(timeOffset),
_lastTimestamp(make_timestamp(timeOffset)),
_sequenceNumber(0),
_sequenceNumberOverflow(false) {
  if (_sequenceNumberLength > 8*sizeof(_sequenceNumber) ||
      _timestampLength > 8*sizeof(_timestampLength)) {
    abort();
  }
}

int flake::generate(size_t bufLen, uint8_t *buf) {
  if (bufLen < byte_length()) {
    // The buffer is too small
    return 3;
  }

  uint64_t timestamp = make_timestamp(_timeOffset);

  if (timestamp < _lastTimestamp - 1000) {
    // The timer has moved backwards by more than 1 second
    return 2;
  }

  if (timestamp < _lastTimestamp) {
    // The timer has moved backwards
    return 1;
  }

  uint64_t nextSequenceNumber;
  bool nextSequenceNumberHasOverflowed;

  if (timestamp == _lastTimestamp) {
    if (_sequenceNumberOverflow) {
      // Sequence number overflow
      return 1;
    }

    if (8*sizeof(_sequenceNumber) == _sequenceNumberLength) {
      nextSequenceNumber = _sequenceNumber+1;
    }
    else {
      nextSequenceNumber = (_sequenceNumber+1) % (1<<_sequenceNumberLength);
    }
    nextSequenceNumberHasOverflowed = (0 == nextSequenceNumber);
  }
  else {
    _sequenceNumber = 0;
    _lastTimestamp = timestamp;
    nextSequenceNumber = 1;
    nextSequenceNumberHasOverflowed = false;
  }

  uint64_t bigEndianTimestamp = htonll(timestamp);
  uint64_t bigEndianSequenceNumber = htonll(_sequenceNumber);

  bitmemcpy(/*out:*/buf,
            /*outBitOffset:*/0,
            /*in:*/(const uint8_t *)&bigEndianTimestamp,
            /*inBitOffset*/8*sizeof(bigEndianTimestamp)-_timestampLength,
            /*bitLength:*/_timestampLength);
  bitmemcpy(/*out:*/buf,
            /*outBitOffset:*/_timestampLength,
            /*in:*/(const uint8_t *)&bigEndianSequenceNumber,
            /*inBitOffset:*/8*sizeof(bigEndianSequenceNumber)-_sequenceNumberLength,
            /*bitLength:*/_sequenceNumberLength);
  bitmemcpy(/*out:*/buf,
            /*outBitOffset:*/_timestampLength+_sequenceNumberLength,
            /*in:*/&_machineNumber[0],
            /*inBitOffset:*/0,
            /*bitLength:*/_machineNumberLength);

  _sequenceNumber = nextSequenceNumber;
  _sequenceNumberOverflow = nextSequenceNumberHasOverflowed;

  return 0;
}
<commit_msg>fix compile error on ubuntu 12.0.4<commit_after>#include "flake.h"

#include <sys/time.h>
#include <netinet/in.h>

using namespace emilir;

// Assumes big endian input
static void bitmemcpy(uint8_t *out,
                      size_t outBitOffset,
                      const uint8_t *in,
                      size_t inBitOffset,
                      size_t bitLength) {
  // This could be optimized.
  for (size_t i=0; i<bitLength; i++) {
    size_t inBytePos =     (i+inBitOffset)/8;
    size_t inBitPos  = 7 - (i+inBitOffset)%8;

    bool inBit = in[inBytePos] & (1 << inBitPos);

    size_t outBytePos =     (i+outBitOffset)/8;
    size_t outBitPos  = 7 - (i+outBitOffset)%8;

    if (inBit) {
      out[outBytePos] |= (1<<outBitPos);
    }
    else {
      out[outBytePos] &= ~(1<<outBitPos);
    }
  }
}

static uint64_t make_timestamp(uint64_t offset) {
  struct timeval tv;
  gettimeofday(&tv, NULL);

  return ((tv.tv_sec - offset/1000)*1000 +
          tv.tv_usec/1000);
}

static uint64_t htonll(uint64_t value) {
  // See http://stackoverflow.com/questions/3022552/is-there-any-standard-htonl-like-function-for-64-bits-integers-in-c

  // The answer is 42
  static const int num = 42;

  // Check the endianness
  if (*reinterpret_cast<const char*>(&num) == num) {
    const uint32_t high_part = htonl(static_cast<uint32_t>(value >> 32));
    const uint32_t low_part = htonl(static_cast<uint32_t>(value & 0xFFFFFFFFLL));

    return (static_cast<uint64_t>(low_part) << 32) | high_part;
  }
  else {
    return value;
  }
}

flake::flake(const uint8_t *machineNumber,
             size_t machineNumberLength,
             size_t sequenceNumberLength,
             size_t timestampLength,
             uint64_t timeOffset) :
_machineNumber(machineNumber, machineNumber+((machineNumberLength+7)/8)),
_machineNumberLength(machineNumberLength),
_sequenceNumberLength(sequenceNumberLength),
_timestampLength(timestampLength),
_timeOffset(timeOffset),
_lastTimestamp(make_timestamp(timeOffset)),
_sequenceNumber(0),
_sequenceNumberOverflow(false) {
  if (_sequenceNumberLength > 8*sizeof(_sequenceNumber) ||
      _timestampLength > 8*sizeof(_timestampLength)) {
    abort();
  }
}

int flake::generate(size_t bufLen, uint8_t *buf) {
  if (bufLen < byte_length()) {
    // The buffer is too small
    return 3;
  }

  uint64_t timestamp = make_timestamp(_timeOffset);

  if (timestamp < _lastTimestamp - 1000) {
    // The timer has moved backwards by more than 1 second
    return 2;
  }

  if (timestamp < _lastTimestamp) {
    // The timer has moved backwards
    return 1;
  }

  uint64_t nextSequenceNumber;
  bool nextSequenceNumberHasOverflowed;

  if (timestamp == _lastTimestamp) {
    if (_sequenceNumberOverflow) {
      // Sequence number overflow
      return 1;
    }

    if (8*sizeof(_sequenceNumber) == _sequenceNumberLength) {
      nextSequenceNumber = _sequenceNumber+1;
    }
    else {
      nextSequenceNumber = (_sequenceNumber+1) % (1<<_sequenceNumberLength);
    }
    nextSequenceNumberHasOverflowed = (0 == nextSequenceNumber);
  }
  else {
    _sequenceNumber = 0;
    _lastTimestamp = timestamp;
    nextSequenceNumber = 1;
    nextSequenceNumberHasOverflowed = false;
  }

  uint64_t bigEndianTimestamp = htonll(timestamp);
  uint64_t bigEndianSequenceNumber = htonll(_sequenceNumber);

  bitmemcpy(/*out:*/buf,
            /*outBitOffset:*/0,
            /*in:*/(const uint8_t *)&bigEndianTimestamp,
            /*inBitOffset*/8*sizeof(bigEndianTimestamp)-_timestampLength,
            /*bitLength:*/_timestampLength);
  bitmemcpy(/*out:*/buf,
            /*outBitOffset:*/_timestampLength,
            /*in:*/(const uint8_t *)&bigEndianSequenceNumber,
            /*inBitOffset:*/8*sizeof(bigEndianSequenceNumber)-_sequenceNumberLength,
            /*bitLength:*/_sequenceNumberLength);
  bitmemcpy(/*out:*/buf,
            /*outBitOffset:*/_timestampLength+_sequenceNumberLength,
            /*in:*/&_machineNumber[0],
            /*inBitOffset:*/0,
            /*bitLength:*/_machineNumberLength);

  _sequenceNumber = nextSequenceNumber;
  _sequenceNumberOverflow = nextSequenceNumberHasOverflowed;

  return 0;
}
<|endoftext|>


<commit_before>/*******************************************************
 * Copyright (c) 2015-2019, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#include <fg/font.h>
#include <fg/exception.h>
#include <common.hpp>
#include <cmath>

#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>

#include <ft2build.h>
#include <freetype.h>
#include <ftglyph.h>
#include FT_FREETYPE_H

#ifndef WINDOWS_OS
#include <fontconfig/fontconfig.h>
#endif

static const char* gFontVertShader =
"#version 330\n"
"uniform mat4 projectionMatrix;\n"
"uniform mat4 modelViewMatrix;\n"
"layout (location = 0) in vec2 inPosition;\n"
"layout (location = 1) in vec2 inCoord;\n"
"out vec2 texCoord;\n"
"void main()\n"
"{\n"
"    gl_Position = projectionMatrix*modelViewMatrix*vec4(inPosition, 0.0, 1.0);\n"
"    texCoord = inCoord;\n"
"}\n";

static const char* gFontFragShader =
"#version 330\n"
"in vec2 texCoord;\n"
"out vec4 outputColor;\n"
"uniform sampler2D tex;\n"
"uniform vec4 textColor;\n"
"void main()\n"
"{\n"
"    vec4 texC = texture2D(tex, texCoord);\n"
"    vec4 alpha = vec4(1.0, 1.0, 1.0, texC.r);\n"
"    outputColor = alpha*textColor;\n"
"}\n";

/* freetype library types */
static FT_Library  gFTLib;
static FT_Face     gFTFace;

namespace fg
{

#define FT_THROW_ERROR(msg, err) \
    throw fg::Error("Freetype library", __LINE__, msg, err);

void Font::extractGlyph(int pCharacter)
{
    FT_Load_Glyph(gFTFace, FT_Get_Char_Index(gFTFace, pCharacter), FT_LOAD_DEFAULT);
    FT_Render_Glyph(gFTFace->glyph, FT_RENDER_MODE_NORMAL);
    FT_Bitmap& bitmap = gFTFace->glyph->bitmap;

    int pIndex = pCharacter - START_CHAR;

    int bmp_w = bitmap.width;
    int bmp_h = bitmap.rows;
    int w     = next_p2(bmp_w);
    int h     = next_p2(bmp_h);

    std::vector<unsigned char> glyphData(w*h, 0);
    for (int j=0; j<h; ++j) {
        for (int i=0; i<w; ++i) {
            glyphData[ (j*w+i) ] =
                (i<bmp_w && j<bmp_h ? bitmap.buffer[(bmp_h-1-j)*bmp_w+i] : 0);
        }
    }

    CheckGL("Before Character texture creation");
    // texture from it
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glGenTextures(1, &(mCharTextures[pIndex]));
    glBindTexture(GL_TEXTURE_2D, mCharTextures[pIndex]);
    glBindSampler(mCharTextures[pIndex], mSampler);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, w, h, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, &glyphData.front());
    glGenerateMipmap(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, 0);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    CheckGL("After Character texture creation");

    mAdvX[pIndex] = gFTFace->glyph->advance.x>>6;
    mBearingX[pIndex] = gFTFace->glyph->metrics.horiBearingX>>6;
    mCharWidth[pIndex] = gFTFace->glyph->metrics.width>>6;

    mAdvY[pIndex] = (gFTFace->glyph->metrics.height - gFTFace->glyph->metrics.horiBearingY)>>6;
    mBearingY[pIndex] = gFTFace->glyph->metrics.horiBearingY>>6;
    mCharHeight[pIndex] = gFTFace->glyph->metrics.height>>6;

    mNewLine = std::max(mNewLine, int(gFTFace->glyph->metrics.height>>6));

    // Rendering data, texture coordinates are always the same,
    // so now we waste a little memory
    float quad[8];
    float quad_texcoords[8] = { 0, 1, 0, 0, 1, 1, 1, 0};

    quad[0] = 0.0f; quad[1] = float(-mAdvY[pIndex]+h);
    quad[2] = 0.0f; quad[3] = float(-mAdvY[pIndex]);
    quad[4] = float(w); quad[5] = float(-mAdvY[pIndex]+h);
    quad[6] = float(w); quad[7] = float(-mAdvY[pIndex]);

    // texture coordinates are duplicated for each character
    // TODO work on removing this duplicates to reduce memory usage
    for (int i=0; i<4; ++i) {
        float* vert_ptr = quad+2*i;
        float* tex_ptr  = quad_texcoords+2*i;
        mVertexData.insert(mVertexData.end(), vert_ptr, vert_ptr+2);
        mVertexData.insert(mVertexData.end(), tex_ptr, tex_ptr+2);
    }
}

void Font::destroyGLResources()
{
    if (mIsFontLoaded) {
        if (mProgram) glDeleteProgram(mProgram);
        if (mVAO) glDeleteVertexArrays(1, &mVAO);
        if (mVBO) glDeleteBuffers(1, &mVBO);
        glDeleteTextures(NUM_CHARS, mCharTextures);
    }
}

Font::Font()
    : mIsFontLoaded(false), mTTFfile(""), mVAO(0), mVBO(0), mProgram(0), mSampler(0)
{
    mProgram = initShaders(gFontVertShader, gFontFragShader);

    memset(mCharTextures, 0, NUM_CHARS);

    glGenSamplers(1, &mSampler);
    glSamplerParameteri(mSampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glSamplerParameteri(mSampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glSamplerParameteri(mSampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glSamplerParameteri(mSampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}

Font::~Font()
{
    destroyGLResources();
    if (mProgram) glDeleteProgram(mProgram);
    if (mSampler) glDeleteSamplers(1, &mSampler);
}

void Font::loadFont(std::string pFile, int pFontSize)
{
    if (mIsFontLoaded) {
        if (pFile==mTTFfile)
            return;
        else {
            destroyGLResources();
            mIsFontLoaded = false;
        }
    }
    mLoadedPixelSize = pFontSize;

    CheckGL("Begin Font::loadFont");
    // Initialize freetype font library
    bool bError = FT_Init_FreeType(&gFTLib);

    bError = FT_New_Face(gFTLib, pFile.c_str(), 0, &gFTFace);
    if(bError) {
        FT_Done_FreeType(gFTLib);
        FT_THROW_ERROR("font face creation failed", FG_ERR_FREETYPE_ERROR);
    }

    bError = FT_Set_Pixel_Sizes(gFTFace, 0, pFontSize);
    if (bError) {
        FT_Done_Face(gFTFace);
        FT_Done_FreeType(gFTLib);
        FT_THROW_ERROR("set font size failed", FG_ERR_FREETYPE_ERROR);
    }

    // read font glyphs for only characters
    // from ' ' to '~'
    for (int i=START_CHAR; i<END_CHAR; ++i) extractGlyph(i);

    FT_Done_Face(gFTFace);
    FT_Done_FreeType(gFTLib);

    size_t size = sizeof(glm::vec2);

    mVBO = createBuffer<float>(mVertexData.size(), &mVertexData.front(), GL_STATIC_DRAW);

    glGenVertexArrays(1, &mVAO);
    glBindVertexArray(mVAO);
    glBindBuffer(GL_ARRAY_BUFFER, mVBO);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, size*2, 0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, size*2, (void*)(size));
    glBindVertexArray(0);

    mIsFontLoaded = true;
    mTTFfile = pFile;
    CheckGL("End Font::loadFont");
}

void Font::loadSystemFont(std::string pName, int pFontSize)
{
    //TODO do error checking once it is working
    std::string ttf_file_path;

#ifndef WINDOWS_OS
    // use fontconfig to get the file
    FcConfig* config = FcInitLoadConfigAndFonts();
    if (!config) {
        FT_THROW_ERROR("fontconfig initilization failed", FG_ERR_FREETYPE_ERROR);
    }
    // configure the search pattern,
    FcPattern* pat = FcNameParse((const FcChar8*)(pName.c_str()));
    if (!pat) {
        FT_THROW_ERROR("fontconfig pattern creation failed", FG_ERR_FREETYPE_ERROR);
    }

    FcConfigSubstitute(config, pat, FcMatchPattern);
    FcDefaultSubstitute(pat);

    // find the font
    FcResult res;
    FcPattern* font = FcFontMatch(config, pat, &res);

    FcConfigSubstitute(config, pat, FcMatchPattern);
    if (font) {
        FcChar8* file = NULL;
        if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) {
            // save the file to another std::string
            ttf_file_path = (char*)file;
        }
        FcPatternDestroy(font);
    }
    // destroy fontconfig pattern object
    FcPatternDestroy(pat);
#else
    char buf[512];
    GetWindowsDirectory(buf, 512);
    string ttf_file_path = buf;
    ttf_file_path += "\\Fonts\\";
    ttf_file_path += sName;
#endif

    loadFont(ttf_file_path, pFontSize);
}

void Font::setOthro2D(int pWidth, int pHeight)
{
    mHeight = pHeight;
    mWidth = pWidth;
}

void Font::render(const float pPos[], const float pColor[], std::string pText, int pFontSize, bool pIsVertical)
{
    if(!mIsFontLoaded)return;

    glDisable(GL_DEPTH_TEST);
    glDepthFunc(GL_ALWAYS);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glUseProgram(mProgram);
    GLuint pmat_loc = glGetUniformLocation(mProgram, "projectionMatrix");
    GLuint mvmat_loc = glGetUniformLocation(mProgram, "modelViewMatrix");
    GLuint tex_loc = glGetUniformLocation(mProgram, "tex");
    GLuint col_loc = glGetUniformLocation(mProgram, "textColor");

    glm::mat4 projMat = glm::ortho(0.0f, float(mWidth), 0.0f, float(mHeight));

    glUniformMatrix4fv(pmat_loc, 1, GL_FALSE, (GLfloat*)&projMat);
    glUniform4fv(col_loc, 1, pColor);

    int loc_x = pPos[0], loc_y = pPos[1];
    if(pFontSize == -1)pFontSize = mLoadedPixelSize;
    float scale_factor = float(pFontSize)/float(mLoadedPixelSize);

    for (std::string::iterator it=pText.begin(); it!=pText.end(); ++it) {
        char currChar = *it;

        if(currChar == '\n') {
            // if it is new line, move location to next line
            loc_x = pPos[0];
            loc_y -= mNewLine*pFontSize/mLoadedPixelSize;
        } else if (currChar <= '~' && currChar >= ' ') {
            // regular characters are rendered as textured quad
            int idx = int(currChar) - START_CHAR;
            loc_x += mBearingX[idx]*pFontSize/mLoadedPixelSize;

            glActiveTexture(GL_TEXTURE0);
            glUniform1i(tex_loc, 0);
            glBindTexture(GL_TEXTURE_2D, mCharTextures[idx]);

            /* rotate by 90 degress if we need
             * to render the characters vertically */
            glm::mat4 modelView = glm::translate(glm::mat4(1.0f),
                    glm::vec3(float(loc_x), float(loc_y), 0.0f));

            modelView = glm::scale(modelView, glm::vec3(scale_factor));
            glUniformMatrix4fv(mvmat_loc, 1, GL_FALSE, (GLfloat*)&modelView);

            // Draw letter
            glBindVertexArray(mVAO);
            glDrawArrays(GL_TRIANGLE_STRIP, idx*4, 4);
            CheckGL("Draw pCharacter");
            glBindVertexArray(0);

            loc_x += (mAdvX[idx]-mBearingX[idx])*pFontSize/mLoadedPixelSize;
        }
        /* if the text needs to be rendered vertically,
         * move the pen cursor to next line after each
         * character render mandatorily */
        if (pIsVertical) {
            loc_x = pPos[0];
            loc_y -= mNewLine*pFontSize/mLoadedPixelSize;
        }
    }

    glUseProgram(0);
    glDisable(GL_BLEND);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
}

}
<commit_msg>BUGFIX: corrected typos in windows platform specific code<commit_after>/*******************************************************
 * Copyright (c) 2015-2019, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#include <fg/font.h>
#include <fg/exception.h>
#include <common.hpp>
#include <cmath>
#include <algorithm>

#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>

#include <ft2build.h>
#include <freetype.h>
#include <ftglyph.h>
#include FT_FREETYPE_H

#ifndef WINDOWS_OS
#include <fontconfig/fontconfig.h>
#endif

static const char* gFontVertShader =
"#version 330\n"
"uniform mat4 projectionMatrix;\n"
"uniform mat4 modelViewMatrix;\n"
"layout (location = 0) in vec2 inPosition;\n"
"layout (location = 1) in vec2 inCoord;\n"
"out vec2 texCoord;\n"
"void main()\n"
"{\n"
"    gl_Position = projectionMatrix*modelViewMatrix*vec4(inPosition, 0.0, 1.0);\n"
"    texCoord = inCoord;\n"
"}\n";

static const char* gFontFragShader =
"#version 330\n"
"in vec2 texCoord;\n"
"out vec4 outputColor;\n"
"uniform sampler2D tex;\n"
"uniform vec4 textColor;\n"
"void main()\n"
"{\n"
"    vec4 texC = texture2D(tex, texCoord);\n"
"    vec4 alpha = vec4(1.0, 1.0, 1.0, texC.r);\n"
"    outputColor = alpha*textColor;\n"
"}\n";

/* freetype library types */
static FT_Library  gFTLib;
static FT_Face     gFTFace;

namespace fg
{

#define FT_THROW_ERROR(msg, err) \
    throw fg::Error("Freetype library", __LINE__, msg, err);

void Font::extractGlyph(int pCharacter)
{
    FT_Load_Glyph(gFTFace, FT_Get_Char_Index(gFTFace, pCharacter), FT_LOAD_DEFAULT);
    FT_Render_Glyph(gFTFace->glyph, FT_RENDER_MODE_NORMAL);
    FT_Bitmap& bitmap = gFTFace->glyph->bitmap;

    int pIndex = pCharacter - START_CHAR;

    int bmp_w = bitmap.width;
    int bmp_h = bitmap.rows;
    int w     = next_p2(bmp_w);
    int h     = next_p2(bmp_h);

    std::vector<unsigned char> glyphData(w*h, 0);
    for (int j=0; j<h; ++j) {
        for (int i=0; i<w; ++i) {
            glyphData[ (j*w+i) ] =
                (i<bmp_w && j<bmp_h ? bitmap.buffer[(bmp_h-1-j)*bmp_w+i] : 0);
        }
    }

    CheckGL("Before Character texture creation");
    // texture from it
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glGenTextures(1, &(mCharTextures[pIndex]));
    glBindTexture(GL_TEXTURE_2D, mCharTextures[pIndex]);
    glBindSampler(mCharTextures[pIndex], mSampler);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, w, h, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, &glyphData.front());
    glGenerateMipmap(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, 0);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    CheckGL("After Character texture creation");

    mAdvX[pIndex] = gFTFace->glyph->advance.x>>6;
    mBearingX[pIndex] = gFTFace->glyph->metrics.horiBearingX>>6;
    mCharWidth[pIndex] = gFTFace->glyph->metrics.width>>6;

    mAdvY[pIndex] = (gFTFace->glyph->metrics.height - gFTFace->glyph->metrics.horiBearingY)>>6;
    mBearingY[pIndex] = gFTFace->glyph->metrics.horiBearingY>>6;
    mCharHeight[pIndex] = gFTFace->glyph->metrics.height>>6;

    mNewLine = std::max(mNewLine, int(gFTFace->glyph->metrics.height>>6));

    // Rendering data, texture coordinates are always the same,
    // so now we waste a little memory
    float quad[8];
    float quad_texcoords[8] = { 0, 1, 0, 0, 1, 1, 1, 0};

    quad[0] = 0.0f; quad[1] = float(-mAdvY[pIndex]+h);
    quad[2] = 0.0f; quad[3] = float(-mAdvY[pIndex]);
    quad[4] = float(w); quad[5] = float(-mAdvY[pIndex]+h);
    quad[6] = float(w); quad[7] = float(-mAdvY[pIndex]);

    // texture coordinates are duplicated for each character
    // TODO work on removing this duplicates to reduce memory usage
    for (int i=0; i<4; ++i) {
        float* vert_ptr = quad+2*i;
        float* tex_ptr  = quad_texcoords+2*i;
        mVertexData.insert(mVertexData.end(), vert_ptr, vert_ptr+2);
        mVertexData.insert(mVertexData.end(), tex_ptr, tex_ptr+2);
    }
}

void Font::destroyGLResources()
{
    if (mIsFontLoaded) {
        if (mProgram) glDeleteProgram(mProgram);
        if (mVAO) glDeleteVertexArrays(1, &mVAO);
        if (mVBO) glDeleteBuffers(1, &mVBO);
        glDeleteTextures(NUM_CHARS, mCharTextures);
    }
}

Font::Font()
    : mIsFontLoaded(false), mTTFfile(""), mVAO(0), mVBO(0), mProgram(0), mSampler(0)
{
    mProgram = initShaders(gFontVertShader, gFontFragShader);

    memset(mCharTextures, 0, NUM_CHARS);

    glGenSamplers(1, &mSampler);
    glSamplerParameteri(mSampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glSamplerParameteri(mSampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glSamplerParameteri(mSampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glSamplerParameteri(mSampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}

Font::~Font()
{
    destroyGLResources();
    if (mProgram) glDeleteProgram(mProgram);
    if (mSampler) glDeleteSamplers(1, &mSampler);
}

void Font::loadFont(std::string pFile, int pFontSize)
{
    if (mIsFontLoaded) {
        if (pFile==mTTFfile)
            return;
        else {
            destroyGLResources();
            mIsFontLoaded = false;
        }
    }
    mLoadedPixelSize = pFontSize;

    CheckGL("Begin Font::loadFont");
    // Initialize freetype font library
    bool bError = FT_Init_FreeType(&gFTLib);

    bError = FT_New_Face(gFTLib, pFile.c_str(), 0, &gFTFace);
    if(bError) {
        FT_Done_FreeType(gFTLib);
        FT_THROW_ERROR("font face creation failed", FG_ERR_FREETYPE_ERROR);
    }

    bError = FT_Set_Pixel_Sizes(gFTFace, 0, pFontSize);
    if (bError) {
        FT_Done_Face(gFTFace);
        FT_Done_FreeType(gFTLib);
        FT_THROW_ERROR("set font size failed", FG_ERR_FREETYPE_ERROR);
    }

    // read font glyphs for only characters
    // from ' ' to '~'
    for (int i=START_CHAR; i<END_CHAR; ++i) extractGlyph(i);

    FT_Done_Face(gFTFace);
    FT_Done_FreeType(gFTLib);

    size_t size = sizeof(glm::vec2);

    mVBO = createBuffer<float>(mVertexData.size(), &mVertexData.front(), GL_STATIC_DRAW);

    glGenVertexArrays(1, &mVAO);
    glBindVertexArray(mVAO);
    glBindBuffer(GL_ARRAY_BUFFER, mVBO);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, size*2, 0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, size*2, (void*)(size));
    glBindVertexArray(0);

    mIsFontLoaded = true;
    mTTFfile = pFile;
    CheckGL("End Font::loadFont");
}

void Font::loadSystemFont(std::string pName, int pFontSize)
{
    //TODO do error checking once it is working
    std::string ttf_file_path;

#ifndef WINDOWS_OS
    // use fontconfig to get the file
    FcConfig* config = FcInitLoadConfigAndFonts();
    if (!config) {
        FT_THROW_ERROR("fontconfig initilization failed", FG_ERR_FREETYPE_ERROR);
    }
    // configure the search pattern,
    FcPattern* pat = FcNameParse((const FcChar8*)(pName.c_str()));
    if (!pat) {
        FT_THROW_ERROR("fontconfig pattern creation failed", FG_ERR_FREETYPE_ERROR);
    }

    FcConfigSubstitute(config, pat, FcMatchPattern);
    FcDefaultSubstitute(pat);

    // find the font
    FcResult res;
    FcPattern* font = FcFontMatch(config, pat, &res);

    FcConfigSubstitute(config, pat, FcMatchPattern);
    if (font) {
        FcChar8* file = NULL;
        if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) {
            // save the file to another std::string
            ttf_file_path = (char*)file;
        }
        FcPatternDestroy(font);
    }
    // destroy fontconfig pattern object
    FcPatternDestroy(pat);
#else
    char buf[512];
    GetWindowsDirectory(buf, 512);
    ttf_file_path = buf;
    ttf_file_path += "\\Fonts\\";
    ttf_file_path += pName;
    ttf_file_path += ".ttf";
#endif

    loadFont(ttf_file_path, pFontSize);
}

void Font::setOthro2D(int pWidth, int pHeight)
{
    mHeight = pHeight;
    mWidth = pWidth;
}

void Font::render(const float pPos[], const float pColor[], std::string pText, int pFontSize, bool pIsVertical)
{
    if(!mIsFontLoaded)return;

    glDisable(GL_DEPTH_TEST);
    glDepthFunc(GL_ALWAYS);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glUseProgram(mProgram);
    GLuint pmat_loc = glGetUniformLocation(mProgram, "projectionMatrix");
    GLuint mvmat_loc = glGetUniformLocation(mProgram, "modelViewMatrix");
    GLuint tex_loc = glGetUniformLocation(mProgram, "tex");
    GLuint col_loc = glGetUniformLocation(mProgram, "textColor");

    glm::mat4 projMat = glm::ortho(0.0f, float(mWidth), 0.0f, float(mHeight));

    glUniformMatrix4fv(pmat_loc, 1, GL_FALSE, (GLfloat*)&projMat);
    glUniform4fv(col_loc, 1, pColor);

    int loc_x = pPos[0], loc_y = pPos[1];
    if(pFontSize == -1)pFontSize = mLoadedPixelSize;
    float scale_factor = float(pFontSize)/float(mLoadedPixelSize);

    for (std::string::iterator it=pText.begin(); it!=pText.end(); ++it) {
        char currChar = *it;

        if(currChar == '\n') {
            // if it is new line, move location to next line
            loc_x = pPos[0];
            loc_y -= mNewLine*pFontSize/mLoadedPixelSize;
        } else if (currChar <= '~' && currChar >= ' ') {
            // regular characters are rendered as textured quad
            int idx = int(currChar) - START_CHAR;
            loc_x += mBearingX[idx]*pFontSize/mLoadedPixelSize;

            glActiveTexture(GL_TEXTURE0);
            glUniform1i(tex_loc, 0);
            glBindTexture(GL_TEXTURE_2D, mCharTextures[idx]);

            /* rotate by 90 degress if we need
             * to render the characters vertically */
            glm::mat4 modelView = glm::translate(glm::mat4(1.0f),
                    glm::vec3(float(loc_x), float(loc_y), 0.0f));

            modelView = glm::scale(modelView, glm::vec3(scale_factor));
            glUniformMatrix4fv(mvmat_loc, 1, GL_FALSE, (GLfloat*)&modelView);

            // Draw letter
            glBindVertexArray(mVAO);
            glDrawArrays(GL_TRIANGLE_STRIP, idx*4, 4);
            CheckGL("Draw pCharacter");
            glBindVertexArray(0);

            loc_x += (mAdvX[idx]-mBearingX[idx])*pFontSize/mLoadedPixelSize;
        }
        /* if the text needs to be rendered vertically,
         * move the pen cursor to next line after each
         * character render mandatorily */
        if (pIsVertical) {
            loc_x = pPos[0];
            loc_y -= mNewLine*pFontSize/mLoadedPixelSize;
        }
    }

    glUseProgram(0);
    glDisable(GL_BLEND);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
}

}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2004-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */
#include "fboss/agent/platforms/wedge/WedgeProductInfo.h"
#include "fboss/agent/FbossError.h"

#include <boost/algorithm/string.hpp>
#include <folly/FileUtil.h>
#include <folly/json.h>
#include <folly/dynamic.h>
#include <folly/MacAddress.h>

namespace {
constexpr auto kInfo = "Information";
constexpr auto kSysMfgDate = "System Manufacturing Date";
constexpr auto kSysMfg = "System Manufacturer";
constexpr auto kSysAmbPartNum = "System Assembly Part Number";
constexpr auto kAmbAt = "Assembled At";
constexpr auto kPcbMfg = "PCB Manufacturer";
constexpr auto kProdAssetTag = "Product Asset Tag";
constexpr auto kProdName = "Product Name";
constexpr auto kProdVersion = "Product Version";
constexpr auto kProductionState = "Product Production State";
constexpr auto kProdPartNum = "Product Part Number";
constexpr auto kSerialNum = "Product Serial Number";
constexpr auto kSubVersion = "Product Sub-Version";
constexpr auto kOdmPcbaPartNum = "ODM PCBA Part Number";
constexpr auto kOdmPcbaSerialNum = "ODM PCBA Serial Number";
constexpr auto kFbPcbaPartNum = "Facebook PCBA Part Number";
constexpr auto kFbPcbPartNum = "Facebook PCB Part Number";
constexpr auto kExtMacSize = "Extended MAC Address Size";
constexpr auto kExtMacBase = "Extended MAC Base";
constexpr auto kLocalMac = "Local MAC";
constexpr auto kVersion = "Version";
constexpr auto kFabricLocation = "Location on Fabric";
constexpr auto kFabricLocationLeft = "LEFT";
constexpr auto kFabricLocationRight = "RIGHT";
}

DEFINE_string(mode, "",
              "The mode the FBOSS controller is running as, wedge, lc, or fc");

namespace facebook { namespace fboss {

using folly::MacAddress;
using folly::StringPiece;
using folly::dynamic;
using folly::parseJson;

WedgeProductInfo::WedgeProductInfo(StringPiece path)
  : path_(path) {
}

void WedgeProductInfo::initialize() {
  try {
    std::string data;
    folly::readFile(path_.str().c_str(), data);
    parse(data);
  } catch (const std::exception& err) {
    LOG(ERROR) << err.what();
    // if fruid info fails fall back to fbwhoami
    initFromFbWhoAmI();
  }
  initMode();
}

void WedgeProductInfo::getInfo(ProductInfo& info) {
  info = productInfo_;
}

WedgePlatformMode WedgeProductInfo::getMode() const {
  return mode_;
}

std::string WedgeProductInfo::getFabricLocation() {
  return productInfo_.fabricLocation;
}

std::string WedgeProductInfo::getProductName() {
  return productInfo_.product;
}

void WedgeProductInfo::initMode() {
  if (FLAGS_mode.empty()) {
    auto modelName = getProductName();
    if (modelName.find("Wedge100") == 0 ||
               modelName.find("WEDGE100") == 0) {
      // Wedge100 comes from fruid.json, WEDGE100 comes from fbwhoami
      mode_ = WedgePlatformMode::WEDGE100;
    } else if (modelName.find("Wedge") == 0 ||
               modelName.find("WEDGE") == 0) {
      // Wedge100 comes from fruid.json, WEDGE comes from fbwhoami
      mode_ = WedgePlatformMode::WEDGE;
    } else if (modelName.find("SCM-LC") == 0 || modelName.find("LC") == 0) {
       // TODO remove LC once fruid.json is fixed on Galaxy Linecards
       mode_ = WedgePlatformMode::GALAXY_LC;
    } else if (modelName.find("SCM-FC") == 0 || modelName.find("FAB") == 0) {
       // TODO remove FAB once fruid.json is fixed on Galaxy fabric cards
       mode_ = WedgePlatformMode::GALAXY_FC;
    } else {
      throw std::runtime_error("invalid model name " + modelName);
    }
  } else {
    if (FLAGS_mode == "wedge") {
      mode_ = WedgePlatformMode::WEDGE;
    } else if (FLAGS_mode == "wedge100") {
      mode_ = WedgePlatformMode::WEDGE100;
    } else if (FLAGS_mode == "galaxy_lc") {
      mode_ = WedgePlatformMode::GALAXY_LC;
    } else if (FLAGS_mode == "galaxy_fc") {
      mode_ = WedgePlatformMode::GALAXY_FC;
    } else {
      throw std::runtime_error("invalid mode " + FLAGS_mode);
    }
  }
}

void WedgeProductInfo::parse(std::string data) {
  dynamic info = parseJson(data)[kInfo];
  productInfo_.oem = folly::to<std::string>(info[kSysMfg].asString());
  productInfo_.product = folly::to<std::string>(info[kProdName].asString());
  productInfo_.serial = folly::to<std::string>(info[kSerialNum].asString());
  productInfo_.mfgDate = folly::to<std::string>(info[kSysMfgDate].asString());
  productInfo_.systemPartNumber =
                      folly::to<std::string>(info[kSysAmbPartNum].asString());
  productInfo_.assembledAt = folly::to<std::string>(info[kAmbAt].asString());
  productInfo_.pcbManufacturer =
                              folly::to<std::string>(info[kPcbMfg].asString());
  productInfo_.assetTag =
                        folly::to<std::string>(info[kProdAssetTag].asString());
  productInfo_.partNumber =
                          folly::to<std::string>(info[kProdPartNum].asString());
  productInfo_.odmPcbaPartNumber = folly::to<std::string>
                                    (info[kOdmPcbaPartNum].asString());
  productInfo_.odmPcbaSerial = folly::to<std::string>
                                  (info[kOdmPcbaSerialNum].asString());
  productInfo_.fbPcbaPartNumber = folly::to<std::string>
                                    (info[kFbPcbaPartNum].asString());
  productInfo_.fbPcbPartNumber = folly::to<std::string>
                                    (info[kFbPcbPartNum].asString());

  productInfo_.fabricLocation = folly::to<std::string>
                                    (info[kFabricLocation].asString());
  // FB only - we apply custom logic to construct unique SN for
  // cases where we create multiple assets for a single physical
  // card in chassis.
  setFBSerial();
  productInfo_.version = info[kVersion].asInt();
  productInfo_.subVersion = info[kSubVersion].asInt();
  productInfo_.productionState = info[kProductionState].asInt();
  productInfo_.productVersion = info[kProdVersion].asInt();
  productInfo_.bmcMac = folly::to<std::string>(info[kLocalMac].asString());
  productInfo_.mgmtMac = folly::to<std::string>(info[kExtMacBase].asString());
  auto macBase = MacAddress(info[kExtMacBase].asString()).u64HBO() + 1;
  productInfo_.macRangeStart = MacAddress::fromHBO(macBase).toString();
  productInfo_.macRangeSize = info[kExtMacSize].asInt() - 1;
}

}} // facebook::fboss
<commit_msg>Handle parsing fruid.json when not indexed by "Information"<commit_after>/*
 *  Copyright (c) 2004-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */
#include "fboss/agent/platforms/wedge/WedgeProductInfo.h"
#include "fboss/agent/FbossError.h"

#include <boost/algorithm/string.hpp>
#include <folly/FileUtil.h>
#include <folly/json.h>
#include <folly/dynamic.h>
#include <folly/MacAddress.h>

namespace {
constexpr auto kInfo = "Information";
constexpr auto kSysMfgDate = "System Manufacturing Date";
constexpr auto kSysMfg = "System Manufacturer";
constexpr auto kSysAmbPartNum = "System Assembly Part Number";
constexpr auto kAmbAt = "Assembled At";
constexpr auto kPcbMfg = "PCB Manufacturer";
constexpr auto kProdAssetTag = "Product Asset Tag";
constexpr auto kProdName = "Product Name";
constexpr auto kProdVersion = "Product Version";
constexpr auto kProductionState = "Product Production State";
constexpr auto kProdPartNum = "Product Part Number";
constexpr auto kSerialNum = "Product Serial Number";
constexpr auto kSubVersion = "Product Sub-Version";
constexpr auto kOdmPcbaPartNum = "ODM PCBA Part Number";
constexpr auto kOdmPcbaSerialNum = "ODM PCBA Serial Number";
constexpr auto kFbPcbaPartNum = "Facebook PCBA Part Number";
constexpr auto kFbPcbPartNum = "Facebook PCB Part Number";
constexpr auto kExtMacSize = "Extended MAC Address Size";
constexpr auto kExtMacBase = "Extended MAC Base";
constexpr auto kLocalMac = "Local MAC";
constexpr auto kVersion = "Version";
constexpr auto kFabricLocation = "Location on Fabric";
constexpr auto kFabricLocationLeft = "LEFT";
constexpr auto kFabricLocationRight = "RIGHT";
}

DEFINE_string(mode, "",
              "The mode the FBOSS controller is running as, wedge, lc, or fc");

namespace facebook { namespace fboss {

using folly::MacAddress;
using folly::StringPiece;
using folly::dynamic;
using folly::parseJson;

WedgeProductInfo::WedgeProductInfo(StringPiece path)
  : path_(path) {
}

void WedgeProductInfo::initialize() {
  try {
    std::string data;
    folly::readFile(path_.str().c_str(), data);
    parse(data);
  } catch (const std::exception& err) {
    LOG(ERROR) << err.what();
    // if fruid info fails fall back to fbwhoami
    initFromFbWhoAmI();
  }
  initMode();
}

void WedgeProductInfo::getInfo(ProductInfo& info) {
  info = productInfo_;
}

WedgePlatformMode WedgeProductInfo::getMode() const {
  return mode_;
}

std::string WedgeProductInfo::getFabricLocation() {
  return productInfo_.fabricLocation;
}

std::string WedgeProductInfo::getProductName() {
  return productInfo_.product;
}

void WedgeProductInfo::initMode() {
  if (FLAGS_mode.empty()) {
    auto modelName = getProductName();
    if (modelName.find("Wedge100") == 0 ||
               modelName.find("WEDGE100") == 0) {
      // Wedge100 comes from fruid.json, WEDGE100 comes from fbwhoami
      mode_ = WedgePlatformMode::WEDGE100;
    } else if (modelName.find("Wedge") == 0 ||
               modelName.find("WEDGE") == 0) {
      // Wedge100 comes from fruid.json, WEDGE comes from fbwhoami
      mode_ = WedgePlatformMode::WEDGE;
    } else if (modelName.find("SCM-LC") == 0 || modelName.find("LC") == 0) {
       // TODO remove LC once fruid.json is fixed on Galaxy Linecards
       mode_ = WedgePlatformMode::GALAXY_LC;
    } else if (
        modelName.find("SCM-FC") == 0 || modelName.find("SCM-FAB") == 0 ||
        modelName.find("FAB") == 0) {
      // TODO remove FAB once fruid.json is fixed on Galaxy fabric cards
      mode_ = WedgePlatformMode::GALAXY_FC;
    } else {
      throw std::runtime_error("invalid model name " + modelName);
    }
  } else {
    if (FLAGS_mode == "wedge") {
      mode_ = WedgePlatformMode::WEDGE;
    } else if (FLAGS_mode == "wedge100") {
      mode_ = WedgePlatformMode::WEDGE100;
    } else if (FLAGS_mode == "galaxy_lc") {
      mode_ = WedgePlatformMode::GALAXY_LC;
    } else if (FLAGS_mode == "galaxy_fc") {
      mode_ = WedgePlatformMode::GALAXY_FC;
    } else {
      throw std::runtime_error("invalid mode " + FLAGS_mode);
    }
  }
}

void WedgeProductInfo::parse(std::string data) {
  dynamic info;
  try {
    info = parseJson(data).at(kInfo);
  } catch (const std::exception& err) {
    LOG(ERROR) << err.what();
    // Handle fruid data present outside of "Information" i.e.
    // {
    //   "Information" : fruid json
    // }
    // vs
    // {
    //  Fruid json
    // }
    info = parseJson(data);
  }
  productInfo_.oem = folly::to<std::string>(info[kSysMfg].asString());
  productInfo_.product = folly::to<std::string>(info[kProdName].asString());
  productInfo_.serial = folly::to<std::string>(info[kSerialNum].asString());
  productInfo_.mfgDate = folly::to<std::string>(info[kSysMfgDate].asString());
  productInfo_.systemPartNumber =
                      folly::to<std::string>(info[kSysAmbPartNum].asString());
  productInfo_.assembledAt = folly::to<std::string>(info[kAmbAt].asString());
  productInfo_.pcbManufacturer =
                              folly::to<std::string>(info[kPcbMfg].asString());
  productInfo_.assetTag =
                        folly::to<std::string>(info[kProdAssetTag].asString());
  productInfo_.partNumber =
                          folly::to<std::string>(info[kProdPartNum].asString());
  productInfo_.odmPcbaPartNumber = folly::to<std::string>
                                    (info[kOdmPcbaPartNum].asString());
  productInfo_.odmPcbaSerial = folly::to<std::string>
                                  (info[kOdmPcbaSerialNum].asString());
  productInfo_.fbPcbaPartNumber = folly::to<std::string>
                                    (info[kFbPcbaPartNum].asString());
  productInfo_.fbPcbPartNumber = folly::to<std::string>
                                    (info[kFbPcbPartNum].asString());

  productInfo_.fabricLocation = folly::to<std::string>
                                    (info[kFabricLocation].asString());
  // FB only - we apply custom logic to construct unique SN for
  // cases where we create multiple assets for a single physical
  // card in chassis.
  setFBSerial();
  productInfo_.version = info[kVersion].asInt();
  productInfo_.subVersion = info[kSubVersion].asInt();
  productInfo_.productionState = info[kProductionState].asInt();
  productInfo_.productVersion = info[kProdVersion].asInt();
  productInfo_.bmcMac = folly::to<std::string>(info[kLocalMac].asString());
  productInfo_.mgmtMac = folly::to<std::string>(info[kExtMacBase].asString());
  auto macBase = MacAddress(info[kExtMacBase].asString()).u64HBO() + 1;
  productInfo_.macRangeStart = MacAddress::fromHBO(macBase).toString();
  productInfo_.macRangeSize = info[kExtMacSize].asInt() - 1;
}

}} // facebook::fboss
<|endoftext|>


<commit_before>#include <ncurses.h>

#include <string>

using namespace std;

void menuShow(WINDOW *wnd, string title);
void startGame();

WINDOW *wmenu, *wmain, *winfo;

int init() {

    initscr();

    /*
     * init main window
     */

    wmain = newwin(40, 80, 1, 1);
    box(wmain, 0, 0);

    /*
     * init info window
     * TODO
     *  [_] allow multiple info lines
     *  [_] delete oldest line when full
     *  [_] don't clear borders
     */

    winfo = newwin(10, 80, 40 + 1, 1);
    box(winfo, 0, 0);

    /*
     * init menu window
     */

    wmenu = newwin(10, 12, 10, 10);
    wborder(wmenu,
            ACS_BULLET, ACS_BULLET, ACS_BULLET, ACS_BULLET,     /* ls, rs, ts, bs */
            '+', '+', '+', '+');                                /* tl, tr, bl, br */

    return 0;
}

void run() {
    char menuItems[2][10] = {
        "start",
        "quit"
    };
    char menuItem[7];
    int ch, i = 0, width = 7;

    /*
     * init title, menu
     */

    for (i = 0; i < 2; i++) {
        if (i == 0) wattron(wmenu, A_STANDOUT);
        else wattroff(wmenu, A_STANDOUT);

        sprintf(menuItem, "%-7s", menuItems[i]);
        mvwprintw(wmenu, i + 1, 2, "%s", menuItem);
    }

    wrefresh(wmain);
    wrefresh(wmenu);
    wrefresh(winfo);
    menuShow(wmain, "TERMINAL QUEST");
    i = 0;
    noecho();
    keypad(wmenu, true);
    curs_set(0);

    string infoPos, infoKey, infoMsg;
    bool exitRequested = false, gameRequested = false;
    while (( ch = wgetch(wmenu)) != 'q') {
        infoPos = to_string(ch);
        infoKey = to_string(i);

        box(winfo, 0, 0);
        wmove(winfo, 1, 1);
        wprintw(winfo, (infoPos + ' ' + infoKey + ' ' + infoMsg).c_str());

        sprintf(menuItem, "%-7s", menuItems[i]);
        mvwprintw(wmenu, i + 1, 2, "%s", menuItem);
        switch (ch) {
            case KEY_UP:
            case 'k':
                i--;
                i = (i < 0) ? 1 : i;
                break;
            case KEY_DOWN:
            case 'j':
                i++;
                i = (i > 1) ? 0: i;
                break;
            case KEY_ENTER: /* numpad enter */
            case '\n':      /* keyboard return */
                if (i == 1) exitRequested = true;
                else if (i == 0) gameRequested = true;
                break;

        }
        wmove(winfo, 1, 1);
        wrefresh(winfo);
        werase(winfo);

        wattron(wmenu, A_STANDOUT);
        sprintf(menuItem, "%-7s", menuItems[i]);
        mvwprintw(wmenu, i + 1, 2, "%s", menuItem);
        wattroff(wmenu, A_STANDOUT);

        if (exitRequested == true) {
            break;
        } else if (gameRequested) {
            delwin(wmenu);
            delwin(wmain);
            delwin(winfo);
            startGame();
            break;
        }
    }

    /*
     * exit
     */

    endwin();

}

void close() {
    endwin();
}

void menuShow(WINDOW *wnd, string title) {

    wmove(wnd, 5, 5);

    for (size_t i = 0; i < title.size(); i++) {
        waddch(wnd, title[i]);
        waddch(wnd, ' ');
    }

    wrefresh(wnd);
}

void startGame() {
    endwin();

    WINDOW *wgame = newwin(40, 80, 1, 1);
    box(wgame, '-', '.');
    wrefresh(wgame);

    keypad(wgame, true);

    wmove(wgame, 1, 1);
    int ch, i;
    while (( ch = wgetch(wgame)) != 'q') {
        waddstr(wgame, to_string(ch).c_str());
        wmove(wgame, 1, 1);
    }
    delwin(wgame);
}

<commit_msg>Move ncurses init builtins to actual init function<commit_after>#include <ncurses.h>

#include <string>

using namespace std;

void menuShow(WINDOW *wnd, string title);
void startGame();

WINDOW *wmenu, *wmain, *winfo;

int init() {

    initscr();

    /*
     * init main window
     */

    wmain = newwin(40, 80, 1, 1);
    box(wmain, 0, 0);

    /*
     * init info window
     * TODO
     *  [_] allow multiple info lines
     *  [_] delete oldest line when full
     *  [_] don't clear borders
     */

    winfo = newwin(10, 80, 40 + 1, 1);
    box(winfo, 0, 0);

    /*
     * init menu window
     */

    wmenu = newwin(10, 12, 10, 10);
    wborder(wmenu,
            ACS_BULLET, ACS_BULLET, ACS_BULLET, ACS_BULLET,     /* ls, rs, ts, bs */
            '+', '+', '+', '+');                                /* tl, tr, bl, br */

    noecho();
    keypad(wmenu, true);
    curs_set(0);

    return 0;
}

void run() {
    char menuItems[2][10] = {
        "start",
        "quit"
    };
    char menuItem[7];
    int ch, i = 0, width = 7;

    /*
     * init title, menu
     */

    for (i = 0; i < 2; i++) {
        if (i == 0) wattron(wmenu, A_STANDOUT);
        else wattroff(wmenu, A_STANDOUT);

        sprintf(menuItem, "%-7s", menuItems[i]);
        mvwprintw(wmenu, i + 1, 2, "%s", menuItem);
    }

    wrefresh(wmain);
    wrefresh(wmenu);
    wrefresh(winfo);
    menuShow(wmain, "TERMINAL QUEST");
    i = 0;

    string infoPos, infoKey, infoMsg;
    bool exitRequested = false, gameRequested = false;
    while (( ch = wgetch(wmenu)) != 'q') {
        infoPos = to_string(ch);
        infoKey = to_string(i);

        box(winfo, 0, 0);
        wmove(winfo, 1, 1);
        wprintw(winfo, (infoPos + ' ' + infoKey + ' ' + infoMsg).c_str());

        sprintf(menuItem, "%-7s", menuItems[i]);
        mvwprintw(wmenu, i + 1, 2, "%s", menuItem);
        switch (ch) {
            case KEY_UP:
            case 'k':
                i--;
                i = (i < 0) ? 1 : i;
                break;
            case KEY_DOWN:
            case 'j':
                i++;
                i = (i > 1) ? 0: i;
                break;
            case KEY_ENTER: /* numpad enter */
            case '\n':      /* keyboard return */
                if (i == 1) exitRequested = true;
                else if (i == 0) gameRequested = true;
                break;

        }
        wmove(winfo, 1, 1);
        wrefresh(winfo);
        werase(winfo);

        wattron(wmenu, A_STANDOUT);
        sprintf(menuItem, "%-7s", menuItems[i]);
        mvwprintw(wmenu, i + 1, 2, "%s", menuItem);
        wattroff(wmenu, A_STANDOUT);

        if (exitRequested == true) {
            break;
        } else if (gameRequested) {
            delwin(wmenu);
            delwin(wmain);
            delwin(winfo);
            startGame();
            break;
        }
    }

    /*
     * exit
     */

    endwin();

}

void close() {
    endwin();
}

void menuShow(WINDOW *wnd, string title) {

    wmove(wnd, 5, 5);

    for (size_t i = 0; i < title.size(); i++) {
        waddch(wnd, title[i]);
        waddch(wnd, ' ');
    }

    wrefresh(wnd);
}

void startGame() {
    endwin();

    WINDOW *wgame = newwin(40, 80, 1, 1);
    box(wgame, '-', '.');
    wrefresh(wgame);

    keypad(wgame, true);

    wmove(wgame, 1, 1);
    int ch, i;
    while (( ch = wgetch(wgame)) != 'q') {
        waddstr(wgame, to_string(ch).c_str());
        wmove(wgame, 1, 1);
    }
    delwin(wgame);
}

<|endoftext|>