<commit_before>// Copyright (c) 2013 The libmumble Developers
// The use of this source code is goverened by a BSD-style
// license that can be found in the LICENSE-file.

#include <mumble/X509Verifier.h>
#include "X509Verifier_win.h"
#include "X509HostnameVerifier.h"
#include <mumble/X509Certificate.h>
#include "X509Certificate_p.h"
#include "OpenSSLUtils.h"

#include <vector>
#include <string>

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <wincrypt.h>

#include "uv.h"

namespace mumble {

static uv_once_t    system_verifier_once_ = UV_ONCE_INIT;
static X509Verifier *system_verifier_ptr_;

void X509VerifierPrivate::InitializeSystemVerifier() {
	OpenSSLUtils::EnsureInitialized();
	system_verifier_ptr_ = new X509Verifier;
}

X509Verifier &X509Verifier::SystemVerifier() {
	uv_once(&system_verifier_once_, X509VerifierPrivate::InitializeSystemVerifier);
	return *system_verifier_ptr_;
}

X509Verifier::X509Verifier() : dptr_(new X509VerifierPrivate) {
}

X509Verifier::~X509Verifier() {
}

bool X509Verifier::VerifyChain(std::vector<X509Certificate> chain, const mumble::X509VerifierOptions &opts) {
	return dptr_->VerifyChain(chain, opts);
}

X509VerifierPrivate::X509VerifierPrivate() {
}

// AddCertToStore creates a CERT_CONTEXT of the certificate passed in as cert and adds it to the certificate store represented
// by store. If ctx_out points to a non-nullptr CERT_CONTEXT, ctx_out will be updated to point to a copy of the CERT_CONTEXT that
// is added to store.
bool X509VerifierPrivate::AddCertToStore(HCERTSTORE store, const X509Certificate &cert, const CERT_CONTEXT **ctx_out) const {
	const ByteArray &buf = cert.dptr_->cert_der_;
	const CERT_CONTEXT *ctx = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, reinterpret_cast<const BYTE*>(buf.ConstData()), buf.Length());
	if (ctx == nullptr) {
		return false;
	}

	bool ok = CertAddCertificateContextToStore(store, ctx, CERT_STORE_ADD_ALWAYS, ctx_out);
	if (!ok) {
		CertFreeCertificateContext(ctx);
		return false;
	}

	CertFreeCertificateContext(ctx);
	return true;
}

// CreateCertContextFromChain creates a CERT_CONTEXT representing the leaf certificate (index 0 of the chain)
// in an in-memory certificate store which will also contains any intermediate certificates found in the chain.
//
// While the method returns a CERT_CONTEXT that represents the leaf certificate, this CERT_CONTEXT contains a pointer
// to the in-memory store that holds the whole certificate chain. This store can be accessed via the hCertStore field
// of the returned CERT_CONTEXT. The store is automatically closed when the CERT_CONTEXT that this function returns
// is freed using CertFreeCertificateContext (it holds the only reference to the store).
const CERT_CONTEXT *X509VerifierPrivate::CreateCertContextFromChain(const std::vector<X509Certificate> &chain) const {
	const CERT_CONTEXT *store_ctx = nullptr;

	HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, nullptr);
	if (store == nullptr) {
		goto err;
	}

	if (!this->AddCertToStore(store, chain.at(0), &store_ctx)) {
		goto err;
	}

	for (int i = 1; i < chain.size(); i++) {
		if (!this->AddCertToStore(store, chain.at(i))) {
			goto err;
		}
	}

	return store_ctx;

err:
	if (store != nullptr) {
		CertCloseStore(store, 0);
	}
	if (store_ctx != nullptr) {
		CertFreeCertificateContext(store_ctx);
	}
	return nullptr;
}

// FileTimeForStdTimeT converts a std::time_t to a FILETIME.
FILETIME X509VerifierPrivate::FileTimeFromStdTimeT(std::time_t time) const {
	FILETIME ft;
	ULARGE_INTEGER lint;

	// 1 Jan 1601 00:00:00 UTC is -11644473600 in Unix epoch representation.
	const ULONGLONG epoch_1601 = 11644473600ULL;
	// Factor that converts from 1 sec (Unix epoch) increments to 100 nsec (FILETIME) increments.
	const ULONGLONG secs_to_100ns =  10000000ULL;

	lint.QuadPart = (epoch_1601 + time) * secs_to_100ns;
	ft.dwLowDateTime = lint.LowPart;
	ft.dwHighDateTime = lint.HighPart;

	return ft;
}

// UTF16StringFromStdString converts a UTF-8 encoded std::string to a UTF-16 WCHAR *.
// The returned pointer must be freed with free().
WCHAR *X509VerifierPrivate::UTF16StringFromStdString(const std::string &str) const {
	WCHAR *buf;
	int sz = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.c_str(), -1, nullptr, 0);
	if (sz == 0) {
		return nullptr;
	}

	buf = reinterpret_cast<WCHAR *>(malloc(sz*sizeof(WCHAR)));
	sz = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.c_str(), -1, buf, sz);
	if (sz == 0) {
		return nullptr;
	}

	return buf;
}

// VerifyChain verifies the certificate chain in chain
// according to the verification options given as opts.
bool X509VerifierPrivate::VerifyChain(std::vector<X509Certificate> chain, const X509VerifierOptions &opts) {
	bool status = false;
	FILETIME verify_time;
	WCHAR *wide_dns_name = nullptr;

	if (chain.empty()) {
		goto out;
	}

	const CERT_CONTEXT *store_ctx = this->CreateCertContextFromChain(chain);
	if (store_ctx == nullptr) {
		goto out;
	}

	CERT_CHAIN_PARA para;
	memset(&para, 0, sizeof(para));
	para.cbSize = sizeof(CERT_CHAIN_PARA);

	LPSTR ssl_oids[] = {
		szOID_PKIX_KP_SERVER_AUTH,
		szOID_SERVER_GATED_CRYPTO,
		szOID_SGC_NETSCAPE,
	};

	if (!opts.dns_name.empty()) {
		para.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
		para.RequestedUsage.Usage.cUsageIdentifier = sizeof(ssl_oids)/sizeof(ssl_oids[0]);
		para.RequestedUsage.Usage.rgpszUsageIdentifier = ssl_oids;
	} else {
		para.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
		para.RequestedUsage.Usage.cUsageIdentifier = 0;
		para.RequestedUsage.Usage.rgpszUsageIdentifier = nullptr;
	}

	const CERT_CHAIN_CONTEXT *chain_ctx = nullptr;
	verify_time = this->FileTimeFromStdTimeT(opts.time);
	bool ok = CertGetCertificateChain(nullptr, store_ctx, (opts.time != 0) ? &verify_time : nullptr, store_ctx->hCertStore, &para, 0, nullptr, &chain_ctx);
	if (!ok) {
		goto out;
	}

	if (chain_ctx->TrustStatus.dwErrorStatus != CERT_TRUST_NO_ERROR) {
		goto out;
	}

	if (!opts.dns_name.empty()) {
		wide_dns_name = this->UTF16StringFromStdString(opts.dns_name);

		SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslpara;
		memset(&sslpara, 0, sizeof(sslpara));
		sslpara.cbSize = sizeof(sslpara);
		sslpara.dwAuthType = AUTHTYPE_SERVER;
		sslpara.pwszServerName = wide_dns_name;

		CERT_CHAIN_POLICY_PARA chainpara;
		memset(&chainpara, 0, sizeof(chainpara));
		chainpara.pvExtraPolicyPara = &sslpara;
		chainpara.dwFlags = 0;
		chainpara.cbSize = sizeof(chainpara);

		CERT_CHAIN_POLICY_STATUS chain_status;
		memset(&chain_status, 0, sizeof(chain_status));
		ok = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chain_ctx, &chainpara, &chain_status);
		if (!ok) {
			goto out;
		}
		if (chain_status.dwError == 0) {
			status = true;
		}
	} else {
		status = true;
	}

out:
	if (store_ctx != nullptr) {
		CertFreeCertificateContext(store_ctx);
	}
	if (chain_ctx != nullptr) {
		CertFreeCertificateChain(chain_ctx);
	}
	if (wide_dns_name != nullptr) {
		free(wide_dns_name);
	}
	return status;
}

}
<commit_msg>X509Verifier_win: fix access of uninitialized local vars in VerifyChain.<commit_after>// Copyright (c) 2013 The libmumble Developers
// The use of this source code is goverened by a BSD-style
// license that can be found in the LICENSE-file.

#include <mumble/X509Verifier.h>
#include "X509Verifier_win.h"
#include "X509HostnameVerifier.h"
#include <mumble/X509Certificate.h>
#include "X509Certificate_p.h"
#include "OpenSSLUtils.h"

#include <vector>
#include <string>

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <wincrypt.h>

#include "uv.h"

namespace mumble {

static uv_once_t    system_verifier_once_ = UV_ONCE_INIT;
static X509Verifier *system_verifier_ptr_;

void X509VerifierPrivate::InitializeSystemVerifier() {
	OpenSSLUtils::EnsureInitialized();
	system_verifier_ptr_ = new X509Verifier;
}

X509Verifier &X509Verifier::SystemVerifier() {
	uv_once(&system_verifier_once_, X509VerifierPrivate::InitializeSystemVerifier);
	return *system_verifier_ptr_;
}

X509Verifier::X509Verifier() : dptr_(new X509VerifierPrivate) {
}

X509Verifier::~X509Verifier() {
}

bool X509Verifier::VerifyChain(std::vector<X509Certificate> chain, const mumble::X509VerifierOptions &opts) {
	return dptr_->VerifyChain(chain, opts);
}

X509VerifierPrivate::X509VerifierPrivate() {
}

// AddCertToStore creates a CERT_CONTEXT of the certificate passed in as cert and adds it to the certificate store represented
// by store. If ctx_out points to a non-nullptr CERT_CONTEXT, ctx_out will be updated to point to a copy of the CERT_CONTEXT that
// is added to store.
bool X509VerifierPrivate::AddCertToStore(HCERTSTORE store, const X509Certificate &cert, const CERT_CONTEXT **ctx_out) const {
	const ByteArray &buf = cert.dptr_->cert_der_;
	const CERT_CONTEXT *ctx = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, reinterpret_cast<const BYTE*>(buf.ConstData()), buf.Length());
	if (ctx == nullptr) {
		return false;
	}

	bool ok = CertAddCertificateContextToStore(store, ctx, CERT_STORE_ADD_ALWAYS, ctx_out);
	if (!ok) {
		CertFreeCertificateContext(ctx);
		return false;
	}

	CertFreeCertificateContext(ctx);
	return true;
}

// CreateCertContextFromChain creates a CERT_CONTEXT representing the leaf certificate (index 0 of the chain)
// in an in-memory certificate store which will also contains any intermediate certificates found in the chain.
//
// While the method returns a CERT_CONTEXT that represents the leaf certificate, this CERT_CONTEXT contains a pointer
// to the in-memory store that holds the whole certificate chain. This store can be accessed via the hCertStore field
// of the returned CERT_CONTEXT. The store is automatically closed when the CERT_CONTEXT that this function returns
// is freed using CertFreeCertificateContext (it holds the only reference to the store).
const CERT_CONTEXT *X509VerifierPrivate::CreateCertContextFromChain(const std::vector<X509Certificate> &chain) const {
	const CERT_CONTEXT *store_ctx = nullptr;

	HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, nullptr);
	if (store == nullptr) {
		goto err;
	}

	if (!this->AddCertToStore(store, chain.at(0), &store_ctx)) {
		goto err;
	}

	for (int i = 1; i < chain.size(); i++) {
		if (!this->AddCertToStore(store, chain.at(i))) {
			goto err;
		}
	}

	return store_ctx;

err:
	if (store != nullptr) {
		CertCloseStore(store, 0);
	}
	if (store_ctx != nullptr) {
		CertFreeCertificateContext(store_ctx);
	}
	return nullptr;
}

// FileTimeForStdTimeT converts a std::time_t to a FILETIME.
FILETIME X509VerifierPrivate::FileTimeFromStdTimeT(std::time_t time) const {
	FILETIME ft;
	ULARGE_INTEGER lint;

	// 1 Jan 1601 00:00:00 UTC is -11644473600 in Unix epoch representation.
	const ULONGLONG epoch_1601 = 11644473600ULL;
	// Factor that converts from 1 sec (Unix epoch) increments to 100 nsec (FILETIME) increments.
	const ULONGLONG secs_to_100ns =  10000000ULL;

	lint.QuadPart = (epoch_1601 + time) * secs_to_100ns;
	ft.dwLowDateTime = lint.LowPart;
	ft.dwHighDateTime = lint.HighPart;

	return ft;
}

