<commit_before>/*
GpuRamDrive proxy for ImDisk Virtual Disk Driver.

Copyright (C) 2016 Syahmi Azhar.

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

#include "stdafx.h"
#include <imdisk/imdisk.h>
#include <imdisk/imdproxy.h>
#include "GpuRamDrive.h"

#define TEST_HOST_RAM 0
char* pBuff = nullptr;

GPURamDrive::GPURamDrive()
	: m_MemSize(0)
	, m_Context(nullptr)
	, m_Queue(nullptr)
	, m_GpuMem(nullptr)
	, m_ImdDrive(INVALID_HANDLE_VALUE)
	, m_ShmHandle(NULL)
	, m_ShmMutexSrv(NULL)
	, m_ShmReqEvent(NULL)
	, m_ShmRespEvent(NULL)
	, m_ShmView(nullptr)
{

}

GPURamDrive::~GPURamDrive()
{
	Close();
}

void GPURamDrive::RefreshGPUInfo()
{
	cl_int clRet;
	cl_platform_id platforms[8];
	cl_uint numPlatforms;

	if ((clRet = clGetPlatformIDs(4, platforms, &numPlatforms)) != CL_SUCCESS) {
		throw std::runtime_error(std::string("Unable to get platform IDs: ") + std::to_string(clRet));
	}

	for (cl_uint i = 0; i < numPlatforms; i++) {
		cl_device_id devices[16];
		cl_uint numDevices;
		char szPlatformName[64] = { 0 };

		if ((clRet = clGetPlatformInfo(platforms[i], CL_PLATFORM_NAME, sizeof(szPlatformName), szPlatformName, nullptr)) != CL_SUCCESS) {
			continue;
		}

		if ((clRet = clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_GPU | CL_DEVICE_TYPE_ACCELERATOR, 16, devices, &numDevices)) != CL_SUCCESS) {
			continue;
		}

		for (cl_uint j = 0; j < numDevices; j++) {
			TGPUDevice GpuDevices;
			char szDevName[64] = { 0 };

			if ((clRet = clGetDeviceInfo(devices[j], CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(cl_ulong), &GpuDevices.memsize, nullptr)) != CL_SUCCESS) {
				continue;
			}

			if ((clRet = clGetDeviceInfo(devices[j], CL_DEVICE_NAME, sizeof(szDevName), szDevName, nullptr)) != CL_SUCCESS) {
				continue;
			}

			GpuDevices.platform_id = platforms[i];
			GpuDevices.device_id = devices[j];
			GpuDevices.name = szPlatformName + std::string(" - ") + szDevName;
			m_Devices.push_back(GpuDevices);
		}
	}
}

const std::vector<TGPUDevice>& GPURamDrive::GetGpuDevices()
{
	return m_Devices;
}

void GPURamDrive::CreateRamDevice(cl_platform_id PlatformId, cl_device_id DeviceId, const std::wstring& ServiceName, safeio_size_t MemSize, const wchar_t* MountPoint)
{
	m_PlatformId = PlatformId;
	m_DeviceId = DeviceId;
	m_MemSize = MemSize;
	m_ServiceName = ServiceName;

	std::exception state_ex;
	std::atomic<int> state = 0;

	m_GpuThread = std::thread([&]() {
		try
		{
			GpuAllocateRam();
			ImdiskSetupComm(ServiceName);
			state = 1;
			ImdiskHandleComm();
		}
		catch (const std::exception& ex)
		{
			Close();
			state_ex = ex;
			state = 2;
		}
	});

	while (state == 0) {
		Sleep(1);
	}

	if (state == 2) {
		if (m_GpuThread.joinable()) m_GpuThread.join();
		throw state_ex;
	}

	ImdiskMountDevice(MountPoint);
	if (m_StateChangeCallback) m_StateChangeCallback();
}

void GPURamDrive::ImdiskMountDevice(const wchar_t* MountPoint)
{
	DISK_GEOMETRY dskGeom = { 0 };

	ImDiskSetAPIFlags(IMDISK_API_FORCE_DISMOUNT);

	m_MountPoint = MountPoint;
	if (!ImDiskCreateDevice(NULL, &dskGeom, nullptr, IMDISK_TYPE_PROXY | IMDISK_PROXY_TYPE_SHM | IMDISK_DEVICE_TYPE_HD, m_ServiceName.c_str(), FALSE, (LPWSTR)MountPoint)) {
		throw std::runtime_error("Unable to create and mount ImDisk drive");
	}
}

void GPURamDrive::ImdiskUnmountDevice()
{
	if (m_MountPoint.length() == 0) return;

	ImDiskRemoveDevice(NULL, 0, m_MountPoint.c_str());
	m_MountPoint.clear();
}

void GPURamDrive::Close()
{
	ImdiskUnmountDevice();

	if (m_GpuThread.get_id() != std::this_thread::get_id()) {
		if (m_GpuThread.joinable()) m_GpuThread.join();
	}

	if (m_ShmView) UnmapViewOfFile(m_ShmView);
	if (m_ShmHandle) CloseHandle(m_ShmHandle);
	if (m_ShmMutexSrv) CloseHandle(m_ShmMutexSrv);
	if (m_ShmReqEvent) CloseHandle(m_ShmReqEvent);
	if (m_ShmRespEvent) CloseHandle(m_ShmRespEvent);

	if (m_GpuMem) clReleaseMemObject(m_GpuMem);
	if (m_Queue) clReleaseCommandQueue(m_Queue);
	if (m_Context) clReleaseContext(m_Context);

	m_ShmView = nullptr;
	m_ShmHandle = NULL;
	m_ShmMutexSrv = NULL;
	m_ShmReqEvent = NULL;
	m_ShmRespEvent = NULL;

	m_GpuMem = nullptr;
	m_Queue = nullptr;
	m_Context = nullptr;
	m_MemSize = 0;

	if (m_StateChangeCallback) m_StateChangeCallback();
}

bool GPURamDrive::IsMounted()
{
	return m_MountPoint.size() != 0 && m_ShmView != nullptr;
}

void GPURamDrive::SetStateChangeCallback(const std::function<void()> callback)
{
	m_StateChangeCallback = callback;
}

void GPURamDrive::GpuAllocateRam()
{
	cl_int clRet;

	m_Context = clCreateContext(nullptr, 1, &m_DeviceId, nullptr, nullptr, &clRet);
	if (m_Context == nullptr) {
		throw std::runtime_error("Unable to create context: " + std::to_string(clRet));
	}

	m_Queue = clCreateCommandQueue(m_Context, m_DeviceId, 0, &clRet);
	if (m_Queue == nullptr) {
		throw std::runtime_error("Unable to create command queue: " + std::to_string(clRet));
	}

	m_GpuMem = clCreateBuffer(m_Context, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, m_MemSize, nullptr, &clRet);
	if (m_GpuMem == nullptr) {
		throw std::runtime_error("Unable to create memory buffer: " + std::to_string(clRet));
	}
}

safeio_ssize_t GPURamDrive::GpuWrite(void *buf, safeio_size_t size, off_t_64 offset)
{
#if TEST_HOST_RAM
	memcpy(pBuff + offset, buf, size);
	return size;
#else
	if (clEnqueueWriteBuffer(m_Queue, m_GpuMem, CL_TRUE, offset, size, buf, 0, nullptr, nullptr) != CL_SUCCESS) {
		return 0;
	}

	return size;
#endif
}

safeio_ssize_t GPURamDrive::GpuRead(void *buf, safeio_size_t size, off_t_64 offset)
{
#if TEST_HOST_RAM
	memcpy(buf, pBuff + offset, size);
	return size;
#else
	if (clEnqueueReadBuffer(m_Queue, m_GpuMem, CL_TRUE, offset, size, buf, 0, nullptr, nullptr) != CL_SUCCESS) {
		return 0;
	}

	return size;
#endif
}

void GPURamDrive::ImdiskSetupComm(const std::wstring& ServiceName)
{
	MEMORY_BASIC_INFORMATION MemInfo;
	ULARGE_INTEGER MapSize;
	DWORD dwErr;
	std::wstring sTemp;
	const std::wstring sPrefix = L"Global\\";

	m_BufSize = (2 << 20);
	MapSize.QuadPart = m_BufSize + IMDPROXY_HEADER_SIZE;

	sTemp = sPrefix + ServiceName;
	m_ShmHandle = CreateFileMapping(INVALID_HANDLE_VALUE,
		NULL,
		PAGE_READWRITE | SEC_COMMIT,
		MapSize.HighPart,
		MapSize.LowPart,
		sTemp.c_str());
	dwErr = GetLastError();
	if (m_ShmHandle == NULL) {
		throw std::runtime_error("Unable to create file mapping: " + std::to_string(dwErr));
	}

	if (dwErr == ERROR_ALREADY_EXISTS) {
		throw std::runtime_error("A service with this name is already running or is still being used by ImDisk");
	}

	m_ShmView = MapViewOfFile(m_ShmHandle, FILE_MAP_WRITE, 0, 0, 0);
	if (m_ShmView == nullptr) {
		dwErr = GetLastError();
		throw std::runtime_error("Unable to map view of shared memory: " + std::to_string(dwErr));
	}

	if (!VirtualQuery(m_ShmView, &MemInfo, sizeof(MemInfo))) {
		dwErr = GetLastError();
		throw std::runtime_error("Unable to query memory info: " + std::to_string(dwErr));
	}

	m_BufStart = (char*)m_ShmView + IMDPROXY_HEADER_SIZE;

	sTemp = sPrefix + ServiceName + L"_Server";
	m_ShmMutexSrv = CreateMutex(NULL, FALSE, sTemp.c_str());
	if (m_ShmMutexSrv == NULL) {
		dwErr = GetLastError();
		throw std::runtime_error("Unable to create mutex object: " + std::to_string(dwErr));
	}

	if (WaitForSingleObject(m_ShmMutexSrv, 0) != WAIT_OBJECT_0) {
		throw std::runtime_error("A service with this name is already running");
	}

	sTemp = sPrefix + ServiceName + L"_Request";
	m_ShmReqEvent = CreateEvent(NULL, FALSE, FALSE, sTemp.c_str());
	if (m_ShmReqEvent == NULL) {
		dwErr = GetLastError();
		throw std::runtime_error("Unable to create request event object: " + std::to_string(dwErr));
	}

	sTemp = sPrefix + ServiceName + L"_Response";
	m_ShmRespEvent = CreateEvent(NULL, FALSE, FALSE, sTemp.c_str());
	if (m_ShmRespEvent == NULL) {
		dwErr = GetLastError();
		throw std::runtime_error("Unable to create response event object: " + std::to_string(dwErr));
	}
}

void GPURamDrive::ImdiskHandleComm()
{
	PIMDPROXY_READ_REQ Req = (PIMDPROXY_READ_REQ)m_ShmView;
	PIMDPROXY_READ_RESP Resp = (PIMDPROXY_READ_RESP)m_ShmView;

	for (;;)
	{
		if (WaitForSingleObject(m_ShmReqEvent, INFINITE) != WAIT_OBJECT_0) {
			return;
		}

		switch (Req->request_code)
		{
			case IMDPROXY_REQ_INFO:
			{
				PIMDPROXY_INFO_RESP resp = (PIMDPROXY_INFO_RESP)m_ShmView;
				resp->file_size = m_MemSize;
				resp->req_alignment = 1;
				resp->flags = 0;
				break;
			}

			case IMDPROXY_REQ_READ:
			{
				Resp->errorno = 0;
				Resp->length = GpuRead(m_BufStart, (safeio_size_t)(Req->length < m_BufSize ? Req->length : m_BufSize), Req->offset);

				break;
			}

			case IMDPROXY_REQ_WRITE:
			{
				Resp->errorno = 0;
				Resp->length = GpuWrite(m_BufStart, (safeio_size_t)(Req->length < m_BufSize ? Req->length : m_BufSize), Req->offset);

				break;
			}

			case IMDPROXY_REQ_CLOSE:
				return;

			default:
				Req->request_code = ENODEV;
		}

		if (!SetEvent(m_ShmRespEvent)) {
			return;
		}
	}
}
<commit_msg>Ignore truncated warnings.<commit_after>/*
GpuRamDrive proxy for ImDisk Virtual Disk Driver.

Copyright (C) 2016 Syahmi Azhar.

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

#include "stdafx.h"
#include <imdisk/imdisk.h>
#include <imdisk/imdproxy.h>
#include "GpuRamDrive.h"

#define TEST_HOST_RAM 0
char* pBuff = nullptr;

GPURamDrive::GPURamDrive()
	: m_MemSize(0)
	, m_Context(nullptr)
	, m_Queue(nullptr)
	, m_GpuMem(nullptr)
	, m_ImdDrive(INVALID_HANDLE_VALUE)
	, m_ShmHandle(NULL)
	, m_ShmMutexSrv(NULL)
	, m_ShmReqEvent(NULL)
	, m_ShmRespEvent(NULL)
	, m_ShmView(nullptr)
{

}

GPURamDrive::~GPURamDrive()
{
	Close();
}

void GPURamDrive::RefreshGPUInfo()
{
	cl_int clRet;
	cl_platform_id platforms[8];
	cl_uint numPlatforms;

	if ((clRet = clGetPlatformIDs(4, platforms, &numPlatforms)) != CL_SUCCESS) {
		throw std::runtime_error(std::string("Unable to get platform IDs: ") + std::to_string(clRet));
	}

	for (cl_uint i = 0; i < numPlatforms; i++) {
		cl_device_id devices[16];
		cl_uint numDevices;
		char szPlatformName[64] = { 0 };

		if ((clRet = clGetPlatformInfo(platforms[i], CL_PLATFORM_NAME, sizeof(szPlatformName), szPlatformName, nullptr)) != CL_SUCCESS) {
			continue;
		}

		if ((clRet = clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_GPU | CL_DEVICE_TYPE_ACCELERATOR, 16, devices, &numDevices)) != CL_SUCCESS) {
			continue;
		}

		for (cl_uint j = 0; j < numDevices; j++) {
			TGPUDevice GpuDevices;
			char szDevName[64] = { 0 };

			if ((clRet = clGetDeviceInfo(devices[j], CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(cl_ulong), &GpuDevices.memsize, nullptr)) != CL_SUCCESS) {
				continue;
			}

			if ((clRet = clGetDeviceInfo(devices[j], CL_DEVICE_NAME, sizeof(szDevName), szDevName, nullptr)) != CL_SUCCESS) {
				continue;
			}

			GpuDevices.platform_id = platforms[i];
			GpuDevices.device_id = devices[j];
			GpuDevices.name = szPlatformName + std::string(" - ") + szDevName;
			m_Devices.push_back(GpuDevices);
		}
	}
}

const std::vector<TGPUDevice>& GPURamDrive::GetGpuDevices()
{
	return m_Devices;
}

void GPURamDrive::CreateRamDevice(cl_platform_id PlatformId, cl_device_id DeviceId, const std::wstring& ServiceName, safeio_size_t MemSize, const wchar_t* MountPoint)
{
	m_PlatformId = PlatformId;
	m_DeviceId = DeviceId;
	m_MemSize = MemSize;
	m_ServiceName = ServiceName;

	std::exception state_ex;
	std::atomic<int> state = 0;

	m_GpuThread = std::thread([&]() {
		try
		{
			GpuAllocateRam();
			ImdiskSetupComm(ServiceName);
			state = 1;
			ImdiskHandleComm();
		}
		catch (const std::exception& ex)
		{
			Close();
			state_ex = ex;
			state = 2;
		}
	});

	while (state == 0) {
		Sleep(1);
	}

	if (state == 2) {
		if (m_GpuThread.joinable()) m_GpuThread.join();
		throw state_ex;
	}

	ImdiskMountDevice(MountPoint);
	if (m_StateChangeCallback) m_StateChangeCallback();
}

void GPURamDrive::ImdiskMountDevice(const wchar_t* MountPoint)
{
	DISK_GEOMETRY dskGeom = { 0 };

	ImDiskSetAPIFlags(IMDISK_API_FORCE_DISMOUNT);

	m_MountPoint = MountPoint;
	if (!ImDiskCreateDevice(NULL, &dskGeom, nullptr, IMDISK_TYPE_PROXY | IMDISK_PROXY_TYPE_SHM | IMDISK_DEVICE_TYPE_HD, m_ServiceName.c_str(), FALSE, (LPWSTR)MountPoint)) {
		throw std::runtime_error("Unable to create and mount ImDisk drive");
	}
}

void GPURamDrive::ImdiskUnmountDevice()
{
	if (m_MountPoint.length() == 0) return;

	ImDiskRemoveDevice(NULL, 0, m_MountPoint.c_str());
	m_MountPoint.clear();
}

void GPURamDrive::Close()
{
	ImdiskUnmountDevice();

	if (m_GpuThread.get_id() != std::this_thread::get_id()) {
		if (m_GpuThread.joinable()) m_GpuThread.join();
	}

	if (m_ShmView) UnmapViewOfFile(m_ShmView);
	if (m_ShmHandle) CloseHandle(m_ShmHandle);
	if (m_ShmMutexSrv) CloseHandle(m_ShmMutexSrv);
	if (m_ShmReqEvent) CloseHandle(m_ShmReqEvent);
	if (m_ShmRespEvent) CloseHandle(m_ShmRespEvent);

	if (m_GpuMem) clReleaseMemObject(m_GpuMem);
	if (m_Queue) clReleaseCommandQueue(m_Queue);
	if (m_Context) clReleaseContext(m_Context);

	m_ShmView = nullptr;
	m_ShmHandle = NULL;
	m_ShmMutexSrv = NULL;
	m_ShmReqEvent = NULL;
	m_ShmRespEvent = NULL;

	m_GpuMem = nullptr;
	m_Queue = nullptr;
	m_Context = nullptr;
	m_MemSize = 0;

	if (m_StateChangeCallback) m_StateChangeCallback();
}

bool GPURamDrive::IsMounted()
{
	return m_MountPoint.size() != 0 && m_ShmView != nullptr;
}

void GPURamDrive::SetStateChangeCallback(const std::function<void()> callback)
{
	m_StateChangeCallback = callback;
}

void GPURamDrive::GpuAllocateRam()
{
	cl_int clRet;

	m_Context = clCreateContext(nullptr, 1, &m_DeviceId, nullptr, nullptr, &clRet);
	if (m_Context == nullptr) {
		throw std::runtime_error("Unable to create context: " + std::to_string(clRet));
	}

	m_Queue = clCreateCommandQueue(m_Context, m_DeviceId, 0, &clRet);
	if (m_Queue == nullptr) {
		throw std::runtime_error("Unable to create command queue: " + std::to_string(clRet));
	}

	m_GpuMem = clCreateBuffer(m_Context, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, m_MemSize, nullptr, &clRet);
	if (m_GpuMem == nullptr) {
		throw std::runtime_error("Unable to create memory buffer: " + std::to_string(clRet));
	}
}

safeio_ssize_t GPURamDrive::GpuWrite(void *buf, safeio_size_t size, off_t_64 offset)
{
#if TEST_HOST_RAM
	memcpy(pBuff + offset, buf, size);
	return size;
#else
	if (clEnqueueWriteBuffer(m_Queue, m_GpuMem, CL_TRUE, (size_t)offset, (size_t)size, buf, 0, nullptr, nullptr) != CL_SUCCESS) {
		return 0;
	}

	return size;
#endif
}

safeio_ssize_t GPURamDrive::GpuRead(void *buf, safeio_size_t size, off_t_64 offset)
{
#if TEST_HOST_RAM
	memcpy(buf, pBuff + offset, size);
	return size;
#else
	if (clEnqueueReadBuffer(m_Queue, m_GpuMem, CL_TRUE, (size_t)offset, (size_t)size, buf, 0, nullptr, nullptr) != CL_SUCCESS) {
		return 0;
	}

	return size;
#endif
}

void GPURamDrive::ImdiskSetupComm(const std::wstring& ServiceName)
{
	MEMORY_BASIC_INFORMATION MemInfo;
	ULARGE_INTEGER MapSize;
	DWORD dwErr;
	std::wstring sTemp;
	const std::wstring sPrefix = L"Global\\";

	m_BufSize = (2 << 20);
	MapSize.QuadPart = m_BufSize + IMDPROXY_HEADER_SIZE;

	sTemp = sPrefix + ServiceName;
	m_ShmHandle = CreateFileMapping(INVALID_HANDLE_VALUE,
		NULL,
		PAGE_READWRITE | SEC_COMMIT,
		MapSize.HighPart,
		MapSize.LowPart,
		sTemp.c_str());
	dwErr = GetLastError();
	if (m_ShmHandle == NULL) {
		throw std::runtime_error("Unable to create file mapping: " + std::to_string(dwErr));
	}

	if (dwErr == ERROR_ALREADY_EXISTS) {
		throw std::runtime_error("A service with this name is already running or is still being used by ImDisk");
	}

	m_ShmView = MapViewOfFile(m_ShmHandle, FILE_MAP_WRITE, 0, 0, 0);
	if (m_ShmView == nullptr) {
		dwErr = GetLastError();
		throw std::runtime_error("Unable to map view of shared memory: " + std::to_string(dwErr));
	}

	if (!VirtualQuery(m_ShmView, &MemInfo, sizeof(MemInfo))) {
		dwErr = GetLastError();
		throw std::runtime_error("Unable to query memory info: " + std::to_string(dwErr));
	}

	m_BufStart = (char*)m_ShmView + IMDPROXY_HEADER_SIZE;

	sTemp = sPrefix + ServiceName + L"_Server";
	m_ShmMutexSrv = CreateMutex(NULL, FALSE, sTemp.c_str());
	if (m_ShmMutexSrv == NULL) {
		dwErr = GetLastError();
		throw std::runtime_error("Unable to create mutex object: " + std::to_string(dwErr));
	}

	if (WaitForSingleObject(m_ShmMutexSrv, 0) != WAIT_OBJECT_0) {
		throw std::runtime_error("A service with this name is already running");
	}

	sTemp = sPrefix + ServiceName + L"_Request";
	m_ShmReqEvent = CreateEvent(NULL, FALSE, FALSE, sTemp.c_str());
	if (m_ShmReqEvent == NULL) {
		dwErr = GetLastError();
		throw std::runtime_error("Unable to create request event object: " + std::to_string(dwErr));
	}

	sTemp = sPrefix + ServiceName + L"_Response";
	m_ShmRespEvent = CreateEvent(NULL, FALSE, FALSE, sTemp.c_str());
	if (m_ShmRespEvent == NULL) {
		dwErr = GetLastError();
		throw std::runtime_error("Unable to create response event object: " + std::to_string(dwErr));
	}
}

void GPURamDrive::ImdiskHandleComm()
{
	PIMDPROXY_READ_REQ Req = (PIMDPROXY_READ_REQ)m_ShmView;
	PIMDPROXY_READ_RESP Resp = (PIMDPROXY_READ_RESP)m_ShmView;

	for (;;)
	{
		if (WaitForSingleObject(m_ShmReqEvent, INFINITE) != WAIT_OBJECT_0) {
			return;
		}

		switch (Req->request_code)
		{
			case IMDPROXY_REQ_INFO:
			{
				PIMDPROXY_INFO_RESP resp = (PIMDPROXY_INFO_RESP)m_ShmView;
				resp->file_size = m_MemSize;
				resp->req_alignment = 1;
				resp->flags = 0;
				break;
			}

			case IMDPROXY_REQ_READ:
			{
				Resp->errorno = 0;
				Resp->length = GpuRead(m_BufStart, (safeio_size_t)(Req->length < m_BufSize ? Req->length : m_BufSize), Req->offset);

				break;
			}

			case IMDPROXY_REQ_WRITE:
			{
				Resp->errorno = 0;
				Resp->length = GpuWrite(m_BufStart, (safeio_size_t)(Req->length < m_BufSize ? Req->length : m_BufSize), Req->offset);

				break;
			}

			case IMDPROXY_REQ_CLOSE:
				return;

			default:
				Req->request_code = ENODEV;
		}

		if (!SetEvent(m_ShmRespEvent)) {
			return;
		}
	}
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkPlaneSource.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkPlaneSource.h"

#include "vtkCellArray.h"
#include "vtkFloatArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
#include "vtkPolyData.h"
#include "vtkTransform.h"

vtkCxxRevisionMacro(vtkPlaneSource, "1.62");
vtkStandardNewMacro(vtkPlaneSource);

// Construct plane perpendicular to z-axis, resolution 1x1, width and height
// 1.0, and centered at the origin.
vtkPlaneSource::vtkPlaneSource()
{
  this->XResolution = 1;
  this->YResolution = 1;

  this->Origin[0] = this->Origin[1] = -0.5;
  this->Origin[2] = 0.0;

  this->Point1[0] = 0.5;
  this->Point1[1] = -0.5;
  this->Point1[2] = 0.0;

  this->Point2[0] = -0.5;
  this->Point2[1] = 0.5;
  this->Point2[2] = 0.0;

  this->Normal[2] = 1.0;
  this->Normal[0] = this->Normal[1] = 0.0;

  this->Center[0] = this->Center[1] = this->Center[2] = 0.0;

  this->SetNumberOfInputPorts(0);
}

// Set the number of x-y subdivisions in the plane.
void vtkPlaneSource::SetResolution(const int xR, const int yR)
{
  if ( xR != this->XResolution || yR != this->YResolution )
    {
    this->XResolution = xR;
    this->YResolution = yR;

    this->XResolution = (this->XResolution > 0 ? this->XResolution : 1);
    this->YResolution = (this->YResolution > 0 ? this->YResolution : 1);

    this->Modified();
    }
}

int vtkPlaneSource::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **vtkNotUsed(inputVector),
  vtkInformationVector *outputVector)
{
  // get the info object
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  // get the ouptut
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  double x[3], tc[2], v1[3], v2[3];
  vtkIdType pts[4];
  int i, j, ii;
  int numPts;
  int numPolys;
  vtkPoints *newPoints;
  vtkFloatArray *newNormals;
  vtkFloatArray *newTCoords;
  vtkCellArray *newPolys;

  // Check input
  for ( i=0; i < 3; i++ )
    {
    v1[i] = this->Point1[i] - this->Origin[i];
    v2[i] = this->Point2[i] - this->Origin[i];
    }
  if ( !this->UpdatePlane(v1,v2) )
    {
    return 0;
    }

  // Set things up; allocate memory
  //
  numPts = (this->XResolution+1) * (this->YResolution+1);
  numPolys = this->XResolution * this->YResolution;

  newPoints = vtkPoints::New();
  newPoints->Allocate(numPts);
  newNormals = vtkFloatArray::New();
  newNormals->SetNumberOfComponents(3);
  newNormals->Allocate(3*numPts);
  newTCoords = vtkFloatArray::New();
  newTCoords->SetNumberOfComponents(2);
  newTCoords->Allocate(2*numPts);

  newPolys = vtkCellArray::New();
  newPolys->Allocate(newPolys->EstimateSize(numPolys,4));

  // Generate points and point data
  //
  for (numPts=0, i=0; i<(this->YResolution+1); i++)
    {
    tc[1] = (double) i / this->YResolution;
    for (j=0; j<(this->XResolution+1); j++)
      {
      tc[0] = (double) j / this->XResolution;

      for ( ii=0; ii < 3; ii++)
        {
        x[ii] = this->Origin[ii] + tc[0]*v1[ii] + tc[1]*v2[ii];
        }

      newPoints->InsertPoint(numPts,x);
      newTCoords->InsertTuple(numPts,tc);
      newNormals->InsertTuple(numPts++,this->Normal);
      }
    }

  // Generate polygon connectivity
  //
  for (i=0; i<this->YResolution; i++)
    {
    for (j=0; j<this->XResolution; j++)
      {
      pts[0] = j + i*(this->XResolution+1);
      pts[1] = pts[0] + 1;
      pts[2] = pts[0] + this->XResolution + 2;
      pts[3] = pts[0] + this->XResolution + 1;
      newPolys->InsertNextCell(4,pts);
      }
    }

  // Update ourselves and release memory
  //
  output->SetPoints(newPoints);
  newPoints->Delete();

  output->GetPointData()->SetNormals(newNormals);
  newNormals->Delete();

  output->GetPointData()->SetTCoords(newTCoords);
  newTCoords->Delete();

  output->SetPolys(newPolys);
  newPolys->Delete();

  return 1;
}

// Set the normal to the plane. Will modify the Origin, Point1, and Point2
// instance variables as necessary (i.e., rotate the plane around its center).
void vtkPlaneSource::SetNormal(double N[3])
{
  double n[3], rotVector[3], theta;

  //make sure input is decent
  n[0] = N[0];
  n[1] = N[1];
  n[2] = N[2];
  if ( vtkMath::Normalize(n) == 0.0 )
    {
    vtkErrorMacro(<<"Specified zero normal");
    return;
    }

  // Compute rotation vector using a transformation matrix.
  // Note that if normals are parallel then the rotation is either
  // 0 or 180 degrees.
  double dp = vtkMath::Dot(this->Normal,n);
  if ( dp >= 1.0 )
    {
    return; //zero rotation
    }
  else if ( dp <= -1.0 )
    {
    theta = 180.0;
    rotVector[0] = this->Point1[0] - this->Origin[0];
    rotVector[1] = this->Point1[1] - this->Origin[1];
    rotVector[2] = this->Point1[2] - this->Origin[2];
    }
  else
    {
    vtkMath::Cross(this->Normal,n,rotVector);
    theta = acos((double)dp) / vtkMath::DoubleDegreesToRadians();
    }

  // create rotation matrix
  vtkTransform *transform = vtkTransform::New();
  transform->PostMultiply();

  transform->Translate(-this->Center[0],-this->Center[1],-this->Center[2]);
  transform->RotateWXYZ(theta,rotVector[0],rotVector[1],rotVector[2]);
  transform->Translate(this->Center[0],this->Center[1],this->Center[2]);

  // transform the three defining points
  transform->TransformPoint(this->Origin,this->Origin);
  transform->TransformPoint(this->Point1,this->Point1);
  transform->TransformPoint(this->Point2,this->Point2);

  this->Normal[0] = n[0]; this->Normal[1] = n[1]; this->Normal[2] = n[2];

  this->Modified();
  transform->Delete();
}

// Set the normal to the plane. Will modify the Origin, Point1, and Point2
// instance variables as necessary (i.e., rotate the plane around its center).
void vtkPlaneSource::SetNormal(double nx, double ny, double nz)
{
  double n[3];

  n[0] = nx; n[1] = ny; n[2] = nz;
  this->SetNormal(n);
}

// Set the center of the plane. Will modify the Origin, Point1, and Point2
// instance variables as necessary (i.e., translate the plane).
void vtkPlaneSource::SetCenter(double center[3])
{
  if ( this->Center[0] == center[0] && this->Center[1] == center[1] &&
  this->Center[2] == center[2] )
    {
    return; //no change
    }
  else
    {
    int i;
    double v1[3], v2[3];

    for ( i=0; i < 3; i++ )
      {
      v1[i] = this->Point1[i] - this->Origin[i];
      v2[i] = this->Point2[i] - this->Origin[i];
      }

    for ( i=0; i < 3; i++ )
      {
      this->Center[i] = center[i];
      this->Origin[i] = this->Center[i] - 0.5*(v1[i] + v2[i]);
      this->Point1[i] = this->Origin[i] + v1[i];
      this->Point2[i] = this->Origin[i] + v2[i];
      }
    this->Modified();
    }
}

// Set the center of the plane. Will modify the Origin, Point1, and Point2
// instance variables as necessary (i.e., translate the plane).
void vtkPlaneSource::SetCenter(double x, double y, double z)
{
  double center[3];

  center[0] = x; center[1] = y; center[2] = z;
  this->SetCenter(center);
}

// modifies the normal and origin
void vtkPlaneSource::SetPoint1(double pnt[3])
{
  if ( this->Point1[0] == pnt[0] && this->Point1[1] == pnt[1] &&
       this->Point1[2] == pnt[2] )
    {
    return; //no change
    }
  else
    {
    int i;
    double v1[3], v2[3];

    for ( i=0; i < 3; i++ )
      {
      this->Point1[i] = pnt[i];
      v1[i] = this->Point1[i] - this->Origin[i];
      v2[i] = this->Point2[i] - this->Origin[i];
      }

    // set plane normal
    this->UpdatePlane(v1,v2);
    this->Modified();
    }
}

// modifies the normal and origin
void vtkPlaneSource::SetPoint2(double pnt[3])
{
  if ( this->Point2[0] == pnt[0] && this->Point2[1] == pnt[1] &&
       this->Point2[2] == pnt[2] )
    {
    return; //no change
    }
  else
    {
    int i;
    double v1[3], v2[3];

    for ( i=0; i < 3; i++ )
      {
      this->Point2[i] = pnt[i];
      v1[i] = this->Point1[i] - this->Origin[i];
      v2[i] = this->Point2[i] - this->Origin[i];
      }
    // set plane normal
    this->UpdatePlane(v1,v2);
    this->Modified();
    }
}

void vtkPlaneSource::SetPoint1(double x, double y, double z)
{
  double pnt[3];

  pnt[0] = x; pnt[1] = y; pnt[2] = z;
  this->SetPoint1(pnt);
}
void vtkPlaneSource::SetPoint2(double x, double y, double z)
{
  double pnt[3];

  pnt[0] = x; pnt[1] = y; pnt[2] = z;
  this->SetPoint2(pnt);
}

// Translate the plane in the direction of the normal by the distance specified.
// Negative values move the plane in the opposite direction.
void vtkPlaneSource::Push(double distance)
{
  int i;

  if ( distance == 0.0 )
    {
    return;
    }
  for (i=0; i < 3; i++ )
    {
    this->Origin[i] += distance * this->Normal[i];
    this->Point1[i] += distance * this->Normal[i];
    this->Point2[i] += distance * this->Normal[i];
    }
  // set the new center
  for ( i=0; i < 3; i++ )
    {
    this->Center[i] = 0.5*(this->Point1[i] + this->Point2[i]);
    }

  this->Modified();
}

// Protected method updates normals and plane center from two axes.
int vtkPlaneSource::UpdatePlane(double v1[3], double v2[3])
{
  // set plane center
  for ( int i=0; i < 3; i++ )
    {
    this->Center[i] = this->Origin[i] + 0.5*(v1[i] + v2[i]);
    }

  // set plane normal
  vtkMath::Cross(v1,v2,this->Normal);
  if ( vtkMath::Normalize(this->Normal) == 0.0 )
    {
    vtkErrorMacro(<<"Bad plane coordinate system");
    return 0;
    }
  else
    {
    return 1;
    }
}

void vtkPlaneSource::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "X Resolution: " << this->XResolution << "\n";
  os << indent << "Y Resolution: " << this->YResolution << "\n";

  os << indent << "Origin: (" << this->Origin[0] << ", "
                              << this->Origin[1] << ", "
                              << this->Origin[2] << ")\n";

  os << indent << "Point 1: (" << this->Point1[0] << ", "
                               << this->Point1[1] << ", "
                               << this->Point1[2] << ")\n";

  os << indent << "Point 2: (" << this->Point2[0] << ", "
                               << this->Point2[1] << ", "
                               << this->Point2[2] << ")\n";

  os << indent << "Normal: (" << this->Normal[0] << ", "
                              << this->Normal[1] << ", "
                              << this->Normal[2] << ")\n";

  os << indent << "Center: (" << this->Center[0] << ", "
                              << this->Center[1] << ", "
                              << this->Center[2] << ")\n";

}
<commit_msg>ENH: Giving names to arrays generated by the source.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkPlaneSource.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkPlaneSource.h"

#include "vtkCellArray.h"
#include "vtkFloatArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
#include "vtkPolyData.h"
#include "vtkTransform.h"

vtkCxxRevisionMacro(vtkPlaneSource, "1.63");
vtkStandardNewMacro(vtkPlaneSource);

// Construct plane perpendicular to z-axis, resolution 1x1, width and height
// 1.0, and centered at the origin.
vtkPlaneSource::vtkPlaneSource()
{
  this->XResolution = 1;
  this->YResolution = 1;

  this->Origin[0] = this->Origin[1] = -0.5;
  this->Origin[2] = 0.0;

  this->Point1[0] = 0.5;
  this->Point1[1] = -0.5;
  this->Point1[2] = 0.0;

  this->Point2[0] = -0.5;
  this->Point2[1] = 0.5;
  this->Point2[2] = 0.0;

  this->Normal[2] = 1.0;
  this->Normal[0] = this->Normal[1] = 0.0;

  this->Center[0] = this->Center[1] = this->Center[2] = 0.0;

  this->SetNumberOfInputPorts(0);
}

// Set the number of x-y subdivisions in the plane.
void vtkPlaneSource::SetResolution(const int xR, const int yR)
{
  if ( xR != this->XResolution || yR != this->YResolution )
    {
    this->XResolution = xR;
    this->YResolution = yR;

    this->XResolution = (this->XResolution > 0 ? this->XResolution : 1);
    this->YResolution = (this->YResolution > 0 ? this->YResolution : 1);

    this->Modified();
    }
}

int vtkPlaneSource::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **vtkNotUsed(inputVector),
  vtkInformationVector *outputVector)
{
  // get the info object
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  // get the ouptut
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  double x[3], tc[2], v1[3], v2[3];
  vtkIdType pts[4];
  int i, j, ii;
  int numPts;
  int numPolys;
  vtkPoints *newPoints;
  vtkFloatArray *newNormals;
  vtkFloatArray *newTCoords;
  vtkCellArray *newPolys;

  // Check input
  for ( i=0; i < 3; i++ )
    {
    v1[i] = this->Point1[i] - this->Origin[i];
    v2[i] = this->Point2[i] - this->Origin[i];
    }
  if ( !this->UpdatePlane(v1,v2) )
    {
    return 0;
    }

  // Set things up; allocate memory
  //
  numPts = (this->XResolution+1) * (this->YResolution+1);
  numPolys = this->XResolution * this->YResolution;

  newPoints = vtkPoints::New();
  newPoints->Allocate(numPts);
  newNormals = vtkFloatArray::New();
  newNormals->SetNumberOfComponents(3);
  newNormals->Allocate(3*numPts);
  newTCoords = vtkFloatArray::New();
  newTCoords->SetNumberOfComponents(2);
  newTCoords->Allocate(2*numPts);

  newPolys = vtkCellArray::New();
  newPolys->Allocate(newPolys->EstimateSize(numPolys,4));

  // Generate points and point data
  //
  for (numPts=0, i=0; i<(this->YResolution+1); i++)
    {
    tc[1] = (double) i / this->YResolution;
    for (j=0; j<(this->XResolution+1); j++)
      {
      tc[0] = (double) j / this->XResolution;

      for ( ii=0; ii < 3; ii++)
        {
        x[ii] = this->Origin[ii] + tc[0]*v1[ii] + tc[1]*v2[ii];
        }

      newPoints->InsertPoint(numPts,x);
      newTCoords->InsertTuple(numPts,tc);
      newNormals->InsertTuple(numPts++,this->Normal);
      }
    }

  // Generate polygon connectivity
  //
  for (i=0; i<this->YResolution; i++)
    {
    for (j=0; j<this->XResolution; j++)
      {
      pts[0] = j + i*(this->XResolution+1);
      pts[1] = pts[0] + 1;
      pts[2] = pts[0] + this->XResolution + 2;
      pts[3] = pts[0] + this->XResolution + 1;
      newPolys->InsertNextCell(4,pts);
      }
    }

  // Update ourselves and release memory
  //
  output->SetPoints(newPoints);
  newPoints->Delete();

  newNormals->SetName("Normals");
  output->GetPointData()->SetNormals(newNormals);
  newNormals->Delete();

  newTCoords->SetName("TextureCoordinates");
  output->GetPointData()->SetTCoords(newTCoords);
  newTCoords->Delete();

  output->SetPolys(newPolys);
  newPolys->Delete();

  return 1;
}

// Set the normal to the plane. Will modify the Origin, Point1, and Point2
// instance variables as necessary (i.e., rotate the plane around its center).
void vtkPlaneSource::SetNormal(double N[3])
{
  double n[3], rotVector[3], theta;

  //make sure input is decent
  n[0] = N[0];
  n[1] = N[1];
  n[2] = N[2];
  if ( vtkMath::Normalize(n) == 0.0 )
    {
    vtkErrorMacro(<<"Specified zero normal");
    return;
    }

  // Compute rotation vector using a transformation matrix.
  // Note that if normals are parallel then the rotation is either
  // 0 or 180 degrees.
  double dp = vtkMath::Dot(this->Normal,n);
  if ( dp >= 1.0 )
    {
    return; //zero rotation
    }
  else if ( dp <= -1.0 )
    {
    theta = 180.0;
    rotVector[0] = this->Point1[0] - this->Origin[0];
    rotVector[1] = this->Point1[1] - this->Origin[1];
    rotVector[2] = this->Point1[2] - this->Origin[2];
    }
  else
    {
    vtkMath::Cross(this->Normal,n,rotVector);
    theta = acos((double)dp) / vtkMath::DoubleDegreesToRadians();
    }

  // create rotation matrix
  vtkTransform *transform = vtkTransform::New();
  transform->PostMultiply();

  transform->Translate(-this->Center[0],-this->Center[1],-this->Center[2]);
  transform->RotateWXYZ(theta,rotVector[0],rotVector[1],rotVector[2]);
  transform->Translate(this->Center[0],this->Center[1],this->Center[2]);

  // transform the three defining points
  transform->TransformPoint(this->Origin,this->Origin);
  transform->TransformPoint(this->Point1,this->Point1);
  transform->TransformPoint(this->Point2,this->Point2);

  this->Normal[0] = n[0]; this->Normal[1] = n[1]; this->Normal[2] = n[2];

  this->Modified();
  transform->Delete();
}

// Set the normal to the plane. Will modify the Origin, Point1, and Point2
// instance variables as necessary (i.e., rotate the plane around its center).
void vtkPlaneSource::SetNormal(double nx, double ny, double nz)
{
  double n[3];

  n[0] = nx; n[1] = ny; n[2] = nz;
  this->SetNormal(n);
}

// Set the center of the plane. Will modify the Origin, Point1, and Point2
// instance variables as necessary (i.e., translate the plane).
void vtkPlaneSource::SetCenter(double center[3])
{
  if ( this->Center[0] == center[0] && this->Center[1] == center[1] &&
  this->Center[2] == center[2] )
    {
    return; //no change
    }
  else
    {
    int i;
    double v1[3], v2[3];

    for ( i=0; i < 3; i++ )
      {
      v1[i] = this->Point1[i] - this->Origin[i];
      v2[i] = this->Point2[i] - this->Origin[i];
      }

    for ( i=0; i < 3; i++ )
      {
      this->Center[i] = center[i];
      this->Origin[i] = this->Center[i] - 0.5*(v1[i] + v2[i]);
      this->Point1[i] = this->Origin[i] + v1[i];
      this->Point2[i] = this->Origin[i] + v2[i];
      }
    this->Modified();
    }
}

// Set the center of the plane. Will modify the Origin, Point1, and Point2
// instance variables as necessary (i.e., translate the plane).
void vtkPlaneSource::SetCenter(double x, double y, double z)
{
  double center[3];

  center[0] = x; center[1] = y; center[2] = z;
  this->SetCenter(center);
}

// modifies the normal and origin
void vtkPlaneSource::SetPoint1(double pnt[3])
{
  if ( this->Point1[0] == pnt[0] && this->Point1[1] == pnt[1] &&
       this->Point1[2] == pnt[2] )
    {
    return; //no change
    }
  else
    {
    int i;
    double v1[3], v2[3];

    for ( i=0; i < 3; i++ )
      {
      this->Point1[i] = pnt[i];
      v1[i] = this->Point1[i] - this->Origin[i];
      v2[i] = this->Point2[i] - this->Origin[i];
      }

    // set plane normal
    this->UpdatePlane(v1,v2);
    this->Modified();
    }
}

// modifies the normal and origin
void vtkPlaneSource::SetPoint2(double pnt[3])
{
  if ( this->Point2[0] == pnt[0] && this->Point2[1] == pnt[1] &&
       this->Point2[2] == pnt[2] )
    {
    return; //no change
    }
  else
    {
    int i;
    double v1[3], v2[3];

    for ( i=0; i < 3; i++ )
      {
      this->Point2[i] = pnt[i];
      v1[i] = this->Point1[i] - this->Origin[i];
      v2[i] = this->Point2[i] - this->Origin[i];
      }
    // set plane normal
    this->UpdatePlane(v1,v2);
    this->Modified();
    }
}

void vtkPlaneSource::SetPoint1(double x, double y, double z)
{
  double pnt[3];

  pnt[0] = x; pnt[1] = y; pnt[2] = z;
  this->SetPoint1(pnt);
}
void vtkPlaneSource::SetPoint2(double x, double y, double z)
{
  double pnt[3];

  pnt[0] = x; pnt[1] = y; pnt[2] = z;
  this->SetPoint2(pnt);
}

// Translate the plane in the direction of the normal by the distance specified.
// Negative values move the plane in the opposite direction.
void vtkPlaneSource::Push(double distance)
{
  int i;

  if ( distance == 0.0 )
    {
    return;
    }
  for (i=0; i < 3; i++ )
    {
    this->Origin[i] += distance * this->Normal[i];
    this->Point1[i] += distance * this->Normal[i];
    this->Point2[i] += distance * this->Normal[i];
    }
  // set the new center
  for ( i=0; i < 3; i++ )
    {
    this->Center[i] = 0.5*(this->Point1[i] + this->Point2[i]);
    }

  this->Modified();
}

// Protected method updates normals and plane center from two axes.
int vtkPlaneSource::UpdatePlane(double v1[3], double v2[3])
{
  // set plane center
  for ( int i=0; i < 3; i++ )
    {
    this->Center[i] = this->Origin[i] + 0.5*(v1[i] + v2[i]);
    }

  // set plane normal
  vtkMath::Cross(v1,v2,this->Normal);
  if ( vtkMath::Normalize(this->Normal) == 0.0 )
    {
    vtkErrorMacro(<<"Bad plane coordinate system");
    return 0;
    }
  else
    {
    return 1;
    }
}

void vtkPlaneSource::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "X Resolution: " << this->XResolution << "\n";
  os << indent << "Y Resolution: " << this->YResolution << "\n";

  os << indent << "Origin: (" << this->Origin[0] << ", "
                              << this->Origin[1] << ", "
                              << this->Origin[2] << ")\n";

  os << indent << "Point 1: (" << this->Point1[0] << ", "
                               << this->Point1[1] << ", "
                               << this->Point1[2] << ")\n";

  os << indent << "Point 2: (" << this->Point2[0] << ", "
                               << this->Point2[1] << ", "
                               << this->Point2[2] << ")\n";

  os << indent << "Normal: (" << this->Normal[0] << ", "
                              << this->Normal[1] << ", "
                              << this->Normal[2] << ")\n";

  os << indent << "Center: (" << this->Center[0] << ", "
                              << this->Center[1] << ", "
                              << this->Center[2] << ")\n";

}
<|endoftext|>


<commit_before>#include <iostream>
#include <cmath>

using namespace std;

int main()
{ //
int c=0;
int count=0;
int iter=1;
cin>>c;
while(c/(pow(5,iter))>0){
count+=c/(pow(5,iter));
	++iter;
}
cout<<count<<endl;
}
<commit_msg>added hi to commit<commit_after>#include <iostream>
#include <cmath>

using namespace std;

int main()
{ // hi
int c=0;
int count=0;
int iter=1;
cin>>c;
while(c/(pow(5,iter))>0){
count+=c/(pow(5,iter));
	++iter;
}
cout<<count<<endl;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 Dan Vrátil <dvratil@redhat.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "contact-info-dialog.h"
#include "contact.h"

#include <QGridLayout>
#include <QPicture>
#include <QLabel>
#include <QVBoxLayout>
#include <QFormLayout>

#include <TelepathyQt/Contact>
#include <TelepathyQt/PendingContactInfo>
#include <TelepathyQt/AvatarData>
#include <TelepathyQt/Presence>
#include <TelepathyQt/SharedPtr>
#include <TelepathyQt/ContactManager>
#include <TelepathyQt/Connection>
#include <TelepathyQt/Account>
#include <TelepathyQt/PendingContacts>

#include <KDebug>
#include <KTitleWidget>
#include <KLocalizedString>
#include <KPushButton>
#include <KLineEdit>
#include <KDateComboBox>
#include <KFileDialog>
#include <KImageFilePreview>
#include <KMessageBox>

namespace KTp {

enum InfoRowIndex {
    FullName = 0,
    Nickname,
    Email,
    Phone,
    Homepage,
    Birthday,
    Organization,
    _InfoRowCount
};

static struct InfoRow {
    const InfoRowIndex index;
    const QString fieldName;
    const char* title;
} InfoRows[] = {                                        // Don't use i18n in global static vars
    { FullName,         QLatin1String("fn"),            I18N_NOOP("Full name:") },
    { Nickname,         QLatin1String("nickname"),      I18N_NOOP("Nickname:") },
    { Email,            QLatin1String("email"),         I18N_NOOP("Email:") },
    { Phone,            QLatin1String("tel"),           I18N_NOOP("Phone:") },
    { Homepage,         QLatin1String("url"),           I18N_NOOP("Homepage:") },
    { Birthday,         QLatin1String("bday"),          I18N_NOOP("Birthday:") },
    { Organization,     QLatin1String("org"),           I18N_NOOP("Organization:") }
};

class ContactInfoDialog::Private
{
  public:
    Private(ContactInfoDialog *parent):
        editable(false),
        infoDataChanged(false),
        avatarChanged(false),
        columnsLayout(0),
        infoLayout(0),
        stateLayout(0),
        changeAvatarButton(0),
        clearAvatarButton(0),
        avatarLabel(0),
        q(parent)
    {}

    void onContactUpgraded(Tp::PendingOperation *op);
    void onContactInfoReceived(Tp::PendingOperation *op);
    void onChangeAvatarButtonClicked();
    void onClearAvatarButtonClicked();
    void onInfoDataChanged();

    void addInfoRow(InfoRowIndex index, const QString &value);
    void addStateRow(const QString &description, Tp::Contact::PresenceState state);

    Tp::AccountPtr account;
    KTp::ContactPtr contact;
    bool editable;

    bool infoDataChanged;
    bool avatarChanged;
    QString newAvatarFile;

    QMap<InfoRowIndex,QWidget*> infoValueWidgets;

    QHBoxLayout *columnsLayout;
    QFormLayout *infoLayout;
    QFormLayout *stateLayout;
    KPushButton *changeAvatarButton;
    KPushButton *clearAvatarButton;
    QLabel *avatarLabel;

  private:
    ContactInfoDialog *q;
};

void ContactInfoDialog::Private::onContactUpgraded(Tp::PendingOperation* op)
{
    Tp::PendingContacts *contacts = qobject_cast<Tp::PendingContacts*>(op);
    Q_ASSERT(contacts->contacts().count() == 1);

    contact = KTp::ContactPtr::qObjectCast(contacts->contacts().first());

    /* Show avatar immediatelly */
    if (contacts->features().contains(Tp::Contact::FeatureAvatarData)) {
        QVBoxLayout *avatarLayout = new QVBoxLayout();
        avatarLayout->setSpacing(5);
        avatarLayout->setAlignment(Qt::AlignHCenter);
        columnsLayout->addLayout(avatarLayout);

        avatarLabel = new QLabel(q);
        avatarLabel->setMaximumSize(150, 150);
        avatarLayout->addWidget(avatarLabel, 0, Qt::AlignTop);

        if (editable) {
            changeAvatarButton = new KPushButton(i18n("Change Avatar"), q);
            connect(changeAvatarButton, SIGNAL(clicked(bool)),
                    q, SLOT(onChangeAvatarButtonClicked()));
            avatarLayout->addWidget(changeAvatarButton);

            clearAvatarButton = new KPushButton(i18n("Clear Avatar"), q);
            connect(clearAvatarButton, SIGNAL(clicked(bool)),
                    q, SLOT(onClearAvatarButtonClicked()));
            avatarLayout->addWidget(clearAvatarButton);

            avatarLayout->addStretch(1);
        }

        QPixmap avatar(contact->avatarPixmap());
        avatarLabel->setPixmap(avatar.scaled(avatarLabel->maximumSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
    }

    /* Request detailed contact info */
    if (contacts->features().contains(Tp::Contact::FeatureInfo)) {
        infoLayout = new QFormLayout();
        infoLayout->setSpacing(10);
        columnsLayout->addLayout(infoLayout);

        Tp::PendingContactInfo *op = contact->requestInfo();
        connect(op, SIGNAL(finished(Tp::PendingOperation*)),
                q, SLOT(onContactInfoReceived(Tp::PendingOperation*)));
    }
}

void ContactInfoDialog::Private::onContactInfoReceived(Tp::PendingOperation* op)
{
    Tp::PendingContactInfo *ci = qobject_cast<Tp::PendingContactInfo*>(op);
    const Tp::ContactInfoFieldList fieldList = ci->infoFields().allFields();

    for (InfoRowIndex index = (InfoRowIndex) 0; index < _InfoRowCount; index = (InfoRowIndex)(index + 1)) {
        QString value;

        Q_FOREACH(const Tp::ContactInfoField &field, fieldList) {
            if (field.fieldValue.count() == 0) {
                continue;
            }

            if (field.fieldName == InfoRows[index].fieldName) {
                value = field.fieldValue.first();
                break;
            }
        }

        /* Show edits for all values when in editable mode */
        if (!editable && value.isEmpty()) {
            continue;
        }

        addInfoRow(index, value);
    }
}

void ContactInfoDialog::Private::onChangeAvatarButtonClicked()
{
    QPointer<KFileDialog> fileDialog = new KFileDialog(KUrl(), QString(), q);
    fileDialog->setOperationMode(KFileDialog::Opening);
    fileDialog->setPreviewWidget(new KImageFilePreview(fileDialog));
    fileDialog->setMimeFilter(QStringList() << QLatin1String("image/*"));

    int c = fileDialog->exec();
    if (fileDialog && c) {
        newAvatarFile = fileDialog->selectedFile();

        QPixmap avatar(newAvatarFile);
        if (avatar.isNull()) {
            KMessageBox::error(q, i18n("Failed to load the new avatar image"));
            newAvatarFile.clear();
            delete fileDialog;
            return;
        }
        avatarLabel->setPixmap(avatar.scaled(avatarLabel->maximumSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
        avatarChanged = true;
        clearAvatarButton->setEnabled(true);
    }

    delete fileDialog;
}

void ContactInfoDialog::Private::onClearAvatarButtonClicked()
{
    QPixmap avatar;
    avatar = KIconLoader::global()->loadIcon(QLatin1String("im-user"), KIconLoader::Desktop, 128);

    newAvatarFile.clear();
    avatarChanged = true;
}

void ContactInfoDialog::Private::onInfoDataChanged()
{
    infoDataChanged = true;
}

void ContactInfoDialog::Private::addInfoRow(InfoRowIndex index, const QString &value)
{
    InfoRow *row = &InfoRows[index];

    // I18N_NOOP only marks the string for translation, the actual lookup of
    // translated row->title happens here
    QLabel *descriptionLabel = new QLabel(i18n(row->title), q);
    QFont font = descriptionLabel->font();
    font.setBold(true);
    descriptionLabel->setFont(font);

    if (editable) {
        if (index == Birthday) {
            KDateComboBox *combo = new KDateComboBox(q);
            combo->setOptions(KDateComboBox::EditDate | KDateComboBox::SelectDate | KDateComboBox::DatePicker);
            combo->setMinimumWidth(200);
            combo->setDate(QDate::fromString(value));
            connect(combo, SIGNAL(dateChanged(QDate)), q, SLOT(onInfoDataChanged()));

            infoValueWidgets.insert(index, combo);
        } else {
            KLineEdit *edit = new KLineEdit(q);
            edit->setMinimumWidth(200);
            edit->setText(value);
            connect(edit, SIGNAL(textChanged(QString)), q, SLOT(onInfoDataChanged()));

            infoValueWidgets.insert(index, edit);
        }
    } else {
        QLabel *label = new QLabel(q);
        label->setOpenExternalLinks(true);
        label->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse);
        if (index == Email) {
            label->setText(QString::fromLatin1("%1").arg(value));
        } else if (index == Homepage) {
            QString format;
            if (!value.startsWith(QLatin1String("http"), Qt::CaseInsensitive)) {
                format = QLatin1String("%1");
            } else {
                format = QLatin1String("%1");
            }
            label->setText(format.arg(value));
        } else {
            label->setText(value);
        }

        infoValueWidgets.insert(index, label);
    }

    infoLayout->addRow(descriptionLabel, infoValueWidgets.value(index));
}

void ContactInfoDialog::Private::addStateRow(const QString& description, Tp::Contact::PresenceState state)
{
    QLabel *descriptionLabel = new QLabel(description, q);

    KIcon icon;
    switch (state) {
        case Tp::Contact::PresenceStateYes:
            icon = KIcon(QLatin1String("task-complete"));
            break;
        case Tp::Contact::PresenceStateNo:
            icon = KIcon(QLatin1String("task-reject"));
            break;
        case Tp::Contact::PresenceStateAsk:
        default:
            icon = KIcon(QLatin1String("task-attempt"));
            break;
    }

    QLabel *stateLabel = new QLabel(q);
    stateLabel->setPixmap(icon.pixmap(16));

    stateLayout->addRow(descriptionLabel, stateLabel);
}

ContactInfoDialog::ContactInfoDialog(const Tp::AccountPtr& account, const Tp::ContactPtr& contact, QWidget* parent)
    : KDialog(parent)
    , d(new Private(this))
{
#if 0   // Editing contacts is not yet supported in TpQt
    /* Whether contact is the user himself */
    d->editable = (contact == account->connection()->selfContact());
#endif
    d->editable = false;
    d->account = account;
    d->contact = KTp::ContactPtr::qObjectCast(contact);

    if (d->editable) {
        setButtons(User1 | Close);
        setButtonGuiItem(User1, KGuiItem(i18n("Save"), QLatin1String("document-save")));
    } else {
        setButtons(Close);
    }

    setMaximumSize(sizeHint());

    QVBoxLayout *layout = new QVBoxLayout(mainWidget());
    layout->setSpacing(30);

    /* Title - presence icon, alias, id */
    KTitleWidget *titleWidget = new KTitleWidget(this);
    KTp::Presence presence(contact->presence());
    titleWidget->setPixmap(presence.icon().pixmap(32, 32), KTitleWidget::ImageLeft);
    titleWidget->setText(contact->alias());
    titleWidget->setComment(contact->id());
    layout->addWidget(titleWidget);

    /* 1st column: avatar; 2nd column: details */
    d->columnsLayout = new QHBoxLayout();
    d->columnsLayout->setSpacing(30);
    layout->addLayout(d->columnsLayout);

    /* Make sure the contact has all neccessary features ready */
    Tp::PendingContacts *op = contact->manager()->upgradeContacts(
            QList<Tp::ContactPtr>() << contact,
            Tp::Features() << Tp::Contact::FeatureAvatarData
                           << Tp::Contact::FeatureInfo);
    connect(op, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onContactUpgraded(Tp::PendingOperation*)));

    /* State Info - there is no point showing this information when it's about ourselves */
    if (!d->editable) {
        d->stateLayout = new QFormLayout();
        d->stateLayout->setSpacing(10);
        layout->addLayout(d->stateLayout);
        d->addStateRow(i18n("Contact can see when you are online:"), contact->publishState());
        d->addStateRow(i18n("You can see when the contact is online:"), contact->subscriptionState());
        d->addStateRow(i18n("Contact is blocked:"), contact->isBlocked() ? Tp::Contact::PresenceStateYes : Tp::Contact::PresenceStateNo);
    }
}

ContactInfoDialog::~ContactInfoDialog()
{
    delete d;
}

void ContactInfoDialog::slotButtonClicked(int button)
{
    if (button == User1) {
        if (d->avatarChanged) {
            Tp::Avatar avatar;
            if (!d->newAvatarFile.isEmpty()) {
                QFile file(d->newAvatarFile);
                file.open(QIODevice::ReadOnly);

                QFileInfo fi(file);

                avatar.avatarData = file.readAll();
                file.seek(0); // reset before passing to KMimeType
                avatar.MIMEType = KMimeType::findByNameAndContent(d->newAvatarFile, &file)->defaultMimeType();
            }

            d->account->setAvatar(avatar);
        }

        if (d->infoDataChanged) {
            Tp::ContactInfoFieldList fieldList;

            for (InfoRowIndex index = (InfoRowIndex) 0; index < _InfoRowCount; index = (InfoRowIndex) (index + 1)) {
                InfoRow *row = &InfoRows[index];

                Tp::ContactInfoField field;
                field.fieldName = row->fieldName;

                if (index == Birthday) {
                    KDateComboBox *combo = qobject_cast<KDateComboBox*>(d->infoValueWidgets.value(index));
                    field.fieldValue << combo->date().toString();
                } else {
                    KLineEdit *lineEdit = qobject_cast<KLineEdit*>(d->infoValueWidgets.value(index));
                    field.fieldValue << lineEdit->text();
                }

                fieldList << field;
            }

#if 0   // This method does not exist in TpQt (yet)
            d->account->connection()->setContactInfo(fieldList);
#endif
        }

        accept();
        return;
    }

    KDialog::slotButtonClicked(button);
}

} /* namespace KTp */

