<commit_before>/*++

Copyright (C) 2019 3MF Consortium

All rights reserved.

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

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

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

Abstract:

NMR_OpcPackageReader.cpp defines an OPC Package reader in a portable way.

--*/

#include "Common/OPC/NMR_OpcPackageReader.h"
#include "Common/OPC/NMR_OpcPackageRelationshipReader.h"
#include "Common/OPC/NMR_OpcPackageContentTypesReader.h"
#include "Common/Platform/NMR_ImportStream_ZIP.h"
#include "Common/NMR_Exception.h"
#include "Common/NMR_StringUtils.h"

#include "Model/Classes/NMR_ModelConstants.h"

#include <iostream>

namespace NMR {

	// custom callbck function for reading from a CImportStream on the fly
	zip_int64_t custom_zip_source_callback(void *userData, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
		if (userData == nullptr)
			throw CNMRException(NMR_ERROR_INVALIDPARAM);

		CImportStream* pImportStream = (CImportStream*)(userData);

		switch (cmd) {
			case ZIP_SOURCE_SUPPORTS:
				zip_int64_t bitmap;
				bitmap = zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE,
					ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_SEEK, ZIP_SOURCE_TELL, ZIP_SOURCE_SUPPORTS, -1);
				return bitmap;

			case ZIP_SOURCE_SEEK:
				zip_source_args_seek argsSeek;
				argsSeek = * ((zip_source_args_seek *)data);
				if (argsSeek.whence == SEEK_SET)
					pImportStream->seekPosition(argsSeek.offset, true);
				else if (argsSeek.whence == SEEK_CUR) {
					pImportStream->seekPosition(pImportStream->getPosition() + argsSeek.offset, true);
				}
				else if (argsSeek.whence == SEEK_END) {
					if (argsSeek.offset > 0)
						throw CNMRException(NMR_ERROR_ZIPCALLBACK);
					pImportStream->seekFromEnd(-argsSeek.offset, true);
				}
				else
					throw CNMRException(NMR_ERROR_ZIPCALLBACK);
				return 0;

			case ZIP_SOURCE_OPEN:
				return 0;

			case ZIP_SOURCE_READ:
				return pImportStream->readBuffer((nfByte*)data, len, true);

			case ZIP_SOURCE_CLOSE:
				return 0;

			case ZIP_SOURCE_TELL:
				return pImportStream->getPosition();

			case ZIP_SOURCE_STAT:
				zip_stat_t* zipStat;
				zipStat  = (zip_stat_t*)data;
				zip_stat_init(zipStat);
				zipStat->size = pImportStream->retrieveSize();
				zipStat->valid |= ZIP_STAT_SIZE;
				return sizeof(zip_stat_t);

			default:
				throw CNMRException(NMR_ERROR_ZIPCALLBACK);
		}
		return -1;
	}

	COpcPackageReader::COpcPackageReader(_In_ PImportStream pImportStream, _In_ PModelReaderWarnings pWarnings, _In_ PProgressMonitor pProgressMonitor)
		: m_pWarnings(pWarnings), m_pProgressMonitor(pProgressMonitor)
	{
		if (!pImportStream)
			throw CNMRException(NMR_ERROR_INVALIDPARAM);

		if (!pProgressMonitor)
			throw CNMRException(NMR_ERROR_INVALIDPARAM);

		m_ZIPError.str = nullptr;
		m_ZIPError.sys_err = 0;
		m_ZIPError.zip_err = 0;
		m_ZIParchive = nullptr;
		m_ZIPsource = nullptr;

		try {
			// determine stream size
			nfUint64 nStreamSize = pImportStream->retrieveSize();
			pImportStream->seekPosition(0, true);

			if (nStreamSize == 0)
				throw CNMRException(NMR_ERROR_COULDNOTGETSTREAMPOSITION);

			// create ZIP objects
			zip_error_init(&m_ZIPError);

			bool bUseCallback = true;
			if (bUseCallback) {
				// read ZIP from callback: faster and requires less memory
				m_ZIPsource = zip_source_function_create(custom_zip_source_callback, pImportStream.get(), &m_ZIPError);
			}
			else {
				// read ZIP into memory
				m_Buffer.resize((size_t)nStreamSize);
				pImportStream->readBuffer(&m_Buffer[0], nStreamSize, true);
				m_ZIPsource = zip_source_buffer_create(&m_Buffer[0], (size_t)nStreamSize, 0, &m_ZIPError);
			}
			if (m_ZIPsource == nullptr)
				throw CNMRException(NMR_ERROR_COULDNOTREADZIPFILE);

			m_ZIParchive = zip_open_from_source(m_ZIPsource, ZIP_RDONLY | ZIP_CHECKCONS, &m_ZIPError);
			if (m_ZIParchive == nullptr) {
				m_ZIParchive = zip_open_from_source(m_ZIPsource, ZIP_RDONLY, &m_ZIPError);
				if (m_ZIParchive == nullptr)
					throw CNMRException(NMR_ERROR_COULDNOTREADZIPFILE);
				else
					m_pWarnings->addException(CNMRException(NMR_ERROR_ZIPCONTAINSINCONSISTENCIES), mrwInvalidMandatoryValue);
			}

			// Get ZIP Content
			nfInt64 nEntryCount = zip_get_num_entries(m_ZIParchive, ZIP_FL_UNCHANGED);
			if (nEntryCount < 0)
				throw CNMRException(NMR_ERROR_COULDNOTREADZIPFILE);

			// List and stat Entries
			nfUint64 nUnzippedFileSize = 0;
			for (nfInt64 nIndex = 0; nIndex < nEntryCount; nIndex++) {
				const char * pszName = zip_get_name(m_ZIParchive, (nfUint64) nIndex, ZIP_FL_ENC_GUESS);
				m_ZIPEntries.insert(std::make_pair(pszName, nIndex));

				zip_stat_t Stat;
				nfInt32 nResult = zip_stat_index(m_ZIParchive, nIndex, ZIP_FL_UNCHANGED, &Stat);
				if (nResult != 0)
					throw CNMRException(NMR_ERROR_COULDNOTSTATZIPENTRY);

				nUnzippedFileSize += Stat.size;
			}

			m_pProgressMonitor->SetMaxProgress(double(nUnzippedFileSize));
			m_pProgressMonitor->ReportProgressAndQueryCancelled(true);

			readContentTypes();
			readRootRelationships();
		}
		catch (...)
		{
			releaseZIP();
			throw;
		}
	}

	COpcPackageReader::~COpcPackageReader()
	{
		releaseZIP();
	}

	_Ret_maybenull_ COpcPackageRelationship * COpcPackageReader::findRootRelation(_In_ std::string sRelationType, _In_ nfBool bMustBeUnique)
	{
		COpcPackageRelationship * pResultRelationship = nullptr;
		auto iIterator = m_RootRelationships.begin();
		while (iIterator != m_RootRelationships.end()) {
			POpcPackageRelationship pRelationship = *iIterator;

			std::string sType = pRelationship->getType();
			if (sType == sRelationType) {
				if (pResultRelationship == nullptr) {
					pResultRelationship = pRelationship.get();
				}
				else {
					if (bMustBeUnique)
						m_pWarnings->addException(CNMRException(NMR_ERROR_OPCRELATIONSHIPNOTUNIQUE), eModelReaderWarningLevel::mrwInvalidOptionalValue);
				}

			}
			iIterator++;
		}

		return pResultRelationship;
	}

	void COpcPackageReader::releaseZIP()
	{
		if (m_ZIParchive != nullptr)
			zip_close(m_ZIParchive);

		if (m_ZIPsource != nullptr)
			zip_source_close(m_ZIPsource);

		zip_error_fini(&m_ZIPError);
		m_Buffer.resize(0);

		m_ZIPsource = nullptr;
		m_ZIParchive = nullptr;
	}

	PImportStream COpcPackageReader::openZIPEntry(_In_ std::string sName)
	{
		auto iIterator = m_ZIPEntries.find(sName);
		if (iIterator == m_ZIPEntries.end()) {
			return nullptr;
		}

		return openZIPEntryIndexed(iIterator->second);
	}

	PImportStream COpcPackageReader::openZIPEntryIndexed(_In_ nfUint64 nIndex)
	{
		zip_stat_t Stat;
		nfInt32 nResult = zip_stat_index(m_ZIParchive, nIndex, ZIP_FL_UNCHANGED, &Stat);
		if (nResult != 0)
			throw CNMRException(NMR_ERROR_COULDNOTSTATZIPENTRY);

		nfUint64 nSize = Stat.size;

		zip_file_t * pFile = zip_fopen_index(m_ZIParchive, nIndex, ZIP_FL_UNCHANGED);
		if (pFile == nullptr)
			throw CNMRException(NMR_ERROR_COULDNOTOPENZIPENTRY);

		return std::make_shared<CImportStream_ZIP>(pFile, nSize);
	}

	void COpcPackageReader::readContentTypes()
	{
		PImportStream pContentStream = openZIPEntry(OPCPACKAGE_PATH_CONTENTTYPES);

		POpcPackageContentTypesReader pReader = std::make_shared<COpcPackageContentTypesReader>(pContentStream, m_pProgressMonitor);

		nfUint32 nCount = pReader->getCount();
		nfUint32 nIndex;

		std::string modelExtension = "";
		std::string modelPart = "";
		m_relationShipExtension = "";
		for (nIndex = 0; nIndex < nCount; nIndex++) {
			POpcPackageContentType pContentType = pReader->getContentType(nIndex);
			if (pContentType->m_contentType == PACKAGE_3D_RELS_CONTENT_TYPE) {
				m_relationShipExtension = pContentType->m_extension;
			}
			if (pContentType->m_contentType == PACKAGE_3D_MODEL_CONTENT_TYPE) {
				modelExtension = pContentType->m_extension;
			}
		}
		if (m_relationShipExtension.empty())
			throw CNMRException(NMR_ERROR_OPC_MISSING_EXTENSION_FOR_RELATIONSHIP);

		nCount = pReader->getOverrideCount();
		for (nIndex = 0; nIndex < nCount; nIndex++) {
			POpcPackageContentType_Override pOverrideContentType = pReader->getOverrideContentType(nIndex);
			if (pOverrideContentType->m_contentType == PACKAGE_3D_MODEL_CONTENT_TYPE) {
				modelPart = pOverrideContentType->m_partName;
			}
		}

		if (modelExtension.empty() && modelPart.empty())
			throw CNMRException(NMR_ERROR_OPC_MISSING_EXTENSION_FOR_MODEL);
	}

	void COpcPackageReader::readRootRelationships()
	{
		PImportStream pRelStream = openZIPEntry(OPCPACKAGE_PATH_ROOTRELATIONSHIPS);

		POpcPackageRelationshipReader pReader = std::make_shared<COpcPackageRelationshipReader>(pRelStream, m_pProgressMonitor);

		nfUint32 nCount = pReader->getCount();
		nfUint32 nIndex;

		for (nIndex = 0; nIndex < nCount; nIndex++) {
			m_RootRelationships.push_back(pReader->getRelationShip(nIndex));
		}
	}

	nfUint64 COpcPackageReader::GetPartSize(_In_ std::string sPath)
	{
		std::string sRealPath = fnRemoveLeadingPathDelimiter(sPath);
		auto iIterator = m_ZIPEntries.find(sRealPath);
		if (iIterator == m_ZIPEntries.end()) {
			return 0;
		}

		zip_stat_t Stat;
		nfInt32 nResult = zip_stat_index(m_ZIParchive, iIterator->second, ZIP_FL_UNCHANGED, &Stat);
		if (nResult != 0)
			throw CNMRException(NMR_ERROR_COULDNOTSTATZIPENTRY);

		return Stat.size;
	}

	POpcPackagePart COpcPackageReader::createPart(_In_ std::string sPath)
	{
		std::string sRealPath = fnRemoveLeadingPathDelimiter (sPath);
		auto iPartIterator = m_Parts.find(sRealPath);
		if (iPartIterator != m_Parts.end()) {
			return iPartIterator->second;
		}

		PImportStream pStream = openZIPEntry(sRealPath);
		if (pStream.get() == nullptr)
			throw CNMRException(NMR_ERROR_COULDNOTCREATEOPCPART);

		POpcPackagePart pPart = std::make_shared<COpcPackagePart>(sRealPath, pStream);
		m_Parts.insert(std::make_pair(sRealPath, pPart));

		std::string sRelationShipName = fnExtractFileName(sRealPath);
		std::string sRelationShipPath = sRealPath.substr(0, sRealPath.length() - sRelationShipName.length());
		sRelationShipPath += "_rels/";
		sRelationShipPath += sRelationShipName;
		sRelationShipPath += "."+m_relationShipExtension;

		PImportStream pRelStream = openZIPEntry(sRelationShipPath);

		if (pRelStream.get() != nullptr) {
			POpcPackageRelationshipReader pReader = std::make_shared<COpcPackageRelationshipReader>(pRelStream, m_pProgressMonitor);

			nfUint32 nCount = pReader->getCount();
			nfUint32 nIndex;

			for (nIndex = 0; nIndex < nCount; nIndex++) {
				POpcPackageRelationship pRelationShip = pReader->getRelationShip(nIndex);
				pPart->addRelationship(pRelationShip->getID(), pRelationShip->getType(), pRelationShip->getTargetPartURI());
			}
		}

		return pPart;
	}

}
<commit_msg>Fix memory leak in libzip when reading files<commit_after>/*++

Copyright (C) 2019 3MF Consortium

All rights reserved.

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

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

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

Abstract:

NMR_OpcPackageReader.cpp defines an OPC Package reader in a portable way.

--*/