// UTF16StringFromStdString converts a UTF-8 encoded std::string to a UTF-16 WCHAR *.
// The returned pointer must be freed with free().
WCHAR *X509VerifierPrivate::UTF16StringFromStdString(const std::string &str) const {
	WCHAR *buf;
	int sz = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.c_str(), -1, nullptr, 0);
	if (sz == 0) {
		return nullptr;
	}

	buf = reinterpret_cast<WCHAR *>(malloc(sz*sizeof(WCHAR)));
	sz = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.c_str(), -1, buf, sz);
	if (sz == 0) {
		return nullptr;
	}

	return buf;
}

// VerifyChain verifies the certificate chain in chain
// according to the verification options given as opts.
bool X509VerifierPrivate::VerifyChain(std::vector<X509Certificate> chain, const X509VerifierOptions &opts) {
	const CERT_CHAIN_CONTEXT *chain_ctx = nullptr;
	const CERT_CONTEXT *store_ctx = nullptr;
	WCHAR *wide_dns_name = nullptr;
	FILETIME verify_time;
	bool status = false;

	if (chain.empty()) {
		goto out;
	}

	store_ctx = this->CreateCertContextFromChain(chain);
	if (store_ctx == nullptr) {
		goto out;
	}

	CERT_CHAIN_PARA para;
	memset(&para, 0, sizeof(para));
	para.cbSize = sizeof(CERT_CHAIN_PARA);

	LPSTR ssl_oids[] = {
		szOID_PKIX_KP_SERVER_AUTH,
		szOID_SERVER_GATED_CRYPTO,
		szOID_SGC_NETSCAPE,
	};

	if (!opts.dns_name.empty()) {
		para.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
		para.RequestedUsage.Usage.cUsageIdentifier = sizeof(ssl_oids)/sizeof(ssl_oids[0]);
		para.RequestedUsage.Usage.rgpszUsageIdentifier = ssl_oids;
	} else {
		para.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
		para.RequestedUsage.Usage.cUsageIdentifier = 0;
		para.RequestedUsage.Usage.rgpszUsageIdentifier = nullptr;
	}

	verify_time = this->FileTimeFromStdTimeT(opts.time);
	bool ok = CertGetCertificateChain(nullptr, store_ctx, (opts.time != 0) ? &verify_time : nullptr, store_ctx->hCertStore, &para, 0, nullptr, &chain_ctx);
	if (!ok) {
		goto out;
	}

	if (chain_ctx->TrustStatus.dwErrorStatus != CERT_TRUST_NO_ERROR) {
		goto out;
	}

	if (!opts.dns_name.empty()) {
		wide_dns_name = this->UTF16StringFromStdString(opts.dns_name);

		SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslpara;
		memset(&sslpara, 0, sizeof(sslpara));
		sslpara.cbSize = sizeof(sslpara);
		sslpara.dwAuthType = AUTHTYPE_SERVER;
		sslpara.pwszServerName = wide_dns_name;

		CERT_CHAIN_POLICY_PARA chainpara;
		memset(&chainpara, 0, sizeof(chainpara));
		chainpara.pvExtraPolicyPara = &sslpara;
		chainpara.dwFlags = 0;
		chainpara.cbSize = sizeof(chainpara);

		CERT_CHAIN_POLICY_STATUS chain_status;
		memset(&chain_status, 0, sizeof(chain_status));
		ok = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chain_ctx, &chainpara, &chain_status);
		if (!ok) {
			goto out;
		}
		if (chain_status.dwError == 0) {
			status = true;
		}
	} else {
		status = true;
	}

out:
	if (store_ctx != nullptr) {
		CertFreeCertificateContext(store_ctx);
	}
	if (chain_ctx != nullptr) {
		CertFreeCertificateChain(chain_ctx);
	}
	if (wide_dns_name != nullptr) {
		free(wide_dns_name);
	}
	return status;
}

}
<|endoftext|>


