<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2011 Francois Beaune
//
// 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.
//

// Interface header.
#include "generictilerenderer.h"

// appleseed.renderer headers.
#include "renderer/kernel/rendering/generic/pixelsampler.h"
#include "renderer/kernel/rendering/isamplerenderer.h"
#include "renderer/kernel/shading/shadingresult.h"
#include "renderer/modeling/frame/frame.h"

// appleseed.foundation headers.
#include "foundation/image/canvasproperties.h"
#include "foundation/image/tile.h"
#include "foundation/math/minmax.h"
#include "foundation/math/ordering.h"
#include "foundation/math/qmc.h"
#include "foundation/math/scalar.h"
#include "foundation/platform/breakpoint.h"
#include "foundation/utility/job.h"

// Standard headers.
#include <vector>

using namespace foundation;
using namespace std;

// Define this symbol to break execution into the debugger
// when a specific pixel is about to be rendered.
// #define DEBUG_BREAK_AT_PIXEL Vector<size_t, 2>(0, 0)

namespace renderer
{

namespace
{
    //
    // Generic tile renderer.
    //
    // Reference for composition algebra with alpha channels:
    //
    //   http://keithp.com/~keithp/porterduff/p253-porter.pdf
    //

    class GenericTileRenderer
      : public ITileRenderer
    {
      public:
        GenericTileRenderer(
            const Frame&            frame,
            ISampleRendererFactory* factory,
            const ParamArray&       params)
          : m_params(params)
          , m_sample_renderer(factory->create())
        {
            // Retrieve frame properties.
            const CanvasProperties& properties = frame.properties();
            const size_t num_pixels = properties.m_tile_width * properties.m_tile_height;

            // Generate pixel ordering.
            vector<size_t> ordering;
            ordering.reserve(num_pixels);
            hilbert_ordering(
                ordering,
                properties.m_tile_width,
                properties.m_tile_height);
            assert(ordering.size() == num_pixels);

            // Convert pixel ordering to (x, y) representation.
            m_pixel_ordering.resize(num_pixels);
            for (size_t i = 0; i < num_pixels; ++i)
            {
                const size_t x = ordering[i] % properties.m_tile_width;
                const size_t y = ordering[i] / properties.m_tile_width;
                assert(x < properties.m_tile_width);
                assert(y < properties.m_tile_height);
                m_pixel_ordering[i].x = static_cast<uint16>(x);
                m_pixel_ordering[i].y = static_cast<uint16>(y);
            }

            // Compute the approximate size of one side of the subpixel grid inside a pixel.
            m_sqrt_max_samples =
                round<size_t>(sqrt(static_cast<double>(m_params.m_max_samples)));
            RENDERER_LOG_INFO(
                "effective subpixel grid size: " FMT_SIZE_T "x" FMT_SIZE_T,
                m_sqrt_max_samples,
                m_sqrt_max_samples);

            // Initialize the pixel sampler.
            m_pixel_sampler.initialize(m_sqrt_max_samples);

            m_rcp_sample_canvas_width = 1.0 / (properties.m_canvas_width * m_sqrt_max_samples);
            m_rcp_sample_canvas_height = 1.0 / (properties.m_canvas_height * m_sqrt_max_samples);
            m_rcp_sample_count = 1.0f / (m_sqrt_max_samples * m_sqrt_max_samples);
        }

        virtual void release()
        {
            delete this;
        }

        virtual void render_tile(
            const Frame&    frame,
            const size_t    tile_x,
            const size_t    tile_y,
            AbortSwitch&    abort_switch)
        {
            // Retrieve frame properties.
            const CanvasProperties& properties = frame.properties();

            assert(tile_x < properties.m_tile_count_x);
            assert(tile_y < properties.m_tile_count_y);

            // Access the tile.
            Tile& tile = frame.tile(tile_x, tile_y);
            const size_t tile_width = tile.get_width();
            const size_t tile_height = tile.get_height();
            const size_t tile_origin_x = properties.m_tile_width * tile_x;
            const size_t tile_origin_y = properties.m_tile_height * tile_y;

            // Precompute some stuff.
            const LightingConditions& lighting_conditions =
                frame.get_lighting_conditions();

            // Loop over tile pixels.
            const size_t num_pixels = m_pixel_ordering.size();
            for (size_t i = 0; i < num_pixels; ++i)
            {
                // Retrieve the coordinates of the pixel in the tile.
                const size_t tx = static_cast<size_t>(m_pixel_ordering[i].x);
                const size_t ty = static_cast<size_t>(m_pixel_ordering[i].y);

                // Skip pixels outside of the tile.
                if (tx >= tile_width || ty >= tile_height)
                    continue;

                // Compute the coordinates of the pixel in the image.
                const size_t ix = tile_origin_x + tx;
                const size_t iy = tile_origin_y + ty;

                // Skip pixels outside the crop window, if cropping is enabled.
                if (m_params.m_crop)
                {
                    if (static_cast<int>(ix) < m_params.m_crop_window[0] ||
                        static_cast<int>(iy) < m_params.m_crop_window[1] ||
                        static_cast<int>(ix) > m_params.m_crop_window[2] ||
                        static_cast<int>(iy) > m_params.m_crop_window[3])
                    {
                        // Pixels outside the crop window are set to transparent black.
                        tile.set_pixel(tx, ty, Color4f(0.0f));
                        continue;
                    }
                }

#ifdef DEBUG_BREAK_AT_PIXEL

                // Break in the debugger when this pixel is reached.
                if (Vector<size_t, 2>(ix, iy) == DEBUG_BREAK_AT_PIXEL)
                    BREAKPOINT();

#endif

                // Initialize the pixel color.
                Color4f pixel_color(0.0f);

                if (!abort_switch.is_aborted())
                {
                    // Render, filter and accumulate samples.
                    const size_t base_sx = ix * m_sqrt_max_samples;
                    const size_t base_sy = iy * m_sqrt_max_samples;
                    for (size_t sy = 0; sy < m_sqrt_max_samples; ++sy)
                    {
                        for (size_t sx = 0; sx < m_sqrt_max_samples; ++sx)
                        {
                            // Compute the sample position in sample space and the instance number.
                            Vector2d s;
                            size_t instance;
                            m_pixel_sampler.sample(
                                base_sx + sx,
                                base_sy + sy,
                                s,
                                instance);

                            // Compute the sample position in NDC.
                            const Vector2d sample_position =
                                frame.get_sample_position(s.x, s.y);

                            // Create a sampling context.
                            SamplingContext sampling_context(
                                m_rng,
                                2,              // number of dimensions
                                0,              // number of samples
                                instance);      // initial instance number

                            // Render the sample.
                            ShadingResult shading_result;
                            m_sample_renderer->render_sample(
                                sampling_context,
                                sample_position,
                                shading_result);

                            // todo: implement proper sample filtering.
                            // todo: detect invalid sample values (NaN, infinity, etc.), set
                            // them to black and mark them as faulty in the diagnostic map.

                            // Transform the sample to the linear RGB color space.
                            shading_result.transform_to_linear_rgb(lighting_conditions);

                            // Accumulate the sample.
                            pixel_color[0] += shading_result.m_color[0];
                            pixel_color[1] += shading_result.m_color[1];
                            pixel_color[2] += shading_result.m_color[2];
                            pixel_color[3] += shading_result.m_alpha[0];
                        }
                    }

                    // Finish computing the pixel color.
                    pixel_color *= m_rcp_sample_count;
                }

                // Store the pixel color into the tile.
                tile.set_pixel(tx, ty, pixel_color);
            }
        }

      private:
        struct Parameters
        {
            const size_t        m_min_samples;          // minimum number of samples per pixel
            const size_t        m_max_samples;          // maximum number of samples per pixel
            bool                m_crop;                 // is cropping enabled?
            Vector4i            m_crop_window;          // crop window

            // Constructor, extract parameters.
            explicit Parameters(const ParamArray& params)
              : m_min_samples   ( params.get_required<size_t>("min_samples", 1) )
              , m_max_samples   ( params.get_required<size_t>("max_samples", 1) )
            {
                // Retrieve crop window parameter.
                m_crop = params.strings().exist("crop_window");
                if (m_crop)
                {
                    m_crop_window =
                        params.get_required<Vector4i>(
                            "crop_window",
                            Vector4i(0, 0, 65535, 65535));
                }
            }
        };

        // Pixel coordinates in a tile; max tile size is 65536 x 65536 pixels.
        typedef Vector<uint16, 2> Pixel;

        const Parameters                    m_params;
        auto_release_ptr<ISampleRenderer>   m_sample_renderer;

        vector<Pixel>                       m_pixel_ordering;
        PixelSampler                        m_pixel_sampler;

        size_t                              m_sqrt_max_samples;
        double                              m_rcp_sample_canvas_width;
        double                              m_rcp_sample_canvas_height;
        float                               m_rcp_sample_count;

        SamplingContext::RNGType            m_rng;
    };
}

//
// GenericTileRendererFactory class implementation.
//

GenericTileRendererFactory::GenericTileRendererFactory(
    const Frame&                frame,
    ISampleRendererFactory*     factory,
    const ParamArray&           params)
  : m_frame(frame)
  , m_factory(factory)
  , m_params(params)
{
}

void GenericTileRendererFactory::release()
{
    delete this;
}

ITileRenderer* GenericTileRendererFactory::create()
{
    return
        new GenericTileRenderer(
            m_frame,
            m_factory,
            m_params);
}

ITileRenderer* GenericTileRendererFactory::create(
    const Frame&                frame,
    ISampleRendererFactory*     factory,
    const ParamArray&           params)
{
    return
        new GenericTileRenderer(
            frame,
            factory,
            params);
}

}   // namespace renderer
<commit_msg>cosmetics.<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2011 Francois Beaune
//
// 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.
//

// Interface header.
#include "generictilerenderer.h"

// appleseed.renderer headers.
#include "renderer/kernel/rendering/generic/pixelsampler.h"
#include "renderer/kernel/rendering/isamplerenderer.h"
#include "renderer/kernel/shading/shadingresult.h"
#include "renderer/modeling/frame/frame.h"

// appleseed.foundation headers.
#include "foundation/image/canvasproperties.h"
#include "foundation/image/tile.h"
#include "foundation/math/minmax.h"
#include "foundation/math/ordering.h"
#include "foundation/math/qmc.h"
#include "foundation/math/scalar.h"
#include "foundation/platform/breakpoint.h"
#include "foundation/utility/job.h"

// Standard headers.
#include <vector>

using namespace foundation;
using namespace std;

namespace renderer
{

namespace
{
    //
    // Generic tile renderer.
    //
    // Reference for composition algebra with alpha channels:
    //
    //   http://keithp.com/~keithp/porterduff/p253-porter.pdf
    //

    // Define this symbol to break execution into the debugger
    // when a specific pixel is about to be rendered.
    // #define DEBUG_BREAK_AT_PIXEL Vector<size_t, 2>(0, 0)

