<commit_before>/** @file
    @brief Implementation

    @date 2016

    @author
    Sensics, Inc.
    <http://sensics.com>

*/

// Copyright 2016 Sensics, Inc.
//
// 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.

// Internal Includes
#include "ComputeDistortionMesh.h"
#include "UnstructuredMeshInterpolator.h"
#include "DistortionCorrectTextureCoordinate.h"

// Library/third-party includes
// - none

// Standard includes
#include <iostream>
#include <cmath>

namespace osvr {
namespace renderkit {

    DistortionMesh ComputeDistortionMesh(size_t eye, DistortionMeshType type, DistortionParameters distort, float overfillFactor) {
        DistortionMesh ret;

        // Check the validity of the parameters, based on the ones we're
        // using.
        if (distort.m_type ==
            DistortionParameters::rgb_symmetric_polynomials) {
            if (distort.m_distortionPolynomialRed.size() < 2) {
                std::cerr << "RenderManager::ComputeDistortionMesh: Need 2+ "
                    "red polynomial coefficients, found "
                    << distort.m_distortionPolynomialRed.size()
                    << std::endl;
                return ret;
            }
            if (distort.m_distortionPolynomialGreen.size() < 2) {
                std::cerr << "RenderManager::ComputeDistortionMesh: Need 2+ "
                    "green polynomial coefficients, found "
                    << distort.m_distortionPolynomialGreen.size()
                    << std::endl;
                return ret;
            }
            if (distort.m_distortionPolynomialBlue.size() < 2) {
                std::cerr << "RenderManager::ComputeDistortionMesh: Need 2+ "
                    "blue polynomial coefficients, found "
                    << distort.m_distortionPolynomialBlue.size()
                    << std::endl;
                return ret;
            }
            if (distort.m_distortionD.size() != 2) {
                std::cerr << "RenderManager::ComputeDistortionMesh: Need 2 "
                    "distortion coefficients, found "
                    << distort.m_distortionD.size() << std::endl;
                return ret;
            }
        } else if (distort.m_type ==
                 DistortionParameters::mono_point_samples) {
          // Nothing special to do, our interpolator is created below
        } else if (distort.m_type ==
                 DistortionParameters::rgb_point_samples) {
        } else {
            std::cerr << "RenderManager::ComputeDistortionMesh: Unrecognized "
                << "distortion parameter type" << std::endl;
            return ret;
        }

        // Make the interpolators to be used by this eye.
        std::vector< std::unique_ptr<UnstructuredMeshInterpolator> >
          interpolators;
        if (!makeUnstructuredMeshInterpolators(distort, eye,
            interpolators)) {
          std::cerr << "ComputeDistortionMesh: Could not "
            << "create mesh interpolators" << std::endl;
          return ret;
        }

        // See what kind of mesh we're supposed to produce.  Make the
        // appropriate one.
        switch (type) {
        case SQUARE: {
              // Figure out how many quads we should use in each dimension.  The
              // minimum is 1.  We have an even number in each.  There are two
              // triangles per quad.
              int quadsPerSide =
                  static_cast<int>(std::sqrt(distort.m_desiredTriangles / 2));
              if (quadsPerSide < 1) {
                  quadsPerSide = 1;
              }

              // Figure out how large each quad will be.  Recall that we're
              // covering a range of 2 (from -1 to 1) in each dimension, so the
              // quads will all be square in texture space.
              float quadSide = 2.0f / quadsPerSide;
              float quadTexSide = 1.0f / quadsPerSide;

              // Compute distorted texture coordinates and use those for each
              // vertex, with appropriate spatial location and texture
              // coordinates.

              auto const numVertsPerSide = quadsPerSide + 1;
              auto const numVertices = numVertsPerSide*numVertsPerSide;
              ret.vertices.reserve(numVertices);

              // Generate a grid of vertices with distorted texture coordinates
              for (int x = 0; x < numVertsPerSide; x++) {
                  float xPos = -1 + x * quadSide;
                  float xTex = x * quadTexSide;

                  for (int y = 0; y < numVertsPerSide; y++) {
                      float yPos = -1 + y * quadSide;
                      float yTex = y * quadTexSide;

                      Float2 pos = { xPos, yPos };
                      Float2 tex = { xTex, yTex };

                      ret.vertices.emplace_back(pos,
                          DistortionCorrectTextureCoordinate(eye, tex, distort, 0, overfillFactor, interpolators),
                          DistortionCorrectTextureCoordinate(eye, tex, distort, 1, overfillFactor, interpolators),
                          DistortionCorrectTextureCoordinate(eye, tex, distort, 2, overfillFactor, interpolators));
                  }
              }

              // Generate a pair of triangles for each quad, wound
              // counter-clockwise from the mesh grid

              // total of quadsPerSide * quadsPerSide * 6 vertices added: reserve
              // that space to avoid excess copying during mesh generation.
              ret.indices.reserve(quadsPerSide * quadsPerSide * 6);
              for (int x = 0; x < quadsPerSide; x++) {
                  for (int y = 0; y < quadsPerSide; y++) {
                      // Grid generated above is in column-major order
                      int indexLL = x*numVertsPerSide + y;
                      int indexHL = indexLL + numVertsPerSide;
                      int indexHH = indexLL + numVertsPerSide + 1;
                      int indexLH = indexLL + 1;

                      // Triangle 1
                      ret.indices.emplace_back(indexLL);
                      ret.indices.emplace_back(indexHL);
                      ret.indices.emplace_back(indexHH);

                      // Triangle 2
                      ret.indices.emplace_back(indexLL);
                      ret.indices.emplace_back(indexHH);
                      ret.indices.emplace_back(indexLH);
                  }
              }
          } break;
        case RADIAL: {
              std::cerr
                  << "RenderManager::ComputeDistortionMesh: Radial mesh type "
                  << "not yet implemented" << std::endl;

              // @todo Scale the aspect ratio of the rings around the center of
              // projection so that they will be round in the visible display.
          } break;
        default:
              std::cerr << "RenderManager::ComputeDistortionMesh: Unsupported "
                  "mesh type: "
                  << type << std::endl;
        }

        return ret;
    }

} // end namespace renderkit
} // end namespace osvr

<commit_msg>Fixed error messages.<commit_after>/** @file
    @brief Implementation

    @date 2016

    @author
    Sensics, Inc.
    <http://sensics.com>

*/

// Copyright 2016 Sensics, Inc.
//
// 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.

// Internal Includes
#include "ComputeDistortionMesh.h"
#include "UnstructuredMeshInterpolator.h"
#include "DistortionCorrectTextureCoordinate.h"

// Library/third-party includes
// - none

// Standard includes
#include <iostream>
#include <cmath>

namespace osvr {
namespace renderkit {

    DistortionMesh ComputeDistortionMesh(size_t eye, DistortionMeshType type, DistortionParameters distort, float overfillFactor) {
        DistortionMesh ret;

        // Check the validity of the parameters, based on the ones we're
        // using.
        if (distort.m_type ==
            DistortionParameters::rgb_symmetric_polynomials) {
            if (distort.m_distortionPolynomialRed.size() < 2) {
                std::cerr << "ComputeDistortionMesh: Need 2+ "
                    "red polynomial coefficients, found "
                    << distort.m_distortionPolynomialRed.size()
                    << std::endl;
                return ret;
            }
            if (distort.m_distortionPolynomialGreen.size() < 2) {
                std::cerr << "ComputeDistortionMesh: Need 2+ "
                    "green polynomial coefficients, found "
                    << distort.m_distortionPolynomialGreen.size()
                    << std::endl;
                return ret;
            }
            if (distort.m_distortionPolynomialBlue.size() < 2) {
                std::cerr << "ComputeDistortionMesh: Need 2+ "
                    "blue polynomial coefficients, found "
                    << distort.m_distortionPolynomialBlue.size()
                    << std::endl;
                return ret;
            }
            if (distort.m_distortionD.size() != 2) {
                std::cerr << "ComputeDistortionMesh: Need 2 "
                    "distortion coefficients, found "
                    << distort.m_distortionD.size() << std::endl;
                return ret;
            }
        } else if (distort.m_type ==
                 DistortionParameters::mono_point_samples) {
          // Nothing special to do, our interpolator is created below
        } else if (distort.m_type ==
                 DistortionParameters::rgb_point_samples) {
          // Nothing special to do, our interpolator is created below
        }
        else {
            std::cerr << "ComputeDistortionMesh: Unrecognized "
                << "distortion parameter type" << std::endl;
            return ret;
        }

        // Make the interpolators to be used by this eye.
        std::vector< std::unique_ptr<UnstructuredMeshInterpolator> >
          interpolators;
        if (!makeUnstructuredMeshInterpolators(distort, eye,
            interpolators)) {
          std::cerr << "ComputeDistortionMesh: Could not "
            << "create mesh interpolators" << std::endl;
          return ret;
        }

        // See what kind of mesh we're supposed to produce.  Make the
        // appropriate one.
        switch (type) {
        case SQUARE: {
              // Figure out how many quads we should use in each dimension.  The
              // minimum is 1.  We have an even number in each.  There are two
              // triangles per quad.
              int quadsPerSide =
                  static_cast<int>(std::sqrt(distort.m_desiredTriangles / 2));
              if (quadsPerSide < 1) {
                  quadsPerSide = 1;
              }

              // Figure out how large each quad will be.  Recall that we're
              // covering a range of 2 (from -1 to 1) in each dimension, so the
              // quads will all be square in texture space.
              float quadSide = 2.0f / quadsPerSide;
              float quadTexSide = 1.0f / quadsPerSide;

              // Compute distorted texture coordinates and use those for each
              // vertex, with appropriate spatial location and texture
              // coordinates.

              auto const numVertsPerSide = quadsPerSide + 1;
              auto const numVertices = numVertsPerSide*numVertsPerSide;
              ret.vertices.reserve(numVertices);

              // Generate a grid of vertices with distorted texture coordinates
              for (int x = 0; x < numVertsPerSide; x++) {
                  float xPos = -1 + x * quadSide;
                  float xTex = x * quadTexSide;

                  for (int y = 0; y < numVertsPerSide; y++) {
                      float yPos = -1 + y * quadSide;
                      float yTex = y * quadTexSide;

                      Float2 pos = { xPos, yPos };
                      Float2 tex = { xTex, yTex };

                      ret.vertices.emplace_back(pos,
                          DistortionCorrectTextureCoordinate(eye, tex, distort, 0, overfillFactor, interpolators),
                          DistortionCorrectTextureCoordinate(eye, tex, distort, 1, overfillFactor, interpolators),
                          DistortionCorrectTextureCoordinate(eye, tex, distort, 2, overfillFactor, interpolators));
                  }
              }

              // Generate a pair of triangles for each quad, wound
              // counter-clockwise from the mesh grid

              // total of quadsPerSide * quadsPerSide * 6 vertices added: reserve
              // that space to avoid excess copying during mesh generation.
              ret.indices.reserve(quadsPerSide * quadsPerSide * 6);
              for (int x = 0; x < quadsPerSide; x++) {
                  for (int y = 0; y < quadsPerSide; y++) {
                      // Grid generated above is in column-major order
                      int indexLL = x*numVertsPerSide + y;
                      int indexHL = indexLL + numVertsPerSide;
                      int indexHH = indexLL + numVertsPerSide + 1;
                      int indexLH = indexLL + 1;

                      // Triangle 1
                      ret.indices.emplace_back(indexLL);
                      ret.indices.emplace_back(indexHL);
                      ret.indices.emplace_back(indexHH);

                      // Triangle 2
                      ret.indices.emplace_back(indexLL);
                      ret.indices.emplace_back(indexHH);
                      ret.indices.emplace_back(indexLH);
                  }
              }
          } break;
        case RADIAL: {
              std::cerr
                  << "ComputeDistortionMesh: Radial mesh type "
                  << "not yet implemented" << std::endl;

              // @todo Scale the aspect ratio of the rings around the center of
              // projection so that they will be round in the visible display.
          } break;
        default:
              std::cerr << "ComputeDistortionMesh: Unsupported "
                  "mesh type: "
                  << type << std::endl;
        }

        return ret;
    }

} // end namespace renderkit
} // end namespace osvr