<commit_before>/*
 *  main.cpp
 *  Program:  kalarm
 *  Copyright © 2001-2007 by David Jarvie <software@astrojar.org.uk>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "kalarm.h"

#include <stdlib.h>

#include <kcmdlineargs.h>
#include <kaboutdata.h>
#include <klocale.h>
#include <kdebug.h>

#include "kalarmapp.h"

#define PROGRAM_NAME "kalarm"

static KCmdLineOptions options[] =
{
	{ "a", 0, 0 },
	{ "ack-confirm", I18N_NOOP("Prompt for confirmation when alarm is acknowledged"), 0 },
	{ "A", 0, 0 },
	{ "attach <url>", I18N_NOOP("Attach file to email (repeat as needed)"), 0 },
	{ "auto-close", I18N_NOOP("Auto-close alarm window after --late-cancel period"), 0 },
	{ "bcc", I18N_NOOP("Blind copy email to self"), 0 },
	{ "b", 0, 0 },
	{ "beep", I18N_NOOP("Beep when message is displayed"), 0 },
	{ "colour", 0, 0 },
	{ "c", 0, 0 },
	{ "color <color>", I18N_NOOP("Message background color (name or hex 0xRRGGBB)"), 0 },
	{ "colourfg", 0, 0 },
	{ "C", 0, 0 },
	{ "colorfg <color>", I18N_NOOP("Message foreground color (name or hex 0xRRGGBB)"), 0 },
	{ "calendarURL <url>", I18N_NOOP("URL of calendar file"), 0 },
	{ "cancelEvent <eventID>", I18N_NOOP("Cancel alarm with the specified event ID"), 0 },
	{ "d", 0, 0 },
	{ "disable", I18N_NOOP("Disable the alarm"), 0 },
	{ "e", 0, 0 },
	{ "!exec <commandline>", I18N_NOOP("Execute a shell command line"), 0 },
	{ "edit <eventID>", I18N_NOOP("Display the alarm edit dialog to edit the specified alarm"), 0 },
	{ "n", 0, 0 },
	{ "edit-new", I18N_NOOP("Display the alarm edit dialog to edit a new alarm"), 0 },
	{ "edit-new-preset <templateName>", I18N_NOOP("Display the alarm edit dialog, preset with a template"), 0 },
	{ "f", 0, 0 },
	{ "file <url>", I18N_NOOP("File to display"), 0 },
	{ "F", 0, 0 },
	{ "from-id <ID>", I18N_NOOP("KMail identity to use as sender of email"), 0 },
	{ "handleEvent <eventID>", I18N_NOOP("Trigger or cancel alarm with the specified event ID"), 0 },
	{ "i", 0, 0 },
	{ "interval <period>", I18N_NOOP("Interval between alarm repetitions"), 0 },
	{ "k", 0, 0 },
	{ "korganizer", I18N_NOOP("Show alarm as an event in KOrganizer"), 0 },
	{ "l", 0, 0 },
	{ "late-cancel <period>", I18N_NOOP("Cancel alarm if more than 'period' late when triggered"), "1" },
	{ "L", 0, 0 },
	{ "login", I18N_NOOP("Repeat alarm at every login"), 0 },
	{ "m", 0, 0 },
	{ "mail <address>", I18N_NOOP("Send an email to the given address (repeat as needed)"), 0 },
	{ "p", 0, 0 },
	{ "play <url>", I18N_NOOP("Audio file to play once"), 0 },
#ifndef WITHOUT_ARTS
	{ "P", 0, 0 },
	{ "play-repeat <url>", I18N_NOOP("Audio file to play repeatedly"), 0 },
#endif
	{ "recurrence <spec>", I18N_NOOP("Specify alarm recurrence using iCalendar syntax"), 0 },
	{ "R", 0, 0 },
	{ "reminder <period>", I18N_NOOP("Display reminder in advance of alarm"), 0 },
	{ "reminder-once <period>", I18N_NOOP("Display reminder once, before first alarm recurrence"), 0 },
	{ "r", 0, 0 },
	{ "repeat <count>", I18N_NOOP("Number of times to repeat alarm (including initial occasion)"), 0 },
	{ "reset", I18N_NOOP("Reset the alarm scheduling daemon"), 0 },
	{ "s", 0, 0 },
	{ "speak", I18N_NOOP("Speak the message when it is displayed"), 0 },
	{ "stop", I18N_NOOP("Stop the alarm scheduling daemon"), 0 },
	{ "S", 0, 0 },
	{ "subject", I18N_NOOP("Email subject line"), 0 },
	{ "t", 0, 0 },
	{ "time <time>", I18N_NOOP("Trigger alarm at time [[[yyyy-]mm-]dd-]hh:mm, or date yyyy-mm-dd"), 0 },
	{ "tray", I18N_NOOP("Display system tray icon"), 0 },
	{ "triggerEvent <eventID>", I18N_NOOP("Trigger alarm with the specified event ID"), 0 },
	{ "u", 0, 0 },
	{ "until <time>", I18N_NOOP("Repeat until time [[[yyyy-]mm-]dd-]hh:mm, or date yyyy-mm-dd"), 0 },
#ifndef WITHOUT_ARTS
	{ "V", 0, 0 },
	{ "volume <percent>", I18N_NOOP("Volume to play audio file"), 0 },
#endif
	{ "+[message]", I18N_NOOP("Message text to display"), 0 },
	KCmdLineLastOption
};

int main(int argc, char *argv[])
{
	KAboutData aboutData(PROGRAM_NAME, I18N_NOOP("KAlarm"), KALARM_VERSION,
		I18N_NOOP("Personal alarm message, command and email scheduler for KDE"),
		KAboutData::License_GPL,
		"(c) 2001-2007, David Jarvie", 0, "http://www.astrojar.org.uk/linux/kalarm.html");
	aboutData.addAuthor("David Jarvie", 0, "software@astrojar.org.uk");

	KCmdLineArgs::init(argc, argv, &aboutData);
	KCmdLineArgs::addCmdLineOptions(options);
	KUniqueApplication::addCmdLineOptions();

	if (!KAlarmApp::start())
	{
		// An instance of the application is already running
		exit(0);
	}

	// This is the first time through
	kdDebug(5950) << "main(): initialising\n";
	KAlarmApp* app = KAlarmApp::getInstance();
	app->restoreSession();
	return app->exec();
}
<commit_msg>Fix copyright notice. Amend KAlarm URL.<commit_after>/*
 *  main.cpp
 *  Program:  kalarm
 *  Copyright © 2001-2007 by David Jarvie <software@astrojar.org.uk>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "kalarm.h"

#include <stdlib.h>

#include <kcmdlineargs.h>
#include <kaboutdata.h>
#include <klocale.h>
#include <kdebug.h>

#include "kalarmapp.h"

#define PROGRAM_NAME "kalarm"

static KCmdLineOptions options[] =
{
	{ "a", 0, 0 },
	{ "ack-confirm", I18N_NOOP("Prompt for confirmation when alarm is acknowledged"), 0 },
	{ "A", 0, 0 },
	{ "attach <url>", I18N_NOOP("Attach file to email (repeat as needed)"), 0 },
	{ "auto-close", I18N_NOOP("Auto-close alarm window after --late-cancel period"), 0 },
	{ "bcc", I18N_NOOP("Blind copy email to self"), 0 },
	{ "b", 0, 0 },
	{ "beep", I18N_NOOP("Beep when message is displayed"), 0 },
	{ "colour", 0, 0 },
	{ "c", 0, 0 },
	{ "color <color>", I18N_NOOP("Message background color (name or hex 0xRRGGBB)"), 0 },
	{ "colourfg", 0, 0 },
	{ "C", 0, 0 },
	{ "colorfg <color>", I18N_NOOP("Message foreground color (name or hex 0xRRGGBB)"), 0 },
	{ "calendarURL <url>", I18N_NOOP("URL of calendar file"), 0 },
	{ "cancelEvent <eventID>", I18N_NOOP("Cancel alarm with the specified event ID"), 0 },
	{ "d", 0, 0 },
	{ "disable", I18N_NOOP("Disable the alarm"), 0 },
	{ "e", 0, 0 },
	{ "!exec <commandline>", I18N_NOOP("Execute a shell command line"), 0 },
	{ "edit <eventID>", I18N_NOOP("Display the alarm edit dialog to edit the specified alarm"), 0 },
	{ "n", 0, 0 },
	{ "edit-new", I18N_NOOP("Display the alarm edit dialog to edit a new alarm"), 0 },
	{ "edit-new-preset <templateName>", I18N_NOOP("Display the alarm edit dialog, preset with a template"), 0 },
	{ "f", 0, 0 },
	{ "file <url>", I18N_NOOP("File to display"), 0 },
	{ "F", 0, 0 },
	{ "from-id <ID>", I18N_NOOP("KMail identity to use as sender of email"), 0 },
	{ "handleEvent <eventID>", I18N_NOOP("Trigger or cancel alarm with the specified event ID"), 0 },
	{ "i", 0, 0 },
	{ "interval <period>", I18N_NOOP("Interval between alarm repetitions"), 0 },
	{ "k", 0, 0 },
	{ "korganizer", I18N_NOOP("Show alarm as an event in KOrganizer"), 0 },
	{ "l", 0, 0 },
	{ "late-cancel <period>", I18N_NOOP("Cancel alarm if more than 'period' late when triggered"), "1" },
	{ "L", 0, 0 },
	{ "login", I18N_NOOP("Repeat alarm at every login"), 0 },
	{ "m", 0, 0 },
	{ "mail <address>", I18N_NOOP("Send an email to the given address (repeat as needed)"), 0 },
	{ "p", 0, 0 },
	{ "play <url>", I18N_NOOP("Audio file to play once"), 0 },
#ifndef WITHOUT_ARTS
	{ "P", 0, 0 },
	{ "play-repeat <url>", I18N_NOOP("Audio file to play repeatedly"), 0 },
#endif
	{ "recurrence <spec>", I18N_NOOP("Specify alarm recurrence using iCalendar syntax"), 0 },
	{ "R", 0, 0 },
	{ "reminder <period>", I18N_NOOP("Display reminder in advance of alarm"), 0 },
	{ "reminder-once <period>", I18N_NOOP("Display reminder once, before first alarm recurrence"), 0 },
	{ "r", 0, 0 },
	{ "repeat <count>", I18N_NOOP("Number of times to repeat alarm (including initial occasion)"), 0 },
	{ "reset", I18N_NOOP("Reset the alarm scheduling daemon"), 0 },
	{ "s", 0, 0 },
	{ "speak", I18N_NOOP("Speak the message when it is displayed"), 0 },
	{ "stop", I18N_NOOP("Stop the alarm scheduling daemon"), 0 },
	{ "S", 0, 0 },
	{ "subject", I18N_NOOP("Email subject line"), 0 },
	{ "t", 0, 0 },
	{ "time <time>", I18N_NOOP("Trigger alarm at time [[[yyyy-]mm-]dd-]hh:mm, or date yyyy-mm-dd"), 0 },
	{ "tray", I18N_NOOP("Display system tray icon"), 0 },
	{ "triggerEvent <eventID>", I18N_NOOP("Trigger alarm with the specified event ID"), 0 },
	{ "u", 0, 0 },
	{ "until <time>", I18N_NOOP("Repeat until time [[[yyyy-]mm-]dd-]hh:mm, or date yyyy-mm-dd"), 0 },
#ifndef WITHOUT_ARTS
	{ "V", 0, 0 },
	{ "volume <percent>", I18N_NOOP("Volume to play audio file"), 0 },
#endif
	{ "+[message]", I18N_NOOP("Message text to display"), 0 },
	KCmdLineLastOption
};

int main(int argc, char *argv[])
{
	KAboutData aboutData(PROGRAM_NAME, I18N_NOOP("KAlarm"), KALARM_VERSION,
		I18N_NOOP("Personal alarm message, command and email scheduler for KDE"),
		KAboutData::License_GPL,
		"Copyright 2001-2007, David Jarvie", 0, "http://www.astrojar.org.uk/kalarm");
	aboutData.addAuthor("David Jarvie", 0, "software@astrojar.org.uk");

	KCmdLineArgs::init(argc, argv, &aboutData);
	KCmdLineArgs::addCmdLineOptions(options);
	KUniqueApplication::addCmdLineOptions();

	if (!KAlarmApp::start())
	{
		// An instance of the application is already running
		exit(0);
	}

	// This is the first time through
	kdDebug(5950) << "main(): initialising\n";
	KAlarmApp* app = KAlarmApp::getInstance();
	app->restoreSession();
	return app->exec();
}
<|endoftext|>


<commit_before>#pragma once

#include "cpputil.hh"
#include "ns.hh"
#include "gc.hh"
#include <atomic>
#include "refcache.hh"
#include "condvar.h"
#include "semaphore.h"
#include "seqlock.hh"
#include "mfs.hh"
#include "sleeplock.hh"
#include <uk/unistd.h>

class dirns;

u64 namehash(const strbuf<DIRSIZ>&);

struct file : public rcu_freed {
  virtual int stat(struct stat*, enum stat_flags) { return -1; }
  virtual ssize_t read(char *addr, size_t n) { return -1; }
  virtual ssize_t write(const char *addr, size_t n) { return -1; }
  virtual ssize_t pread(char *addr, size_t n, off_t offset) { return -1; }
  virtual ssize_t pwrite(const char *addr, size_t n, off_t offset) { return -1; }

  virtual void inc() = 0;
  virtual void dec() = 0;

protected:
  file() : rcu_freed("file", this, sizeof(*this)) {}
};

struct file_inode : public refcache::referenced, public file {
public:
  file_inode(sref<mnode> i, bool r, bool w, bool a)
    : ip(i), readable(r), writable(w), append(a), off(0) {}
  NEW_DELETE_OPS(file_inode);

  void inc() override { refcache::referenced::inc(); }
  void dec() override { refcache::referenced::dec(); }

  sref<mnode> ip;
  const bool readable;
  const bool writable;
  const bool append;
  u32 off;
  sleeplock off_lock;

  int stat(struct stat*, enum stat_flags) override;
  ssize_t read(char *addr, size_t n) override;
  ssize_t write(const char *addr, size_t n) override;
  ssize_t pread(char* addr, size_t n, off_t off) override;
  ssize_t pwrite(const char *addr, size_t n, off_t offset) override;
  void onzero() override;

protected:
  void do_gc(void) override { delete this; }
};

struct file_socket : public refcache::referenced, public file {
public:
  file_socket() : socket(0), localsock(nullptr),
                  wsem("file::wsem", 1), rsem("file::rsem", 1) {}
  NEW_DELETE_OPS(file_socket);

  void inc() override { referenced::inc(); }
  void dec() override { referenced::dec(); }

  int socket;
  struct localsock *localsock;
  char socketpath[UNIX_PATH_MAX];

  ssize_t read(char *addr, size_t n) override;
  ssize_t write(const char *addr, size_t n) override;
  void onzero() override;

protected:
  void do_gc(void) override { delete this; }

private:
  // XXX This locking should be handled in net, not here.
  semaphore wsem, rsem;
};

struct file_pipe_reader : public refcache::referenced, public file {
public:
  file_pipe_reader(pipe* p) : pipe(p) {}
  NEW_DELETE_OPS(file_pipe_reader);

  void inc() override { refcache::referenced::inc(); }
  void dec() override { refcache::referenced::dec(); }

  ssize_t read(char *addr, size_t n) override;
  void onzero() override;

protected:
  void do_gc(void) override { delete this; }

private:
  struct pipe* const pipe;
};

struct file_pipe_writer : public referenced, public file {
public:
  file_pipe_writer(pipe* p) : pipe(p) {}
  NEW_DELETE_OPS(file_pipe_writer);

  void inc() override { referenced::inc(); }
  void dec() override { referenced::dec(); }

  ssize_t write(const char *addr, size_t n) override;
  void onzero() override;

protected:
  void do_gc(void) override { delete this; }

private:
  struct pipe* const pipe;
};

// in-core file system types
struct inode : public referenced, public rcu_freed
{
  void  init();
  void  link();
  void  unlink();
  short nlink();

  inode& operator=(const inode&) = delete;
  inode(const inode& x) = delete;

  void do_gc() override { delete this; }

  // const for lifetime of object:
  const u32 dev;
  const u32 inum;

  // const unless inode is reused:
  u32 gen;
  std::atomic<short> type;
  short major;
  short minor;

  // locks for the rest of the inode
  seqcount<u64> seq;
  struct condvar cv;
  struct spinlock lock;
  char lockname[16];

  // initially null, set once:
  std::atomic<dirns*> dir;
  std::atomic<bool> valid;

  // protected by seq/lock:
  std::atomic<bool> busy;
  std::atomic<int> readbusy;

  u32 size;
  std::atomic<u32> addrs[NDIRECT+2];
  std::atomic<volatile u32*> iaddrs;
  short nlink_;

  // ??? what's the concurrency control plan?
  struct localsock *localsock;
  char socketpath[PATH_MAX];

private:
  inode(u32 dev, u32 inum);
  ~inode();
  NEW_DELETE_OPS(inode)

  static sref<inode> alloc(u32 dev, u32 inum);
  friend void initinode();
  friend sref<inode> iget(u32, u32);

protected:
  void onzero() override;
};

// device implementations

class mdev;

struct devsw {
  int (*read)(mdev*, char*, u32);
  int (*pread)(mdev*, char*, u32, u32);
  int (*write)(mdev*, const char*, u32);
  int (*pwrite)(mdev*, const char*, u32, u32);
  void (*stat)(mdev*, struct stat*);
};

extern struct devsw devsw[];
<commit_msg>more const<commit_after>#pragma once

#include "cpputil.hh"
#include "ns.hh"
#include "gc.hh"
#include <atomic>
#include "refcache.hh"
#include "condvar.h"
#include "semaphore.h"
#include "seqlock.hh"
#include "mfs.hh"
#include "sleeplock.hh"
#include <uk/unistd.h>

class dirns;

u64 namehash(const strbuf<DIRSIZ>&);

struct file : public rcu_freed {
  virtual int stat(struct stat*, enum stat_flags) { return -1; }
  virtual ssize_t read(char *addr, size_t n) { return -1; }
  virtual ssize_t write(const char *addr, size_t n) { return -1; }
  virtual ssize_t pread(char *addr, size_t n, off_t offset) { return -1; }
  virtual ssize_t pwrite(const char *addr, size_t n, off_t offset) { return -1; }

  virtual void inc() = 0;
  virtual void dec() = 0;

protected:
  file() : rcu_freed("file", this, sizeof(*this)) {}
};

struct file_inode : public refcache::referenced, public file {
public:
  file_inode(sref<mnode> i, bool r, bool w, bool a)
    : ip(i), readable(r), writable(w), append(a), off(0) {}
  NEW_DELETE_OPS(file_inode);

  void inc() override { refcache::referenced::inc(); }
  void dec() override { refcache::referenced::dec(); }

  const sref<mnode> ip;
  const bool readable;
  const bool writable;
  const bool append;
  u32 off;
  sleeplock off_lock;

  int stat(struct stat*, enum stat_flags) override;
  ssize_t read(char *addr, size_t n) override;
  ssize_t write(const char *addr, size_t n) override;
  ssize_t pread(char* addr, size_t n, off_t off) override;
  ssize_t pwrite(const char *addr, size_t n, off_t offset) override;
  void onzero() override;

protected:
  void do_gc(void) override { delete this; }
};

struct file_socket : public refcache::referenced, public file {
public:
  file_socket() : socket(0), localsock(nullptr),
                  wsem("file::wsem", 1), rsem("file::rsem", 1) {}
  NEW_DELETE_OPS(file_socket);

  void inc() override { referenced::inc(); }
  void dec() override { referenced::dec(); }

  int socket;
  struct localsock *localsock;
  char socketpath[UNIX_PATH_MAX];

  ssize_t read(char *addr, size_t n) override;
  ssize_t write(const char *addr, size_t n) override;
  void onzero() override;

protected:
  void do_gc(void) override { delete this; }

private:
  // XXX This locking should be handled in net, not here.
  semaphore wsem, rsem;
};

struct file_pipe_reader : public refcache::referenced, public file {
public:
  file_pipe_reader(pipe* p) : pipe(p) {}
  NEW_DELETE_OPS(file_pipe_reader);

  void inc() override { refcache::referenced::inc(); }
  void dec() override { refcache::referenced::dec(); }

  ssize_t read(char *addr, size_t n) override;
  void onzero() override;

protected:
  void do_gc(void) override { delete this; }

private:
  struct pipe* const pipe;
};

struct file_pipe_writer : public referenced, public file {
public:
  file_pipe_writer(pipe* p) : pipe(p) {}
  NEW_DELETE_OPS(file_pipe_writer);

  void inc() override { referenced::inc(); }
  void dec() override { referenced::dec(); }

  ssize_t write(const char *addr, size_t n) override;
  void onzero() override;

protected:
  void do_gc(void) override { delete this; }

private:
  struct pipe* const pipe;
};

// in-core file system types
struct inode : public referenced, public rcu_freed
{
  void  init();
  void  link();
  void  unlink();
  short nlink();

  inode& operator=(const inode&) = delete;
  inode(const inode& x) = delete;

  void do_gc() override { delete this; }

  // const for lifetime of object:
  const u32 dev;
  const u32 inum;

  // const unless inode is reused:
  u32 gen;
  std::atomic<short> type;
  short major;
  short minor;

  // locks for the rest of the inode
  seqcount<u64> seq;
  struct condvar cv;
  struct spinlock lock;
  char lockname[16];

  // initially null, set once:
  std::atomic<dirns*> dir;
  std::atomic<bool> valid;

  // protected by seq/lock:
  std::atomic<bool> busy;
  std::atomic<int> readbusy;

  u32 size;
  std::atomic<u32> addrs[NDIRECT+2];
  std::atomic<volatile u32*> iaddrs;
  short nlink_;

  // ??? what's the concurrency control plan?
  struct localsock *localsock;
  char socketpath[PATH_MAX];

private:
  inode(u32 dev, u32 inum);
  ~inode();
  NEW_DELETE_OPS(inode)

  static sref<inode> alloc(u32 dev, u32 inum);
  friend void initinode();
  friend sref<inode> iget(u32, u32);

protected:
  void onzero() override;
};

// device implementations

class mdev;

struct devsw {
  int (*read)(mdev*, char*, u32);
  int (*pread)(mdev*, char*, u32, u32);
  int (*write)(mdev*, const char*, u32);
  int (*pwrite)(mdev*, const char*, u32, u32);
  void (*stat)(mdev*, struct stat*);
};

extern struct devsw devsw[];
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ExternalUriReferenceTranslator.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: hr $ $Date: 2007-09-27 13:06:11 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_stoc.hxx"

#include "stocservices.hxx"

#include "supportsService.hxx"

#include "com/sun/star/lang/XServiceInfo.hpp"
#include "com/sun/star/uno/Exception.hpp"
#include "com/sun/star/uno/Reference.hxx"
#include "com/sun/star/uno/RuntimeException.hpp"
#include "com/sun/star/uno/Sequence.hxx"
#include "com/sun/star/uno/XComponentContext.hpp"
#include "com/sun/star/uno/XInterface.hpp"
#include "com/sun/star/uri/XExternalUriReferenceTranslator.hpp"
#include "cppuhelper/implbase2.hxx"
#include "cppuhelper/weak.hxx"
#include "osl/thread.h"
#include "rtl/string.h"
#include "rtl/textenc.h"
#include "rtl/uri.h"
#include "rtl/uri.hxx"
#include "rtl/ustrbuf.hxx"
#include "rtl/ustring.hxx"
#include "sal/types.h"

#include <new>

namespace css = com::sun::star;

namespace {

class Translator: public cppu::WeakImplHelper2<
    css::lang::XServiceInfo, css::uri::XExternalUriReferenceTranslator >
{
public:
    explicit Translator(
        css::uno::Reference< css::uno::XComponentContext > const & context):
        m_context(context) {}

    virtual rtl::OUString SAL_CALL getImplementationName()
        throw (css::uno::RuntimeException);

    virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & serviceName)
        throw (css::uno::RuntimeException);

    virtual css::uno::Sequence< rtl::OUString > SAL_CALL
    getSupportedServiceNames() throw (css::uno::RuntimeException);

    virtual rtl::OUString SAL_CALL
    translateToInternal(rtl::OUString const & externalUriReference)
        throw (css::uno::RuntimeException);

    virtual rtl::OUString SAL_CALL
    translateToExternal(rtl::OUString const & internalUriReference)
        throw (css::uno::RuntimeException);

private:
    Translator(Translator &); // not implemented
    void operator =(Translator); // not implemented

    virtual ~Translator() {}

    css::uno::Reference< css::uno::XComponentContext > m_context;
};

rtl::OUString Translator::getImplementationName()
    throw (css::uno::RuntimeException)
{
    return
        stoc_services::ExternalUriReferenceTranslator::getImplementationName();
}

sal_Bool Translator::supportsService(rtl::OUString const & serviceName)
    throw (css::uno::RuntimeException)
{
    return stoc::uriproc::supportsService(
        getSupportedServiceNames(), serviceName);
}

css::uno::Sequence< rtl::OUString > Translator::getSupportedServiceNames()
    throw (css::uno::RuntimeException)
{
    return stoc_services::ExternalUriReferenceTranslator::
        getSupportedServiceNames();
}

rtl::OUString Translator::translateToInternal(
    rtl::OUString const & externalUriReference)
    throw (css::uno::RuntimeException)
{
    if (!externalUriReference.matchIgnoreAsciiCaseAsciiL(
            RTL_CONSTASCII_STRINGPARAM("file:/")))
    {
        return externalUriReference;
    }
    sal_Int32 i = RTL_CONSTASCII_LENGTH("file:");
    rtl::OUStringBuffer buf;
    buf.append(externalUriReference.getStr(), i);
    // Some environments (e.g., Java) produce illegal file URLs without an
    // authority part; treat them as having an empty authority part:
    if (!externalUriReference.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("//"), i))
    {
        buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
    }
    rtl_TextEncoding encoding = osl_getThreadTextEncoding();
    for (bool path = true;;) {
        sal_Int32 j = i;
        while (j != externalUriReference.getLength()
               && externalUriReference[j] != '#'
               && (!path || externalUriReference[j] != '/'))
        {
            ++j;
        }
        if (j != i) {
            rtl::OUString seg(
                rtl::Uri::encode(
                    rtl::Uri::decode(
                        externalUriReference.copy(i, j - i),
                        rtl_UriDecodeStrict, encoding),
                    rtl_UriCharClassPchar, rtl_UriEncodeStrict,
                    RTL_TEXTENCODING_UTF8));
            if (seg.getLength() == 0) {
                return rtl::OUString();
            }
            buf.append(seg);
        }
        if (j == externalUriReference.getLength()) {
            break;
        }
        buf.append(externalUriReference[j]);
        path = externalUriReference[j] == '/';
        i = j + 1;
    }
    return buf.makeStringAndClear();
}

rtl::OUString Translator::translateToExternal(
    rtl::OUString const & internalUriReference)
    throw (css::uno::RuntimeException)
{
    if (!internalUriReference.matchIgnoreAsciiCaseAsciiL(
            RTL_CONSTASCII_STRINGPARAM("file://")))
    {
        return internalUriReference;
    }
    sal_Int32 i = RTL_CONSTASCII_LENGTH("file://");
    rtl::OUStringBuffer buf;
    buf.append(internalUriReference.getStr(), i);
    rtl_TextEncoding encoding = osl_getThreadTextEncoding();
    for (bool path = true;;) {
        sal_Int32 j = i;
        while (j != internalUriReference.getLength()
               && internalUriReference[j] != '#'
               && (!path || internalUriReference[j] != '/'))
        {
            ++j;
        }
        if (j != i) {
            // Use rtl_UriDecodeToIuri -> rtl_UriEncodeStrictKeepEscapes instead
            // of rtl_UriDecodeStrict -> rtl_UriEncodeStrict, so that spurious
            // non--UTF-8 octets like "%FE" are copied verbatim:
            rtl::OUString seg(
                rtl::Uri::encode(
                    rtl::Uri::decode(
                        internalUriReference.copy(i, j - i),
                        rtl_UriDecodeToIuri, RTL_TEXTENCODING_UTF8),
                    rtl_UriCharClassPchar, rtl_UriEncodeStrictKeepEscapes,
                    encoding));
            if (seg.getLength() == 0) {
                return rtl::OUString();
            }
            buf.append(seg);
        }
        if (j == internalUriReference.getLength()) {
            break;
        }
        buf.append(internalUriReference[j]);
        path = internalUriReference[j] == '/';
        i = j + 1;
    }
    return buf.makeStringAndClear();
}

}

namespace stoc_services  { namespace ExternalUriReferenceTranslator {

css::uno::Reference< css::uno::XInterface > create(
    css::uno::Reference< css::uno::XComponentContext > const & context)
    SAL_THROW((css::uno::Exception))
{
    try {
        return static_cast< cppu::OWeakObject * >(new Translator(context));
    } catch (std::bad_alloc &) {
        throw css::uno::RuntimeException(
            rtl::OUString::createFromAscii("std::bad_alloc"), 0);
    }
}

rtl::OUString getImplementationName() {
    return rtl::OUString::createFromAscii(
        "com.sun.star.comp.uri.ExternalUriReferenceTranslator");
}

css::uno::Sequence< rtl::OUString > getSupportedServiceNames() {
    css::uno::Sequence< rtl::OUString > s(1);
    s[0] = rtl::OUString::createFromAscii(
        "com.sun.star.uri.ExternalUriReferenceTranslator");
    return s;
}

} }
<commit_msg>INTEGRATION: CWS changefileheader (1.6.12); FILE MERGED 2008/03/31 07:26:13 rt 1.6.12.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: ExternalUriReferenceTranslator.cxx,v $
 * $Revision: 1.7 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_stoc.hxx"

#include "stocservices.hxx"

#include "supportsService.hxx"

#include "com/sun/star/lang/XServiceInfo.hpp"
#include "com/sun/star/uno/Exception.hpp"
#include "com/sun/star/uno/Reference.hxx"
#include "com/sun/star/uno/RuntimeException.hpp"
#include "com/sun/star/uno/Sequence.hxx"
#include "com/sun/star/uno/XComponentContext.hpp"
#include "com/sun/star/uno/XInterface.hpp"
#include "com/sun/star/uri/XExternalUriReferenceTranslator.hpp"
#include "cppuhelper/implbase2.hxx"
#include "cppuhelper/weak.hxx"
#include "osl/thread.h"
#include "rtl/string.h"
#include "rtl/textenc.h"
#include "rtl/uri.h"
#include "rtl/uri.hxx"
#include "rtl/ustrbuf.hxx"
#include "rtl/ustring.hxx"
#include "sal/types.h"

#include <new>

namespace css = com::sun::star;

namespace {

class Translator: public cppu::WeakImplHelper2<
    css::lang::XServiceInfo, css::uri::XExternalUriReferenceTranslator >
{
public:
    explicit Translator(
        css::uno::Reference< css::uno::XComponentContext > const & context):
        m_context(context) {}

    virtual rtl::OUString SAL_CALL getImplementationName()
        throw (css::uno::RuntimeException);

    virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & serviceName)
        throw (css::uno::RuntimeException);

    virtual css::uno::Sequence< rtl::OUString > SAL_CALL
    getSupportedServiceNames() throw (css::uno::RuntimeException);

    virtual rtl::OUString SAL_CALL
    translateToInternal(rtl::OUString const & externalUriReference)
        throw (css::uno::RuntimeException);

    virtual rtl::OUString SAL_CALL
    translateToExternal(rtl::OUString const & internalUriReference)
        throw (css::uno::RuntimeException);

private:
    Translator(Translator &); // not implemented
    void operator =(Translator); // not implemented

    virtual ~Translator() {}

    css::uno::Reference< css::uno::XComponentContext > m_context;
};

rtl::OUString Translator::getImplementationName()
    throw (css::uno::RuntimeException)
{
    return
        stoc_services::ExternalUriReferenceTranslator::getImplementationName();
}

sal_Bool Translator::supportsService(rtl::OUString const & serviceName)
    throw (css::uno::RuntimeException)
{
    return stoc::uriproc::supportsService(
        getSupportedServiceNames(), serviceName);
}

css::uno::Sequence< rtl::OUString > Translator::getSupportedServiceNames()
    throw (css::uno::RuntimeException)
{
    return stoc_services::ExternalUriReferenceTranslator::
        getSupportedServiceNames();
}

rtl::OUString Translator::translateToInternal(
    rtl::OUString const & externalUriReference)
    throw (css::uno::RuntimeException)
{
    if (!externalUriReference.matchIgnoreAsciiCaseAsciiL(
            RTL_CONSTASCII_STRINGPARAM("file:/")))
    {
        return externalUriReference;
    }
    sal_Int32 i = RTL_CONSTASCII_LENGTH("file:");
    rtl::OUStringBuffer buf;
    buf.append(externalUriReference.getStr(), i);
    // Some environments (e.g., Java) produce illegal file URLs without an
    // authority part; treat them as having an empty authority part:
    if (!externalUriReference.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("//"), i))
    {
        buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
    }
    rtl_TextEncoding encoding = osl_getThreadTextEncoding();
    for (bool path = true;;) {
        sal_Int32 j = i;
        while (j != externalUriReference.getLength()
               && externalUriReference[j] != '#'
               && (!path || externalUriReference[j] != '/'))
        {
            ++j;
        }
        if (j != i) {
            rtl::OUString seg(
                rtl::Uri::encode(
                    rtl::Uri::decode(
                        externalUriReference.copy(i, j - i),
                        rtl_UriDecodeStrict, encoding),
                    rtl_UriCharClassPchar, rtl_UriEncodeStrict,
                    RTL_TEXTENCODING_UTF8));
            if (seg.getLength() == 0) {
                return rtl::OUString();
            }
            buf.append(seg);
        }
        if (j == externalUriReference.getLength()) {
            break;
        }
        buf.append(externalUriReference[j]);
        path = externalUriReference[j] == '/';
        i = j + 1;
    }
    return buf.makeStringAndClear();
}

rtl::OUString Translator::translateToExternal(
    rtl::OUString const & internalUriReference)
    throw (css::uno::RuntimeException)
{
    if (!internalUriReference.matchIgnoreAsciiCaseAsciiL(
            RTL_CONSTASCII_STRINGPARAM("file://")))
    {
        return internalUriReference;
    }
    sal_Int32 i = RTL_CONSTASCII_LENGTH("file://");
    rtl::OUStringBuffer buf;
    buf.append(internalUriReference.getStr(), i);
    rtl_TextEncoding encoding = osl_getThreadTextEncoding();
    for (bool path = true;;) {
        sal_Int32 j = i;
        while (j != internalUriReference.getLength()
               && internalUriReference[j] != '#'
               && (!path || internalUriReference[j] != '/'))
        {
            ++j;
        }
        if (j != i) {
            // Use rtl_UriDecodeToIuri -> rtl_UriEncodeStrictKeepEscapes instead
            // of rtl_UriDecodeStrict -> rtl_UriEncodeStrict, so that spurious
            // non--UTF-8 octets like "%FE" are copied verbatim:
            rtl::OUString seg(
                rtl::Uri::encode(
                    rtl::Uri::decode(
                        internalUriReference.copy(i, j - i),
                        rtl_UriDecodeToIuri, RTL_TEXTENCODING_UTF8),
                    rtl_UriCharClassPchar, rtl_UriEncodeStrictKeepEscapes,
                    encoding));
            if (seg.getLength() == 0) {
                return rtl::OUString();
            }
            buf.append(seg);
        }
        if (j == internalUriReference.getLength()) {
            break;
        }
        buf.append(internalUriReference[j]);
        path = internalUriReference[j] == '/';
        i = j + 1;
    }
    return buf.makeStringAndClear();
}

}

namespace stoc_services  { namespace ExternalUriReferenceTranslator {

css::uno::Reference< css::uno::XInterface > create(
    css::uno::Reference< css::uno::XComponentContext > const & context)
    SAL_THROW((css::uno::Exception))
{
    try {
        return static_cast< cppu::OWeakObject * >(new Translator(context));
    } catch (std::bad_alloc &) {
        throw css::uno::RuntimeException(
            rtl::OUString::createFromAscii("std::bad_alloc"), 0);
    }
}

rtl::OUString getImplementationName() {
    return rtl::OUString::createFromAscii(
        "com.sun.star.comp.uri.ExternalUriReferenceTranslator");
}

css::uno::Sequence< rtl::OUString > getSupportedServiceNames() {
    css::uno::Sequence< rtl::OUString > s(1);
    s[0] = rtl::OUString::createFromAscii(
        "com.sun.star.uri.ExternalUriReferenceTranslator");
    return s;
}

} }
<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2018 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

// ospcommon
#include "ospcommon/tasking/parallel_for.h"
#include "ospcommon/utility/StringManip.h"
// sg
#include "../common/Data.h"
#include "Generator.h"
// vtk
#include <vtkImageData.h>
#include <vtkRTAnalyticSource.h>
#include <vtkSmartPointer.h>

namespace ospray {
  namespace sg {

    void generateVTKWaveletVolume(const std::shared_ptr<Node> &world,
                                  const std::vector<string_pair> &params)
    {
      auto volume_node = createNode("wavelet", "StructuredVolume");

      // get generator parameters

      vec3i dims(256, 256, 256);

      for (auto &p : params) {
        if (p.first == "dimensions" || p.first == "dims") {
          auto string_dims = ospcommon::utility::split(p.second, 'x');
          if (string_dims.size() != 3) {
            std::cout << "WARNING: ignoring incorrect 'dimensions' parameter,"
                      << " it must be of the form 'dimensions=XxYxZ'"
                      << std::endl;
            continue;
          }

          dims = vec3i(std::atoi(string_dims[0].c_str()),
                       std::atoi(string_dims[1].c_str()),
                       std::atoi(string_dims[2].c_str()));
        } else {
          std::cout << "WARNING: unknown spheres generator parameter '"
                    << p.first << "' with value '" << p.second << "'"
                    << std::endl;
        }
      }

      // generate volume data

      std::cout << "...generating wavelet volume with dims=" << dims << "..."
                << std::endl;

      auto halfDims = dims / 2;

      vtkSmartPointer<vtkRTAnalyticSource> wavelet = vtkRTAnalyticSource::New();
      wavelet->SetWholeExtent(-halfDims.x, halfDims.x-1,
                              -halfDims.y, halfDims.y-1,
                              -halfDims.z, halfDims.z-1);

      wavelet->SetCenter(0, 0, 0);
      wavelet->SetMaximum(255);
      wavelet->SetStandardDeviation(.5);
      wavelet->SetXFreq(60);
      wavelet->SetYFreq(30);
      wavelet->SetZFreq(40);
      wavelet->SetXMag(10);
      wavelet->SetYMag(18);
      wavelet->SetZMag(5);
      wavelet->SetSubsampleRate(1);

      wavelet->Update();

      std::cout << "...data generated, now creating scene graph objects..."
                << std::endl;

      auto imageData = wavelet->GetOutput();

      // validate expected outputs

      std::string voxelType = imageData->GetScalarTypeAsString();

      if (voxelType != "float")
        throw std::runtime_error("wavelet not floats? got '" + voxelType + "'");

      auto dimentionality = imageData->GetDataDimension();

      if (dimentionality != 3)
        throw std::runtime_error("wavelet not 3 dimentional?");

      // import data into sg nodes

      dims = vec3i(imageData->GetDimensions()[0],
                   imageData->GetDimensions()[1],
                   imageData->GetDimensions()[2]);

      auto numVoxels = dims.product();

      auto *voxels_ptr = (float*)imageData->GetScalarPointer();

      auto voxel_data = std::make_shared<DataArray1f>(voxels_ptr, numVoxels);

      voxel_data->setName("voxelData");

      volume_node->add(voxel_data);

      // volume attributes

      volume_node->child("voxelType")  = voxelType;
      volume_node->child("dimensions") = dims;

      volume_node->createChild("stashed_vtk_source", "Node", wavelet);

      // add volume to world

      world->add(volume_node);

      std::cout << "...finished!" << std::endl;
    }

    OSPSG_REGISTER_GENERATE_FUNCTION(generateVTKWaveletVolume, vtkWavelet);

  }  // ::ospray::sg
}  // ::ospray
<commit_msg>run marching cubes on the wavelet using VTK if "isovalues" parameter given<commit_after>// ======================================================================== //
// Copyright 2009-2018 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

// ospcommon
#include "ospcommon/tasking/parallel_for.h"
#include "ospcommon/utility/StringManip.h"
// sg
#include "../common/Data.h"
#include "Generator.h"
// vtk
#include <vtkImageData.h>
#include <vtkMarchingCubes.h>
#include <vtkRTAnalyticSource.h>
#include <vtkSmartPointer.h>

namespace ospray {
  namespace sg {

    void generateVTKWaveletVolume(const std::shared_ptr<Node> &world,
                                  const std::vector<string_pair> &params)
    {
      auto volume_node = createNode("wavelet", "StructuredVolume");
      auto iso_node    = createNode("wavelet_isosurface", "TriangleMesh");

      // get generator parameters

      vec3i dims(256, 256, 256);
      std::vector<float> isoValues;

      for (auto &p : params) {
        if (p.first == "dimensions" || p.first == "dims") {
          auto string_dims = ospcommon::utility::split(p.second, 'x');
          if (string_dims.size() != 3) {
            std::cout << "WARNING: ignoring incorrect 'dimensions' parameter,"
                      << " it must be of the form 'dimensions=XxYxZ'"
                      << std::endl;
            continue;
          }

          dims = vec3i(std::atoi(string_dims[0].c_str()),
                       std::atoi(string_dims[1].c_str()),
                       std::atoi(string_dims[2].c_str()));
        } else if (p.first == "isosurfaces" || p.first == "isovalues") {
          auto string_isos = ospcommon::utility::split(p.second, '/');
          for (const auto &s : string_isos)
            isoValues.push_back(std::atof(s.c_str()));
        } else {
          std::cout << "WARNING: unknown wavelet generator parameter '"
                    << p.first << "' with value '" << p.second << "'"
                    << std::endl;
        }
      }

      bool computeIsosurface = !isoValues.empty();

      // generate volume data

      std::cout << "...generating wavelet volume with dims=" << dims << "..."
                << std::endl;

      auto halfDims = dims / 2;

      vtkSmartPointer<vtkRTAnalyticSource> wavelet = vtkRTAnalyticSource::New();
      wavelet->SetWholeExtent(-halfDims.x, halfDims.x-1,
                              -halfDims.y, halfDims.y-1,
                              -halfDims.z, halfDims.z-1);

      wavelet->SetCenter(0, 0, 0);
      wavelet->SetMaximum(255);
      wavelet->SetStandardDeviation(.5);
      wavelet->SetXFreq(60);
      wavelet->SetYFreq(30);
      wavelet->SetZFreq(40);
      wavelet->SetXMag(10);
      wavelet->SetYMag(18);
      wavelet->SetZMag(5);
      wavelet->SetSubsampleRate(1);

      wavelet->Update();

      auto imageData = wavelet->GetOutput();

      // generate isosurface

      vtkSmartPointer<vtkMarchingCubes> mc =
        vtkSmartPointer<vtkMarchingCubes>::New();

      if (computeIsosurface) {
        std::cout << "...creating isosurfaces with wavelet volume data..."
                  << std::endl;

        mc->SetInputConnection(wavelet->GetOutputPort());
        mc->ComputeNormalsOn();
        mc->ComputeGradientsOn();
        mc->SetNumberOfContours(int(isoValues.size()));

        for (int i = 0; i < int(isoValues.size()); ++i)
          mc->SetValue(i, isoValues[i]);

        mc->Update();
      }

      std::cout << "...data generated, now creating scene graph objects..."
                << std::endl;

      // validate expected outputs

      std::string voxelType = imageData->GetScalarTypeAsString();

      if (voxelType != "float")
        throw std::runtime_error("wavelet not floats? got '" + voxelType + "'");

      auto dimentionality = imageData->GetDataDimension();

      if (dimentionality != 3)
        throw std::runtime_error("wavelet not 3 dimentional?");

      if (computeIsosurface) {
        // import isosurface data into sg nodes
        auto polyData = mc->GetOutput();

        auto vertices =
              createNode("vertex", "DataVector3f")->nodeAs<DataVector3f>();
        auto indices =
              createNode("index", "DataVector3i")->nodeAs<DataVector3i>();

        int numberOfCells  = polyData->GetNumberOfCells();
        int numberOfPoints = polyData->GetNumberOfPoints();

        double point[3];
        for (int i = 0; i < numberOfPoints; i++) {
          polyData->GetPoint(i, point);
          vertices->push_back(vec3f(point[0], point[1], point[2]));
        }

        for (int i = 0; i < numberOfCells; i++) {
          vtkCell *cell = polyData->GetCell(i);

          if (cell->GetCellType() == VTK_TRIANGLE) {
            indices->push_back(vec3i(cell->GetPointId(0),
                                     cell->GetPointId(1),
                                     cell->GetPointId(2)));
          }
        }

        iso_node->add(vertices);
        iso_node->add(indices);

        // add isosurface to world
        world->add(iso_node);
      } else {
        // import volume data into sg nodes

        dims = vec3i(imageData->GetDimensions()[0],
                     imageData->GetDimensions()[1],
                     imageData->GetDimensions()[2]);

        auto numVoxels = dims.product();

        auto *voxels_ptr = (float*)imageData->GetScalarPointer();

        auto voxel_data = std::make_shared<DataArray1f>(voxels_ptr, numVoxels);

        voxel_data->setName("voxelData");

        volume_node->add(voxel_data);

        // volume attributes

        volume_node->child("voxelType")  = voxelType;
        volume_node->child("dimensions") = dims;

        volume_node->createChild("stashed_vtk_source", "Node", wavelet);

        // add volume to world
        world->add(volume_node);
      }

      std::cout << "...finished!" << std::endl;
    }

    OSPSG_REGISTER_GENERATE_FUNCTION(generateVTKWaveletVolume, vtkWavelet);

  }  // ::ospray::sg
}  // ::ospray
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: saldata.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: kz $ $Date: 2007-10-09 15:12:44 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"

#include "saldata.hxx"

// =======================================================================

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

void SalSetSalData( struct SalData* pData )
{
    SetSalData( pData );
}

// -----------------------------------------------------------------------

struct SalData* SalGetSalData()
{
    return GetSalData();
}

// -----------------------------------------------------------------------

struct SalData* SalGetAppSalData()
{
    return GetAppSalData();
}

// -----------------------------------------------------------------------

BOOL SalGetAppQuit()
{
    return ImplGetSVData()->maAppData.mbAppQuit;
}

#ifdef __cplusplus
}
#endif // __cplusplus

<commit_msg>INTEGRATION: CWS aquavcl04 (1.9.2); FILE MERGED 2007/11/27 11:24:01 pl 1.9.2.4: #i83820# an autorelease pool per yield level as suggested by documentation 2007/11/21 17:09:59 pl 1.9.2.3: #i83820# release pools per thread 2007/10/18 14:05:51 pl 1.9.2.2: #i77848# complete cursor mappings 2007/10/17 18:13:38 pl 1.9.2.1: #i77848# add cursor images<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: saldata.cxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: ihi $ $Date: 2008-01-14 16:15:21 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"

#include "saldata.hxx"

oslThreadKey SalData::s_aAutoReleaseKey = 0;

static void SAL_CALL releasePool( void* pPool )
{
    if( pPool )
        [(NSAutoreleasePool*)pPool release];
}

SalData::SalData()
:
    mpTimerProc( NULL ),
    mpFirstInstance( NULL ),
    mpFirstObject( NULL ),
    mpFirstVD( NULL ),
    mpFirstPrinter( NULL ),
    mpFontList( NULL ),
    mxRGBSpace( CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB) ),
    mxGraySpace( CGColorSpaceCreateWithName(kCGColorSpaceGenericGray) ),
    maCursors( POINTER_COUNT, INVALID_CURSOR_PTR ),
    mbIsScrollbarDoubleMax( false )
{
    if( s_aAutoReleaseKey == 0 )
        s_aAutoReleaseKey = osl_createThreadKey( releasePool );
}

SalData::~SalData()
{
    CFRelease( mxRGBSpace );
    CFRelease( mxGraySpace );
    for( unsigned int i = 0; i < maCursors.size(); i++ )
    {
        NSCursor* pCurs = maCursors[i];
        if( pCurs && pCurs != INVALID_CURSOR_PTR )
            [pCurs release];
    }
    if( s_aAutoReleaseKey )
    {
        // release the last pool
        NSAutoreleasePool* pPool = nil;
        pPool = reinterpret_cast<NSAutoreleasePool*>( osl_getThreadKeyData( s_aAutoReleaseKey ) );
        if( pPool )
        {
            osl_setThreadKeyData( s_aAutoReleaseKey, NULL );
            [pPool release];
        }

        osl_destroyThreadKey( s_aAutoReleaseKey );
        s_aAutoReleaseKey = NULL;
    }
}

void SalData::ensureThreadAutoreleasePool()
{
    NSAutoreleasePool* pPool = nil;
    if( s_aAutoReleaseKey )
    {
        pPool = reinterpret_cast<NSAutoreleasePool*>( osl_getThreadKeyData( s_aAutoReleaseKey ) );
        if( ! pPool )
        {
            pPool = [[NSAutoreleasePool alloc] init];
            osl_setThreadKeyData( s_aAutoReleaseKey, pPool );
        }
    }
    else
    {
        DBG_ERROR( "no autorelease key" );
    }
}

void SalData::drainThreadAutoreleasePool()
{
    NSAutoreleasePool* pPool = nil;
    if( s_aAutoReleaseKey )
    {
        pPool = reinterpret_cast<NSAutoreleasePool*>( osl_getThreadKeyData( s_aAutoReleaseKey ) );
        if( pPool )
        {
            // osl_setThreadKeyData( s_aAutoReleaseKey, NULL );
            // [pPool release];
            [pPool drain];
        }
        else
        {
            pPool = [[NSAutoreleasePool alloc] init];
            osl_setThreadKeyData( s_aAutoReleaseKey, pPool );
        }
    }
    else
    {
        DBG_ERROR( "no autorelease key" );
    }
}

struct curs_ent
{
    const char*         pBaseName;
    const NSPoint       aHotSpot;
}
const aCursorTab[ POINTER_COUNT ] =
{
{ NULL, { 0, 0 } }, //POINTER_ARROW
{ "nullptr", { 16, 16 } }, //POINTER_NULL
{ "hourglass", { 15, 15 } }, //POINTER_WAIT
{ NULL, { 0, 0 } }, //POINTER_TEXT
{ "help", { 0, 0 } }, //POINTER_HELP
{ NULL, { 0, 0 } }, //POINTER_CROSS
{ NULL, { 0, 0 } }, //POINTER_MOVE
{ NULL, { 0, 0 } }, //POINTER_NSIZE
{ NULL, { 0, 0 } }, //POINTER_SSIZE
{ NULL, { 0, 0 } }, //POINTER_WSIZE
{ NULL, { 0, 0 } }, //POINTER_ESIZE
{ "nwsesize", { 15, 15 } }, //POINTER_NWSIZE
{ "neswsize", { 15, 15 } }, //POINTER_NESIZE
{ "neswsize", { 15, 15 } }, //POINTER_SWSIZE
{ "nwsesize", { 15, 15 } }, //POINTER_SESIZE
{ NULL, { 0, 0 } }, //POINTER_WINDOW_NSIZE
{ NULL, { 0, 0 } }, //POINTER_WINDOW_SSIZE
{ NULL, { 0, 0 } }, //POINTER_WINDOW_WSIZE
{ NULL, { 0, 0 } }, //POINTER_WINDOW_ESIZE
{ "nwsesize", { 15, 15 } }, //POINTER_WINDOW_NWSIZE
{ "neswsize", { 15, 15 } }, //POINTER_WINDOW_NESIZE
{ "neswsize", { 15, 15 } }, //POINTER_WINDOW_SWSIZE
{ "nwsesize", { 15, 15 } }, //POINTER_WINDOW_SESIZE
{ NULL, { 0, 0 } }, //POINTER_HSPLIT
{ NULL, { 0, 0 } }, //POINTER_VSPLIT
{ NULL, { 0, 0 } }, //POINTER_HSIZEBAR
{ NULL, { 0, 0 } }, //POINTER_VSIZEBAR
{ NULL, { 0, 0 } }, //POINTER_HAND
{ NULL, { 0, 0 } }, //POINTER_REFHAND
{ "pen", { 3, 27 } }, //POINTER_PEN
{ "magnify", { 12, 13 } }, //POINTER_MAGNIFY
{ "fill", { 10, 22 } }, //POINTER_FILL
{ "rotate", { 15, 15 } }, //POINTER_ROTATE
{ "hshear", { 15, 15 } }, //POINTER_HSHEAR
{ "vshear", { 15, 15 } }, //POINTER_VSHEAR
{ "mirror", { 14, 12 } }, //POINTER_MIRROR
{ "crook", { 15, 14 } }, //POINTER_CROOK
{ "crop", { 9, 9 } }, //POINTER_CROP
{ "movept", { 0, 0 } }, //POINTER_MOVEPOINT
{ "movebw", { 0, 0 } }, //POINTER_MOVEBEZIERWEIGHT
{ "movedata", { 0, 0 } }, //POINTER_MOVEDATA
{ "copydata", { 0, 0 } }, //POINTER_COPYDATA
{ "linkdata", { 0, 0 } }, //POINTER_LINKDATA
{ "movedlnk", { 0, 0 } }, //POINTER_MOVEDATALINK
{ "copydlnk", { 0, 0 } }, //POINTER_COPYDATALINK
{ "movef", { 8, 8 } }, //POINTER_MOVEFILE
{ "copyf", { 8, 8 } }, //POINTER_COPYFILE
{ "linkf", { 8, 8 } }, //POINTER_LINKFILE
{ "moveflnk", { 8, 8 } }, //POINTER_MOVEFILELINK
{ "copyflnk", { 8, 8 } }, //POINTER_COPYFILELINK
{ "movef2", { 7, 8 } }, //POINTER_MOVEFILES
{ "copyf2", { 7, 8 } }, //POINTER_COPYFILES
{ "notallow", { 15, 15 } }, //POINTER_NOTALLOWED
{ "dline", { 8, 8 } }, //POINTER_DRAW_LINE
{ "drect", { 8, 8 } }, //POINTER_DRAW_RECT
{ "dpolygon", { 8, 8 } }, //POINTER_DRAW_POLYGON
{ "dbezier", { 8, 8 } }, //POINTER_DRAW_BEZIER
{ "darc", { 8, 8 } }, //POINTER_DRAW_ARC
{ "dpie", { 8, 8 } }, //POINTER_DRAW_PIE
{ "dcirccut", { 8, 8 } }, //POINTER_DRAW_CIRCLECUT
{ "dellipse", { 8, 8 } }, //POINTER_DRAW_ELLIPSE
{ "dfree", { 8, 8 } }, //POINTER_DRAW_FREEHAND
{ "dconnect", { 8, 8 } }, //POINTER_DRAW_CONNECT
{ "dtext", { 8, 8 } }, //POINTER_DRAW_TEXT
{ "dcapt", { 8, 8 } }, //POINTER_DRAW_CAPTION
{ "chart", { 15, 16 } }, //POINTER_CHART
{ "detectiv", { 12, 13 } }, //POINTER_DETECTIVE
{ "pivotcol", { 7, 5 } }, //POINTER_PIVOT_COL
{ "pivotrow", { 8, 7 } }, //POINTER_PIVOT_ROW
{ "pivotfld", { 8, 7 } }, //POINTER_PIVOT_FIELD
{ "chain", { 0, 2 } }, //POINTER_CHAIN
{ "chainnot", { 2, 2 } }, //POINTER_CHAIN_NOTALLOWED
{ "timemove", { 16, 16 } }, //POINTER_TIMEEVENT_MOVE
{ "timesize", { 16, 17 } }, //POINTER_TIMEEVENT_SIZE
{ "asn", { 16, 12 } }, //POINTER_AUTOSCROLL_N
{ "ass", { 15, 19 } }, //POINTER_AUTOSCROLL_S
{ "asw", { 12, 15 } }, //POINTER_AUTOSCROLL_W
{ "ase", { 19, 16 } }, //POINTER_AUTOSCROLL_E
{ "asnw", { 10, 10 } }, //POINTER_AUTOSCROLL_NW
{ "asne", { 21, 10 } }, //POINTER_AUTOSCROLL_NE
{ "assw", { 21, 21 } }, //POINTER_AUTOSCROLL_SW
{ "asse", { 21, 21 } }, //POINTER_AUTOSCROLL_SE
{ "asns", { 15, 15 } }, //POINTER_AUTOSCROLL_NS
{ "aswe", { 15, 15 } }, //POINTER_AUTOSCROLL_WE
{ "asnswe", { 15, 15 } }, //POINTER_AUTOSCROLL_NSWE
{ "airbrush", { 5, 22 } }, //POINTER_AIRBRUSH
{ "vtext", { 15, 15 } }, //POINTER_TEXT_VERTICAL
{ "pivotdel", { 18, 15 } }, //POINTER_PIVOT_DELETE
{ "tblsels", { 15, 30 } }, //POINTER_TAB_SELECT_S
{ "tblsele", { 30, 16 } }, //POINTER_TAB_SELECT_E
{ "tblselse", { 30, 30 } }, //POINTER_TAB_SELECT_SE
{ "tblselw", { 1, 16 } }, //POINTER_TAB_SELECT_W
{ "tblselsw", { 1, 30 } }, //POINTER_TAB_SELECT_SW
{ "pntbrsh", { 9, 16 } }  //POINTER_PAINTBRUSH
};

NSCursor* SalData::getCursor( PointerStyle i_eStyle )
{
    if( i_eStyle >= POINTER_COUNT )
        return nil;

    NSCursor* pCurs = maCursors[ i_eStyle ];
    if( pCurs == INVALID_CURSOR_PTR )
    {
        pCurs = nil;
        if( aCursorTab[ i_eStyle ].pBaseName )
        {
            NSPoint aHotSpot = aCursorTab[ i_eStyle ].aHotSpot;
            CFStringRef pCursorName =
                CFStringCreateWithCStringNoCopy(
                    kCFAllocatorDefault,
                    aCursorTab[ i_eStyle ].pBaseName,
                    kCFStringEncodingASCII,
                    kCFAllocatorNull );
            CFBundleRef hMain = CFBundleGetMainBundle();
            CFURLRef hURL = CFBundleCopyResourceURL( hMain, pCursorName, CFSTR("png"), CFSTR("cursors") );
            if( hURL )
            {
                pCurs = [[NSCursor alloc] initWithImage: [[NSImage alloc] initWithContentsOfURL: (NSURL*)hURL] hotSpot: aHotSpot];
                CFRelease( hURL );
            }
            CFRelease( pCursorName );
        }
        maCursors[ i_eStyle ] = pCurs;
    }
    return pCurs;
}
<|endoftext|>


<commit_before>/* vi:set ts=8 sts=8 sw=8:
 *
 * Practical Music Search
 * Copyright (c) 2006-2011  Kim Tore Jensen
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "console.h"
#include "curses.h"
#include <stdarg.h>
#include <stdio.h>
#include <string>
#include <vector>

using namespace std;

vector<string> logbuffer;
extern Curses curses;

void console_log(int level, const char * format, ...)
{
	va_list		ap;
	char		buffer[1024];

	va_start(ap, format);
	vsprintf(buffer, format, ap);
	va_end(ap);

	logbuffer.push_back(buffer);
	if (level <= MSG_LEVEL_INFO)
	{
		curses.wipe(&curses.statusbar);
		curses.print(&curses.statusbar, 0, 0, buffer);
		curses.draw();
	}
}
<commit_msg>Window-based statusbar management.<commit_after>/* vi:set ts=8 sts=8 sw=8:
 *
 * Practical Music Search
 * Copyright (c) 2006-2011  Kim Tore Jensen
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "console.h"
#include "window.h"
#include "curses.h"
#include <stdarg.h>
#include <stdio.h>
#include <string>
#include <vector>

using namespace std;

vector<string> logbuffer;
extern Curses curses;
extern Windowmanager wm;

void console_log(int level, const char * format, ...)
{
	va_list		ap;
	char		buffer[1024];

	va_start(ap, format);
	vsprintf(buffer, format, ap);
	va_end(ap);

	logbuffer.push_back(buffer);
	if (level <= MSG_LEVEL_INFO)
	{
		wm.statusbar->draw();
		curses.draw(); // instant status updates
	}
}
<|endoftext|>


<commit_before>// truncate.cpp: test suite runner for truncation functions trunc, round, floor, and ceil
//
// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc.
//
// This file is part of the universal numbers project, which is released under an MIT Open Source license.
#include <universal/utility/directives.hpp>
// use default number system library configuration
#include <universal/number/cfloat/cfloat.hpp>
#include <universal/verification/cfloat_math_test_suite.hpp>

template<typename TestType>
int VerifyFloor(bool reportTestCases) {
	using namespace sw::universal;
	constexpr size_t nbits = TestType::nbits;
	constexpr size_t NR_VALUES = (1ull << nbits);
	int nrOfFailedTestCases = 0;

	TestType a;
	for (size_t i = 0; i < NR_VALUES; ++i) {
		a.setbits(i);
		auto l1 = floor(a);
		// generate the reference
		float f = float(a);
		auto l2 = std::floor(f);
		if (l1 != l2) {             // TODO: fix float to int64 comparison
			++nrOfFailedTestCases;
			if (reportTestCases) ReportOneInputFunctionError("floor", "floor", a, TestType(l1), TestType(l2));
		}
	}
	return nrOfFailedTestCases;
}

template<typename TestType>
int VerifyCeil(bool reportTestCases) {
	using namespace sw::universal;
	constexpr size_t nbits = TestType::nbits;
	constexpr size_t NR_VALUES = (1ull << nbits);
	int nrOfFailedTestCases = 0;

	TestType a;
	for (size_t i = 0; i < NR_VALUES; ++i) {
		a.setbits(i);
		auto l1 = ceil(a);
		// generate the reference
		float f = float(a);
		auto l2 = std::ceil(f);
		if (l1 != l2) {             // TODO: fix float to int64 comparison
			++nrOfFailedTestCases;
			if (reportTestCases) ReportOneInputFunctionError("ceil", "ceil", a, TestType(l1), TestType(l2));
		}
	}
	return nrOfFailedTestCases;
}

#define MANUAL_TESTING 1

int main()
try {
	using namespace sw::universal;

	std::string test_suite  = "cfloat<> mathlib truncation validation";
	std::string test_tag    = "truncation";
	bool reportTestCases    = false;
	int nrOfFailedTestCases = 0;

	std::cout << test_suite << '\n';

#if MANUAL_TESTING
	// generate individual testcases to hand trace/debug

	nrOfFailedTestCases = ReportTestResult(VerifyFloor< cfloat<8, 2, uint8_t> >(reportTestCases), "floor", "cfloat<8,2>");
	nrOfFailedTestCases = ReportTestResult(VerifyCeil < cfloat<8, 2, uint8_t> >(reportTestCases), "ceil ", "cfloat<8,2>");

	ReportTestSuiteResults(test_suite, nrOfFailedTestCases);
	return EXIT_SUCCESS;  // ignore failures in manual testing mode
#else

	// clang and gcc fail due to NaN != NaN relationship

	nrOfFailedTestCases = ReportTestResult(VerifyFloor< cfloat<8, 2, uint8_t> >(reportTestCases), "floor", "cfloat<8,2>");
	nrOfFailedTestCases = ReportTestResult(VerifyCeil < cfloat<8, 2, uint8_t> >(reportTestCases), "ceil ", "cfloat<8,2>");

	ReportTestSuiteResults(test_suite, nrOfFailedTestCases);
	return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS);

#endif  // MANUAL_TESTING
}
catch (char const* msg) {
	std::cerr << "Caught ad-hoc exception: " << msg << std::endl;
	return EXIT_FAILURE;
}
catch (const sw::universal::universal_arithmetic_exception& err) {
	std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (const sw::universal::universal_internal_exception& err) {
	std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (const std::runtime_error& err) {
	std::cerr << "Caught runtime exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (...) {
	std::cerr << "Caught unknown exception" << std::endl;
	return EXIT_FAILURE;
}
<commit_msg>filtering out NaN cases for floor/ceil: debug and release builds behave differently<commit_after>// truncate.cpp: test suite runner for truncation functions trunc, round, floor, and ceil
//
// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc.
//
// This file is part of the universal numbers project, which is released under an MIT Open Source license.
#include <universal/utility/directives.hpp>
// use default number system library configuration
#include <universal/number/cfloat/cfloat.hpp>
#include <universal/verification/cfloat_math_test_suite.hpp>

template<typename TestType>
int VerifyFloor(bool reportTestCases) {
	using namespace sw::universal;
	constexpr size_t nbits = TestType::nbits;
	constexpr size_t NR_VALUES = (1ull << nbits);
	int nrOfFailedTestCases = 0;

	TestType a;
	for (size_t i = 0; i < NR_VALUES; ++i) {
		a.setbits(i);
		TestType l1 = floor(a);
		// generate the reference
		float f = float(a);         // we can stay with floats as the state space NR_VALUES is always going to be small to be practical (nbits < 16)
		float l2 = std::floor(f);
		if (l1 != l2) {
			if (a.isnan() || l1.isnan()) continue;
			std::cout << to_binary(a) << " : " << a << '\n';
//			std::cout << to_binary(l1) << " : " << l1 << '\n';
			std::cout << "floor(" << f << ") = " << l2 << " vs result " << l1 << '\n';
			++nrOfFailedTestCases;
			if (reportTestCases) ReportOneInputFunctionError("floor", "floor", a, TestType(l1), TestType(l2));
		}
	}
	return nrOfFailedTestCases;
}

template<typename TestType>
int VerifyCeil(bool reportTestCases) {
	using namespace sw::universal;
	constexpr size_t nbits = TestType::nbits;
	constexpr size_t NR_VALUES = (1ull << nbits);
	int nrOfFailedTestCases = 0;

	TestType a;
	for (size_t i = 0; i < NR_VALUES; ++i) {
		a.setbits(i);
		TestType l1 = ceil(a);
		// generate the reference
		float f = float(a);
		float l2 = std::ceil(f);
		if (l1 != l2) {
			if (a.isnan() || l1.isnan()) continue;
			std::cout << to_binary(a) << " : " << a << '\n';
//			std::cout << to_binary(l1) << " : " << l1 << '\n';
			std::cout << "ceil(" << f << ") = " << l2 << " vs result " << l1 << '\n';
			++nrOfFailedTestCases;
			if (reportTestCases) ReportOneInputFunctionError("ceil", "ceil", a, TestType(l1), TestType(l2));
		}
	}
	return nrOfFailedTestCases;
}

#define MANUAL_TESTING 1

int main()
try {
	using namespace sw::universal;

	std::string test_suite  = "cfloat<> mathlib truncation validation";
	std::string test_tag    = "truncation";
	bool reportTestCases    = false;
	int nrOfFailedTestCases = 0;

	std::cout << test_suite << '\n';

#if MANUAL_TESTING
	// generate individual testcases to hand trace/debug

	nrOfFailedTestCases = ReportTestResult(VerifyFloor< cfloat<8, 2, uint8_t> >(reportTestCases), "floor", "cfloat<8,2>");
	nrOfFailedTestCases = ReportTestResult(VerifyCeil < cfloat<8, 2, uint8_t> >(reportTestCases), "ceil ", "cfloat<8,2>");

	ReportTestSuiteResults(test_suite, nrOfFailedTestCases);
	return EXIT_SUCCESS;  // ignore failures in manual testing mode
#else

	// clang and gcc fail due to NaN != NaN relationship

	nrOfFailedTestCases = ReportTestResult(VerifyFloor< cfloat<8, 2, uint8_t> >(reportTestCases), "floor", "cfloat<8,2>");
	nrOfFailedTestCases = ReportTestResult(VerifyCeil < cfloat<8, 2, uint8_t> >(reportTestCases), "ceil ", "cfloat<8,2>");

	ReportTestSuiteResults(test_suite, nrOfFailedTestCases);
	return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS);

#endif  // MANUAL_TESTING
}
catch (char const* msg) {
	std::cerr << "Caught ad-hoc exception: " << msg << std::endl;
	return EXIT_FAILURE;
}
catch (const sw::universal::universal_arithmetic_exception& err) {
	std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (const sw::universal::universal_internal_exception& err) {
	std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (const std::runtime_error& err) {
	std::cerr << "Caught runtime exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (...) {
	std::cerr << "Caught unknown exception" << std::endl;
	return EXIT_FAILURE;
}
<|endoftext|>


<commit_before>/* Copyright (c) 2020-2021 ARM Limited
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "blockdevice/internal/SFDP.h"

class TestSFDP : public testing::Test {
};

/**
 * Test if sfdp_iterate_next_largest_erase_type() returns the most
 * optimal erase type, whose erase size is as large as possible
 * while being compatible with both alignment and size requirements.
 */