#include "contact-info-dialog.moc"
<commit_msg>Check upgradeContacts succeeded<commit_after>/*
 * Copyright (C) 2013 Dan Vrátil <dvratil@redhat.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "contact-info-dialog.h"
#include "contact.h"

#include <QGridLayout>
#include <QPicture>
#include <QLabel>
#include <QVBoxLayout>
#include <QFormLayout>

#include <TelepathyQt/Contact>
#include <TelepathyQt/PendingContactInfo>
#include <TelepathyQt/AvatarData>
#include <TelepathyQt/Presence>
#include <TelepathyQt/SharedPtr>
#include <TelepathyQt/ContactManager>
#include <TelepathyQt/Connection>
#include <TelepathyQt/Account>
#include <TelepathyQt/PendingContacts>

#include <KDebug>
#include <KTitleWidget>
#include <KLocalizedString>
#include <KPushButton>
#include <KLineEdit>
#include <KDateComboBox>
#include <KFileDialog>
#include <KImageFilePreview>
#include <KMessageBox>

namespace KTp {

enum InfoRowIndex {
    FullName = 0,
    Nickname,
    Email,
    Phone,
    Homepage,
    Birthday,
    Organization,
    _InfoRowCount
};

static struct InfoRow {
    const InfoRowIndex index;
    const QString fieldName;
    const char* title;
} InfoRows[] = {                                        // Don't use i18n in global static vars
    { FullName,         QLatin1String("fn"),            I18N_NOOP("Full name:") },
    { Nickname,         QLatin1String("nickname"),      I18N_NOOP("Nickname:") },
    { Email,            QLatin1String("email"),         I18N_NOOP("Email:") },
    { Phone,            QLatin1String("tel"),           I18N_NOOP("Phone:") },
    { Homepage,         QLatin1String("url"),           I18N_NOOP("Homepage:") },
    { Birthday,         QLatin1String("bday"),          I18N_NOOP("Birthday:") },
    { Organization,     QLatin1String("org"),           I18N_NOOP("Organization:") }
};

class ContactInfoDialog::Private
{
  public:
    Private(ContactInfoDialog *parent):
        editable(false),
        infoDataChanged(false),
        avatarChanged(false),
        columnsLayout(0),
        infoLayout(0),
        stateLayout(0),
        changeAvatarButton(0),
        clearAvatarButton(0),
        avatarLabel(0),
        q(parent)
    {}

    void onContactUpgraded(Tp::PendingOperation *op);
    void onContactInfoReceived(Tp::PendingOperation *op);
    void onChangeAvatarButtonClicked();
    void onClearAvatarButtonClicked();
    void onInfoDataChanged();

    void addInfoRow(InfoRowIndex index, const QString &value);
    void addStateRow(const QString &description, Tp::Contact::PresenceState state);

    Tp::AccountPtr account;
    KTp::ContactPtr contact;
    bool editable;

    bool infoDataChanged;
    bool avatarChanged;
    QString newAvatarFile;

    QMap<InfoRowIndex,QWidget*> infoValueWidgets;

    QHBoxLayout *columnsLayout;
    QFormLayout *infoLayout;
    QFormLayout *stateLayout;
    KPushButton *changeAvatarButton;
    KPushButton *clearAvatarButton;
    QLabel *avatarLabel;

  private:
    ContactInfoDialog *q;
};

void ContactInfoDialog::Private::onContactUpgraded(Tp::PendingOperation* op)
{
    Tp::PendingContacts *contacts = qobject_cast<Tp::PendingContacts*>(op);
    if (op->isError()) {
        return;
    }

    Q_ASSERT(contacts->contacts().count() == 1);

    contact = KTp::ContactPtr::qObjectCast(contacts->contacts().first());

    /* Show avatar immediatelly */
    if (contacts->features().contains(Tp::Contact::FeatureAvatarData)) {
        QVBoxLayout *avatarLayout = new QVBoxLayout();
        avatarLayout->setSpacing(5);
        avatarLayout->setAlignment(Qt::AlignHCenter);
        columnsLayout->addLayout(avatarLayout);

        avatarLabel = new QLabel(q);
        avatarLabel->setMaximumSize(150, 150);
        avatarLayout->addWidget(avatarLabel, 0, Qt::AlignTop);

        if (editable) {
            changeAvatarButton = new KPushButton(i18n("Change Avatar"), q);
            connect(changeAvatarButton, SIGNAL(clicked(bool)),
                    q, SLOT(onChangeAvatarButtonClicked()));
            avatarLayout->addWidget(changeAvatarButton);

            clearAvatarButton = new KPushButton(i18n("Clear Avatar"), q);
            connect(clearAvatarButton, SIGNAL(clicked(bool)),
                    q, SLOT(onClearAvatarButtonClicked()));
            avatarLayout->addWidget(clearAvatarButton);

            avatarLayout->addStretch(1);
        }

        QPixmap avatar(contact->avatarPixmap());
        avatarLabel->setPixmap(avatar.scaled(avatarLabel->maximumSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
    }

    /* Request detailed contact info */
    if (contacts->features().contains(Tp::Contact::FeatureInfo)) {
        infoLayout = new QFormLayout();
        infoLayout->setSpacing(10);
        columnsLayout->addLayout(infoLayout);

        Tp::PendingContactInfo *op = contact->requestInfo();
        connect(op, SIGNAL(finished(Tp::PendingOperation*)),
                q, SLOT(onContactInfoReceived(Tp::PendingOperation*)));
    }
}

void ContactInfoDialog::Private::onContactInfoReceived(Tp::PendingOperation* op)
{
    Tp::PendingContactInfo *ci = qobject_cast<Tp::PendingContactInfo*>(op);
    const Tp::ContactInfoFieldList fieldList = ci->infoFields().allFields();

    for (InfoRowIndex index = (InfoRowIndex) 0; index < _InfoRowCount; index = (InfoRowIndex)(index + 1)) {
        QString value;

        Q_FOREACH(const Tp::ContactInfoField &field, fieldList) {
            if (field.fieldValue.count() == 0) {
                continue;
            }

            if (field.fieldName == InfoRows[index].fieldName) {
                value = field.fieldValue.first();
                break;
            }
        }

        /* Show edits for all values when in editable mode */
        if (!editable && value.isEmpty()) {
            continue;
        }

        addInfoRow(index, value);
    }
}

void ContactInfoDialog::Private::onChangeAvatarButtonClicked()
{
    QPointer<KFileDialog> fileDialog = new KFileDialog(KUrl(), QString(), q);
    fileDialog->setOperationMode(KFileDialog::Opening);
    fileDialog->setPreviewWidget(new KImageFilePreview(fileDialog));
    fileDialog->setMimeFilter(QStringList() << QLatin1String("image/*"));

    int c = fileDialog->exec();
    if (fileDialog && c) {
        newAvatarFile = fileDialog->selectedFile();

        QPixmap avatar(newAvatarFile);
        if (avatar.isNull()) {
            KMessageBox::error(q, i18n("Failed to load the new avatar image"));
            newAvatarFile.clear();
            delete fileDialog;
            return;
        }
        avatarLabel->setPixmap(avatar.scaled(avatarLabel->maximumSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
        avatarChanged = true;
        clearAvatarButton->setEnabled(true);
    }

    delete fileDialog;
}

void ContactInfoDialog::Private::onClearAvatarButtonClicked()
{
    QPixmap avatar;
    avatar = KIconLoader::global()->loadIcon(QLatin1String("im-user"), KIconLoader::Desktop, 128);

    newAvatarFile.clear();
    avatarChanged = true;
}

void ContactInfoDialog::Private::onInfoDataChanged()
{
    infoDataChanged = true;
}

void ContactInfoDialog::Private::addInfoRow(InfoRowIndex index, const QString &value)
{
    InfoRow *row = &InfoRows[index];

    // I18N_NOOP only marks the string for translation, the actual lookup of
    // translated row->title happens here
    QLabel *descriptionLabel = new QLabel(i18n(row->title), q);
    QFont font = descriptionLabel->font();
    font.setBold(true);
    descriptionLabel->setFont(font);

    if (editable) {
        if (index == Birthday) {
            KDateComboBox *combo = new KDateComboBox(q);
            combo->setOptions(KDateComboBox::EditDate | KDateComboBox::SelectDate | KDateComboBox::DatePicker);
            combo->setMinimumWidth(200);
            combo->setDate(QDate::fromString(value));
            connect(combo, SIGNAL(dateChanged(QDate)), q, SLOT(onInfoDataChanged()));

            infoValueWidgets.insert(index, combo);
        } else {
            KLineEdit *edit = new KLineEdit(q);
            edit->setMinimumWidth(200);
            edit->setText(value);
            connect(edit, SIGNAL(textChanged(QString)), q, SLOT(onInfoDataChanged()));

            infoValueWidgets.insert(index, edit);
        }
    } else {
        QLabel *label = new QLabel(q);
        label->setOpenExternalLinks(true);
        label->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse);
        if (index == Email) {
            label->setText(QString::fromLatin1("%1").arg(value));
        } else if (index == Homepage) {
            QString format;
            if (!value.startsWith(QLatin1String("http"), Qt::CaseInsensitive)) {
                format = QLatin1String("%1");
            } else {
                format = QLatin1String("%1");
            }
            label->setText(format.arg(value));
        } else {
            label->setText(value);
        }

        infoValueWidgets.insert(index, label);
    }

    infoLayout->addRow(descriptionLabel, infoValueWidgets.value(index));
}

void ContactInfoDialog::Private::addStateRow(const QString& description, Tp::Contact::PresenceState state)
{
    QLabel *descriptionLabel = new QLabel(description, q);

    KIcon icon;
    switch (state) {
        case Tp::Contact::PresenceStateYes:
            icon = KIcon(QLatin1String("task-complete"));
            break;
        case Tp::Contact::PresenceStateNo:
            icon = KIcon(QLatin1String("task-reject"));
            break;
        case Tp::Contact::PresenceStateAsk:
        default:
            icon = KIcon(QLatin1String("task-attempt"));
            break;
    }

    QLabel *stateLabel = new QLabel(q);
    stateLabel->setPixmap(icon.pixmap(16));

    stateLayout->addRow(descriptionLabel, stateLabel);
}

ContactInfoDialog::ContactInfoDialog(const Tp::AccountPtr& account, const Tp::ContactPtr& contact, QWidget* parent)
    : KDialog(parent)
    , d(new Private(this))
{
#if 0   // Editing contacts is not yet supported in TpQt
    /* Whether contact is the user himself */
    d->editable = (contact == account->connection()->selfContact());
#endif
    d->editable = false;
    d->account = account;
    d->contact = KTp::ContactPtr::qObjectCast(contact);

    if (d->editable) {
        setButtons(User1 | Close);
        setButtonGuiItem(User1, KGuiItem(i18n("Save"), QLatin1String("document-save")));
    } else {
        setButtons(Close);
    }

    setMaximumSize(sizeHint());

    QVBoxLayout *layout = new QVBoxLayout(mainWidget());
    layout->setSpacing(30);

    /* Title - presence icon, alias, id */
    KTitleWidget *titleWidget = new KTitleWidget(this);
    KTp::Presence presence(contact->presence());
    titleWidget->setPixmap(presence.icon().pixmap(32, 32), KTitleWidget::ImageLeft);
    titleWidget->setText(contact->alias());
    titleWidget->setComment(contact->id());
    layout->addWidget(titleWidget);

    /* 1st column: avatar; 2nd column: details */
    d->columnsLayout = new QHBoxLayout();
    d->columnsLayout->setSpacing(30);
    layout->addLayout(d->columnsLayout);

    /* Make sure the contact has all neccessary features ready */
    Tp::PendingContacts *op = contact->manager()->upgradeContacts(
            QList<Tp::ContactPtr>() << contact,
            Tp::Features() << Tp::Contact::FeatureAvatarData
                           << Tp::Contact::FeatureInfo);
    connect(op, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onContactUpgraded(Tp::PendingOperation*)));

    /* State Info - there is no point showing this information when it's about ourselves */
    if (!d->editable) {
        d->stateLayout = new QFormLayout();
        d->stateLayout->setSpacing(10);
        layout->addLayout(d->stateLayout);
        d->addStateRow(i18n("Contact can see when you are online:"), contact->publishState());
        d->addStateRow(i18n("You can see when the contact is online:"), contact->subscriptionState());
        d->addStateRow(i18n("Contact is blocked:"), contact->isBlocked() ? Tp::Contact::PresenceStateYes : Tp::Contact::PresenceStateNo);
    }
}

ContactInfoDialog::~ContactInfoDialog()
{
    delete d;
}

void ContactInfoDialog::slotButtonClicked(int button)
{
    if (button == User1) {
        if (d->avatarChanged) {
            Tp::Avatar avatar;
            if (!d->newAvatarFile.isEmpty()) {
                QFile file(d->newAvatarFile);
                file.open(QIODevice::ReadOnly);

                QFileInfo fi(file);

                avatar.avatarData = file.readAll();
                file.seek(0); // reset before passing to KMimeType
                avatar.MIMEType = KMimeType::findByNameAndContent(d->newAvatarFile, &file)->defaultMimeType();
            }

            d->account->setAvatar(avatar);
        }

        if (d->infoDataChanged) {
            Tp::ContactInfoFieldList fieldList;

            for (InfoRowIndex index = (InfoRowIndex) 0; index < _InfoRowCount; index = (InfoRowIndex) (index + 1)) {
                InfoRow *row = &InfoRows[index];

                Tp::ContactInfoField field;
                field.fieldName = row->fieldName;

                if (index == Birthday) {
                    KDateComboBox *combo = qobject_cast<KDateComboBox*>(d->infoValueWidgets.value(index));
                    field.fieldValue << combo->date().toString();
                } else {
                    KLineEdit *lineEdit = qobject_cast<KLineEdit*>(d->infoValueWidgets.value(index));
                    field.fieldValue << lineEdit->text();
                }

                fieldList << field;
            }

#if 0   // This method does not exist in TpQt (yet)
            d->account->connection()->setContactInfo(fieldList);
#endif
        }

        accept();
        return;
    }

    KDialog::slotButtonClicked(button);
}

} /* namespace KTp */

