<commit_before>/*
 * HTTP server implementation.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "Internal.hxx"
#include "Request.hxx"
#include "http_headers.hxx"
#include "http_upgrade.hxx"
#include "http_date.hxx"
#include "direct.hxx"
#include "header_writer.hxx"
#include "format.h"
#include "GrowingBuffer.hxx"
#include "istream_gb.hxx"
#include "istream/istream_cat.hxx"
#include "istream/istream_chunked.hxx"
#include "istream/istream_dechunk.hxx"
#include "istream/istream_memory.hxx"
#include "istream/istream_string.hxx"

#include <string.h>

bool
HttpServerConnection::MaybeSend100Continue()
{
    assert(IsValid());
    assert(request.read_state == Request::BODY);

    if (!request.expect_100_continue)
        return true;

    assert(!response.istream.IsDefined());

    request.expect_100_continue = false;

    /* this string is simple enough to expect that we don't need to
       check for partial writes, not before we have sent a single byte
       of response to the peer */
    static const char *const response_string = "HTTP/1.1 100 Continue\r\n\r\n";
    const size_t length = strlen(response_string);
    ssize_t nbytes = socket.Write(response_string, length);
    if (gcc_likely(nbytes == (ssize_t)length))
        return true;

    if (nbytes == WRITE_ERRNO)
        ErrorErrno("write error");
    else if (nbytes != WRITE_DESTROYED)
        Error("write error");
    return false;
}

static size_t
format_status_line(char *p, http_status_t status)
{
    assert(http_status_is_valid(status));

    const char *status_string = http_status_to_string(status);
    assert(status_string != nullptr);
    size_t length = strlen(status_string);

    memcpy(p, "HTTP/1.1 ", 9);
    memcpy(p + 9, status_string, length);
    length += 9;
    p[length++] = '\r';
    p[length++] = '\n';

    return length;
}

inline void
HttpServerConnection::SubmitResponse(http_status_t status,
                                     HttpHeaders &&headers,
                                     Istream *body)
{
    assert(http_status_is_valid(status));
    assert(score != HTTP_SERVER_NEW);
    assert(socket.IsConnected());

    if (http_status_is_success(status)) {
        if (score == HTTP_SERVER_FIRST)
            score = HTTP_SERVER_SUCCESS;
    } else {
        score = HTTP_SERVER_ERROR;
    }

    if (request.read_state == HttpServerConnection::Request::BODY &&
        /* if we didn't send "100 Continue" yet, we should do it now;
           we don't know if the request body will be used, but at
           least it hasn't been closed yet */
        !MaybeSend100Continue())
        return;

    auto &request_pool = request.request->pool;

    response.status = status;
    Istream *status_stream
        = istream_memory_new(&request_pool,
                             response.status_buffer,
                             format_status_line(response.status_buffer,
                                                status));

    /* how will we transfer the body?  determine length and
       transfer-encoding */

    const off_t content_length = body == nullptr
        ? 0 : body->GetAvailable(false);
    if (content_length == (off_t)-1) {
        /* the response length is unknown yet */
        assert(!http_status_is_empty(status));

        if (!http_method_is_empty(request.request->method) && keep_alive) {
            /* keep-alive is enabled, which means that we have to
               enable chunking */
            headers.Write("transfer-encoding", "chunked");

            /* optimized code path: if an istream_dechunked shall get
               chunked via istream_chunk, let's just skip both to
               reduce the amount of work and I/O we have to do */
            if (!istream_dechunk_check_verbatim(*body))
                body = istream_chunked_new(request_pool, *body);
        }
    } else if (http_status_is_empty(status)) {
        assert(content_length == 0);
    } else if (body != nullptr || !http_method_is_empty(request.request->method)) {
        /* fixed body size */
        format_uint64(response.content_length_buffer, content_length);
        headers.Write("content-length", response.content_length_buffer);
    }

    if (http_method_is_empty(request.request->method) && body != nullptr)
        istream_free_unused(&body);

    const bool upgrade = body != nullptr && http_is_upgrade(status, headers);
    if (upgrade) {
        headers.Write("connection", "upgrade");
        headers.MoveToBuffer("upgrade");
    } else if (!keep_alive && !request.http_1_0)
        headers.Write("connection", "close");

    GrowingBuffer headers3 = headers.ToBuffer();
    headers3.Write("\r\n", 2);
    Istream *header_stream = istream_gb_new(request_pool, std::move(headers3));

    response.length = - status_stream->GetAvailable(false)
        - header_stream->GetAvailable(false);

    /* make sure the access logger gets a negative value if there
       is no response body */
    response.length -= body == nullptr;

    body = istream_cat_new(request_pool, status_stream,
                           header_stream, body);

    SetResponseIstream(*body);
    TryWrite();
}

void
http_server_response(const HttpServerRequest *request,
                     http_status_t status,
                     HttpHeaders &&headers,
                     Istream *body)
{
    auto &connection = request->connection;
    assert(connection.request.request == request);

    connection.SubmitResponse(status, std::move(headers), body);
}

void
http_server_simple_response(const HttpServerRequest &request,
                            http_status_t status, const char *location,
                            const char *msg)
{
    assert(status >= 200 && status < 600);

    if (http_status_is_empty(status))
        msg = nullptr;
    else if (msg == nullptr)
        msg = http_status_to_string(status);

    HttpHeaders headers(request.pool);

#ifndef NO_DATE_HEADER
    headers.Write("date", http_date_format(std::chrono::system_clock::now()));
#endif

    if (location != nullptr)
        headers.Write("location", location);

    Istream *body = nullptr;
    if (msg != nullptr) {
        headers.Write("content-type", "text/plain");
        body = istream_string_new(&request.pool, msg);
    }

    http_server_response(&request, status, std::move(headers), body);
}

void
http_server_send_message(const HttpServerRequest *request,
                         http_status_t status, const char *msg)
{
    HttpHeaders headers(request->pool);

    headers.Write("content-type", "text/plain");

#ifndef NO_DATE_HEADER
    headers.Write("date", http_date_format(std::chrono::system_clock::now()));
#endif

    http_server_response(request, status, std::move(headers),
                         istream_string_new(&request->pool, msg));
}

void
http_server_send_redirect(const HttpServerRequest *request,
                          http_status_t status, const char *location,
                          const char *msg)
{
    assert(request != nullptr);
    assert(status >= 300 && status < 400);
    assert(location != nullptr);

    if (msg == nullptr)
        msg = "redirection";

    HttpHeaders headers(request->pool);

    headers.Write("content-type", "text/plain");
    headers.Write("location", location);

#ifndef NO_DATE_HEADER
    headers.Write("date", http_date_format(std::chrono::system_clock::now()));
#endif

    http_server_response(request, status, std::move(headers),
                         istream_string_new(&request->pool, msg));
}
<commit_msg>http_server: cast http_status_t to unsigned before checking<commit_after>/*
 * HTTP server implementation.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "Internal.hxx"
#include "Request.hxx"
#include "http_headers.hxx"
#include "http_upgrade.hxx"
#include "http_date.hxx"
#include "direct.hxx"
#include "header_writer.hxx"
#include "format.h"
#include "GrowingBuffer.hxx"
#include "istream_gb.hxx"
#include "istream/istream_cat.hxx"
#include "istream/istream_chunked.hxx"
#include "istream/istream_dechunk.hxx"
#include "istream/istream_memory.hxx"
#include "istream/istream_string.hxx"

#include <string.h>

bool
HttpServerConnection::MaybeSend100Continue()
{
    assert(IsValid());
    assert(request.read_state == Request::BODY);

    if (!request.expect_100_continue)
        return true;

    assert(!response.istream.IsDefined());

    request.expect_100_continue = false;

    /* this string is simple enough to expect that we don't need to
       check for partial writes, not before we have sent a single byte
       of response to the peer */
    static const char *const response_string = "HTTP/1.1 100 Continue\r\n\r\n";
    const size_t length = strlen(response_string);
    ssize_t nbytes = socket.Write(response_string, length);
    if (gcc_likely(nbytes == (ssize_t)length))
        return true;

    if (nbytes == WRITE_ERRNO)
        ErrorErrno("write error");
    else if (nbytes != WRITE_DESTROYED)
        Error("write error");
    return false;
}

static size_t
format_status_line(char *p, http_status_t status)
{
    assert(http_status_is_valid(status));

    const char *status_string = http_status_to_string(status);
    assert(status_string != nullptr);
    size_t length = strlen(status_string);

    memcpy(p, "HTTP/1.1 ", 9);
    memcpy(p + 9, status_string, length);
    length += 9;
    p[length++] = '\r';
    p[length++] = '\n';

    return length;
}

