<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <swmodeltestbase.hxx>

#include <com/sun/star/awt/Gradient.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <rtl/byteseq.hxx>

#include <swmodule.hxx>
#include <swdll.hxx>
#include <usrpref.hxx>

#include <test/htmltesttools.hxx>

using namespace rtl;

class HtmlExportTest : public SwModelTestBase, public HtmlTestTools
{
private:
    FieldUnit m_eUnit;

public:
    HtmlExportTest() :
        SwModelTestBase("/sw/qa/extras/htmlexport/data/", "HTML (StarWriter)"),
        m_eUnit(FUNIT_NONE)
    {}

private:
    bool mustCalcLayoutOf(const char* filename) SAL_OVERRIDE
    {
        return OString(filename) != "fdo62336.docx";
    }

    bool mustTestImportOf(const char* filename) const SAL_OVERRIDE
    {
        return OString(filename) != "fdo62336.docx";
    }

    void preTest(const char* filename) SAL_OVERRIDE
    {
        if (getTestName().indexOf("SkipImage") != -1)
            setFilterOptions("SkipImages");
        else
            setFilterOptions("");

        if (OString(filename) == "charborder.odt")
        {
            // FIXME if padding-top gets exported as inches, not cms, we get rounding errors.
            SwGlobals::ensure(); // make sure that SW_MOD() is not 0
            SwMasterUsrPref* pPref = const_cast<SwMasterUsrPref*>(SW_MOD()->GetUsrPref(false));
            m_eUnit = pPref->GetMetric();
            pPref->SetMetric(FUNIT_CM);
        }
    }

    void postTest(const char* filename) SAL_OVERRIDE
    {
        if (OString(filename) == "charborder.odt")
        {
            SwMasterUsrPref* pPref = const_cast<SwMasterUsrPref*>(SW_MOD()->GetUsrPref(false));
            pPref->SetMetric(m_eUnit);
        }
    }
};

#define DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, HtmlExportTest)

DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(testFdo81276, "fdo81276.html")
{
    uno::Reference<container::XNameAccess> xPageStyles(getStyles("PageStyles"));
    uno::Reference<beans::XPropertySet> xStyle(xPageStyles->getByName("HTML"), uno::UNO_QUERY);
    // some rounding going on here?
    CPPUNIT_ASSERT(abs(sal_Int32(29700) - getProperty<sal_Int32>(xStyle, "Width")) < 10);
    CPPUNIT_ASSERT(abs(sal_Int32(21006) - getProperty<sal_Int32>(xStyle, "Height")) < 10);
    CPPUNIT_ASSERT(abs(sal_Int32(500) - getProperty<sal_Int32>(xStyle, "LeftMargin")) < 10);
    CPPUNIT_ASSERT(abs(sal_Int32(500) - getProperty<sal_Int32>(xStyle, "RightMargin")) < 10);
    CPPUNIT_ASSERT(abs(sal_Int32(2000) - getProperty<sal_Int32>(xStyle, "TopMargin")) < 10);
    CPPUNIT_ASSERT(abs(sal_Int32(500) - getProperty<sal_Int32>(xStyle, "BottomMargin")) < 10);
}

DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(testFdo62336, "fdo62336.docx")
{
    // The problem was essentially a crash during table export as docx/rtf/html
    // If either of no-calc-layout or no-test-import is enabled, the crash does not occur
}

DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(testCharacterBorder, "charborder.odt")
{

    uno::Reference<beans::XPropertySet> xRun(getRun(getParagraph(1),1), uno::UNO_QUERY);
    // Different Border
    {
        CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0x6666FF,12,12,12,3,37), getProperty<table::BorderLine2>(xRun,"CharTopBorder"));
        CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0xFF9900,0,99,0,2,99), getProperty<table::BorderLine2>(xRun,"CharLeftBorder"));
        CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0xFF0000,0,169,0,1,169), getProperty<table::BorderLine2>(xRun,"CharBottomBorder"));
        CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0x0000FF,0,169,0,0,169), getProperty<table::BorderLine2>(xRun,"CharRightBorder"));
    }

    // Different Padding
    {
        CPPUNIT_ASSERT_EQUAL(sal_Int32(450), getProperty<sal_Int32>(xRun,"CharTopBorderDistance"));
        CPPUNIT_ASSERT_EQUAL(sal_Int32(550), getProperty<sal_Int32>(xRun,"CharLeftBorderDistance"));
        CPPUNIT_ASSERT_EQUAL(sal_Int32(150), getProperty<sal_Int32>(xRun,"CharBottomBorderDistance"));
        CPPUNIT_ASSERT_EQUAL(sal_Int32(250), getProperty<sal_Int32>(xRun,"CharRightBorderDistance"));
    }

    // No shadow
}

#define DECLARE_HTMLEXPORT_TEST(TestName, filename) DECLARE_SW_EXPORT_TEST(TestName, filename, HtmlExportTest)

DECLARE_HTMLEXPORT_TEST(testExportOfImages, "textAndImage.docx")
{
    htmlDocPtr pDoc = parseHtml(maTempFile);
    CPPUNIT_ASSERT(pDoc);

    assertXPath(pDoc, "/html/body", 1);
    assertXPath(pDoc, "/html/body/p/img", 1);
}

DECLARE_HTMLEXPORT_TEST(testExportOfImagesWithSkipImageEnabled, "textAndImage.docx")
{
    htmlDocPtr pDoc = parseHtml(maTempFile);
    CPPUNIT_ASSERT(pDoc);

    assertXPath(pDoc, "/html/body", 1);
    assertXPath(pDoc, "/html/body/p/img", 0);
}

DECLARE_HTMLEXPORT_TEST(testSkipImageEmbedded, "skipimage-embedded.doc")
{
    // Embedded spreadsheet was exported as image, so content was lost. Make
    // sure it's exported as HTML instead.
    htmlDocPtr pDoc = parseHtml(maTempFile);
    CPPUNIT_ASSERT(pDoc);

    // This was 0.
    assertXPath(pDoc, "//table", 1);
    // This was 2, the HTML header was in the document two times.
    assertXPath(pDoc, "//meta[@name='generator']", 1);
    // This was 0, <table> was directly under <p>, which caused errors in the parser.
    assertXPath(pDoc, "//span/table", 1);
}

DECLARE_HTMLEXPORT_TEST(testSkipImageEmbeddedDocument, "skipimage-embedded-document.docx")
{
    // Similar to testSkipImageEmbedded, but with an embedded Writer object,
    // not a Calc one, and this time OOXML, not WW8.
    htmlDocPtr pDoc = parseHtml(maTempFile);
    CPPUNIT_ASSERT(pDoc);

    // This was 2, the HTML header was in the document two times.
    assertXPath(pDoc, "//meta[@name='generator']", 1);
    // Text of embedded document was missing.
    assertXPathContent(pDoc, "/html/body/p/span/p/span", "Inner.");
}

DECLARE_HTMLEXPORT_TEST(testExportImageProperties, "HTMLImage.odt")
{
    htmlDocPtr pDoc = parseHtml(maTempFile);
    CPPUNIT_ASSERT(pDoc);

    assertXPath(pDoc, "/html/body", 1);

    assertXPath(pDoc, "/html/body/p/map/area", "shape", "poly");
    assertXPath(pDoc, "/html/body/p/map/area", "href", "http://www.microsoft.com/");
    assertXPath(pDoc, "/html/body/p/map/area", "target", "_self");
    assertXPath(pDoc, "/html/body/p/map/area", "alt", "microsoft");

    assertXPath(pDoc, "/html/body/p/a", 1);
    assertXPath(pDoc, "/html/body/p/a", "href", "http://www.google.com/");

    assertXPath(pDoc, "/html/body/p/a/font", 1);
    assertXPath(pDoc, "/html/body/p/a/font", "color", "#ff0000");

    assertXPath(pDoc, "/html/body/p/a/font/img", 1);
    assertXPath(pDoc, "/html/body/p/a/font/img", "name", "Text");
    assertXPath(pDoc, "/html/body/p/a/font/img", "alt", "Four colors");
    assertXPath(pDoc, "/html/body/p/a/font/img", "align", "middle");
#ifndef MACOSX // For some reason the hspace is "28" on OSX - disable this check for now
    assertXPath(pDoc, "/html/body/p/a/font/img", "hspace", "38");
    assertXPath(pDoc, "/html/body/p/a/font/img", "vspace", "19");
    assertXPath(pDoc, "/html/body/p/a/font/img", "width", "222");
    assertXPath(pDoc, "/html/body/p/a/font/img", "height", "222");
#endif
    assertXPath(pDoc, "/html/body/p/a/font/img", "border", "3");
    assertXPath(pDoc, "/html/body/p/a/font/img", "usemap", "#map1");
}

CPPUNIT_PLUGIN_IMPLEMENT();

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Disable HTML any check which uses twip->pixel conversion on OSX<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <swmodeltestbase.hxx>

#include <com/sun/star/awt/Gradient.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <rtl/byteseq.hxx>

#include <swmodule.hxx>
#include <swdll.hxx>
#include <usrpref.hxx>

#include <test/htmltesttools.hxx>

using namespace rtl;

class HtmlExportTest : public SwModelTestBase, public HtmlTestTools
{
private:
    FieldUnit m_eUnit;

public:
    HtmlExportTest() :
        SwModelTestBase("/sw/qa/extras/htmlexport/data/", "HTML (StarWriter)"),
        m_eUnit(FUNIT_NONE)
    {}

private:
    bool mustCalcLayoutOf(const char* filename) SAL_OVERRIDE
    {
        return OString(filename) != "fdo62336.docx";
    }

    bool mustTestImportOf(const char* filename) const SAL_OVERRIDE
    {
        return OString(filename) != "fdo62336.docx";
    }

    void preTest(const char* filename) SAL_OVERRIDE
    {
        if (getTestName().indexOf("SkipImage") != -1)
            setFilterOptions("SkipImages");
        else
            setFilterOptions("");

        if (OString(filename) == "charborder.odt")
        {
            // FIXME if padding-top gets exported as inches, not cms, we get rounding errors.
            SwGlobals::ensure(); // make sure that SW_MOD() is not 0
            SwMasterUsrPref* pPref = const_cast<SwMasterUsrPref*>(SW_MOD()->GetUsrPref(false));
            m_eUnit = pPref->GetMetric();
            pPref->SetMetric(FUNIT_CM);
        }
    }

    void postTest(const char* filename) SAL_OVERRIDE
    {
        if (OString(filename) == "charborder.odt")
        {
            SwMasterUsrPref* pPref = const_cast<SwMasterUsrPref*>(SW_MOD()->GetUsrPref(false));
            pPref->SetMetric(m_eUnit);
        }
    }
};

#define DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, HtmlExportTest)

DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(testFdo81276, "fdo81276.html")
{
    uno::Reference<container::XNameAccess> xPageStyles(getStyles("PageStyles"));
    uno::Reference<beans::XPropertySet> xStyle(xPageStyles->getByName("HTML"), uno::UNO_QUERY);
    // some rounding going on here?
    CPPUNIT_ASSERT(abs(sal_Int32(29700) - getProperty<sal_Int32>(xStyle, "Width")) < 10);
    CPPUNIT_ASSERT(abs(sal_Int32(21006) - getProperty<sal_Int32>(xStyle, "Height")) < 10);
    CPPUNIT_ASSERT(abs(sal_Int32(500) - getProperty<sal_Int32>(xStyle, "LeftMargin")) < 10);
    CPPUNIT_ASSERT(abs(sal_Int32(500) - getProperty<sal_Int32>(xStyle, "RightMargin")) < 10);
    CPPUNIT_ASSERT(abs(sal_Int32(2000) - getProperty<sal_Int32>(xStyle, "TopMargin")) < 10);
    CPPUNIT_ASSERT(abs(sal_Int32(500) - getProperty<sal_Int32>(xStyle, "BottomMargin")) < 10);
}

DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(testFdo62336, "fdo62336.docx")
{
    // The problem was essentially a crash during table export as docx/rtf/html
    // If either of no-calc-layout or no-test-import is enabled, the crash does not occur
}

DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(testCharacterBorder, "charborder.odt")
{

    uno::Reference<beans::XPropertySet> xRun(getRun(getParagraph(1),1), uno::UNO_QUERY);
    // Different Border
    {
        CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0x6666FF,12,12,12,3,37), getProperty<table::BorderLine2>(xRun,"CharTopBorder"));
        CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0xFF9900,0,99,0,2,99), getProperty<table::BorderLine2>(xRun,"CharLeftBorder"));
        CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0xFF0000,0,169,0,1,169), getProperty<table::BorderLine2>(xRun,"CharBottomBorder"));
        CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0x0000FF,0,169,0,0,169), getProperty<table::BorderLine2>(xRun,"CharRightBorder"));
    }

    // Different Padding
    {
        CPPUNIT_ASSERT_EQUAL(sal_Int32(450), getProperty<sal_Int32>(xRun,"CharTopBorderDistance"));
        CPPUNIT_ASSERT_EQUAL(sal_Int32(550), getProperty<sal_Int32>(xRun,"CharLeftBorderDistance"));
        CPPUNIT_ASSERT_EQUAL(sal_Int32(150), getProperty<sal_Int32>(xRun,"CharBottomBorderDistance"));
        CPPUNIT_ASSERT_EQUAL(sal_Int32(250), getProperty<sal_Int32>(xRun,"CharRightBorderDistance"));
    }

    // No shadow
}

#define DECLARE_HTMLEXPORT_TEST(TestName, filename) DECLARE_SW_EXPORT_TEST(TestName, filename, HtmlExportTest)

DECLARE_HTMLEXPORT_TEST(testExportOfImages, "textAndImage.docx")
{
    htmlDocPtr pDoc = parseHtml(maTempFile);
    CPPUNIT_ASSERT(pDoc);

    assertXPath(pDoc, "/html/body", 1);
    assertXPath(pDoc, "/html/body/p/img", 1);
}

DECLARE_HTMLEXPORT_TEST(testExportOfImagesWithSkipImageEnabled, "textAndImage.docx")
{
    htmlDocPtr pDoc = parseHtml(maTempFile);
    CPPUNIT_ASSERT(pDoc);

    assertXPath(pDoc, "/html/body", 1);
    assertXPath(pDoc, "/html/body/p/img", 0);
}

DECLARE_HTMLEXPORT_TEST(testSkipImageEmbedded, "skipimage-embedded.doc")
{
    // Embedded spreadsheet was exported as image, so content was lost. Make
    // sure it's exported as HTML instead.
    htmlDocPtr pDoc = parseHtml(maTempFile);
    CPPUNIT_ASSERT(pDoc);

    // This was 0.
    assertXPath(pDoc, "//table", 1);
    // This was 2, the HTML header was in the document two times.
    assertXPath(pDoc, "//meta[@name='generator']", 1);
    // This was 0, <table> was directly under <p>, which caused errors in the parser.
    assertXPath(pDoc, "//span/table", 1);
}

DECLARE_HTMLEXPORT_TEST(testSkipImageEmbeddedDocument, "skipimage-embedded-document.docx")
{
    // Similar to testSkipImageEmbedded, but with an embedded Writer object,
    // not a Calc one, and this time OOXML, not WW8.
    htmlDocPtr pDoc = parseHtml(maTempFile);
    CPPUNIT_ASSERT(pDoc);

    // This was 2, the HTML header was in the document two times.
    assertXPath(pDoc, "//meta[@name='generator']", 1);
    // Text of embedded document was missing.
    assertXPathContent(pDoc, "/html/body/p/span/p/span", "Inner.");
}

DECLARE_HTMLEXPORT_TEST(testExportImageProperties, "HTMLImage.odt")
{
    htmlDocPtr pDoc = parseHtml(maTempFile);
    CPPUNIT_ASSERT(pDoc);

    assertXPath(pDoc, "/html/body", 1);

    assertXPath(pDoc, "/html/body/p/map/area", "shape", "poly");
    assertXPath(pDoc, "/html/body/p/map/area", "href", "http://www.microsoft.com/");
    assertXPath(pDoc, "/html/body/p/map/area", "target", "_self");
    assertXPath(pDoc, "/html/body/p/map/area", "alt", "microsoft");

    assertXPath(pDoc, "/html/body/p/a", 1);
    assertXPath(pDoc, "/html/body/p/a", "href", "http://www.google.com/");

    assertXPath(pDoc, "/html/body/p/a/font", 1);
    assertXPath(pDoc, "/html/body/p/a/font", "color", "#ff0000");

    assertXPath(pDoc, "/html/body/p/a/font/img", 1);
    assertXPath(pDoc, "/html/body/p/a/font/img", "name", "Text");
    assertXPath(pDoc, "/html/body/p/a/font/img", "alt", "Four colors");
    assertXPath(pDoc, "/html/body/p/a/font/img", "align", "middle");

    // Probably the DPI in OSX is different and Twip -> Pixel conversion produces
    // different results - so disable OSX for now.
    //
    // It would make sense to switch to use CSS and use "real world" units instead
    // i.e. (style="margin: 0cm 1.5cm; width: 1cm; height: 1cm")
#ifndef MACOSX
    assertXPath(pDoc, "/html/body/p/a/font/img", "hspace", "38");
    assertXPath(pDoc, "/html/body/p/a/font/img", "vspace", "19");
    assertXPath(pDoc, "/html/body/p/a/font/img", "width", "222");
    assertXPath(pDoc, "/html/body/p/a/font/img", "height", "222");
    assertXPath(pDoc, "/html/body/p/a/font/img", "border", "3");
#endif
    assertXPath(pDoc, "/html/body/p/a/font/img", "usemap", "#map1");
}

CPPUNIT_PLUGIN_IMPLEMENT();

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2022 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "RFC.hxx"
#include "Document.hxx"
#include "Internal.hxx"
#include "strmap.hxx"
#include "ResourceAddress.hxx"
#include "io/Logger.hxx"
#include "http/Date.hxx"
#include "http/PHeaderUtil.hxx"
#include "http/PList.hxx"
#include "util/StringView.hxx"
#include "util/IterableSplitString.hxx"
#include "AllocatorPtr.hxx"

#include <stdlib.h>

/* check whether the request could produce a cacheable response */
std::optional<HttpCacheRequestInfo>
http_cache_request_evaluate(http_method_t method,
			    const ResourceAddress &address,
			    const StringMap &headers,
			    bool obey_no_cache,
			    bool has_request_body) noexcept
{
	if (method != HTTP_METHOD_GET || has_request_body)
		/* RFC 2616 13.11 "Write-Through Mandatory" */
		return std::nullopt;

	if (headers.Contains("range"))
		return std::nullopt;

	/* RFC 2616 14.8: "When a shared cache receives a request
	   containing an Authorization field, it MUST NOT return the
	   corresponding response as a reply to any other request
	   [...] */
	if (headers.Get("authorization") != nullptr)
		return std::nullopt;

	bool only_if_cached = false;

	if (const char *cache_control = headers.Get("cache-control")) {
		for (auto s : IterableSplitString(cache_control, ',')) {
			s.Strip();

			if (obey_no_cache &&
			    (s.Equals("no-cache") || s.Equals("no-store")))
				return std::nullopt;

			if (s.Equals("only-if-cached"))
				only_if_cached = true;
		}
	} else if (obey_no_cache) {
		if (const char *pragma = headers.Get("pragma");
		    pragma != nullptr && strcmp(pragma, "no-cache") == 0)
			return std::nullopt;
	}

	HttpCacheRequestInfo info;
	info.is_remote = address.type == ResourceAddress::Type::HTTP;
	info.only_if_cached = only_if_cached;
	info.has_query_string = address.HasQueryString();

	info.if_match = headers.Get("if-match");
	info.if_none_match = headers.Get("if-none-match");
	info.if_modified_since = headers.Get("if-modified-since");
	info.if_unmodified_since = headers.Get("if-unmodified-since");

	return info;
}

bool
http_cache_vary_fits(const StringMap &vary, const StringMap &headers) noexcept
{
	for (const auto &i : vary) {
		const char *value = headers.Get(i.key);
		if (value == nullptr)
			value = "";

		if (strcmp(i.value, value) != 0)
			/* mismatch in one of the "Vary" request headers */
			return false;
	}

	return true;
}

bool
http_cache_vary_fits(const StringMap *vary, const StringMap &headers) noexcept
{
	return vary == nullptr || http_cache_vary_fits(*vary, headers);
}

bool
http_cache_request_invalidate(http_method_t method) noexcept
{
	/* RFC 2616 13.10 "Invalidation After Updates or Deletions" */
	return method == HTTP_METHOD_PUT || method == HTTP_METHOD_DELETE ||
		method == HTTP_METHOD_POST;
}

[[gnu::pure]]
static std::chrono::system_clock::time_point
parse_translate_time(const char *p,
		     std::chrono::system_clock::duration offset) noexcept
{
	if (p == nullptr)
		return std::chrono::system_clock::from_time_t(-1);

	auto t = http_date_parse(p);
	if (t != std::chrono::system_clock::from_time_t(-1))
		t += offset;

	return t;
}

/**
 * RFC 2616 13.4
 */
static constexpr bool
http_status_cacheable(http_status_t status) noexcept
{
	return status == HTTP_STATUS_OK ||
		status == HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION ||
		status == HTTP_STATUS_PARTIAL_CONTENT ||
		status == HTTP_STATUS_MULTIPLE_CHOICES ||
		status == HTTP_STATUS_MOVED_PERMANENTLY ||
		status == HTTP_STATUS_GONE;
}