#include "Common/OPC/NMR_OpcPackageReader.h"
#include "Common/OPC/NMR_OpcPackageRelationshipReader.h"
#include "Common/OPC/NMR_OpcPackageContentTypesReader.h"
#include "Common/Platform/NMR_ImportStream_ZIP.h"
#include "Common/NMR_Exception.h"
#include "Common/NMR_StringUtils.h"

#include "Model/Classes/NMR_ModelConstants.h"

#include <iostream>

namespace NMR {

	// custom callbck function for reading from a CImportStream on the fly
	zip_int64_t custom_zip_source_callback(void *userData, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
		if (userData == nullptr)
			throw CNMRException(NMR_ERROR_INVALIDPARAM);

		CImportStream* pImportStream = (CImportStream*)(userData);

		switch (cmd) {
			case ZIP_SOURCE_SUPPORTS:
				zip_int64_t bitmap;
				bitmap = zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE,
					ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_SEEK, ZIP_SOURCE_TELL, ZIP_SOURCE_SUPPORTS, -1);
				return bitmap;

			case ZIP_SOURCE_SEEK:
				zip_source_args_seek argsSeek;
				argsSeek = * ((zip_source_args_seek *)data);
				if (argsSeek.whence == SEEK_SET)
					pImportStream->seekPosition(argsSeek.offset, true);
				else if (argsSeek.whence == SEEK_CUR) {
					pImportStream->seekPosition(pImportStream->getPosition() + argsSeek.offset, true);
				}
				else if (argsSeek.whence == SEEK_END) {
					if (argsSeek.offset > 0)
						throw CNMRException(NMR_ERROR_ZIPCALLBACK);
					pImportStream->seekFromEnd(-argsSeek.offset, true);
				}
				else
					throw CNMRException(NMR_ERROR_ZIPCALLBACK);
				return 0;

			case ZIP_SOURCE_OPEN:
				return 0;

			case ZIP_SOURCE_READ:
				return pImportStream->readBuffer((nfByte*)data, len, true);

			case ZIP_SOURCE_CLOSE:
				return 0;

			case ZIP_SOURCE_TELL:
				return pImportStream->getPosition();

			case ZIP_SOURCE_STAT:
				zip_stat_t* zipStat;
				zipStat  = (zip_stat_t*)data;
				zip_stat_init(zipStat);
				zipStat->size = pImportStream->retrieveSize();
				zipStat->valid |= ZIP_STAT_SIZE;
				return sizeof(zip_stat_t);

			case ZIP_SOURCE_FREE:
				return 0;

			default:
				throw CNMRException(NMR_ERROR_ZIPCALLBACK);
		}
		return -1;
	}

	COpcPackageReader::COpcPackageReader(_In_ PImportStream pImportStream, _In_ PModelReaderWarnings pWarnings, _In_ PProgressMonitor pProgressMonitor)
		: m_pWarnings(pWarnings), m_pProgressMonitor(pProgressMonitor)
	{
		if (!pImportStream)
			throw CNMRException(NMR_ERROR_INVALIDPARAM);

		if (!pProgressMonitor)
			throw CNMRException(NMR_ERROR_INVALIDPARAM);

		m_ZIPError.str = nullptr;
		m_ZIPError.sys_err = 0;
		m_ZIPError.zip_err = 0;
		m_ZIParchive = nullptr;
		m_ZIPsource = nullptr;

		try {
			// determine stream size
			nfUint64 nStreamSize = pImportStream->retrieveSize();
			pImportStream->seekPosition(0, true);

			if (nStreamSize == 0)
				throw CNMRException(NMR_ERROR_COULDNOTGETSTREAMPOSITION);

			// create ZIP objects
			zip_error_init(&m_ZIPError);

			bool bUseCallback = true;
			if (bUseCallback) {
				// read ZIP from callback: faster and requires less memory
				m_ZIPsource = zip_source_function_create(custom_zip_source_callback, pImportStream.get(), &m_ZIPError);
			}
			else {
				// read ZIP into memory
				m_Buffer.resize((size_t)nStreamSize);
				pImportStream->readBuffer(&m_Buffer[0], nStreamSize, true);
				m_ZIPsource = zip_source_buffer_create(&m_Buffer[0], (size_t)nStreamSize, 0, &m_ZIPError);
			}
			if (m_ZIPsource == nullptr)
				throw CNMRException(NMR_ERROR_COULDNOTREADZIPFILE);

			m_ZIParchive = zip_open_from_source(m_ZIPsource, ZIP_RDONLY | ZIP_CHECKCONS, &m_ZIPError);
			if (m_ZIParchive == nullptr) {
				m_ZIParchive = zip_open_from_source(m_ZIPsource, ZIP_RDONLY, &m_ZIPError);
				if (m_ZIParchive == nullptr)
					throw CNMRException(NMR_ERROR_COULDNOTREADZIPFILE);
				else
					m_pWarnings->addException(CNMRException(NMR_ERROR_ZIPCONTAINSINCONSISTENCIES), mrwInvalidMandatoryValue);
			}

			// Get ZIP Content
			nfInt64 nEntryCount = zip_get_num_entries(m_ZIParchive, ZIP_FL_UNCHANGED);
			if (nEntryCount < 0)
				throw CNMRException(NMR_ERROR_COULDNOTREADZIPFILE);

			// List and stat Entries
			nfUint64 nUnzippedFileSize = 0;
			for (nfInt64 nIndex = 0; nIndex < nEntryCount; nIndex++) {
				const char * pszName = zip_get_name(m_ZIParchive, (nfUint64) nIndex, ZIP_FL_ENC_GUESS);
				m_ZIPEntries.insert(std::make_pair(pszName, nIndex));

				zip_stat_t Stat;
				nfInt32 nResult = zip_stat_index(m_ZIParchive, nIndex, ZIP_FL_UNCHANGED, &Stat);
				if (nResult != 0)
					throw CNMRException(NMR_ERROR_COULDNOTSTATZIPENTRY);

				nUnzippedFileSize += Stat.size;
			}

			m_pProgressMonitor->SetMaxProgress(double(nUnzippedFileSize));
			m_pProgressMonitor->ReportProgressAndQueryCancelled(true);

			readContentTypes();
			readRootRelationships();
		}
		catch (...)
		{
			releaseZIP();
			throw;
		}
	}

	COpcPackageReader::~COpcPackageReader()
	{
		releaseZIP();
	}

	_Ret_maybenull_ COpcPackageRelationship * COpcPackageReader::findRootRelation(_In_ std::string sRelationType, _In_ nfBool bMustBeUnique)
	{
		COpcPackageRelationship * pResultRelationship = nullptr;
		auto iIterator = m_RootRelationships.begin();
		while (iIterator != m_RootRelationships.end()) {
			POpcPackageRelationship pRelationship = *iIterator;

			std::string sType = pRelationship->getType();
			if (sType == sRelationType) {
				if (pResultRelationship == nullptr) {
					pResultRelationship = pRelationship.get();
				}
				else {
					if (bMustBeUnique)
						m_pWarnings->addException(CNMRException(NMR_ERROR_OPCRELATIONSHIPNOTUNIQUE), eModelReaderWarningLevel::mrwInvalidOptionalValue);
				}

			}
			iIterator++;
		}

		return pResultRelationship;
	}

	void COpcPackageReader::releaseZIP()
	{
		if (m_ZIParchive != nullptr)
			zip_close(m_ZIParchive);

		if (m_ZIPsource != nullptr)
			zip_source_close(m_ZIPsource);

		zip_error_fini(&m_ZIPError);
		m_Buffer.resize(0);

		m_ZIPsource = nullptr;
		m_ZIParchive = nullptr;
	}

	PImportStream COpcPackageReader::openZIPEntry(_In_ std::string sName)
	{
		auto iIterator = m_ZIPEntries.find(sName);
		if (iIterator == m_ZIPEntries.end()) {
			return nullptr;
		}

		return openZIPEntryIndexed(iIterator->second);
	}

	PImportStream COpcPackageReader::openZIPEntryIndexed(_In_ nfUint64 nIndex)
	{
		zip_stat_t Stat;
		nfInt32 nResult = zip_stat_index(m_ZIParchive, nIndex, ZIP_FL_UNCHANGED, &Stat);
		if (nResult != 0)
			throw CNMRException(NMR_ERROR_COULDNOTSTATZIPENTRY);

		nfUint64 nSize = Stat.size;

		zip_file_t * pFile = zip_fopen_index(m_ZIParchive, nIndex, ZIP_FL_UNCHANGED);
		if (pFile == nullptr)
			throw CNMRException(NMR_ERROR_COULDNOTOPENZIPENTRY);

		return std::make_shared<CImportStream_ZIP>(pFile, nSize);
	}

	void COpcPackageReader::readContentTypes()
	{
		PImportStream pContentStream = openZIPEntry(OPCPACKAGE_PATH_CONTENTTYPES);

		POpcPackageContentTypesReader pReader = std::make_shared<COpcPackageContentTypesReader>(pContentStream, m_pProgressMonitor);

		nfUint32 nCount = pReader->getCount();
		nfUint32 nIndex;

		std::string modelExtension = "";
		std::string modelPart = "";
		m_relationShipExtension = "";
		for (nIndex = 0; nIndex < nCount; nIndex++) {
			POpcPackageContentType pContentType = pReader->getContentType(nIndex);
			if (pContentType->m_contentType == PACKAGE_3D_RELS_CONTENT_TYPE) {
				m_relationShipExtension = pContentType->m_extension;
			}
			if (pContentType->m_contentType == PACKAGE_3D_MODEL_CONTENT_TYPE) {
				modelExtension = pContentType->m_extension;
			}
		}
		if (m_relationShipExtension.empty())
			throw CNMRException(NMR_ERROR_OPC_MISSING_EXTENSION_FOR_RELATIONSHIP);

		nCount = pReader->getOverrideCount();
		for (nIndex = 0; nIndex < nCount; nIndex++) {
			POpcPackageContentType_Override pOverrideContentType = pReader->getOverrideContentType(nIndex);
			if (pOverrideContentType->m_contentType == PACKAGE_3D_MODEL_CONTENT_TYPE) {
				modelPart = pOverrideContentType->m_partName;
			}
		}

		if (modelExtension.empty() && modelPart.empty())
			throw CNMRException(NMR_ERROR_OPC_MISSING_EXTENSION_FOR_MODEL);
	}

	void COpcPackageReader::readRootRelationships()
	{
		PImportStream pRelStream = openZIPEntry(OPCPACKAGE_PATH_ROOTRELATIONSHIPS);

		POpcPackageRelationshipReader pReader = std::make_shared<COpcPackageRelationshipReader>(pRelStream, m_pProgressMonitor);

		nfUint32 nCount = pReader->getCount();
		nfUint32 nIndex;

		for (nIndex = 0; nIndex < nCount; nIndex++) {
			m_RootRelationships.push_back(pReader->getRelationShip(nIndex));
		}
	}

	nfUint64 COpcPackageReader::GetPartSize(_In_ std::string sPath)
	{
		std::string sRealPath = fnRemoveLeadingPathDelimiter(sPath);
		auto iIterator = m_ZIPEntries.find(sRealPath);
		if (iIterator == m_ZIPEntries.end()) {
			return 0;
		}

		zip_stat_t Stat;
		nfInt32 nResult = zip_stat_index(m_ZIParchive, iIterator->second, ZIP_FL_UNCHANGED, &Stat);
		if (nResult != 0)
			throw CNMRException(NMR_ERROR_COULDNOTSTATZIPENTRY);

		return Stat.size;
	}

	POpcPackagePart COpcPackageReader::createPart(_In_ std::string sPath)
	{
		std::string sRealPath = fnRemoveLeadingPathDelimiter (sPath);
		auto iPartIterator = m_Parts.find(sRealPath);
		if (iPartIterator != m_Parts.end()) {
			return iPartIterator->second;
		}

		PImportStream pStream = openZIPEntry(sRealPath);
		if (pStream.get() == nullptr)
			throw CNMRException(NMR_ERROR_COULDNOTCREATEOPCPART);

		POpcPackagePart pPart = std::make_shared<COpcPackagePart>(sRealPath, pStream);
		m_Parts.insert(std::make_pair(sRealPath, pPart));

		std::string sRelationShipName = fnExtractFileName(sRealPath);
		std::string sRelationShipPath = sRealPath.substr(0, sRealPath.length() - sRelationShipName.length());
		sRelationShipPath += "_rels/";
		sRelationShipPath += sRelationShipName;
		sRelationShipPath += "."+m_relationShipExtension;

		PImportStream pRelStream = openZIPEntry(sRelationShipPath);

		if (pRelStream.get() != nullptr) {
			POpcPackageRelationshipReader pReader = std::make_shared<COpcPackageRelationshipReader>(pRelStream, m_pProgressMonitor);

			nfUint32 nCount = pReader->getCount();
			nfUint32 nIndex;

			for (nIndex = 0; nIndex < nCount; nIndex++) {
				POpcPackageRelationship pRelationShip = pReader->getRelationShip(nIndex);
				pPart->addRelationship(pRelationShip->getID(), pRelationShip->getType(), pRelationShip->getTargetPartURI());
			}
		}

		return pPart;
	}

}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "platform/fonts/FontFallbackList.h"