    class GenericTileRenderer
      : public ITileRenderer
    {
      public:
        GenericTileRenderer(
            const Frame&            frame,
            ISampleRendererFactory* factory,
            const ParamArray&       params)
          : m_params(params)
          , m_sample_renderer(factory->create())
        {
            // Retrieve frame properties.
            const CanvasProperties& properties = frame.properties();
            const size_t num_pixels = properties.m_tile_width * properties.m_tile_height;

            // Generate pixel ordering.
            vector<size_t> ordering;
            ordering.reserve(num_pixels);
            hilbert_ordering(
                ordering,
                properties.m_tile_width,
                properties.m_tile_height);
            assert(ordering.size() == num_pixels);

            // Convert pixel ordering to (x, y) representation.
            m_pixel_ordering.resize(num_pixels);
            for (size_t i = 0; i < num_pixels; ++i)
            {
                const size_t x = ordering[i] % properties.m_tile_width;
                const size_t y = ordering[i] / properties.m_tile_width;
                assert(x < properties.m_tile_width);
                assert(y < properties.m_tile_height);
                m_pixel_ordering[i].x = static_cast<uint16>(x);
                m_pixel_ordering[i].y = static_cast<uint16>(y);
            }

            // Compute the approximate size of one side of the subpixel grid inside a pixel.
            m_sqrt_max_samples =
                round<size_t>(sqrt(static_cast<double>(m_params.m_max_samples)));
            RENDERER_LOG_INFO(
                "effective subpixel grid size: " FMT_SIZE_T "x" FMT_SIZE_T,
                m_sqrt_max_samples,
                m_sqrt_max_samples);

            // Initialize the pixel sampler.
            m_pixel_sampler.initialize(m_sqrt_max_samples);

            m_rcp_sample_canvas_width = 1.0 / (properties.m_canvas_width * m_sqrt_max_samples);
            m_rcp_sample_canvas_height = 1.0 / (properties.m_canvas_height * m_sqrt_max_samples);
            m_rcp_sample_count = 1.0f / (m_sqrt_max_samples * m_sqrt_max_samples);
        }

        virtual void release()
        {
            delete this;
        }

        virtual void render_tile(
            const Frame&    frame,
            const size_t    tile_x,
            const size_t    tile_y,
            AbortSwitch&    abort_switch)
        {
            // Retrieve frame properties.
            const CanvasProperties& properties = frame.properties();

            assert(tile_x < properties.m_tile_count_x);
            assert(tile_y < properties.m_tile_count_y);

            // Access the tile.
            Tile& tile = frame.tile(tile_x, tile_y);
            const size_t tile_width = tile.get_width();
            const size_t tile_height = tile.get_height();
            const size_t tile_origin_x = properties.m_tile_width * tile_x;
            const size_t tile_origin_y = properties.m_tile_height * tile_y;

            // Precompute some stuff.
            const LightingConditions& lighting_conditions =
                frame.get_lighting_conditions();

            // Loop over tile pixels.
            const size_t num_pixels = m_pixel_ordering.size();
            for (size_t i = 0; i < num_pixels; ++i)
            {
                // Retrieve the coordinates of the pixel in the tile.
                const size_t tx = static_cast<size_t>(m_pixel_ordering[i].x);
                const size_t ty = static_cast<size_t>(m_pixel_ordering[i].y);

                // Skip pixels outside of the tile.
                if (tx >= tile_width || ty >= tile_height)
                    continue;

                // Compute the coordinates of the pixel in the image.
                const size_t ix = tile_origin_x + tx;
                const size_t iy = tile_origin_y + ty;

                // Skip pixels outside the crop window, if cropping is enabled.
                if (m_params.m_crop)
                {
                    if (static_cast<int>(ix) < m_params.m_crop_window[0] ||
                        static_cast<int>(iy) < m_params.m_crop_window[1] ||
                        static_cast<int>(ix) > m_params.m_crop_window[2] ||
                        static_cast<int>(iy) > m_params.m_crop_window[3])
                    {
                        // Pixels outside the crop window are set to transparent black.
                        tile.set_pixel(tx, ty, Color4f(0.0f));
                        continue;
                    }
                }

#ifdef DEBUG_BREAK_AT_PIXEL

                // Break in the debugger when this pixel is reached.
                if (Vector<size_t, 2>(ix, iy) == DEBUG_BREAK_AT_PIXEL)
                    BREAKPOINT();

#endif

                // Initialize the pixel color.
                Color4f pixel_color(0.0f);

                if (!abort_switch.is_aborted())
                {
                    // Render, filter and accumulate samples.
                    const size_t base_sx = ix * m_sqrt_max_samples;
                    const size_t base_sy = iy * m_sqrt_max_samples;
                    for (size_t sy = 0; sy < m_sqrt_max_samples; ++sy)
                    {
                        for (size_t sx = 0; sx < m_sqrt_max_samples; ++sx)
                        {
                            // Compute the sample position in sample space and the instance number.
                            Vector2d s;
                            size_t instance;
                            m_pixel_sampler.sample(
                                base_sx + sx,
                                base_sy + sy,
                                s,
                                instance);

                            // Compute the sample position in NDC.
                            const Vector2d sample_position =
                                frame.get_sample_position(s.x, s.y);

                            // Create a sampling context.
                            SamplingContext sampling_context(
                                m_rng,
                                2,              // number of dimensions
                                0,              // number of samples
                                instance);      // initial instance number

                            // Render the sample.
                            ShadingResult shading_result;
                            m_sample_renderer->render_sample(
                                sampling_context,
                                sample_position,
                                shading_result);

                            // todo: implement proper sample filtering.
                            // todo: detect invalid sample values (NaN, infinity, etc.), set
                            // them to black and mark them as faulty in the diagnostic map.

                            // Transform the sample to the linear RGB color space.
                            shading_result.transform_to_linear_rgb(lighting_conditions);

                            // Accumulate the sample.
                            pixel_color[0] += shading_result.m_color[0];
                            pixel_color[1] += shading_result.m_color[1];
                            pixel_color[2] += shading_result.m_color[2];
                            pixel_color[3] += shading_result.m_alpha[0];
                        }
                    }

                    // Finish computing the pixel color.
                    pixel_color *= m_rcp_sample_count;
                }

                // Store the pixel color into the tile.
                tile.set_pixel(tx, ty, pixel_color);
            }
        }

      private:
        struct Parameters
        {
            const size_t        m_min_samples;          // minimum number of samples per pixel
            const size_t        m_max_samples;          // maximum number of samples per pixel
            bool                m_crop;                 // is cropping enabled?
            Vector4i            m_crop_window;          // crop window

            // Constructor, extract parameters.
            explicit Parameters(const ParamArray& params)
              : m_min_samples   ( params.get_required<size_t>("min_samples", 1) )
              , m_max_samples   ( params.get_required<size_t>("max_samples", 1) )
            {
                // Retrieve crop window parameter.
                m_crop = params.strings().exist("crop_window");
                if (m_crop)
                {
                    m_crop_window =
                        params.get_required<Vector4i>(
                            "crop_window",
                            Vector4i(0, 0, 65535, 65535));
                }
            }
        };

        // Pixel coordinates in a tile; max tile size is 65536 x 65536 pixels.
        typedef Vector<uint16, 2> Pixel;

        const Parameters                    m_params;
        auto_release_ptr<ISampleRenderer>   m_sample_renderer;

        vector<Pixel>                       m_pixel_ordering;
        PixelSampler                        m_pixel_sampler;

        size_t                              m_sqrt_max_samples;
        double                              m_rcp_sample_canvas_width;
        double                              m_rcp_sample_canvas_height;
        float                               m_rcp_sample_count;

        SamplingContext::RNGType            m_rng;
    };
}

//
// GenericTileRendererFactory class implementation.
//

GenericTileRendererFactory::GenericTileRendererFactory(
    const Frame&                frame,
    ISampleRendererFactory*     factory,
    const ParamArray&           params)
  : m_frame(frame)
  , m_factory(factory)
  , m_params(params)
{
}

void GenericTileRendererFactory::release()
{
    delete this;
}

ITileRenderer* GenericTileRendererFactory::create()
{
    return
        new GenericTileRenderer(
            m_frame,
            m_factory,
            m_params);
}

ITileRenderer* GenericTileRendererFactory::create(
    const Frame&                frame,
    ISampleRendererFactory*     factory,
    const ParamArray&           params)
{
    return
        new GenericTileRenderer(
            frame,
            factory,
            params);
}

}   // namespace renderer
<|endoftext|>


<commit_before>//===- lib/ReaderWriter/FileArchive.cpp -----------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lld/Core/ArchiveLibraryFile.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/LinkingContext.h"
#include "lld/Core/Parallel.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
#include <memory>
#include <mutex>
#include <set>
#include <unordered_map>

using llvm::object::Archive;
using llvm::object::ObjectFile;
using llvm::object::SymbolRef;
using llvm::object::symbol_iterator;
using llvm::object::object_error;

namespace lld {

namespace {

/// \brief The FileArchive class represents an Archive Library file
class FileArchive : public lld::ArchiveLibraryFile {
public:
  FileArchive(std::unique_ptr<MemoryBuffer> mb, const Registry &reg,
              StringRef path, bool logLoading)
      : ArchiveLibraryFile(path), _mb(std::shared_ptr<MemoryBuffer>(mb.release())),
        _registry(reg), _logLoading(logLoading) {}

  /// \brief Check if any member of the archive contains an Atom with the
  /// specified name and return the File object for that member, or nullptr.
  File *find(StringRef name, bool dataSymbolOnly) override {
    auto member = _symbolMemberMap.find(name);
    if (member == _symbolMemberMap.end())
      return nullptr;
    Archive::child_iterator ci = member->second;

    // Don't return a member already returned
    const char *memberStart = ci->getBuffer().data();
    if (_membersInstantiated.count(memberStart))
      return nullptr;
    if (dataSymbolOnly && !isDataSymbol(ci, name))
      return nullptr;

    _membersInstantiated.insert(memberStart);

    // Check if a file is preloaded.
    {
      std::lock_guard<std::mutex> lock(_mutex);
      auto it = _preloaded.find(memberStart);
      if (it != _preloaded.end()) {
        std::unique_ptr<Future<File *>> &p = it->second;
        Future<File *> *future = p.get();
        return future->get();
      }
    }

    std::unique_ptr<File> result;
    if (instantiateMember(ci, result))
      return nullptr;

    // give up the pointer so that this object no longer manages it
    return result.release();
  }

  // Instantiate a member file containing a given symbol name.
  void preload(TaskGroup &group, StringRef name) override {
    auto member = _symbolMemberMap.find(name);
    if (member == _symbolMemberMap.end())
      return;
    Archive::child_iterator ci = member->second;

    // Do nothing if a member is already instantiated.
    const char *memberStart = ci->getBuffer().data();
    if (_membersInstantiated.count(memberStart))
      return;

    std::lock_guard<std::mutex> lock(_mutex);
    if (_preloaded.find(memberStart) != _preloaded.end())
      return;

    // Instantiate the member
    auto *future = new Future<File *>();
    _preloaded[memberStart] = std::unique_ptr<Future<File *>>(future);

    group.spawn([=] {
      std::unique_ptr<File> result;
      std::error_code ec = instantiateMember(ci, result);
      future->set(ec ? nullptr : result.release());
    });
  }

  /// \brief parse each member
  std::error_code
  parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
    if (std::error_code ec = parse())
      return ec;
    for (auto mf = _archive->child_begin(), me = _archive->child_end();
         mf != me; ++mf) {
      std::unique_ptr<File> file;
      if (std::error_code ec = instantiateMember(mf, file))
        return ec;
      result.push_back(std::move(file));
    }
    return std::error_code();
  }

  const atom_collection<DefinedAtom> &defined() const override {
    return _definedAtoms;
  }

  const atom_collection<UndefinedAtom> &undefined() const override {
    return _undefinedAtoms;
  }

  const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
    return _sharedLibraryAtoms;
  }

  const atom_collection<AbsoluteAtom> &absolute() const override {
    return _absoluteAtoms;
  }

  /// Returns a set of all defined symbols in the archive.
  std::set<StringRef> getDefinedSymbols() override {
    parse();
    std::set<StringRef> ret;
    for (const auto &e : _symbolMemberMap)
      ret.insert(e.first);
    return ret;
  }

protected:
  std::error_code doParse() override {
    // Make Archive object which will be owned by FileArchive object.
    std::error_code ec;
    _archive.reset(new Archive(_mb->getMemBufferRef(), ec));
    if (ec)
      return ec;
    if ((ec = buildTableOfContents()))
      return ec;
    return std::error_code();
  }

private:
  std::error_code
  instantiateMember(Archive::child_iterator member,
                    std::unique_ptr<File> &result) const {
    ErrorOr<llvm::MemoryBufferRef> mbOrErr = member->getMemoryBufferRef();
    if (std::error_code ec = mbOrErr.getError())
      return ec;
    llvm::MemoryBufferRef mb = mbOrErr.get();
    std::string memberPath = (_archive->getFileName() + "("
                           + mb.getBufferIdentifier() + ")").str();

    if (_logLoading)
      llvm::errs() << memberPath << "\n";

    std::unique_ptr<MemoryBuffer> memberMB(MemoryBuffer::getMemBuffer(
        mb.getBuffer(), mb.getBufferIdentifier(), false));

    std::vector<std::unique_ptr<File>> files;
    if (std::error_code ec = _registry.loadFile(std::move(memberMB), files))
      return ec;
    assert(files.size() == 1);
    result = std::move(files[0]);
    if (std::error_code ec = result->parse())
      return ec;
    result->setArchivePath(_archive->getFileName());

    // The memory buffer is co-owned by the archive file and the children,
    // so that the bufffer is deallocated when all the members are destructed.
    result->setSharedMemoryBuffer(_mb);
    return std::error_code();
  }