<|endoftext|>


<commit_before><commit_msg>Internal CI change for absl refactor<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Zubax, zubax.com
 * Distributed under the MIT License, available in the file LICENSE.
 * Author: Pavel Kirienko <pavel.kirienko@zubax.com>
 */

/*
 * Platform-independent I2C master implemented in software.
 * Sources:
 *      https://en.wikipedia.org/wiki/I%C2%B2C
 *      http://www.robot-electronics.co.uk/i2c-tutorial
 */

#pragma once

#include <zubax_chibios/os.hpp>
#include <unistd.h>
#include <cstdint>
#include <array>

namespace os
{
namespace software_i2c
{
/**
 * Generic bit-banging I2C master on bare GPIO.
 * The pins must be configured in open-drain mode, at high level by default.
 * This class automatically emits I2C stop condition and releases the pins when the instance is destroyed.
 *
 * All access must be done from regular threads outside of critical sections.
 *
 * All access is protected with a mutex, so that I2C transactions are atomic, and the class can be used from
 * multiple threads concurrently. If recursive mutexes are enabled, it is also possible to lock the bus
 * for multiple atomic transactions.
 *
 * Usage:
 *     Master master(GPIO_PORT_I2C_SCL, GPIO_PIN_I2C_SCL,
 *                   GPIO_PORT_I2C_SDA, GPIO_PIN_I2C_SDA);
 *     const std::array<std::uint8_t, 3> tx = { 1, 2, 3 };
 *     std::array<std::uint8_t, 5> rx;
 *     auto result = master.exchange(address, tx, rx);
 */
class Master final
{
public:
    enum class Result
    {
        OK,
        Timeout,
        ArbitrationLost,
        NACK
    };

    static constexpr std::uint32_t DefaultClockStretchTimeoutUSec = 10000;
    static constexpr std::uint32_t DefaultCycleDelayUSec = 10;

private:
    class I2CPin
    {
        ::ioportid_t const port_;
        const std::uint8_t pin_;

    public:
        I2CPin(::ioportid_t gpio_port, std::uint8_t gpio_pin) :
            port_(gpio_port), pin_(gpio_pin)
        {
        }

        ~I2CPin()
        {
            set();       // Returning to default state
        }

        void set()       { palSetPad(port_, pin_); }
        void clear()     { palClearPad(port_, pin_); }
        bool get() const { return palReadPad(port_, pin_); }
    };

    chibios_rt::Mutex mutex_;
    I2CPin scl_;
    I2CPin sda_;
    bool started_ = false;
    const std::uint32_t clock_stretch_timeout_usec_;
    const std::uint32_t delay_usec_;

    void delay() const
    {
        ::usleep(delay_usec_);
    }

    bool sclWait() const
    {
        const ::systime_t started_at = chVTGetSystemTimeX();
        while (!scl_.get())
        {
            chThdSleep(1);          // Sleeping one sys tick
            if (chVTTimeElapsedSinceX(started_at) > US2ST(clock_stretch_timeout_usec_))
            {
                return false;
            }
        }
        return true;
    }

    Result writeBit(bool bit)
    {
        if (bit)
        {
            sda_.set();
        }
        else
        {
            sda_.clear();
        }
        delay();
        scl_.set();
        delay();
        if (!sclWait())
        {
            return Result::Timeout;
        }
        if (bit && !sda_.get())
        {
            return Result::ArbitrationLost;
        }
        scl_.clear();
        return Result::OK;
    }

    Result readBit(bool& out_bit)
    {
        sda_.set();
        delay();
        scl_.set();
        if (!sclWait())
        {
            return Result::Timeout;
        }
        delay();
        out_bit = sda_.get();
        scl_.clear();
        return Result::OK;
    }

    /**
     * Generates I2C start on the bus.
     * If the bus has already been started, generates a repeated start sequence.
     */
    Result start()
    {
        sda_.set();
        delay();
        scl_.set();
        if (!sclWait())
        {
            return Result::Timeout;
        }
        delay();
        if (!sda_.get())
        {
            return Result::ArbitrationLost;
        }
        sda_.clear();
        delay();
        scl_.clear();
        delay();
        started_ = true;
        return Result::OK;
    }

    bool isStarted() const { return started_; }

    /**
     * Stops the bus.
     * If the bus has not been started, the function will generate an assertion failure.
     */
    Result stop()
    {
        assert(started_);
        sda_.clear();
        delay();
        scl_.set();
        if (!sclWait())
        {
            return Result::Timeout;
        }
        delay();
        sda_.set();
        delay();
        if (!sda_.get())
        {
            return Result::ArbitrationLost;
        }
        delay();
        started_ = false;
        return Result::OK;
    }

    Result writeByte(std::uint8_t byte)
    {
        assert(started_);
        for (std::uint8_t bit = 0; bit < 8; bit++)
        {
            auto res = writeBit((byte & 0x80) != 0);
            if (res != Result::OK)
            {
                return res;
            }
            byte = std::uint8_t(byte << 1U);
        }

        bool nack = false;
        auto res = readBit(nack);
        if (res != Result::OK)
        {
            return res;
        }

        return nack ? Result::NACK : Result::OK;
    }

    Result writeAddress7Bit(std::uint8_t address, bool read)
    {
        assert(address < 128U);
        address = std::uint8_t((address << 1U) | read);
        return writeByte(address);
    }

    Result readByte(std::uint8_t& out_byte, bool ack)
    {
        assert(started_);
        out_byte = 0;
        for (std::uint8_t i = 0; i < 8; i++)
        {
            bool bit = false;
            auto res = readBit(bit);
            if (res != Result::OK)
            {
                return res;
            }
            out_byte = std::uint8_t((out_byte << 1) | (bit ? 1U : 0U));
        }

        return writeBit(!ack);
    }

    // Master is non-copyable! Otherwise that breaks the mutex.
    Master(const Master&)  = delete;
    Master(const Master&&) = delete;
    Master& operator=(const Master&)  = delete;
    Master& operator=(const Master&&) = delete;

public:
    Master(::ioportid_t scl_port, std::uint8_t scl_pin,
           ::ioportid_t sda_port, std::uint8_t sda_pin,
           std::uint32_t arg_clock_stretch_timeout_usec = DefaultClockStretchTimeoutUSec,
           std::uint32_t arg_delay_usec = DefaultCycleDelayUSec) :
        scl_(scl_port, scl_pin),
        sda_(sda_port, sda_pin),
        clock_stretch_timeout_usec_(arg_clock_stretch_timeout_usec),
        delay_usec_(arg_delay_usec)
    { }

    /**
     * Destructor ensures that the bus is correctly stopped, and GPIO pins are correctly set to the high level.
     */
    ~Master()
    {
        if (started_)
        {
            (void)stop();
        }
    }

    /**
     * Modulates a bus reset sequence.
     * The reset sequence allows the master to bring the bus into a known state.
     * Its use is advised by some EEPROM memory chip vendors, for example, like ROHM BR24G128.
     */
    void reset()
    {
        static constexpr std::uint8_t MaxClockCycles = 30;
        static constexpr std::uint8_t AllowStopIfSDAHighAfterThisManyClockCycles = 14;

        ::os::MutexLocker bus_locker(mutex_);

        for (std::uint8_t i = 0; i < MaxClockCycles; i++)
        {
            bool the_bit = false;
            (void) readBit(the_bit);
            if ((i > AllowStopIfSDAHighAfterThisManyClockCycles) && the_bit)
            {
                break;
            }
        }

        delay();

        started_ = true;
        (void) stop();
    }

    /**
     * This function first writes bytes to the bus, if any, and then reads data back, if requested.
     * It will automatically generate start and stop sequences.
     */
    Result exchange(std::uint8_t address,
                    const void* tx_data, const std::uint16_t tx_size,
                          void* rx_data, const std::uint16_t rx_size)
    {
        ::os::MutexLocker bus_locker(mutex_);

        // This will ensure that the bus is correctly stopped at exit
        struct RAIIStopper
        {
            Master& owner_;
            RAIIStopper(Master& master) : owner_(master) { }
            ~RAIIStopper()
            {
                if (owner_.isStarted())
                {
                    (void)owner_.stop();
                }
            }
        } const volatile stopper(*this);

        // Writing
        if (tx_size > 0)
        {
            auto res = start();
            if (res != Result::OK)
            {
                return res;
            }

            res = writeAddress7Bit(address, false);
            if (res != Result::OK)
            {
                return res;
            }

            const std::uint8_t* p = reinterpret_cast<const std::uint8_t*>(tx_data);

            for (std::uint16_t i = 0; i < tx_size; i++)
            {
                res = writeByte(*p++);
                if (res != Result::OK)
                {
                    return res;
                }
            }
        }

        // Reading
        if (rx_size > 0)
        {
            auto res = start();
            if (res != Result::OK)
            {
                return res;
            }

            res = writeAddress7Bit(address, true);
            if (res != Result::OK)
            {
                return res;
            }

            std::uint8_t* p = reinterpret_cast<std::uint8_t*>(rx_data);
            std::uint16_t left = rx_size;

            while (left --> 0)
            {
                res = readByte(*p++, left > 0);
                if (res != Result::OK)
                {
                    return res;
                }
            }
        }

        return Result::OK;
    }