#include "contact-info-dialog.moc"
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007-2008 Digital Bazaar, Inc.  All rights reserved.
 */
#include "db/rt/DynamicObjectImpl.h"

#include "db/rt/DynamicObject.h"

using namespace std;
using namespace db::rt;

DynamicObjectImpl::DynamicObjectImpl()
{
   mType = String;
   mString = NULL;
   mStringValue = NULL;
}

DynamicObjectImpl::~DynamicObjectImpl()
{
   DynamicObjectImpl::freeData();

   // free cached string value
   if(mStringValue != NULL)
   {
      free(mStringValue);
   }
}

void DynamicObjectImpl::freeMapKeys()
{
   // clean up member names
   for(ObjectMap::iterator i = mMap->begin(); i != mMap->end(); i++)
   {
      free((char*)i->first);
   }
}

void DynamicObjectImpl::freeData()
{
   // clean up data based on type
   switch(mType)
   {
      case String:
         {
            if(mString != NULL)
            {
               free(mString);
            }
            mString = NULL;
         }
         break;
      case Map:
         if(mMap != NULL)
         {
            freeMapKeys();
            delete mMap;
            mMap = NULL;
         }
         break;
      case Array:
         if(mArray != NULL)
         {
            delete mArray;
            mArray = NULL;
         }
         break;
      default:
         // nothing to cleanup
         break;
   }
}