inline void
HttpServerConnection::SubmitResponse(http_status_t status,
                                     HttpHeaders &&headers,
                                     Istream *body)
{
    assert(http_status_is_valid(status));
    assert(score != HTTP_SERVER_NEW);
    assert(socket.IsConnected());

    if (http_status_is_success(status)) {
        if (score == HTTP_SERVER_FIRST)
            score = HTTP_SERVER_SUCCESS;
    } else {
        score = HTTP_SERVER_ERROR;
    }

    if (request.read_state == HttpServerConnection::Request::BODY &&
        /* if we didn't send "100 Continue" yet, we should do it now;
           we don't know if the request body will be used, but at
           least it hasn't been closed yet */
        !MaybeSend100Continue())
        return;

    auto &request_pool = request.request->pool;

    response.status = status;
    Istream *status_stream
        = istream_memory_new(&request_pool,
                             response.status_buffer,
                             format_status_line(response.status_buffer,
                                                status));

    /* how will we transfer the body?  determine length and
       transfer-encoding */

    const off_t content_length = body == nullptr
        ? 0 : body->GetAvailable(false);
    if (content_length == (off_t)-1) {
        /* the response length is unknown yet */
        assert(!http_status_is_empty(status));

        if (!http_method_is_empty(request.request->method) && keep_alive) {
            /* keep-alive is enabled, which means that we have to
               enable chunking */
            headers.Write("transfer-encoding", "chunked");

            /* optimized code path: if an istream_dechunked shall get
               chunked via istream_chunk, let's just skip both to
               reduce the amount of work and I/O we have to do */
            if (!istream_dechunk_check_verbatim(*body))
                body = istream_chunked_new(request_pool, *body);
        }
    } else if (http_status_is_empty(status)) {
        assert(content_length == 0);
    } else if (body != nullptr || !http_method_is_empty(request.request->method)) {
        /* fixed body size */
        format_uint64(response.content_length_buffer, content_length);
        headers.Write("content-length", response.content_length_buffer);
    }

    if (http_method_is_empty(request.request->method) && body != nullptr)
        istream_free_unused(&body);

    const bool upgrade = body != nullptr && http_is_upgrade(status, headers);
    if (upgrade) {
        headers.Write("connection", "upgrade");
        headers.MoveToBuffer("upgrade");
    } else if (!keep_alive && !request.http_1_0)
        headers.Write("connection", "close");

    GrowingBuffer headers3 = headers.ToBuffer();
    headers3.Write("\r\n", 2);
    Istream *header_stream = istream_gb_new(request_pool, std::move(headers3));

    response.length = - status_stream->GetAvailable(false)
        - header_stream->GetAvailable(false);

    /* make sure the access logger gets a negative value if there
       is no response body */
    response.length -= body == nullptr;

    body = istream_cat_new(request_pool, status_stream,
                           header_stream, body);

    SetResponseIstream(*body);
    TryWrite();
}

void
http_server_response(const HttpServerRequest *request,
                     http_status_t status,
                     HttpHeaders &&headers,
                     Istream *body)
{
    auto &connection = request->connection;
    assert(connection.request.request == request);

    connection.SubmitResponse(status, std::move(headers), body);
}

void
http_server_simple_response(const HttpServerRequest &request,
                            http_status_t status, const char *location,
                            const char *msg)
{
    assert(unsigned(status) >= 200 && unsigned(status) < 600);

    if (http_status_is_empty(status))
        msg = nullptr;
    else if (msg == nullptr)
        msg = http_status_to_string(status);

    HttpHeaders headers(request.pool);

#ifndef NO_DATE_HEADER
    headers.Write("date", http_date_format(std::chrono::system_clock::now()));
#endif

    if (location != nullptr)
        headers.Write("location", location);

    Istream *body = nullptr;
    if (msg != nullptr) {
        headers.Write("content-type", "text/plain");
        body = istream_string_new(&request.pool, msg);
    }

    http_server_response(&request, status, std::move(headers), body);
}

void
http_server_send_message(const HttpServerRequest *request,
                         http_status_t status, const char *msg)
{
    HttpHeaders headers(request->pool);

    headers.Write("content-type", "text/plain");

#ifndef NO_DATE_HEADER
    headers.Write("date", http_date_format(std::chrono::system_clock::now()));
#endif

    http_server_response(request, status, std::move(headers),
                         istream_string_new(&request->pool, msg));
}