TEST_F(TestSFDP, TestEraseTypeAlgorithm)
{
    // Erase 104KB starting at 92KB
    int address = 92 * 1024;
    int size = 104 * 1024;
    int region = 1;
    int type;

    // The mock flash supports 4KB, 32KB and 64KB erase types
    struct mbed::sfdp_smptbl_info smptbl;
    smptbl.erase_type_size_arr[0] = 4 * 1024;
    smptbl.erase_type_size_arr[1] = 32 * 1024;
    smptbl.erase_type_size_arr[2] = 64 * 1024;

    // The mock flash has three regions, with address ranges:
    // * 0 to 64KB - 1B
    // * 64KB to 256KB - 1B
    // * 256KB to 1024KB - 1B
    smptbl.region_high_boundary[0] = 64 * 1024 - 1;
    smptbl.region_high_boundary[1] = 256 * 1024 - 1;
    smptbl.region_high_boundary[2] = 1024 * 1024 - 1;

    // Bitfields indicating which regions support which erase types
    smptbl.region_erase_types_bitfld[0] = 0b0001;   // 4KB only
    smptbl.region_erase_types_bitfld[1] = 0b0111;   // 64KB, 32KB, 4KB
    smptbl.region_erase_types_bitfld[2] = 0b0110;   // 64KB, 32KB

    // Expected outcome:
    // * The starting position 92KB is 4KB-aligned
    // * The next position 96KB (92KB + 4KB) is 32KB-aligned
    // * The next position 128KB (96KB + 32KB) is 64KB-aligned
    // * At the final position 192KB (128KB + 64KB), we only
    //   have 4KB (104KB - 4KB - 32KB - 64KB) remaining to erase
    int expected_erase_KBs[] = {4, 32, 64, 4};

    for (int i = 0; i < sizeof(expected_erase_KBs) / sizeof(int); i++) {
        type = sfdp_iterate_next_largest_erase_type(
                    smptbl.region_erase_types_bitfld[region],
                    size,
                    address,
                    region,
                    smptbl);
        int erase_size = smptbl.erase_type_size_arr[type];
        EXPECT_EQ(erase_size, expected_erase_KBs[i] * 1024);
        address += erase_size;
        size -= erase_size;
    }

    EXPECT_EQ(size, 0); // All erased

    // Test unaligned erase
    // Region 2 only allows at least 32KB-aligned erases
    address = (512 + 16) * 1024;
    size = 64 * 1024;
    region = 2;
    type = sfdp_iterate_next_largest_erase_type(
                smptbl.region_erase_types_bitfld[region],
                size,
                address,
                region,
                smptbl);
    EXPECT_EQ(type, -1); // Invalid erase
}
<commit_msg>SFDP: Add unit tests for Sector Map Parameter Table parsing<commit_after>/* Copyright (c) 2020-2021 ARM Limited
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "blockdevice/internal/SFDP.h"

using ::testing::_;
using ::testing::MockFunction;
using ::testing::Return;

/**
 * The Sector Map Parameter Table of Cypress S25FS512S:
 * https://www.cypress.com/file/216376/download Table 71.
 */