void DynamicObjectImpl::setString(const char* value)
{
   freeData();
   mType = String;
   mString = strdup(value);
}

void DynamicObjectImpl::operator=(const char* value)
{
   setString(value);
}

void DynamicObjectImpl::operator=(bool value)
{
   freeData();
   mType = Boolean;
   mBoolean = value;
}

void DynamicObjectImpl::operator=(int value)
{
   freeData();
   mType = Int32;
   mInt32 = value;
}

void DynamicObjectImpl::operator=(unsigned int value)
{
   freeData();
   mType = UInt32;
   mUInt32 = value;
}

void DynamicObjectImpl::operator=(long long value)
{
   freeData();
   mType = Int64;
   mInt64 = value;
}

void DynamicObjectImpl::operator=(unsigned long long value)
{
   freeData();
   mType = UInt64;
   mUInt64 = value;
}

void DynamicObjectImpl::operator=(double value)
{
   freeData();
   mType = Double;
   mDouble = value;
}

DynamicObject& DynamicObjectImpl::operator[](const char* name)
{
   DynamicObject* rval = NULL;

   // change to map type if necessary
   setType(Map);

   ObjectMap::iterator i = mMap->find(name);
   if(i == mMap->end())
   {
      // create new map entry
      DynamicObject dyno;
      mMap->insert(std::make_pair(strdup(name), dyno));
      rval = &(*mMap)[name];
   }
   else
   {
      // get existing map entry
      rval = &i->second;
   }

   return *rval;
}