void
http_server_send_redirect(const HttpServerRequest *request,
                          http_status_t status, const char *location,
                          const char *msg)
{
    assert(request != nullptr);
    assert(status >= 300 && status < 400);
    assert(location != nullptr);

    if (msg == nullptr)
        msg = "redirection";

    HttpHeaders headers(request->pool);

    headers.Write("content-type", "text/plain");
    headers.Write("location", location);

#ifndef NO_DATE_HEADER
    headers.Write("date", http_date_format(std::chrono::system_clock::now()));
#endif

    http_server_response(request, status, std::move(headers),
                         istream_string_new(&request->pool, msg));
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/hwpf/fapi2/include/ffdc.H $                        */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2011,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/**
 *  @file ffdc.H
 *  @brief Defines the FirstFailureData class
 */

#ifndef FAPI2_FFDC_H_
#define FAPI2_FFDC_H_

#include <memory>
#include <hwp_return_codes.H>
#include <plat_trace.H>
#include <error_info.H>
#include <target.H>

using fapi2::TARGET_TYPE_ALL;

namespace fapi2
{
    ///
    /// @brief Check the type of a variable
    ///
    /// This function can be called to check that a variable type is as expected
    /// @note This mechanism will allow for cast ctor's which other static type
    /// checking might not.
    ///
    template<typename T>
    inline
    void checkType(const T &) {}

    class ReturnCode;

    ///
    /// @class FirstFailureData
    ///
    /// This class provides storage and methods for creating and manipulating
    /// FFDC.
    /// It is not needed on all platforms - platforms which need this class have
    /// specified this by forcing their fapi2::ReturnCode to be a subclass of
    /// this class.
    ///
    template< class R = fapi2::ReturnCode >
    class FirstFailureData
    {
    public:

        ///
        /// @brief Default constructor.
        /// @note We don't create our error info be default. It will be created
        /// when its needed in the setHwpError() method. Note that dereferencing
        /// the error info without will create a problem.
        ///
        FirstFailureData(void):
            iv_info( nullptr )
            {}

        ///
        /// @brief Copy Constructor
        ///
        /// @param[in] i_right Reference to FirstFailureData to copy
        /// @note Generates default copy constructor - no deep pointer
        /// copies necessary.
        ///
        FirstFailureData(const FirstFailureData & i_right) = default;

        ///
        /// @brief Destructor
        ///
        ~FirstFailureData(void) = default;

        ///
        /// @brief Assignment Operator.
        ///
        /// @param[in] i_right Reference to FirstFailureData to assign from.
        /// @return Reference to 'this' FirstFailureData
        ///
        FirstFailureData & operator=(const FirstFailureData & i_right) = default;

        ///
        /// @brief Sets a HWP error. Sets the rcValue to the supplied value (from
        ///      the HwpFirstFailureData enumeration) and deletes any
        /// associated data.
        ///
        /// HWP code must call the FAPI_SET_HWP_ERROR macro rather than this
        /// function
        /// directly to generate an error so that any error information is
        /// automatically added to the FirstFailureData
        ///
        /// @param[in] i_rcValue Error value to set
        ///
        inline void _setHwpError(const fapi2::HwpReturnCode i_rcValue)
            {
                FAPI_ERR("_setHwpError: Creating HWP error 0x%x", i_rcValue);
                static_cast<R*>(this)->operator=(i_rcValue);

                // Forget about any associated data (this is a new error)
                iv_info.reset(new ErrorInfo());
            }

        ///
        /// @brief Get a pointer to any PlatData. FirstFailureData is still
        ///        responsible for deletion of the data. The caller must not
        ///        delete
        ///
        /// This is called by PLAT. The expected use-case is to get a pointer to
        /// a platform error log. The data pointer should be used immediately in
        /// the same thread.
        ///
        /// @return void *. Pointer to any PlatData. If NULL then no data
        ///
        void* getData(void) const;

        ///
        /// @brief Get a pointer to any PlatData and release ownership from
        ///      FirstFailureData. The caller is responsible for deletion.
        ///
        /// This is called by PLAT. The expected use-case is to retrieve a
        /// platform error log.
        ///
        /// @return void*. Pointer to any PlatData. If NULL then no data
        ///
        void* releaseData(void);

        ///
        /// @brief Add ErrorInfo
        ///
        /// This is called by the FAPI_SET_HWP_ERROR and macro to add ErrorInfo
        /// to the FirstFailureData when a HWP generates an error. The function
        /// is designed to add all the ErrorInfo at once rather than the
        /// FAPI_SET_HWP_ERROR macro making multiple function calls to add each
        /// piece of ErrorInfo individually in order to minimize code size
        ///
        /// @param[in] i_pObjects Pointer to array of const pointers to const
        ///     objects that are referred to by ErrorInfoEntry objects
        /// @param[in] i_pEntries Pointer to array of ErrorInfoEntry objects
        ///     defining the ErrorInfo that needs to be added
        /// @param[in] i_count    Number of ErrorInfoEntry entries
        ///
        void addErrorInfo(const void* const * i_pObjects,
                          const ErrorInfoEntry* i_pEntries,
                          const uint8_t i_count);

        ///
        /// @brief Get a pointer to any ErrorInfo
        ///
        /// This is called by PLAT to find information about an error
        ///
        /// @return ErrorInfo *. Pointer to any ErrorInfo. If NULL then no info
        ///
        inline const fapi2::ErrorInfo* getErrorInfo(void) const
            { return iv_info.get(); }

        ///
        /// @brief Forgets about any associated data (PlatData and ErrorInfo)
        ///
        /// If this is the only FirstFailureData pointing to the data then the
        /// data is deleted
        ///
        inline void forgetData(void)
            { iv_info = nullptr; }

    private:

        // Pointer to the data
        std::shared_ptr<ErrorInfo> iv_info;
    };

}
#endif // FAPI2_FFDC_H_
<commit_msg>Additional change for FAPI2 FFDC<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/hwpf/fapi2/include/ffdc.H $                        */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2011,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/**
 *  @file ffdc.H
 *  @brief Defines the FirstFailureData class
 */

#ifndef FAPI2_FFDC_H_
#define FAPI2_FFDC_H_

#include <memory>
#include <hwp_return_codes.H>
#include <plat_trace.H>
#include <error_info.H>
#include <target.H>

using fapi2::TARGET_TYPE_ALL;

namespace fapi2
{
///
/// @brief Check the type of a variable
///
/// This function can be called to check that a variable type is as expected
/// @note This mechanism will allow for cast ctor's which other static type
/// checking might not.
///
template<typename T>
inline
void checkType(const T&) {}

class ReturnCode;

///
/// @class FirstFailureData
///
/// This class provides storage and methods for creating and manipulating
/// FFDC.
/// It is not needed on all platforms - platforms which need this class have
/// specified this by forcing their fapi2::ReturnCode to be a subclass of
/// this class.
///
template< class R = fapi2::ReturnCode >
class FirstFailureData
{
    public:

        ///
        /// @brief Default constructor.
        /// @note We don't create our error info be default. It will be created
        /// when its needed in the setHwpError() method. Note that dereferencing
        /// the error info without will create a problem.
        ///
        FirstFailureData(void):
            iv_info( nullptr )
        {}

        ///
        /// @brief Copy Constructor
        ///
        /// @param[in] i_right Reference to FirstFailureData to copy
        /// @note Generates default copy constructor - no deep pointer
        /// copies necessary.
        ///
        FirstFailureData(const FirstFailureData& i_right) = default;

        ///
        /// @brief Destructor
        ///
        ~FirstFailureData(void) = default;

        ///
        /// @brief Assignment Operator.
        ///
        /// @param[in] i_right Reference to FirstFailureData to assign from.
        /// @return Reference to 'this' FirstFailureData
        ///
        FirstFailureData& operator=(const FirstFailureData& i_right) = default;

        ///
        /// @brief Sets a HWP error. Sets the rcValue to the supplied value (from
        ///      the HwpFirstFailureData enumeration) and deletes any
        /// associated data.
        ///
        /// HWP code must call the FAPI_SET_HWP_ERROR macro rather than this
        /// function
        /// directly to generate an error so that any error information is
        /// automatically added to the FirstFailureData
        ///
        /// @param[in] i_rcValue Error value to set
        ///
        inline void _setHwpError(const fapi2::HwpReturnCode i_rcValue)
        {
            FAPI_ERR("_setHwpError: Creating HWP error 0x%x", i_rcValue);
            static_cast<R*>(this)->operator=(i_rcValue);

            // Forget about any associated data (this is a new error)
            iv_info.reset(new ErrorInfo());
        }

        ///
        /// @brief Get a pointer to any PlatData. FirstFailureData is still
        ///        responsible for deletion of the data. The caller must not
        ///        delete
        ///
        /// This is called by PLAT. The expected use-case is to get a pointer to
        /// a platform error log. The data pointer should be used immediately in
        /// the same thread.
        ///
        /// @return void *. Pointer to any PlatData. If NULL then no data
        ///
        void* getData(void) const;

        ///
        /// @brief Get a pointer to any PlatData and release ownership from
        ///      FirstFailureData. The caller is responsible for deletion.
        ///
        /// This is called by PLAT. The expected use-case is to retrieve a
        /// platform error log.
        ///
        /// @return void*. Pointer to any PlatData. If NULL then no data
        ///
        inline void* releaseData(void)
        {
            void* l_pData = iv_info;
            iv_info = NULL;
            return l_pData;
        }

        ///
        /// @brief Add ErrorInfo
        ///
        /// This is called by the FAPI_SET_HWP_ERROR and macro to add ErrorInfo
        /// to the FirstFailureData when a HWP generates an error. The function
        /// is designed to add all the ErrorInfo at once rather than the
        /// FAPI_SET_HWP_ERROR macro making multiple function calls to add each
        /// piece of ErrorInfo individually in order to minimize code size
        ///
        /// @param[in] i_pObjects Pointer to array of const pointers to const
        ///     objects that are referred to by ErrorInfoEntry objects
        /// @param[in] i_pEntries Pointer to array of ErrorInfoEntry objects
        ///     defining the ErrorInfo that needs to be added
        /// @param[in] i_count    Number of ErrorInfoEntry entries
        ///
        void addErrorInfo(const void* const* i_pObjects,
                          const ErrorInfoEntry* i_pEntries,
                          const uint8_t i_count);

        ///
        /// @brief Get a pointer to any ErrorInfo
        ///
        /// This is called by PLAT to find information about an error
        ///
        /// @return ErrorInfo *. Pointer to any ErrorInfo. If NULL then no info
        ///
        inline const fapi2::ErrorInfo* getErrorInfo(void) const
        {
            return iv_info.get();
        }

        ///
        /// @brief Forgets about any associated data (PlatData and ErrorInfo)
        ///
        /// If this is the only FirstFailureData pointing to the data then the
        /// data is deleted
        ///
        inline void forgetData(void)
        {
            iv_info = nullptr;
        }

    private:

        // Pointer to the data
        std::shared_ptr<ErrorInfo> iv_info;
};

}
#endif // FAPI2_FFDC_H_
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/include/usr/isteps/istep16list.H $                        */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2012,2018                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

#ifndef __ISTEPS_ISTEP16LIST_H
#define __ISTEPS_ISTEP16LIST_H

/**
 * @file    istep16list.H
 *
 *  IStep 16    Core Activate
 *  IPL FLow Doc        v0.60 (06/02/15)
 *
 *    16.1    host_activate_master
 *          : Activate master core
 *
 *  Please see the note in initsvcstructs.H for description of
 *      the ISTEPNAME macro.
 *
 */

#include    <initservice/initsvcstructs.H>
#include    <initservice/initsvcreasoncodes.H>

namespace   ISTEP_16
{

/**
 *  @brief   host_activate_master
 *
 *  param[in,out]   -   pointer to any arguments, usually NULL
 *
 *  return any errlogs to istep
 *
 */
void*  call_host_activate_master( void    *io_pArgs );

/**
 *  @brief   host_activate_slave_cores
 *
 *  param[in,out]   -   pointer to any arguments, usually NULL
 *
 *  return  any errlogs to istep
 *
 */
void*    call_host_activate_slave_cores( void    *io_pArgs );

/**
 *  @brief   host_secure_rng
 *
 *  param[in,out]   -   pointer to any arguments, usually NULL
 *
 *  return  any errlogs to istep
 *
 */
void*    call_host_secure_rng( void    *io_pArgs );

/**
 *  @brief   mss_scrub
 *
 *  param[in,out]   -   pointer to any arguments, usually NULL
 *
 *  return  any errlogs to istep
 *
 */
void*    call_mss_scrub( void    *io_pArgs );

/**
 *  @brief    host_ipl_complete
 *
 *  param[in,out]   -   pointer to any arguments, usually NULL
 *
 *  return  any errlogs to istep
 *
 */
void*    call_host_ipl_complete( void    *io_pArgs );

/**
 *  @brief    host_load_io_ppe
 *
 *  param[in,out]   -   pointer to any arguments, usually NULL
 *
 *  return  any errlogs to istep
 *
 */
void*    call_host_load_io_ppe( void    *io_pArgs );

};

namespace   INITSERVICE
{
    const   TaskInfo    g_istep16[]  =   {
        {
                "",         // dummy, index 0
                NULL,
                { NONE, EXT_IMAGE, IPL_NOOP, false }
        },
        {
                ISTEPNAME(16,01,"host_activate_master"),
                ISTEP_16::call_host_activate_master,
                { START_FN, EXT_IMAGE, NORMAL_IPL_OP | MPIPL_OP, false }
        },
        {
                ISTEPNAME(16,02,"host_activate_slave_cores"),
                ISTEP_16::call_host_activate_slave_cores,
                { START_FN, EXT_IMAGE, NORMAL_IPL_OP | MPIPL_OP, true }
        },
        {
                ISTEPNAME(16,03,"host_secure_rng"),
                ISTEP_16::call_host_secure_rng,
                { START_FN, EXT_IMAGE, NORMAL_IPL_OP, true }
        },
        {
                // Hostboot PRD should no longer be called after this step.
                ISTEPNAME(16,04,"mss_scrub"),
                ISTEP_16::call_mss_scrub,
                { START_FN, EXT_IMAGE, NORMAL_IPL_OP, false }
        },
        {
                ISTEPNAME(16,05,"host_ipl_complete"),
                ISTEP_16::call_host_ipl_complete,
                { START_FN, EXT_IMAGE, NORMAL_IPL_OP | MPIPL_OP, false }
        },
        {
                ISTEPNAME(16,06,"host_load_io_ppe"),
                ISTEP_16::call_host_load_io_ppe,
                { START_FN, EXT_IMAGE, NORMAL_IPL_OP, false }
        },
};

const DepModInfo g_istep16Dependancies = {
    {
        DEP_LIB(libistep16.so),
        DEP_LIB(libnestmemutils.so),
        DEP_LIB(libp9_cpuWkup.so),
        DEP_LIB(libisteps_mss.so),
        DEP_LIB(libpm.so),
        DEP_LIB(libimageprocs.so),
        NULL
    }
};

const   ExtTaskInfo g_istep16TaskList    =   {
    &(g_istep16[0]),
    ( sizeof(g_istep16)/sizeof(TaskInfo) ),
    &g_istep16Dependancies
};

};  // end namespace

#endif
<commit_msg>Itep16 substep order does not match documentation<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/include/usr/isteps/istep16list.H $                        */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2012,2018                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

#ifndef __ISTEPS_ISTEP16LIST_H
#define __ISTEPS_ISTEP16LIST_H

/**
 * @file    istep16list.H
 *
 *  IStep 16    Core Activate
 *  IPL FLow Doc        v0.60 (06/02/15)
 *
 *    16.1    host_activate_master
 *          : Activate master core
 *
 *  Please see the note in initsvcstructs.H for description of
 *      the ISTEPNAME macro.
 *
 */

#include    <initservice/initsvcstructs.H>
#include    <initservice/initsvcreasoncodes.H>

namespace   ISTEP_16
{

/**
 *  @brief   host_activate_master
 *
 *  param[in,out]   -   pointer to any arguments, usually NULL
 *
 *  return any errlogs to istep
 *
 */
void*  call_host_activate_master( void    *io_pArgs );

/**
 *  @brief   host_activate_slave_cores
 *
 *  param[in,out]   -   pointer to any arguments, usually NULL
 *
 *  return  any errlogs to istep
 *
 */
void*    call_host_activate_slave_cores( void    *io_pArgs );

/**
 *  @brief   host_secure_rng
 *
 *  param[in,out]   -   pointer to any arguments, usually NULL
 *
 *  return  any errlogs to istep
 *
 */
void*    call_host_secure_rng( void    *io_pArgs );

/**
 *  @brief   mss_scrub
 *
 *  param[in,out]   -   pointer to any arguments, usually NULL
 *
 *  return  any errlogs to istep
 *
 */
void*    call_mss_scrub( void    *io_pArgs );

/**
 *  @brief    host_ipl_complete
 *
 *  param[in,out]   -   pointer to any arguments, usually NULL
 *
 *  return  any errlogs to istep
 *
 */
void*    call_host_ipl_complete( void    *io_pArgs );

/**
 *  @brief    host_load_io_ppe
 *
 *  param[in,out]   -   pointer to any arguments, usually NULL
 *
 *  return  any errlogs to istep
 *
 */
void*    call_host_load_io_ppe( void    *io_pArgs );

};

namespace   INITSERVICE
{
    const   TaskInfo    g_istep16[]  =   {
        {
                "",         // dummy, index 0
                NULL,
                { NONE, EXT_IMAGE, IPL_NOOP, false }
        },
        {
                ISTEPNAME(16,01,"host_activate_master"),
                ISTEP_16::call_host_activate_master,
                { START_FN, EXT_IMAGE, NORMAL_IPL_OP | MPIPL_OP, false }
        },
        {
                ISTEPNAME(16,02,"host_activate_slave_cores"),
                ISTEP_16::call_host_activate_slave_cores,
                { START_FN, EXT_IMAGE, NORMAL_IPL_OP | MPIPL_OP, true }
        },
        {
                ISTEPNAME(16,03,"host_secure_rng"),
                ISTEP_16::call_host_secure_rng,
                { START_FN, EXT_IMAGE, NORMAL_IPL_OP, true }
        },
        {
                // Hostboot PRD should no longer be called after this step.
                ISTEPNAME(16,04,"mss_scrub"),
                ISTEP_16::call_mss_scrub,
                { START_FN, EXT_IMAGE, NORMAL_IPL_OP, false }
        },
        {
                ISTEPNAME(16,05,"host_load_io_ppe"),
                ISTEP_16::call_host_load_io_ppe,
                { START_FN, EXT_IMAGE, NORMAL_IPL_OP, false }
        },
        {
                ISTEPNAME(16,06,"host_ipl_complete"),
                ISTEP_16::call_host_ipl_complete,
                { START_FN, EXT_IMAGE, NORMAL_IPL_OP | MPIPL_OP, false }
        },
};

const DepModInfo g_istep16Dependancies = {
    {
        DEP_LIB(libistep16.so),
        DEP_LIB(libnestmemutils.so),
        DEP_LIB(libp9_cpuWkup.so),
        DEP_LIB(libisteps_mss.so),
        DEP_LIB(libpm.so),
        DEP_LIB(libimageprocs.so),
        NULL
    }
};

const   ExtTaskInfo g_istep16TaskList    =   {
    &(g_istep16[0]),
    ( sizeof(g_istep16)/sizeof(TaskInfo) ),
    &g_istep16Dependancies
};

};  // end namespace

#endif
<|endoftext|>


<commit_before><commit_msg>no YES-NO for 'query already exists' dialog, but OK only<commit_after><|endoftext|>


<commit_before>/*  junctions_annotator.cc -- class methods for `junctions annotate`

    Copyright (c) 2015, The Griffith Lab

    Author: Avinash Ramu <aramu@genome.wustl.edu>

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

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

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

#include <getopt.h>
#include <stdexcept>
#include <string>
#include "common.h"
#include "junctions_annotator.h"
#include "faidx.h"

using namespace std;

//Return stream to write output to
void JunctionsAnnotator::close_ofstream() {
    if(ofs_.is_open())
        ofs_.close();
}

//Return stream to write output to
//If output file is not empty, attempt to open
//If output file is empty, set to cout
void JunctionsAnnotator::set_ofstream_object(ofstream &out) {
    if(output_file_ == "NA") {
        copy_stream(cout, out);
        return;
    }
    ofs_.open(output_file_.c_str());
    if(!ofs_.is_open())
        throw runtime_error("Unable to open " +
                            output_file_);
    copy_stream(ofs_, out);
}

//Open junctions file
void JunctionsAnnotator::open_junctions() {
    junctions_.Open();
}

//Open junctions file
void JunctionsAnnotator::close_junctions() {
    junctions_.Close();
}

//Adjust the start and end of the junction
void JunctionsAnnotator::adjust_junction_ends(BED & line) {
    //Adjust the start and end with block sizes
    //The junction start is thick_start + block_size1
    //The junction end is thick_end - block_size2 + 1
    if(!line.fields.size() || line.fields[10].empty()) {
        stringstream position;
        position << line.chrom << ":" << line.start;
        throw runtime_error("Block sizes not found. Invalid line. " +
                            position.str());
    }
    string blocksize_field = line.fields[10];
    vector<int> block_sizes;
    Tokenize(blocksize_field, block_sizes, ',');
    line.start += block_sizes[0];
    line.end -= block_sizes[1] - 1;
}

//Get a single line from the junctions file
bool JunctionsAnnotator::get_single_junction(BED & line) {
    junctions_._status = BED_INVALID;
    if(junctions_.GetNextBed(line) && junctions_._status == BED_VALID) {
        adjust_junction_ends(line);
        return true;
    } else {
        return false;
    }
}

//Get the splice_site bases
bool JunctionsAnnotator::get_splice_site(AnnotatedJunction & line) {
    string position1 = line.chrom + ":" +
                      num_to_str(line.start + 1) + "-" + num_to_str(line.start + 2);
    string position2 = line.chrom + ":" +
                      num_to_str(line.end - 2) + "-" + num_to_str(line.end - 1);
    string seq1, seq2;
    try {
        seq1 = get_reference_sequence(position1);
        seq2 = get_reference_sequence(position2);
    } catch (const runtime_error& e) {
        throw e;
    }
    if(line.strand == "-") {
        seq1 = rev_comp(seq1);
        seq2 = rev_comp(seq2);
        line.splice_site = seq2 + "-" + seq1;
    } else {
        line.splice_site = seq1 + "-" + seq2;
    }
    return true;
}

//Extract gtf info
bool JunctionsAnnotator::read_gtf() {
    gtf_.create_transcript_map();
    gtf_.construct_junctions();
    gtf_.sort_exons_within_transcripts();
    gtf_.annotate_transcript_with_bins();
    //gtf_.print_transcripts();
    return true;
}

//Find overlap between transcript and junction on the negative strand,
//function returns true if either the acceptor or the donor is known
bool JunctionsAnnotator::overlap_ps(const vector<BED>& exons,
                                          AnnotatedJunction & junction) {
    //skip single exon genes
    if(skip_single_exon_genes_ && exons.size() == 1) return false;
    bool junction_start = false;
    bool known_junction = false;
    //check if transcript overlaps with junction
    if(exons[0].start > junction.end &&
            exons[exons.size() - 1].end < junction.start)
        return false;
    for(std::size_t i = 0; i < exons.size(); i++) {
        if(exons[i].start > junction.end) {
            //No need to look any further
            //the rest of the exons are outside the junction
            break;
        }
        //known junction
        if(exons[i].end == junction.start &&
                exons[i + 1].start == junction.end) {
            junction.known_acceptor = true;
            junction.known_donor = true;
            junction.known_junction = true;
            known_junction = true;
        }
        else {
            if(!junction_start) {
                if(exons[i].end >= junction.start) {
                    junction_start = true;
                }
            }
            if(junction_start) {
                if(exons[i].start > junction.start &&
                        exons[i].end < junction.end) {
                    junction.exons_skipped.insert(exons[i].name);
                }
                if(exons[i].start > junction.start) {
                    junction.donors_skipped.insert(exons[i].start);
                }
                if(exons[i].end < junction.end) {
                    junction.acceptors_skipped.insert(exons[i].end);
                }
                if(exons[i].end == junction.start) {
                    junction.known_donor = true;
                }
                //TODO - check for last exon
                if(exons[i].start == junction.end) {
                    junction.known_acceptor = true;
                }
            }
        }
    }
    annotate_anchor(junction);
    return (junction.anchor != "N");
}

//Find overlap between transcript and junction on the negative strand,
//function returns true if either the acceptor or the donor is known
bool JunctionsAnnotator::overlap_ns(const vector<BED> & exons,
                                          AnnotatedJunction & junction) {
    //skip single exon genes
    if(skip_single_exon_genes_ && exons.size() == 1) return false;
    bool junction_start = false;
    bool known_junction = false;
    //check if transcript overlaps with junction
    if(exons[0].end < junction.start ||
            exons[exons.size() - 1].start > junction.end) {
        return known_junction;
    }
    for(std::size_t i = 0; i < exons.size(); i++) {
        if(exons[i].end < junction.start) {
            //No need to look any further
            //the rest of the exons are outside the junction
            break;
        }
        //Check if this is a known junction
        if(exons[i].start == junction.end &&
                exons[i + 1].end == junction.start) {
            junction.known_acceptor = true;
            junction.known_donor = true;
            junction.known_junction = true;
            known_junction = true;
        }
        else {
            if(!junction_start) {
                if(exons[i].start <= junction.end) {
                    junction_start = true;
                }
            }
            if(junction_start) {
                if(exons[i].start > junction.start &&
                        exons[i].end < junction.end) {
                    junction.exons_skipped.insert(exons[i].name);
                }
                if(exons[i].start > junction.start) {
                    junction.donors_skipped.insert(exons[i].start);
                }
                if(exons[i].end < junction.end) {
                    junction.acceptors_skipped.insert(exons[i].end);
                }
                if(exons[i].start == junction.end) {
                    junction.known_donor = true;
                }
                if(exons[i].end == junction.start) {
                    junction.known_acceptor = true;
                }
            }
        }
    }
    annotate_anchor(junction);
    return (junction.anchor != "N");
}

//Annotate the anchor i.e is this a known/novel donor-acceptor pair
void JunctionsAnnotator::annotate_anchor(AnnotatedJunction & junction) {
    junction.anchor = string("N");
    if(junction.known_junction) {
        junction.anchor = "DA";
    } else {
        if(junction.known_donor)
            if(junction.known_acceptor)
                junction.anchor = string("NDA");
            else
                junction.anchor = string("D");
        else if(junction.known_acceptor)
            junction.anchor = string("A");
    }
}

//Check for overlap between a transcript and junctions
//Check if the junction we saw is a known junction
//Calculate exons_skipped, donors_skipped, acceptors_skipped
void JunctionsAnnotator::check_for_overlap(string transcript_id, AnnotatedJunction & junction) {
    const vector<BED> & exons =
        gtf_.get_exons_from_transcript(transcript_id);
    if(!exons.size()) {
        throw runtime_error("Unexpected error. No exons for transcript "
                            + transcript_id);
    }
    string transcript_strand = exons[0].strand;
    //Make sure the strands of the junction and transcript match
    if(junction.strand != transcript_strand)
        return;
    //Remember exons are sorted from exon1 to last exon
    if(junction.strand == "+") {
        if(overlap_ps(exons, junction)) {
            junction.transcripts_overlap.insert(transcript_id);
            junction.genes_overlap.insert(
                    gtf_.get_gene_from_transcript(transcript_id));
        }
    } else if(junction.strand == "-") {
        if(overlap_ns(exons, junction)) {
            junction.transcripts_overlap.insert(transcript_id);
            junction.genes_overlap.insert(
                    gtf_.get_gene_from_transcript(transcript_id));
        }
    } else {
        throw runtime_error("\nUnknown strand " + junction.strand);
    }
    cerr << "\n\tDonors skipped " << junction.donors_skipped.size();
    cerr << "\n\tExons skipped " << junction.exons_skipped.size();
    cerr << "\n\tAcceptors skipped " << junction.acceptors_skipped.size();
    cerr << "\n\tSplice site " << junction.anchor;
}

//Annotate with gtf
//Takes a single junction BED and annotates with GTF
void JunctionsAnnotator::annotate_junction_with_gtf(AnnotatedJunction & j1) {
    //From BedTools
    BIN start_bin, end_bin;
    start_bin = (j1.start >> _binFirstShift);
    end_bin = ((j1.end-1) >> _binFirstShift);
    //We loop through each UCSC BIN level for feature A's chrom.
    //For each BIN, we loop through each B feature and add it to
    // hits if it meets all of the user's requests.
    for (BINLEVEL i = 0; i < _binLevels; ++i) {
        BIN offset = _binOffsetsExtended[i];
        for (BIN b = (start_bin + offset); b <= (end_bin + offset); ++b) {
            vector<string> transcripts = gtf_.transcripts_from_bin(j1.chrom, b);
            if(transcripts.size())
                for(std::size_t i = 0; i < transcripts.size(); i++)
                    check_for_overlap(transcripts[i], j1);
        }
        start_bin >>= _binNextShift;
        end_bin >>= _binNextShift;
    }
}

//Get the reference sequence at a particular coordinate
string JunctionsAnnotator::get_reference_sequence(string position) {
    int len;
    faidx_t *fai = fai_load(ref_.c_str());
    char *s = fai_fetch(fai, position.c_str(), &len);
    if(s == NULL)
        throw runtime_error("Unable to extract FASTA sequence "
                             "for position " + position);
    std::string seq(s);
    free(s);
    fai_destroy(fai);
    return seq;
}

//Get the name of the GTF file
string JunctionsAnnotator::gtf_file() {
    return gtf_.gtffile();
}

//Parse the options passed to this tool
int JunctionsAnnotator::parse_options(int argc, char *argv[]) {
    optind = 1; //Reset before parsing again.
    int c;
    while((c = getopt(argc, argv, "Eo:")) != -1) {
        switch(c) {
            case 'E':
                skip_single_exon_genes_ = false;
                break;
            case 'o':
                output_file_ = string(optarg);
                break;
            default:
                usage();
                throw runtime_error("\nError parsing inputs!");
        }
    }
    if(argc - optind >= 3) {
        junctions_.bedFile = string(argv[optind++]);
        ref_ = string(argv[optind++]);
        gtf_.set_gtffile(string(argv[optind++]));
    }
    if(optind < argc ||
       ref_ == "NA" ||
       junctions_.bedFile.empty() ||
       gtf_.gtffile().empty()) {
        usage();
        throw runtime_error("\nError parsing inputs!");
    }
    cerr << "\nReference: " << ref_;
    cerr << "\nGTF: " << gtf_.gtffile();
    cerr << "\nJunctions: " << junctions_.bedFile;
    if(skip_single_exon_genes_)
        cerr << "\nSkip single exon genes.";
    if(!output_file_.empty())
        cerr << "\nOutput file: " << output_file_;
    return 0;
}

//Usage statement for this tool
int JunctionsAnnotator::usage() {
    cout << "\nUsage:\t\t" << "regtools junctions annotate [options] junctions.bed ref.fa annotations.gtf";
    cout << "\nOptions:\t" << "-E include single exon genes";
    cout << "\n\t\t" << "-o Output file";
    cout << "\n";
    return 0;
}
<commit_msg>Catch and rethrow gtf parser exceptions.<commit_after>/*  junctions_annotator.cc -- class methods for `junctions annotate`

    Copyright (c) 2015, The Griffith Lab

    Author: Avinash Ramu <aramu@genome.wustl.edu>

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

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

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

#include <getopt.h>
#include <stdexcept>
#include <string>
#include "common.h"
#include "junctions_annotator.h"
#include "faidx.h"

using namespace std;

//Return stream to write output to
void JunctionsAnnotator::close_ofstream() {
    if(ofs_.is_open())
        ofs_.close();
}

//Return stream to write output to
//If output file is not empty, attempt to open
//If output file is empty, set to cout
void JunctionsAnnotator::set_ofstream_object(ofstream &out) {
    if(output_file_ == "NA") {
        copy_stream(cout, out);
        return;
    }
    ofs_.open(output_file_.c_str());
    if(!ofs_.is_open())
        throw runtime_error("Unable to open " +
                            output_file_);
    copy_stream(ofs_, out);
}

//Open junctions file
void JunctionsAnnotator::open_junctions() {
    junctions_.Open();
}

//Open junctions file
void JunctionsAnnotator::close_junctions() {
    junctions_.Close();
}

//Adjust the start and end of the junction
void JunctionsAnnotator::adjust_junction_ends(BED & line) {
    //Adjust the start and end with block sizes
    //The junction start is thick_start + block_size1
    //The junction end is thick_end - block_size2 + 1
    if(!line.fields.size() || line.fields[10].empty()) {
        stringstream position;
        position << line.chrom << ":" << line.start;
        throw runtime_error("Block sizes not found. Invalid line. " +
                            position.str());
    }
    string blocksize_field = line.fields[10];
    vector<int> block_sizes;
    Tokenize(blocksize_field, block_sizes, ',');
    line.start += block_sizes[0];
    line.end -= block_sizes[1] - 1;
}

//Get a single line from the junctions file
bool JunctionsAnnotator::get_single_junction(BED & line) {
    junctions_._status = BED_INVALID;
    if(junctions_.GetNextBed(line) && junctions_._status == BED_VALID) {
        adjust_junction_ends(line);
        return true;
    } else {
        return false;
    }
}

//Get the splice_site bases
bool JunctionsAnnotator::get_splice_site(AnnotatedJunction & line) {
    string position1 = line.chrom + ":" +
                      num_to_str(line.start + 1) + "-" + num_to_str(line.start + 2);
    string position2 = line.chrom + ":" +
                      num_to_str(line.end - 2) + "-" + num_to_str(line.end - 1);
    string seq1, seq2;
    try {
        seq1 = get_reference_sequence(position1);
        seq2 = get_reference_sequence(position2);
    } catch (const runtime_error& e) {
        throw e;
    }
    if(line.strand == "-") {
        seq1 = rev_comp(seq1);
        seq2 = rev_comp(seq2);
        line.splice_site = seq2 + "-" + seq1;
    } else {
        line.splice_site = seq1 + "-" + seq2;
    }
    return true;
}

//Extract gtf info
bool JunctionsAnnotator::read_gtf() {
    try {
        gtf_.create_transcript_map();
        gtf_.construct_junctions();
        gtf_.sort_exons_within_transcripts();
        gtf_.annotate_transcript_with_bins();
        //gtf_.print_transcripts();
    } catch (runtime_error e) {
        throw e;
    }
    return true;
}

//Find overlap between transcript and junction on the negative strand,
//function returns true if either the acceptor or the donor is known
bool JunctionsAnnotator::overlap_ps(const vector<BED>& exons,
                                          AnnotatedJunction & junction) {
    //skip single exon genes
    if(skip_single_exon_genes_ && exons.size() == 1) return false;
    bool junction_start = false;
    bool known_junction = false;
    //check if transcript overlaps with junction
    if(exons[0].start > junction.end &&
            exons[exons.size() - 1].end < junction.start)
        return false;
    for(std::size_t i = 0; i < exons.size(); i++) {
        if(exons[i].start > junction.end) {
            //No need to look any further
            //the rest of the exons are outside the junction
            break;
        }
        //known junction
        if(exons[i].end == junction.start &&
                exons[i + 1].start == junction.end) {
            junction.known_acceptor = true;
            junction.known_donor = true;
            junction.known_junction = true;
            known_junction = true;
        }
        else {
            if(!junction_start) {
                if(exons[i].end >= junction.start) {
                    junction_start = true;
                }
            }
            if(junction_start) {
                if(exons[i].start > junction.start &&
                        exons[i].end < junction.end) {
                    junction.exons_skipped.insert(exons[i].name);
                }
                if(exons[i].start > junction.start) {
                    junction.donors_skipped.insert(exons[i].start);
                }
                if(exons[i].end < junction.end) {
                    junction.acceptors_skipped.insert(exons[i].end);
                }
                if(exons[i].end == junction.start) {
                    junction.known_donor = true;
                }
                //TODO - check for last exon
                if(exons[i].start == junction.end) {
                    junction.known_acceptor = true;
                }
            }
        }
    }
    annotate_anchor(junction);
    return (junction.anchor != "N");
}

//Find overlap between transcript and junction on the negative strand,
//function returns true if either the acceptor or the donor is known
bool JunctionsAnnotator::overlap_ns(const vector<BED> & exons,
                                          AnnotatedJunction & junction) {
    //skip single exon genes
    if(skip_single_exon_genes_ && exons.size() == 1) return false;
    bool junction_start = false;
    bool known_junction = false;
    //check if transcript overlaps with junction
    if(exons[0].end < junction.start ||
            exons[exons.size() - 1].start > junction.end) {
        return known_junction;
    }
    for(std::size_t i = 0; i < exons.size(); i++) {
        if(exons[i].end < junction.start) {
            //No need to look any further
            //the rest of the exons are outside the junction
            break;
        }
        //Check if this is a known junction
        if(exons[i].start == junction.end &&
                exons[i + 1].end == junction.start) {
            junction.known_acceptor = true;
            junction.known_donor = true;
            junction.known_junction = true;
            known_junction = true;
        }
        else {
            if(!junction_start) {
                if(exons[i].start <= junction.end) {
                    junction_start = true;
                }
            }
            if(junction_start) {
                if(exons[i].start > junction.start &&
                        exons[i].end < junction.end) {
                    junction.exons_skipped.insert(exons[i].name);
                }
                if(exons[i].start > junction.start) {
                    junction.donors_skipped.insert(exons[i].start);
                }
                if(exons[i].end < junction.end) {
                    junction.acceptors_skipped.insert(exons[i].end);
                }
                if(exons[i].start == junction.end) {
                    junction.known_donor = true;
                }
                if(exons[i].end == junction.start) {
                    junction.known_acceptor = true;
                }
            }
        }
    }
    annotate_anchor(junction);
    return (junction.anchor != "N");
}

//Annotate the anchor i.e is this a known/novel donor-acceptor pair
void JunctionsAnnotator::annotate_anchor(AnnotatedJunction & junction) {
    junction.anchor = string("N");
    if(junction.known_junction) {
        junction.anchor = "DA";
    } else {
        if(junction.known_donor)
            if(junction.known_acceptor)
                junction.anchor = string("NDA");
            else
                junction.anchor = string("D");
        else if(junction.known_acceptor)
            junction.anchor = string("A");
    }
}

//Check for overlap between a transcript and junctions
//Check if the junction we saw is a known junction
//Calculate exons_skipped, donors_skipped, acceptors_skipped
void JunctionsAnnotator::check_for_overlap(string transcript_id, AnnotatedJunction & junction) {
    const vector<BED> & exons =
        gtf_.get_exons_from_transcript(transcript_id);
    if(!exons.size()) {
        throw runtime_error("Unexpected error. No exons for transcript "
                            + transcript_id);
    }
    string transcript_strand = exons[0].strand;
    //Make sure the strands of the junction and transcript match
    if(junction.strand != transcript_strand)
        return;
    //Remember exons are sorted from exon1 to last exon
    if(junction.strand == "+") {
        if(overlap_ps(exons, junction)) {
            junction.transcripts_overlap.insert(transcript_id);
            junction.genes_overlap.insert(
                    gtf_.get_gene_from_transcript(transcript_id));
        }
    } else if(junction.strand == "-") {
        if(overlap_ns(exons, junction)) {
            junction.transcripts_overlap.insert(transcript_id);
            junction.genes_overlap.insert(
                    gtf_.get_gene_from_transcript(transcript_id));
        }
    } else {
        throw runtime_error("\nUnknown strand " + junction.strand);
    }
    cerr << "\n\tDonors skipped " << junction.donors_skipped.size();
    cerr << "\n\tExons skipped " << junction.exons_skipped.size();
    cerr << "\n\tAcceptors skipped " << junction.acceptors_skipped.size();
    cerr << "\n\tSplice site " << junction.anchor;
}

//Annotate with gtf
//Takes a single junction BED and annotates with GTF
void JunctionsAnnotator::annotate_junction_with_gtf(AnnotatedJunction & j1) {
    //From BedTools
    BIN start_bin, end_bin;
    start_bin = (j1.start >> _binFirstShift);
    end_bin = ((j1.end-1) >> _binFirstShift);
    //We loop through each UCSC BIN level for feature A's chrom.
    //For each BIN, we loop through each B feature and add it to
    // hits if it meets all of the user's requests.
    for (BINLEVEL i = 0; i < _binLevels; ++i) {
        BIN offset = _binOffsetsExtended[i];
        for (BIN b = (start_bin + offset); b <= (end_bin + offset); ++b) {
            vector<string> transcripts = gtf_.transcripts_from_bin(j1.chrom, b);
            if(transcripts.size())
                for(std::size_t i = 0; i < transcripts.size(); i++)
                    check_for_overlap(transcripts[i], j1);
        }
        start_bin >>= _binNextShift;
        end_bin >>= _binNextShift;
    }
}

//Get the reference sequence at a particular coordinate
string JunctionsAnnotator::get_reference_sequence(string position) {
    int len;
    faidx_t *fai = fai_load(ref_.c_str());
    char *s = fai_fetch(fai, position.c_str(), &len);
    if(s == NULL)
        throw runtime_error("Unable to extract FASTA sequence "
                             "for position " + position);
    std::string seq(s);
    free(s);
    fai_destroy(fai);
    return seq;
}

//Get the name of the GTF file
string JunctionsAnnotator::gtf_file() {
    return gtf_.gtffile();
}

//Parse the options passed to this tool
int JunctionsAnnotator::parse_options(int argc, char *argv[]) {
    optind = 1; //Reset before parsing again.
    int c;
    while((c = getopt(argc, argv, "Eo:")) != -1) {
        switch(c) {
            case 'E':
                skip_single_exon_genes_ = false;
                break;
            case 'o':
                output_file_ = string(optarg);
                break;
            default:
                usage();
                throw runtime_error("\nError parsing inputs!");
        }
    }
    if(argc - optind >= 3) {
        junctions_.bedFile = string(argv[optind++]);
        ref_ = string(argv[optind++]);
        gtf_.set_gtffile(string(argv[optind++]));
    }
    if(optind < argc ||
       ref_ == "NA" ||
       junctions_.bedFile.empty() ||
       gtf_.gtffile().empty()) {
        usage();
        throw runtime_error("\nError parsing inputs!");
    }
    cerr << "\nReference: " << ref_;
    cerr << "\nGTF: " << gtf_.gtffile();
    cerr << "\nJunctions: " << junctions_.bedFile;
    if(skip_single_exon_genes_)
        cerr << "\nSkip single exon genes.";
    if(!output_file_.empty())
        cerr << "\nOutput file: " << output_file_;
    return 0;
}

//Usage statement for this tool
int JunctionsAnnotator::usage() {
    cout << "\nUsage:\t\t" << "regtools junctions annotate [options] junctions.bed ref.fa annotations.gtf";
    cout << "\nOptions:\t" << "-E include single exon genes";
    cout << "\n\t\t" << "-o Output file";
    cout << "\n";
    return 0;
}
<|endoftext|>


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

// SystemInfo_win.cpp: implementation of the Windows-specific parts of SystemInfo.h

#include "gpu_info_util/SystemInfo_internal.h"

#include "common/debug.h"
#include "common/string_utils.h"

// Windows.h needs to be included first
#include <windows.h>

#include <d3d10.h>
#include <dxgi.h>

#include <array>
#include <sstream>

namespace angle
{

namespace
{

bool GetDevicesFromDXGI(std::vector<GPUDeviceInfo> *devices)
{
    IDXGIFactory *factory;
    if (!SUCCEEDED(CreateDXGIFactory(__uuidof(IDXGIFactory), reinterpret_cast<void **>(&factory))))
    {
        return false;
    }

    UINT i                = 0;
    IDXGIAdapter *adapter = nullptr;
    while (factory->EnumAdapters(i++, &adapter) != DXGI_ERROR_NOT_FOUND)
    {
        DXGI_ADAPTER_DESC desc;
        adapter->GetDesc(&desc);

        LARGE_INTEGER umdVersion;
        if (adapter->CheckInterfaceSupport(__uuidof(ID3D10Device), &umdVersion) ==
            DXGI_ERROR_UNSUPPORTED)
        {
            adapter->Release();
            continue;
        }

        // The UMD driver version here is the same as in the registry except for the last number.
        uint64_t intVersion = umdVersion.QuadPart;
        std::ostringstream o;

        const uint64_t kMask = 0xFF;
        o << ((intVersion >> 48) & kMask) << ".";
        o << ((intVersion >> 32) & kMask) << ".";
        o << ((intVersion >> 16) & kMask) << ".";
        o << (intVersion & kMask);

        GPUDeviceInfo device;
        device.vendorId      = desc.VendorId;
        device.deviceId      = desc.DeviceId;
        device.driverVersion = o.str();

        devices->push_back(device);

        adapter->Release();
    }

    factory->Release();

    return (i > 0);
}

}  // anonymous namespace

bool GetSystemInfo(SystemInfo *info)
{
    if (!GetDevicesFromDXGI(&info->gpus))
    {
        return false;
    }

    if (info->gpus.size() == 0)
    {
        return false;
    }

    // Call GetDualGPUInfo to populate activeGPUIndex, isOptimus, and isAMDSwitchable.
    GetDualGPUInfo(info);

    // Override activeGPUIndex. The first index returned by EnumAdapters is the active GPU. We
    // can override the heuristic to find the active GPU
    info->activeGPUIndex = 0;

    // Override isOptimus. nvd3d9wrap.dll is loaded into all processes when Optimus is enabled.
    HMODULE nvd3d9wrap = GetModuleHandleW(L"nvd3d9wrap.dll");
    info->isOptimus    = nvd3d9wrap != nullptr;

    return true;
}

}  // namespace angle
<commit_msg>SystemInfo: Fix Windows driver version masking.<commit_after>//
// Copyright 2013 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

// SystemInfo_win.cpp: implementation of the Windows-specific parts of SystemInfo.h

#include "gpu_info_util/SystemInfo_internal.h"

#include "common/debug.h"
#include "common/string_utils.h"

// Windows.h needs to be included first
#include <windows.h>

#include <d3d10.h>
#include <dxgi.h>

#include <array>
#include <sstream>

namespace angle
{

namespace
{

bool GetDevicesFromDXGI(std::vector<GPUDeviceInfo> *devices)
{
    IDXGIFactory *factory;
    if (!SUCCEEDED(CreateDXGIFactory(__uuidof(IDXGIFactory), reinterpret_cast<void **>(&factory))))
    {
        return false;
    }

    UINT i                = 0;
    IDXGIAdapter *adapter = nullptr;
    while (factory->EnumAdapters(i++, &adapter) != DXGI_ERROR_NOT_FOUND)
    {
        DXGI_ADAPTER_DESC desc;
        adapter->GetDesc(&desc);

        LARGE_INTEGER umdVersion;
        if (adapter->CheckInterfaceSupport(__uuidof(ID3D10Device), &umdVersion) ==
            DXGI_ERROR_UNSUPPORTED)
        {
            adapter->Release();
            continue;
        }

        // The UMD driver version here is the same as in the registry except for the last number.
        uint64_t intVersion = umdVersion.QuadPart;
        std::ostringstream o;

        constexpr uint64_t kMask16 = std::numeric_limits<uint16_t>::max();
        o << ((intVersion >> 48) & kMask16) << ".";
        o << ((intVersion >> 32) & kMask16) << ".";
        o << ((intVersion >> 16) & kMask16) << ".";
        o << (intVersion & kMask16);

        GPUDeviceInfo device;
        device.vendorId      = desc.VendorId;
        device.deviceId      = desc.DeviceId;
        device.driverVersion = o.str();

        devices->push_back(device);

        adapter->Release();
    }

    factory->Release();

    return (i > 0);
}

}  // anonymous namespace

bool GetSystemInfo(SystemInfo *info)
{
    if (!GetDevicesFromDXGI(&info->gpus))
    {
        return false;
    }

    if (info->gpus.size() == 0)
    {
        return false;
    }

    // Call GetDualGPUInfo to populate activeGPUIndex, isOptimus, and isAMDSwitchable.
    GetDualGPUInfo(info);

    // Override activeGPUIndex. The first index returned by EnumAdapters is the active GPU. We
    // can override the heuristic to find the active GPU
    info->activeGPUIndex = 0;

    // Override isOptimus. nvd3d9wrap.dll is loaded into all processes when Optimus is enabled.
    HMODULE nvd3d9wrap = GetModuleHandleW(L"nvd3d9wrap.dll");
    info->isOptimus    = nvd3d9wrap != nullptr;

    return true;
}

}  // namespace angle
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: td.cxx,v $
 *
 *  $Revision: 1.1 $
 *
 *  last change: $Author: kso $ $Date: 2002-11-11 08:35:46 $
 *
 *  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 _STOC_RDBTDP_BASE_HXX
#include "base.hxx"
#endif

namespace stoc_rdbtdp
{
TypeDescriptionImpl::~TypeDescriptionImpl()
{
    g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
}

// XTypeDescription
//__________________________________________________________________________________________________
TypeClass TypeDescriptionImpl::getTypeClass()
    throw(::com::sun::star::uno::RuntimeException)
{
    return _eTypeClass;
}
//__________________________________________________________________________________________________
OUString TypeDescriptionImpl::getName()
    throw(::com::sun::star::uno::RuntimeException)
{
    return _aName;
}

}

<commit_msg>INTEGRATION: CWS jl3 (1.1.82); FILE MERGED 2003/12/19 11:32:28 dbo 1.1.82.1: #114506# cleanup<commit_after>/*************************************************************************
 *
 *  $RCSfile: td.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: kz $ $Date: 2004-03-25 14:47:43 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/

#include "osl/doublecheckedlocking.h"
#ifndef _STOC_RDBTDP_BASE_HXX
#include "base.hxx"
#endif

namespace stoc_rdbtdp
{

//------------------------------------------------------------------------------
::osl::Mutex & getMutex()
{
    static ::osl::Mutex * s_pmutex = 0;
    if (s_pmutex == 0)
    {
        ::osl::MutexGuard guard( ::osl::Mutex::getGlobalMutex() );
        if (s_pmutex == 0)
        {
            static ::osl::Mutex s_mutex;
            OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
            s_pmutex = &s_mutex;
        }
    }
    else
    {
        OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
    }
    return *s_pmutex;
}

TypeDescriptionImpl::~TypeDescriptionImpl()
{
    g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
}

// XTypeDescription
//__________________________________________________________________________________________________
TypeClass TypeDescriptionImpl::getTypeClass()
    throw(::com::sun::star::uno::RuntimeException)
{
    return _eTypeClass;
}
//__________________________________________________________________________________________________
OUString TypeDescriptionImpl::getName()
    throw(::com::sun::star::uno::RuntimeException)
{
    return _aName;
}

}

<|endoftext|>


<commit_before>/*
 * Copyright 2007-2017 Content Management AG
 * 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 "Internal.hxx"
#include "Request.hxx"
#include "http_headers.hxx"
#include "http_upgrade.hxx"
#include "direct.hxx"
#include "header_writer.hxx"
#include "GrowingBuffer.hxx"
#include "istream_gb.hxx"
#include "istream/istream_cat.hxx"
#include "istream/istream_chunked.hxx"
#include "istream/istream_dechunk.hxx"
#include "istream/istream_memory.hxx"
#include "istream/istream_string.hxx"
#include "http/Date.hxx"
#include "util/DecimalFormat.h"

#include <string.h>

bool
HttpServerConnection::MaybeSend100Continue()
{
    assert(IsValid());
    assert(request.read_state == Request::BODY);

    if (!request.expect_100_continue)
        return true;

    assert(!response.istream.IsDefined());

    request.expect_100_continue = false;

    /* this string is simple enough to expect that we don't need to
       check for partial writes, not before we have sent a single byte
       of response to the peer */
    static const char *const response_string = "HTTP/1.1 100 Continue\r\n\r\n";
    const size_t length = strlen(response_string);
    ssize_t nbytes = socket.Write(response_string, length);
    if (gcc_likely(nbytes == (ssize_t)length))
        return true;

    if (nbytes == WRITE_ERRNO)
        SocketErrorErrno("write error");
    else if (nbytes != WRITE_DESTROYED)
        SocketError("write error");
    return false;
}