/**
 * Determine the difference between this host's real-time clock and
 * the server's clock.  This is used to adjust the "Expires" time
 * stamp.
 *
 * @return the difference or min() if the server did not send a valid
 * "Date" header
 */
[[gnu::pure]]
static std::chrono::system_clock::duration
GetServerDateOffset(const HttpCacheRequestInfo &request_info,
		    std::chrono::system_clock::time_point now,
		    const StringMap &response_headers) noexcept
{
	if (!request_info.is_remote)
		/* server is local (e.g. FastCGI); we don't need an offset */
		return std::chrono::system_clock::duration::zero();

	const auto server_date = GetServerDate(response_headers);
	if (server_date == std::chrono::system_clock::from_time_t(-1))
		return std::chrono::system_clock::duration::min();

	return now - server_date;
}

std::optional<HttpCacheResponseInfo>
http_cache_response_evaluate(const HttpCacheRequestInfo &request_info,
			     AllocatorPtr alloc,
			     bool eager_cache,
			     http_status_t status, const StringMap &headers,
			     off_t body_available) noexcept
{
	if (!http_status_cacheable(status))
		return std::nullopt;

	if (body_available != (off_t)-1 && body_available > cacheable_size_limit)
		/* too large for the cache */
		return std::nullopt;

	HttpCacheResponseInfo info;
	info.expires = std::chrono::system_clock::from_time_t(-1);
	if (const char *cache_control = headers.Get("cache-control")) {
		for (auto s : IterableSplitString(cache_control, ',')) {
			s.Strip();

			if (s.StartsWith("private") ||
			    s.Equals("no-cache") || s.Equals("no-store"))
				return std::nullopt;

			if (s.StartsWith("max-age=")) {
				/* RFC 2616 14.9.3 */
				char value[16];
				int seconds;

				StringView param(s.data + 8, s.size - 8);
				if (param.size >= sizeof(value))
					continue;

				memcpy(value, param.data, param.size);
				value[param.size] = 0;

				seconds = atoi(value);
				if (seconds > 0)
					info.expires = std::chrono::system_clock::now() + std::chrono::seconds(seconds);
			}
		}
	}

	const auto now = std::chrono::system_clock::now();

	const auto offset = GetServerDateOffset(request_info, now, headers);
	if (offset == std::chrono::system_clock::duration::min())
		/* we cannot determine whether to cache a resource if the
		   server does not provide its system time */
		return std::nullopt;

	if (info.expires == std::chrono::system_clock::from_time_t(-1)) {
		/* RFC 2616 14.9.3: "If a response includes both an Expires
		   header and a max-age directive, the max-age directive
		   overrides the Expires header" */

		info.expires = parse_translate_time(headers.Get("expires"), offset);
		if (info.expires != std::chrono::system_clock::from_time_t(-1) &&
		    info.expires < now)
			LogConcat(4, "HttpCache", "invalid 'expires' header");
	}

	if (request_info.has_query_string &&
	    !eager_cache &&
	    info.expires == std::chrono::system_clock::from_time_t(-1))
		/* RFC 2616 13.9: "since some applications have traditionally
		   used GETs and HEADs with query URLs (those containing a "?"
		   in the rel_path part) to perform operations with
		   significant side effects, caches MUST NOT treat responses
		   to such URIs as fresh unless the server provides an
		   explicit expiration time" */
		return std::nullopt;

	info.last_modified = headers.Get("last-modified");
	info.etag = headers.Get("etag");

	info.vary = nullptr;
	const auto vary = headers.EqualRange("vary");
	for (auto i = vary.first; i != vary.second; ++i) {
		const char *value = i->value;
		if (*value == 0)
			continue;

		if (strcmp(value, "*") == 0)
			/* RFC 2616 13.6: A Vary header field-value of
			   "*" always fails to match and subsequent
			   requests on that resource can only be
			   properly interpreted by the origin
			   server. */
			return std::nullopt;

		if (info.vary == nullptr)
			info.vary = value;
		else
			info.vary = alloc.Concat(info.vary, ", ", value);
	}

	if (info.expires == std::chrono::system_clock::from_time_t(-1) &&
	    info.last_modified == nullptr &&
	    info.etag == nullptr) {
		if (eager_cache)
			// TODO
			info.expires = std::chrono::system_clock::now() + std::chrono::hours(1);
		else
			return std::nullopt;
	}

	return info;
}

void
http_cache_copy_vary(StringMap &dest, AllocatorPtr alloc, const char *vary,
		     const StringMap &request_headers) noexcept
{
	for (const char *const*list = http_list_split(alloc, vary);
	     *list != nullptr; ++list) {
		const char *name = *list;
		const char *value = request_headers.Get(name);
		if (value == nullptr)
			value = "";
		else
			value = alloc.Dup(value);
		dest.Set(alloc, name, value);
	}
}

bool
http_cache_prefer_cached(const HttpCacheDocument &document,
			 const StringMap &response_headers) noexcept
{
	if (document.info.etag == nullptr)
		return false;

	const char *etag = response_headers.Get("etag");

	/* if the ETags are the same, then the resource hasn't changed,
	   but the server was too lazy to check that properly */
	return etag != nullptr && strcmp(etag, document.info.etag) == 0;
}
<commit_msg>http/cache/RFC: use std::string_view<commit_after>/*
 * Copyright 2007-2022 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "RFC.hxx"
#include "Document.hxx"
#include "Internal.hxx"
#include "strmap.hxx"
#include "ResourceAddress.hxx"
#include "io/Logger.hxx"
#include "http/Date.hxx"
#include "http/PHeaderUtil.hxx"
#include "http/PList.hxx"
#include "util/IterableSplitString.hxx"
#include "util/StringCompare.hxx"
#include "util/StringStrip.hxx"
#include "AllocatorPtr.hxx"

#include <stdlib.h>

using std::string_view_literals::operator""sv;

/* check whether the request could produce a cacheable response */
std::optional<HttpCacheRequestInfo>
http_cache_request_evaluate(http_method_t method,
			    const ResourceAddress &address,
			    const StringMap &headers,
			    bool obey_no_cache,
			    bool has_request_body) noexcept
{
	if (method != HTTP_METHOD_GET || has_request_body)
		/* RFC 2616 13.11 "Write-Through Mandatory" */
		return std::nullopt;

	if (headers.Contains("range"))
		return std::nullopt;

	/* RFC 2616 14.8: "When a shared cache receives a request
	   containing an Authorization field, it MUST NOT return the
	   corresponding response as a reply to any other request
	   [...] */
	if (headers.Get("authorization") != nullptr)
		return std::nullopt;

	bool only_if_cached = false;

	if (const char *cache_control = headers.Get("cache-control")) {
		for (std::string_view s : IterableSplitString(cache_control, ',')) {
			s = Strip(s);

			if (obey_no_cache &&
			    (s == "no-cache"sv || s == "no-store"sv))
				return std::nullopt;

			if (s == "only-if-cached"sv)
				only_if_cached = true;
		}
	} else if (obey_no_cache) {
		if (const char *pragma = headers.Get("pragma");
		    pragma != nullptr && strcmp(pragma, "no-cache") == 0)
			return std::nullopt;
	}

	HttpCacheRequestInfo info;
	info.is_remote = address.type == ResourceAddress::Type::HTTP;
	info.only_if_cached = only_if_cached;
	info.has_query_string = address.HasQueryString();

	info.if_match = headers.Get("if-match");
	info.if_none_match = headers.Get("if-none-match");
	info.if_modified_since = headers.Get("if-modified-since");
	info.if_unmodified_since = headers.Get("if-unmodified-since");

	return info;
}

bool
http_cache_vary_fits(const StringMap &vary, const StringMap &headers) noexcept
{
	for (const auto &i : vary) {
		const char *value = headers.Get(i.key);
		if (value == nullptr)
			value = "";

		if (strcmp(i.value, value) != 0)
			/* mismatch in one of the "Vary" request headers */
			return false;
	}

	return true;
}

bool
http_cache_vary_fits(const StringMap *vary, const StringMap &headers) noexcept
{
	return vary == nullptr || http_cache_vary_fits(*vary, headers);
}

bool
http_cache_request_invalidate(http_method_t method) noexcept
{
	/* RFC 2616 13.10 "Invalidation After Updates or Deletions" */
	return method == HTTP_METHOD_PUT || method == HTTP_METHOD_DELETE ||
		method == HTTP_METHOD_POST;
}

[[gnu::pure]]
static std::chrono::system_clock::time_point
parse_translate_time(const char *p,
		     std::chrono::system_clock::duration offset) noexcept
{
	if (p == nullptr)
		return std::chrono::system_clock::from_time_t(-1);

	auto t = http_date_parse(p);
	if (t != std::chrono::system_clock::from_time_t(-1))
		t += offset;

	return t;
}

/**
 * RFC 2616 13.4
 */
static constexpr bool
http_status_cacheable(http_status_t status) noexcept
{
	return status == HTTP_STATUS_OK ||
		status == HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION ||
		status == HTTP_STATUS_PARTIAL_CONTENT ||
		status == HTTP_STATUS_MULTIPLE_CHOICES ||
		status == HTTP_STATUS_MOVED_PERMANENTLY ||
		status == HTTP_STATUS_GONE;
}

/**
 * Determine the difference between this host's real-time clock and
 * the server's clock.  This is used to adjust the "Expires" time
 * stamp.
 *
 * @return the difference or min() if the server did not send a valid
 * "Date" header
 */
[[gnu::pure]]
static std::chrono::system_clock::duration
GetServerDateOffset(const HttpCacheRequestInfo &request_info,
		    std::chrono::system_clock::time_point now,
		    const StringMap &response_headers) noexcept
{
	if (!request_info.is_remote)
		/* server is local (e.g. FastCGI); we don't need an offset */
		return std::chrono::system_clock::duration::zero();

	const auto server_date = GetServerDate(response_headers);
	if (server_date == std::chrono::system_clock::from_time_t(-1))
		return std::chrono::system_clock::duration::min();

	return now - server_date;
}