DynamicObject& DynamicObjectImpl::operator[](int index)
{
   // change to array type if necessary
   setType(Array);

   if(index < 0)
   {
      index = mArray->size() + index;
   }

   // fill the object array as necessary
   if(index >= (int)mArray->size())
   {
      int i = index - (int)mArray->size() + 1;
      for(; i > 0; i--)
      {
         DynamicObject dyno;
         mArray->push_back(dyno);
      }
   }

   return (*mArray)[index];
}

DynamicObject& DynamicObjectImpl::append()
{
   return (*this)[length()];
}

void DynamicObjectImpl::setType(DynamicObjectType type)
{
   if(mType != type)
   {
      switch(type)
      {
         case String:
            *this = getString();
            break;
         case Boolean:
            *this = getBoolean();
            break;
         case Int32:
            *this = getInt32();
            break;
         case UInt32:
            *this = getUInt32();
            break;
         case Int64:
            *this = getInt64();
            break;
         case UInt64:
            *this = getUInt64();
            break;
         case Double:
            *this = getDouble();
            break;
         case Map:
            {
               freeData();
               mType = Map;
               mMap = new ObjectMap();
            }
            break;
         case Array:
            {
               freeData();
               mType = Array;
               mArray = new ObjectArray();
            }
            break;
      }
   }
}