static size_t
format_status_line(char *p, http_status_t status)
{
    assert(http_status_is_valid(status));

    const char *status_string = http_status_to_string(status);
    assert(status_string != nullptr);
    size_t length = strlen(status_string);

    memcpy(p, "HTTP/1.1 ", 9);
    memcpy(p + 9, status_string, length);
    length += 9;
    p[length++] = '\r';
    p[length++] = '\n';

    return length;
}

inline void
HttpServerConnection::SubmitResponse(http_status_t status,
                                     HttpHeaders &&headers,
                                     UnusedIstreamPtr _body)
{
    assert(http_status_is_valid(status));
    assert(score != HTTP_SERVER_NEW);
    assert(socket.IsConnected());
    assert(request.read_state == Request::END ||
           request.body_state == Request::BodyState::READING);

    if (http_status_is_success(status)) {
        if (score == HTTP_SERVER_FIRST)
            score = HTTP_SERVER_SUCCESS;
    } else {
        score = HTTP_SERVER_ERROR;
    }

    if (request.read_state == HttpServerConnection::Request::BODY &&
        /* if we didn't send "100 Continue" yet, we should do it now;
           we don't know if the request body will be used, but at
           least it hasn't been closed yet */
        !MaybeSend100Continue())
        return;

    auto &request_pool = request.request->pool;

    response.status = status;
    Istream *status_stream
        = istream_memory_new(&request_pool,
                             response.status_buffer,
                             format_status_line(response.status_buffer,
                                                status));

    /* how will we transfer the body?  determine length and
       transfer-encoding */

    auto *body = _body.Steal();
    const off_t content_length = body == nullptr
        ? 0 : body->GetAvailable(false);
    if (content_length == (off_t)-1) {
        /* the response length is unknown yet */
        assert(!http_status_is_empty(status));

        if (!http_method_is_empty(request.request->method) && keep_alive) {
            /* keep-alive is enabled, which means that we have to
               enable chunking */
            headers.Write("transfer-encoding", "chunked");

            /* optimized code path: if an istream_dechunked shall get
               chunked via istream_chunk, let's just skip both to
               reduce the amount of work and I/O we have to do */
            if (!istream_dechunk_check_verbatim(*body))
                body = istream_chunked_new(request_pool, *body);
        }
    } else if (http_status_is_empty(status)) {
        assert(content_length == 0);
    } else if (body != nullptr || !http_method_is_empty(request.request->method)) {
        /* fixed body size */
        format_uint64(response.content_length_buffer, content_length);
        headers.Write("content-length", response.content_length_buffer);
    }

    if (http_method_is_empty(request.request->method) && body != nullptr)
        istream_free_unused(&body);

    const bool upgrade = body != nullptr && http_is_upgrade(status, headers);
    if (upgrade) {
        headers.Write("connection", "upgrade");
        headers.MoveToBuffer("upgrade");
    } else if (!keep_alive && !request.http_1_0)
        headers.Write("connection", "close");

    GrowingBuffer headers3 = headers.ToBuffer();
    headers3.Write("\r\n", 2);
    Istream *header_stream = istream_gb_new(request_pool, std::move(headers3));

    response.length = - status_stream->GetAvailable(false)
        - header_stream->GetAvailable(false);

    /* make sure the access logger gets a negative value if there
       is no response body */
    response.length -= body == nullptr;

    body = istream_cat_new(request_pool, status_stream,
                           header_stream, body);

    SetResponseIstream(*body);
    TryWrite();
}