std::optional<HttpCacheResponseInfo>
http_cache_response_evaluate(const HttpCacheRequestInfo &request_info,
			     AllocatorPtr alloc,
			     bool eager_cache,
			     http_status_t status, const StringMap &headers,
			     off_t body_available) noexcept
{
	if (!http_status_cacheable(status))
		return std::nullopt;

	if (body_available != (off_t)-1 && body_available > cacheable_size_limit)
		/* too large for the cache */
		return std::nullopt;

	HttpCacheResponseInfo info;
	info.expires = std::chrono::system_clock::from_time_t(-1);
	if (const char *cache_control = headers.Get("cache-control")) {
		for (std::string_view s : IterableSplitString(cache_control, ',')) {
			s = Strip(s);

			if (s.starts_with("private"sv) ||
			    s == "no-cache"sv || s == "no-store"sv)
				return std::nullopt;

			if (SkipPrefix(s, "max-age="sv)) {
				/* RFC 2616 14.9.3 */
				char value[16];
				int seconds;

				if (s.size() >= sizeof(value))
					continue;

				*std::copy(s.begin(), s.end(), value) = 0;

				seconds = atoi(value);
				if (seconds > 0)
					info.expires = std::chrono::system_clock::now() + std::chrono::seconds(seconds);
			}
		}
	}

	const auto now = std::chrono::system_clock::now();

	const auto offset = GetServerDateOffset(request_info, now, headers);
	if (offset == std::chrono::system_clock::duration::min())
		/* we cannot determine whether to cache a resource if the
		   server does not provide its system time */
		return std::nullopt;

	if (info.expires == std::chrono::system_clock::from_time_t(-1)) {
		/* RFC 2616 14.9.3: "If a response includes both an Expires
		   header and a max-age directive, the max-age directive
		   overrides the Expires header" */

		info.expires = parse_translate_time(headers.Get("expires"), offset);
		if (info.expires != std::chrono::system_clock::from_time_t(-1) &&
		    info.expires < now)
			LogConcat(4, "HttpCache", "invalid 'expires' header");
	}

	if (request_info.has_query_string &&
	    !eager_cache &&
	    info.expires == std::chrono::system_clock::from_time_t(-1))
		/* RFC 2616 13.9: "since some applications have traditionally
		   used GETs and HEADs with query URLs (those containing a "?"
		   in the rel_path part) to perform operations with
		   significant side effects, caches MUST NOT treat responses
		   to such URIs as fresh unless the server provides an
		   explicit expiration time" */
		return std::nullopt;

	info.last_modified = headers.Get("last-modified");
	info.etag = headers.Get("etag");

	info.vary = nullptr;
	const auto vary = headers.EqualRange("vary");
	for (auto i = vary.first; i != vary.second; ++i) {
		const char *value = i->value;
		if (*value == 0)
			continue;

		if (strcmp(value, "*") == 0)
			/* RFC 2616 13.6: A Vary header field-value of
			   "*" always fails to match and subsequent
			   requests on that resource can only be
			   properly interpreted by the origin
			   server. */
			return std::nullopt;

		if (info.vary == nullptr)
			info.vary = value;
		else
			info.vary = alloc.Concat(info.vary, ", ", value);
	}

	if (info.expires == std::chrono::system_clock::from_time_t(-1) &&
	    info.last_modified == nullptr &&
	    info.etag == nullptr) {
		if (eager_cache)
			// TODO
			info.expires = std::chrono::system_clock::now() + std::chrono::hours(1);
		else
			return std::nullopt;
	}

	return info;
}

void
http_cache_copy_vary(StringMap &dest, AllocatorPtr alloc, const char *vary,
		     const StringMap &request_headers) noexcept
{
	for (const char *const*list = http_list_split(alloc, vary);
	     *list != nullptr; ++list) {
		const char *name = *list;
		const char *value = request_headers.Get(name);
		if (value == nullptr)
			value = "";
		else
			value = alloc.Dup(value);
		dest.Set(alloc, name, value);
	}
}