DynamicObjectType DynamicObjectImpl::getType()
{
   return mType;
}

const char* DynamicObjectImpl::getString()
{
   const char* rval;

   if(mType == String)
   {
      if(mString != NULL)
      {
         // use existing string
         rval = mString;
      }
      else
      {
         // only duplicate blank string upon request
         rval = mString = strdup("");
      }
   }
   else
   {
      // convert type as appropriate
      switch(mType)
      {
         case Boolean:
            mStringValue = (char*)realloc(mStringValue, 6);
            snprintf(mStringValue, 6, "%s", (mBoolean ? "true" : "false"));
            break;
         case Int32:
            mStringValue = (char*)realloc(mStringValue, 12);
            snprintf(mStringValue, 12, "%i", mInt32);
            break;
         case UInt32:
            mStringValue = (char*)realloc(mStringValue, 11);
            snprintf(mStringValue, 11, "%u", mUInt32);
            break;
         case Int64:
            mStringValue = (char*)realloc(mStringValue, 22);
            snprintf(mStringValue, 22, "%lli", mInt64);
            break;
         case UInt64:
            mStringValue = (char*)realloc(mStringValue, 21);
            snprintf(mStringValue, 21, "%llu", mUInt64);
            break;
         case Double:
            // use default precision of 6
            // X.000000e+00 = 11 places to right of decimal
            mStringValue = (char*)realloc(mStringValue, 50);
            snprintf(mStringValue, 50, "%e", mDouble);
            break;
         default: /* Map, Array, ... */
            {
               if(mStringValue == NULL)
               {
                  // duplicate blank string
                  mStringValue = strdup("");
               }
               else
               {
                  // set null-terminator to first character
                  mStringValue[0] = 0;
               }
            }
            break;
      }

      // return generated value
      rval = mStringValue;
   }

   return rval;
}