    /**
     * Safer wrapper over @ref exchange(). Usage:
     *     const std::array<std::uint8_t, 3> tx = { 1, 2, 3 };
     *     std::array<std::uint8_t, 5> rx;
     *     auto result = master.exchange(address, tx, rx);
     */
    template<std::size_t TxSize, std::size_t RxSize>
    Result exchange(std::uint8_t address,
                    const std::array<std::uint8_t, TxSize>& tx,
                          std::array<std::uint8_t, RxSize>& rx)
    {
        return exchange(address, tx.data(), TxSize, rx.data(), RxSize);
    }

#if CH_CFG_USE_MUTEXES_RECURSIVE
    /**
     * This RAII helper allows the user to lock the bus for multiple subsequent atomic transactions.
     * This class is only available if recursive mutexes are enabled.
     */
    class AtomicBusAccessLocker
    {
        ::os::MutexLocker mutex_locker_;
    public:
        explicit AtomicBusAccessLocker(Master& m) : mutex_locker_(m.mutex_) { }
    };
#endif
};

}
}
<commit_msg>Software I2C: using external delay function - that allows for faster clock rates<commit_after>/*
 * Copyright (c) 2016 Zubax, zubax.com
 * Distributed under the MIT License, available in the file LICENSE.
 * Author: Pavel Kirienko <pavel.kirienko@zubax.com>
 */

/*
 * Platform-independent I2C master implemented in software.
 * Sources:
 *      https://en.wikipedia.org/wiki/I%C2%B2C
 *      http://www.robot-electronics.co.uk/i2c-tutorial
 */

#pragma once

#include <zubax_chibios/os.hpp>
#include <functional>
#include <cstdint>
#include <array>

namespace os
{
namespace software_i2c
{
/**
 * Generic bit-banging I2C master on bare GPIO.
 * The pins must be configured in open-drain mode, at high level by default.
 * This class automatically emits I2C stop condition and releases the pins when the instance is destroyed.
 *
 * All access must be done from regular threads outside of critical sections.
 *
 * All access is protected with a mutex, so that I2C transactions are atomic, and the class can be used from
 * multiple threads concurrently. If recursive mutexes are enabled, it is also possible to lock the bus
 * for multiple atomic transactions.
 *
 * Usage:
 *     Master master(GPIO_PORT_I2C_SCL, GPIO_PIN_I2C_SCL,
 *                   GPIO_PORT_I2C_SDA, GPIO_PIN_I2C_SDA);
 *     const std::array<std::uint8_t, 3> tx = { 1, 2, 3 };
 *     std::array<std::uint8_t, 5> rx;
 *     auto result = master.exchange(address, tx, rx);
 */
class Master final
{
public:
    enum class Result
    {
        OK,
        Timeout,
        ArbitrationLost,
        NACK
    };

    static constexpr std::uint32_t DefaultClockStretchTimeoutUSec = 10000;

private:
    class I2CPin
    {
        ::ioportid_t const port_;
        const std::uint8_t pin_;

    public:
        I2CPin(::ioportid_t gpio_port, std::uint8_t gpio_pin) :
            port_(gpio_port), pin_(gpio_pin)
        {
        }

        ~I2CPin()
        {
            set();       // Returning to default state
        }

        void set()       { palSetPad(port_, pin_); }
        void clear()     { palClearPad(port_, pin_); }
        bool get() const { return palReadPad(port_, pin_); }
    };

    chibios_rt::Mutex mutex_;
    I2CPin scl_;
    I2CPin sda_;
    bool started_ = false;
    const std::function<void ()> delay_;
    const std::uint32_t clock_stretch_timeout_usec_;

    bool sclWait() const
    {
        const ::systime_t started_at = chVTGetSystemTimeX();
        while (!scl_.get())
        {
            chThdSleep(1);          // Sleeping one sys tick
            if (chVTTimeElapsedSinceX(started_at) > US2ST(clock_stretch_timeout_usec_))
            {
                return false;
            }
        }
        return true;
    }

    Result writeBit(bool bit)
    {
        if (bit)
        {
            sda_.set();
        }
        else
        {
            sda_.clear();
        }
        delay_();
        scl_.set();
        delay_();
        if (!sclWait())
        {
            return Result::Timeout;
        }
        if (bit && !sda_.get())
        {
            return Result::ArbitrationLost;
        }
        scl_.clear();
        return Result::OK;
    }

    Result readBit(bool& out_bit)
    {
        sda_.set();
        delay_();
        scl_.set();
        if (!sclWait())
        {
            return Result::Timeout;
        }
        delay_();
        out_bit = sda_.get();
        scl_.clear();
        return Result::OK;
    }

    /**
     * Generates I2C start on the bus.
     * If the bus has already been started, generates a repeated start sequence.
     */
    Result start()
    {
        sda_.set();
        delay_();
        scl_.set();
        if (!sclWait())
        {
            return Result::Timeout;
        }
        delay_();
        if (!sda_.get())
        {
            return Result::ArbitrationLost;
        }
        sda_.clear();
        delay_();
        scl_.clear();
        delay_();
        started_ = true;
        return Result::OK;
    }

    bool isStarted() const { return started_; }

    /**
     * Stops the bus.
     * If the bus has not been started, the function will generate an assertion failure.
     */
    Result stop()
    {
        assert(started_);
        sda_.clear();
        delay_();
        scl_.set();
        if (!sclWait())
        {
            return Result::Timeout;
        }
        delay_();
        sda_.set();
        delay_();
        if (!sda_.get())
        {
            return Result::ArbitrationLost;
        }
        delay_();
        started_ = false;
        return Result::OK;
    }

    Result writeByte(std::uint8_t byte)
    {
        assert(started_);
        for (std::uint8_t bit = 0; bit < 8; bit++)
        {
            auto res = writeBit((byte & 0x80) != 0);
            if (res != Result::OK)
            {
                return res;
            }
            byte = std::uint8_t(byte << 1U);
        }

        bool nack = false;
        auto res = readBit(nack);
        if (res != Result::OK)
        {
            return res;
        }

        return nack ? Result::NACK : Result::OK;
    }

    Result writeAddress7Bit(std::uint8_t address, bool read)
    {
        assert(address < 128U);
        address = std::uint8_t((address << 1U) | read);
        return writeByte(address);
    }

    Result readByte(std::uint8_t& out_byte, bool ack)
    {
        assert(started_);
        out_byte = 0;
        for (std::uint8_t i = 0; i < 8; i++)
        {
            bool bit = false;
            auto res = readBit(bit);
            if (res != Result::OK)
            {
                return res;
            }
            out_byte = std::uint8_t((out_byte << 1) | (bit ? 1U : 0U));
        }

        return writeBit(!ack);
    }

    // Master is non-copyable! Otherwise that breaks the mutex.
    Master(const Master&)  = delete;
    Master(const Master&&) = delete;
    Master& operator=(const Master&)  = delete;
    Master& operator=(const Master&&) = delete;

public:
    Master(::ioportid_t scl_port, std::uint8_t scl_pin,
           ::ioportid_t sda_port, std::uint8_t sda_pin,
           std::function<void ()> arg_cycle_delay,
           std::uint32_t arg_clock_stretch_timeout_usec = DefaultClockStretchTimeoutUSec) :
        scl_(scl_port, scl_pin),
        sda_(sda_port, sda_pin),
        delay_(arg_cycle_delay),
        clock_stretch_timeout_usec_(arg_clock_stretch_timeout_usec)
    {
        assert(delay_);
    }

    /**
     * Destructor ensures that the bus is correctly stopped, and GPIO pins are correctly set to the high level.
     */
    ~Master()
    {
        if (started_)
        {
            (void)stop();
        }
    }

    /**
     * Modulates a bus reset sequence.
     * The reset sequence allows the master to bring the bus into a known state.
     * Its use is advised by some EEPROM memory chip vendors, for example, like ROHM BR24G128.
     */
    void reset()
    {
        static constexpr std::uint8_t MaxClockCycles = 30;
        static constexpr std::uint8_t AllowStopIfSDAHighAfterThisManyClockCycles = 14;

        ::os::MutexLocker bus_locker(mutex_);

        for (std::uint8_t i = 0; i < MaxClockCycles; i++)
        {
            bool the_bit = false;
            (void) readBit(the_bit);
            if ((i > AllowStopIfSDAHighAfterThisManyClockCycles) && the_bit)
            {
                break;
            }
        }

        delay_();

        started_ = true;
        (void) stop();
    }

    /**
     * This function first writes bytes to the bus, if any, and then reads data back, if requested.
     * It will automatically generate start and stop sequences.
     */
    Result exchange(std::uint8_t address,
                    const void* tx_data, const std::uint16_t tx_size,
                          void* rx_data, const std::uint16_t rx_size)
    {
        ::os::MutexLocker bus_locker(mutex_);

        // This will ensure that the bus is correctly stopped at exit
        struct RAIIStopper
        {
            Master& owner_;
            RAIIStopper(Master& master) : owner_(master) { }
            ~RAIIStopper()
            {
                if (owner_.isStarted())
                {
                    (void)owner_.stop();
                }
            }
        } const volatile stopper(*this);

        // Writing
        if (tx_size > 0)
        {
            auto res = start();
            if (res != Result::OK)
            {
                return res;
            }

            res = writeAddress7Bit(address, false);
            if (res != Result::OK)
            {
                return res;
            }

            const std::uint8_t* p = reinterpret_cast<const std::uint8_t*>(tx_data);

            for (std::uint16_t i = 0; i < tx_size; i++)
            {
                res = writeByte(*p++);
                if (res != Result::OK)
                {
                    return res;
                }
            }
        }

        // Reading
        if (rx_size > 0)
        {
            auto res = start();
            if (res != Result::OK)
            {
                return res;
            }

            res = writeAddress7Bit(address, true);
            if (res != Result::OK)
            {
                return res;
            }

            std::uint8_t* p = reinterpret_cast<std::uint8_t*>(rx_data);
            std::uint16_t left = rx_size;

            while (left --> 0)
            {
                res = readByte(*p++, left > 0);
                if (res != Result::OK)
                {
                    return res;
                }
            }
        }

        return Result::OK;
    }

    /**
     * Safer wrapper over @ref exchange(). Usage:
     *     const std::array<std::uint8_t, 3> tx = { 1, 2, 3 };
     *     std::array<std::uint8_t, 5> rx;
     *     auto result = master.exchange(address, tx, rx);
     */
    template<std::size_t TxSize, std::size_t RxSize>
    Result exchange(std::uint8_t address,
                    const std::array<std::uint8_t, TxSize>& tx,
                          std::array<std::uint8_t, RxSize>& rx)
    {
        return exchange(address, tx.data(), TxSize, rx.data(), RxSize);
    }

#if CH_CFG_USE_MUTEXES_RECURSIVE
    /**
     * This RAII helper allows the user to lock the bus for multiple subsequent atomic transactions.
     * This class is only available if recursive mutexes are enabled.
     */
    class AtomicBusAccessLocker
    {
        ::os::MutexLocker mutex_locker_;
    public:
        explicit AtomicBusAccessLocker(Master& m) : mutex_locker_(m.mutex_) { }
    };
#endif
};

}
}
<|endoftext|>


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