#include "FontFamilyNames.h"
#include "platform/fonts/FontCache.h"
#include "platform/fonts/FontDescription.h"
#include "platform/fonts/FontFamily.h"
#include "platform/fonts/SegmentedFontData.h"

namespace WebCore {

FontFallbackList::FontFallbackList()
    : m_pageZero(0)
    , m_cachedPrimarySimpleFontData(0)
    , m_fontSelector(nullptr)
    , m_fontSelectorVersion(0)
    , m_familyIndex(0)
    , m_generation(FontCache::fontCache()->generation())
    , m_pitch(UnknownPitch)
    , m_loadingCustomFonts(false)
{
}

void FontFallbackList::invalidate(PassRefPtr<FontSelector> fontSelector)
{
    releaseFontData();
    m_fontList.clear();
    m_pageZero = 0;
    m_pages.clear();
    m_cachedPrimarySimpleFontData = 0;
    m_familyIndex = 0;
    m_pitch = UnknownPitch;
    m_loadingCustomFonts = false;
    m_fontSelector = fontSelector;
    m_fontSelectorVersion = m_fontSelector ? m_fontSelector->version() : 0;
    m_generation = FontCache::fontCache()->generation();
    m_widthCache.clear();
}

void FontFallbackList::releaseFontData()
{
    unsigned numFonts = m_fontList.size();
    for (unsigned i = 0; i < numFonts; ++i) {
        if (!m_fontList[i]->isCustomFont()) {
            ASSERT(!m_fontList[i]->isSegmented());
            FontCache::fontCache()->releaseFontData(static_cast<const SimpleFontData*>(m_fontList[i].get()));
        }
    }
}

void FontFallbackList::determinePitch(const FontDescription& fontDescription) const
{
    const FontData* fontData = primaryFontData(fontDescription);
    if (!fontData->isSegmented())
        m_pitch = static_cast<const SimpleFontData*>(fontData)->pitch();
    else {
        const SegmentedFontData* segmentedFontData = static_cast<const SegmentedFontData*>(fontData);
        unsigned numRanges = segmentedFontData->numRanges();
        if (numRanges == 1 && segmentedFontData->rangeAt(0).isEntireRange())
            m_pitch = segmentedFontData->rangeAt(0).fontData()->pitch();
        else
            m_pitch = VariablePitch;
    }
}

bool FontFallbackList::loadingCustomFonts() const
{
    if (m_loadingCustomFonts)
        return true;

    unsigned numFonts = m_fontList.size();
    for (unsigned i = 0; i < numFonts; ++i) {
        if (m_fontList[i]->isCustomFont() && m_fontList[i]->isLoading()) {
            m_loadingCustomFonts = true;
            return true;
        }
    }
    return false;
}

const FontData* FontFallbackList::primaryFontData(const FontDescription& fontDescription) const
{
    bool shouldLoadCustomFont = true;

    for (unsigned fontIndex = 0; ; ++fontIndex) {
        const FontData* fontData = fontDataAt(fontDescription, fontIndex);
        if (!fontData) {
            // All fonts are custom fonts and are loading. Return the first FontData.
            // FIXME: Correct fallback to the default font.
            return fontDataAt(fontDescription, 0);
        }

        if (fontData->isSegmented() && !toSegmentedFontData(fontData)->containsCharacter(' '))
            continue;

        // When a custom font is loading, we should use the correct fallback font to layout the text.
        // Here skip the temporary font for the loading custom font which may not act as the correct fallback font.
        if (!fontData->isLoadingFallback())
            return fontData;

        // Begin to load the first custom font if needed.
        if (shouldLoadCustomFont) {
            shouldLoadCustomFont = false;
            const SimpleFontData* simpleFontData = fontData->fontDataForCharacter(' ');
            if (simpleFontData && simpleFontData->customFontData())
                simpleFontData->customFontData()->beginLoadIfNeeded();
        }
    }
}

PassRefPtr<FontData> FontFallbackList::getFontData(const FontDescription& fontDescription, int& familyIndex) const
{
    RefPtr<FontData> result;

    int startIndex = familyIndex;
    const FontFamily* startFamily = &fontDescription.family();
    for (int i = 0; startFamily && i < startIndex; i++)
        startFamily = startFamily->next();
    const FontFamily* currFamily = startFamily;
    while (currFamily && !result) {
        familyIndex++;
        if (currFamily->family().length()) {
            if (m_fontSelector)
                result = m_fontSelector->getFontData(fontDescription, currFamily->family());

            if (!result)
                result = FontCache::fontCache()->getFontData(fontDescription, currFamily->family());
        }
        currFamily = currFamily->next();
    }

    if (!currFamily)
        familyIndex = cAllFamiliesScanned;

    if (result || startIndex)
        return result.release();

    // If it's the primary font that we couldn't find, we try the following. In all other cases, we will
    // just use per-character system fallback.

    if (m_fontSelector) {
        // Try the user's preferred standard font.
        if (RefPtr<FontData> data = m_fontSelector->getFontData(fontDescription, FontFamilyNames::webkit_standard))
            return data.release();
    }

    // Still no result. Hand back our last resort fallback font.
    return FontCache::fontCache()->getLastResortFallbackFont(fontDescription);
}

const FontData* FontFallbackList::fontDataAt(const FontDescription& fontDescription, unsigned realizedFontIndex) const
{
    if (realizedFontIndex < m_fontList.size())
        return m_fontList[realizedFontIndex].get(); // This fallback font is already in our list.

    // Make sure we're not passing in some crazy value here.
    ASSERT(realizedFontIndex == m_fontList.size());

    if (m_familyIndex == cAllFamiliesScanned)
        return 0;

    // Ask the font cache for the font data.
    // We are obtaining this font for the first time.  We keep track of the families we've looked at before
    // in |m_familyIndex|, so that we never scan the same spot in the list twice.  getFontData will adjust our
    // |m_familyIndex| as it scans for the right font to make.
    ASSERT(FontCache::fontCache()->generation() == m_generation);
    RefPtr<FontData> result = getFontData(fontDescription, m_familyIndex);
    if (result) {
        m_fontList.append(result);
        if (result->isLoading())
            m_loadingCustomFonts = true;
    }
    return result.get();
}

}
<commit_msg>Add last resort to fallback chain in FontFallbackList::primaryFontData<commit_after>/*
 * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "platform/fonts/FontFallbackList.h"

#include "FontFamilyNames.h"
#include "platform/fonts/FontCache.h"
#include "platform/fonts/FontDescription.h"
#include "platform/fonts/FontFamily.h"
#include "platform/fonts/SegmentedFontData.h"

namespace WebCore {

FontFallbackList::FontFallbackList()
    : m_pageZero(0)
    , m_cachedPrimarySimpleFontData(0)
    , m_fontSelector(nullptr)
    , m_fontSelectorVersion(0)
    , m_familyIndex(0)
    , m_generation(FontCache::fontCache()->generation())
    , m_pitch(UnknownPitch)
    , m_loadingCustomFonts(false)
{
}

void FontFallbackList::invalidate(PassRefPtr<FontSelector> fontSelector)
{
    releaseFontData();
    m_fontList.clear();
    m_pageZero = 0;
    m_pages.clear();
    m_cachedPrimarySimpleFontData = 0;
    m_familyIndex = 0;
    m_pitch = UnknownPitch;
    m_loadingCustomFonts = false;
    m_fontSelector = fontSelector;
    m_fontSelectorVersion = m_fontSelector ? m_fontSelector->version() : 0;
    m_generation = FontCache::fontCache()->generation();
    m_widthCache.clear();
}

void FontFallbackList::releaseFontData()
{
    unsigned numFonts = m_fontList.size();
    for (unsigned i = 0; i < numFonts; ++i) {
        if (!m_fontList[i]->isCustomFont()) {
            ASSERT(!m_fontList[i]->isSegmented());
            FontCache::fontCache()->releaseFontData(static_cast<const SimpleFontData*>(m_fontList[i].get()));
        }
    }
}

void FontFallbackList::determinePitch(const FontDescription& fontDescription) const
{
    const FontData* fontData = primaryFontData(fontDescription);
    if (!fontData->isSegmented())
        m_pitch = static_cast<const SimpleFontData*>(fontData)->pitch();
    else {
        const SegmentedFontData* segmentedFontData = static_cast<const SegmentedFontData*>(fontData);
        unsigned numRanges = segmentedFontData->numRanges();
        if (numRanges == 1 && segmentedFontData->rangeAt(0).isEntireRange())
            m_pitch = segmentedFontData->rangeAt(0).fontData()->pitch();
        else
            m_pitch = VariablePitch;
    }
}

bool FontFallbackList::loadingCustomFonts() const
{
    if (m_loadingCustomFonts)
        return true;

    unsigned numFonts = m_fontList.size();
    for (unsigned i = 0; i < numFonts; ++i) {
        if (m_fontList[i]->isCustomFont() && m_fontList[i]->isLoading()) {
            m_loadingCustomFonts = true;
            return true;
        }
    }
    return false;
}

const FontData* FontFallbackList::primaryFontData(const FontDescription& fontDescription) const
{
    bool shouldLoadCustomFont = true;

    for (unsigned fontIndex = 0; ; ++fontIndex) {
        const FontData* fontData = fontDataAt(fontDescription, fontIndex);
        if (!fontData) {
            // All fonts are custom fonts and are loading. Return the first FontData.
            fontData = fontDataAt(fontDescription, 0);
            if (!fontData)
                fontData = FontCache::fontCache()->getLastResortFallbackFont(fontDescription).get();
            ASSERT(fontData);
            return fontData;
        }

        if (fontData->isSegmented() && !toSegmentedFontData(fontData)->containsCharacter(' '))
            continue;

        // When a custom font is loading, we should use the correct fallback font to layout the text.
        // Here skip the temporary font for the loading custom font which may not act as the correct fallback font.
        if (!fontData->isLoadingFallback())
            return fontData;

        // Begin to load the first custom font if needed.
        if (shouldLoadCustomFont) {
            shouldLoadCustomFont = false;
            const SimpleFontData* simpleFontData = fontData->fontDataForCharacter(' ');
            if (simpleFontData && simpleFontData->customFontData())
                simpleFontData->customFontData()->beginLoadIfNeeded();
        }
    }
}

PassRefPtr<FontData> FontFallbackList::getFontData(const FontDescription& fontDescription, int& familyIndex) const
{
    RefPtr<FontData> result;

    int startIndex = familyIndex;
    const FontFamily* startFamily = &fontDescription.family();
    for (int i = 0; startFamily && i < startIndex; i++)
        startFamily = startFamily->next();
    const FontFamily* currFamily = startFamily;
    while (currFamily && !result) {
        familyIndex++;
        if (currFamily->family().length()) {
            if (m_fontSelector)
                result = m_fontSelector->getFontData(fontDescription, currFamily->family());

            if (!result)
                result = FontCache::fontCache()->getFontData(fontDescription, currFamily->family());
        }
        currFamily = currFamily->next();
    }

    if (!currFamily)
        familyIndex = cAllFamiliesScanned;

    if (result || startIndex)
        return result.release();

    // If it's the primary font that we couldn't find, we try the following. In all other cases, we will
    // just use per-character system fallback.

    if (m_fontSelector) {
        // Try the user's preferred standard font.
        if (RefPtr<FontData> data = m_fontSelector->getFontData(fontDescription, FontFamilyNames::webkit_standard))
            return data.release();
    }

    // Still no result. Hand back our last resort fallback font.
    return FontCache::fontCache()->getLastResortFallbackFont(fontDescription);
}

const FontData* FontFallbackList::fontDataAt(const FontDescription& fontDescription, unsigned realizedFontIndex) const
{
    if (realizedFontIndex < m_fontList.size())
        return m_fontList[realizedFontIndex].get(); // This fallback font is already in our list.

    // Make sure we're not passing in some crazy value here.
    ASSERT(realizedFontIndex == m_fontList.size());

    if (m_familyIndex == cAllFamiliesScanned)
        return 0;

    // Ask the font cache for the font data.
    // We are obtaining this font for the first time.  We keep track of the families we've looked at before
    // in |m_familyIndex|, so that we never scan the same spot in the list twice.  getFontData will adjust our
    // |m_familyIndex| as it scans for the right font to make.
    ASSERT(FontCache::fontCache()->generation() == m_generation);
    RefPtr<FontData> result = getFontData(fontDescription, m_familyIndex);
    if (result) {
        m_fontList.append(result);
        if (result->isLoading())
            m_loadingCustomFonts = true;
    }
    return result.get();
}

}
<|endoftext|>


<commit_before>#include "Relocation.h"

#include "Builder.h"
#include "Instruction.h"
#include "Object.h"
#include "SBTError.h"
#include "Section.h"
#include "ShadowImage.h"
#include "Translator.h"

#include <llvm/IR/Module.h>
#include <llvm/Object/ELF.h>
#include <llvm/Support/FormatVariadic.h>

#undef ENABLE_DBGS
#define ENABLE_DBGS 1
#include "Debug.h"

#include <functional>

namespace sbt {

SBTRelocation::SBTRelocation(
    Context* ctx,
    ConstRelocIter ri,
    ConstRelocIter re,
    ConstSectionPtr section)
    :
    _ctx(ctx),
    _ri(ri),
    _re(re),
    _section(section),
    _cur(nextReloc(true)),
    _curP(nullptr)
{
}

ConstRelocationPtr SBTRelocation::nextReloc(bool init)
{
    if (init)
        _cur = _ri == _re? nullptr : *_ri;
    else {
        xassert(_cur == *_ri);
        ++_ri;
        if (_ri != _re)
            _cur = *_ri;
        else
            _cur = nullptr;
    }

    // skip relax
    if (_cur && _cur->type() == llvm::ELF::R_RISCV_RELAX)
        return nextReloc();
    return _cur;
}

ConstRelocationPtr SBTRelocation::nextPReloc()
{
    xassert(_curP == _proxyRelocs.front());
    _proxyRelocs.pop();
    if (!_proxyRelocs.empty())
        _curP = _proxyRelocs.front();
    else
        _curP = nullptr;
    return _curP;
}

ConstRelocationPtr SBTRelocation::getReloc(uint64_t addr)
{
    if (!_cur && !_curP)
        return nullptr;

    // check if we skipped some addresses and now need to
    // advance the iterator
    while (_cur && addr > _cur->offset())
        nextReloc();
    while (_curP && addr > _curP->offset())
        nextPReloc();

    ConstRelocationPtr ret = nullptr, next = nullptr;
    if (_cur && _cur->offset() == addr) {
        ret = _cur;
        next = nextReloc();
    } else if (_curP && _curP->offset() == addr) {
        ret = _curP;
        next = nextPReloc();
    }

    xassert(!next || next->offset() != addr);
    return ret;
}

void SBTRelocation::skipRelocation(uint64_t addr)
{
    // check if there is a relocation for current address
    getReloc(addr);
}

void SBTRelocation::addProxyReloc(ConstRelocationPtr reloc,
    Relocation::RType rtype)
{
    const LLVMRelocation* llrel = static_cast<const LLVMRelocation*>(&*reloc);
    ProxyRelocation* hi = new ProxyRelocation(*llrel);
    ProxyRelocation* lo = new ProxyRelocation(*llrel);

    switch (rtype) {
        case Relocation::PROXY:
            hi->setType(Relocation::PROXY_HI);
            lo->setType(Relocation::PROXY_LO);
            break;
        case Relocation::PROXY_PCREL:
            hi->setType(Relocation::PROXY_PCREL_HI);
            lo->setType(Relocation::PROXY_PCREL_LO);
            lo->setHiPC(hi->offset());
            break;
        case Relocation::PROXY_CALL:
            hi->setType(Relocation::PROXY_CALL_HI);
            lo->setType(Relocation::PROXY_CALL_LO);
            break;
        default:
            xunreachable("Unknown proxy relocation type");
    }

    lo->setOffset(hi->offset() + Constants::INSTRUCTION_SIZE);

    _proxyRelocs.emplace(hi);
    _proxyRelocs.emplace(lo);

    if (!_curP)
        _curP = _proxyRelocs.front();
}

llvm::Expected<llvm::Constant*>
SBTRelocation::handleRelocation(uint64_t addr, llvm::raw_ostream* os)
{
    ConstRelocationPtr reloc = getReloc(addr);

    // no more relocations exist
    if (!reloc)
        return nullptr;

    DBGS << __METHOD_NAME__ << llvm::formatv("({0:X+8})\n", addr);
    DBGF("{0}", reloc->str());

    std::function<llvm::Constant*(llvm::Constant* addr)> relfn;

    switch (reloc->type()) {
        case Relocation::PROXY_HI:
        case llvm::ELF::R_RISCV_HI20:
            // hi20 = (symbol_address + 0x800) >> 12
            relfn = [this](llvm::Constant* addr) {
                llvm::Constant* c = llvm::ConstantExpr::getAdd(
                    addr, _ctx->c.u32(0x800));
                c = llvm::ConstantExpr::getLShr(c, _ctx->c.u32(12));
                return c;
            };
            break;

        case Relocation::PROXY_LO:
        case llvm::ELF::R_RISCV_LO12_I:
        case llvm::ELF::R_RISCV_LO12_S:
            // lo12 = symbol_address - hi20
            // hi20 = (symbol_address + 0x800) & 0xFFFFF000
            relfn = [this](llvm::Constant* addr) {
                llvm::Constant* hi20 = llvm::ConstantExpr::getAdd(
                    addr, _ctx->c.u32(0x800));
                hi20 = llvm::ConstantExpr::getAnd(
                    hi20, _ctx->c.u32(0xFFFFF000));

                llvm::Constant* c = llvm::ConstantExpr::getSub(addr, hi20);
                return c;
            };
            break;

        case Relocation::PROXY_CALL_HI:
        case Relocation::PROXY_PCREL_HI:
            // hi20 = (symbol_address - pc + 0x800) >> 12
            relfn = [this, addr](llvm::Constant* symaddr) {
                llvm::Constant* c = llvm::ConstantExpr::getSub(
                    symaddr, _ctx->c.u32(addr));
                c = llvm::ConstantExpr::getAdd(c, _ctx->c.u32(0x800));
                c = llvm::ConstantExpr::getLShr(c, _ctx->c.u32(12));
                return c;
            };
            break;

        case Relocation::PROXY_CALL_LO:
        case Relocation::PROXY_PCREL_LO:
            // lo12 = symbol_address - hipc - hi20
            // hi20 = (symbol_address - hipc + 0x800) & 0xFFFFF000
            relfn = [this, &reloc](llvm::Constant* symaddr) {
                const ProxyRelocation* pr =
                    static_cast<const ProxyRelocation*>(reloc.get());
                llvm::Constant* hipc = _ctx->c.u32(pr->hiPC());

                llvm::Constant* hi20 = llvm::ConstantExpr::getSub(
                    symaddr, hipc);
                hi20 = llvm::ConstantExpr::getAdd(hi20, _ctx->c.u32(0x800));
                hi20 = llvm::ConstantExpr::getAnd(
                        hi20, _ctx->c.u32(0xFFFFF000));

                llvm::Constant* c = llvm::ConstantExpr::getSub(
                    symaddr, hipc);
                c = llvm::ConstantExpr::getSub(c, hi20);
                return c;
            };
            break;

        case llvm::ELF::R_RISCV_CALL:
            addProxyReloc(reloc, Relocation::PROXY_CALL);
            return handleRelocation(addr, os);

        case llvm::ELF::R_RISCV_PCREL_HI20:
        case llvm::ELF::R_RISCV_PCREL_LO12_I:
        case llvm::ELF::R_RISCV_PCREL_LO12_S:
        default:
            xunreachable("unknown relocation");
    }

    bool isLocalFunc = reloc->isLocalFunction();
    bool isExt = reloc->isExternal();
    reloc->validate();

    llvm::Constant* c = nullptr;

    // external symbol case: handle data or function
    if (isExt) {
        auto expAddr =_ctx->translator->import(reloc->symName());
        if (!expAddr)
            return expAddr.takeError();
        uint64_t saddr = expAddr.get().first;
        const std::string& xfunc = expAddr.get().second;

        // data
        if (saddr == SYM_TYPE_DATA) {
            DBGF("external data: saddr={0:X+8}", saddr);

            const Types& t = _ctx->t;
            c = _ctx->module->getOrInsertGlobal(reloc->symName(), t.i32);
            c = llvm::ConstantExpr::getPointerCast(c, t.i32);

        // handle external function
        } else {
            DBGF("external function: saddr={0:X+8}", saddr);
            c = _ctx->c.i32(saddr);
        }

        if (os)
            *os << xfunc;

    // internal function or label case
    // XXX we rely on symbol information to distinguish
    //     between function or label (see isFunction())
    } else if (isLocalFunc) {
        // get address
        uint64_t saddr;
        if (reloc->hasSym())
            saddr = reloc->symAddr();
        else
            saddr = reloc->addend();

        bool isFunc = Function::isFunction(_ctx, saddr);
        Function* f = _ctx->funcByAddr(saddr, !ASSERT_NOT_NULL);

        if (isFunc) {
            if (!f) {
                // function not found: it should be ahead of current
                // translation address
                xassert(saddr > _ctx->addr);
                f = Function::getByAddr(_ctx, saddr);
            }

            DBGF("internal function: name=\"{0}\", saddr={1:X+8}",
                f->name(), saddr);
            if (os)
                *os << f->name();
        } else {
            DBGF("internal label: saddr={0:X+8}", saddr);
            if (os)
                *os << llvm::formatv("{0:X+8}", saddr);
        }

        // XXX for now, internal functions are always called
        //     indirectly, via icaller, so return just their
        //     original guest address
        c = _ctx->c.i32(saddr);

    // other relocations
    // add the relocation offset to ShadowImage to get the final address
    } else {
        xassert(reloc->hasSec());
        uint64_t saddr;

        if (reloc->hasSym()) {
            DBGF("symbol reloc: symbol=\"{0}\", addend={1:X+8}, section=\"{2}\"",
                reloc->symName(), reloc->addend(), reloc->secName());

            saddr = reloc->symAddr() + reloc->addend();

            if (os)
                *os << reloc->symName();

        } else {
            DBGF("section reloc: section=\"{0}\", addend={1:X+8}",
                reloc->secName(), reloc->addend());

            saddr = reloc->addend();

            if (os)
                *os << llvm::formatv("{0}+{1:X+8}",
                    reloc->secName(), reloc->addend());
        }

        // TODO speed up section lookup for relocations
        c = llvm::ConstantExpr::getAdd(
            _ctx->shadowImage->getSection(reloc->secName()),
            _ctx->c.i32(saddr));
    }

    _lastSymVal = c;
    c = relfn(c);
    DBG(c->dump());
    _last = reloc;
    return c;
}

bool SBTRelocation::isCall(uint64_t addr) const
{
    return _last && _last->offset() == addr &&
        _last->type() == Relocation::PROXY_CALL_LO;
}

llvm::Constant* SBTRelocation::lastSymVal() const
{
    xassert(_lastSymVal);
    return _lastSymVal;
}

llvm::GlobalVariable* SBTRelocation::relocateSection(
    const std::vector<uint8_t>& bytes,
    const ShadowImage* shadowImage)
{
    xassert(_section);
    DBGF("relocating section {0}", _section->name());
    std::vector<llvm::Constant*> cvec;

    size_t n = bytes.size();
    ConstRelocIter rit = _ri;

    for (size_t addr = 0; addr < n; addr+=4) {
        // reloc
        if (rit != _re && addr == (*rit)->offset()) {
            ConstRelocationPtr reloc = *rit;
            switch (reloc->type()) {
                case llvm::ELF::R_RISCV_32: {
                    uint64_t addr = reloc->addend();
                    xassert(reloc->hasSec());
                    if (reloc->hasSym()) {
                        addr += reloc->symAddr();
                        DBGF(
                            "relocating {0:X-8}: "
                            "symbol=\"{1}\", symaddr={2:X+8}, "
                            "section=\"{3}\", addend={4:X+8}, "
                            "addr={5:X-8}",
                            reloc->offset(),
                            reloc->symName(), reloc->symAddr(),
                            reloc->secName(), reloc->addend(),
                            addr);
                    } else {
                        DBGF(
                            "relocating {0:X-8}: "
                            "section=\"{1}\", addend={2:X+8}",
                            reloc->offset(),
                            reloc->secName(), reloc->addend());
                    }

                    llvm::Constant* cexpr =
                        llvm::ConstantExpr::getAdd(
                            shadowImage->getSection(reloc->secName()),
                            _ctx->c.u32(addr));
                    cvec.push_back(cexpr);
                    break;
                }

                default:
                    DBGF("unknown relocation type: {0}", reloc->type());
                    xunreachable("Unsupported relocation type");
            }
            ++rit;
        // or just copy the raw bytes
        } else {
            uint32_t val = *(uint32_t*)&bytes[addr];
            DBGF("copying raw bytes @{0:X-8}: {1:X-8}", addr, val);
            cvec.push_back(_ctx->c.u32(val));
        }
    }

    llvm::ArrayType* aty = llvm::ArrayType::get(_ctx->t.i32, cvec.size());
    llvm::Constant* ca = llvm::ConstantArray::get(aty, cvec);
    return new llvm::GlobalVariable(*_ctx->module, ca->getType(),
        !CONSTANT, llvm::GlobalValue::ExternalLinkage, ca);
}

}
<commit_msg>Fix SBT crash<commit_after>#include "Relocation.h"

#include "Builder.h"
#include "Instruction.h"
#include "Object.h"
#include "SBTError.h"
#include "Section.h"
#include "ShadowImage.h"
#include "Translator.h"

#include <llvm/IR/Module.h>
#include <llvm/Object/ELF.h>
#include <llvm/Support/FormatVariadic.h>

#undef ENABLE_DBGS
#define ENABLE_DBGS 1
#include "Debug.h"

#include <functional>

namespace sbt {

SBTRelocation::SBTRelocation(
    Context* ctx,
    ConstRelocIter ri,
    ConstRelocIter re,
    ConstSectionPtr section)
    :
    _ctx(ctx),
    _ri(ri),
    _re(re),
    _section(section),
    _cur(nullptr),
    _curP(nullptr)
{
    _cur = nextReloc(true);
}

ConstRelocationPtr SBTRelocation::nextReloc(bool init)
{
    if (init)
        _cur = _ri == _re? nullptr : *_ri;
    else {
        xassert(_cur == *_ri);
        ++_ri;
        if (_ri != _re)
            _cur = *_ri;
        else
            _cur = nullptr;
    }

    // skip relax
    if (_cur && _cur->type() == llvm::ELF::R_RISCV_RELAX)
        return nextReloc();
    return _cur;
}

ConstRelocationPtr SBTRelocation::nextPReloc()
{
    xassert(_curP == _proxyRelocs.front());
    _proxyRelocs.pop();
    if (!_proxyRelocs.empty())
        _curP = _proxyRelocs.front();
    else
        _curP = nullptr;
    return _curP;
}

ConstRelocationPtr SBTRelocation::getReloc(uint64_t addr)
{
    if (!_cur && !_curP)
        return nullptr;

    // check if we skipped some addresses and now need to
    // advance the iterator
    while (_cur && addr > _cur->offset())
        nextReloc();
    while (_curP && addr > _curP->offset())
        nextPReloc();

    ConstRelocationPtr ret = nullptr, next = nullptr;
    if (_cur && _cur->offset() == addr) {
        ret = _cur;
        next = nextReloc();
    } else if (_curP && _curP->offset() == addr) {
        ret = _curP;
        next = nextPReloc();
    }

    xassert(!next || next->offset() != addr);
    return ret;
}

void SBTRelocation::skipRelocation(uint64_t addr)
{
    // check if there is a relocation for current address
    getReloc(addr);
}

void SBTRelocation::addProxyReloc(ConstRelocationPtr reloc,
    Relocation::RType rtype)
{
    const LLVMRelocation* llrel = static_cast<const LLVMRelocation*>(&*reloc);
    ProxyRelocation* hi = new ProxyRelocation(*llrel);
    ProxyRelocation* lo = new ProxyRelocation(*llrel);

    switch (rtype) {
        case Relocation::PROXY:
            hi->setType(Relocation::PROXY_HI);
            lo->setType(Relocation::PROXY_LO);
            break;
        case Relocation::PROXY_PCREL:
            hi->setType(Relocation::PROXY_PCREL_HI);
            lo->setType(Relocation::PROXY_PCREL_LO);
            lo->setHiPC(hi->offset());
            break;
        case Relocation::PROXY_CALL:
            hi->setType(Relocation::PROXY_CALL_HI);
            lo->setType(Relocation::PROXY_CALL_LO);
            break;
        default:
            xunreachable("Unknown proxy relocation type");
    }

    lo->setOffset(hi->offset() + Constants::INSTRUCTION_SIZE);

    _proxyRelocs.emplace(hi);
    _proxyRelocs.emplace(lo);

    if (!_curP)
        _curP = _proxyRelocs.front();
}

llvm::Expected<llvm::Constant*>
SBTRelocation::handleRelocation(uint64_t addr, llvm::raw_ostream* os)
{
    ConstRelocationPtr reloc = getReloc(addr);

    // no more relocations exist
    if (!reloc)
        return nullptr;

    DBGS << __METHOD_NAME__ << llvm::formatv("({0:X+8})\n", addr);
    DBGF("{0}", reloc->str());

    std::function<llvm::Constant*(llvm::Constant* addr)> relfn;

    switch (reloc->type()) {
        case Relocation::PROXY_HI:
        case llvm::ELF::R_RISCV_HI20:
            // hi20 = (symbol_address + 0x800) >> 12
            relfn = [this](llvm::Constant* addr) {
                llvm::Constant* c = llvm::ConstantExpr::getAdd(
                    addr, _ctx->c.u32(0x800));
                c = llvm::ConstantExpr::getLShr(c, _ctx->c.u32(12));
                return c;
            };
            break;

        case Relocation::PROXY_LO:
        case llvm::ELF::R_RISCV_LO12_I:
        case llvm::ELF::R_RISCV_LO12_S:
            // lo12 = symbol_address - hi20
            // hi20 = (symbol_address + 0x800) & 0xFFFFF000
            relfn = [this](llvm::Constant* addr) {
                llvm::Constant* hi20 = llvm::ConstantExpr::getAdd(
                    addr, _ctx->c.u32(0x800));
                hi20 = llvm::ConstantExpr::getAnd(
                    hi20, _ctx->c.u32(0xFFFFF000));

                llvm::Constant* c = llvm::ConstantExpr::getSub(addr, hi20);
                return c;
            };
            break;

        case Relocation::PROXY_CALL_HI:
        case Relocation::PROXY_PCREL_HI:
            // hi20 = (symbol_address - pc + 0x800) >> 12
            relfn = [this, addr](llvm::Constant* symaddr) {
                llvm::Constant* c = llvm::ConstantExpr::getSub(
                    symaddr, _ctx->c.u32(addr));
                c = llvm::ConstantExpr::getAdd(c, _ctx->c.u32(0x800));
                c = llvm::ConstantExpr::getLShr(c, _ctx->c.u32(12));
                return c;
            };
            break;

        case Relocation::PROXY_CALL_LO:
        case Relocation::PROXY_PCREL_LO:
            // lo12 = symbol_address - hipc - hi20
            // hi20 = (symbol_address - hipc + 0x800) & 0xFFFFF000
            relfn = [this, &reloc](llvm::Constant* symaddr) {
                const ProxyRelocation* pr =
                    static_cast<const ProxyRelocation*>(reloc.get());
                llvm::Constant* hipc = _ctx->c.u32(pr->hiPC());

                llvm::Constant* hi20 = llvm::ConstantExpr::getSub(
                    symaddr, hipc);
                hi20 = llvm::ConstantExpr::getAdd(hi20, _ctx->c.u32(0x800));
                hi20 = llvm::ConstantExpr::getAnd(
                        hi20, _ctx->c.u32(0xFFFFF000));

                llvm::Constant* c = llvm::ConstantExpr::getSub(
                    symaddr, hipc);
                c = llvm::ConstantExpr::getSub(c, hi20);
                return c;
            };
            break;

        case llvm::ELF::R_RISCV_CALL:
            addProxyReloc(reloc, Relocation::PROXY_CALL);
            return handleRelocation(addr, os);

        case llvm::ELF::R_RISCV_PCREL_HI20:
        case llvm::ELF::R_RISCV_PCREL_LO12_I:
        case llvm::ELF::R_RISCV_PCREL_LO12_S:
        default:
            xunreachable("unknown relocation");
    }

    bool isLocalFunc = reloc->isLocalFunction();
    bool isExt = reloc->isExternal();
    reloc->validate();

    llvm::Constant* c = nullptr;

    // external symbol case: handle data or function
    if (isExt) {
        auto expAddr =_ctx->translator->import(reloc->symName());
        if (!expAddr)
            return expAddr.takeError();
        uint64_t saddr = expAddr.get().first;
        const std::string& xfunc = expAddr.get().second;

        // data
        if (saddr == SYM_TYPE_DATA) {
            DBGF("external data: saddr={0:X+8}", saddr);

            const Types& t = _ctx->t;
            c = _ctx->module->getOrInsertGlobal(reloc->symName(), t.i32);
            c = llvm::ConstantExpr::getPointerCast(c, t.i32);

        // handle external function
        } else {
            DBGF("external function: saddr={0:X+8}", saddr);
            c = _ctx->c.i32(saddr);
        }

        if (os)
            *os << xfunc;

    // internal function or label case
    // XXX we rely on symbol information to distinguish
    //     between function or label (see isFunction())
    } else if (isLocalFunc) {
        // get address
        uint64_t saddr;
        if (reloc->hasSym())
            saddr = reloc->symAddr();
        else
            saddr = reloc->addend();

        bool isFunc = Function::isFunction(_ctx, saddr);
        Function* f = _ctx->funcByAddr(saddr, !ASSERT_NOT_NULL);

        if (isFunc) {
            if (!f) {
                // function not found: it should be ahead of current
                // translation address
                xassert(saddr > _ctx->addr);
                f = Function::getByAddr(_ctx, saddr);
            }

            DBGF("internal function: name=\"{0}\", saddr={1:X+8}",
                f->name(), saddr);
            if (os)
                *os << f->name();
        } else {
            DBGF("internal label: saddr={0:X+8}", saddr);
            if (os)
                *os << llvm::formatv("{0:X+8}", saddr);
        }

        // XXX for now, internal functions are always called
        //     indirectly, via icaller, so return just their
        //     original guest address
        c = _ctx->c.i32(saddr);

    // other relocations
    // add the relocation offset to ShadowImage to get the final address
    } else {
        xassert(reloc->hasSec());
        uint64_t saddr;

        if (reloc->hasSym()) {
            DBGF("symbol reloc: symbol=\"{0}\", addend={1:X+8}, section=\"{2}\"",
                reloc->symName(), reloc->addend(), reloc->secName());

            saddr = reloc->symAddr() + reloc->addend();

            if (os)
                *os << reloc->symName();

        } else {
            DBGF("section reloc: section=\"{0}\", addend={1:X+8}",
                reloc->secName(), reloc->addend());

            saddr = reloc->addend();

            if (os)
                *os << llvm::formatv("{0}+{1:X+8}",
                    reloc->secName(), reloc->addend());
        }

        // TODO speed up section lookup for relocations
        c = llvm::ConstantExpr::getAdd(
            _ctx->shadowImage->getSection(reloc->secName()),
            _ctx->c.i32(saddr));
    }

    _lastSymVal = c;
    c = relfn(c);
    DBG(c->dump());
    _last = reloc;
    return c;
}

bool SBTRelocation::isCall(uint64_t addr) const
{
    return _last && _last->offset() == addr &&
        _last->type() == Relocation::PROXY_CALL_LO;
}

llvm::Constant* SBTRelocation::lastSymVal() const
{
    xassert(_lastSymVal);
    return _lastSymVal;
}

llvm::GlobalVariable* SBTRelocation::relocateSection(
    const std::vector<uint8_t>& bytes,
    const ShadowImage* shadowImage)
{
    xassert(_section);
    DBGF("relocating section {0}", _section->name());
    std::vector<llvm::Constant*> cvec;

    size_t n = bytes.size();
    ConstRelocIter rit = _ri;

    for (size_t addr = 0; addr < n; addr+=4) {
        // reloc
        if (rit != _re && addr == (*rit)->offset()) {
            ConstRelocationPtr reloc = *rit;
            switch (reloc->type()) {
                case llvm::ELF::R_RISCV_32: {
                    uint64_t addr = reloc->addend();
                    xassert(reloc->hasSec());
                    if (reloc->hasSym()) {
                        addr += reloc->symAddr();
                        DBGF(
                            "relocating {0:X-8}: "
                            "symbol=\"{1}\", symaddr={2:X+8}, "
                            "section=\"{3}\", addend={4:X+8}, "
                            "addr={5:X-8}",
                            reloc->offset(),
                            reloc->symName(), reloc->symAddr(),
                            reloc->secName(), reloc->addend(),
                            addr);
                    } else {
                        DBGF(
                            "relocating {0:X-8}: "
                            "section=\"{1}\", addend={2:X+8}",
                            reloc->offset(),
                            reloc->secName(), reloc->addend());
                    }

                    llvm::Constant* cexpr =
                        llvm::ConstantExpr::getAdd(
                            shadowImage->getSection(reloc->secName()),
                            _ctx->c.u32(addr));
                    cvec.push_back(cexpr);
                    break;
                }

                default:
                    DBGF("unknown relocation type: {0}", reloc->type());
                    xunreachable("Unsupported relocation type");
            }
            ++rit;
        // or just copy the raw bytes
        } else {
            uint32_t val = *(uint32_t*)&bytes[addr];
            DBGF("copying raw bytes @{0:X-8}: {1:X-8}", addr, val);
            cvec.push_back(_ctx->c.u32(val));
        }
    }

    llvm::ArrayType* aty = llvm::ArrayType::get(_ctx->t.i32, cvec.size());
    llvm::Constant* ca = llvm::ConstantArray::get(aty, cvec);
    return new llvm::GlobalVariable(*_ctx->module, ca->getType(),
        !CONSTANT, llvm::GlobalValue::ExternalLinkage, ca);
}

}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0.
// Author: Jin Qing (http://blog.csdn.net/jq0123)

#include "client_async_reader_writer_impl2.h"

#include <grpc_cb/channel.h>                           // for MakeSharedCall()
#include <grpc_cb/impl/client/client_recv_init_md_cqtag.h>  // for ClientRecvInitMdCqTag
#include <grpc_cb/impl/client/client_send_close_cqtag.h>    // for ClientSendCloseCqTag
#include <grpc_cb/impl/client/client_send_init_md_cqtag.h>  // ClientSendInitMdCqTag

#include "client_async_reader_helper.h"  // for ClientAsyncReaderHelper
#include "client_async_writer_helper.h"  // for ClientAsyncWriterHelper

namespace grpc_cb {

using Sptr = std::shared_ptr<ClientAsyncReaderWriterImpl2>;

// Todo: BlockingGetInitMd();

ClientAsyncReaderWriterImpl2::ClientAsyncReaderWriterImpl2(
    const ChannelSptr& channel, const std::string& method,
    const CompletionQueueSptr& cq_sptr, const StatusCallback& on_status)
    : call_sptr_(channel->MakeSharedCall(method, *cq_sptr)),
      on_status_(on_status) {
  assert(cq_sptr);
  assert(call_sptr_);

  ClientSendInitMdCqTag* send_tag = new ClientSendInitMdCqTag(call_sptr_);
  if (!send_tag->Start()) {
    delete send_tag;
    SetInternalError("Failed to send init metadata to init stream.");
    return;
  }

  ClientRecvInitMdCqTag* recv_tag = new ClientRecvInitMdCqTag(call_sptr_);
  if (!recv_tag->Start()) {
    delete recv_tag;
    SetInternalError("Failed to receive init metadata to init stream.");
    return;
  }
}

ClientAsyncReaderWriterImpl2::~ClientAsyncReaderWriterImpl2() {
  // Reader and Writer helpers share this.
  assert(!reader_sptr_);
  assert(!writer_sptr_);
  SendCloseIfNot();
}

bool ClientAsyncReaderWriterImpl2::Write(const MessageSptr& msg_sptr) {
  Guard g(mtx_);

  if (!status_.ok()) {
    assert(!reader_sptr_ && !writer_sptr_);
    return false;
  }

  if (writer_sptr_)
    return writer_sptr_->Queue(msg_sptr);
  if (writing_started_)  // but writer_sptr_ is reset
    return false;

  // new writer only once
  writing_started_ = true;
  // Impl2 and WriterHelper share each other untill OnEndOfWriting().
  auto sptr = shared_from_this();  // can not in ctr().
  writer_sptr_.reset(new ClientAsyncWriterHelper(call_sptr_,
      [sptr]() { sptr->OnEndOfWriting(); }));
  return writer_sptr_->Queue(msg_sptr);
}

void ClientAsyncReaderWriterImpl2::CloseWriting() {
  Guard g(mtx_);
  writing_started_ = true;  // Maybe without any Write().

  // End when all messages are written.
  if (writer_sptr_)
      writer_sptr_->QueueEnd();
}

// Called in dtr().
// Send close only if reading and writing are both ended.
void ClientAsyncReaderWriterImpl2::SendCloseIfNot() {
  assert(!reader_sptr_);  // Must be ended.
  assert(!writer_sptr_);  // Must be ended.
  if (!status_.ok()) return;
  if (has_sent_close_) return;
  has_sent_close_ = true;

  ClientSendCloseCqTag* tag = new ClientSendCloseCqTag(call_sptr_);
  if (tag->Start()) {
    CallOnStatus();
    return;
  }

  delete tag;
  SetInternalError("Failed to close writing.");  // calls on_status_
}

// Todo: same as ClientReader?

void ClientAsyncReaderWriterImpl2::ReadEach(
    const ReadHandlerSptr& handler_sptr) {
  Guard g(mtx_);

  read_handler_sptr_ = handler_sptr;
  if (reading_started_) return;
  reading_started_ = true;  // new reader_sptr_ once

  assert(!reader_sptr_);
  // Impl2 and ReaderHelper will share each other until OnEndOfReading().
  auto sptr = shared_from_this();
  reader_sptr_.reset(new ClientAsyncReaderHelper(
      call_sptr_, read_handler_sptr_, [sptr]() { sptr->OnEndOfReading(); }));
  reader_sptr_->Start();
}

void ClientAsyncReaderWriterImpl2::OnEndOfReading() {
  Guard g(mtx_);
  if (!reader_sptr_) return;
  Status r_status(reader_sptr_->GetStatus());  // before reset()
  reader_sptr_.reset();  // Stop circular sharing.

  if (!status_.ok()) return;
  status_ = r_status;
  if (!status_.ok()) {
    CallOnStatus();
    return;
  }

  assert(IsReadingEnded());
  if (IsWritingEnded())
    SendCloseIfNot();
}

void ClientAsyncReaderWriterImpl2::OnEndOfWriting() {
  Guard g(mtx_);
  if (!writer_sptr_) return;
  Status w_status(writer_sptr_->GetStatus());  // before reset()
  writer_sptr_.reset();  // Stop circular sharing.

  if (!status_.ok()) return;
  status_ = w_status;
  if (!status_.ok()) {
    CallOnStatus();
    return;
  }

  assert(IsWritingEnded());
  if (IsReadingEnded())
    SendCloseIfNot();
}

// Set status and callback and reset helpers.
void ClientAsyncReaderWriterImpl2::SetInternalError(const std::string& sError) {
  status_.SetInternalError(sError);
  CallOnStatus();

  if (reader_sptr_) {
    reader_sptr_->Abort();
    reader_sptr_.reset();
  }
  if (writer_sptr_) {
    writer_sptr_->Abort();
    writer_sptr_.reset();
  }
}

bool ClientAsyncReaderWriterImpl2::IsReadingEnded() const {
  return reading_started_ && !reader_sptr_;
}

bool ClientAsyncReaderWriterImpl2::IsWritingEnded() const {
  return writing_started_ && !writer_sptr_;
}

void ClientAsyncReaderWriterImpl2::CallOnStatus() {
  if (!on_status_) return;
  on_status_(status_);
  on_status_ = StatusCallback();
}

}  // namespace grpc_cb
<commit_msg>Format.<commit_after>// Licensed under the Apache License, Version 2.0.
// Author: Jin Qing (http://blog.csdn.net/jq0123)

#include "client_async_reader_writer_impl2.h"

#include <grpc_cb/channel.h>  // for MakeSharedCall()
#include <grpc_cb/impl/client/client_recv_init_md_cqtag.h>  // for ClientRecvInitMdCqTag
#include <grpc_cb/impl/client/client_send_close_cqtag.h>    // for ClientSendCloseCqTag
#include <grpc_cb/impl/client/client_send_init_md_cqtag.h>  // ClientSendInitMdCqTag

#include "client_async_reader_helper.h"  // for ClientAsyncReaderHelper
#include "client_async_writer_helper.h"  // for ClientAsyncWriterHelper

namespace grpc_cb {

using Sptr = std::shared_ptr<ClientAsyncReaderWriterImpl2>;

// Todo: BlockingGetInitMd();

ClientAsyncReaderWriterImpl2::ClientAsyncReaderWriterImpl2(
    const ChannelSptr& channel, const std::string& method,
    const CompletionQueueSptr& cq_sptr, const StatusCallback& on_status)
    : call_sptr_(channel->MakeSharedCall(method, *cq_sptr)),
      on_status_(on_status) {
  assert(cq_sptr);
  assert(call_sptr_);

  ClientSendInitMdCqTag* send_tag = new ClientSendInitMdCqTag(call_sptr_);
  if (!send_tag->Start()) {
    delete send_tag;
    SetInternalError("Failed to send init metadata to init stream.");
    return;
  }

  ClientRecvInitMdCqTag* recv_tag = new ClientRecvInitMdCqTag(call_sptr_);
  if (!recv_tag->Start()) {
    delete recv_tag;
    SetInternalError("Failed to receive init metadata to init stream.");
    return;
  }
}

ClientAsyncReaderWriterImpl2::~ClientAsyncReaderWriterImpl2() {
  // Reader and Writer helpers share this.
  assert(!reader_sptr_);
  assert(!writer_sptr_);
  SendCloseIfNot();
}

bool ClientAsyncReaderWriterImpl2::Write(const MessageSptr& msg_sptr) {
  Guard g(mtx_);

  if (!status_.ok()) {
    assert(!reader_sptr_ && !writer_sptr_);
    return false;
  }

  if (writer_sptr_)
    return writer_sptr_->Queue(msg_sptr);
  if (writing_started_)  // but writer_sptr_ is reset
    return false;

  // new writer only once
  writing_started_ = true;
  // Impl2 and WriterHelper share each other untill OnEndOfWriting().
  auto sptr = shared_from_this();  // can not in ctr().
  writer_sptr_.reset(new ClientAsyncWriterHelper(call_sptr_,
      [sptr]() { sptr->OnEndOfWriting(); }));
  return writer_sptr_->Queue(msg_sptr);
}

void ClientAsyncReaderWriterImpl2::CloseWriting() {
  Guard g(mtx_);
  writing_started_ = true;  // Maybe without any Write().

  // End when all messages are written.
  if (writer_sptr_)
      writer_sptr_->QueueEnd();
}

// Called in dtr().
// Send close only if reading and writing are both ended.
void ClientAsyncReaderWriterImpl2::SendCloseIfNot() {
  assert(!reader_sptr_);  // Must be ended.
  assert(!writer_sptr_);  // Must be ended.
  if (!status_.ok()) return;
  if (has_sent_close_) return;
  has_sent_close_ = true;

  ClientSendCloseCqTag* tag = new ClientSendCloseCqTag(call_sptr_);
  if (tag->Start()) {
    CallOnStatus();
    return;
  }

  delete tag;
  SetInternalError("Failed to close writing.");  // calls on_status_
}

// Todo: same as ClientReader?

void ClientAsyncReaderWriterImpl2::ReadEach(
    const ReadHandlerSptr& handler_sptr) {
  Guard g(mtx_);

  read_handler_sptr_ = handler_sptr;
  if (reading_started_) return;
  reading_started_ = true;  // new reader_sptr_ once

  assert(!reader_sptr_);
  // Impl2 and ReaderHelper will share each other until OnEndOfReading().
  auto sptr = shared_from_this();
  reader_sptr_.reset(new ClientAsyncReaderHelper(
      call_sptr_, read_handler_sptr_, [sptr]() { sptr->OnEndOfReading(); }));
  reader_sptr_->Start();
}

void ClientAsyncReaderWriterImpl2::OnEndOfReading() {
  Guard g(mtx_);
  if (!reader_sptr_) return;
  Status r_status(reader_sptr_->GetStatus());  // before reset()
  reader_sptr_.reset();  // Stop circular sharing.

  if (!status_.ok()) return;
  status_ = r_status;
  if (!status_.ok()) {
    CallOnStatus();
    return;
  }

  assert(IsReadingEnded());
  if (IsWritingEnded())
    SendCloseIfNot();
}

void ClientAsyncReaderWriterImpl2::OnEndOfWriting() {
  Guard g(mtx_);
  if (!writer_sptr_) return;
  Status w_status(writer_sptr_->GetStatus());  // before reset()
  writer_sptr_.reset();  // Stop circular sharing.

  if (!status_.ok()) return;
  status_ = w_status;
  if (!status_.ok()) {
    CallOnStatus();
    return;
  }

  assert(IsWritingEnded());
  if (IsReadingEnded())
    SendCloseIfNot();
}

// Set status and callback and reset helpers.
void ClientAsyncReaderWriterImpl2::SetInternalError(const std::string& sError) {
  status_.SetInternalError(sError);
  CallOnStatus();

  if (reader_sptr_) {
    reader_sptr_->Abort();
    reader_sptr_.reset();
  }
  if (writer_sptr_) {
    writer_sptr_->Abort();
    writer_sptr_.reset();
  }
}

bool ClientAsyncReaderWriterImpl2::IsReadingEnded() const {
  return reading_started_ && !reader_sptr_;
}

bool ClientAsyncReaderWriterImpl2::IsWritingEnded() const {
  return writing_started_ && !writer_sptr_;
}

void ClientAsyncReaderWriterImpl2::CallOnStatus() {
  if (!on_status_) return;
  on_status_(status_);
  on_status_ = StatusCallback();
}

}  // namespace grpc_cb
<|endoftext|>


<commit_before>/*
 * Copyright 2012 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "include/core/SkCanvas.h"
#include "include/core/SkColorFilter.h"
#include "include/effects/SkImageFilters.h"
#include "src/core/SkColorFilterBase.h"
#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
#include "src/core/SkSpecialSurface.h"
#include "src/core/SkWriteBuffer.h"

namespace {

class SkColorFilterImageFilter final : public SkImageFilter_Base {
public:
    SkColorFilterImageFilter(sk_sp<SkColorFilter> cf, sk_sp<SkImageFilter> input,
                             const SkRect* cropRect)
            : INHERITED(&input, 1, cropRect)
            , fColorFilter(std::move(cf)) {}

protected:
    void flatten(SkWriteBuffer&) const override;
    sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override;
    bool onIsColorFilterNode(SkColorFilter**) const override;
    MatrixCapability onGetCTMCapability() const override { return MatrixCapability::kComplex; }
    bool onAffectsTransparentBlack() const override;

private:
    friend void ::SkRegisterColorFilterImageFilterFlattenable();
    SK_FLATTENABLE_HOOKS(SkColorFilterImageFilter)

    sk_sp<SkColorFilter> fColorFilter;

    using INHERITED = SkImageFilter_Base;
};

} // end namespace

sk_sp<SkImageFilter> SkImageFilters::ColorFilter(
        sk_sp<SkColorFilter> cf, sk_sp<SkImageFilter> input, const CropRect& cropRect) {
    if (!cf) {
        return nullptr;
    }

    SkColorFilter* inputCF;
    if (input && input->isColorFilterNode(&inputCF)) {
        // This is an optimization, as it collapses the hierarchy by just combining the two
        // colorfilters into a single one, which the new imagefilter will wrap.
        sk_sp<SkColorFilter> newCF = cf->makeComposed(sk_sp<SkColorFilter>(inputCF));
        if (newCF) {
            return sk_sp<SkImageFilter>(new SkColorFilterImageFilter(
                    std::move(newCF), sk_ref_sp(input->getInput(0)), cropRect));
        }
    }

    return sk_sp<SkImageFilter>(new SkColorFilterImageFilter(
            std::move(cf), std::move(input), cropRect));
}

void SkRegisterColorFilterImageFilterFlattenable() {
    SK_REGISTER_FLATTENABLE(SkColorFilterImageFilter);
    // TODO (michaelludwig) - Remove after grace period for SKPs to stop using old name
    SkFlattenable::Register("SkColorFilterImageFilterImpl", SkColorFilterImageFilter::CreateProc);
}

sk_sp<SkFlattenable> SkColorFilterImageFilter::CreateProc(SkReadBuffer& buffer) {
    SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
    sk_sp<SkColorFilter> cf(buffer.readColorFilter());
    return SkImageFilters::ColorFilter(std::move(cf), common.getInput(0), common.cropRect());
}

void SkColorFilterImageFilter::flatten(SkWriteBuffer& buffer) const {
    this->INHERITED::flatten(buffer);
    buffer.writeFlattenable(fColorFilter.get());
}

///////////////////////////////////////////////////////////////////////////////////////////////////

sk_sp<SkSpecialImage> SkColorFilterImageFilter::onFilterImage(const Context& ctx,
                                                              SkIPoint* offset) const {
    SkIPoint inputOffset = SkIPoint::Make(0, 0);
    sk_sp<SkSpecialImage> input(this->filterInput(0, ctx, &inputOffset));

    SkIRect inputBounds;
    if (as_CFB(fColorFilter)->affectsTransparentBlack()) {
        // If the color filter affects transparent black, the bounds are the entire clip.
        inputBounds = ctx.clipBounds();
    } else if (!input) {
        return nullptr;
    } else {
        inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
                                        input->width(), input->height());
    }

    SkIRect bounds;
    if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
        return nullptr;
    }

    sk_sp<SkSpecialSurface> surf(ctx.makeSurface(bounds.size()));
    if (!surf) {
        return nullptr;
    }

    SkCanvas* canvas = surf->getCanvas();
    SkASSERT(canvas);

    SkPaint paint;

    paint.setBlendMode(SkBlendMode::kSrc);
    paint.setColorFilter(fColorFilter);

    // TODO: it may not be necessary to clear or drawPaint inside the input bounds
    // (see skbug.com/5075)
    if (as_CFB(fColorFilter)->affectsTransparentBlack()) {
        // The subsequent input->draw() call may not fill the entire canvas. For filters which
        // affect transparent black, ensure that the filter is applied everywhere.
        paint.setColor(SK_ColorTRANSPARENT);
        canvas->drawPaint(paint);
        paint.setColor(SK_ColorBLACK);
    } else {
        canvas->clear(0x0);
    }

    if (input) {
        input->draw(canvas,
                    SkIntToScalar(inputOffset.fX - bounds.fLeft),
                    SkIntToScalar(inputOffset.fY - bounds.fTop),
                    SkSamplingOptions(), &paint);
    }

    offset->fX = bounds.fLeft;
    offset->fY = bounds.fTop;
    return surf->makeImageSnapshot();
}

bool SkColorFilterImageFilter::onIsColorFilterNode(SkColorFilter** filter) const {
    SkASSERT(1 == this->countInputs());
    if (!this->cropRectIsSet()) {
        if (filter) {
            *filter = SkRef(fColorFilter.get());
        }
        return true;
    }
    return false;
}

bool SkColorFilterImageFilter::onAffectsTransparentBlack() const {
    return as_CFB(fColorFilter)->affectsTransparentBlack();
}
<commit_msg>Fix SkImageFilters::ColorFilter when color filter is null<commit_after>/*
 * Copyright 2012 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "include/core/SkCanvas.h"
#include "include/core/SkColorFilter.h"
#include "include/effects/SkImageFilters.h"
#include "src/core/SkColorFilterBase.h"
#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
#include "src/core/SkSpecialSurface.h"
#include "src/core/SkWriteBuffer.h"

namespace {

class SkColorFilterImageFilter final : public SkImageFilter_Base {
public:
    SkColorFilterImageFilter(sk_sp<SkColorFilter> cf, sk_sp<SkImageFilter> input,
                             const SkRect* cropRect)
            : INHERITED(&input, 1, cropRect)
            , fColorFilter(std::move(cf)) {}

protected:
    void flatten(SkWriteBuffer&) const override;
    sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override;
    bool onIsColorFilterNode(SkColorFilter**) const override;
    MatrixCapability onGetCTMCapability() const override { return MatrixCapability::kComplex; }
    bool onAffectsTransparentBlack() const override;

private:
    friend void ::SkRegisterColorFilterImageFilterFlattenable();
    SK_FLATTENABLE_HOOKS(SkColorFilterImageFilter)

    sk_sp<SkColorFilter> fColorFilter;

    using INHERITED = SkImageFilter_Base;
};

} // end namespace

sk_sp<SkImageFilter> SkImageFilters::ColorFilter(
        sk_sp<SkColorFilter> cf, sk_sp<SkImageFilter> input, const CropRect& cropRect) {
    if (!cf) {
        // The color filter is the identity, but 'cropRect' and 'input' may perform actions in the
        // image filter graph.
        const SkRect* crop = cropRect;
        if (crop) {
            // Wrap 'input' in an offset filter with (0,0) and the crop rect.
            // TODO(michaelludwig): Replace this with SkCropImageFilter when that's ready for use.
            return SkImageFilters::Offset(0.f, 0.f, std::move(input), cropRect);
        } else {
            // Just forward 'input' on
            return input;
        }
    }

    SkColorFilter* inputCF;
    if (input && input->isColorFilterNode(&inputCF)) {
        // This is an optimization, as it collapses the hierarchy by just combining the two
        // colorfilters into a single one, which the new imagefilter will wrap.
        sk_sp<SkColorFilter> newCF = cf->makeComposed(sk_sp<SkColorFilter>(inputCF));
        if (newCF) {
            return sk_sp<SkImageFilter>(new SkColorFilterImageFilter(
                    std::move(newCF), sk_ref_sp(input->getInput(0)), cropRect));
        }
    }

    return sk_sp<SkImageFilter>(new SkColorFilterImageFilter(
            std::move(cf), std::move(input), cropRect));
}

void SkRegisterColorFilterImageFilterFlattenable() {
    SK_REGISTER_FLATTENABLE(SkColorFilterImageFilter);
    // TODO (michaelludwig) - Remove after grace period for SKPs to stop using old name
    SkFlattenable::Register("SkColorFilterImageFilterImpl", SkColorFilterImageFilter::CreateProc);
}

sk_sp<SkFlattenable> SkColorFilterImageFilter::CreateProc(SkReadBuffer& buffer) {
    SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
    sk_sp<SkColorFilter> cf(buffer.readColorFilter());
    return SkImageFilters::ColorFilter(std::move(cf), common.getInput(0), common.cropRect());
}

void SkColorFilterImageFilter::flatten(SkWriteBuffer& buffer) const {
    this->INHERITED::flatten(buffer);
    buffer.writeFlattenable(fColorFilter.get());
}

///////////////////////////////////////////////////////////////////////////////////////////////////

sk_sp<SkSpecialImage> SkColorFilterImageFilter::onFilterImage(const Context& ctx,
                                                              SkIPoint* offset) const {
    SkIPoint inputOffset = SkIPoint::Make(0, 0);
    sk_sp<SkSpecialImage> input(this->filterInput(0, ctx, &inputOffset));

    SkIRect inputBounds;
    if (as_CFB(fColorFilter)->affectsTransparentBlack()) {
        // If the color filter affects transparent black, the bounds are the entire clip.
        inputBounds = ctx.clipBounds();
    } else if (!input) {
        return nullptr;
    } else {
        inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
                                        input->width(), input->height());
    }

    SkIRect bounds;
    if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
        return nullptr;
    }

    sk_sp<SkSpecialSurface> surf(ctx.makeSurface(bounds.size()));
    if (!surf) {
        return nullptr;
    }

    SkCanvas* canvas = surf->getCanvas();
    SkASSERT(canvas);

    SkPaint paint;

    paint.setBlendMode(SkBlendMode::kSrc);
    paint.setColorFilter(fColorFilter);

    // TODO: it may not be necessary to clear or drawPaint inside the input bounds
    // (see skbug.com/5075)
    if (as_CFB(fColorFilter)->affectsTransparentBlack()) {
        // The subsequent input->draw() call may not fill the entire canvas. For filters which
        // affect transparent black, ensure that the filter is applied everywhere.
        paint.setColor(SK_ColorTRANSPARENT);
        canvas->drawPaint(paint);
        paint.setColor(SK_ColorBLACK);
    } else {
        canvas->clear(0x0);
    }

    if (input) {
        input->draw(canvas,
                    SkIntToScalar(inputOffset.fX - bounds.fLeft),
                    SkIntToScalar(inputOffset.fY - bounds.fTop),
                    SkSamplingOptions(), &paint);
    }

    offset->fX = bounds.fLeft;
    offset->fY = bounds.fTop;
    return surf->makeImageSnapshot();
}

bool SkColorFilterImageFilter::onIsColorFilterNode(SkColorFilter** filter) const {
    SkASSERT(1 == this->countInputs());
    if (!this->cropRectIsSet()) {
        if (filter) {
            *filter = SkRef(fColorFilter.get());
        }
        return true;
    }
    return false;
}

bool SkColorFilterImageFilter::onAffectsTransparentBlack() const {
    return as_CFB(fColorFilter)->affectsTransparentBlack();
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <fstream>
#include <iostream>

#include "rlcsa.h"
#include "misc/utils.h"

using namespace CSA;

int main(int argc, char** argv)
{
  std::cout << "RLCSA locate test" << std::endl;
  if(argc < 3)
  {
    std::cout << "Usage: locate_test basename [begin end] output [d|s]" << std::endl;
    std::cout << "  d  Use direct locate." << std::endl;
    std::cout << "  s  Output a 32-bit suffix array." << std::endl;
    return 1;
  }

  usint begin = 0, end = 0;
  int output_arg = 2;
  std::cout << "Base name: " << argv[1] << std::endl;
  if(argc >= 5)
  {
    output_arg = 4;
    begin = atoi(argv[2]), end = atoi(argv[3]);
    std::cout << "Begin: " << begin << std::endl;
    std::cout << "End: " << end << std::endl;
    if(begin > end)
    {
      std::cerr << "Error: Empty range!" << std::endl;
      return 2;
    }
  }

  bool direct = false, do_output = false;
  for(int i = output_arg + 1; i < argc; i++)
  {
    switch(argv[i][0])
    {
      case 'd':
        direct = true; break;
      case 's':
        do_output = true; break;
    }
  }
  if(!direct)
  {
    std::cout << "Using run-based optimizations." << std::endl;
  }
  else
  {
    std::cout << "Using direct locate." << std::endl;
  }
  if(do_output)
  {
    std::cout << "Writing plain SA to output file, ignoring begin and end." << std::endl;
  }
  std::cout << std::endl;

  RLCSA rlcsa(argv[1]);
  if(!rlcsa.supportsLocate())
  {
    std::cerr << "Error: Locate is not supported!" << std::endl;
    return 3;
  }

  if(output_arg == 4 && !do_output)
  {
    if(end >= rlcsa.getSize())
    {
      std::cerr << "Error: Invalid range!" << std::endl;
      return 4;
    }
  }
  else
  {
    begin = 0; end = rlcsa.getSize() - 1;
  }

  std::ofstream output(argv[output_arg], std::ios_base::binary);
  if(!output)
  {
    std::cerr << "Error: Cannot open output file!" << std::endl;
    return 5;
  }

  usint* buffer = new usint[MILLION]; CSA::uint temp;
  std::clock_t start = std::clock();
  if(do_output) { temp = rlcsa.getSize(); output.write((char*)&temp, sizeof(temp)); }
  for(usint curr = begin; curr <= end; curr += MILLION)
  {
    pair_type range(curr, std::min(end, curr + MILLION - 1));
    if(direct)
    {
      for(usint i = 0; i < range.second + 1 - range.first; i++)
      {
        buffer[i] = rlcsa.locate(curr + i, false);
      }
    }
    else { rlcsa.locate(range, buffer); }
    for(usint i = 0; i < range.second + 1 - range.first; i++)
    {
      if(do_output) { temp = buffer[i]; output.write((char*)&temp, sizeof(temp)); }
      else          { output.write((char*)&(buffer[i]), sizeof(usint)); }
    }
  }
  std::clock_t stop = std::clock();
  delete[] buffer;

  double size = (end + 1 - begin);
  double time = (stop - start) / (double)CLOCKS_PER_SEC;
  std::cout << size << " locates in " << time << " seconds (" << (size / time) << " locates/s)" << std::endl;
  output.close();

  return 0;
}
<commit_msg>Fixing a typo in locate_test.cpp.<commit_after>#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <fstream>
#include <iostream>

#include "rlcsa.h"
#include "misc/utils.h"

using namespace CSA;

int main(int argc, char** argv)
{
  std::cout << "RLCSA locate test" << std::endl;
  if(argc < 3)
  {
    std::cout << "Usage: locate_test basename [begin end] output [d|s]" << std::endl;
    std::cout << "  d  Use direct locate." << std::endl;
    std::cout << "  s  Output a 32-bit suffix array." << std::endl;
    return 1;
  }

  usint begin = 0, end = 0;
  int output_arg = 2;
  std::cout << "Base name: " << argv[1] << std::endl;
  if(argc >= 5)
  {
    output_arg = 4;
    begin = atoi(argv[2]), end = atoi(argv[3]);
    std::cout << "Begin: " << begin << std::endl;
    std::cout << "End: " << end << std::endl;
    if(begin > end)
    {
      std::cerr << "Error: Empty range!" << std::endl;
      return 2;
    }
  }

  bool direct = false, do_output = false;
  for(int i = output_arg + 1; i < argc; i++)
  {
    switch(argv[i][0])
    {
      case 'd':
        direct = true; break;
      case 's':
        do_output = true; break;
    }
  }
  if(!direct)
  {
    std::cout << "Using run-based optimizations." << std::endl;
  }
  else
  {
    std::cout << "Using direct locate." << std::endl;
  }
  if(do_output)
  {
    std::cout << "Writing plain SA to output file, ignoring begin and end." << std::endl;
  }
  std::cout << std::endl;

  RLCSA rlcsa(argv[1]);
  if(!rlcsa.supportsLocate())
  {
    std::cerr << "Error: Locate is not supported!" << std::endl;
    return 3;
  }

  if(output_arg == 4 && !do_output)
  {
    if(end >= rlcsa.getSize())
    {
      std::cerr << "Error: Invalid range!" << std::endl;
      return 4;
    }
  }
  else
  {
    begin = 0; end = rlcsa.getSize() - 1;
  }

  std::ofstream output(argv[output_arg], std::ios_base::binary);
  if(!output)
  {
    std::cerr << "Error: Cannot open output file!" << std::endl;
    return 5;
  }

  usint* buffer = new usint[MILLION]; CSA::usint temp;
  std::clock_t start = std::clock();
  if(do_output) { temp = rlcsa.getSize(); output.write((char*)&temp, sizeof(temp)); }
  for(usint curr = begin; curr <= end; curr += MILLION)
  {
    pair_type range(curr, std::min(end, curr + MILLION - 1));
    if(direct)
    {
      for(usint i = 0; i < range.second + 1 - range.first; i++)
      {
        buffer[i] = rlcsa.locate(curr + i, false);
      }
    }
    else { rlcsa.locate(range, buffer); }
    for(usint i = 0; i < range.second + 1 - range.first; i++)
    {
      if(do_output) { temp = buffer[i]; output.write((char*)&temp, sizeof(temp)); }
      else          { output.write((char*)&(buffer[i]), sizeof(usint)); }
    }
  }
  std::clock_t stop = std::clock();
  delete[] buffer;

  double size = (end + 1 - begin);
  double time = (stop - start) / (double)CLOCKS_PER_SEC;
  std::cout << size << " locates in " << time << " seconds (" << (size / time) << " locates/s)" << std::endl;
  output.close();

  return 0;
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2015, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */
#include <folly/Memory.h>