static const mbed::bd_addr_t sector_map_start_addr = 0xD81000;

/**
 * Based on Cypress S25FS512S, modified to have one descriptor,
 * three regions for test purpose.
 */
static const uint8_t sector_map_single_descriptor[] {
    0xFF, 0x01, 0x02, 0xFF,     // header, highest region = 0x02
    0xF1, 0x7F, 0x00, 0x00,     // region 0
    0xF4, 0x7F, 0x03, 0x00,     // region 1
    0xF4, 0xFF, 0xFB, 0x03      // region 2
};

/**
 * Based on Cypress S25FS512S, modified to have one descriptor,
 * twelve regions for test purpose.
 */
static const uint8_t sector_map_single_descriptor_twelve_regions[] {
    0xFF, 0x01, 0x0B, 0xFF,     // header, highest region = 0x0B
    0xF1, 0x7F, 0x00, 0x00,     // region 0
    0xF4, 0x7F, 0x03, 0x00,     // region 1
    0xF4, 0xFF, 0xFB, 0x03,     // region 2
    0xF1, 0x7F, 0x00, 0x00,     // region 3
    0xF4, 0x7F, 0x03, 0x00,     // region 4
    0xF4, 0xFF, 0xFB, 0x03,     // region 5
    0xF1, 0x7F, 0x00, 0x00,     // region 6
    0xF4, 0x7F, 0x03, 0x00,     // region 7
    0xF4, 0xFF, 0xFB, 0x03,     // region 8
    0xF1, 0x7F, 0x00, 0x00,     // region 9
    0xF4, 0x7F, 0x03, 0x00,     // region 10
    0xF4, 0xFF, 0xFB, 0x03,     // region 11
};