namespace utl
{

//------------------------------------------------------------------------------
void SAL_CALL OInputStreamHelper::acquire() throw ()
{
    InputStreamHelper_Base::acquire();
}

//------------------------------------------------------------------------------
void SAL_CALL OInputStreamHelper::release() throw ()
{
    InputStreamHelper_Base::release();
}

//------------------------------------------------------------------------------
sal_Int32 SAL_CALL OInputStreamHelper::readBytes(staruno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
    throw(stario::NotConnectedException, stario::BufferSizeExceededException, stario::IOException, staruno::RuntimeException)
{
    if (!m_xLockBytes.Is())
        throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this));

    if (nBytesToRead < 0)
        throw stario::BufferSizeExceededException(::rtl::OUString(), static_cast<staruno::XWeak*>(this));

    ::osl::MutexGuard aGuard( m_aMutex );
    aData.realloc(nBytesToRead);

    sal_Size nRead;
    ErrCode nError = m_xLockBytes->ReadAt(m_nActPos, (void*)aData.getArray(), nBytesToRead, &nRead);
    // FIXME  nRead could be truncated on 64-bit arches
    m_nActPos += (sal_uInt32)nRead;

    if (nError != ERRCODE_NONE)
        throw stario::IOException(::rtl::OUString(), static_cast<staruno::XWeak*>(this));

    // adjust sequence if data read is lower than the desired data
    if (nRead < (sal_uInt32)nBytesToRead)
        aData.realloc( nRead );

    return nRead;
}

void SAL_CALL OInputStreamHelper::seek( sal_Int64 location ) throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    m_nActPos = location;
}

sal_Int64 SAL_CALL OInputStreamHelper::getPosition(  ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException)
{
    return m_nActPos;
}

sal_Int64 SAL_CALL OInputStreamHelper::getLength(  ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException)
{
    if (!m_xLockBytes.Is())
        return 0;

    ::osl::MutexGuard aGuard( m_aMutex );
    SvLockBytesStat aStat;
    m_xLockBytes->Stat( &aStat, SVSTATFLAG_DEFAULT );
    return aStat.nSize;
}

//------------------------------------------------------------------------------
sal_Int32 SAL_CALL OInputStreamHelper::readSomeBytes(staruno::Sequence< sal_Int8 >& aData,
                                                     sal_Int32 nMaxBytesToRead)
    throw (stario::NotConnectedException, stario::BufferSizeExceededException, stario::IOException, staruno::RuntimeException)
{
    // read all data desired
    return readBytes(aData, nMaxBytesToRead);
}

//------------------------------------------------------------------------------
void SAL_CALL OInputStreamHelper::skipBytes(sal_Int32 nBytesToSkip)
    throw (stario::NotConnectedException, stario::BufferSizeExceededException, stario::IOException, staruno::RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (!m_xLockBytes.Is())
        throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this));

    if (nBytesToSkip < 0)
        throw stario::BufferSizeExceededException(::rtl::OUString(), static_cast<staruno::XWeak*>(this));

    m_nActPos += nBytesToSkip;
}

//------------------------------------------------------------------------------
sal_Int32 SAL_CALL OInputStreamHelper::available()
    throw (stario::NotConnectedException, stario::IOException, staruno::RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (!m_xLockBytes.Is())
        throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this));

    return m_nAvailable;
}

//------------------------------------------------------------------------------
void SAL_CALL OInputStreamHelper::closeInput()
    throw (stario::NotConnectedException, stario::IOException, staruno::RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (!m_xLockBytes.Is())
        throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this));

    m_xLockBytes = NULL;
}

/*************************************************************************/
//------------------------------------------------------------------------------
void SAL_CALL OOutputStreamHelper::acquire() throw ()
{
    OutputStreamHelper_Base::acquire();
}

//------------------------------------------------------------------------------
void SAL_CALL OOutputStreamHelper::release() throw ()
{
    OutputStreamHelper_Base::release();
}
// stario::XOutputStream
//------------------------------------------------------------------------------
void SAL_CALL OOutputStreamHelper::writeBytes(const staruno::Sequence< sal_Int8 >& aData)
    throw (stario::NotConnectedException, stario::BufferSizeExceededException, stario::IOException, staruno::RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (!m_xLockBytes.Is())
        throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this));

    sal_Size nWritten;
    ErrCode nError = m_xLockBytes->WriteAt( m_nActPos, aData.getConstArray(), aData.getLength(), &nWritten );
    // FIXME  nWritten could be truncated on 64-bit arches
    m_nActPos += (sal_uInt32)nWritten;

    if (nError != ERRCODE_NONE ||
        nWritten != aData.getLength())
    {
        throw stario::IOException(::rtl::OUString(),static_cast<staruno::XWeak*>(this));
    }
}

//------------------------------------------------------------------
void SAL_CALL OOutputStreamHelper::flush()
    throw (stario::NotConnectedException, stario::BufferSizeExceededException, stario::IOException, staruno::RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (!m_xLockBytes.Is())
        throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this));

    ErrCode nError = m_xLockBytes->Flush();
    if (nError != ERRCODE_NONE)
        throw stario::IOException(::rtl::OUString(),static_cast<staruno::XWeak*>(this));
}

//------------------------------------------------------------------
void SAL_CALL OOutputStreamHelper::closeOutput(  )
    throw(stario::NotConnectedException, stario::BufferSizeExceededException, stario::IOException, staruno::RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (!m_xLockBytes.Is())
        throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this));

    m_xLockBytes = NULL;
}

} // namespace utl

<commit_msg>INTEGRATION: CWS warnings01 (1.5.16); FILE MERGED 2005/10/27 10:51:17 pl 1.5.16.2: #i55991# removed warnings for solaris platform 2005/10/21 09:49:00 dbo 1.5.16.1: #i53898# warning free code<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: streamhelper.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 14:09:03 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#include <unotools/streamhelper.hxx>
#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

namespace utl
{

//------------------------------------------------------------------------------
void SAL_CALL OInputStreamHelper::acquire() throw ()
{
    InputStreamHelper_Base::acquire();
}

//------------------------------------------------------------------------------
void SAL_CALL OInputStreamHelper::release() throw ()
{
    InputStreamHelper_Base::release();
}

//------------------------------------------------------------------------------
sal_Int32 SAL_CALL OInputStreamHelper::readBytes(staruno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
    throw(stario::NotConnectedException, stario::BufferSizeExceededException, stario::IOException, staruno::RuntimeException)
{
    if (!m_xLockBytes.Is())
        throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this));

    if (nBytesToRead < 0)
        throw stario::BufferSizeExceededException(::rtl::OUString(), static_cast<staruno::XWeak*>(this));

    ::osl::MutexGuard aGuard( m_aMutex );
    aData.realloc(nBytesToRead);

    sal_Size nRead;
    ErrCode nError = m_xLockBytes->ReadAt(m_nActPos, (void*)aData.getArray(), nBytesToRead, &nRead);
    // FIXME  nRead could be truncated on 64-bit arches
    m_nActPos += (sal_uInt32)nRead;

    if (nError != ERRCODE_NONE)
        throw stario::IOException(::rtl::OUString(), static_cast<staruno::XWeak*>(this));

    // adjust sequence if data read is lower than the desired data
    if (nRead < (sal_uInt32)nBytesToRead)
        aData.realloc( nRead );

    return nRead;
}

void SAL_CALL OInputStreamHelper::seek( sal_Int64 location ) throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    // cast is truncating, but position would be truncated as soon as
    // put into SvLockBytes anyway
    m_nActPos = sal::static_int_cast<sal_uInt32>(location);
}

sal_Int64 SAL_CALL OInputStreamHelper::getPosition(  ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException)
{
    return m_nActPos;
}

sal_Int64 SAL_CALL OInputStreamHelper::getLength(  ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException)
{
    if (!m_xLockBytes.Is())
        return 0;

    ::osl::MutexGuard aGuard( m_aMutex );
    SvLockBytesStat aStat;
    m_xLockBytes->Stat( &aStat, SVSTATFLAG_DEFAULT );
    return aStat.nSize;
}

//------------------------------------------------------------------------------
sal_Int32 SAL_CALL OInputStreamHelper::readSomeBytes(staruno::Sequence< sal_Int8 >& aData,
                                                     sal_Int32 nMaxBytesToRead)
    throw (stario::NotConnectedException, stario::BufferSizeExceededException, stario::IOException, staruno::RuntimeException)
{
    // read all data desired
    return readBytes(aData, nMaxBytesToRead);
}

//------------------------------------------------------------------------------
void SAL_CALL OInputStreamHelper::skipBytes(sal_Int32 nBytesToSkip)
    throw (stario::NotConnectedException, stario::BufferSizeExceededException, stario::IOException, staruno::RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (!m_xLockBytes.Is())
        throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this));

    if (nBytesToSkip < 0)
        throw stario::BufferSizeExceededException(::rtl::OUString(), static_cast<staruno::XWeak*>(this));

    m_nActPos += nBytesToSkip;
}

//------------------------------------------------------------------------------
sal_Int32 SAL_CALL OInputStreamHelper::available()
    throw (stario::NotConnectedException, stario::IOException, staruno::RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (!m_xLockBytes.Is())
        throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this));

    return m_nAvailable;
}

//------------------------------------------------------------------------------
void SAL_CALL OInputStreamHelper::closeInput()
    throw (stario::NotConnectedException, stario::IOException, staruno::RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (!m_xLockBytes.Is())
        throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this));

    m_xLockBytes = NULL;
}

/*************************************************************************/
//------------------------------------------------------------------------------
void SAL_CALL OOutputStreamHelper::acquire() throw ()
{
    OutputStreamHelper_Base::acquire();
}

//------------------------------------------------------------------------------
void SAL_CALL OOutputStreamHelper::release() throw ()
{
    OutputStreamHelper_Base::release();
}
// stario::XOutputStream
//------------------------------------------------------------------------------
void SAL_CALL OOutputStreamHelper::writeBytes(const staruno::Sequence< sal_Int8 >& aData)
    throw (stario::NotConnectedException, stario::BufferSizeExceededException, stario::IOException, staruno::RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (!m_xLockBytes.Is())
        throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this));

    sal_Size nWritten;
    ErrCode nError = m_xLockBytes->WriteAt( m_nActPos, aData.getConstArray(), aData.getLength(), &nWritten );
    // FIXME  nWritten could be truncated on 64-bit arches
    m_nActPos += (sal_uInt32)nWritten;

    if (nError != ERRCODE_NONE ||
        sal::static_int_cast<sal_Int32>(nWritten) != aData.getLength())
    {
        throw stario::IOException(::rtl::OUString(),static_cast<staruno::XWeak*>(this));
    }
}