  // Parses the given memory buffer as an object file, and returns true
  // code if the given symbol is a data symbol. If the symbol is not a data
  // symbol or does not exist, returns false.
  bool isDataSymbol(Archive::child_iterator member, StringRef symbol) const {
    ErrorOr<llvm::MemoryBufferRef> buf = member->getMemoryBufferRef();
    if (buf.getError())
      return false;
    std::unique_ptr<MemoryBuffer> mb(MemoryBuffer::getMemBuffer(
        buf.get().getBuffer(), buf.get().getBufferIdentifier(), false));

    auto objOrErr(ObjectFile::createObjectFile(mb->getMemBufferRef()));
    if (objOrErr.getError())
      return false;
    std::unique_ptr<ObjectFile> obj = std::move(objOrErr.get());

    for (SymbolRef sym : obj->symbols()) {
      // Skip until we find the symbol.
      StringRef name;
      if (sym.getName(name))
        return false;
      if (name != symbol)
        continue;
      uint32_t flags = sym.getFlags();
      if (flags <= SymbolRef::SF_Undefined)
        continue;

      // Returns true if it's a data symbol.
      SymbolRef::Type type;
      if (sym.getType(type))
        return false;
      if (type == SymbolRef::ST_Data)
        return true;
    }
    return false;
  }

  std::error_code buildTableOfContents() {
    DEBUG_WITH_TYPE("FileArchive", llvm::dbgs()
                                       << "Table of contents for archive '"
                                       << _archive->getFileName() << "':\n");
    for (const Archive::Symbol &sym : _archive->symbols()) {
      StringRef name = sym.getName();
      ErrorOr<Archive::child_iterator> memberOrErr = sym.getMember();
      if (std::error_code ec = memberOrErr.getError())
        return ec;
      Archive::child_iterator member = memberOrErr.get();
      DEBUG_WITH_TYPE(
          "FileArchive",
          llvm::dbgs() << llvm::format("0x%08llX ", member->getBuffer().data())
                       << "'" << name << "'\n");
      _symbolMemberMap[name] = member;
    }
    return std::error_code();
  }

  typedef std::unordered_map<StringRef, Archive::child_iterator> MemberMap;
  typedef std::set<const char *> InstantiatedSet;

  std::shared_ptr<MemoryBuffer> _mb;
  const Registry &_registry;
  std::unique_ptr<Archive> _archive;
  MemberMap _symbolMemberMap;
  InstantiatedSet _membersInstantiated;
  atom_collection_vector<DefinedAtom> _definedAtoms;
  atom_collection_vector<UndefinedAtom> _undefinedAtoms;
  atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
  atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
  bool _logLoading;
  std::vector<std::unique_ptr<MemoryBuffer>> _memberBuffers;
  std::map<const char *, std::unique_ptr<Future<File *>>> _preloaded;
  std::mutex _mutex;
};

class ArchiveReader : public Reader {
public:
  ArchiveReader(bool logLoading) : _logLoading(logLoading) {}

  bool canParse(file_magic magic, const MemoryBuffer &) const override {
    return magic == llvm::sys::fs::file_magic::archive;
  }

  std::error_code
  loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &reg,
           std::vector<std::unique_ptr<File>> &result) const override {
    StringRef path = mb->getBufferIdentifier();
    std::unique_ptr<FileArchive> file(
        new FileArchive(std::move(mb), reg, path, _logLoading));
    result.push_back(std::move(file));
    return std::error_code();
  }

private:
  bool _logLoading;
};

} // anonymous namespace

void Registry::addSupportArchives(bool logLoading) {
  add(std::unique_ptr<Reader>(new ArchiveReader(logLoading)));
}

} // end namespace lld
<commit_msg>Remove unused vectors from FileArchive.<commit_after>//===- lib/ReaderWriter/FileArchive.cpp -----------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lld/Core/ArchiveLibraryFile.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/LinkingContext.h"
#include "lld/Core/Parallel.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
#include <memory>
#include <mutex>
#include <set>
#include <unordered_map>

using llvm::object::Archive;
using llvm::object::ObjectFile;
using llvm::object::SymbolRef;
using llvm::object::symbol_iterator;
using llvm::object::object_error;

namespace lld {

namespace {

/// \brief The FileArchive class represents an Archive Library file
class FileArchive : public lld::ArchiveLibraryFile {
public:
  FileArchive(std::unique_ptr<MemoryBuffer> mb, const Registry &reg,
              StringRef path, bool logLoading)
      : ArchiveLibraryFile(path), _mb(std::shared_ptr<MemoryBuffer>(mb.release())),
        _registry(reg), _logLoading(logLoading) {}

  /// \brief Check if any member of the archive contains an Atom with the
  /// specified name and return the File object for that member, or nullptr.
  File *find(StringRef name, bool dataSymbolOnly) override {
    auto member = _symbolMemberMap.find(name);
    if (member == _symbolMemberMap.end())
      return nullptr;
    Archive::child_iterator ci = member->second;

    // Don't return a member already returned
    const char *memberStart = ci->getBuffer().data();
    if (_membersInstantiated.count(memberStart))
      return nullptr;
    if (dataSymbolOnly && !isDataSymbol(ci, name))
      return nullptr;

    _membersInstantiated.insert(memberStart);

    // Check if a file is preloaded.
    {
      std::lock_guard<std::mutex> lock(_mutex);
      auto it = _preloaded.find(memberStart);
      if (it != _preloaded.end()) {
        std::unique_ptr<Future<File *>> &p = it->second;
        Future<File *> *future = p.get();
        return future->get();
      }
    }

    std::unique_ptr<File> result;
    if (instantiateMember(ci, result))
      return nullptr;

    // give up the pointer so that this object no longer manages it
    return result.release();
  }

  // Instantiate a member file containing a given symbol name.
  void preload(TaskGroup &group, StringRef name) override {
    auto member = _symbolMemberMap.find(name);
    if (member == _symbolMemberMap.end())
      return;
    Archive::child_iterator ci = member->second;

    // Do nothing if a member is already instantiated.
    const char *memberStart = ci->getBuffer().data();
    if (_membersInstantiated.count(memberStart))
      return;

    std::lock_guard<std::mutex> lock(_mutex);
    if (_preloaded.find(memberStart) != _preloaded.end())
      return;

    // Instantiate the member
    auto *future = new Future<File *>();
    _preloaded[memberStart] = std::unique_ptr<Future<File *>>(future);

    group.spawn([=] {
      std::unique_ptr<File> result;
      std::error_code ec = instantiateMember(ci, result);
      future->set(ec ? nullptr : result.release());
    });
  }

  /// \brief parse each member
  std::error_code
  parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
    if (std::error_code ec = parse())
      return ec;
    for (auto mf = _archive->child_begin(), me = _archive->child_end();
         mf != me; ++mf) {
      std::unique_ptr<File> file;
      if (std::error_code ec = instantiateMember(mf, file))
        return ec;
      result.push_back(std::move(file));
    }
    return std::error_code();
  }

  const atom_collection<DefinedAtom> &defined() const override {
    return _noDefinedAtoms;
  }

  const atom_collection<UndefinedAtom> &undefined() const override {
    return _noUndefinedAtoms;
  }

  const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
    return _noSharedLibraryAtoms;
  }

  const atom_collection<AbsoluteAtom> &absolute() const override {
    return _noAbsoluteAtoms;
  }

  /// Returns a set of all defined symbols in the archive.
  std::set<StringRef> getDefinedSymbols() override {
    parse();
    std::set<StringRef> ret;
    for (const auto &e : _symbolMemberMap)
      ret.insert(e.first);
    return ret;
  }

protected:
  std::error_code doParse() override {
    // Make Archive object which will be owned by FileArchive object.
    std::error_code ec;
    _archive.reset(new Archive(_mb->getMemBufferRef(), ec));
    if (ec)
      return ec;
    if ((ec = buildTableOfContents()))
      return ec;
    return std::error_code();
  }

private:
  std::error_code
  instantiateMember(Archive::child_iterator member,
                    std::unique_ptr<File> &result) const {
    ErrorOr<llvm::MemoryBufferRef> mbOrErr = member->getMemoryBufferRef();
    if (std::error_code ec = mbOrErr.getError())
      return ec;
    llvm::MemoryBufferRef mb = mbOrErr.get();
    std::string memberPath = (_archive->getFileName() + "("
                           + mb.getBufferIdentifier() + ")").str();

    if (_logLoading)
      llvm::errs() << memberPath << "\n";

    std::unique_ptr<MemoryBuffer> memberMB(MemoryBuffer::getMemBuffer(
        mb.getBuffer(), mb.getBufferIdentifier(), false));

    std::vector<std::unique_ptr<File>> files;
    if (std::error_code ec = _registry.loadFile(std::move(memberMB), files))
      return ec;
    assert(files.size() == 1);
    result = std::move(files[0]);
    if (std::error_code ec = result->parse())
      return ec;
    result->setArchivePath(_archive->getFileName());

    // The memory buffer is co-owned by the archive file and the children,
    // so that the bufffer is deallocated when all the members are destructed.
    result->setSharedMemoryBuffer(_mb);
    return std::error_code();
  }

  // Parses the given memory buffer as an object file, and returns true
  // code if the given symbol is a data symbol. If the symbol is not a data
  // symbol or does not exist, returns false.
  bool isDataSymbol(Archive::child_iterator member, StringRef symbol) const {
    ErrorOr<llvm::MemoryBufferRef> buf = member->getMemoryBufferRef();
    if (buf.getError())
      return false;
    std::unique_ptr<MemoryBuffer> mb(MemoryBuffer::getMemBuffer(
        buf.get().getBuffer(), buf.get().getBufferIdentifier(), false));

    auto objOrErr(ObjectFile::createObjectFile(mb->getMemBufferRef()));
    if (objOrErr.getError())
      return false;
    std::unique_ptr<ObjectFile> obj = std::move(objOrErr.get());

    for (SymbolRef sym : obj->symbols()) {
      // Skip until we find the symbol.
      StringRef name;
      if (sym.getName(name))
        return false;
      if (name != symbol)
        continue;
      uint32_t flags = sym.getFlags();
      if (flags <= SymbolRef::SF_Undefined)
        continue;

      // Returns true if it's a data symbol.
      SymbolRef::Type type;
      if (sym.getType(type))
        return false;
      if (type == SymbolRef::ST_Data)
        return true;
    }
    return false;
  }

  std::error_code buildTableOfContents() {
    DEBUG_WITH_TYPE("FileArchive", llvm::dbgs()
                                       << "Table of contents for archive '"
                                       << _archive->getFileName() << "':\n");
    for (const Archive::Symbol &sym : _archive->symbols()) {
      StringRef name = sym.getName();
      ErrorOr<Archive::child_iterator> memberOrErr = sym.getMember();
      if (std::error_code ec = memberOrErr.getError())
        return ec;
      Archive::child_iterator member = memberOrErr.get();
      DEBUG_WITH_TYPE(
          "FileArchive",
          llvm::dbgs() << llvm::format("0x%08llX ", member->getBuffer().data())
                       << "'" << name << "'\n");
      _symbolMemberMap[name] = member;
    }
    return std::error_code();
  }

  typedef std::unordered_map<StringRef, Archive::child_iterator> MemberMap;
  typedef std::set<const char *> InstantiatedSet;

  std::shared_ptr<MemoryBuffer> _mb;
  const Registry &_registry;
  std::unique_ptr<Archive> _archive;
  MemberMap _symbolMemberMap;
  InstantiatedSet _membersInstantiated;
  bool _logLoading;
  std::vector<std::unique_ptr<MemoryBuffer>> _memberBuffers;
  std::map<const char *, std::unique_ptr<Future<File *>>> _preloaded;
  std::mutex _mutex;
};

class ArchiveReader : public Reader {
public:
  ArchiveReader(bool logLoading) : _logLoading(logLoading) {}