void
http_server_response(const HttpServerRequest *request,
                     http_status_t status,
                     HttpHeaders &&headers,
                     UnusedIstreamPtr body)
{
    auto &connection = request->connection;
    assert(connection.request.request == request);

    connection.SubmitResponse(status, std::move(headers), std::move(body));
}

void
http_server_simple_response(const HttpServerRequest &request,
                            http_status_t status, const char *location,
                            const char *msg)
{
    assert(unsigned(status) >= 200 && unsigned(status) < 600);

    if (http_status_is_empty(status))
        msg = nullptr;
    else if (msg == nullptr)
        msg = http_status_to_string(status);

    HttpHeaders headers(request.pool);

#ifndef NO_DATE_HEADER
    headers.Write("date", http_date_format(std::chrono::system_clock::now()));
#endif

    if (location != nullptr)
        headers.Write("location", location);

    Istream *body = nullptr;
    if (msg != nullptr) {
        headers.Write("content-type", "text/plain");
        body = istream_string_new(&request.pool, msg);
    }

    http_server_response(&request, status, std::move(headers),
                         UnusedIstreamPtr(body));
}

void
http_server_send_message(const HttpServerRequest *request,
                         http_status_t status, const char *msg)
{
    HttpHeaders headers(request->pool);

    headers.Write("content-type", "text/plain");

#ifndef NO_DATE_HEADER
    headers.Write("date", http_date_format(std::chrono::system_clock::now()));
#endif

    http_server_response(request, status, std::move(headers),
                         UnusedIstreamPtr(istream_string_new(&request->pool,
                                                             msg)));
}