//------------------------------------------------------------------
void SAL_CALL OOutputStreamHelper::flush()
    throw (stario::NotConnectedException, stario::BufferSizeExceededException, stario::IOException, staruno::RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (!m_xLockBytes.Is())
        throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this));

    ErrCode nError = m_xLockBytes->Flush();
    if (nError != ERRCODE_NONE)
        throw stario::IOException(::rtl::OUString(),static_cast<staruno::XWeak*>(this));
}

//------------------------------------------------------------------
void SAL_CALL OOutputStreamHelper::closeOutput(  )
    throw(stario::NotConnectedException, stario::BufferSizeExceededException, stario::IOException, staruno::RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (!m_xLockBytes.Is())
        throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this));

    m_xLockBytes = NULL;
}

} // namespace utl

<|endoftext|>


<commit_before>#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef struct {
    unsigned short width;
    unsigned short height;
    size_t rowSize;
    unsigned char *data;
} charData_t;
typedef struct {
    unsigned short lineHeight;
    unsigned short indent;
    unsigned char ascFont;
    unsigned char hzkFont;
    unsigned short fontWidth;
    unsigned short fontHeight;
    unsigned short fontAttr;
    short charSpace;
    charData_t *data;
} rowData_t;
typedef struct {
    unsigned short magicNum;
    unsigned long size;
    unsigned short res;
    unsigned short res2;
    unsigned long dataOffset;
    unsigned long headerSize;
    long width;
    long height;
    unsigned short planes;
    unsigned short bpp;
    unsigned long compression;
    unsigned long imageSize;
    long xres;
    long yres;
    unsigned long res3;
    unsigned long res4;
} bmpHeader_t;

#define BMP_PALETTE_SIZE (8)
#define BMP_HEADER_SIZE (40)

static uint8_t bitmapBuf[32768];

int checkEnv()
{
    union REGS regs;
    regs.x.ax = 0xdb00;
    int86(0x2f,&regs,&regs);
    if (regs.x.bx != 0x5450) {
        fputs("Please run UCDOS first.\n", stderr);
        return 1;
    }
    regs.h.ah = 0;
    regs.h.al = 0x1;
    int86(0x79,&regs,&regs);
    if (0 == (regs.x.flags & 0x40)) {
        fputs("Please run RDNFT.COM first.\n", stderr);
        return 1;
    }
    return 0;
}
charData_t* getCharBitmap(unsigned short ch, unsigned char fontAsc, unsigned char fontHzk,
    unsigned short width, unsigned short height, unsigned short attr)
{
    union REGS regs;
	struct SREGS sregs;
    size_t rowSize, dataSize;
    charData_t *res = NULL;
    struct Int7eParam_s{
        unsigned short ch;
        unsigned short font;
        unsigned short width;
        unsigned short height;
        unsigned short top;
        unsigned short bottom;
        unsigned short attr;
        unsigned short buflen;
    } param;
    param.ch = ch;
    param.font = ch <= 0xff ? fontAsc : fontHzk,
    param.width = ch <= 0xff ? (width >> 1) : width;
    param.height = height;
    param.top = 0;
    param.bottom = height - 1;
    param.attr = attr;
    param.buflen = sizeof(bitmapBuf);
    regs.x.si = FP_OFF(&param);
	regs.x.di = FP_OFF(bitmapBuf);
	sregs.ds = FP_SEG(&param);
	sregs.es = FP_SEG(bitmapBuf);
    int86x(0x7e, &regs, &regs, &sregs);
    rowSize = (param.width + 0x7) >> 3;
    dataSize = rowSize * param.height;
    res = (charData_t*)malloc(sizeof(charData_t) + dataSize);
    res->width = param.width;
    res->height = param.height;
    res->rowSize = rowSize;
    res->data = ((uint8_t*)res) + sizeof(charData_t);
    memcpy(res->data, bitmapBuf, dataSize);
    return res;
}
void drawPixels(unsigned char *dest, unsigned short pos,
    unsigned char *src, unsigned short length)
{
    unsigned short i, bias = pos & 0x7;
    unsigned char val, *pSrc = src, *pDest = dest + (pos >> 3);
    if (bias == 0) {
        while (length) {
            *pDest |= *pSrc;
            pSrc++;
            pDest++;
            length--;
        }
        return;
    }
    *pDest |= (*pSrc >> bias);
    pDest++;
    length--;
    while (length) {
        val = *pSrc << (8 - bias);
        pSrc++;
        val |= *pSrc >> bias;
        *pDest |= val;
        pDest++;
        length--;
    }
    *pDest |= (*pSrc << (8 - bias));
}
void writeBMP(FILE *fp, charData_t *charData[], short charspc)
{
    charData_t **pChar = NULL;
    unsigned short imgWidth = 0, imgHeight = 0, x, y;
    size_t rowBytes = 0;
    unsigned char *bmpData = NULL, *pBmp = NULL;
    bmpHeader_t header;

    // Calculate width and height
    for (pChar = charData; *pChar != NULL; pChar++) {
        unsigned short charWidth = (*pChar)->width;
        if (imgHeight < (*pChar)->height) {
            imgHeight = (*pChar)->height;
        }
        imgWidth += charWidth;
        if (*(pChar + 1) == NULL) {
            continue;
        }
        if (charspc < 0 && -charspc >= charWidth) {
           imgWidth -= charWidth;
        } else {
           imgWidth += charspc;
        }
    }

    // Prepare bitmap data for BMP
    rowBytes = ((imgWidth + 0x1f) >> 5) << 2;
    bmpData = (unsigned char *)calloc(rowBytes, imgHeight);
    if (NULL == bmpData) {
        fputs("Failed to allocate mem for BMP.\n", stderr);
        return;
    }
    x = 0;
    for (pChar = charData; *pChar != NULL; pChar++) {
        unsigned short charWidth = (*pChar)->width;
        for (y = 0; y < (*pChar)->height; y++) {
            drawPixels(bmpData + y * rowBytes, x,
                (*pChar)->data + y * (*pChar)->rowSize, (*pChar)->rowSize);
        }
        x += charWidth;
        if (*(pChar + 1) == NULL) {
            continue;
        }
        if (charspc < 0 && -charspc >= charWidth) {
           x -= charWidth;
        } else {
           x += charspc;
        }
    }

    // Write to bmp
    header.magicNum = 0x4d42;
    header.size = sizeof(bmpHeader_t) + BMP_PALETTE_SIZE +
        (unsigned long)rowBytes * (unsigned long)imgHeight;
    header.res = header.res2 = 0;
    header.dataOffset = sizeof(bmpHeader_t) + BMP_PALETTE_SIZE;
    header.headerSize = BMP_HEADER_SIZE;
    header.width = imgWidth;
    header.height = imgHeight;
    header.planes = 1;
    header.bpp = 1;
    header.compression = 0;
    header.imageSize = (unsigned long)rowBytes * (unsigned long)imgHeight;
    header.xres = header.yres = 72;
    header.res3 = header.res4 = 0;
    fwrite(&header, sizeof(header), 1, fp);
    fwrite("\0\0\0\0\xff\xff\xff\xff", BMP_PALETTE_SIZE, 1, fp);
    for (y = imgHeight; y > 0; y--) {
        fwrite(bmpData + (y - 1) * rowBytes, rowBytes, 1, fp);
    }
    free(bmpData);
}
int main(int argc, char *argv[])
{
    unsigned short ascfont, hzkfont, width, height;
    short charspc;
    charData_t *charData[512];
    size_t charDataLen = 0;
    int i;
    char *p;
    FILE *target = NULL;

    if (argc < 4) {
        fputs("Usage: TEXT2BMP.EXE ascfont,hzkfont,width,height,space text bmpfile.bmp\n", stderr);
        return 1;
    }
    if (checkEnv() != 0) {
        return 2;
    }
    if (5 != sscanf(argv[1], "%u,%u,%u,%u,%d", &ascfont, &hzkfont, &width, &height, &charspc)) {
        fputs("Failed to specify font format.\n", stderr);
        return 3;
    }
    target = fopen(argv[3], "wb");
    if (NULL == target) {
        fputs("Failed to open target file.\n", stderr);
        return 4;
    }

    // Get bitmap for each character
    for (p = argv[2]; *p != '\0'; p++) {
         unsigned short chData = *p;
         if (chData > 0x7f) {
             chData <<= 8;
             p++;
             chData |= *p;
         }
         charData[charDataLen] = getCharBitmap(chData, ascfont, hzkfont, width, height, 1);
         charDataLen++;
    }
    charData[charDataLen] = NULL;
    writeBMP(target, charData, charspc);

    // Clean up
    for (i = 0; i < charDataLen; i++) {
        free(charData[i]);
    }
    fclose(target);
    return 0;
}
<commit_msg>TEXT2BMP.C updated args<commit_after>#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef struct {
    unsigned short width;
    unsigned short height;
    size_t rowSize;
    unsigned char *data;
} charData_t;
typedef struct {
    unsigned short lineHeight;
    unsigned short indent;
    unsigned char ascFont;
    unsigned char hzkFont;
    unsigned short fontWidth;
    unsigned short fontHeight;
    unsigned short fontAttr;
    short charSpace;
    charData_t *data;
} rowData_t;
typedef struct {
    unsigned short magicNum;
    unsigned long size;
    unsigned short res;
    unsigned short res2;
    unsigned long dataOffset;
    unsigned long headerSize;
    long width;
    long height;
    unsigned short planes;
    unsigned short bpp;
    unsigned long compression;
    unsigned long imageSize;
    long xres;
    long yres;
    unsigned long res3;
    unsigned long res4;
} bmpHeader_t;

#define BMP_PALETTE_SIZE (8)
#define BMP_HEADER_SIZE (40)

static uint8_t bitmapBuf[32768];