  bool canParse(file_magic magic, const MemoryBuffer &) const override {
    return magic == llvm::sys::fs::file_magic::archive;
  }

  std::error_code
  loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &reg,
           std::vector<std::unique_ptr<File>> &result) const override {
    StringRef path = mb->getBufferIdentifier();
    std::unique_ptr<FileArchive> file(
        new FileArchive(std::move(mb), reg, path, _logLoading));
    result.push_back(std::move(file));
    return std::error_code();
  }

private:
  bool _logLoading;
};

} // anonymous namespace

void Registry::addSupportArchives(bool logLoading) {
  add(std::unique_ptr<Reader>(new ArchiveReader(logLoading)));
}

} // end namespace lld
<|endoftext|>


<commit_before>// This is the main DLL file.

#include "liblzma_wrapper.h"

/// Information about a .xz file
typedef struct {
	/// Combined Index of all Streams in the file
	lzma_index *idx;

	/// Total amount of Stream Padding
	uint64_t stream_padding;

	/// Highest memory usage so far
	uint64_t memusage_max;

	/// True if all Blocks so far have Compressed Size and
	/// Uncompressed Size fields
	bool all_have_sizes;

	/// Oldest XZ Utils version that will decompress the file
	uint32_t min_version;

} xz_file_info;

static String^ message_strm(lzma_ret code)
{
	switch (code) {
	case LZMA_NO_CHECK:
		return ("No integrity check; not verifying file integrity");

	case LZMA_UNSUPPORTED_CHECK:
		return ("Unsupported type of integrity check; "
			"not verifying file integrity");

	case LZMA_MEM_ERROR:
		return ("Memory error");

	case LZMA_MEMLIMIT_ERROR:
		return ("Memory usage limit reached");

	case LZMA_FORMAT_ERROR:
		return ("File format not recognized");

	case LZMA_OPTIONS_ERROR:
		return ("Unsupported options");

	case LZMA_DATA_ERROR:
		return ("Compressed data is corrupt");

	case LZMA_BUF_ERROR:
		return ("Unexpected end of input");

	case LZMA_OK:
	case LZMA_STREAM_END:
	case LZMA_GET_CHECK:
	case LZMA_PROG_ERROR:
		// Without "default", compiler will warn if new constants
		// are added to lzma_ret, it is not too easy to forget to
		// add the new constants to this function.
		break;
	}

	return ("Internal error (bug)");
}

static bool io_pread(Stream ^stream, array<Byte>^buf, size_t size, int64_t pos)
{
	if (stream->Seek(pos, SeekOrigin::Begin) != pos)
		throw gcnew InvalidDataException("unable to seek to pos");
	if (stream->Read(buf, 0, size) != size)
		throw gcnew InvalidDataException("unable to read size");
	return true;
}

struct xz_file_basic_info
{
	uint64_t stream_count;
	uint64_t block_count;
	uint64_t file_size;
	uint64_t uncompressed_size;
};

static void liblzma_wrapper::parse_indexes(liblzma_wrapper::XZFileInfo ^xfbi, Stream ^stream)
{
	xz_file_info sxfi = { NULL, 0, 0, true, 50000002 };
	xz_file_info *xfi = &sxfi;
	int64_t length = stream->Length;
	if (length < 2 * LZMA_STREAM_HEADER_SIZE)
		throw gcnew InvalidDataException("Too small to be a valid .xz file");

	lzma_stream_flags header_flags;
	lzma_stream_flags footer_flags;
	lzma_ret ret;

	// lzma_stream for the Index decoder
	lzma_stream strm = LZMA_STREAM_INIT;

	// All Indexes decoded so far
	lzma_index *combined_index = NULL;

	// The Index currently being decoded
	lzma_index *this_index = NULL;

	try {

		// Current position in the file. We parse the file backwards so
		// initialize it to point to the end of the file.
		int64_t pos = length;
		array<Byte>^ nums = gcnew array<Byte>(IO_BUFFER_SIZE);
		pin_ptr<Byte> pp = &nums[0];
		uint8_t *buf_u8 = pp;
		uint32_t *buf_u32 = (uint32_t *)(buf_u8);

		// Each loop iteration decodes one Index.
		do {
			// Check that there is enough data left to contain at least
			// the Stream Header and Stream Footer. This check cannot
			// fail in the first pass of this loop.
			if (pos < 2 * LZMA_STREAM_HEADER_SIZE)
				throw gcnew InvalidDataException(message_strm(LZMA_DATA_ERROR));

			pos -= LZMA_STREAM_HEADER_SIZE;
			lzma_vli stream_padding = 0;

			// Locate the Stream Footer. There may be Stream Padding which
			// we must skip when reading backwards.
			while (true) {
				if (pos < LZMA_STREAM_HEADER_SIZE)
					throw gcnew InvalidDataException(message_strm(LZMA_DATA_ERROR));

				io_pread(stream, nums, LZMA_STREAM_HEADER_SIZE, pos);

				// Stream Padding is always a multiple of four bytes.
				int i = 2;
				if (buf_u32[i] != 0)
					break;

				// To avoid calling io_pread() for every four bytes
				// of Stream Padding, take advantage that we read
				// 12 bytes (LZMA_STREAM_HEADER_SIZE) already and
				// check them too before calling io_pread() again.
				do {
					stream_padding += 4;
					pos -= 4;
					--i;
				} while (i >= 0 && buf_u32[i] == 0);
			}

			// Decode the Stream Footer.
			ret = lzma_stream_footer_decode(&footer_flags, buf_u8);
			if (ret != LZMA_OK)
				throw gcnew InvalidDataException(message_strm(ret));

			// Check that the Stream Footer doesn't specify something
			// that we don't support. This can only happen if the xz
			// version is older than liblzma and liblzma supports
			// something new.
			//
			// It is enough to check Stream Footer. Stream Header must
			// match when it is compared against Stream Footer with
			// lzma_stream_flags_compare().
			if (footer_flags.version != 0)
				throw gcnew InvalidDataException(message_strm(LZMA_OPTIONS_ERROR));

			// Check that the size of the Index field looks sane.
			lzma_vli index_size = footer_flags.backward_size;
			if ((lzma_vli)(pos) < index_size + LZMA_STREAM_HEADER_SIZE)
				throw gcnew InvalidDataException(message_strm(LZMA_DATA_ERROR));

			// Set pos to the beginning of the Index.
			pos -= index_size;

			// Decode the Index.
			ret = lzma_index_decoder(&strm, &this_index, UINT64_MAX);
			if (ret != LZMA_OK)
				throw gcnew InvalidDataException(message_strm(ret));

			do {
				// Don't give the decoder more input than the
				// Index size.
				strm.avail_in = (size_t)(IO_BUFFER_SIZE < index_size ? IO_BUFFER_SIZE : index_size);
				io_pread(stream, nums, strm.avail_in, pos);

				pos += strm.avail_in;
				index_size -= strm.avail_in;

				strm.next_in = buf_u8;
				ret = lzma_code(&strm, LZMA_RUN);

			} while (ret == LZMA_OK);

			// If the decoding seems to be successful, check also that
			// the Index decoder consumed as much input as indicated
			// by the Backward Size field.
			if (ret == LZMA_STREAM_END)
				if (index_size != 0 || strm.avail_in != 0)
					ret = LZMA_DATA_ERROR;

			if (ret != LZMA_STREAM_END) {
				// LZMA_BUFFER_ERROR means that the Index decoder
				// would have liked more input than what the Index
				// size should be according to Stream Footer.
				// The message for LZMA_DATA_ERROR makes more
				// sense in that case.
				if (ret == LZMA_BUF_ERROR)
					ret = LZMA_DATA_ERROR;

				throw gcnew InvalidDataException(message_strm(ret));
			}

			// Decode the Stream Header and check that its Stream Flags
			// match the Stream Footer.
			pos -= footer_flags.backward_size + LZMA_STREAM_HEADER_SIZE;
			if ((lzma_vli)(pos) < lzma_index_total_size(this_index))
				throw gcnew InvalidDataException(message_strm(LZMA_DATA_ERROR));

			pos -= lzma_index_total_size(this_index);
			io_pread(stream, nums, LZMA_STREAM_HEADER_SIZE, pos);

			ret = lzma_stream_header_decode(&header_flags, buf_u8);
			if (ret != LZMA_OK)
				throw gcnew InvalidDataException(message_strm(ret));

			ret = lzma_stream_flags_compare(&header_flags, &footer_flags);
			if (ret != LZMA_OK)
				throw gcnew InvalidDataException(message_strm(ret));

			// Store the decoded Stream Flags into this_index. This is
			// needed so that we can print which Check is used in each
			// Stream.
			ret = lzma_index_stream_flags(this_index, &footer_flags);
			if (ret != LZMA_OK)
				throw gcnew InvalidOperationException(message_strm(ret));

			// Store also the size of the Stream Padding field. It is
			// needed to show the offsets of the Streams correctly.
			ret = lzma_index_stream_padding(this_index, stream_padding);
			if (ret != LZMA_OK)
				throw gcnew InvalidOperationException(message_strm(ret));

			if (combined_index != NULL) {
				// Append the earlier decoded Indexes
				// after this_index.
				ret = lzma_index_cat(
					this_index, combined_index, NULL);
				if (ret != LZMA_OK)
					throw gcnew InvalidOperationException(message_strm(ret));
			}

			combined_index = this_index;
			this_index = NULL;

			xfi->stream_padding += stream_padding;

		} while (pos > 0);

		// All OK. Make combined_index available to the caller.
		xfi->idx = combined_index;

		xfbi->stream_count = lzma_index_stream_count(xfi->idx);
		xfbi->block_count = lzma_index_block_count(xfi->idx);
		xfbi->file_size = lzma_index_file_size(xfi->idx);
		xfbi->uncompressed_size = lzma_index_uncompressed_size(xfi->idx);
	}
	finally
	{
		lzma_end(&strm);
		lzma_index_end(combined_index, NULL);
		lzma_index_end(this_index, NULL);
	}
}

int liblzma_wrapper::LZMAStream::Read(cli::array<unsigned char, 1> ^buffer, int offset, int size)
{
	if (bCompress)
		throw gcnew InvalidOperationException("Operation not supported");

	if (strm->avail_in == 0)
	{
		strm->avail_in = stream->Read(gc_buf, 0, gc_buf->Length);
		pin_ptr<Byte> pp_inbuf = &gc_buf[0];
		strm->next_in = pp_inbuf;
	}

	pin_ptr<Byte> pp_outbuf = &buffer[0];
	strm->next_out = pp_outbuf + offset;
	strm->avail_out = size;

	ret = lzma_code(strm, LZMA_RUN);

	if (ret != LZMA_OK && ret != LZMA_STREAM_END)
		throw gcnew InvalidOperationException(message_strm(ret));

	return size - strm->avail_out;
}

void liblzma_wrapper::LZMAStream::Flush()
{
	if (bCompress)
	{
		do
		{
			strm->next_in = nullptr;
			strm->avail_in = 0;

			pin_ptr<Byte> pp_outbuf = &gc_buf[0];
			strm->next_out = pp_outbuf;
			size_t outlen = gc_buf->Length;
			strm->avail_out = outlen;

			ret = lzma_code(strm, LZMA_FINISH);

			if (ret != LZMA_OK && ret != LZMA_STREAM_END)
				throw gcnew InvalidOperationException(message_strm(ret));

			int64_t avail = outlen - strm->avail_out;
			if (avail > 0)
				stream->Write(gc_buf, 0, avail);
		} while (strm->avail_in > 0);
	}
}

void liblzma_wrapper::LZMAStream::Write(cli::array<unsigned char, 1> ^buffer, int offset, int size)
{
	if (!bCompress)
		throw gcnew InvalidOperationException("Operation not supported");

	pin_ptr<Byte> pp_inbuf = &buffer[0];
	strm->next_in = pp_inbuf + offset;
	strm->avail_in = size;

	while (strm->avail_in > 0)
	{
		pin_ptr<Byte> pp_outbuf = &gc_buf[0];
		strm->next_out = pp_outbuf;
		size_t outlen = gc_buf->Length;
		strm->avail_out = outlen;

		ret = lzma_code(strm, LZMA_RUN);

		if (ret != LZMA_OK && ret != LZMA_STREAM_END)
			throw gcnew InvalidOperationException(message_strm(ret));

		int64_t avail = outlen - strm->avail_out;
		if (avail > 0)
			stream->Write(gc_buf, 0, avail);
	}
}
<commit_msg>Fix conversion warnings in liblzma_wrapper<commit_after>// This is the main DLL file.