class TestSFDP : public testing::Test {

public:
    mbed::Callback<int(mbed::bd_addr_t, void*, bd_size_t)> sfdp_reader_callback;

protected:
    TestSFDP() : sfdp_reader_callback(this, &TestSFDP::sfdp_reader) {};

    int sfdp_reader(mbed::bd_addr_t addr, void *buff, bd_size_t buff_size)
    {
        int mock_return = sfdp_reader_mock.Call(addr, buff, buff_size);
        if (mock_return != 0) {
            return mock_return;
        }

        memcpy(buff, sector_descriptors, sector_descriptors_size);
        return 0;
    };

    void set_sector_map_param_table(mbed::sfdp_smptbl_info &smptbl, const uint8_t *table, const size_t table_size)
    {
        smptbl.size = table_size;
        smptbl.addr = sector_map_start_addr;

        sector_descriptors = table;
        sector_descriptors_size = table_size;
    }

    MockFunction<int(mbed::bd_addr_t, void*, bd_size_t)> sfdp_reader_mock;
    const uint8_t *sector_descriptors;
    bd_size_t sector_descriptors_size;
};

/**
 * Utilities for conversions to bytes.
 */
namespace{
    auto operator "" _B(unsigned long long int size) {
        return size;
    }

    auto operator "" _KB(unsigned long long int size) {
        return size * 1024;
    }