int checkEnv()
{
    union REGS regs;
    regs.x.ax = 0xdb00;
    int86(0x2f,&regs,&regs);
    if (regs.x.bx != 0x5450) {
        fputs("Please run UCDOS first.\n", stderr);
        return 1;
    }
    regs.h.ah = 0;
    regs.h.al = 0x1;
    int86(0x79,&regs,&regs);
    if (0 == (regs.x.flags & 0x40)) {
        fputs("Please run RDNFT.COM first.\n", stderr);
        return 1;
    }
    return 0;
}
charData_t* getCharBitmap(unsigned short ch, unsigned char fontAsc, unsigned char fontHzk,
    unsigned short width, unsigned short height, unsigned short attr)
{
    union REGS regs;
	struct SREGS sregs;
    size_t rowSize, dataSize;
    charData_t *res = NULL;
    struct Int7eParam_s{
        unsigned short ch;
        unsigned short font;
        unsigned short width;
        unsigned short height;
        unsigned short top;
        unsigned short bottom;
        unsigned short attr;
        unsigned short buflen;
    } param;
    param.ch = ch;
    param.font = ch <= 0xff ? fontAsc : fontHzk,
    param.width = ch <= 0xff ? (width >> 1) : width;
    param.height = height;
    param.top = 0;
    param.bottom = height - 1;
    param.attr = attr;
    param.buflen = sizeof(bitmapBuf);
    regs.x.si = FP_OFF(&param);
	regs.x.di = FP_OFF(bitmapBuf);
	sregs.ds = FP_SEG(&param);
	sregs.es = FP_SEG(bitmapBuf);
    int86x(0x7e, &regs, &regs, &sregs);
    rowSize = (param.width + 0x7) >> 3;
    dataSize = rowSize * param.height;
    res = (charData_t*)malloc(sizeof(charData_t) + dataSize);
    res->width = param.width;
    res->height = param.height;
    res->rowSize = rowSize;
    res->data = ((uint8_t*)res) + sizeof(charData_t);
    memcpy(res->data, bitmapBuf, dataSize);
    return res;
}
void drawPixels(unsigned char *dest, unsigned short pos,
    unsigned char *src, unsigned short length)
{
    unsigned short i, bias = pos & 0x7;
    unsigned char val, *pSrc = src, *pDest = dest + (pos >> 3);
    if (bias == 0) {
        while (length) {
            *pDest |= *pSrc;
            pSrc++;
            pDest++;
            length--;
        }
        return;
    }
    *pDest |= (*pSrc >> bias);
    pDest++;
    length--;
    while (length) {
        val = *pSrc << (8 - bias);
        pSrc++;
        val |= *pSrc >> bias;
        *pDest |= val;
        pDest++;
        length--;
    }
    *pDest |= (*pSrc << (8 - bias));
}
void writeBMP(FILE *fp, charData_t *charData[], short charspc)
{
    charData_t **pChar = NULL;
    unsigned short imgWidth = 0, imgHeight = 0, x, y;
    size_t rowBytes = 0;
    unsigned char *bmpData = NULL, *pBmp = NULL;
    bmpHeader_t header;

    // Calculate width and height
    for (pChar = charData; *pChar != NULL; pChar++) {
        unsigned short charWidth = (*pChar)->width;
        if (imgHeight < (*pChar)->height) {
            imgHeight = (*pChar)->height;
        }
        imgWidth += charWidth;
        if (*(pChar + 1) == NULL) {
            continue;
        }
        if (charspc < 0 && -charspc >= charWidth) {
           imgWidth -= charWidth;
        } else {
           imgWidth += charspc;
        }
    }

    // Prepare bitmap data for BMP
    rowBytes = ((imgWidth + 0x1f) >> 5) << 2;
    bmpData = (unsigned char *)calloc(rowBytes, imgHeight);
    if (NULL == bmpData) {
        fputs("Failed to allocate mem for BMP.\n", stderr);
        return;
    }
    x = 0;
    for (pChar = charData; *pChar != NULL; pChar++) {
        unsigned short charWidth = (*pChar)->width;
        for (y = 0; y < (*pChar)->height; y++) {
            drawPixels(bmpData + y * rowBytes, x,
                (*pChar)->data + y * (*pChar)->rowSize, (*pChar)->rowSize);
        }
        x += charWidth;
        if (*(pChar + 1) == NULL) {
            continue;
        }
        if (charspc < 0 && -charspc >= charWidth) {
           x -= charWidth;
        } else {
           x += charspc;
        }
    }

    // Write to bmp
    header.magicNum = 0x4d42;
    header.size = sizeof(bmpHeader_t) + BMP_PALETTE_SIZE +
        (unsigned long)rowBytes * (unsigned long)imgHeight;
    header.res = header.res2 = 0;
    header.dataOffset = sizeof(bmpHeader_t) + BMP_PALETTE_SIZE;
    header.headerSize = BMP_HEADER_SIZE;
    header.width = imgWidth;
    header.height = imgHeight;
    header.planes = 1;
    header.bpp = 1;
    header.compression = 0;
    header.imageSize = (unsigned long)rowBytes * (unsigned long)imgHeight;
    header.xres = header.yres = 72;
    header.res3 = header.res4 = 0;
    fwrite(&header, sizeof(header), 1, fp);
    fwrite("\0\0\0\0\xff\xff\xff\xff", BMP_PALETTE_SIZE, 1, fp);
    for (y = imgHeight; y > 0; y--) {
        fwrite(bmpData + (y - 1) * rowBytes, rowBytes, 1, fp);
    }
    free(bmpData);
}
int main(int argc, char *argv[])
{
    unsigned short ascfont, hzkfont, width, height, attr;
    short charspc;
    charData_t *charData[512];
    size_t charDataLen = 0;
    int i;
    char *p;
    FILE *target = NULL;

    if (argc < 4) {
        fputs("Usage:\nTEXT2PIC.EXE out.bmp \
ascfont,hzkfont,w,h,space,attr text1 text2 ...\n", stderr);
        return 1;
    }
    if (checkEnv() != 0) {
        return 2;
    }
    if (6 != sscanf(argv[2], "%u,%u,%u,%u,%d,%u",
        &ascfont, &hzkfont, &width, &height, &charspc, &attr)) {
        fputs("Failed to specify font format.\n", stderr);
        return 3;
    }
    target = fopen(argv[1], "wb");
    if (NULL == target) {
        fputs("Failed to open target file.\n", stderr);
        return 4;
    }

    // Get bitmap for each character
    for (i = 3; i < argc; i++) {
        if (i != 3) {
            charData[charDataLen] = getCharBitmap(' ', ascfont, hzkfont,
                 width, height, attr);
            charDataLen++;
        }
        for (p = argv[i]; *p != '\0'; p++) {
             unsigned short chData = *p;
             if (chData > 0x7f) {
                 chData <<= 8;
                 p++;
                 chData |= *p;
             }
             charData[charDataLen] = getCharBitmap(chData, ascfont, hzkfont,
                 width, height, attr);
             charDataLen++;
         }
    }
    charData[charDataLen] = NULL;
    writeBMP(target, charData, charspc);

    // Clean up
    for (i = 0; i < charDataLen; i++) {
        free(charData[i]);
    }
    fclose(target);
    return 0;
}
<|endoftext|>


<commit_before>#include "BencodeParser.h"
#include <algorithm>
#include "..\Core\Logging.h"

#define PARSER_LOG(x) WRITE_LOG(LogTypeBencodeParser, x)

bool mtt::BencodeParser::parse(const uint8_t* data, size_t length)
{
	deep = 0;
	objects.clear();

	uint32_t reserveSize = length < 200 ? uint32_t(length*0.2f) : std::min(uint32_t(2000), uint32_t(40 + length/500));
	objects.reserve(reserveSize);

	bodyEnd = (const char*)data + length;
	bodyStart = (const char*)data;
	auto parserEnd = bodyStart;

	internalParse(&parserEnd);

	remainingData = parserEnd >= bodyEnd ? 0 : (length - (parserEnd - (const char*)data));
	bodyEnd = parserEnd;

	return getRoot() != nullptr;
}

inline bool IS_NUM_CHAR(char c) { return ((c >= '0') && (c <= '9')); }

mtt::BencodeParser::Object* mtt::BencodeParser::internalParse(const char** body)
{
	Object* obj = nullptr;
	char c = **body;

	if (IS_NUM_CHAR(c))
	{
		obj = parseString(body);
	}
	else if (c == 'i')
	{
		obj = parseInt(body);
	}
	else if (c == 'l')
	{
		obj = parseList(body);
	}
	else if (c == 'd')
	{
		obj = parseDictionary(body);
	}
	else
		parseError(body);

	return obj;
}

void mtt::BencodeParser::parseError(const char** body)
{
	PARSER_LOG("PARSE ERROR character " << **body);
	*body = bodyEnd;
}

#define NOT_END_OF_ELEMENTS (**body != 'e' && (*body < bodyEnd))

mtt::BencodeParser::Object* mtt::BencodeParser::parseList(const char** body)
{
	PARSER_LOG("List start " << deep);

	(*body)++;
	deep++;

	int rootId = (int)objects.size();
	objects.emplace_back(mtt::BencodeParser::Object());
	objects.back().info.type = Object::Item::List;

	int count = 0;
	while (NOT_END_OF_ELEMENTS)
	{
		auto objPos = (uint16_t)objects.size();
		auto o = internalParse(body);

		if (o)
		{
			o->info.nextSiblingOffset = NOT_END_OF_ELEMENTS ? (uint16_t)objects.size() - objPos : 0;
			count++;
		}
	}

	(*body)++;
	deep--;

	objects[rootId].info.size = count;
	objects[rootId].info.nextSiblingOffset = NOT_END_OF_ELEMENTS ? (uint16_t)objects.size() - rootId : 0;

	PARSER_LOG("List end " << deep);

	return &objects[rootId];
}

mtt::BencodeParser::Object* mtt::BencodeParser::parseDictionary(const char** body)
{
	PARSER_LOG("Dictionary start" << deep);

	(*body)++;
	deep++;

	int rootId = (int)objects.size();
	objects.emplace_back(mtt::BencodeParser::Object());
	objects.back().info.type = Object::Item::Dictionary;

	int count = 0;
	while (NOT_END_OF_ELEMENTS)
	{
		auto s = parseString(body);

		if (s)
		{
			auto objPos = (uint16_t)objects.size();
			auto o = internalParse(body);

			if (o)
			{
				objects[objPos - 1].info.nextSiblingOffset = 1;
				o->info.nextSiblingOffset = NOT_END_OF_ELEMENTS ? (uint16_t)objects.size() - objPos : 0;
				count++;
			}
			else
				count = 0;
		}
	}

	(*body)++;
	deep--;

	objects[rootId].info.size = count;
	objects[rootId].info.nextSiblingOffset = NOT_END_OF_ELEMENTS ? (uint16_t)objects.size() - rootId : 0;

	PARSER_LOG("Dictionary end" << deep);

	return &objects[rootId];
}

mtt::BencodeParser::Object* mtt::BencodeParser::parseString(const char** body)
{
	mtt::BencodeParser::Object obj;
	char* endPtr = 0;
	obj.info.size = strtol(*body, &endPtr, 10);
	*body = endPtr;

	if (**body != ':' || (bodyEnd - *body) < obj.info.size)
	{
		parseError(body);
		return nullptr;
	}

	(*body)++;

	obj.info.type = Object::Item::Text;
	obj.info.data = *body;
	(*body) += obj.info.size;

	PARSER_LOG("String " << std::string(obj.info.data, obj.info.size));

	objects.push_back(obj);
	return &objects.back();
}

mtt::BencodeParser::Object* mtt::BencodeParser::parseInt(const char** body)
{
	(*body)++;

	mtt::BencodeParser::Object obj;
	obj.info.data = *body;

	while ((IS_NUM_CHAR(**body) || (**body == '-' && obj.info.size == 0)) && *body != bodyEnd)
	{
		obj.info.size++;
		(*body)++;
	}

	if (**body != 'e')
	{
		parseError(body);
		return nullptr;
	}

	(*body)++;

	obj.info.type = Object::Item::Number;
	PARSER_LOG("Number " << std::string(obj.info.data, obj.info.size));

	objects.push_back(obj);
	return &objects.back();
}