bool
http_cache_prefer_cached(const HttpCacheDocument &document,
			 const StringMap &response_headers) noexcept
{
	if (document.info.etag == nullptr)
		return false;

	const char *etag = response_headers.Get("etag");

	/* if the ETags are the same, then the resource hasn't changed,
	   but the server was too lazy to check that properly */
	return etag != nullptr && strcmp(etag, document.info.etag) == 0;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: propertystatecontainer.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: hr $ $Date: 2004-08-02 17:51:02 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef COMPHELPER_PROPERTYSTATECONTAINER_HXX
#define COMPHELPER_PROPERTYSTATECONTAINER_HXX

#ifndef _COMPHELPER_PROPERTYCONTAINER_HXX_
#include <comphelper/propertycontainer.hxx>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSTATE_HPP_
#include <com/sun/star/beans/XPropertyState.hpp>
#endif
#ifndef _CPPUHELPER_IMPLBASE1_HXX_
#include <cppuhelper/implbase1.hxx>
#endif
#ifndef _COMPHELPER_UNO3_HXX_
#include <comphelper/uno3.hxx>
#endif
#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif

#include <map>

//.........................................................................
namespace comphelper
{
//.........................................................................

    //=====================================================================
    //= OPropertyStateContainer
    //=====================================================================
    typedef ::cppu::ImplHelper1 <   ::com::sun::star::beans::XPropertyState
                                >   OPropertyStateContainer_TBase;

    /** helper implementation for components which have properties with a default

This class is not intended for direct use, you need to derive from it.

        @see com.sun.star.beans.XPropertyState
    */
    class OPropertyStateContainer
                :public  OPropertyContainer
                ,public  OPropertyStateContainer_TBase
    {
    protected:
        /** ctor
            @param _rBHelper
                help to be used for broadcasting events
        */
        OPropertyStateContainer( ::cppu::OBroadcastHelper&  _rBHelper );

        // ................................................................
        // XPropertyState
        virtual ::com::sun::star::beans::PropertyState SAL_CALL getPropertyState( const ::rtl::OUString& PropertyName ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
        virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyState > SAL_CALL getPropertyStates( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aPropertyName ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
        virtual void SAL_CALL setPropertyToDefault( const ::rtl::OUString& PropertyName ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
        virtual ::com::sun::star::uno::Any SAL_CALL getPropertyDefault( const ::rtl::OUString& aPropertyName ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);

        // ................................................................
        // own overridables
        // these are the impl-methods for the XPropertyState members - they are implemented already by this class,
        // but you may want to override them for whatever reasons (for instance, if your derived class
        // supports the AMBIGUOUS state for properties)

        /** get the PropertyState of the property denoted by the given handle

Already implemented by this base class, no need to override

            @precond <arg>_nHandle</arg> is a valid property handle
        */
        virtual ::com::sun::star::beans::PropertyState  getPropertyStateByHandle( sal_Int32 _nHandle );

        /** set the property denoted by the given handle to it's default value

Already implemented by this base class, no need to override

            @precond <arg>_nHandle</arg> is a valid property handle
        */
        virtual void                                    setPropertyToDefaultByHandle( sal_Int32 _nHandle );

        /** get the default value for the property denoted by the given handle

Already implemented by this base class, no need to override

            @precond <arg>_nHandle</arg> is a valid property handle
        */
        virtual ::com::sun::star::uno::Any              getPropertyDefaultByHandle( sal_Int32 _nHandle ) const = 0;

    protected:
        // XInterface
        virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type& _rType ) throw (::com::sun::star::uno::RuntimeException);
        // XTypeProvider
        DECLARE_XTYPEPROVIDER( )

    protected:
        sal_Int32   getHandleForName( const ::rtl::OUString& _rPropertyName ) SAL_THROW( ( ::com::sun::star::beans::UnknownPropertyException ) );
    };

//.........................................................................
}   // namespace comphelper
//.........................................................................

#endif // COMPHELPER_PROPERTYSTATECONTAINER_HXX
<commit_msg>INTEGRATION: CWS visibility02 (1.2.54); FILE MERGED 2005/01/05 05:54:11 mnicel 1.2.54.1: Issue number: 38608 Part of symbol visibility work.<commit_after>/*************************************************************************
 *
 *  $RCSfile: propertystatecontainer.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: vg $ $Date: 2005-02-16 15:59:50 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef COMPHELPER_PROPERTYSTATECONTAINER_HXX
#define COMPHELPER_PROPERTYSTATECONTAINER_HXX

#ifndef _COMPHELPER_PROPERTYCONTAINER_HXX_
#include <comphelper/propertycontainer.hxx>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSTATE_HPP_
#include <com/sun/star/beans/XPropertyState.hpp>
#endif
#ifndef _CPPUHELPER_IMPLBASE1_HXX_
#include <cppuhelper/implbase1.hxx>
#endif
#ifndef _COMPHELPER_UNO3_HXX_
#include <comphelper/uno3.hxx>
#endif
#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif
#ifndef INCLUDED_COMPHELPERDLLAPI_H
#include "comphelper/comphelperdllapi.h"
#endif

#include <map>

//.........................................................................
namespace comphelper
{
//.........................................................................

    //=====================================================================
    //= OPropertyStateContainer
    //=====================================================================
    typedef ::cppu::ImplHelper1 <   ::com::sun::star::beans::XPropertyState
                                >   OPropertyStateContainer_TBase;

    /** helper implementation for components which have properties with a default

This class is not intended for direct use, you need to derive from it.

        @see com.sun.star.beans.XPropertyState
    */
    class COMPHELPER_DLLPUBLIC OPropertyStateContainer
                :public  OPropertyContainer
                ,public  OPropertyStateContainer_TBase
    {
    protected:
        /** ctor
            @param _rBHelper
                help to be used for broadcasting events
        */
        OPropertyStateContainer( ::cppu::OBroadcastHelper&  _rBHelper );

        // ................................................................
        // XPropertyState
        virtual ::com::sun::star::beans::PropertyState SAL_CALL getPropertyState( const ::rtl::OUString& PropertyName ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
        virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyState > SAL_CALL getPropertyStates( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aPropertyName ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
        virtual void SAL_CALL setPropertyToDefault( const ::rtl::OUString& PropertyName ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
        virtual ::com::sun::star::uno::Any SAL_CALL getPropertyDefault( const ::rtl::OUString& aPropertyName ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);

        // ................................................................
        // own overridables
        // these are the impl-methods for the XPropertyState members - they are implemented already by this class,
        // but you may want to override them for whatever reasons (for instance, if your derived class
        // supports the AMBIGUOUS state for properties)

        /** get the PropertyState of the property denoted by the given handle

Already implemented by this base class, no need to override

            @precond <arg>_nHandle</arg> is a valid property handle
        */
        virtual ::com::sun::star::beans::PropertyState  getPropertyStateByHandle( sal_Int32 _nHandle );

        /** set the property denoted by the given handle to it's default value

Already implemented by this base class, no need to override

            @precond <arg>_nHandle</arg> is a valid property handle
        */
        virtual void                                    setPropertyToDefaultByHandle( sal_Int32 _nHandle );

        /** get the default value for the property denoted by the given handle

Already implemented by this base class, no need to override

            @precond <arg>_nHandle</arg> is a valid property handle
        */
        virtual ::com::sun::star::uno::Any              getPropertyDefaultByHandle( sal_Int32 _nHandle ) const = 0;

    protected:
        // XInterface
        virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type& _rType ) throw (::com::sun::star::uno::RuntimeException);
        // XTypeProvider
        DECLARE_XTYPEPROVIDER( )

    protected:
        sal_Int32   getHandleForName( const ::rtl::OUString& _rPropertyName ) SAL_THROW( ( ::com::sun::star::beans::UnknownPropertyException ) );
    };

//.........................................................................
}   // namespace comphelper
//.........................................................................

#endif // COMPHELPER_PROPERTYSTATECONTAINER_HXX
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: defdescr.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: hr $ $Date: 2007-11-02 16:50:53 $
 *
 *  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
 *
 ************************************************************************/

#include <precomp.h>
#include "defdescr.hxx"

// NOT FULLY DEFINED SERVICES
#include <prprpr.hxx>

namespace cpp
{

DefineDescription::DefineDescription( const String  &       i_sName,
                                      const str_vector &    i_rDefinition )
    :   sName(i_sName),
        // aParams,
        aDefinition(i_rDefinition),
        eDefineType(type_define)
{
}

DefineDescription::DefineDescription( const String  &       i_sName,
                                      const str_vector &    i_rParams,
                                      const str_vector &    i_rDefinition )
    :   sName(i_sName),
        aParams(i_rParams),
        aDefinition(i_rDefinition),
        eDefineType(type_macro)
{
}

DefineDescription::~DefineDescription()
{
}

void
DefineDescription::GetDefineText( csv::StreamStr & o_rText ) const
{
    if ( aDefinition.begin() == aDefinition.end() OR eDefineType != type_define )
        return;

    bool bSwitch_Stringify = false;
    bool bSwitch_Concatenate = false;

    for ( str_vector::const_iterator it = aDefinition.begin();
          it != aDefinition.end();
          ++it )
    {
        if ( HandleOperatorsBeforeTextItem( o_rText,
                                            bSwitch_Stringify,
                                            bSwitch_Concatenate,
                                            *it ) )
        {
            continue;
        }

        o_rText << (*it);

        Do_bStringify_end(o_rText, bSwitch_Stringify);
        o_rText << " ";
    }
    o_rText.seekp(-1, csv::cur);
}

void
DefineDescription::GetMacroText( csv::StreamStr &               o_rText,
                                 const StringVector & i_rGivenArguments ) const
{
    bool bSwitch_Stringify = false;
    bool bSwitch_Concatenate = false;
    intt nActiveParamNr = -1;

    if ( aDefinition.begin() == aDefinition.end() OR eDefineType != type_macro )
        return;

    for ( str_vector::const_iterator it = aDefinition.begin();
          it != aDefinition.end();
          ++it )
    {
        if ( HandleOperatorsBeforeTextItem( o_rText,
                                            bSwitch_Stringify,
                                            bSwitch_Concatenate,
                                            *it ) )
        {
            continue;
        }

        for ( str_vector::const_iterator param_it = aParams.begin();
              param_it != aParams.end() AND nActiveParamNr == -1;
              ++param_it )
        {
             if ( strcmp(*it, *param_it) == 0 )
                nActiveParamNr = param_it - aParams.begin();
        }
        if ( nActiveParamNr == -1 )
        {
            o_rText << (*it);
        }
        else
        {
            o_rText << i_rGivenArguments[nActiveParamNr];
            nActiveParamNr = -1;
        }

        Do_bStringify_end(o_rText, bSwitch_Stringify);
        o_rText << " ";
    }
    o_rText.seekp(-1, csv::cur);
}

}   // end namespace cpp

bool
CheckForOperator( bool &              o_bStringify,
                  bool &              o_bConcatenate,
                  const String &      i_sTextItem )
{
    if ( strcmp(i_sTextItem, "##") == 0 )
    {
        o_bConcatenate = true;
        return true;
    }
    else if ( strcmp(i_sTextItem, "#") == 0 )
    {
        o_bStringify = true;
        return true;
    }
    return false;
}

void
Do_bConcatenate( csv::StreamStr &    o_rText,
                 bool &              io_bConcatenate )
{
    if ( io_bConcatenate )
    {
        uintt nPos;
        for ( nPos = o_rText.tellp() - 1;
              nPos > 0 ? o_rText.c_str()[nPos] == ' ' : false;
              --nPos );
        o_rText.seekp(nPos+1);
        io_bConcatenate = false;
    }
}

void
Do_bStringify_begin( csv::StreamStr & o_rText,
                     bool             i_bStringify )
{
    if ( i_bStringify )
    {
        o_rText << "\"";
    }
}

void
Do_bStringify_end( csv::StreamStr & o_rText,
                   bool &           io_bStringify )
{
    if ( io_bStringify )
    {
        o_rText << "\"";
        io_bStringify = false;
    }
}

bool
HandleOperatorsBeforeTextItem( csv::StreamStr &    o_rText,
                               bool &              io_bStringify,
                               bool &              io_bConcatenate,
                               const String  &     i_sTextItem )
{
    if ( CheckForOperator( io_bStringify,
                           io_bConcatenate,
                           i_sTextItem) )
    {
        return true;
    }
    Do_bConcatenate(o_rText, io_bConcatenate);
    Do_bStringify_begin(o_rText, io_bStringify);

    return false;
}

<commit_msg>INTEGRATION: CWS changefileheader (1.5.22); FILE MERGED 2008/03/28 16:02:23 rt 1.5.22.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: defdescr.cxx,v $
 * $Revision: 1.6 $
 *
 * 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.
 *
 ************************************************************************/

#include <precomp.h>
#include "defdescr.hxx"

// NOT FULLY DEFINED SERVICES
#include <prprpr.hxx>

namespace cpp
{

DefineDescription::DefineDescription( const String  &       i_sName,
                                      const str_vector &    i_rDefinition )
    :   sName(i_sName),
        // aParams,
        aDefinition(i_rDefinition),
        eDefineType(type_define)
{
}

DefineDescription::DefineDescription( const String  &       i_sName,
                                      const str_vector &    i_rParams,
                                      const str_vector &    i_rDefinition )
    :   sName(i_sName),
        aParams(i_rParams),
        aDefinition(i_rDefinition),
        eDefineType(type_macro)
{
}

DefineDescription::~DefineDescription()
{
}

void
DefineDescription::GetDefineText( csv::StreamStr & o_rText ) const
{
    if ( aDefinition.begin() == aDefinition.end() OR eDefineType != type_define )
        return;

    bool bSwitch_Stringify = false;
    bool bSwitch_Concatenate = false;

    for ( str_vector::const_iterator it = aDefinition.begin();
          it != aDefinition.end();
          ++it )
    {
        if ( HandleOperatorsBeforeTextItem( o_rText,
                                            bSwitch_Stringify,
                                            bSwitch_Concatenate,
                                            *it ) )
        {
            continue;
        }

        o_rText << (*it);

        Do_bStringify_end(o_rText, bSwitch_Stringify);
        o_rText << " ";
    }
    o_rText.seekp(-1, csv::cur);
}

void
DefineDescription::GetMacroText( csv::StreamStr &               o_rText,
                                 const StringVector & i_rGivenArguments ) const
{
    bool bSwitch_Stringify = false;
    bool bSwitch_Concatenate = false;
    intt nActiveParamNr = -1;

    if ( aDefinition.begin() == aDefinition.end() OR eDefineType != type_macro )
        return;

    for ( str_vector::const_iterator it = aDefinition.begin();
          it != aDefinition.end();
          ++it )
    {
        if ( HandleOperatorsBeforeTextItem( o_rText,
                                            bSwitch_Stringify,
                                            bSwitch_Concatenate,
                                            *it ) )
        {
            continue;
        }

        for ( str_vector::const_iterator param_it = aParams.begin();
              param_it != aParams.end() AND nActiveParamNr == -1;
              ++param_it )
        {
             if ( strcmp(*it, *param_it) == 0 )
                nActiveParamNr = param_it - aParams.begin();
        }
        if ( nActiveParamNr == -1 )
        {
            o_rText << (*it);
        }
        else
        {
            o_rText << i_rGivenArguments[nActiveParamNr];
            nActiveParamNr = -1;
        }

        Do_bStringify_end(o_rText, bSwitch_Stringify);
        o_rText << " ";
    }
    o_rText.seekp(-1, csv::cur);
}

}   // end namespace cpp

bool
CheckForOperator( bool &              o_bStringify,
                  bool &              o_bConcatenate,
                  const String &      i_sTextItem )
{
    if ( strcmp(i_sTextItem, "##") == 0 )
    {
        o_bConcatenate = true;
        return true;
    }
    else if ( strcmp(i_sTextItem, "#") == 0 )
    {
        o_bStringify = true;
        return true;
    }
    return false;
}

void
Do_bConcatenate( csv::StreamStr &    o_rText,
                 bool &              io_bConcatenate )
{
    if ( io_bConcatenate )
    {
        uintt nPos;
        for ( nPos = o_rText.tellp() - 1;
              nPos > 0 ? o_rText.c_str()[nPos] == ' ' : false;
              --nPos );
        o_rText.seekp(nPos+1);
        io_bConcatenate = false;
    }
}

void
Do_bStringify_begin( csv::StreamStr & o_rText,
                     bool             i_bStringify )
{
    if ( i_bStringify )
    {
        o_rText << "\"";
    }
}

void
Do_bStringify_end( csv::StreamStr & o_rText,
                   bool &           io_bStringify )
{
    if ( io_bStringify )
    {
        o_rText << "\"";
        io_bStringify = false;
    }
}

bool
HandleOperatorsBeforeTextItem( csv::StreamStr &    o_rText,
                               bool &              io_bStringify,
                               bool &              io_bConcatenate,
                               const String  &     i_sTextItem )
{
    if ( CheckForOperator( io_bStringify,
                           io_bConcatenate,
                           i_sTextItem) )
    {
        return true;
    }
    Do_bConcatenate(o_rText, io_bConcatenate);
    Do_bStringify_begin(o_rText, io_bStringify);

    return false;
}

<|endoftext|>


<commit_before>#include "forth_common.th"

// A little Forth.

.set link, 0
.global __zero
__zero:
__boot:
    S <- [reloc(_PSPinit)]
    R <- [reloc(_RSPinit)]
    I <- reloc(QUIT)        // enter text interpreter
    goto(NEXT)

    .global _PSPinit
    .global _RSPinit
_PSPinit:   .word   0x007fffff
_RSPinit:   .word   0x00ffffff

// TODO smudge internal words
head(RESET_RSP,RESET_RSP): .word . + 1
    R <- [reloc(_RSPinit)]
    goto(NEXT)

head(NEXT,NEXT):
    W  <- [I]
    W  <-  rel(W)
    I  <-  I + 1
    X  <- [W]
    jmp(X)

head(ENTER,ENTER):
    .word . + 1
    push(R,I)
    I  <- W + 1
    goto(NEXT)

head(EXIT,EXIT):
    .word . + 1
    pop(R,I)
    goto(NEXT)

    .global source_id
source_id: .word 0
head(SOURCE_ID,SOURCE-ID): .word
    @ENTER, @LITERAL, @source_id, @RELOC, @EXIT

    .global __done
__done:
    // return to caller of forth, abort, whatever is required
    //p <- reloc(__boot)
    illegal

<commit_msg>Drop interp-word pointer in ENTER<commit_after>#include "forth_common.th"

// A little Forth.

.set link, 0
.global __zero
__zero:
__boot:
    S <- [reloc(_PSPinit)]
    R <- [reloc(_RSPinit)]
    I <- reloc(QUIT)        // enter text interpreter
    goto(NEXT)

    .global _PSPinit
    .global _RSPinit
_PSPinit:   .word   0x007fffff
_RSPinit:   .word   0x00ffffff

// TODO smudge internal words
head(RESET_RSP,RESET_RSP): .word . + 1
    R <- [reloc(_RSPinit)]
    goto(NEXT)

head(NEXT,NEXT):
    W  <- [I]
    W  <-  rel(W)
    I  <-  I + 1
    X  <- [W]
    jmp(X)

head(ENTER,ENTER):
    // ENTER is special and does not have an interp-word entry
    push(R,I)
    I  <- W + 1
    goto(NEXT)

head(EXIT,EXIT):
    .word . + 1
    pop(R,I)
    goto(NEXT)

    .global source_id
source_id: .word 0
head(SOURCE_ID,SOURCE-ID): .word
    @ENTER, @LITERAL, @source_id, @RELOC, @EXIT

    .global __done
__done:
    // return to caller of forth, abort, whatever is required
    //p <- reloc(__boot)
    illegal

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: pe_tpltp.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: vg $ $Date: 2007-09-18 14:14:02 $
 *
 *  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
 *
 ************************************************************************/

#include <precomp.h>
#include "pe_tpltp.hxx"

// NOT FULLY DECLARED SERVICES
#include <cosv/template/tpltools.hxx>

namespace cpp {

PE_TemplateTop::PE_TemplateTop( Cpp_PE * i_pParent )
    :   Cpp_PE(i_pParent),
        pStati( new PeStatusArray<PE_TemplateTop> ),
        // aResult_Parameters,
        bCurIsConstant(false)
{
        Setup_StatusFunctions();
}

PE_TemplateTop::~PE_TemplateTop()
{
}

void
PE_TemplateTop::Call_Handler( const cpp::Token & i_rTok )
{
    pStati->Cur().Call_Handler(i_rTok.TypeId(), i_rTok.Text());
}

void
PE_TemplateTop::Setup_StatusFunctions()
{
    typedef CallFunction<PE_TemplateTop>::F_Tok F_Tok;

    static F_Tok stateF_start[] =           { &PE_TemplateTop::On_start_Less };
    static INT16 stateT_start[] =           { Tid_Less };

    static F_Tok stateF_expect_qualifier[]= { &PE_TemplateTop::On_expect_qualifier_ClassOrTypename,
                                              &PE_TemplateTop::On_expect_qualifier_ClassOrTypename };
    static INT16 stateT_expect_qualifier[]= { Tid_class,
                                              Tid_typename };

    static F_Tok stateF_expect_name[] =     { &PE_TemplateTop::On_expect_name_Identifier };
    static INT16 stateT_expect_name[] =     { Tid_Identifier };

    static F_Tok stateF_expect_separator[]= { &PE_TemplateTop::On_expect_separator_Comma,
                                              &PE_TemplateTop::On_expect_separator_Greater };
    static INT16 stateT_expect_separator[]= { Tid_Comma,
                                              Tid_Greater };

    SEMPARSE_CREATE_STATUS(PE_TemplateTop, start,            Hdl_SyntaxError);
    SEMPARSE_CREATE_STATUS(PE_TemplateTop, expect_qualifier, On_expect_qualifier_Other);
    SEMPARSE_CREATE_STATUS(PE_TemplateTop, expect_name,      Hdl_SyntaxError);
    SEMPARSE_CREATE_STATUS(PE_TemplateTop, expect_separator, Hdl_SyntaxError);
}

void
PE_TemplateTop::InitData()
{
    pStati->SetCur(start);
    csv::erase_container(aResult_Parameters);
    bCurIsConstant = false;
}

void
PE_TemplateTop::TransferData()
{
    pStati->SetCur(size_of_states);
}

void
PE_TemplateTop::Hdl_SyntaxError(const char * i_sText)
{
    StdHandlingOfSyntaxError(i_sText);
}

void
PE_TemplateTop::On_start_Less( const char *)
{
    SetTokenResult(done, stay);
    pStati->SetCur(expect_qualifier);
}

void
PE_TemplateTop::On_expect_qualifier_ClassOrTypename( const char *)
{
    SetTokenResult(done, stay);
    pStati->SetCur(expect_name);
}

void
PE_TemplateTop::On_expect_qualifier_Other( const char *)
{
    SetTokenResult(done, stay);
    pStati->SetCur(expect_name);

    bCurIsConstant = true;
}

void
PE_TemplateTop::On_expect_name_Identifier( const char * i_sText)
{
    SetTokenResult(done, stay);
    pStati->SetCur(expect_separator);

    StreamLock sl(50);
    if ( NOT bCurIsConstant )
    {
        String sText( sl() << "typename " << i_sText << c_str );
        aResult_Parameters.push_back(sText);
    }
    else //
    {
        String sText( sl() << "constant " << i_sText << c_str );
        aResult_Parameters.push_back(sText);
        bCurIsConstant = false;
    }  // endif
}

void
PE_TemplateTop::On_expect_separator_Comma( const char *)
{
    SetTokenResult(done, stay);
    pStati->SetCur(expect_qualifier);
}

void
PE_TemplateTop::On_expect_separator_Greater( const char *)
{
    SetTokenResult(done, pop_success);
}

}   // namespace cpp
<commit_msg>INTEGRATION: CWS adc18 (1.8.2); FILE MERGED 2007/10/18 15:23:18 np 1.8.2.1: #i81775#<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: pe_tpltp.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: hr $ $Date: 2007-11-02 16:57:02 $
 *
 *  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
 *
 ************************************************************************/

#include <precomp.h>
#include "pe_tpltp.hxx"

// NOT FULLY DECLARED SERVICES
#include <cosv/tpl/tpltools.hxx>

namespace cpp {

PE_TemplateTop::PE_TemplateTop( Cpp_PE * i_pParent )
    :   Cpp_PE(i_pParent),
        pStati( new PeStatusArray<PE_TemplateTop> ),
        // aResult_Parameters,
        bCurIsConstant(false)
{
        Setup_StatusFunctions();
}

PE_TemplateTop::~PE_TemplateTop()
{
}

void
PE_TemplateTop::Call_Handler( const cpp::Token & i_rTok )
{
    pStati->Cur().Call_Handler(i_rTok.TypeId(), i_rTok.Text());
}

void
PE_TemplateTop::Setup_StatusFunctions()
{
    typedef CallFunction<PE_TemplateTop>::F_Tok F_Tok;

    static F_Tok stateF_start[] =           { &PE_TemplateTop::On_start_Less };
    static INT16 stateT_start[] =           { Tid_Less };

    static F_Tok stateF_expect_qualifier[]= { &PE_TemplateTop::On_expect_qualifier_ClassOrTypename,
                                              &PE_TemplateTop::On_expect_qualifier_Greater,
                                              &PE_TemplateTop::On_expect_qualifier_ClassOrTypename };
    static INT16 stateT_expect_qualifier[]= { Tid_class,
                                              Tid_Greater,
                                              Tid_typename };

    static F_Tok stateF_expect_name[] =     { &PE_TemplateTop::On_expect_name_Identifier };
    static INT16 stateT_expect_name[] =     { Tid_Identifier };

    static F_Tok stateF_expect_separator[]= { &PE_TemplateTop::On_expect_separator_Comma,
                                              &PE_TemplateTop::On_expect_separator_Greater };
    static INT16 stateT_expect_separator[]= { Tid_Comma,
                                              Tid_Greater };

    SEMPARSE_CREATE_STATUS(PE_TemplateTop, start,            Hdl_SyntaxError);
    SEMPARSE_CREATE_STATUS(PE_TemplateTop, expect_qualifier, On_expect_qualifier_Other);
    SEMPARSE_CREATE_STATUS(PE_TemplateTop, expect_name,      Hdl_SyntaxError);
    SEMPARSE_CREATE_STATUS(PE_TemplateTop, expect_separator, Hdl_SyntaxError);
}

void
PE_TemplateTop::InitData()
{
    pStati->SetCur(start);
    csv::erase_container(aResult_Parameters);
    bCurIsConstant = false;
}

void
PE_TemplateTop::TransferData()
{
    pStati->SetCur(size_of_states);
}

void
PE_TemplateTop::Hdl_SyntaxError(const char * i_sText)
{
    StdHandlingOfSyntaxError(i_sText);
}

void
PE_TemplateTop::On_start_Less( const char *)
{
    SetTokenResult(done, stay);
    pStati->SetCur(expect_qualifier);
}

void
PE_TemplateTop::On_expect_qualifier_ClassOrTypename( const char *)
{
    SetTokenResult(done, stay);
    pStati->SetCur(expect_name);
}

void
PE_TemplateTop::On_expect_qualifier_Greater(const char *)
{
    SetTokenResult(done, pop_success);
}

void
PE_TemplateTop::On_expect_qualifier_Other( const char *)
{
    SetTokenResult(done, stay);
    pStati->SetCur(expect_name);

    bCurIsConstant = true;
}

void
PE_TemplateTop::On_expect_name_Identifier( const char * i_sText)
{
    SetTokenResult(done, stay);
    pStati->SetCur(expect_separator);

    StreamLock sl(50);
    if ( NOT bCurIsConstant )
    {
        String sText( sl() << "typename " << i_sText << c_str );
        aResult_Parameters.push_back(sText);
    }
    else //
    {
        String sText( sl() << "constant " << i_sText << c_str );
        aResult_Parameters.push_back(sText);
        bCurIsConstant = false;
    }  // endif
}

void
PE_TemplateTop::On_expect_separator_Comma( const char *)
{
    SetTokenResult(done, stay);
    pStati->SetCur(expect_qualifier);
}

void
PE_TemplateTop::On_expect_separator_Greater( const char *)
{
    SetTokenResult(done, pop_success);
}

}   // namespace cpp
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/renderer_host/p2p/socket_host_tcp.h"

#include "base/sys_byteorder.h"
#include "content/common/p2p_messages.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/socket/tcp_client_socket.h"

namespace {
const int kReadBufferSize = 4096;
const int kPacketHeaderSize = sizeof(uint16);
}  // namespace

namespace content {

P2PSocketHostTcp::P2PSocketHostTcp(IPC::Message::Sender* message_sender,
                                   int routing_id, int id)
    : P2PSocketHost(message_sender, routing_id, id),
      connected_(false) {
}

P2PSocketHostTcp::~P2PSocketHostTcp() {
  if (state_ == STATE_OPEN) {
    DCHECK(socket_.get());
    socket_.reset();
  }
}

bool P2PSocketHostTcp::InitAccepted(const net::IPEndPoint& remote_address,
                                    net::StreamSocket* socket) {
  DCHECK(socket);
  DCHECK_EQ(state_, STATE_UNINITIALIZED);

  remote_address_ = remote_address;
  socket_.reset(socket);
  state_ = STATE_OPEN;
  DoRead();
  return state_ != STATE_ERROR;
}

bool P2PSocketHostTcp::Init(const net::IPEndPoint& local_address,
                            const net::IPEndPoint& remote_address) {
  DCHECK_EQ(state_, STATE_UNINITIALIZED);

  remote_address_ = remote_address;
  state_ = STATE_CONNECTING;
  scoped_ptr<net::TCPClientSocket> tcp_socket(new net::TCPClientSocket(
      net::AddressList::CreateFromIPAddress(
          remote_address.address(), remote_address.port()),
      NULL, net::NetLog::Source()));
  if (tcp_socket->Bind(local_address) != net::OK) {
    OnError();
    return false;
  }
  socket_.reset(tcp_socket.release());

  if (socket_->SetSendBufferSize(kMaxSendBufferSize))
    LOG(WARNING) << "Failed to set send buffer size for TCP socket.";

  int result = socket_->Connect(
      base::Bind(&P2PSocketHostTcp::OnConnected, base::Unretained(this)));
  if (result != net::ERR_IO_PENDING) {
    OnConnected(result);
  }

  return state_ != STATE_ERROR;
}

void P2PSocketHostTcp::OnError() {
  socket_.reset();

  if (state_ == STATE_UNINITIALIZED || state_ == STATE_CONNECTING ||
      state_ == STATE_OPEN)
    message_sender_->Send(new P2PMsg_OnError(routing_id_, id_));

  state_ = STATE_ERROR;
}

void P2PSocketHostTcp::OnConnected(int result) {
  DCHECK_EQ(state_, STATE_CONNECTING);
  DCHECK_NE(result, net::ERR_IO_PENDING);

  if (result != net::OK) {
    OnError();
    return;
  }

  net::IPEndPoint address;
  result = socket_->GetLocalAddress(&address);
  if (result < 0) {
    LOG(ERROR) << "P2PSocket::Init(): unable to get local address: "
               << result;
    OnError();
    return;
  }

  VLOG(1) << "Local address: " << address.ToString();
  state_ = STATE_OPEN;
  message_sender_->Send(new P2PMsg_OnSocketCreated(routing_id_, id_, address));
  DoRead();
}

void P2PSocketHostTcp::DoRead() {
  int result;
  do {
    if (!read_buffer_) {
      read_buffer_ = new net::GrowableIOBuffer();
      read_buffer_->SetCapacity(kReadBufferSize);
    } else if (read_buffer_->RemainingCapacity() < kReadBufferSize) {
      // Make sure that we always have at least kReadBufferSize of
      // remaining capacity in the read buffer. Normally all packets
      // are smaller than kReadBufferSize, so this is not really
      // required.
      read_buffer_->SetCapacity(read_buffer_->capacity() + kReadBufferSize -
                                read_buffer_->RemainingCapacity());
    }
    result = socket_->Read(read_buffer_, read_buffer_->RemainingCapacity(),
                           base::Bind(&P2PSocketHostTcp::OnRead,
                                      base::Unretained(this)));
    DidCompleteRead(result);
  } while (result > 0);
}

void P2PSocketHostTcp::OnRead(int result) {
  DidCompleteRead(result);
  if (state_ == STATE_OPEN) {
    DoRead();
  }
}

void P2PSocketHostTcp::OnPacket(std::vector<char>& data) {
  if (!connected_) {
    P2PSocketHost::StunMessageType type;
    bool stun = GetStunPacketType(&*data.begin(), data.size(), &type);
    if (stun && IsRequestOrResponse(type)) {
      connected_ = true;
    } else if (!stun || type == STUN_DATA_INDICATION) {
      LOG(ERROR) << "Received unexpected data packet from "
                 << remote_address_.ToString()
                 << " before STUN binding is finished. "
                 << "Terminating connection.";
      OnError();
      return;
    }
  }

  message_sender_->Send(new P2PMsg_OnDataReceived(routing_id_, id_,
                                                  remote_address_, data));
}

void P2PSocketHostTcp::DidCompleteRead(int result) {
  DCHECK_EQ(state_, STATE_OPEN);

  if (result == net::ERR_IO_PENDING) {
    return;
  } else if (result < 0){
    LOG(ERROR) << "Error when reading from TCP socket: " << result;
    OnError();
    return;
  }

  read_buffer_->set_offset(read_buffer_->offset() + result);
  if (read_buffer_->offset() > kPacketHeaderSize) {
    int packet_size =
        ntohs(*reinterpret_cast<uint16*>(read_buffer_->StartOfBuffer()));
    if (packet_size + kPacketHeaderSize <= read_buffer_->offset()) {
      // We've got a full packet!
      char* start = read_buffer_->StartOfBuffer() + kPacketHeaderSize;
      std::vector<char> data(start, start + packet_size);
      OnPacket(data);

      // Move remaining data to the start of the buffer.
      memmove(read_buffer_->StartOfBuffer(), start + packet_size,
              read_buffer_->offset() - packet_size - kPacketHeaderSize);
      read_buffer_->set_offset(read_buffer_->offset() - packet_size -
                               kPacketHeaderSize);
    }
  }
}

void P2PSocketHostTcp::Send(const net::IPEndPoint& to,
                            const std::vector<char>& data) {
  if (!socket_.get()) {
    // The Send message may be sent after the an OnError message was
    // sent by hasn't been processed the renderer.
    return;
  }

  if (write_buffer_) {
    // Silently drop packet if we haven't finished sending previous
    // packet.
    VLOG(1) << "Dropping TCP packet.";
    return;
  }

  if (!(to == remote_address_)) {
    // Renderer should use this socket only to send data to
    // |remote_address_|.
    NOTREACHED();
    OnError();
    return;
  }

  if (!connected_) {
    P2PSocketHost::StunMessageType type;
    bool stun = GetStunPacketType(&*data.begin(), data.size(), &type);
    if (!stun || type == STUN_DATA_INDICATION) {
      LOG(ERROR) << "Page tried to send a data packet to " << to.ToString()
                 << " before STUN binding is finished.";
      OnError();
      return;
    }
  }

  int size = kPacketHeaderSize + data.size();
  write_buffer_ = new net::DrainableIOBuffer(new net::IOBuffer(size), size);
  *reinterpret_cast<uint16*>(write_buffer_->data()) = htons(data.size());
  memcpy(write_buffer_->data() + kPacketHeaderSize, &data[0], data.size());

  DoWrite();
}

void P2PSocketHostTcp::DoWrite() {
  while (true) {
    int result = socket_->Write(write_buffer_, write_buffer_->BytesRemaining(),
                                base::Bind(&P2PSocketHostTcp::OnWritten,
                                           base::Unretained(this)));
    if (result >= 0) {
      write_buffer_->DidConsume(result);
      if (write_buffer_->BytesRemaining() == 0) {
        write_buffer_ = NULL;
        break;
      }
    } else {
      if (result != net::ERR_IO_PENDING) {
        LOG(ERROR) << "Error when sending data in TCP socket: " << result;
        OnError();
      }
      break;
    }
  }
}

void P2PSocketHostTcp::OnWritten(int result) {
  DCHECK(write_buffer_);
  DCHECK_NE(result, net::ERR_IO_PENDING);

  if (result < 0) {
    DCHECK(result != net::ERR_IO_PENDING);
    LOG(ERROR) << "Error when sending data in TCP socket: " << result;
    OnError();
    return;
  }

  write_buffer_->DidConsume(result);
  if (write_buffer_->BytesRemaining() == 0) {
    write_buffer_ = NULL;
  } else {
    DoWrite();
  }
}

P2PSocketHost* P2PSocketHostTcp::AcceptIncomingTcpConnection(
    const net::IPEndPoint& remote_address, int id) {
  NOTREACHED();
  OnError();
  return NULL;
}

} // namespace content
<commit_msg>P2PSocketHostTcp::Init method calls SetSendBufferSize after net::TCPClientSocket object creation. After the object creation TCPClientSocket::socket_ is pointing to invalid address where as bound_socket_ has the right value. The socket_ will have right value of socket fd once Connect method is called for the socket object.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/renderer_host/p2p/socket_host_tcp.h"

#include "base/sys_byteorder.h"
#include "content/common/p2p_messages.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/socket/tcp_client_socket.h"

namespace {
const int kReadBufferSize = 4096;
const int kPacketHeaderSize = sizeof(uint16);
}  // namespace

namespace content {

P2PSocketHostTcp::P2PSocketHostTcp(IPC::Message::Sender* message_sender,
                                   int routing_id, int id)
    : P2PSocketHost(message_sender, routing_id, id),
      connected_(false) {
}

P2PSocketHostTcp::~P2PSocketHostTcp() {
  if (state_ == STATE_OPEN) {
    DCHECK(socket_.get());
    socket_.reset();
  }
}

bool P2PSocketHostTcp::InitAccepted(const net::IPEndPoint& remote_address,
                                    net::StreamSocket* socket) {
  DCHECK(socket);
  DCHECK_EQ(state_, STATE_UNINITIALIZED);

  remote_address_ = remote_address;
  socket_.reset(socket);
  state_ = STATE_OPEN;
  DoRead();
  return state_ != STATE_ERROR;
}

bool P2PSocketHostTcp::Init(const net::IPEndPoint& local_address,
                            const net::IPEndPoint& remote_address) {
  DCHECK_EQ(state_, STATE_UNINITIALIZED);

  remote_address_ = remote_address;
  state_ = STATE_CONNECTING;
  scoped_ptr<net::TCPClientSocket> tcp_socket(new net::TCPClientSocket(
      net::AddressList::CreateFromIPAddress(
          remote_address.address(), remote_address.port()),
      NULL, net::NetLog::Source()));
  if (tcp_socket->Bind(local_address) != net::OK) {
    OnError();
    return false;
  }
  socket_.reset(tcp_socket.release());

  int result = socket_->Connect(
      base::Bind(&P2PSocketHostTcp::OnConnected, base::Unretained(this)));
  if (result != net::ERR_IO_PENDING) {
    OnConnected(result);
  }

  return state_ != STATE_ERROR;
}

void P2PSocketHostTcp::OnError() {
  socket_.reset();

  if (state_ == STATE_UNINITIALIZED || state_ == STATE_CONNECTING ||
      state_ == STATE_OPEN) {
    message_sender_->Send(new P2PMsg_OnError(routing_id_, id_));
  }

  state_ = STATE_ERROR;
}

void P2PSocketHostTcp::OnConnected(int result) {
  DCHECK_EQ(state_, STATE_CONNECTING);
  DCHECK_NE(result, net::ERR_IO_PENDING);

  if (result != net::OK) {
    OnError();
    return;
  }

  if (socket_->SetSendBufferSize(kMaxSendBufferSize)) {
    LOG(WARNING) << "Failed to set send buffer size for TCP socket.";
  }

  net::IPEndPoint address;
  result = socket_->GetLocalAddress(&address);
  if (result < 0) {
    LOG(ERROR) << "P2PSocket::Init(): unable to get local address: "
               << result;
    OnError();
    return;
  }

  VLOG(1) << "Local address: " << address.ToString();
  state_ = STATE_OPEN;
  message_sender_->Send(new P2PMsg_OnSocketCreated(routing_id_, id_, address));
  DoRead();
}

void P2PSocketHostTcp::DoRead() {
  int result;
  do {
    if (!read_buffer_) {
      read_buffer_ = new net::GrowableIOBuffer();
      read_buffer_->SetCapacity(kReadBufferSize);
    } else if (read_buffer_->RemainingCapacity() < kReadBufferSize) {
      // Make sure that we always have at least kReadBufferSize of
      // remaining capacity in the read buffer. Normally all packets
      // are smaller than kReadBufferSize, so this is not really
      // required.
      read_buffer_->SetCapacity(read_buffer_->capacity() + kReadBufferSize -
                                read_buffer_->RemainingCapacity());
    }
    result = socket_->Read(read_buffer_, read_buffer_->RemainingCapacity(),
                           base::Bind(&P2PSocketHostTcp::OnRead,
                                      base::Unretained(this)));
    DidCompleteRead(result);
  } while (result > 0);
}

void P2PSocketHostTcp::OnRead(int result) {
  DidCompleteRead(result);
  if (state_ == STATE_OPEN) {
    DoRead();
  }
}

void P2PSocketHostTcp::OnPacket(std::vector<char>& data) {
  if (!connected_) {
    P2PSocketHost::StunMessageType type;
    bool stun = GetStunPacketType(&*data.begin(), data.size(), &type);
    if (stun && IsRequestOrResponse(type)) {
      connected_ = true;
    } else if (!stun || type == STUN_DATA_INDICATION) {
      LOG(ERROR) << "Received unexpected data packet from "
                 << remote_address_.ToString()
                 << " before STUN binding is finished. "
                 << "Terminating connection.";
      OnError();
      return;
    }
  }

  message_sender_->Send(new P2PMsg_OnDataReceived(routing_id_, id_,
                                                  remote_address_, data));
}

void P2PSocketHostTcp::DidCompleteRead(int result) {
  DCHECK_EQ(state_, STATE_OPEN);

  if (result == net::ERR_IO_PENDING) {
    return;
  } else if (result < 0){
    LOG(ERROR) << "Error when reading from TCP socket: " << result;
    OnError();
    return;
  }

  read_buffer_->set_offset(read_buffer_->offset() + result);
  if (read_buffer_->offset() > kPacketHeaderSize) {
    int packet_size =
        ntohs(*reinterpret_cast<uint16*>(read_buffer_->StartOfBuffer()));
    if (packet_size + kPacketHeaderSize <= read_buffer_->offset()) {
      // We've got a full packet!
      char* start = read_buffer_->StartOfBuffer() + kPacketHeaderSize;
      std::vector<char> data(start, start + packet_size);
      OnPacket(data);

      // Move remaining data to the start of the buffer.
      memmove(read_buffer_->StartOfBuffer(), start + packet_size,
              read_buffer_->offset() - packet_size - kPacketHeaderSize);
      read_buffer_->set_offset(read_buffer_->offset() - packet_size -
                               kPacketHeaderSize);
    }
  }
}

void P2PSocketHostTcp::Send(const net::IPEndPoint& to,
                            const std::vector<char>& data) {
  if (!socket_.get()) {
    // The Send message may be sent after the an OnError message was
    // sent by hasn't been processed the renderer.
    return;
  }

  if (write_buffer_) {
    // Silently drop packet if we haven't finished sending previous
    // packet.
    VLOG(1) << "Dropping TCP packet.";
    return;
  }

  if (!(to == remote_address_)) {
    // Renderer should use this socket only to send data to
    // |remote_address_|.
    NOTREACHED();
    OnError();
    return;
  }

  if (!connected_) {
    P2PSocketHost::StunMessageType type;
    bool stun = GetStunPacketType(&*data.begin(), data.size(), &type);
    if (!stun || type == STUN_DATA_INDICATION) {
      LOG(ERROR) << "Page tried to send a data packet to " << to.ToString()
                 << " before STUN binding is finished.";
      OnError();
      return;
    }
  }

  int size = kPacketHeaderSize + data.size();
  write_buffer_ = new net::DrainableIOBuffer(new net::IOBuffer(size), size);
  *reinterpret_cast<uint16*>(write_buffer_->data()) = htons(data.size());
  memcpy(write_buffer_->data() + kPacketHeaderSize, &data[0], data.size());

  DoWrite();
}

void P2PSocketHostTcp::DoWrite() {
  while (true) {
    int result = socket_->Write(write_buffer_, write_buffer_->BytesRemaining(),
                                base::Bind(&P2PSocketHostTcp::OnWritten,
                                           base::Unretained(this)));
    if (result >= 0) {
      write_buffer_->DidConsume(result);
      if (write_buffer_->BytesRemaining() == 0) {
        write_buffer_ = NULL;
        break;
      }
    } else {
      if (result != net::ERR_IO_PENDING) {
        LOG(ERROR) << "Error when sending data in TCP socket: " << result;
        OnError();
      }
      break;
    }
  }
}

void P2PSocketHostTcp::OnWritten(int result) {
  DCHECK(write_buffer_);
  DCHECK_NE(result, net::ERR_IO_PENDING);

  if (result < 0) {
    DCHECK(result != net::ERR_IO_PENDING);
    LOG(ERROR) << "Error when sending data in TCP socket: " << result;
    OnError();
    return;
  }

  write_buffer_->DidConsume(result);
  if (write_buffer_->BytesRemaining() == 0) {
    write_buffer_ = NULL;
  } else {
    DoWrite();
  }
}

P2PSocketHost* P2PSocketHostTcp::AcceptIncomingTcpConnection(
    const net::IPEndPoint& remote_address, int id) {
  NOTREACHED();
  OnError();
  return NULL;
}

} // namespace content
<|endoftext|>


<commit_before>#include <possumwood_sdk/node_implementation.h>

#include <tbb/parallel_for.h>

#include "sequence.h"

namespace {

dependency_graph::InAttr<possumwood::opencv::Sequence> a_in;
dependency_graph::OutAttr<possumwood::opencv::Sequence> a_out;

dependency_graph::State compute(dependency_graph::Values& data) {
	const possumwood::opencv::Sequence& in = data.get(a_in);

	if(!in.isValid())
		throw std::runtime_error("Input sequence does not have consistent size or type.");

	possumwood::opencv::Sequence out = in;

	if(!in.empty()) {
		if(in.type() != CV_32FC1)
			throw std::runtime_error("Only 1-channel float images supported for the moment.");

		const int cols = in.cols();
		const int rows = in.rows();

		tbb::parallel_for(0, rows, [&](int r) {
			for(int c=0; c<cols; ++c) {
				auto it = out.begin();
				float max = (*it)->at<float>(r, c);
				float min = (*it)->at<float>(r, c);
				++it;

				while(it != out.end()) {
					max = std::max(max, (*it)->at<float>(r, c));
					min = std::min(min, (*it)->at<float>(r, c));

					++it;
				}

				for(it = out.begin(); it != out.end(); ++it) {
					float& val = (*it)->at<float>(r, c);
					val = (val - min) / (max - min);
				}
			}
		});
	}

	data.set(a_out, out);

	return dependency_graph::State();
}

void init(possumwood::Metadata& meta) {
	meta.addAttribute(a_in, "in");
	meta.addAttribute(a_out, "out");

	meta.addInfluence(a_in, a_out);

	meta.setCompute(compute);
}

possumwood::NodeImplementation s_impl("opencv/sequence/pixel_normalize", init);

}
<commit_msg>Added Max, Min-Max and Sum normalization modes to sequence/pixel_normalize<commit_after>#include <possumwood_sdk/node_implementation.h>

#include <tbb/parallel_for.h>

#include "possumwood_sdk/datatypes/enum.h"

#include "sequence.h"

namespace {

dependency_graph::InAttr<possumwood::opencv::Sequence> a_in;
dependency_graph::InAttr<possumwood::Enum> a_mode;
dependency_graph::OutAttr<possumwood::opencv::Sequence> a_out;

enum Mode {
	kMinMax,
	kMax,
	kSum
};

dependency_graph::State compute(dependency_graph::Values& data) {
	const possumwood::opencv::Sequence& in = data.get(a_in);

	if(!in.isValid())
		throw std::runtime_error("Input sequence does not have consistent size or type.");

	possumwood::opencv::Sequence out = in.clone();

	if(!in.empty()) {
		if(in.type() != CV_32FC1)
			throw std::runtime_error("Only 1-channel float images supported for the moment.");

		const int cols = in.cols();
		const int rows = in.rows();

		Mode mode = kMinMax;
		if(data.get(a_mode).value() == "Maximum")
			mode = kMax;
		else if(data.get(a_mode).value() == "Sum")
			mode = kSum;

		tbb::parallel_for(0, rows, [&](int r) {
			for(int c=0; c<cols; ++c) {
				auto it = out.begin();

				float max = (*it)->at<float>(r, c);
				float min = max;
				float sum = max;
				++it;

				while(it != out.end()) {
					const float& tmp = (*it)->at<float>(r, c);

					max = std::max(max, tmp);
					min = std::min(min, tmp);
					sum += tmp;

					++it;
				}

				if(mode == kMinMax)
					for(it = out.begin(); it != out.end(); ++it) {
						float& val = (*it)->at<float>(r, c);
						val = (val - min) / (max - min);
					}
				else if(mode == kMax)
					for(it = out.begin(); it != out.end(); ++it) {
						float& val = (*it)->at<float>(r, c);
						val /= max;
					}
				else if(mode == kSum)
					for(it = out.begin(); it != out.end(); ++it) {
						float& val = (*it)->at<float>(r, c);
						val /= sum;
					}
			}
		});
	}

	data.set(a_out, out);

	return dependency_graph::State();
}

void init(possumwood::Metadata& meta) {
	meta.addAttribute(a_in, "in");
	meta.addAttribute(a_mode, "mode",
	                  possumwood::Enum({"Minimum-maximum", "Maximum", "Sum"}));
	meta.addAttribute(a_out, "out");

	meta.addInfluence(a_in, a_out);
	meta.addInfluence(a_mode, a_out);

	meta.setCompute(compute);
}

possumwood::NodeImplementation s_impl("opencv/sequence/pixel_normalize", init);

}
<|endoftext|>