bool DynamicObjectImpl::getBoolean()
{
   bool rval;

   switch(mType)
   {
      case Boolean:
         rval = mBoolean;
         break;
      case String:
         rval = (mString == NULL) ? false : (strcmp(mString, "true") == 0);
         break;
      case Int32:
         rval = (mInt32 == 1);
         break;
      case UInt32:
         rval = (mUInt32 == 1);
         break;
      case Int64:
         rval = (mInt64 == 1);
         break;
      case UInt64:
         rval = (mUInt64 == 1);
         break;
      case Double:
         rval = (mDouble == 1);
         break;
      default:
         rval = false;
         break;
   }

   return rval;
}

int DynamicObjectImpl::getInt32()
{
   int rval;

   switch(mType)
   {
      case Int32:
         rval = mInt32;
         break;
      case String:
         rval = (mString == NULL) ? 0 : strtol(mString, NULL, 10);
         break;
      case Boolean:
         rval = mBoolean ? 1 : 0;
         break;
      case UInt32:
         rval = (int)mUInt32;
         break;
      case Int64:
         rval = (int)mInt64;
         break;
      case UInt64:
         rval = (int)mUInt64;
         break;
      case Double:
         rval = (int)mDouble;
         break;
      default:
         rval = 0;
         break;
   }

   return rval;
}

unsigned int DynamicObjectImpl::getUInt32()
{
   unsigned int rval;

   switch(mType)
   {
      case UInt32:
         rval = mUInt32;
         break;
      case String:
         rval = (mString == NULL) ? 0 : strtoul(mString, NULL, 10);
         break;
      case Boolean:
         rval = mBoolean ? 1 : 0;
         break;
      case Int32:
         rval = (mInt32 < 0) ? 0 : mInt32;
         break;
      case Int64:
         rval = (mInt64 < 0) ? 0 : (unsigned int)mInt64;
         break;
      case UInt64:
         rval = (unsigned int)mUInt64;
         break;
      case Double:
         rval = (unsigned int)mDouble;
         break;
      default:
         rval = 0;
         break;
   }

   return rval;
}

long long DynamicObjectImpl::getInt64()
{
   long long rval;

   switch(mType)
   {
      case Int64:
         rval = mInt64;
         break;
      case String:
         rval = (mString == NULL) ? 0 : strtoll(mString, NULL, 10);
         break;
      case Boolean:
         rval = mBoolean ? 1 : 0;
         break;
      case Int32:
         rval = mInt32;
         break;
      case UInt32:
         rval = mUInt32;
         break;
      case UInt64:
         rval = (long long)mUInt64;
         break;
      case Double:
         rval = (long long)mDouble;
         break;
      default:
         rval = 0;
         break;
   }

   return rval;
}

unsigned long long DynamicObjectImpl::getUInt64()
{
   unsigned long long rval;

   switch(mType)
   {
      case UInt64:
         rval = mUInt64;
         break;
      case String:
         rval = (mString == NULL) ? 0 : strtoull(mString, NULL, 10);
         break;
      case Boolean:
         rval = mBoolean ? 1 : 0;
         break;
      case Int32:
         rval = (mInt32 < 0) ? 0 : mInt32;
         break;
      case UInt32:
         rval = mUInt32;
         break;
      case Int64:
         rval = (mInt64 < 0) ? 0 : mInt64;
         break;
      case Double:
         rval = mDouble;
         break;
      default:
         rval = 0;
         break;
   }

   return rval;
}

double DynamicObjectImpl::getDouble()
{
   double rval;

   switch(mType)
   {
      case Double:
         rval = mDouble;
         break;
      case String:
         rval = (mString == NULL) ? 0 : strtod(mString, NULL);
         break;
      case Boolean:
         rval = mBoolean ? 1 : 0;
         break;
      case Int32:
         rval = mInt32;
         break;
      case UInt32:
         rval = mUInt32;
         break;
      case Int64:
         rval = mInt64;
         break;
      case UInt64:
         rval = mUInt64;
         break;
      default:
         rval = 0;
         break;
   }

   return rval;
}

bool DynamicObjectImpl::hasMember(const char* name)
{
   bool rval = false;

   if(mType == Map)
   {
      ObjectMap::iterator i = mMap->find(name);
      rval = (i != mMap->end());
   }

   return rval;
}

DynamicObject DynamicObjectImpl::removeMember(const char* name)
{
   DynamicObject rval(NULL);

   if(mType == Map)
   {
      ObjectMap::iterator i = mMap->find(name);
      if(i != mMap->end())
      {
         // clean up key and remove map entry
         free((char*)i->first);
         rval = i->second;
         mMap->erase(i);
      }
   }

   return rval;
}

void DynamicObjectImpl::clear()
{
   switch(mType)
   {
      case String:
         *this = "";
         break;
      case Boolean:
         *this = false;
         break;
      case Int32:
         *this = (int)0;
         break;
      case UInt32:
         *this = (unsigned int)0;
         break;
      case Int64:
         *this = (long long)0;
         break;
      case UInt64:
         *this = (unsigned long long)0;
         break;
      case Double:
         *this = (double)0.0;
         break;
      case Map:
         freeMapKeys();
         mMap->clear();
         break;
      case Array:
         mArray->clear();
         break;
   }
}