mtt::BencodeParser::Object* mtt::BencodeParser::getRoot()
{
	return objects.empty() ? nullptr : &objects[0];
}

const mtt::BencodeParser::Object* mtt::BencodeParser::Object::getDictItem(const char* name) const
{
	auto obj = getFirstItem();
	auto len = strlen(name);

	while (obj)
	{
		if (obj->info.equals(name, len) && (obj + 1)->isMap())
			return obj + 1;

		obj = (obj + 1)->getNextSibling();
	}

	return nullptr;
}

const mtt::BencodeParser::Object* mtt::BencodeParser::Object::getListItem(const char* name) const
{
	auto obj = getFirstItem();
	auto len = strlen(name);

	while (obj)
	{
		if (obj->info.equals(name, len) && (obj + 1)->isList())
			return obj + 1;

		obj = (obj + 1)->getNextSibling();
	}

	return nullptr;
}

const mtt::BencodeParser::Object::Item* mtt::BencodeParser::Object::getTxtItem(const char* name) const
{
	auto obj = getFirstItem();
	auto len = strlen(name);

	while(obj)
	{
		if (obj->info.equals(name, len) && (obj + 1)->isText())
			return &(obj + 1)->info;

		obj = (obj + 1)->getNextSibling();
	}

	return nullptr;
}

std::string mtt::BencodeParser::Object::getTxt(const char* name) const
{
	auto item = getTxtItem(name);

	return item ? std::string(item->data, item->size) : std::string();
}

std::string mtt::BencodeParser::Object::getTxt() const
{
	return isText() ? std::string(info.data, info.size) : std::string();
}

const mtt::BencodeParser::Object* mtt::BencodeParser::Object::getIntItem(const char* name) const
{
	auto obj = getFirstItem();
	auto len = strlen(name);

	while (obj)
	{
		if (obj->info.equals(name, len) && (obj + 1)->isInt())
			return obj + 1;

		obj = (obj + 1)->getNextSibling();
	}

	return nullptr;
}

int mtt::BencodeParser::Object::getInt(const char* name) const
{
	auto o = getIntItem(name);
	return o ? o->getInt() : 0;
}

int mtt::BencodeParser::Object::getInt() const
{
	return strtol(info.data, 0, 10);
}

uint64_t mtt::BencodeParser::Object::getBigInt(const char* name) const
{
	auto o = getIntItem(name);
	return o ? o->getBigInt() : 0;
}

uint64_t mtt::BencodeParser::Object::getBigInt() const
{
	return strtoull(info.data, 0, 10);
}

const mtt::BencodeParser::Object* mtt::BencodeParser::Object::getFirstItem() const
{
	return info.size ? this + 1 : nullptr;
}

const mtt::BencodeParser::Object* mtt::BencodeParser::Object::getNextSibling() const
{
	return info.nextSiblingOffset ? this + info.nextSiblingOffset : nullptr;
}

const mtt::BencodeParser::Object& mtt::BencodeParser::Object::operator[](int index)
{
	auto ptr = getFirstItem();

	for (int i = 0; i < index; i++)
	{
		ptr = ptr->getNextSibling();
	}

	return *ptr;
}

bool mtt::BencodeParser::Object::Item::equals(const char* txt, size_t l) const
{
	return l != size ? false : strncmp(txt, data, size) == 0;
}

bool mtt::BencodeParser::Object::isMap() const
{
	return info.type == Item::Dictionary;
}

bool mtt::BencodeParser::Object::isList() const
{
	return info.type == Item::List;
}

bool mtt::BencodeParser::Object::isInt() const
{
	return info.type == Item::Number;
}

bool mtt::BencodeParser::Object::isText() const
{
	return info.type == Item::Text;
}

bool mtt::BencodeParser::Object::isText(const char* str, size_t l) const
{
	return isText() && info.equals(str, l);
}
<commit_msg>Bencode: lower max reserved size for big messages<commit_after>#include "BencodeParser.h"
#include <algorithm>
#include "..\Core\Logging.h"

#define PARSER_LOG(x) WRITE_LOG(LogTypeBencodeParser, x)

bool mtt::BencodeParser::parse(const uint8_t* data, size_t length)
{
	deep = 0;
	objects.clear();

	uint32_t reserveSize = length < 200 ? uint32_t(length*0.2f) : std::min(uint32_t(100), uint32_t(40 + length/500));
	objects.reserve(reserveSize);

	bodyEnd = (const char*)data + length;
	bodyStart = (const char*)data;
	auto parserEnd = bodyStart;

	internalParse(&parserEnd);

	remainingData = parserEnd >= bodyEnd ? 0 : (length - (parserEnd - (const char*)data));
	bodyEnd = parserEnd;

	return getRoot() != nullptr;
}

inline bool IS_NUM_CHAR(char c) { return ((c >= '0') && (c <= '9')); }

mtt::BencodeParser::Object* mtt::BencodeParser::internalParse(const char** body)
{
	Object* obj = nullptr;
	char c = **body;

	if (IS_NUM_CHAR(c))
	{
		obj = parseString(body);
	}
	else if (c == 'i')
	{
		obj = parseInt(body);
	}
	else if (c == 'l')
	{
		obj = parseList(body);
	}
	else if (c == 'd')
	{
		obj = parseDictionary(body);
	}
	else
		parseError(body);

	return obj;
}

void mtt::BencodeParser::parseError(const char** body)
{
	PARSER_LOG("PARSE ERROR character " << **body);
	*body = bodyEnd;
}

#define NOT_END_OF_ELEMENTS (**body != 'e' && (*body < bodyEnd))

mtt::BencodeParser::Object* mtt::BencodeParser::parseList(const char** body)
{
	PARSER_LOG("List start " << deep);

	(*body)++;
	deep++;

	int rootId = (int)objects.size();
	objects.emplace_back(mtt::BencodeParser::Object());
	objects.back().info.type = Object::Item::List;

	int count = 0;
	while (NOT_END_OF_ELEMENTS)
	{
		auto objPos = (uint16_t)objects.size();
		auto o = internalParse(body);

		if (o)
		{
			o->info.nextSiblingOffset = NOT_END_OF_ELEMENTS ? (uint16_t)objects.size() - objPos : 0;
			count++;
		}
	}

	(*body)++;
	deep--;

	objects[rootId].info.size = count;
	objects[rootId].info.nextSiblingOffset = NOT_END_OF_ELEMENTS ? (uint16_t)objects.size() - rootId : 0;

	PARSER_LOG("List end " << deep);

	return &objects[rootId];
}

mtt::BencodeParser::Object* mtt::BencodeParser::parseDictionary(const char** body)
{
	PARSER_LOG("Dictionary start" << deep);

	(*body)++;
	deep++;

	int rootId = (int)objects.size();
	objects.emplace_back(mtt::BencodeParser::Object());
	objects.back().info.type = Object::Item::Dictionary;

	int count = 0;
	while (NOT_END_OF_ELEMENTS)
	{
		auto s = parseString(body);

		if (s)
		{
			auto objPos = (uint16_t)objects.size();
			auto o = internalParse(body);

			if (o)
			{
				objects[objPos - 1].info.nextSiblingOffset = 1;
				o->info.nextSiblingOffset = NOT_END_OF_ELEMENTS ? (uint16_t)objects.size() - objPos : 0;
				count++;
			}
			else
				count = 0;
		}
	}

	(*body)++;
	deep--;

	objects[rootId].info.size = count;
	objects[rootId].info.nextSiblingOffset = NOT_END_OF_ELEMENTS ? (uint16_t)objects.size() - rootId : 0;

	PARSER_LOG("Dictionary end" << deep);

	return &objects[rootId];
}

mtt::BencodeParser::Object* mtt::BencodeParser::parseString(const char** body)
{
	mtt::BencodeParser::Object obj;
	char* endPtr = 0;
	obj.info.size = strtol(*body, &endPtr, 10);
	*body = endPtr;

	if (**body != ':' || (bodyEnd - *body) < obj.info.size)
	{
		parseError(body);
		return nullptr;
	}

	(*body)++;

	obj.info.type = Object::Item::Text;
	obj.info.data = *body;
	(*body) += obj.info.size;

	PARSER_LOG("String " << std::string(obj.info.data, obj.info.size));

	objects.push_back(obj);
	return &objects.back();
}

mtt::BencodeParser::Object* mtt::BencodeParser::parseInt(const char** body)
{
	(*body)++;

	mtt::BencodeParser::Object obj;
	obj.info.data = *body;

	while ((IS_NUM_CHAR(**body) || (**body == '-' && obj.info.size == 0)) && *body != bodyEnd)
	{
		obj.info.size++;
		(*body)++;
	}

	if (**body != 'e')
	{
		parseError(body);
		return nullptr;
	}

	(*body)++;

	obj.info.type = Object::Item::Number;
	PARSER_LOG("Number " << std::string(obj.info.data, obj.info.size));

	objects.push_back(obj);
	return &objects.back();
}

mtt::BencodeParser::Object* mtt::BencodeParser::getRoot()
{
	return objects.empty() ? nullptr : &objects[0];
}

const mtt::BencodeParser::Object* mtt::BencodeParser::Object::getDictItem(const char* name) const
{
	auto obj = getFirstItem();
	auto len = strlen(name);

	while (obj)
	{
		if (obj->info.equals(name, len) && (obj + 1)->isMap())
			return obj + 1;

		obj = (obj + 1)->getNextSibling();
	}

	return nullptr;
}

const mtt::BencodeParser::Object* mtt::BencodeParser::Object::getListItem(const char* name) const
{
	auto obj = getFirstItem();
	auto len = strlen(name);

	while (obj)
	{
		if (obj->info.equals(name, len) && (obj + 1)->isList())
			return obj + 1;

		obj = (obj + 1)->getNextSibling();
	}

	return nullptr;
}

const mtt::BencodeParser::Object::Item* mtt::BencodeParser::Object::getTxtItem(const char* name) const
{
	auto obj = getFirstItem();
	auto len = strlen(name);

	while(obj)
	{
		if (obj->info.equals(name, len) && (obj + 1)->isText())
			return &(obj + 1)->info;

		obj = (obj + 1)->getNextSibling();
	}

	return nullptr;
}

std::string mtt::BencodeParser::Object::getTxt(const char* name) const
{
	auto item = getTxtItem(name);

	return item ? std::string(item->data, item->size) : std::string();
}

std::string mtt::BencodeParser::Object::getTxt() const
{
	return isText() ? std::string(info.data, info.size) : std::string();
}