#include "liblzma_wrapper.h"

/// Information about a .xz file
typedef struct {
	/// Combined Index of all Streams in the file
	lzma_index *idx;

	/// Total amount of Stream Padding
	uint64_t stream_padding;

	/// Highest memory usage so far
	uint64_t memusage_max;

	/// True if all Blocks so far have Compressed Size and
	/// Uncompressed Size fields
	bool all_have_sizes;

	/// Oldest XZ Utils version that will decompress the file
	uint32_t min_version;

} xz_file_info;

static String^ message_strm(lzma_ret code)
{
	switch (code) {
	case LZMA_NO_CHECK:
		return ("No integrity check; not verifying file integrity");

	case LZMA_UNSUPPORTED_CHECK:
		return ("Unsupported type of integrity check; "
			"not verifying file integrity");

	case LZMA_MEM_ERROR:
		return ("Memory error");

	case LZMA_MEMLIMIT_ERROR:
		return ("Memory usage limit reached");

	case LZMA_FORMAT_ERROR:
		return ("File format not recognized");

	case LZMA_OPTIONS_ERROR:
		return ("Unsupported options");

	case LZMA_DATA_ERROR:
		return ("Compressed data is corrupt");

	case LZMA_BUF_ERROR:
		return ("Unexpected end of input");

	case LZMA_OK:
	case LZMA_STREAM_END:
	case LZMA_GET_CHECK:
	case LZMA_PROG_ERROR:
		// Without "default", compiler will warn if new constants
		// are added to lzma_ret, it is not too easy to forget to
		// add the new constants to this function.
		break;
	}

	return ("Internal error (bug)");
}

static bool io_pread(Stream ^stream, array<Byte>^buf, size_t size, int64_t pos)
{
	if (stream->Seek(pos, SeekOrigin::Begin) != pos)
		throw gcnew InvalidDataException("unable to seek to pos");
	if (stream->Read(buf, 0, size) != size)
		throw gcnew InvalidDataException("unable to read size");
	return true;
}

struct xz_file_basic_info
{
	uint64_t stream_count;
	uint64_t block_count;
	uint64_t file_size;
	uint64_t uncompressed_size;
};

static void liblzma_wrapper::parse_indexes(liblzma_wrapper::XZFileInfo ^xfbi, Stream ^stream)
{
	xz_file_info sxfi = { NULL, 0, 0, true, 50000002 };
	xz_file_info *xfi = &sxfi;
	int64_t length = stream->Length;
	if (length < 2 * LZMA_STREAM_HEADER_SIZE)
		throw gcnew InvalidDataException("Too small to be a valid .xz file");

	lzma_stream_flags header_flags;
	lzma_stream_flags footer_flags;
	lzma_ret ret;

	// lzma_stream for the Index decoder
	lzma_stream strm = LZMA_STREAM_INIT;

	// All Indexes decoded so far
	lzma_index *combined_index = NULL;

	// The Index currently being decoded
	lzma_index *this_index = NULL;

	try {

		// Current position in the file. We parse the file backwards so
		// initialize it to point to the end of the file.
		int64_t pos = length;
		array<Byte>^ nums = gcnew array<Byte>(IO_BUFFER_SIZE);
		pin_ptr<Byte> pp = &nums[0];
		uint8_t *buf_u8 = pp;
		uint32_t *buf_u32 = (uint32_t *)(buf_u8);

		// Each loop iteration decodes one Index.
		do {
			// Check that there is enough data left to contain at least
			// the Stream Header and Stream Footer. This check cannot
			// fail in the first pass of this loop.
			if (pos < 2 * LZMA_STREAM_HEADER_SIZE)
				throw gcnew InvalidDataException(message_strm(LZMA_DATA_ERROR));

			pos -= LZMA_STREAM_HEADER_SIZE;
			lzma_vli stream_padding = 0;

			// Locate the Stream Footer. There may be Stream Padding which
			// we must skip when reading backwards.
			while (true) {
				if (pos < LZMA_STREAM_HEADER_SIZE)
					throw gcnew InvalidDataException(message_strm(LZMA_DATA_ERROR));

				io_pread(stream, nums, LZMA_STREAM_HEADER_SIZE, pos);

				// Stream Padding is always a multiple of four bytes.
				int i = 2;
				if (buf_u32[i] != 0)
					break;

				// To avoid calling io_pread() for every four bytes
				// of Stream Padding, take advantage that we read
				// 12 bytes (LZMA_STREAM_HEADER_SIZE) already and
				// check them too before calling io_pread() again.
				do {
					stream_padding += 4;
					pos -= 4;
					--i;
				} while (i >= 0 && buf_u32[i] == 0);
			}

			// Decode the Stream Footer.
			ret = lzma_stream_footer_decode(&footer_flags, buf_u8);
			if (ret != LZMA_OK)
				throw gcnew InvalidDataException(message_strm(ret));

			// Check that the Stream Footer doesn't specify something
			// that we don't support. This can only happen if the xz
			// version is older than liblzma and liblzma supports
			// something new.
			//
			// It is enough to check Stream Footer. Stream Header must
			// match when it is compared against Stream Footer with
			// lzma_stream_flags_compare().
			if (footer_flags.version != 0)
				throw gcnew InvalidDataException(message_strm(LZMA_OPTIONS_ERROR));

			// Check that the size of the Index field looks sane.
			lzma_vli index_size = footer_flags.backward_size;
			if ((lzma_vli)(pos) < index_size + LZMA_STREAM_HEADER_SIZE)
				throw gcnew InvalidDataException(message_strm(LZMA_DATA_ERROR));

			// Set pos to the beginning of the Index.
			pos -= index_size;

			// Decode the Index.
			ret = lzma_index_decoder(&strm, &this_index, UINT64_MAX);
			if (ret != LZMA_OK)
				throw gcnew InvalidDataException(message_strm(ret));

			do {
				// Don't give the decoder more input than the
				// Index size.
				strm.avail_in = (size_t)(IO_BUFFER_SIZE < index_size ? IO_BUFFER_SIZE : index_size);
				io_pread(stream, nums, strm.avail_in, pos);

				pos += strm.avail_in;
				index_size -= strm.avail_in;

				strm.next_in = buf_u8;
				ret = lzma_code(&strm, LZMA_RUN);

			} while (ret == LZMA_OK);

			// If the decoding seems to be successful, check also that
			// the Index decoder consumed as much input as indicated
			// by the Backward Size field.
			if (ret == LZMA_STREAM_END)
				if (index_size != 0 || strm.avail_in != 0)
					ret = LZMA_DATA_ERROR;

			if (ret != LZMA_STREAM_END) {
				// LZMA_BUFFER_ERROR means that the Index decoder
				// would have liked more input than what the Index
				// size should be according to Stream Footer.
				// The message for LZMA_DATA_ERROR makes more
				// sense in that case.
				if (ret == LZMA_BUF_ERROR)
					ret = LZMA_DATA_ERROR;

				throw gcnew InvalidDataException(message_strm(ret));
			}

			// Decode the Stream Header and check that its Stream Flags
			// match the Stream Footer.
			pos -= footer_flags.backward_size + LZMA_STREAM_HEADER_SIZE;
			if ((lzma_vli)(pos) < lzma_index_total_size(this_index))
				throw gcnew InvalidDataException(message_strm(LZMA_DATA_ERROR));

			pos -= lzma_index_total_size(this_index);
			io_pread(stream, nums, LZMA_STREAM_HEADER_SIZE, pos);

			ret = lzma_stream_header_decode(&header_flags, buf_u8);
			if (ret != LZMA_OK)
				throw gcnew InvalidDataException(message_strm(ret));

			ret = lzma_stream_flags_compare(&header_flags, &footer_flags);
			if (ret != LZMA_OK)
				throw gcnew InvalidDataException(message_strm(ret));

			// Store the decoded Stream Flags into this_index. This is
			// needed so that we can print which Check is used in each
			// Stream.
			ret = lzma_index_stream_flags(this_index, &footer_flags);
			if (ret != LZMA_OK)
				throw gcnew InvalidOperationException(message_strm(ret));

			// Store also the size of the Stream Padding field. It is
			// needed to show the offsets of the Streams correctly.
			ret = lzma_index_stream_padding(this_index, stream_padding);
			if (ret != LZMA_OK)
				throw gcnew InvalidOperationException(message_strm(ret));

			if (combined_index != NULL) {
				// Append the earlier decoded Indexes
				// after this_index.
				ret = lzma_index_cat(
					this_index, combined_index, NULL);
				if (ret != LZMA_OK)
					throw gcnew InvalidOperationException(message_strm(ret));
			}

			combined_index = this_index;
			this_index = NULL;

			xfi->stream_padding += stream_padding;

		} while (pos > 0);

		// All OK. Make combined_index available to the caller.
		xfi->idx = combined_index;

		xfbi->stream_count = lzma_index_stream_count(xfi->idx);
		xfbi->block_count = lzma_index_block_count(xfi->idx);
		xfbi->file_size = lzma_index_file_size(xfi->idx);
		xfbi->uncompressed_size = lzma_index_uncompressed_size(xfi->idx);
	}
	finally
	{
		lzma_end(&strm);
		lzma_index_end(combined_index, NULL);
		lzma_index_end(this_index, NULL);
	}
}

int liblzma_wrapper::LZMAStream::Read(cli::array<unsigned char, 1> ^buffer, int offset, int size)
{
	if (bCompress)
		throw gcnew InvalidOperationException("Operation not supported");

	if (strm->avail_in == 0)
	{
		strm->avail_in = stream->Read(gc_buf, 0, gc_buf->Length);
		pin_ptr<Byte> pp_inbuf = &gc_buf[0];
		strm->next_in = pp_inbuf;
	}

	pin_ptr<Byte> pp_outbuf = &buffer[0];
	strm->next_out = pp_outbuf + offset;
	strm->avail_out = size;

	ret = lzma_code(strm, LZMA_RUN);

	if (ret != LZMA_OK && ret != LZMA_STREAM_END)
		throw gcnew InvalidOperationException(message_strm(ret));

	return size - strm->avail_out;
}

void liblzma_wrapper::LZMAStream::Flush()
{
	if (bCompress)
	{
		do
		{
			strm->next_in = nullptr;
			strm->avail_in = 0;

			pin_ptr<Byte> pp_outbuf = &gc_buf[0];
			strm->next_out = pp_outbuf;
			size_t outlen = gc_buf->Length;
			strm->avail_out = outlen;

			ret = lzma_code(strm, LZMA_FINISH);

			if (ret != LZMA_OK && ret != LZMA_STREAM_END)
				throw gcnew InvalidOperationException(message_strm(ret));

			int64_t avail = outlen - strm->avail_out;
			if (avail > 0)
				stream->Write(gc_buf, 0, (int)avail);
		} while (strm->avail_in > 0);
	}
}