    auto operator "" _MB(unsigned long long int size) {
        return size * 1024 * 1024;
    }
}

/**
 * Test if sfdp_iterate_next_largest_erase_type() returns the most
 * optimal erase type, whose erase size is as large as possible
 * while being compatible with both alignment and size requirements.
 */
TEST_F(TestSFDP, TestEraseTypeAlgorithm)
{
    // Erase 104KB starting at 92KB
    int address = 92 * 1024;
    int size = 104 * 1024;
    int region = 1;
    int type;

    // The mock flash supports 4KB, 32KB and 64KB erase types
    struct mbed::sfdp_smptbl_info smptbl;
    smptbl.erase_type_size_arr[0] = 4 * 1024;
    smptbl.erase_type_size_arr[1] = 32 * 1024;
    smptbl.erase_type_size_arr[2] = 64 * 1024;

    // The mock flash has three regions, with address ranges:
    // * 0 to 64KB - 1B
    // * 64KB to 256KB - 1B
    // * 256KB to 1024KB - 1B
    smptbl.region_high_boundary[0] = 64 * 1024 - 1;
    smptbl.region_high_boundary[1] = 256 * 1024 - 1;
    smptbl.region_high_boundary[2] = 1024 * 1024 - 1;

    // Bitfields indicating which regions support which erase types
    smptbl.region_erase_types_bitfld[0] = 0b0001;   // 4KB only
    smptbl.region_erase_types_bitfld[1] = 0b0111;   // 64KB, 32KB, 4KB
    smptbl.region_erase_types_bitfld[2] = 0b0110;   // 64KB, 32KB

    // Expected outcome:
    // * The starting position 92KB is 4KB-aligned
    // * The next position 96KB (92KB + 4KB) is 32KB-aligned
    // * The next position 128KB (96KB + 32KB) is 64KB-aligned
    // * At the final position 192KB (128KB + 64KB), we only
    //   have 4KB (104KB - 4KB - 32KB - 64KB) remaining to erase
    int expected_erase_KBs[] = {4, 32, 64, 4};

    for (int i = 0; i < sizeof(expected_erase_KBs) / sizeof(int); i++) {
        type = sfdp_iterate_next_largest_erase_type(
                    smptbl.region_erase_types_bitfld[region],
                    size,
                    address,
                    region,
                    smptbl);
        int erase_size = smptbl.erase_type_size_arr[type];
        EXPECT_EQ(erase_size, expected_erase_KBs[i] * 1024);
        address += erase_size;
        size -= erase_size;
    }

    EXPECT_EQ(size, 0); // All erased

    // Test unaligned erase
    // Region 2 only allows at least 32KB-aligned erases
    address = (512 + 16) * 1024;
    size = 64 * 1024;
    region = 2;
    type = sfdp_iterate_next_largest_erase_type(
                smptbl.region_erase_types_bitfld[region],
                size,
                address,
                region,
                smptbl);
    EXPECT_EQ(type, -1); // Invalid erase
}