const mtt::BencodeParser::Object* mtt::BencodeParser::Object::getIntItem(const char* name) const
{
	auto obj = getFirstItem();
	auto len = strlen(name);

	while (obj)
	{
		if (obj->info.equals(name, len) && (obj + 1)->isInt())
			return obj + 1;

		obj = (obj + 1)->getNextSibling();
	}

	return nullptr;
}

int mtt::BencodeParser::Object::getInt(const char* name) const
{
	auto o = getIntItem(name);
	return o ? o->getInt() : 0;
}

int mtt::BencodeParser::Object::getInt() const
{
	return strtol(info.data, 0, 10);
}

uint64_t mtt::BencodeParser::Object::getBigInt(const char* name) const
{
	auto o = getIntItem(name);
	return o ? o->getBigInt() : 0;
}

uint64_t mtt::BencodeParser::Object::getBigInt() const
{
	return strtoull(info.data, 0, 10);
}

const mtt::BencodeParser::Object* mtt::BencodeParser::Object::getFirstItem() const
{
	return info.size ? this + 1 : nullptr;
}

const mtt::BencodeParser::Object* mtt::BencodeParser::Object::getNextSibling() const
{
	return info.nextSiblingOffset ? this + info.nextSiblingOffset : nullptr;
}

const mtt::BencodeParser::Object& mtt::BencodeParser::Object::operator[](int index)
{
	auto ptr = getFirstItem();

	for (int i = 0; i < index; i++)
	{
		ptr = ptr->getNextSibling();
	}

	return *ptr;
}

bool mtt::BencodeParser::Object::Item::equals(const char* txt, size_t l) const
{
	return l != size ? false : strncmp(txt, data, size) == 0;
}

bool mtt::BencodeParser::Object::isMap() const
{
	return info.type == Item::Dictionary;
}

bool mtt::BencodeParser::Object::isList() const
{
	return info.type == Item::List;
}

bool mtt::BencodeParser::Object::isInt() const
{
	return info.type == Item::Number;
}

bool mtt::BencodeParser::Object::isText() const
{
	return info.type == Item::Text;
}

bool mtt::BencodeParser::Object::isText(const char* str, size_t l) const
{
	return isText() && info.equals(str, l);
}
<|endoftext|>


<commit_before>#include <iostream>

using namespace std;

const static int Dimensions = 3;

void multiplyMatrix(const int[] A, const int[] B, int[] C)
{
  for (size_t i = 0, j = 0; i < Dimensions, j < Dimensions;) {
    if (j + 1 % Dimensions == 0) {
      j = 0;
      i += 1;
    } else {
      j += 1;
    }

    int value = 0;
    for (size_t k = 0; k < Dimensions; k++) {
      value += A[i * Dimensions + k] * B[j + k * Dimensions];
    }

    C[i * Dimensions + j] = value;
  }
}

int int main(int argc, char const *argv[]) {
  int[] A = {1,2,3,4,5,6,7,8,1};
  int[] B = {1,2,3,3,2,1,4,5,2};
  int[9] C;
  multiplyMatrix(A, B, C);
  for (int i = 0 ; i < 9; ++i)
    cout << C[i] << endl;
  return 0;
}
<commit_msg>fix bug<commit_after>#include <iostream>

using namespace std;

const static unsigned int Dimensions = 3;

void multiplyMatrix(const int A[], const int B[], int C[])
{
  for (size_t i = 0, j = 0; i < Dimensions, j < Dimensions;) {
    if (j + 1 % Dimensions == 0) {
      j = 0;
      i += 1;
    } else {
      j += 1;
    }

    int value = 0;
    for (size_t k = 0; k < Dimensions; k++) {
      value += A[i * Dimensions + k] * B[j + k * Dimensions];
    }

    C[i * Dimensions + j] = value;
  }
}

int int main(int argc, char const *argv[]) {
  int A[] = {1,2,3,4,5,6,7,8,1};
  int B[] = {1,2,3,3,2,1,4,5,2};
  int C[9];
  multiplyMatrix(A, B, C);
  for (int i = 0 ; i < 9; ++i)
    cout << C[i] << endl;
  return 0;
}
<|endoftext|>


<commit_before>//=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*-
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// These tablegen backends emit Clang diagnostics tables.
//
//===----------------------------------------------------------------------===//

#include "ClangDiagnosticsEmitter.h"
#include "Record.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Streams.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/VectorExtras.h"
#include <set>
#include <map>
using namespace llvm;

//===----------------------------------------------------------------------===//
// Warning Tables (.inc file) generation.
//===----------------------------------------------------------------------===//

void ClangDiagsDefsEmitter::run(std::ostream &OS) {
  // Write the #if guard
  if (!Component.empty()) {
    std::string ComponentName = UppercaseString(Component);
    OS << "#ifdef " << ComponentName << "START\n";
    OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
       << ",\n";
    OS << "#undef " << ComponentName << "START\n";
    OS << "#endif\n";
  }

  const std::vector<Record*> &Diags =
    Records.getAllDerivedDefinitions("Diagnostic");

  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
    const Record &R = *Diags[i];
    // Filter by component.
    if (!Component.empty() && Component != R.getValueAsString("Component"))
      continue;

    OS << "DIAG(" << R.getName() << ", ";
    OS << R.getValueAsDef("Class")->getName();
    OS << ", diag::" << R.getValueAsDef("DefaultMapping")->getName();
    OS << ", \"";
    std::string S = R.getValueAsString("Text");
    EscapeString(S);
    OS << S << "\")\n";
  }
}

//===----------------------------------------------------------------------===//
// Warning Group Tables generation
//===----------------------------------------------------------------------===//

void ClangDiagGroupsEmitter::run(std::ostream &OS) {
  // Invert the 1-[0/1] mapping of diags to group into a one to many mapping of
  // groups to diags in the group.
  std::map<std::string, std::vector<const Record*> > DiagsInGroup;

  const std::vector<Record*> &Diags =
    Records.getAllDerivedDefinitions("Diagnostic");

  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
    const Record *R = Diags[i];
    DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group"));
    if (DI == 0) continue;
    DiagsInGroup[DI->getDef()->getValueAsString("GroupName")].push_back(R);
  }

  // Walk through the groups emitting an array for each diagnostic of the diags
  // that are mapped to.
  OS << "\n#ifdef GET_DIAG_ARRAYS\n";
  unsigned IDNo = 0;
  unsigned MaxLen = 0;
  for (std::map<std::string, std::vector<const Record*> >::iterator
       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
    MaxLen = std::max(MaxLen, (unsigned)I->first.size());

    OS << "static const short DiagArray" << IDNo++
       << "[] = { ";
    std::vector<const Record*> &V = I->second;
    for (unsigned i = 0, e = V.size(); i != e; ++i)
      OS << "diag::" << V[i]->getName() << ", ";
    OS << "-1 };\n";
  }
  OS << "#endif // GET_DIAG_ARRAYS\n\n";

  // Emit the table now.
  OS << "\n#ifdef GET_DIAG_TABLE\n";
  IDNo = 0;
  for (std::map<std::string, std::vector<const Record*> >::iterator
       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
    std::string S = I->first;
    EscapeString(S);
    OS << "  { \"" << S << "\","
       << std::string(MaxLen-I->first.size()+1, ' ')
       << "DiagArray" << IDNo++ << " },\n";
  }
  OS << "#endif // GET_DIAG_TABLE\n\n";
}
<commit_msg>make sure that empty diag groups get known by clang.<commit_after>//=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*-
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// These tablegen backends emit Clang diagnostics tables.
//
//===----------------------------------------------------------------------===//

#include "ClangDiagnosticsEmitter.h"
#include "Record.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Streams.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/VectorExtras.h"
#include <set>
#include <map>
using namespace llvm;

//===----------------------------------------------------------------------===//
// Warning Tables (.inc file) generation.
//===----------------------------------------------------------------------===//

void ClangDiagsDefsEmitter::run(std::ostream &OS) {
  // Write the #if guard
  if (!Component.empty()) {
    std::string ComponentName = UppercaseString(Component);
    OS << "#ifdef " << ComponentName << "START\n";
    OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
       << ",\n";
    OS << "#undef " << ComponentName << "START\n";
    OS << "#endif\n";
  }

  const std::vector<Record*> &Diags =
    Records.getAllDerivedDefinitions("Diagnostic");

  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
    const Record &R = *Diags[i];
    // Filter by component.
    if (!Component.empty() && Component != R.getValueAsString("Component"))
      continue;

    OS << "DIAG(" << R.getName() << ", ";
    OS << R.getValueAsDef("Class")->getName();
    OS << ", diag::" << R.getValueAsDef("DefaultMapping")->getName();
    OS << ", \"";
    std::string S = R.getValueAsString("Text");
    EscapeString(S);
    OS << S << "\")\n";
  }
}

//===----------------------------------------------------------------------===//
// Warning Group Tables generation
//===----------------------------------------------------------------------===//

void ClangDiagGroupsEmitter::run(std::ostream &OS) {
  // Invert the 1-[0/1] mapping of diags to group into a one to many mapping of
  // groups to diags in the group.
  std::map<std::string, std::vector<const Record*> > DiagsInGroup;

  std::vector<Record*> Diags =
    Records.getAllDerivedDefinitions("Diagnostic");
  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
    const Record *R = Diags[i];
    DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group"));
    if (DI == 0) continue;
    DiagsInGroup[DI->getDef()->getValueAsString("GroupName")].push_back(R);
  }

  // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
  // groups (these are warnings that GCC supports that clang never produces).
  Diags = Records.getAllDerivedDefinitions("DiagGroup");
  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
    DiagsInGroup[Diags[i]->getValueAsString("GroupName")];
  }

  // Walk through the groups emitting an array for each diagnostic of the diags
  // that are mapped to.
  OS << "\n#ifdef GET_DIAG_ARRAYS\n";
  unsigned IDNo = 0;
  unsigned MaxLen = 0;
  for (std::map<std::string, std::vector<const Record*> >::iterator
       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
    MaxLen = std::max(MaxLen, (unsigned)I->first.size());

    OS << "static const short DiagArray" << IDNo++
       << "[] = { ";
    std::vector<const Record*> &V = I->second;
    for (unsigned i = 0, e = V.size(); i != e; ++i)
      OS << "diag::" << V[i]->getName() << ", ";
    OS << "-1 };\n";
  }
  OS << "#endif // GET_DIAG_ARRAYS\n\n";

  // Emit the table now.
  OS << "\n#ifdef GET_DIAG_TABLE\n";
  IDNo = 0;
  for (std::map<std::string, std::vector<const Record*> >::iterator
       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
    std::string S = I->first;
    EscapeString(S);
    OS << "  { \"" << S << "\","
       << std::string(MaxLen-I->first.size()+1, ' ')
       << "DiagArray" << IDNo++ << " },\n";
  }
  OS << "#endif // GET_DIAG_TABLE\n\n";
}
<|endoftext|>