void
http_server_send_redirect(const HttpServerRequest *request,
                          http_status_t status, const char *location,
                          const char *msg)
{
    assert(request != nullptr);
    assert(status >= 300 && status < 400);
    assert(location != nullptr);

    if (msg == nullptr)
        msg = "redirection";

    HttpHeaders headers(request->pool);

    headers.Write("content-type", "text/plain");
    headers.Write("location", location);

#ifndef NO_DATE_HEADER
    headers.Write("date", http_date_format(std::chrono::system_clock::now()));
#endif

    http_server_response(request, status, std::move(headers),
                         UnusedIstreamPtr(istream_string_new(&request->pool,
                                                             msg)));
}
<commit_msg>http_server: discard unused response body early<commit_after>/*
 * Copyright 2007-2017 Content Management AG
 * 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 "Internal.hxx"
#include "Request.hxx"
#include "http_headers.hxx"
#include "http_upgrade.hxx"
#include "direct.hxx"
#include "header_writer.hxx"
#include "GrowingBuffer.hxx"
#include "istream_gb.hxx"
#include "istream/istream_cat.hxx"
#include "istream/istream_chunked.hxx"
#include "istream/istream_dechunk.hxx"
#include "istream/istream_memory.hxx"
#include "istream/istream_string.hxx"
#include "http/Date.hxx"
#include "util/DecimalFormat.h"

#include <string.h>

bool
HttpServerConnection::MaybeSend100Continue()
{
    assert(IsValid());
    assert(request.read_state == Request::BODY);

    if (!request.expect_100_continue)
        return true;

    assert(!response.istream.IsDefined());

    request.expect_100_continue = false;

    /* this string is simple enough to expect that we don't need to
       check for partial writes, not before we have sent a single byte
       of response to the peer */
    static const char *const response_string = "HTTP/1.1 100 Continue\r\n\r\n";
    const size_t length = strlen(response_string);
    ssize_t nbytes = socket.Write(response_string, length);
    if (gcc_likely(nbytes == (ssize_t)length))
        return true;

    if (nbytes == WRITE_ERRNO)
        SocketErrorErrno("write error");
    else if (nbytes != WRITE_DESTROYED)
        SocketError("write error");
    return false;
}