/**
 * Test that sfdp_parse_sector_map_table() treats a whole flash
 * as one region if no sector map is available.
 */
TEST_F(TestSFDP, TestNoSectorMap)
{
    const bd_size_t device_size = 512_KB;

    mbed::sfdp_hdr_info header_info;
    header_info.smptbl.size = 0; // No Sector Map Table
    header_info.bptbl.device_size_bytes = device_size;

    // No need to read anything
    EXPECT_CALL(sfdp_reader_mock, Call(_, _, _)).Times(0);

    EXPECT_EQ(0, sfdp_parse_sector_map_table(sfdp_reader_callback, header_info));

    EXPECT_EQ(1, header_info.smptbl.region_cnt);
    EXPECT_EQ(device_size, header_info.smptbl.region_size[0]);
    EXPECT_EQ(device_size - 1, header_info.smptbl.region_high_boundary[0]);
}

/**
 * When a Sector Map Parameter Table has a single descriptor (i.e. non-configurable flash layout).
 */
TEST_F(TestSFDP, TestSingleSectorConfig)
{
    mbed::sfdp_hdr_info header_info;
    set_sector_map_param_table(header_info.smptbl, sector_map_single_descriptor, sizeof(sector_map_single_descriptor));

    EXPECT_CALL(sfdp_reader_mock, Call(sector_map_start_addr, _, sizeof(sector_map_single_descriptor)))
    .Times(1)
    .WillOnce(Return(0));

    EXPECT_EQ(0, sfdp_parse_sector_map_table(sfdp_reader_callback, header_info));

    // Three regions
    EXPECT_EQ(3, header_info.smptbl.region_cnt);

    // Region 0: erase type 1 (32KB erase)
    EXPECT_EQ(32_KB, header_info.smptbl.region_size[0]);
    EXPECT_EQ(32_KB - 1_B, header_info.smptbl.region_high_boundary[0]);
    EXPECT_EQ(1 << (1 - 1), header_info.smptbl.region_erase_types_bitfld[0]);

    // Region 1: erase type 3 (256KB erase which includes 32KB from Region 0)
    EXPECT_EQ(224_KB, header_info.smptbl.region_size[1]);
    EXPECT_EQ(256_KB - 1_B, header_info.smptbl.region_high_boundary[1]);
    EXPECT_EQ(1 << (3 - 1), header_info.smptbl.region_erase_types_bitfld[1]);

    // Region 2: erase type 3 (256KB erase)
    EXPECT_EQ(64_MB - 32_KB - 224_KB, header_info.smptbl.region_size[2]);
    EXPECT_EQ(64_MB - 1_B, header_info.smptbl.region_high_boundary[2]);
    EXPECT_EQ(1 << (3 - 1), header_info.smptbl.region_erase_types_bitfld[2]);
}

/**
 * When an SFDP reader fails to read data requested by sfdp_parse_sector_map_table().
 */
TEST_F(TestSFDP, TestSFDPReadFailure)
{
    mbed::sfdp_hdr_info header_info;
    set_sector_map_param_table(header_info.smptbl, sector_map_single_descriptor, sizeof(sector_map_single_descriptor));

    EXPECT_CALL(sfdp_reader_mock, Call(sector_map_start_addr, _, sizeof(sector_map_single_descriptor)))
    .Times(1)
    .WillOnce(Return(-1)); // Emulate read failure

    EXPECT_EQ(-1, sfdp_parse_sector_map_table(sfdp_reader_callback, header_info));
}

/**
 * When a flash layout has more regions than Mbed OS supports (10).
 * Note: This is unlikely to happens in practice.
 */
TEST_F(TestSFDP, TestMoreRegionsThanSupported)
{
    mbed::sfdp_hdr_info header_info;
    set_sector_map_param_table(
        header_info.smptbl,
        sector_map_single_descriptor_twelve_regions,
        sizeof(sector_map_single_descriptor_twelve_regions)
    );

    EXPECT_CALL(sfdp_reader_mock, Call(sector_map_start_addr, _, sizeof(sector_map_single_descriptor_twelve_regions)))
    .Times(1)
    .WillOnce(Return(0));

    EXPECT_EQ(-1, sfdp_parse_sector_map_table(sfdp_reader_callback, header_info));
}
<|endoftext|>