#include "mcrouter/config.h"
#include "mcrouter/flavor.h"
#include "mcrouter/McrouterInstance.h"
#include "mcrouter/McrouterLogger.h"
#include "mcrouter/options.h"
#include "mcrouter/proxy.h"
#include "mcrouter/routes/McExtraRouteHandleProvider.h"

namespace facebook { namespace memcache { namespace mcrouter {

int router_configure_from_string(McrouterInstance* router,
                                 folly::StringPiece input) {
  return router->configure(input);
}

bool read_standalone_flavor(
    const std::string& flavor,
    std::unordered_map<std::string, std::string>& option_dict,
    std::unordered_map<std::string, std::string>& st_option_dict) {

  if (!readFlavor(flavor, st_option_dict, option_dict)) {
    LOG(ERROR) << "CRITICAL: Couldn't initialize from standalone flavor file "
               << flavor;
    return false;
  }
  return true;
}

std::unique_ptr<ConfigApi> createConfigApi(const McrouterOptions& opts) {
  return folly::make_unique<ConfigApi>(opts);
}

std::string performOptionSubstitution(std::string str) {
  return str;
}

bool standaloneInit(const McrouterOptions& opts) {
  int numSources = (opts.config_file.empty() ? 0 : 1) +
    (opts.config_str.empty() ? 0 : 1);
  if (numSources == 0) {
    LOG(ERROR) << "no configuration source";
    return false;
  } else if (numSources > 1) {
    LOG(ERROR) << "ambiguous configuration options";
    return false;
  }
  return true;
}

std::unique_ptr<ExtraRouteHandleProviderIf> createExtraRouteHandleProvider() {
  return folly::make_unique<McExtraRouteHandleProvider>();
}

std::unique_ptr<McrouterLogger> createMcrouterLogger(McrouterInstance* router) {
  return folly::make_unique<McrouterLogger>(router);
}

void applyTestMode(McrouterOptions& opts) {
  opts.enable_failure_logging = false;
  opts.stats_logging_interval = 0;
}

McrouterOptions defaultTestOptions() {
  auto opts = McrouterOptions();
  applyTestMode(opts);
  return opts;
}

std::vector<std::string> defaultTestCommandLineArgs() {
  return { "--disable-failure-logging", "--stats-logging-interval=0" };
}

void logTkoEvent(proxy_t* proxy, const TkoLog& tkoLog) { }

void initFailureLogger() { }

void scheduleSingletonCleanup() { }

std::unordered_map<std::string, folly::dynamic> additionalConfigParams() {
  return {};
}

}}}  // facebook::memcache::mcrouter
<commit_msg>Fix OSS build with gcc 4.9<commit_after>/*
 *  Copyright (c) 2015, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */
#include <folly/Memory.h>

#include "mcrouter/config.h"
#include "mcrouter/flavor.h"
#include "mcrouter/McrouterInstance.h"
#include "mcrouter/McrouterLogger.h"
#include "mcrouter/options.h"
#include "mcrouter/proxy.h"
#include "mcrouter/routes/McExtraRouteHandleProvider.h"

namespace facebook { namespace memcache { namespace mcrouter {

int router_configure_from_string(McrouterInstance* router,
                                 folly::StringPiece input) {
  return router->configure(input);
}

bool read_standalone_flavor(
    const std::string& flavor,
    std::unordered_map<std::string, std::string>& option_dict,
    std::unordered_map<std::string, std::string>& st_option_dict) {

  if (!readFlavor(flavor, st_option_dict, option_dict)) {
    LOG(ERROR) << "CRITICAL: Couldn't initialize from standalone flavor file "
               << flavor;
    return false;
  }
  return true;
}

std::unique_ptr<ConfigApi> createConfigApi(const McrouterOptions& opts) {
  return folly::make_unique<ConfigApi>(opts);
}

std::string performOptionSubstitution(std::string str) {
  return str;
}

bool standaloneInit(const McrouterOptions& opts) {
  int numSources = (opts.config_file.empty() ? 0 : 1) +
    (opts.config_str.empty() ? 0 : 1);
  if (numSources == 0) {
    LOG(ERROR) << "no configuration source";
    return false;
  } else if (numSources > 1) {
    LOG(ERROR) << "ambiguous configuration options";
    return false;
  }
  return true;
}

std::unique_ptr<ExtraRouteHandleProviderIf> createExtraRouteHandleProvider() {
  return folly::make_unique<McExtraRouteHandleProvider>();
}

std::unique_ptr<McrouterLogger> createMcrouterLogger(McrouterInstance* router) {
  return folly::make_unique<McrouterLogger>(router);
}

void applyTestMode(McrouterOptions& opts) {
  opts.enable_failure_logging = false;
  opts.stats_logging_interval = 0;
}

McrouterOptions defaultTestOptions() {
  auto opts = McrouterOptions();
  applyTestMode(opts);
  return opts;
}

std::vector<std::string> defaultTestCommandLineArgs() {
  return { "--disable-failure-logging", "--stats-logging-interval=0" };
}

void logTkoEvent(proxy_t* proxy, const TkoLog& tkoLog) { }

void initFailureLogger() { }

void scheduleSingletonCleanup() { }

std::unordered_map<std::string, folly::dynamic> additionalConfigParams() {
  return std::unordered_map<std::string, folly::dynamic>();
}

}}}  // facebook::memcache::mcrouter
<|endoftext|>