int DynamicObjectImpl::length()
{
   int rval = 0;

   switch(mType)
   {
      case String:
         if(mString != NULL)
         {
            rval = strlen(getString());
         }
         break;
      case Boolean:
         rval = 1;
         break;
      case Int32:
      case UInt32:
         rval = sizeof(unsigned int);
         break;
      case Int64:
      case UInt64:
         rval = sizeof(unsigned long long);
         break;
      case Double:
         rval = sizeof(double);
         break;
      case Map:
         rval = mMap->size();
         break;
      case Array:
         rval = mArray->size();
         break;
   }

   return rval;
}
<commit_msg>Fixed db::rt warnings.<commit_after>/*
 * Copyright (c) 2007-2008 Digital Bazaar, Inc.  All rights reserved.
 */
#include "db/rt/DynamicObjectImpl.h"

#include "db/rt/DynamicObject.h"

using namespace std;
using namespace db::rt;

DynamicObjectImpl::DynamicObjectImpl()
{
   mType = String;
   mString = NULL;
   mStringValue = NULL;
}

DynamicObjectImpl::~DynamicObjectImpl()
{
   DynamicObjectImpl::freeData();

   // free cached string value
   if(mStringValue != NULL)
   {
      free(mStringValue);
   }
}

void DynamicObjectImpl::freeMapKeys()
{
   // clean up member names
   for(ObjectMap::iterator i = mMap->begin(); i != mMap->end(); i++)
   {
      free((char*)i->first);
   }
}

void DynamicObjectImpl::freeData()
{
   // clean up data based on type
   switch(mType)
   {
      case String:
         {
            if(mString != NULL)
            {
               free(mString);
            }
            mString = NULL;
         }
         break;
      case Map:
         if(mMap != NULL)
         {
            freeMapKeys();
            delete mMap;
            mMap = NULL;
         }
         break;
      case Array:
         if(mArray != NULL)
         {
            delete mArray;
            mArray = NULL;
         }
         break;
      default:
         // nothing to cleanup
         break;
   }
}

void DynamicObjectImpl::setString(const char* value)
{
   freeData();
   mType = String;
   mString = strdup(value);
}

void DynamicObjectImpl::operator=(const char* value)
{
   setString(value);
}

void DynamicObjectImpl::operator=(bool value)
{
   freeData();
   mType = Boolean;
   mBoolean = value;
}

void DynamicObjectImpl::operator=(int value)
{
   freeData();
   mType = Int32;
   mInt32 = value;
}

void DynamicObjectImpl::operator=(unsigned int value)
{
   freeData();
   mType = UInt32;
   mUInt32 = value;
}

void DynamicObjectImpl::operator=(long long value)
{
   freeData();
   mType = Int64;
   mInt64 = value;
}

void DynamicObjectImpl::operator=(unsigned long long value)
{
   freeData();
   mType = UInt64;
   mUInt64 = value;
}

void DynamicObjectImpl::operator=(double value)
{
   freeData();
   mType = Double;
   mDouble = value;
}

DynamicObject& DynamicObjectImpl::operator[](const char* name)
{
   DynamicObject* rval = NULL;

   // change to map type if necessary
   setType(Map);

   ObjectMap::iterator i = mMap->find(name);
   if(i == mMap->end())
   {
      // create new map entry
      DynamicObject dyno;
      mMap->insert(std::make_pair(strdup(name), dyno));
      rval = &(*mMap)[name];
   }
   else
   {
      // get existing map entry
      rval = &i->second;
   }

   return *rval;
}

DynamicObject& DynamicObjectImpl::operator[](int index)
{
   // change to array type if necessary
   setType(Array);

   if(index < 0)
   {
      index = mArray->size() + index;
   }

   // fill the object array as necessary
   if(index >= (int)mArray->size())
   {
      int i = index - (int)mArray->size() + 1;
      for(; i > 0; i--)
      {
         DynamicObject dyno;
         mArray->push_back(dyno);
      }
   }

   return (*mArray)[index];
}

DynamicObject& DynamicObjectImpl::append()
{
   return (*this)[length()];
}

void DynamicObjectImpl::setType(DynamicObjectType type)
{
   if(mType != type)
   {
      switch(type)
      {
         case String:
            *this = getString();
            break;
         case Boolean:
            *this = getBoolean();
            break;
         case Int32:
            *this = getInt32();
            break;
         case UInt32:
            *this = getUInt32();
            break;
         case Int64:
            *this = getInt64();
            break;
         case UInt64:
            *this = getUInt64();
            break;
         case Double:
            *this = getDouble();
            break;
         case Map:
            {
               freeData();
               mType = Map;
               mMap = new ObjectMap();
            }
            break;
         case Array:
            {
               freeData();
               mType = Array;
               mArray = new ObjectArray();
            }
            break;
      }
   }
}

DynamicObjectType DynamicObjectImpl::getType()
{
   return mType;
}

const char* DynamicObjectImpl::getString()
{
   const char* rval;

   if(mType == String)
   {
      if(mString != NULL)
      {
         // use existing string
         rval = mString;
      }
      else
      {
         // only duplicate blank string upon request
         rval = mString = strdup("");
      }
   }
   else
   {
      // convert type as appropriate
      switch(mType)
      {
         case Boolean:
            mStringValue = (char*)realloc(mStringValue, 6);
            snprintf(mStringValue, 6, "%s", (mBoolean ? "true" : "false"));
            break;
         case Int32:
            mStringValue = (char*)realloc(mStringValue, 12);
            snprintf(mStringValue, 12, "%i", mInt32);
            break;
         case UInt32:
            mStringValue = (char*)realloc(mStringValue, 11);
            snprintf(mStringValue, 11, "%u", mUInt32);
            break;
         case Int64:
            mStringValue = (char*)realloc(mStringValue, 22);
            snprintf(mStringValue, 22, "%lli", mInt64);
            break;
         case UInt64:
            mStringValue = (char*)realloc(mStringValue, 21);
            snprintf(mStringValue, 21, "%llu", mUInt64);
            break;
         case Double:
            // use default precision of 6
            // X.000000e+00 = 11 places to right of decimal
            mStringValue = (char*)realloc(mStringValue, 50);
            snprintf(mStringValue, 50, "%e", mDouble);
            break;
         default: /* Map, Array, ... */
            {
               if(mStringValue == NULL)
               {
                  // duplicate blank string
                  mStringValue = strdup("");
               }
               else
               {
                  // set null-terminator to first character
                  mStringValue[0] = 0;
               }
            }
            break;
      }

      // return generated value
      rval = mStringValue;
   }

   return rval;
}

bool DynamicObjectImpl::getBoolean()
{
   bool rval;

   switch(mType)
   {
      case Boolean:
         rval = mBoolean;
         break;
      case String:
         rval = (mString == NULL) ? false : (strcmp(mString, "true") == 0);
         break;
      case Int32:
         rval = (mInt32 == 1);
         break;
      case UInt32:
         rval = (mUInt32 == 1);
         break;
      case Int64:
         rval = (mInt64 == 1);
         break;
      case UInt64:
         rval = (mUInt64 == 1);
         break;
      case Double:
         rval = (mDouble == 1);
         break;
      default:
         rval = false;
         break;
   }

   return rval;
}

int DynamicObjectImpl::getInt32()
{
   int rval;

   switch(mType)
   {
      case Int32:
         rval = mInt32;
         break;
      case String:
         rval = (mString == NULL) ? 0 : strtol(mString, NULL, 10);
         break;
      case Boolean:
         rval = mBoolean ? 1 : 0;
         break;
      case UInt32:
         rval = (int)mUInt32;
         break;
      case Int64:
         rval = (int)mInt64;
         break;
      case UInt64:
         rval = (int)mUInt64;
         break;
      case Double:
         rval = (int)mDouble;
         break;
      default:
         rval = 0;
         break;
   }

   return rval;
}

unsigned int DynamicObjectImpl::getUInt32()
{
   unsigned int rval;

   switch(mType)
   {
      case UInt32:
         rval = mUInt32;
         break;
      case String:
         rval = (mString == NULL) ? 0 : strtoul(mString, NULL, 10);
         break;
      case Boolean:
         rval = mBoolean ? 1 : 0;
         break;
      case Int32:
         rval = (mInt32 < 0) ? 0 : mInt32;
         break;
      case Int64:
         rval = (mInt64 < 0) ? 0 : (unsigned int)mInt64;
         break;
      case UInt64:
         rval = (unsigned int)mUInt64;
         break;
      case Double:
         rval = (unsigned int)mDouble;
         break;
      default:
         rval = 0;
         break;
   }

   return rval;
}

long long DynamicObjectImpl::getInt64()
{
   long long rval;

   switch(mType)
   {
      case Int64:
         rval = mInt64;
         break;
      case String:
         rval = (mString == NULL) ? 0 : strtoll(mString, NULL, 10);
         break;
      case Boolean:
         rval = mBoolean ? 1 : 0;
         break;
      case Int32:
         rval = mInt32;
         break;
      case UInt32:
         rval = mUInt32;
         break;
      case UInt64:
         rval = (long long)mUInt64;
         break;
      case Double:
         rval = (long long)mDouble;
         break;
      default:
         rval = 0;
         break;
   }

   return rval;
}

unsigned long long DynamicObjectImpl::getUInt64()
{
   unsigned long long rval;

   switch(mType)
   {
      case UInt64:
         rval = mUInt64;
         break;
      case String:
         rval = (mString == NULL) ? 0 : strtoull(mString, NULL, 10);
         break;
      case Boolean:
         rval = mBoolean ? 1 : 0;
         break;
      case Int32:
         rval = (mInt32 < 0) ? 0 : mInt32;
         break;
      case UInt32:
         rval = mUInt32;
         break;
      case Int64:
         rval = (mInt64 < 0) ? 0 : mInt64;
         break;
      case Double:
         rval = (unsigned long long)mDouble;
         break;
      default:
         rval = 0;
         break;
   }

   return rval;
}

double DynamicObjectImpl::getDouble()
{
   double rval;

   switch(mType)
   {
      case Double:
         rval = mDouble;
         break;
      case String:
         rval = (mString == NULL) ? 0 : strtod(mString, NULL);
         break;
      case Boolean:
         rval = mBoolean ? 1 : 0;
         break;
      case Int32:
         rval = mInt32;
         break;
      case UInt32:
         rval = mUInt32;
         break;
      case Int64:
         rval = mInt64;
         break;
      case UInt64:
         rval = mUInt64;
         break;
      default:
         rval = 0;
         break;
   }

   return rval;
}

bool DynamicObjectImpl::hasMember(const char* name)
{
   bool rval = false;

   if(mType == Map)
   {
      ObjectMap::iterator i = mMap->find(name);
      rval = (i != mMap->end());
   }

   return rval;
}

DynamicObject DynamicObjectImpl::removeMember(const char* name)
{
   DynamicObject rval(NULL);

   if(mType == Map)
   {
      ObjectMap::iterator i = mMap->find(name);
      if(i != mMap->end())
      {
         // clean up key and remove map entry
         free((char*)i->first);
         rval = i->second;
         mMap->erase(i);
      }
   }

   return rval;
}

void DynamicObjectImpl::clear()
{
   switch(mType)
   {
      case String:
         *this = "";
         break;
      case Boolean:
         *this = false;
         break;
      case Int32:
         *this = (int)0;
         break;
      case UInt32:
         *this = (unsigned int)0;
         break;
      case Int64:
         *this = (long long)0;
         break;
      case UInt64:
         *this = (unsigned long long)0;
         break;
      case Double:
         *this = (double)0.0;
         break;
      case Map:
         freeMapKeys();
         mMap->clear();
         break;
      case Array:
         mArray->clear();
         break;
   }
}

int DynamicObjectImpl::length()
{
   int rval = 0;

   switch(mType)
   {
      case String:
         if(mString != NULL)
         {
            rval = strlen(getString());
         }
         break;
      case Boolean:
         rval = 1;
         break;
      case Int32:
      case UInt32:
         rval = sizeof(unsigned int);
         break;
      case Int64:
      case UInt64:
         rval = sizeof(unsigned long long);
         break;
      case Double:
         rval = sizeof(double);
         break;
      case Map:
         rval = mMap->size();
         break;
      case Array:
         rval = mArray->size();
         break;
   }

   return rval;
}
<|endoftext|>