void liblzma_wrapper::LZMAStream::Write(cli::array<unsigned char, 1> ^buffer, int offset, int size)
{
	if (!bCompress)
		throw gcnew InvalidOperationException("Operation not supported");

	pin_ptr<Byte> pp_inbuf = &buffer[0];
	strm->next_in = pp_inbuf + offset;
	strm->avail_in = size;

	while (strm->avail_in > 0)
	{
		pin_ptr<Byte> pp_outbuf = &gc_buf[0];
		strm->next_out = pp_outbuf;
		size_t outlen = gc_buf->Length;
		strm->avail_out = outlen;

		ret = lzma_code(strm, LZMA_RUN);

		if (ret != LZMA_OK && ret != LZMA_STREAM_END)
			throw gcnew InvalidOperationException(message_strm(ret));

		int64_t avail = outlen - strm->avail_out;
		if (avail > 0)
			stream->Write(gc_buf, 0, (int)avail);
	}
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImagePipe.cxx

  Copyright (c) John Baxter, Robarts Research Institute
  All rights reserved.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkImagePipe.h"

#include "vtkObjectFactory.h"
#include "vtkDataArray.h"
#include "vtkUnsignedCharArray.h"
#include "vtkCriticalSection.h"
#include "vtkTimerLog.h"

#include "vtkPointData.h"

#include <iostream>

#include <unistd.h>

vtkStandardNewMacro(vtkImagePipe);

extern "C"
struct vtkImagePipeInitData {
	int extent[6];
	double origin[3];
	double spacing[3];
	int scalarType;
	int scalarSize;
	int numComponents;
	int imageSize; //can also be used to weakly confirm data integrity
};

//----------------------------------------------------------------------------
vtkImagePipe::vtkImagePipe()
{
	//set some reasonable default values
	this->Initialized = 0;

	this->controller = vtkSocketController::New();
	this->controller->Initialize();
	threader = vtkMultiThreader::New();

	//initialize to neither client nor server, but unset
	this->isServer = false;
	this->serverSet = false;
	this->portNumber = -1;
	this->IPAddress = 0;
	this->serverSocket = 0;
	this->clientSocket = 0;
	this->buffer = 0;
	this->ImageSize = 0;

	//initialize the mutex locks
	this->newThreadLock = vtkMutexLock::New();
	this->rwBufferLock = vtkReadWriteLock::New();

}

//----------------------------------------------------------------------------
vtkImagePipe::~vtkImagePipe()
{
  this->ReleaseSystemResources();
  this->newThreadLock->Delete();
  this->rwBufferLock->Delete();
  this->threader->Delete();
}

//----------------------------------------------------------------------------
void vtkImagePipe::ReleaseSystemResources()
{
	if( !this->Initialized ) return;

	if( !this->isServer ){
		int request = -1;
		this->clientSocket->Send( (void*) &request, sizeof(request) );
		this->clientSocket->CloseSocket();
	}else{
		this->threader->TerminateThread( this->mainServerThread );
	}

	if( this->serverSocket ){
		this->serverSocket->CloseSocket();
		this->serverSocket->Delete();
		this->serverSocket = 0;
	}
	if( this->clientSocket ){
		this->clientSocket->CloseSocket();
		this->clientSocket->Delete();
		this->clientSocket = 0;
	}
	this->portNumber = -1;
	this->IPAddress = 0;
	this->isServer = false;
	this->serverSet = false;
	this->Initialized = 0;
}

//----------------------------------------------------------------------------
void vtkImagePipe::SetInput( vtkImageData* in ){
	if( !this->serverSet || !this->isServer ){
		vtkErrorMacro(<<"Must be in server mode.");
		return;
	}

	this->buffer = in;
}

//----------------------------------------------------------------------------
vtkImageData* vtkImagePipe::GetOutput( ){
	if( !this->serverSet || this->isServer ){
		vtkErrorMacro(<<"Must be in client mode.");
		return 0 ;
	}
	if( !this->Initialized ){
		vtkErrorMacro(<<"Must be initialized first.");
		return 0 ;
	}

	return this->buffer;
}

//----------------------------------------------------------------------------
void vtkImagePipe::SetAsServer( bool isServer ){

	// if we are already initialized, you cannot set the server status
	if (this->Initialized){
		vtkErrorMacro(<<"Must uninitialize before changing parameters.");
		return;
	}

	this->isServer = isServer;
	if( this->serverSocket ){
		this->serverSocket->CloseSocket();
		this->serverSocket->Delete();
		this->serverSocket = 0;
	}
	if( this->clientSocket ){
		this->clientSocket->CloseSocket();
		this->clientSocket->Delete();
		this->clientSocket = 0;
	}
	if( isServer ) this->serverSocket = vtkServerSocket::New();
	else this->clientSocket = vtkClientSocket::New();
	this->serverSet = true;
}

void vtkImagePipe::SetSourceAddress( char* ipAddress, int portNumber ){

	// if we are already initialized, you cannot set the server status
	if (this->Initialized){
		vtkErrorMacro(<<"Must uninitialize before changing parameters.");
		return;
	}

	if( portNumber < 0 ) {
		vtkErrorMacro(<<"Invalid port number.");
		return;
	}

	if( !this->serverSet ) {
		vtkErrorMacro(<<"Must first specify whether client or server using SetAsServer().");
		return;
	}

	if( this->isServer ){
		if( this->serverSocket->CreateServer( portNumber ) ){
			vtkErrorMacro(<<"Could not connect to port.");
			return;
		}else{
			this->portNumber = portNumber;
		}
	}else{
		this->IPAddress = ipAddress;
		this->portNumber = portNumber;
	}
}

//----------------------------------------------------------------------------
void vtkImagePipe::PrintSelf(ostream& os, vtkIndent indent)
{

}

//----------------------------------------------------------------------------
void vtkImagePipe::Initialize()
{
	// if we are already initialized, do not initialize again
	if (this->Initialized){
		return;
	}

	//if we haven't set the client-server status,
	if ( !this->serverSet || this->portNumber == -1 ){
		vtkErrorMacro(<<"Set the client/server settings before initialization.");
		return;
	}

	//if we are the server, make sure we have input set
	if( this->isServer ){
		if( !this->buffer ){
			vtkErrorMacro(<<"Need to set the input.");
			return;
		}
		this->mainServerThread = this->threader->SpawnThread( (vtkThreadFunctionType) &FirstServerSideUpdate, (void*) this );
	}

	//create the connection if a client
	if( !this->isServer ){
		int connectedStatus = this->clientSocket->ConnectToServer( this->IPAddress, this->portNumber );
		if( connectedStatus ){
			vtkErrorMacro(<<"Could not connect to server side socket.");
			return;
		}
	}

	//create output buffer if client
	if( !this->isServer ){
		buffer = vtkImageData::New();
	}

	// Initialization worked
	this->Initialized = 1;

}

void* vtkImagePipe::FirstServerSideUpdate(vtkMultiThreader::ThreadInfo *data){

	vtkImagePipe *self = (vtkImagePipe *)(data->UserData);

	//enter the infinite loop
	while(true){
		//check for any new clients
		vtkClientSocket* newClient = self->serverSocket->WaitForConnection(1);
		if( newClient ){
			self->newThreadLock->Lock();
			self->clientSocket = newClient;
			self->threader->SpawnThread( (vtkThreadFunctionType) &ServerSideUpdate, (void*) self );
		}else{
			sleep( 100 );
		}
	}
	return 0;

}

void* vtkImagePipe::ServerSideUpdate(vtkMultiThreader::ThreadInfo *data){

	//collect server and client information
	vtkImagePipe *self = (vtkImagePipe *)(data->UserData);
	vtkClientSocket* client = self->clientSocket;
	self->newThreadLock->Unlock();

	//enter the infinite loop
	while(true){

		//if we have a request, push data onto the pipe
		int request = 0;
		int amount = client->Receive( &request, sizeof(request), 1 );
		if( amount == 0 ) break;
		else if( amount < sizeof(request) ) continue;
		else if( request != 1 ) break;

		//read lock the buffer
		self->rwBufferLock->ReaderLock();

		//create the info structure
		vtkImagePipeInitData initData;
		self->buffer->GetExtent( initData.extent );
		self->buffer->GetSpacing( initData.spacing );
		self->buffer->GetOrigin( initData.origin );
		initData.scalarType = self->buffer->GetScalarType();
		initData.numComponents = self->buffer->GetNumberOfScalarComponents();
		initData.scalarSize = self->buffer->GetScalarSize();
		initData.imageSize = (initData.extent[1] - initData.extent[0] + 1) *
								(initData.extent[3] - initData.extent[2] + 1) *
								(initData.extent[5] - initData.extent[4] + 1) *
								initData.numComponents * initData.scalarSize;
		self->ImageSize = initData.imageSize;

		//send over the data
		client->Send( (void*) &initData, sizeof(initData) );
		client->Send( self->buffer->GetScalarPointer(), self->ImageSize );

		//read unlock the buffer
		self->rwBufferLock->ReaderUnlock();

	}

	client->CloseSocket();
	return 0;

}

void vtkImagePipe::Update(){
	if( !this->Initialized ) return;
	if( this->isServer ){
		//protect buffer updating with read/write lock
		this->rwBufferLock->WriterLock();
		this->buffer->Update();
		this->rwBufferLock->WriterUnlock();
	}else{
		ClientSideUpdate();
	}
}

void vtkImagePipe::ClientSideUpdate(){

	//send input request
	int request = 1;
	int serverThere = this->clientSocket->Send( &request, sizeof(request) );
	if( !serverThere ){
		vtkErrorMacro(<<"Server unavailable.");
		return;
	}

	//collect input parameters and change the output buffer if needed
	vtkImagePipeInitData initData;
	serverThere = clientSocket->Receive( (void*) &initData, sizeof(initData), 1 );
	if( !serverThere ){
		vtkErrorMacro(<<"Server unavailable.");
		return;
	}
	this->buffer->SetSpacing( initData.spacing );
	this->buffer->SetOrigin( initData.origin );
	this->buffer->SetExtent( initData.extent );
	this->buffer->SetNumberOfScalarComponents( initData.numComponents );
	this->buffer->SetScalarType( initData.scalarType );
	int calcImageSize = (initData.extent[1] - initData.extent[0] + 1) *
						(initData.extent[3] - initData.extent[2] + 1) *
						(initData.extent[5] - initData.extent[4] + 1) *
						initData.numComponents * initData.scalarSize;
	this->ImageSize = initData.imageSize;
	if( this->ImageSize != calcImageSize ){
		vtkErrorMacro(<<"Image information packet does not conform to the image size error check.");
		return;
	}
	this->buffer->AllocateScalars();

	//grab the data from the socket
	serverThere = this->clientSocket->Receive( this->buffer->GetScalarPointer(), this->ImageSize, 1 );
	if( !serverThere ){
		vtkErrorMacro(<<"Server unavailable.");
		return;
	}

}
<commit_msg>FIX: Sleep command should now be OS independent.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImagePipe.cxx

  Copyright (c) John Baxter, Robarts Research Institute
  All rights reserved.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkImagePipe.h"

#include "vtkObjectFactory.h"
#include "vtkDataArray.h"
#include "vtkUnsignedCharArray.h"
#include "vtkCriticalSection.h"
#include "vtkTimerLog.h"

#include "vtkPointData.h"

#include <iostream>

vtkStandardNewMacro(vtkImagePipe);

extern "C"
struct vtkImagePipeInitData {
	int extent[6];
	double origin[3];
	double spacing[3];
	int scalarType;
	int scalarSize;
	int numComponents;
	int imageSize; //can also be used to weakly confirm data integrity
};

//----------------------------------------------------------------------------
vtkImagePipe::vtkImagePipe()
{
	//set some reasonable default values
	this->Initialized = 0;

	this->controller = vtkSocketController::New();
	this->controller->Initialize();
	threader = vtkMultiThreader::New();

	//initialize to neither client nor server, but unset
	this->isServer = false;
	this->serverSet = false;
	this->portNumber = -1;
	this->IPAddress = 0;
	this->serverSocket = 0;
	this->clientSocket = 0;
	this->buffer = 0;
	this->ImageSize = 0;

	//initialize the mutex locks
	this->newThreadLock = vtkMutexLock::New();
	this->rwBufferLock = vtkReadWriteLock::New();

}

//----------------------------------------------------------------------------
vtkImagePipe::~vtkImagePipe()
{
  this->ReleaseSystemResources();
  this->newThreadLock->Delete();
  this->rwBufferLock->Delete();
  this->threader->Delete();
}

//----------------------------------------------------------------------------
void vtkImagePipe::ReleaseSystemResources()
{
	if( !this->Initialized ) return;

	if( !this->isServer ){
		int request = -1;
		this->clientSocket->Send( (void*) &request, sizeof(request) );
		this->clientSocket->CloseSocket();
	}else{
		this->threader->TerminateThread( this->mainServerThread );
	}

	if( this->serverSocket ){
		this->serverSocket->CloseSocket();
		this->serverSocket->Delete();
		this->serverSocket = 0;
	}
	if( this->clientSocket ){
		this->clientSocket->CloseSocket();
		this->clientSocket->Delete();
		this->clientSocket = 0;
	}
	this->portNumber = -1;
	this->IPAddress = 0;
	this->isServer = false;
	this->serverSet = false;
	this->Initialized = 0;
}

//----------------------------------------------------------------------------
void vtkImagePipe::SetInput( vtkImageData* in ){
	if( !this->serverSet || !this->isServer ){
		vtkErrorMacro(<<"Must be in server mode.");
		return;
	}

	this->buffer = in;
}

//----------------------------------------------------------------------------
vtkImageData* vtkImagePipe::GetOutput( ){
	if( !this->serverSet || this->isServer ){
		vtkErrorMacro(<<"Must be in client mode.");
		return 0 ;
	}
	if( !this->Initialized ){
		vtkErrorMacro(<<"Must be initialized first.");
		return 0 ;
	}

	return this->buffer;
}

//----------------------------------------------------------------------------
void vtkImagePipe::SetAsServer( bool isServer ){

	// if we are already initialized, you cannot set the server status
	if (this->Initialized){
		vtkErrorMacro(<<"Must uninitialize before changing parameters.");
		return;
	}

	this->isServer = isServer;
	if( this->serverSocket ){
		this->serverSocket->CloseSocket();
		this->serverSocket->Delete();
		this->serverSocket = 0;
	}
	if( this->clientSocket ){
		this->clientSocket->CloseSocket();
		this->clientSocket->Delete();
		this->clientSocket = 0;
	}
	if( isServer ) this->serverSocket = vtkServerSocket::New();
	else this->clientSocket = vtkClientSocket::New();
	this->serverSet = true;
}

void vtkImagePipe::SetSourceAddress( char* ipAddress, int portNumber ){

	// if we are already initialized, you cannot set the server status
	if (this->Initialized){
		vtkErrorMacro(<<"Must uninitialize before changing parameters.");
		return;
	}

	if( portNumber < 0 ) {
		vtkErrorMacro(<<"Invalid port number.");
		return;
	}

	if( !this->serverSet ) {
		vtkErrorMacro(<<"Must first specify whether client or server using SetAsServer().");
		return;
	}

	if( this->isServer ){
		if( this->serverSocket->CreateServer( portNumber ) ){
			vtkErrorMacro(<<"Could not connect to port.");
			return;
		}else{
			this->portNumber = portNumber;
		}
	}else{
		this->IPAddress = ipAddress;
		this->portNumber = portNumber;
	}
}

//----------------------------------------------------------------------------
void vtkImagePipe::PrintSelf(ostream& os, vtkIndent indent)
{

}

//----------------------------------------------------------------------------
void vtkImagePipe::Initialize()
{
	// if we are already initialized, do not initialize again
	if (this->Initialized){
		return;
	}

	//if we haven't set the client-server status,
	if ( !this->serverSet || this->portNumber == -1 ){
		vtkErrorMacro(<<"Set the client/server settings before initialization.");
		return;
	}

	//if we are the server, make sure we have input set
	if( this->isServer ){
		if( !this->buffer ){
			vtkErrorMacro(<<"Need to set the input.");
			return;
		}
		this->mainServerThread = this->threader->SpawnThread( (vtkThreadFunctionType) &FirstServerSideUpdate, (void*) this );
	}

	//create the connection if a client
	if( !this->isServer ){
		int connectedStatus = this->clientSocket->ConnectToServer( this->IPAddress, this->portNumber );
		if( connectedStatus ){
			vtkErrorMacro(<<"Could not connect to server side socket.");
			return;
		}
	}

	//create output buffer if client
	if( !this->isServer ){
		buffer = vtkImageData::New();
	}

	// Initialization worked
	this->Initialized = 1;

}

//----------------------------------------------------------------------------
// platform-independent sleep function
static inline void vtkSleep(double duration)
{
  duration = duration; // avoid warnings
  // sleep according to OS preference
#ifdef _WIN32
  Sleep((int)(1000*duration));
#elif defined(__FreeBSD__) || defined(__linux__) || defined(sgi)
  struct timespec sleep_time, dummy;
  sleep_time.tv_sec = (int)duration;
  sleep_time.tv_nsec = (int)(1000000000*(duration-sleep_time.tv_sec));
  nanosleep(&sleep_time,&dummy);
#endif
}
//----------------------------------------------------------------------------

void* vtkImagePipe::FirstServerSideUpdate(vtkMultiThreader::ThreadInfo *data){

	vtkImagePipe *self = (vtkImagePipe *)(data->UserData);

	//enter the infinite loop
	while(true){
		//check for any new clients
		vtkClientSocket* newClient = self->serverSocket->WaitForConnection(1);
		if( newClient ){
			self->newThreadLock->Lock();
			self->clientSocket = newClient;
			self->threader->SpawnThread( (vtkThreadFunctionType) &ServerSideUpdate, (void*) self );
		}else{
			vtkSleep(100);
		}
	}
	return 0;

}

void* vtkImagePipe::ServerSideUpdate(vtkMultiThreader::ThreadInfo *data){

	//collect server and client information
	vtkImagePipe *self = (vtkImagePipe *)(data->UserData);
	vtkClientSocket* client = self->clientSocket;
	self->newThreadLock->Unlock();

	//enter the infinite loop
	while(true){

		//if we have a request, push data onto the pipe
		int request = 0;
		int amount = client->Receive( &request, sizeof(request), 1 );
		if( amount == 0 ) break;
		else if( amount < sizeof(request) ) continue;
		else if( request != 1 ) break;

		//read lock the buffer
		self->rwBufferLock->ReaderLock();

		//create the info structure
		vtkImagePipeInitData initData;
		self->buffer->GetExtent( initData.extent );
		self->buffer->GetSpacing( initData.spacing );
		self->buffer->GetOrigin( initData.origin );
		initData.scalarType = self->buffer->GetScalarType();
		initData.numComponents = self->buffer->GetNumberOfScalarComponents();
		initData.scalarSize = self->buffer->GetScalarSize();
		initData.imageSize = (initData.extent[1] - initData.extent[0] + 1) *
								(initData.extent[3] - initData.extent[2] + 1) *
								(initData.extent[5] - initData.extent[4] + 1) *
								initData.numComponents * initData.scalarSize;
		self->ImageSize = initData.imageSize;

		//send over the data
		client->Send( (void*) &initData, sizeof(initData) );
		client->Send( self->buffer->GetScalarPointer(), self->ImageSize );

		//read unlock the buffer
		self->rwBufferLock->ReaderUnlock();

	}

	client->CloseSocket();
	return 0;

}

void vtkImagePipe::Update(){
	if( !this->Initialized ) return;
	if( this->isServer ){
		//protect buffer updating with read/write lock
		this->rwBufferLock->WriterLock();
		this->buffer->Update();
		this->rwBufferLock->WriterUnlock();
	}else{
		ClientSideUpdate();
	}
}

void vtkImagePipe::ClientSideUpdate(){

	//send input request
	int request = 1;
	int serverThere = this->clientSocket->Send( &request, sizeof(request) );
	if( !serverThere ){
		vtkErrorMacro(<<"Server unavailable.");
		return;
	}

	//collect input parameters and change the output buffer if needed
	vtkImagePipeInitData initData;
	serverThere = clientSocket->Receive( (void*) &initData, sizeof(initData), 1 );
	if( !serverThere ){
		vtkErrorMacro(<<"Server unavailable.");
		return;
	}
	this->buffer->SetSpacing( initData.spacing );
	this->buffer->SetOrigin( initData.origin );
	this->buffer->SetExtent( initData.extent );
	this->buffer->SetNumberOfScalarComponents( initData.numComponents );
	this->buffer->SetScalarType( initData.scalarType );
	int calcImageSize = (initData.extent[1] - initData.extent[0] + 1) *
						(initData.extent[3] - initData.extent[2] + 1) *
						(initData.extent[5] - initData.extent[4] + 1) *
						initData.numComponents * initData.scalarSize;
	this->ImageSize = initData.imageSize;
	if( this->ImageSize != calcImageSize ){
		vtkErrorMacro(<<"Image information packet does not conform to the image size error check.");
		return;
	}
	this->buffer->AllocateScalars();

	//grab the data from the socket
	serverThere = this->clientSocket->Receive( this->buffer->GetScalarPointer(), this->ImageSize, 1 );
	if( !serverThere ){
		vtkErrorMacro(<<"Server unavailable.");
		return;
	}

}
<|endoftext|>


<commit_before><commit_msg>Don't consider a certificate revoked if we don't have fresh revocation status of the certificate.<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/browser/ui/views/menu_bar.h"

#if defined(USE_X11)
#include "gtk/gtk.h"
#endif

#include "atom/browser/ui/views/menu_delegate.h"
#include "atom/browser/ui/views/submenu_button.h"
#include "ui/base/models/menu_model.h"
#include "ui/views/background.h"
#include "ui/views/layout/box_layout.h"

#if defined(OS_WIN)
#include "ui/gfx/color_utils.h"
#elif defined(USE_X11)
#include "chrome/browser/ui/libgtk2ui/owned_widget_gtk2.h"
#include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h"
#endif

namespace atom {

namespace {

const char kViewClassName[] = "AtomMenuBar";

// Default color of the menu bar.
const SkColor kDefaultColor = SkColorSetARGB(255, 233, 233, 233);

#if defined(USE_X11)
void GetMenuBarColor(SkColor* enabled, SkColor* disabled, SkColor* highlight,
                     SkColor* hover, SkColor* background) {
  libgtk2ui::OwnedWidgetGtk fake_menu_bar;
  fake_menu_bar.Own(gtk_menu_bar_new());

  GtkStyle* style = gtk_rc_get_style(fake_menu_bar.get());
  *enabled = libgtk2ui::GdkColorToSkColor(style->fg[GTK_STATE_NORMAL]);
  *disabled = libgtk2ui::GdkColorToSkColor(style->fg[GTK_STATE_INSENSITIVE]);
  *highlight = libgtk2ui::GdkColorToSkColor(style->fg[GTK_STATE_SELECTED]);
  *hover = libgtk2ui::GdkColorToSkColor(style->fg[GTK_STATE_PRELIGHT]);
  *background = libgtk2ui::GdkColorToSkColor(style->bg[GTK_STATE_NORMAL]);
}
#endif

}  // namespace

MenuBar::MenuBar()
    : background_color_(kDefaultColor),
      menu_model_(NULL) {
#if defined(OS_WIN)
  background_color_ = color_utils::GetSysSkColor(COLOR_MENUBAR);
#elif defined(USE_X11)
  GetMenuBarColor(&enabled_color_, &disabled_color_, &highlight_color_,
                  &hover_color_, &background_color_);
#endif

  set_background(views::Background::CreateSolidBackground(background_color_));
  SetLayoutManager(new views::BoxLayout(
      views::BoxLayout::kHorizontal, 0, 0, 0));
}

MenuBar::~MenuBar() {
}

void MenuBar::SetMenu(ui::MenuModel* model) {
  menu_model_ = model;
  RemoveAllChildViews(true);

  for (int i = 0; i < model->GetItemCount(); ++i) {
    SubmenuButton* button = new SubmenuButton(this, model->GetLabelAt(i), this);
    button->set_tag(i);

#if defined(USE_X11)
    button->SetEnabledColor(enabled_color_);
    button->SetDisabledColor(disabled_color_);
    button->SetHighlightColor(highlight_color_);
    button->SetHoverColor(hover_color_);
    button->SetUnderlineColor(enabled_color_);
#endif

    AddChildView(button);
  }
}

void MenuBar::SetAcceleratorVisibility(bool visible) {
  for (int i = 0; i < child_count(); ++i)
    static_cast<SubmenuButton*>(child_at(i))->SetAcceleratorVisibility(visible);
}

int MenuBar::GetAcceleratorIndex(base::char16 key) {
  for (int i = 0; i < child_count(); ++i) {
    SubmenuButton* button = static_cast<SubmenuButton*>(child_at(i));
    if (button->accelerator() == key)
      return i;
  }
  return -1;
}

void MenuBar::ActivateAccelerator(base::char16 key) {
  int i = GetAcceleratorIndex(key);
  if (i != -1) {
    SetAcceleratorVisibility(false);
    static_cast<SubmenuButton*>(child_at(i))->Activate();
  }
}

int MenuBar::GetItemCount() const {
  return menu_model_->GetItemCount();
}

bool MenuBar::GetMenuButtonFromScreenPoint(const gfx::Point& point,
                                           ui::MenuModel** menu_model,
                                           views::MenuButton** button) {
  gfx::Point location(point);
  views::View::ConvertPointFromScreen(this, &location);

  if (location.x() < 0 || location.x() >= width() || location.y() < 0 ||
      location.y() >= height())
    return false;

  for (int i = 0; i < child_count(); ++i) {
    views::View* view = child_at(i);
    if (view->bounds().Contains(location) &&
        (menu_model_->GetTypeAt(i) == ui::MenuModel::TYPE_SUBMENU)) {
      *menu_model = menu_model_->GetSubmenuModelAt(i);
      *button = static_cast<views::MenuButton*>(view);
      return true;
    }
  }

  return false;
}

const char* MenuBar::GetClassName() const {
  return kViewClassName;
}

void MenuBar::ButtonPressed(views::Button* sender, const ui::Event& event) {
}

void MenuBar::OnMenuButtonClicked(views::View* source,
                                  const gfx::Point& point) {
  if (!menu_model_)
    return;

  views::MenuButton* button = static_cast<views::MenuButton*>(source);
  int id = button->tag();
  ui::MenuModel::ItemType type = menu_model_->GetTypeAt(id);
  if (type != ui::MenuModel::TYPE_SUBMENU)
    return;

  menu_delegate_.reset(new MenuDelegate(this));
  menu_delegate_->RunMenu(menu_model_->GetSubmenuModelAt(id), button);
}

}  // namespace atom
<commit_msg>views: Always hide accelerator when submenu is activated.<commit_after>// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/browser/ui/views/menu_bar.h"

#if defined(USE_X11)
#include "gtk/gtk.h"
#endif

#include "atom/browser/ui/views/menu_delegate.h"
#include "atom/browser/ui/views/submenu_button.h"
#include "ui/base/models/menu_model.h"
#include "ui/views/background.h"
#include "ui/views/layout/box_layout.h"

#if defined(OS_WIN)
#include "ui/gfx/color_utils.h"
#elif defined(USE_X11)
#include "chrome/browser/ui/libgtk2ui/owned_widget_gtk2.h"
#include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h"
#endif

namespace atom {

namespace {

const char kViewClassName[] = "AtomMenuBar";

// Default color of the menu bar.
const SkColor kDefaultColor = SkColorSetARGB(255, 233, 233, 233);

#if defined(USE_X11)
void GetMenuBarColor(SkColor* enabled, SkColor* disabled, SkColor* highlight,
                     SkColor* hover, SkColor* background) {
  libgtk2ui::OwnedWidgetGtk fake_menu_bar;
  fake_menu_bar.Own(gtk_menu_bar_new());

  GtkStyle* style = gtk_rc_get_style(fake_menu_bar.get());
  *enabled = libgtk2ui::GdkColorToSkColor(style->fg[GTK_STATE_NORMAL]);
  *disabled = libgtk2ui::GdkColorToSkColor(style->fg[GTK_STATE_INSENSITIVE]);
  *highlight = libgtk2ui::GdkColorToSkColor(style->fg[GTK_STATE_SELECTED]);
  *hover = libgtk2ui::GdkColorToSkColor(style->fg[GTK_STATE_PRELIGHT]);
  *background = libgtk2ui::GdkColorToSkColor(style->bg[GTK_STATE_NORMAL]);
}
#endif

}  // namespace

MenuBar::MenuBar()
    : background_color_(kDefaultColor),
      menu_model_(NULL) {
#if defined(OS_WIN)
  background_color_ = color_utils::GetSysSkColor(COLOR_MENUBAR);
#elif defined(USE_X11)
  GetMenuBarColor(&enabled_color_, &disabled_color_, &highlight_color_,
                  &hover_color_, &background_color_);
#endif

  set_background(views::Background::CreateSolidBackground(background_color_));
  SetLayoutManager(new views::BoxLayout(
      views::BoxLayout::kHorizontal, 0, 0, 0));
}

MenuBar::~MenuBar() {
}

void MenuBar::SetMenu(ui::MenuModel* model) {
  menu_model_ = model;
  RemoveAllChildViews(true);

  for (int i = 0; i < model->GetItemCount(); ++i) {
    SubmenuButton* button = new SubmenuButton(this, model->GetLabelAt(i), this);
    button->set_tag(i);

#if defined(USE_X11)
    button->SetEnabledColor(enabled_color_);
    button->SetDisabledColor(disabled_color_);
    button->SetHighlightColor(highlight_color_);
    button->SetHoverColor(hover_color_);
    button->SetUnderlineColor(enabled_color_);
#endif

    AddChildView(button);
  }
}

void MenuBar::SetAcceleratorVisibility(bool visible) {
  for (int i = 0; i < child_count(); ++i)
    static_cast<SubmenuButton*>(child_at(i))->SetAcceleratorVisibility(visible);
}

int MenuBar::GetAcceleratorIndex(base::char16 key) {
  for (int i = 0; i < child_count(); ++i) {
    SubmenuButton* button = static_cast<SubmenuButton*>(child_at(i));
    if (button->accelerator() == key)
      return i;
  }
  return -1;
}

void MenuBar::ActivateAccelerator(base::char16 key) {
  int i = GetAcceleratorIndex(key);
  if (i != -1)
    static_cast<SubmenuButton*>(child_at(i))->Activate();
}

int MenuBar::GetItemCount() const {
  return menu_model_->GetItemCount();
}

bool MenuBar::GetMenuButtonFromScreenPoint(const gfx::Point& point,
                                           ui::MenuModel** menu_model,
                                           views::MenuButton** button) {
  gfx::Point location(point);
  views::View::ConvertPointFromScreen(this, &location);

  if (location.x() < 0 || location.x() >= width() || location.y() < 0 ||
      location.y() >= height())
    return false;

  for (int i = 0; i < child_count(); ++i) {
    views::View* view = child_at(i);
    if (view->bounds().Contains(location) &&
        (menu_model_->GetTypeAt(i) == ui::MenuModel::TYPE_SUBMENU)) {
      *menu_model = menu_model_->GetSubmenuModelAt(i);
      *button = static_cast<views::MenuButton*>(view);
      return true;
    }
  }

  return false;
}

const char* MenuBar::GetClassName() const {
  return kViewClassName;
}

void MenuBar::ButtonPressed(views::Button* sender, const ui::Event& event) {
}

void MenuBar::OnMenuButtonClicked(views::View* source,
                                  const gfx::Point& point) {
  // Hide the accelerator when a submenu is activated.
  SetAcceleratorVisibility(false);

  if (!menu_model_)
    return;

  views::MenuButton* button = static_cast<views::MenuButton*>(source);
  int id = button->tag();
  ui::MenuModel::ItemType type = menu_model_->GetTypeAt(id);
  if (type != ui::MenuModel::TYPE_SUBMENU)
    return;

  menu_delegate_.reset(new MenuDelegate(this));
  menu_delegate_->RunMenu(menu_model_->GetSubmenuModelAt(id), button);
}

}  // namespace atom
<|endoftext|>


<commit_before>#include <iostream>
#include <unordered_map>
#include <string>

class Node{
  public:
    std::unordered_map<char, Node*> values;
    bool end_word;

    Node():end_word{true}{}
};

class Trie{
  private:
    Node root;
    Node * current;

  public:
    void add_word(const std::string & s){
      for (char c : s){
        if (root.
      }
    }
};

int main(){
  Trie a;
  a.add_word("abc");

  return 0;
}

<commit_msg>working, but needs improvemnt when counting the elements<commit_after>#include <iostream>
#include <unordered_map>
#include <string>

class Node{
  public:
    std::unordered_map<char, Node*> hash;
    bool end_word;

    Node():end_word{false}{}

    ~Node(){
      for (auto it = hash.begin(); it != hash.end(); it++){
        delete it->second;
      }
    }

};

class Trie{
  private:
    Node root;
  public:
    void add_word(const std::string & s){
      Node * aux = &root;
      for (int i=0; i < s.size(); i++){
        char c = s.at(i);
        std::unordered_map<char, Node*>::iterator it = aux->hash.find(c);
        if (it != aux->hash.end()){
          aux = it->second;
        }
        else {
          aux->hash.emplace(c, new Node());
          it = aux->hash.find(c);
          aux = it->second;
        }
        if (i==s.size()-1){
          aux->end_word = true;
        }
      }
    }

    void count_end_words(Node * aux, int & counter){
      if (aux->hash.empty()){
        return;
      }

      for(auto it = aux->hash.begin(); it!= aux->hash.end(); it++){
        if (it->second->end_word)
          counter++;
        count_end_words(it->second, counter);
      }
    }

    int count_words_starting_with(const std::string &s){
      Node * aux = &root;
      for (const char c : s){
        std::unordered_map<char, Node*>::iterator it = aux->hash.find(c);
        if (it == aux->hash.end()){
          /**letter does not exist in the current branch, therefore,
          * the word does not exist in the trie */
          return 0;
        }
        aux = it->second;
      }
      int count = 0;
      if (aux->end_word)
        count++;
      count_end_words(aux, count);
      return count;
    }
};

int main(){
  int n;
  std::cin >> n;
  Trie trie;
  for(int i = 0; i < n; i++){
    std::string s;
    std::cin >> s;
    if(!s.compare("add")){
      std::cin >> s;
      trie.add_word(s);
    } else {
      std::cin >> s;
      std::cout << trie.count_words_starting_with(s) << std::endl;
    }
  }

  return 0;
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007 Digital Bazaar, Inc.  All rights reserved.
 */
#include "AsymmetricKey.h"

using namespace std;
using namespace db::crypto;

AsymmetricKey::AsymmetricKey(EVP_PKEY* pkey)
{
   // set the public/private key structure
   mKey = pkey;
   mAlgorithm = NULL;
}

AsymmetricKey::~AsymmetricKey()
{
   // free the public/private key structure
   EVP_PKEY_free(mKey);

   if(mAlgorithm != NULL)
   {
      delete mAlgorithm;
   }
}

EVP_PKEY* AsymmetricKey::getPKEY()
{
   return mKey;
}

const char* AsymmetricKey::getAlgorithm()
{
   if(mAlgorithm == NULL)
   {
      switch(EVP_PKEY_type(getPKEY()->type))
      {
         case EVP_PKEY_DSA:
            mAlgorithm = "DSA";
            break;
         case EVP_PKEY_RSA:
            mAlgorithm = "RSA";
            break;
         default:
            mAlgorithm = "NONE";
      }
   }

   return mAlgorithm;
}

unsigned int AsymmetricKey::getOutputSize()
{
   return EVP_PKEY_size(getPKEY());
}
<commit_msg>Fixed memory leak with mAlgorithm in AsymmetricKey.<commit_after>/*
 * Copyright (c) 2007 Digital Bazaar, Inc.  All rights reserved.
 */
#include "AsymmetricKey.h"

using namespace std;
using namespace db::crypto;

AsymmetricKey::AsymmetricKey(EVP_PKEY* pkey)
{
   // set the public/private key structure
   mKey = pkey;
   mAlgorithm = NULL;
}

AsymmetricKey::~AsymmetricKey()
{
   // free the public/private key structure
   EVP_PKEY_free(mKey);

   if(mAlgorithm != NULL)
   {
      delete [] mAlgorithm;
   }
}

EVP_PKEY* AsymmetricKey::getPKEY()
{
   return mKey;
}

const char* AsymmetricKey::getAlgorithm()
{
   if(mAlgorithm == NULL)
   {
      switch(EVP_PKEY_type(getPKEY()->type))
      {
         case EVP_PKEY_DSA:
            mAlgorithm = new char[4];
            strcpy(mAlgorithm, "DSA");
            break;
         case EVP_PKEY_RSA:
            mAlgorithm = new char[4];
            strcpy(mAlgorithm, "RSA");
            break;
         default:
            mAlgorithm = new char[5];
            strcpy(mAlgorithm, "NONE");
      }
   }

   return mAlgorithm;
}

unsigned int AsymmetricKey::getOutputSize()
{
   return EVP_PKEY_size(getPKEY());
}
<|endoftext|>