static size_t
format_status_line(char *p, http_status_t status)
{
    assert(http_status_is_valid(status));

    const char *status_string = http_status_to_string(status);
    assert(status_string != nullptr);
    size_t length = strlen(status_string);

    memcpy(p, "HTTP/1.1 ", 9);
    memcpy(p + 9, status_string, length);
    length += 9;
    p[length++] = '\r';
    p[length++] = '\n';

    return length;
}

inline void
HttpServerConnection::SubmitResponse(http_status_t status,
                                     HttpHeaders &&headers,
                                     UnusedIstreamPtr _body)
{
    assert(http_status_is_valid(status));
    assert(score != HTTP_SERVER_NEW);
    assert(socket.IsConnected());
    assert(request.read_state == Request::END ||
           request.body_state == Request::BodyState::READING);

    if (http_status_is_success(status)) {
        if (score == HTTP_SERVER_FIRST)
            score = HTTP_SERVER_SUCCESS;
    } else {
        score = HTTP_SERVER_ERROR;
    }

    if (request.read_state == HttpServerConnection::Request::BODY &&
        /* if we didn't send "100 Continue" yet, we should do it now;
           we don't know if the request body will be used, but at
           least it hasn't been closed yet */
        !MaybeSend100Continue())
        return;

    auto &request_pool = request.request->pool;

    response.status = status;
    Istream *status_stream
        = istream_memory_new(&request_pool,
                             response.status_buffer,
                             format_status_line(response.status_buffer,
                                                status));

    /* how will we transfer the body?  determine length and
       transfer-encoding */

    const off_t content_length = _body ? _body.GetAvailable(false) : 0;
    if (http_method_is_empty(request.request->method))
        _body.Clear();

    auto *body = _body.Steal();
    if (content_length == (off_t)-1) {
        /* the response length is unknown yet */
        assert(!http_status_is_empty(status));

        if (body != nullptr && keep_alive) {
            /* keep-alive is enabled, which means that we have to
               enable chunking */
            headers.Write("transfer-encoding", "chunked");

            /* optimized code path: if an istream_dechunked shall get
               chunked via istream_chunk, let's just skip both to
               reduce the amount of work and I/O we have to do */
            if (!istream_dechunk_check_verbatim(*body))
                body = istream_chunked_new(request_pool, *body);
        }
    } else if (http_status_is_empty(status)) {
        assert(content_length == 0);
    } else if (body != nullptr) {
        /* fixed body size */
        format_uint64(response.content_length_buffer, content_length);
        headers.Write("content-length", response.content_length_buffer);
    }

    const bool upgrade = body != nullptr && http_is_upgrade(status, headers);
    if (upgrade) {
        headers.Write("connection", "upgrade");
        headers.MoveToBuffer("upgrade");
    } else if (!keep_alive && !request.http_1_0)
        headers.Write("connection", "close");

    GrowingBuffer headers3 = headers.ToBuffer();
    headers3.Write("\r\n", 2);
    Istream *header_stream = istream_gb_new(request_pool, std::move(headers3));

    response.length = - status_stream->GetAvailable(false)
        - header_stream->GetAvailable(false);

    /* make sure the access logger gets a negative value if there
       is no response body */
    response.length -= body == nullptr;

    body = istream_cat_new(request_pool, status_stream,
                           header_stream, body);

    SetResponseIstream(*body);
    TryWrite();
}

void
http_server_response(const HttpServerRequest *request,
                     http_status_t status,
                     HttpHeaders &&headers,
                     UnusedIstreamPtr body)
{
    auto &connection = request->connection;
    assert(connection.request.request == request);

    connection.SubmitResponse(status, std::move(headers), std::move(body));
}

void
http_server_simple_response(const HttpServerRequest &request,
                            http_status_t status, const char *location,
                            const char *msg)
{
    assert(unsigned(status) >= 200 && unsigned(status) < 600);

    if (http_status_is_empty(status))
        msg = nullptr;
    else if (msg == nullptr)
        msg = http_status_to_string(status);

    HttpHeaders headers(request.pool);

#ifndef NO_DATE_HEADER
    headers.Write("date", http_date_format(std::chrono::system_clock::now()));
#endif

    if (location != nullptr)
        headers.Write("location", location);

    Istream *body = nullptr;
    if (msg != nullptr) {
        headers.Write("content-type", "text/plain");
        body = istream_string_new(&request.pool, msg);
    }

    http_server_response(&request, status, std::move(headers),
                         UnusedIstreamPtr(body));
}

void
http_server_send_message(const HttpServerRequest *request,
                         http_status_t status, const char *msg)
{
    HttpHeaders headers(request->pool);

    headers.Write("content-type", "text/plain");

#ifndef NO_DATE_HEADER
    headers.Write("date", http_date_format(std::chrono::system_clock::now()));
#endif

    http_server_response(request, status, std::move(headers),
                         UnusedIstreamPtr(istream_string_new(&request->pool,
                                                             msg)));
}

void
http_server_send_redirect(const HttpServerRequest *request,
                          http_status_t status, const char *location,
                          const char *msg)
{
    assert(request != nullptr);
    assert(status >= 300 && status < 400);
    assert(location != nullptr);

    if (msg == nullptr)
        msg = "redirection";

    HttpHeaders headers(request->pool);

    headers.Write("content-type", "text/plain");
    headers.Write("location", location);

#ifndef NO_DATE_HEADER
    headers.Write("date", http_date_format(std::chrono::system_clock::now()));
#endif

    http_server_response(request, status, std::move(headers),
                         UnusedIstreamPtr(istream_string_new(&request->pool,
                                                             msg)));
}
<|endoftext|>