<commit_before>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-443271.
//
// This file is part of the GLVis visualization tool and library. For more
// information and source code availability see https://glvis.org.
//
// GLVis is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include "visual.hpp"
#include "palettes.hpp"
#include "stream_reader.hpp"
#include <SDL2/SDL_hints.h>
#include <emscripten/bind.h>
#include <emscripten/html5.h>

std::string plot_caption;
std::string extra_caption; // used in extern context
mfem::GeometryRefiner GLVisGeometryRefiner; // used in extern context

static VisualizationSceneScalarData * vs{nullptr};

namespace js
{

using namespace mfem;

// Replace a given VectorFiniteElement-based grid function (e.g. from a Nedelec
// or Raviart-Thomas space) with a discontinuous piece-wise polynomial Cartesian
// product vector grid function of the same order.
GridFunction *ProjectVectorFEGridFunction(GridFunction *gf)
{
   if ((gf->VectorDim() == 3) && (gf->FESpace()->GetVDim() == 1))
   {
      int p = gf->FESpace()->GetOrder(0);
      cout << "Switching to order " << p
           << " discontinuous vector grid function..." << endl;
      int dim = gf->FESpace()->GetMesh()->Dimension();
      FiniteElementCollection *d_fec = new L2_FECollection(p, dim, 1);
      FiniteElementSpace *d_fespace =
         new FiniteElementSpace(gf->FESpace()->GetMesh(), d_fec, 3);
      GridFunction *d_gf = new GridFunction(d_fespace);
      d_gf->MakeOwner(d_fec);
      gf->ProjectVectorFieldOn(*d_gf);
      delete gf;
      return d_gf;
   }
   return gf;
}

bool startVisualization(const std::string input, const std::string data_type,
                        int w, int h)
{
   std::stringstream ss(input);
   const int field_type = ReadStream(ss, data_type);

   // reset antialiasing
   GetAppWindow()->getRenderer().setAntialiasing(0);

   std::string line;
   while (ss >> line)
   {
      if (line == "keys")
      {
         std::cout << "parsing 'keys'" << std::endl;
         ss >> stream_state.keys;
      }
      else
      {
         std::cout << "unknown line '" << line << "'" << std::endl;
      }
   }

   if (field_type < 0 || field_type > 2)
   {
      return false;
   }

   if (InitVisualization("glvis", 0, 0, w, h))
   {
      return false;
   }

   delete vs;
   vs = nullptr;

   double mesh_range = -1.0;
   if (field_type == 0 || field_type == 2)
   {
      if (stream_state.grid_f)
      {
         stream_state.grid_f->GetNodalValues(stream_state.sol);
      }
      if (stream_state.mesh->SpaceDimension() == 2)
      {
         VisualizationSceneSolution * vss;
         if (field_type == 2)
         {
            // Use the 'bone' palette when visualizing a 2D mesh only
            paletteSet(4);
         }
         // Otherwise, the 'jet-like' palette is used in 2D see vssolution.cpp

         if (stream_state.normals.Size() > 0)
         {
            vs = vss = new VisualizationSceneSolution(*stream_state.mesh, stream_state.sol,
                                                      &stream_state.normals);
         }
         else
         {
            vs = vss = new VisualizationSceneSolution(*stream_state.mesh, stream_state.sol);
         }
         if (stream_state.grid_f)
         {
            vss->SetGridFunction(*stream_state.grid_f);
         }
         if (field_type == 2)
         {
            vs->OrthogonalProjection = 1;
            vs->SetLight(0);
            vs->Zoom(1.8);
         }
      }
      else if (stream_state.mesh->SpaceDimension() == 3)
      {
         VisualizationSceneSolution3d * vss;
         vs = vss = new VisualizationSceneSolution3d(*stream_state.mesh,
                                                     stream_state.sol);
         if (stream_state.grid_f)
         {
            vss->SetGridFunction(stream_state.grid_f);
         }
         if (field_type == 2)
         {
            if (stream_state.mesh->Dimension() == 3)
            {
               // Use the 'white' palette when visualizing a 3D volume mesh only
               // paletteSet(4);
               paletteSet(11);
               vss->SetLightMatIdx(4);
            }
            else
            {
               // Use the 'bone' palette when visualizing a surface mesh only
               // (the same as when visualizing a 2D mesh only)
               paletteSet(4);
            }
            // Otherwise, the 'vivid' palette is used in 3D see vssolution3d.cpp

            vss->ToggleDrawAxes();
            vss->ToggleDrawMesh();
         }
      }
      if (field_type == 2)
      {
         if (stream_state.grid_f)
         {
            mesh_range = stream_state.grid_f->Max() + 1.0;
         }
         else
         {
            mesh_range = stream_state.sol.Max() + 1.0;
         }
      }
   }
   else if (field_type == 1)
   {
      if (stream_state.mesh->SpaceDimension() == 2)
      {
         if (stream_state.grid_f)
         {
            vs = new VisualizationSceneVector(*stream_state.grid_f);
         }
         else
         {
            vs = new VisualizationSceneVector(*stream_state.mesh, stream_state.solu,
                                              stream_state.solv);
         }
      }
      else if (stream_state.mesh->SpaceDimension() == 3)
      {
         if (stream_state.grid_f)
         {
            stream_state.grid_f = ProjectVectorFEGridFunction(stream_state.grid_f);
            vs = new VisualizationSceneVector3d(*stream_state.grid_f);
         }
         else
         {
            vs = new VisualizationSceneVector3d(*stream_state.mesh, stream_state.solu,
                                                stream_state.solv, stream_state.solw);
         }
      }
   }

   if (vs)
   {
      // increase the refinement factors if visualizing a GridFunction
      if (stream_state.grid_f)
      {
         vs->AutoRefine();
         vs->SetShading(2, true);
      }
      if (mesh_range > 0.0)
      {
         vs->SetValueRange(-mesh_range, mesh_range);
         vs->SetAutoscale(0);
      }
      if (stream_state.mesh->SpaceDimension() == 2 && field_type == 2)
      {
         SetVisualizationScene(vs, 2);
      }
      else
      {
         SetVisualizationScene(vs, 3);
      }
   }

   CallKeySequence(stream_state.keys.c_str());

   SendExposeEvent();
   return true;
}

int updateVisualization(std::string data_type, std::string stream)
{
   std::stringstream ss(stream);

   if (data_type != "solution")
   {
      std::cerr << "unsupported data type '" << data_type << "' for stream update" <<
                std::endl;
      return 1;
   }

   auto * new_m = new Mesh(ss, 1, 0, stream_state.fix_elem_orient);
   auto * new_g = new GridFunction(new_m, ss);
   double mesh_range = -1.0;

   if (new_m->SpaceDimension() == stream_state.mesh->SpaceDimension() &&
       new_g->VectorDim() == stream_state.grid_f->VectorDim())
   {
      if (new_m->SpaceDimension() == 2)
      {
         if (new_g->VectorDim() == 1)
         {
            VisualizationSceneSolution *vss =
               dynamic_cast<VisualizationSceneSolution *>(vs);
            new_g->GetNodalValues(stream_state.sol);
            vss->NewMeshAndSolution(new_m, &stream_state.sol, new_g);
         }
         else
         {
            VisualizationSceneVector *vsv =
               dynamic_cast<VisualizationSceneVector *>(vs);
            vsv->NewMeshAndSolution(*new_g);
         }
      }
      else
      {
         if (new_g->VectorDim() == 1)
         {
            VisualizationSceneSolution3d *vss =
               dynamic_cast<VisualizationSceneSolution3d *>(vs);
            new_g->GetNodalValues(stream_state.sol);
            vss->NewMeshAndSolution(new_m, &stream_state.sol, new_g);
         }
         else
         {
            new_g = ProjectVectorFEGridFunction(new_g);
            VisualizationSceneVector3d *vss =
               dynamic_cast<VisualizationSceneVector3d *>(vs);
            vss->NewMeshAndSolution(new_m, new_g);
         }
      }
      if (mesh_range > 0.0)
      {
         vs->SetValueRange(-mesh_range, mesh_range);
      }

      delete stream_state.grid_f;
      stream_state.grid_f = new_g;
      delete stream_state.mesh;
      stream_state.mesh = new_m;

      SendExposeEvent();
      return 0;
   }
   else
   {
      cout << "Stream: field type does not match!" << endl;
      delete new_g;
      delete new_m;
      return 1;
   }
}

void iterVisualization()
{
   GetAppWindow()->mainIter();
}

void setCanvasId(const std::string & id)
{
   std::cout << "glvis: setting canvas id to " << id << std::endl;
   GetAppWindow()->setCanvasId(id);
}

void disableKeyHandling()
{
   SDL_EventState(SDL_KEYDOWN, SDL_DISABLE);
   SDL_EventState(SDL_KEYUP, SDL_DISABLE);
}

void enableKeyHandling()
{
   SDL_EventState(SDL_KEYDOWN, SDL_ENABLE);
   SDL_EventState(SDL_KEYUP, SDL_ENABLE);
}

void setKeyboardListeningElementId(const std::string & id)
{
   SDL_SetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT, id.c_str());
}

void setupResizeEventCallback(const std::string & id)
{
   // typedef EM_BOOL (*em_ui_callback_func)(int eventType, const EmscriptenUiEvent *uiEvent, void *userData);
   std::cout << "glvis: adding resize callback for " << id << std::endl;
   auto err = emscripten_set_resize_callback(id.c_str(), nullptr,
                                             true, [](int eventType, const EmscriptenUiEvent *uiEvent,
                                                      void *userData) -> EM_BOOL
   {
      std::cout << "got resize event" << std::endl;
      return true;
   });
   // TODO: macro to wrap this
   if (err != EMSCRIPTEN_RESULT_SUCCESS)
   {
      std::cerr << "error (emscripten_set_resize_callback): " << err << std::endl;
   }
}

std::string getHelpString()
{
   VisualizationSceneScalarData* vss
      = dynamic_cast<VisualizationSceneScalarData*>(GetVisualizationScene());
   return vss->GetHelpString();
}
} // namespace js

namespace em = emscripten;
EMSCRIPTEN_BINDINGS(js_funcs)
{
   em::function("startVisualization", &js::startVisualization);
   em::function("updateVisualization", &js::updateVisualization);
   em::function("iterVisualization", &js::iterVisualization);
   em::function("sendExposeEvent", &SendExposeEvent);
   em::function("disableKeyHanding", &js::disableKeyHandling);
   em::function("enableKeyHandling", &js::enableKeyHandling);
   em::function("setKeyboardListeningElementId",
                js::setKeyboardListeningElementId);
   em::function("getTextureMode", &GetUseTexture);
   em::function("setTextureMode", &SetUseTexture);
   em::function("resizeWindow", &ResizeWindow);
   em::function("setCanvasId", &js::setCanvasId);
   em::function("setupResizeEventCallback", &js::setupResizeEventCallback);
   em::function("getHelpString", &js::getHelpString);
}
<commit_msg>use uniform assignment<commit_after>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-443271.
//
// This file is part of the GLVis visualization tool and library. For more
// information and source code availability see https://glvis.org.
//
// GLVis is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include "visual.hpp"
#include "palettes.hpp"
#include "stream_reader.hpp"
#include <SDL2/SDL_hints.h>
#include <emscripten/bind.h>
#include <emscripten/html5.h>

std::string plot_caption;
std::string extra_caption; // used in extern context
mfem::GeometryRefiner GLVisGeometryRefiner; // used in extern context

static VisualizationSceneScalarData * vs = nullptr;

namespace js
{

using namespace mfem;

// Replace a given VectorFiniteElement-based grid function (e.g. from a Nedelec
// or Raviart-Thomas space) with a discontinuous piece-wise polynomial Cartesian
// product vector grid function of the same order.
GridFunction *ProjectVectorFEGridFunction(GridFunction *gf)
{
   if ((gf->VectorDim() == 3) && (gf->FESpace()->GetVDim() == 1))
   {
      int p = gf->FESpace()->GetOrder(0);
      cout << "Switching to order " << p
           << " discontinuous vector grid function..." << endl;
      int dim = gf->FESpace()->GetMesh()->Dimension();
      FiniteElementCollection *d_fec = new L2_FECollection(p, dim, 1);
      FiniteElementSpace *d_fespace =
         new FiniteElementSpace(gf->FESpace()->GetMesh(), d_fec, 3);
      GridFunction *d_gf = new GridFunction(d_fespace);
      d_gf->MakeOwner(d_fec);
      gf->ProjectVectorFieldOn(*d_gf);
      delete gf;
      return d_gf;
   }
   return gf;
}

bool startVisualization(const std::string input, const std::string data_type,
                        int w, int h)
{
   std::stringstream ss(input);
   const int field_type = ReadStream(ss, data_type);

   // reset antialiasing
   GetAppWindow()->getRenderer().setAntialiasing(0);

   std::string line;
   while (ss >> line)
   {
      if (line == "keys")
      {
         std::cout << "parsing 'keys'" << std::endl;
         ss >> stream_state.keys;
      }
      else
      {
         std::cout << "unknown line '" << line << "'" << std::endl;
      }
   }

   if (field_type < 0 || field_type > 2)
   {
      return false;
   }

   if (InitVisualization("glvis", 0, 0, w, h))
   {
      return false;
   }

   delete vs;
   vs = nullptr;

   double mesh_range = -1.0;
   if (field_type == 0 || field_type == 2)
   {
      if (stream_state.grid_f)
      {
         stream_state.grid_f->GetNodalValues(stream_state.sol);
      }
      if (stream_state.mesh->SpaceDimension() == 2)
      {
         VisualizationSceneSolution * vss;
         if (field_type == 2)
         {
            // Use the 'bone' palette when visualizing a 2D mesh only
            paletteSet(4);
         }
         // Otherwise, the 'jet-like' palette is used in 2D see vssolution.cpp

         if (stream_state.normals.Size() > 0)
         {
            vs = vss = new VisualizationSceneSolution(*stream_state.mesh, stream_state.sol,
                                                      &stream_state.normals);
         }
         else
         {
            vs = vss = new VisualizationSceneSolution(*stream_state.mesh, stream_state.sol);
         }
         if (stream_state.grid_f)
         {
            vss->SetGridFunction(*stream_state.grid_f);
         }
         if (field_type == 2)
         {
            vs->OrthogonalProjection = 1;
            vs->SetLight(0);
            vs->Zoom(1.8);
         }
      }
      else if (stream_state.mesh->SpaceDimension() == 3)
      {
         VisualizationSceneSolution3d * vss;
         vs = vss = new VisualizationSceneSolution3d(*stream_state.mesh,
                                                     stream_state.sol);
         if (stream_state.grid_f)
         {
            vss->SetGridFunction(stream_state.grid_f);
         }
         if (field_type == 2)
         {
            if (stream_state.mesh->Dimension() == 3)
            {
               // Use the 'white' palette when visualizing a 3D volume mesh only
               // paletteSet(4);
               paletteSet(11);
               vss->SetLightMatIdx(4);
            }
            else
            {
               // Use the 'bone' palette when visualizing a surface mesh only
               // (the same as when visualizing a 2D mesh only)
               paletteSet(4);
            }
            // Otherwise, the 'vivid' palette is used in 3D see vssolution3d.cpp

            vss->ToggleDrawAxes();
            vss->ToggleDrawMesh();
         }
      }
      if (field_type == 2)
      {
         if (stream_state.grid_f)
         {
            mesh_range = stream_state.grid_f->Max() + 1.0;
         }
         else
         {
            mesh_range = stream_state.sol.Max() + 1.0;
         }
      }
   }
   else if (field_type == 1)
   {
      if (stream_state.mesh->SpaceDimension() == 2)
      {
         if (stream_state.grid_f)
         {
            vs = new VisualizationSceneVector(*stream_state.grid_f);
         }
         else
         {
            vs = new VisualizationSceneVector(*stream_state.mesh, stream_state.solu,
                                              stream_state.solv);
         }
      }
      else if (stream_state.mesh->SpaceDimension() == 3)
      {
         if (stream_state.grid_f)
         {
            stream_state.grid_f = ProjectVectorFEGridFunction(stream_state.grid_f);
            vs = new VisualizationSceneVector3d(*stream_state.grid_f);
         }
         else
         {
            vs = new VisualizationSceneVector3d(*stream_state.mesh, stream_state.solu,
                                                stream_state.solv, stream_state.solw);
         }
      }
   }

   if (vs)
   {
      // increase the refinement factors if visualizing a GridFunction
      if (stream_state.grid_f)
      {
         vs->AutoRefine();
         vs->SetShading(2, true);
      }
      if (mesh_range > 0.0)
      {
         vs->SetValueRange(-mesh_range, mesh_range);
         vs->SetAutoscale(0);
      }
      if (stream_state.mesh->SpaceDimension() == 2 && field_type == 2)
      {
         SetVisualizationScene(vs, 2);
      }
      else
      {
         SetVisualizationScene(vs, 3);
      }
   }

   CallKeySequence(stream_state.keys.c_str());

   SendExposeEvent();
   return true;
}

int updateVisualization(std::string data_type, std::string stream)
{
   std::stringstream ss(stream);

   if (data_type != "solution")
   {
      std::cerr << "unsupported data type '" << data_type << "' for stream update" <<
                std::endl;
      return 1;
   }

   auto * new_m = new Mesh(ss, 1, 0, stream_state.fix_elem_orient);
   auto * new_g = new GridFunction(new_m, ss);
   double mesh_range = -1.0;

   if (new_m->SpaceDimension() == stream_state.mesh->SpaceDimension() &&
       new_g->VectorDim() == stream_state.grid_f->VectorDim())
   {
      if (new_m->SpaceDimension() == 2)
      {
         if (new_g->VectorDim() == 1)
         {
            VisualizationSceneSolution *vss =
               dynamic_cast<VisualizationSceneSolution *>(vs);
            new_g->GetNodalValues(stream_state.sol);
            vss->NewMeshAndSolution(new_m, &stream_state.sol, new_g);
         }
         else
         {
            VisualizationSceneVector *vsv =
               dynamic_cast<VisualizationSceneVector *>(vs);
            vsv->NewMeshAndSolution(*new_g);
         }
      }
      else
      {
         if (new_g->VectorDim() == 1)
         {
            VisualizationSceneSolution3d *vss =
               dynamic_cast<VisualizationSceneSolution3d *>(vs);
            new_g->GetNodalValues(stream_state.sol);
            vss->NewMeshAndSolution(new_m, &stream_state.sol, new_g);
         }
         else
         {
            new_g = ProjectVectorFEGridFunction(new_g);
            VisualizationSceneVector3d *vss =
               dynamic_cast<VisualizationSceneVector3d *>(vs);
            vss->NewMeshAndSolution(new_m, new_g);
         }
      }
      if (mesh_range > 0.0)
      {
         vs->SetValueRange(-mesh_range, mesh_range);
      }

      delete stream_state.grid_f;
      stream_state.grid_f = new_g;
      delete stream_state.mesh;
      stream_state.mesh = new_m;

      SendExposeEvent();
      return 0;
   }
   else
   {
      cout << "Stream: field type does not match!" << endl;
      delete new_g;
      delete new_m;
      return 1;
   }
}

void iterVisualization()
{
   GetAppWindow()->mainIter();
}

void setCanvasId(const std::string & id)
{
   std::cout << "glvis: setting canvas id to " << id << std::endl;
   GetAppWindow()->setCanvasId(id);
}

void disableKeyHandling()
{
   SDL_EventState(SDL_KEYDOWN, SDL_DISABLE);
   SDL_EventState(SDL_KEYUP, SDL_DISABLE);
}

void enableKeyHandling()
{
   SDL_EventState(SDL_KEYDOWN, SDL_ENABLE);
   SDL_EventState(SDL_KEYUP, SDL_ENABLE);
}

void setKeyboardListeningElementId(const std::string & id)
{
   SDL_SetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT, id.c_str());
}

void setupResizeEventCallback(const std::string & id)
{
   // typedef EM_BOOL (*em_ui_callback_func)(int eventType, const EmscriptenUiEvent *uiEvent, void *userData);
   std::cout << "glvis: adding resize callback for " << id << std::endl;
   auto err = emscripten_set_resize_callback(id.c_str(), nullptr,
                                             true, [](int eventType, const EmscriptenUiEvent *uiEvent,
                                                      void *userData) -> EM_BOOL
   {
      std::cout << "got resize event" << std::endl;
      return true;
   });
   // TODO: macro to wrap this
   if (err != EMSCRIPTEN_RESULT_SUCCESS)
   {
      std::cerr << "error (emscripten_set_resize_callback): " << err << std::endl;
   }
}

std::string getHelpString()
{
   VisualizationSceneScalarData* vss
      = dynamic_cast<VisualizationSceneScalarData*>(GetVisualizationScene());
   return vss->GetHelpString();
}
} // namespace js

namespace em = emscripten;
EMSCRIPTEN_BINDINGS(js_funcs)
{
   em::function("startVisualization", &js::startVisualization);
   em::function("updateVisualization", &js::updateVisualization);
   em::function("iterVisualization", &js::iterVisualization);
   em::function("sendExposeEvent", &SendExposeEvent);
   em::function("disableKeyHanding", &js::disableKeyHandling);
   em::function("enableKeyHandling", &js::enableKeyHandling);
   em::function("setKeyboardListeningElementId",
                js::setKeyboardListeningElementId);
   em::function("getTextureMode", &GetUseTexture);
   em::function("setTextureMode", &SetUseTexture);
   em::function("resizeWindow", &ResizeWindow);
   em::function("setCanvasId", &js::setCanvasId);
   em::function("setupResizeEventCallback", &js::setupResizeEventCallback);
   em::function("getHelpString", &js::getHelpString);
}
<|endoftext|>


<commit_before>#include <utility>

/******************************************************************************
 * Copyright (C) 2017 Kitsune Ral <kitsune-ral@users.sf.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "avatar.h"

#include "jobs/mediathumbnailjob.h"
#include "events/eventcontent.h"
#include "connection.h"

#include <QtGui/QPainter>
#include <QtCore/QPointer>

using namespace QMatrixClient;
using std::move;

class Avatar::Private
{
    public:
        explicit Private(QIcon di, QUrl url = {})
            : _defaultIcon(move(di)), _url(move(url))
        { }
        QImage get(Connection* connection, QSize size,
                   get_callback_t callback) const;
        bool upload(UploadContentJob* job, upload_callback_t callback);

        bool checkUrl(QUrl url) const;

        const QIcon _defaultIcon;
        QUrl _url;

        // The below are related to image caching, hence mutable
        mutable QImage _originalImage;
        mutable std::vector<QPair<QSize, QImage>> _scaledImages;
        mutable QSize _requestedSize;
        mutable bool _bannedUrl = false;
        mutable bool _fetched = false;
        mutable QPointer<MediaThumbnailJob> _thumbnailRequest = nullptr;
        mutable QPointer<BaseJob> _uploadRequest = nullptr;
        mutable std::vector<get_callback_t> callbacks;
};

Avatar::Avatar(QIcon defaultIcon)
    : d(std::make_unique<Private>(std::move(defaultIcon)))
{ }

Avatar::Avatar(QUrl url, QIcon defaultIcon)
    : d(std::make_unique<Private>(std::move(defaultIcon), std::move(url)))
{ }

Avatar::Avatar(Avatar&&) = default;

Avatar::~Avatar() = default;

Avatar& Avatar::operator=(Avatar&&) = default;

QImage Avatar::get(Connection* connection, int dimension,
                   get_callback_t callback) const
{
    return d->get(connection, {dimension, dimension}, move(callback));
}

QImage Avatar::get(Connection* connection, int width, int height,
                   get_callback_t callback) const
{
    return d->get(connection, {width, height}, move(callback));
}

bool Avatar::upload(Connection* connection, const QString& fileName,
                    upload_callback_t callback) const
{
    if (isJobRunning(d->_uploadRequest))
        return false;
    return d->upload(connection->uploadFile(fileName), move(callback));
}

bool Avatar::upload(Connection* connection, QIODevice* source,
                    upload_callback_t callback) const
{
    if (isJobRunning(d->_uploadRequest) || !source->isReadable())
        return false;
    return d->upload(connection->uploadContent(source), move(callback));
}

QString Avatar::mediaId() const
{
    return d->_url.authority() + d->_url.path();
}

QImage Avatar::Private::get(Connection* connection, QSize size,
                            get_callback_t callback) const
{
    // FIXME: Alternating between longer-width and longer-height requests
    // is a sure way to trick the below code into constantly getting another
    // image from the server because the existing one is alleged unsatisfactory.
    // This is plain abuse by the client, though; so not critical for now.
    if( ( !(_fetched || _thumbnailRequest)
          || size.width() > _requestedSize.width()
          || size.height() > _requestedSize.height() ) && checkUrl(_url) )
    {
        qCDebug(MAIN) << "Getting avatar from" << _url.toString();
        _requestedSize = size;
        if (isJobRunning(_thumbnailRequest))
            _thumbnailRequest->abandon();
        callbacks.emplace_back(move(callback));
        _thumbnailRequest = connection->getThumbnail(_url, size);
        QObject::connect( _thumbnailRequest, &MediaThumbnailJob::success,
            _thumbnailRequest, [this] {
                _fetched = true;
                _originalImage =
                        _thumbnailRequest->scaledThumbnail(_requestedSize);
                _scaledImages.clear();
                for (const auto& n: callbacks)
                    n();
                callbacks.clear();
            });
    }

    if( _originalImage.isNull() )
    {
        if (_defaultIcon.isNull())
            return _originalImage;

        QPainter p { &_originalImage };
        _defaultIcon.paint(&p, { QPoint(), _defaultIcon.actualSize(size) });
    }

    for (const auto& p: _scaledImages)
        if (p.first == size)
            return p.second;
    auto result = _originalImage.scaled(size,
                    Qt::KeepAspectRatio, Qt::SmoothTransformation);
    _scaledImages.emplace_back(size, result);
    return result;
}

bool Avatar::Private::upload(UploadContentJob* job, upload_callback_t callback)
{
    _uploadRequest = job;
    if (!isJobRunning(_uploadRequest))
        return false;
    _uploadRequest->connect(_uploadRequest, &BaseJob::success, _uploadRequest,
                            [job,callback] { callback(job->contentUri()); });
    return true;
}

bool Avatar::Private::checkUrl(QUrl url) const
{
    if (_bannedUrl || url.isEmpty())
        return false;

    // FIXME: Make "mxc" a library-wide constant and maybe even make
    // the URL checker a Connection(?) method.
    _bannedUrl = !(url.isValid() &&
            url.scheme() == "mxc" && url.path().count('/') == 1);
    if (_bannedUrl)
        qCWarning(MAIN) << "Avatar URL is invalid or not mxc-based:"
                        << url.toDisplayString();
    return !_bannedUrl;
}

QUrl Avatar::url() const { return d->_url; }

bool Avatar::updateUrl(const QUrl& newUrl)
{
    if (newUrl == d->_url)
        return false;

    d->_url = newUrl;
    d->_fetched = false;
    if (isJobRunning(d->_thumbnailRequest))
        d->_thumbnailRequest->abandon();
    return true;
}

<commit_msg>Avatar: don't allow null callbacks to be registered<commit_after>#include <utility>

/******************************************************************************
 * Copyright (C) 2017 Kitsune Ral <kitsune-ral@users.sf.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "avatar.h"

#include "jobs/mediathumbnailjob.h"
#include "events/eventcontent.h"
#include "connection.h"

#include <QtGui/QPainter>
#include <QtCore/QPointer>

using namespace QMatrixClient;
using std::move;

class Avatar::Private
{
    public:
        explicit Private(QIcon di, QUrl url = {})
            : _defaultIcon(move(di)), _url(move(url))
        { }
        QImage get(Connection* connection, QSize size,
                   get_callback_t callback) const;
        bool upload(UploadContentJob* job, upload_callback_t callback);

        bool checkUrl(QUrl url) const;

        const QIcon _defaultIcon;
        QUrl _url;

        // The below are related to image caching, hence mutable
        mutable QImage _originalImage;
        mutable std::vector<QPair<QSize, QImage>> _scaledImages;
        mutable QSize _requestedSize;
        mutable bool _bannedUrl = false;
        mutable bool _fetched = false;
        mutable QPointer<MediaThumbnailJob> _thumbnailRequest = nullptr;
        mutable QPointer<BaseJob> _uploadRequest = nullptr;
        mutable std::vector<get_callback_t> callbacks;
};

Avatar::Avatar(QIcon defaultIcon)
    : d(std::make_unique<Private>(std::move(defaultIcon)))
{ }

Avatar::Avatar(QUrl url, QIcon defaultIcon)
    : d(std::make_unique<Private>(std::move(defaultIcon), std::move(url)))
{ }

Avatar::Avatar(Avatar&&) = default;

Avatar::~Avatar() = default;

Avatar& Avatar::operator=(Avatar&&) = default;

QImage Avatar::get(Connection* connection, int dimension,
                   get_callback_t callback) const
{
    return d->get(connection, {dimension, dimension}, move(callback));
}

QImage Avatar::get(Connection* connection, int width, int height,
                   get_callback_t callback) const
{
    return d->get(connection, {width, height}, move(callback));
}

bool Avatar::upload(Connection* connection, const QString& fileName,
                    upload_callback_t callback) const
{
    if (isJobRunning(d->_uploadRequest))
        return false;
    return d->upload(connection->uploadFile(fileName), move(callback));
}

bool Avatar::upload(Connection* connection, QIODevice* source,
                    upload_callback_t callback) const
{
    if (isJobRunning(d->_uploadRequest) || !source->isReadable())
        return false;
    return d->upload(connection->uploadContent(source), move(callback));
}

QString Avatar::mediaId() const
{
    return d->_url.authority() + d->_url.path();
}

QImage Avatar::Private::get(Connection* connection, QSize size,
                            get_callback_t callback) const
{
    if (!callback)
    {
        qCCritical(MAIN) << "Null callbacks are not allowed in Avatar::get";
        Q_ASSERT(false);
    }
    // FIXME: Alternating between longer-width and longer-height requests
    // is a sure way to trick the below code into constantly getting another
    // image from the server because the existing one is alleged unsatisfactory.
    // This is plain abuse by the client, though; so not critical for now.
    if( ( !(_fetched || _thumbnailRequest)
          || size.width() > _requestedSize.width()
          || size.height() > _requestedSize.height() ) && checkUrl(_url) )
    {
        qCDebug(MAIN) << "Getting avatar from" << _url.toString();
        _requestedSize = size;
        if (isJobRunning(_thumbnailRequest))
            _thumbnailRequest->abandon();
        if (callback)
            callbacks.emplace_back(move(callback));
        _thumbnailRequest = connection->getThumbnail(_url, size);
        QObject::connect( _thumbnailRequest, &MediaThumbnailJob::success,
            _thumbnailRequest, [this] {
                _fetched = true;
                _originalImage =
                        _thumbnailRequest->scaledThumbnail(_requestedSize);
                _scaledImages.clear();
                for (const auto& n: callbacks)
                    n();
                callbacks.clear();
            });
    }

    if( _originalImage.isNull() )
    {
        if (_defaultIcon.isNull())
            return _originalImage;

        QPainter p { &_originalImage };
        _defaultIcon.paint(&p, { QPoint(), _defaultIcon.actualSize(size) });
    }

    for (const auto& p: _scaledImages)
        if (p.first == size)
            return p.second;
    auto result = _originalImage.scaled(size,
                    Qt::KeepAspectRatio, Qt::SmoothTransformation);
    _scaledImages.emplace_back(size, result);
    return result;
}

bool Avatar::Private::upload(UploadContentJob* job, upload_callback_t callback)
{
    _uploadRequest = job;
    if (!isJobRunning(_uploadRequest))
        return false;
    _uploadRequest->connect(_uploadRequest, &BaseJob::success, _uploadRequest,
                            [job,callback] { callback(job->contentUri()); });
    return true;
}

bool Avatar::Private::checkUrl(QUrl url) const
{
    if (_bannedUrl || url.isEmpty())
        return false;

    // FIXME: Make "mxc" a library-wide constant and maybe even make
    // the URL checker a Connection(?) method.
    _bannedUrl = !(url.isValid() &&
            url.scheme() == "mxc" && url.path().count('/') == 1);
    if (_bannedUrl)
        qCWarning(MAIN) << "Avatar URL is invalid or not mxc-based:"
                        << url.toDisplayString();
    return !_bannedUrl;
}

QUrl Avatar::url() const { return d->_url; }

bool Avatar::updateUrl(const QUrl& newUrl)
{
    if (newUrl == d->_url)
        return false;

    d->_url = newUrl;
    d->_fetched = false;
    if (isJobRunning(d->_thumbnailRequest))
        d->_thumbnailRequest->abandon();
    return true;
}

<|endoftext|>


<commit_before>#include <boost/test/unit_test.hpp>

#include "ports/events/event_sinks.hpp"
#include "ports/events/event_sources.hpp"
#include "event_sink_with_queue.hpp"
#include "core/connection.hpp"

using namespace fc;

namespace fc
{
namespace pure
{

template<class T>
struct event_sink_value
{
	void operator()(T in) { *storage = in; }
	std::shared_ptr<T> storage = std::make_shared<T>();
};

template<class T>
struct event_sink_vector
{
	void operator()(T in) {	storage->push_back(in);	}
	std::shared_ptr<std::vector<T>> storage = std::make_shared<std::vector<T>>();
};

} // namespace pure

template<class T> struct is_passive_sink<pure::event_sink_value<T>> : std::true_type {};
template<class T> struct is_passive_sink<pure::event_sink_vector<T>> : std::true_type {};

} // namespace fc

namespace
{

/**
 * \brief Node for calculating the number of elements in a range
 */
struct range_size
{
public:
	range_size()
		: out()
	{}
	pure::event_source<int> out;

	auto in()
	{
		return ::fc::pure::make_event_sink_tmpl( [this](auto event)
		{
			size_t elems = std::distance(std::begin(event), std::end(event));
			this->out.fire(static_cast<int>(elems));
		} );
	}
};

/**
 * Helper class for testing event_in_port_tmpl
 */
class generic_input_node
{
public:
	generic_input_node() : value() {}

	/*
	 * Define a getter for the port named "in" and
	 * Declare a member function to be called from the port.
	 * The token type is available as "event_t" and the token as "event".
	 */
	auto in()
	{
		return ::fc::pure::make_event_sink_tmpl( [this](auto event)
		{
			value = event;
		} );
	}

	int value;
};

} // unnamed namespace

BOOST_AUTO_TEST_SUITE(test_events)

BOOST_AUTO_TEST_CASE( test_event_in_port_tmpl )
{
	pure::event_source<int> src_int;
	pure::event_source<double> src_double;
	generic_input_node to;

	src_int >> to.in();
	src_double >> to.in();

	src_int.fire(2);
	BOOST_CHECK_EQUAL(to.value, 2);
	src_int.fire(4.1);
	BOOST_CHECK_EQUAL(to.value, 4);
}

BOOST_AUTO_TEST_CASE( connections )
{
	static_assert(is_active<pure::event_source<int>>{},
			"event_out_port is active by definition");
	static_assert(is_passive<pure::event_sink<int>>{},
			"event_in_port is passive by definition");
	static_assert(!is_active<pure::event_sink<int>>{},
			"event_in_port is not active by definition");
	static_assert(!is_passive<pure::event_source<int>>{},
			"event_out_port is not passive by definition");

	pure::event_source<int> test_event;
	pure::event_sink_value<int> test_handler;

	connect(test_event, test_handler);
	test_event.fire(1);
	BOOST_CHECK_EQUAL(*(test_handler.storage), 1);

	auto tmp_connection = test_event >> [](int i){return ++i;};
	static_assert(is_instantiation_of<
			detail::active_connection_proxy, decltype(tmp_connection)>{},
			"active port connected with standard connectable gets proxy");
	std::move(tmp_connection) >> test_handler;

	test_event.fire(1);
	BOOST_CHECK_EQUAL(*(test_handler.storage), 2);

	auto incr = [](int i){return ++i;};
	test_event >> incr >> incr >> incr >> test_handler;
	test_event.fire(1);
	BOOST_CHECK_EQUAL(*(test_handler.storage), 4);
}

BOOST_AUTO_TEST_CASE( queue_sink )
{
	auto inc = [](int i) { return i + 1; };

	pure::event_source<int> source;
	pure::event_sink_queue<int> sink;
	source >> inc >> sink;
	source.fire(4);
	BOOST_CHECK_EQUAL(sink.empty(), false);
	int received = sink.get();
	BOOST_CHECK_EQUAL(received, 5);
	BOOST_CHECK_EQUAL(sink.empty(), true);
}

BOOST_AUTO_TEST_CASE( merge_events )
{
	pure::event_source<int> test_event;
	pure::event_source<int> test_event_2;
	pure::event_sink_vector<int> test_handler;

	test_event >> test_handler;
	test_event_2 >> test_handler;

	test_event.fire(0);
	BOOST_CHECK_EQUAL(test_handler.storage->size(), 1);
	BOOST_CHECK_EQUAL(test_handler.storage->back(), 0);

	test_event_2.fire(1);

	BOOST_CHECK_EQUAL(test_handler.storage->size(), 2);
	BOOST_CHECK_EQUAL(test_handler.storage->front(), 0);
	BOOST_CHECK_EQUAL(test_handler.storage->back(), 1);

}

BOOST_AUTO_TEST_CASE( split_events )
{
	pure::event_source<int> test_event;
	pure::event_sink_value<int> test_handler_1;
	pure::event_sink_value<int> test_handler_2;

	test_event >> test_handler_1;
	test_event >> test_handler_2;

	test_event.fire(2);
	BOOST_CHECK_EQUAL(*(test_handler_1.storage), 2);
	BOOST_CHECK_EQUAL(*(test_handler_2.storage), 2);
}

BOOST_AUTO_TEST_CASE( in_port )
{
	int test_value = 0;

	auto test_writer = [&](int i) {test_value = i;};

	pure::event_sink<int> in_port(test_writer);
	pure::event_source<int> test_event;

	test_event >> in_port;
	test_event.fire(1);
	BOOST_CHECK_EQUAL(test_value, 1);

	//test void event
	auto write_999 = [&]() {test_value = 999;};

	pure::event_sink<void> void_in(write_999);
	pure::event_source<void> void_out;
	void_out >> void_in;
	void_out.fire();
	BOOST_CHECK_EQUAL(test_value, 999);
}

BOOST_AUTO_TEST_CASE( test_event_out_port )
{
	range_size get_size;
	int storage = 0;
	get_size.out >> [&](int i) { storage = i; };

	get_size.in()(std::list<float>{1., 2., .3});
	BOOST_CHECK_EQUAL(storage, 3);

	get_size.in()(std::vector<int>{0, 1});
	BOOST_CHECK_EQUAL(storage, 2);
}

BOOST_AUTO_TEST_CASE( lambda )
{
	int test_value = 0;

	auto write_666 = [&]() {test_value = 666;};
	pure::event_source<void> void_out_2;
	void_out_2 >> write_666;
	void_out_2.fire();
	BOOST_CHECK_EQUAL(test_value, 666);
}

namespace
{
template<class T>
void test_connection(const T& connection)
{
	int storage = 0;
	pure::event_source<int> a;
	pure::event_sink_queue<int> d;
	auto c = [&](int i) { storage = i; return i; };
	auto b = [](int i) { return i + 1; };

	connection(a,b,c,d);

	a.fire(2);
	BOOST_CHECK_EQUAL(storage, 3);
	BOOST_CHECK_EQUAL(d.get(), 3);
}
}

/**
 * Confirm that connecting ports and connectables
 * does not depend on any particular order.
 */
BOOST_AUTO_TEST_CASE( associativity )
{
	test_connection([](auto& a, auto& b, auto& c, auto& d)
	{
		a >> b >> c >> d;
	});

	test_connection([](auto& a, auto& b, auto& c, auto& d)
	{
		(a >> b) >> (c >> d);
	});

	test_connection([](auto& a, auto& b, auto& c, auto& d)
	{
		a >> ((b >> c) >> d);
	});

	test_connection([](auto& a, auto& b, auto& c, auto& d)
	{
		(a >> (b >> c)) >> d;
	});
}

namespace
{
template<class operation>
struct sink_t
{
	typedef void result_t;
	template <class T>
	void operator()(T&& in) { op(std::forward<T>(in)); }

	operation op;
};

template<class operation>
auto sink(const operation& op )
{
	return sink_t<operation>{op};
}
}

BOOST_AUTO_TEST_CASE( test_polymorphic_lambda )
{
	int test_value = 0;

	pure::event_source<int> p;
	auto write = sink([&](auto in) {test_value = in;});

	static_assert(is_passive_sink<decltype(write)>{}, "");

	p >> write;
	BOOST_CHECK_EQUAL(test_value, 0);
	p.fire(4);
	BOOST_CHECK_EQUAL(test_value, 4);
}

BOOST_AUTO_TEST_CASE(test_sink_has_callback)
{
	static_assert(has_register_function<pure::event_sink<void>>(0),
				"type is defined with ability to register a callback");
}

template <class T>
struct disconnecting_event_sink : public pure::event_sink<T>
{
	disconnecting_event_sink() :
		pure::event_sink<T>(
			[&](T in){
				*storage = in;
			}
		)
	{
	}

	std::shared_ptr<T> storage = std::make_shared<T>();
};

BOOST_AUTO_TEST_CASE(test_sink_deleted_callback)
{
	disconnecting_event_sink<int> test_sink1;

	{
		pure::event_source<int> test_source;

		disconnecting_event_sink<int> test_sink4;
		test_source >> test_sink1;
		test_source.fire(5);
		BOOST_CHECK_EQUAL(*(test_sink1.storage), 5);

		{
			disconnecting_event_sink<int> test_sink2;
			disconnecting_event_sink<int> test_sink3;
			test_source >> test_sink2;
			test_source >> test_sink3;
			test_source.fire(6);
			BOOST_CHECK_EQUAL(*(test_sink2.storage), 6);
			BOOST_CHECK_EQUAL(*(test_sink3.storage), 6);

			test_source >> test_sink4;
			test_source.fire(7);
			BOOST_CHECK_EQUAL(*(test_sink4.storage), 7);
		}

		// this primarily checks, that no exception is thrown
		// since the connections from test_source to sink1-3 are deleted.
		test_source.fire(8);
		BOOST_CHECK_EQUAL(*(test_sink4.storage), 8);
	}

}

BOOST_AUTO_TEST_CASE(test_delete_with_lambda_in_connection)
{
	disconnecting_event_sink<int> test_sink;

	pure::event_source<int> test_source;

	(test_source >> [](int i){ return i+1; }) >> test_sink;

	{
		disconnecting_event_sink<int> test_sink_2;
		test_source >> ([](int i){ return i+1; }
				>> [](int i){ return i+1; })
				>> test_sink_2;
				test_source.fire(10);
				BOOST_CHECK_EQUAL(*(test_sink_2.storage), 12);
	}

	test_source.fire(11);
	BOOST_CHECK_EQUAL(*(test_sink.storage), 12);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Added test to check for correct deletion of handlers in event_source<commit_after>#include <boost/test/unit_test.hpp>

#include "ports/events/event_sinks.hpp"
#include "ports/events/event_sources.hpp"
#include "event_sink_with_queue.hpp"
#include "core/connection.hpp"

using namespace fc;

namespace fc
{
namespace pure
{

template<class T>
struct event_sink_value
{
	void operator()(T in) { *storage = in; }
	std::shared_ptr<T> storage = std::make_shared<T>();
};

template<class T>
struct event_sink_vector
{
	void operator()(T in) {	storage->push_back(in);	}
	std::shared_ptr<std::vector<T>> storage = std::make_shared<std::vector<T>>();
};

} // namespace pure

template<class T> struct is_passive_sink<pure::event_sink_value<T>> : std::true_type {};
template<class T> struct is_passive_sink<pure::event_sink_vector<T>> : std::true_type {};

} // namespace fc

namespace
{

/**
 * \brief Node for calculating the number of elements in a range
 */
struct range_size
{
public:
	range_size()
		: out()
	{}
	pure::event_source<int> out;

	auto in()
	{
		return ::fc::pure::make_event_sink_tmpl( [this](auto event)
		{
			size_t elems = std::distance(std::begin(event), std::end(event));
			this->out.fire(static_cast<int>(elems));
		} );
	}
};

/**
 * Helper class for testing event_in_port_tmpl
 */
class generic_input_node
{
public:
	generic_input_node() : value() {}

	/*
	 * Define a getter for the port named "in" and
	 * Declare a member function to be called from the port.
	 * The token type is available as "event_t" and the token as "event".
	 */
	auto in()
	{
		return ::fc::pure::make_event_sink_tmpl( [this](auto event)
		{
			value = event;
		} );
	}

	int value;
};

} // unnamed namespace

BOOST_AUTO_TEST_SUITE(test_events)

BOOST_AUTO_TEST_CASE( test_event_in_port_tmpl )
{
	pure::event_source<int> src_int;
	pure::event_source<double> src_double;
	generic_input_node to;

	src_int >> to.in();
	src_double >> to.in();

	src_int.fire(2);
	BOOST_CHECK_EQUAL(to.value, 2);
	src_int.fire(4.1);
	BOOST_CHECK_EQUAL(to.value, 4);
}

BOOST_AUTO_TEST_CASE( connections )
{
	static_assert(is_active<pure::event_source<int>>{},
			"event_out_port is active by definition");
	static_assert(is_passive<pure::event_sink<int>>{},
			"event_in_port is passive by definition");
	static_assert(!is_active<pure::event_sink<int>>{},
			"event_in_port is not active by definition");
	static_assert(!is_passive<pure::event_source<int>>{},
			"event_out_port is not passive by definition");

	pure::event_source<int> test_event;
	pure::event_sink_value<int> test_handler;

	connect(test_event, test_handler);
	test_event.fire(1);
	BOOST_CHECK_EQUAL(*(test_handler.storage), 1);

	auto tmp_connection = test_event >> [](int i){return ++i;};
	static_assert(is_instantiation_of<
			detail::active_connection_proxy, decltype(tmp_connection)>{},
			"active port connected with standard connectable gets proxy");
	std::move(tmp_connection) >> test_handler;

	test_event.fire(1);
	BOOST_CHECK_EQUAL(*(test_handler.storage), 2);

	auto incr = [](int i){return ++i;};
	test_event >> incr >> incr >> incr >> test_handler;
	test_event.fire(1);
	BOOST_CHECK_EQUAL(*(test_handler.storage), 4);
}

BOOST_AUTO_TEST_CASE( queue_sink )
{
	auto inc = [](int i) { return i + 1; };

	pure::event_source<int> source;
	pure::event_sink_queue<int> sink;
	source >> inc >> sink;
	source.fire(4);
	BOOST_CHECK_EQUAL(sink.empty(), false);
	int received = sink.get();
	BOOST_CHECK_EQUAL(received, 5);
	BOOST_CHECK_EQUAL(sink.empty(), true);
}

BOOST_AUTO_TEST_CASE( merge_events )
{
	pure::event_source<int> test_event;
	pure::event_source<int> test_event_2;
	pure::event_sink_vector<int> test_handler;

	test_event >> test_handler;
	test_event_2 >> test_handler;

	test_event.fire(0);
	BOOST_CHECK_EQUAL(test_handler.storage->size(), 1);
	BOOST_CHECK_EQUAL(test_handler.storage->back(), 0);

	test_event_2.fire(1);

	BOOST_CHECK_EQUAL(test_handler.storage->size(), 2);
	BOOST_CHECK_EQUAL(test_handler.storage->front(), 0);
	BOOST_CHECK_EQUAL(test_handler.storage->back(), 1);

}

BOOST_AUTO_TEST_CASE( split_events )
{
	pure::event_source<int> test_event;
	pure::event_sink_value<int> test_handler_1;
	pure::event_sink_value<int> test_handler_2;

	test_event >> test_handler_1;
	test_event >> test_handler_2;

	test_event.fire(2);
	BOOST_CHECK_EQUAL(*(test_handler_1.storage), 2);
	BOOST_CHECK_EQUAL(*(test_handler_2.storage), 2);
}

BOOST_AUTO_TEST_CASE( in_port )
{
	int test_value = 0;

	auto test_writer = [&](int i) {test_value = i;};

	pure::event_sink<int> in_port(test_writer);
	pure::event_source<int> test_event;

	test_event >> in_port;
	test_event.fire(1);
	BOOST_CHECK_EQUAL(test_value, 1);

	//test void event
	auto write_999 = [&]() {test_value = 999;};

	pure::event_sink<void> void_in(write_999);
	pure::event_source<void> void_out;
	void_out >> void_in;
	void_out.fire();
	BOOST_CHECK_EQUAL(test_value, 999);
}

BOOST_AUTO_TEST_CASE( test_event_out_port )
{
	range_size get_size;
	int storage = 0;
	get_size.out >> [&](int i) { storage = i; };

	get_size.in()(std::list<float>{1., 2., .3});
	BOOST_CHECK_EQUAL(storage, 3);

	get_size.in()(std::vector<int>{0, 1});
	BOOST_CHECK_EQUAL(storage, 2);
}

BOOST_AUTO_TEST_CASE( lambda )
{
	int test_value = 0;

	auto write_666 = [&]() {test_value = 666;};
	pure::event_source<void> void_out_2;
	void_out_2 >> write_666;
	void_out_2.fire();
	BOOST_CHECK_EQUAL(test_value, 666);
}

namespace
{
template<class T>
void test_connection(const T& connection)
{
	int storage = 0;
	pure::event_source<int> a;
	pure::event_sink_queue<int> d;
	auto c = [&](int i) { storage = i; return i; };
	auto b = [](int i) { return i + 1; };

	connection(a,b,c,d);

	a.fire(2);
	BOOST_CHECK_EQUAL(storage, 3);
	BOOST_CHECK_EQUAL(d.get(), 3);
}
}

/**
 * Confirm that connecting ports and connectables
 * does not depend on any particular order.
 */
BOOST_AUTO_TEST_CASE( associativity )
{
	test_connection([](auto& a, auto& b, auto& c, auto& d)
	{
		a >> b >> c >> d;
	});

	test_connection([](auto& a, auto& b, auto& c, auto& d)
	{
		(a >> b) >> (c >> d);
	});

	test_connection([](auto& a, auto& b, auto& c, auto& d)
	{
		a >> ((b >> c) >> d);
	});

	test_connection([](auto& a, auto& b, auto& c, auto& d)
	{
		(a >> (b >> c)) >> d;
	});
}

namespace
{
template<class operation>
struct sink_t
{
	typedef void result_t;
	template <class T>
	void operator()(T&& in) { op(std::forward<T>(in)); }

	operation op;
};

template<class operation>
auto sink(const operation& op )
{
	return sink_t<operation>{op};
}
}

BOOST_AUTO_TEST_CASE( test_polymorphic_lambda )
{
	int test_value = 0;

	pure::event_source<int> p;
	auto write = sink([&](auto in) {test_value = in;});

	static_assert(is_passive_sink<decltype(write)>{}, "");

	p >> write;
	BOOST_CHECK_EQUAL(test_value, 0);
	p.fire(4);
	BOOST_CHECK_EQUAL(test_value, 4);
}

BOOST_AUTO_TEST_CASE(test_sink_has_callback)
{
	static_assert(has_register_function<pure::event_sink<void>>(0),
				"type is defined with ability to register a callback");
}

template <class T>
struct disconnecting_event_sink : public pure::event_sink<T>
{
	disconnecting_event_sink() :
		pure::event_sink<T>(
			[&](T in){
				*storage = in;
			}
		)
	{
	}

	std::shared_ptr<T> storage = std::make_shared<T>();
};

BOOST_AUTO_TEST_CASE(test_sink_deleted_callback)
{
	disconnecting_event_sink<int> test_sink1;

	{
		pure::event_source<int> test_source;

		disconnecting_event_sink<int> test_sink4;
		test_source >> test_sink1;
		test_source.fire(5);
		BOOST_CHECK_EQUAL(*(test_sink1.storage), 5);

		{
			disconnecting_event_sink<int> test_sink2;
			disconnecting_event_sink<int> test_sink3;
			test_source >> test_sink2;
			test_source >> test_sink3;
			test_source.fire(6);
			BOOST_CHECK_EQUAL(*(test_sink2.storage), 6);
			BOOST_CHECK_EQUAL(*(test_sink3.storage), 6);

			test_source >> test_sink4;
			test_source.fire(7);
			BOOST_CHECK_EQUAL(*(test_sink4.storage), 7);

			BOOST_CHECK_EQUAL(test_source.nr_connected_handlers(), 4);
		}

		BOOST_CHECK_EQUAL(test_source.nr_connected_handlers(), 2);

		// this primarily checks, that no exception is thrown
		// since the connections from test_source to sink1-3 are deleted.
		test_source.fire(8);
		BOOST_CHECK_EQUAL(*(test_sink4.storage), 8);
	}

}

BOOST_AUTO_TEST_CASE(test_delete_with_lambda_in_connection)
{
	disconnecting_event_sink<int> test_sink;

	pure::event_source<int> test_source;

	(test_source >> [](int i){ return i+1; }) >> test_sink;

	{
		disconnecting_event_sink<int> test_sink_2;
		test_source >> ([](int i){ return i+1; }
				>> [](int i){ return i+1; })
				>> test_sink_2;
				test_source.fire(10);
				BOOST_CHECK_EQUAL(*(test_sink_2.storage), 12);
				BOOST_CHECK_EQUAL(test_source.nr_connected_handlers(), 2);
	}

	BOOST_CHECK_EQUAL(test_source.nr_connected_handlers(), 1);

	test_source.fire(11);
	BOOST_CHECK_EQUAL(*(test_sink.storage), 12);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>//===-------- cfi.cc ------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the runtime support for the cross-DSO CFI.
//
//===----------------------------------------------------------------------===//

// FIXME: Intercept dlopen/dlclose.
// FIXME: Support diagnostic mode.
// FIXME: Harden:
//  * mprotect shadow, use mremap for updates
//  * something else equally important

#include <assert.h>
#include <elf.h>
#include <link.h>
#include <string.h>

typedef ElfW(Phdr) Elf_Phdr;
typedef ElfW(Ehdr) Elf_Ehdr;

#include "interception/interception.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flag_parser.h"
#include "ubsan/ubsan_init.h"
#include "ubsan/ubsan_flags.h"

static uptr __cfi_shadow;
static constexpr uptr kShadowGranularity = 12;
static constexpr uptr kShadowAlign = 1UL << kShadowGranularity; // 4096

static constexpr uint16_t kInvalidShadow = 0;
static constexpr uint16_t kUncheckedShadow = 0xFFFFU;

static uint16_t *mem_to_shadow(uptr x) {
  return (uint16_t *)(__cfi_shadow + ((x >> kShadowGranularity) << 1));
}

typedef int (*CFICheckFn)(uptr, void *);

class ShadowValue {
  uptr addr;
  uint16_t v;
  explicit ShadowValue(uptr addr, uint16_t v) : addr(addr), v(v) {}

public:
  bool is_invalid() const { return v == kInvalidShadow; }

  bool is_unchecked() const { return v == kUncheckedShadow; }

  CFICheckFn get_cfi_check() const {
    assert(!is_invalid() && !is_unchecked());
    uptr aligned_addr = addr & ~(kShadowAlign - 1);
    uptr p = aligned_addr - (((uptr)v - 1) << kShadowGranularity);
    return reinterpret_cast<CFICheckFn>(p);
  }

  // Load a shadow valud for the given application memory address.
  static const ShadowValue load(uptr addr) {
    return ShadowValue(addr, *mem_to_shadow(addr));
  }
};

static void fill_shadow_constant(uptr begin, uptr end, uint16_t v) {
  assert(v == kInvalidShadow || v == kUncheckedShadow);
  uint16_t *shadow_begin = mem_to_shadow(begin);
  uint16_t *shadow_end = mem_to_shadow(end - 1) + 1;
  memset(shadow_begin, v, (shadow_end - shadow_begin) * sizeof(*shadow_begin));
}

static void fill_shadow(uptr begin, uptr end, uptr cfi_check) {
  assert((cfi_check & (kShadowAlign - 1)) == 0);

  // Don't fill anything below cfi_check. We can not represent those addresses
  // in the shadow, and must make sure at codegen to place all valid call
  // targets above cfi_check.
  uptr p = Max(begin, cfi_check);
  uint16_t *s = mem_to_shadow(p);
  uint16_t *s_end = mem_to_shadow(end - 1) + 1;
  uint16_t sv = ((p - cfi_check) >> kShadowGranularity) + 1;
  for (; s < s_end; s++, sv++)
    *s = sv;

  // Sanity checks.
  uptr q = p & ~(kShadowAlign - 1);
  for (; q < end; q += kShadowAlign) {
    assert((uptr)ShadowValue::load(q).get_cfi_check() == cfi_check);
    assert((uptr)ShadowValue::load(q + kShadowAlign / 2).get_cfi_check() ==
           cfi_check);
    assert((uptr)ShadowValue::load(q + kShadowAlign - 1).get_cfi_check() ==
           cfi_check);
  }
}

// This is a workaround for a glibc bug:
// https://sourceware.org/bugzilla/show_bug.cgi?id=15199
// Other platforms can, hopefully, just do
//    dlopen(RTLD_NOLOAD | RTLD_LAZY)
//    dlsym("__cfi_check").
static uptr find_cfi_check_in_dso(dl_phdr_info *info) {
  const ElfW(Dyn) *dynamic = nullptr;
  for (int i = 0; i < info->dlpi_phnum; ++i) {
    if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) {
      dynamic =
          (const ElfW(Dyn) *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
      break;
    }
  }
  if (!dynamic) return 0;
  uptr strtab = 0, symtab = 0;
  for (const ElfW(Dyn) *p = dynamic; p->d_tag != PT_NULL; ++p) {
    if (p->d_tag == DT_SYMTAB)
      symtab = p->d_un.d_ptr;
    else if (p->d_tag == DT_STRTAB)
      strtab = p->d_un.d_ptr;
  }

  if (symtab > strtab) {
    VReport(1, "Can not handle: symtab > strtab (%p > %zx)\n", symtab, strtab);
    return 0;
  }

  // Verify that strtab and symtab are inside of the same LOAD segment.
  // This excludes VDSO, which has (very high) bogus strtab and symtab pointers.
  int phdr_idx;
  for (phdr_idx = 0; phdr_idx < info->dlpi_phnum; phdr_idx++) {
    const Elf_Phdr *phdr = &info->dlpi_phdr[phdr_idx];
    if (phdr->p_type == PT_LOAD) {
      uptr beg = info->dlpi_addr + phdr->p_vaddr;
      uptr end = beg + phdr->p_memsz;
      if (strtab >= beg && strtab < end && symtab >= beg && symtab < end)
        break;
    }
  }
  if (phdr_idx == info->dlpi_phnum) {
    // Nope, either different segments or just bogus pointers.
    // Can not handle this.
    VReport(1, "Can not handle: symtab %p, strtab %zx\n", symtab, strtab);
    return 0;
  }

  for (const ElfW(Sym) *p = (const ElfW(Sym) *)symtab; (ElfW(Addr))p < strtab;
       ++p) {
    char *name = (char*)(strtab + p->st_name);
    if (strcmp(name, "__cfi_check") == 0) {
      assert(p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC));
      uptr addr = info->dlpi_addr + p->st_value;
      return addr;
    }
  }
  return 0;
}

static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *data) {
  uptr cfi_check = find_cfi_check_in_dso(info);
  if (cfi_check)
    VReport(1, "Module '%s' __cfi_check %zx\n", info->dlpi_name, cfi_check);

  for (int i = 0; i < info->dlpi_phnum; i++) {
    const Elf_Phdr *phdr = &info->dlpi_phdr[i];
    if (phdr->p_type == PT_LOAD) {
      // Jump tables are in the executable segment.
      // VTables are in the non-executable one.
      // Need to fill shadow for both.
      // FIXME: reject writable if vtables are in the r/o segment. Depend on
      // PT_RELRO?
      uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
      uptr cur_end = cur_beg + phdr->p_memsz;
      if (cfi_check) {
        VReport(1, "   %zx .. %zx\n", cur_beg, cur_end);
        fill_shadow(cur_beg, cur_end, cfi_check ? cfi_check : (uptr)(-1));
      } else {
        fill_shadow_constant(cur_beg, cur_end, kInvalidShadow);
      }
    }
  }
  return 0;
}

// Fill shadow for the initial libraries.
static void init_shadow() {
  dl_iterate_phdr(dl_iterate_phdr_cb, nullptr);
}

SANITIZER_INTERFACE_ATTRIBUTE extern "C"
void __cfi_slowpath(uptr CallSiteTypeId, void *Ptr) {
  uptr Addr = (uptr)Ptr;
  VReport(3, "__cfi_slowpath: %zx, %p\n", CallSiteTypeId, Ptr);
  ShadowValue sv = ShadowValue::load(Addr);
  if (sv.is_invalid()) {
    VReport(2, "CFI: invalid memory region for a function pointer (shadow==0): %p\n", Ptr);
    Die();
  }
  if (sv.is_unchecked()) {
    VReport(2, "CFI: unchecked call (shadow=FFFF): %p\n", Ptr);
    return;
  }
  CFICheckFn cfi_check = sv.get_cfi_check();
  VReport(2, "__cfi_check at %p\n", cfi_check);
  cfi_check(CallSiteTypeId, Ptr);
}

static void InitializeFlags() {
  SetCommonFlagsDefaults();
  __ubsan::Flags *uf = __ubsan::flags();
  uf->SetDefaults();

  FlagParser cfi_parser;
  RegisterCommonFlags(&cfi_parser);

  FlagParser ubsan_parser;
  __ubsan::RegisterUbsanFlags(&ubsan_parser, uf);
  RegisterCommonFlags(&ubsan_parser);

  const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions();
  ubsan_parser.ParseString(ubsan_default_options);

  cfi_parser.ParseString(GetEnv("CFI_OPTIONS"));
  ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS"));

  SetVerbosity(common_flags()->verbosity);

  if (Verbosity()) ReportUnrecognizedFlags();

  if (common_flags()->help) {
    cfi_parser.PrintFlagDescriptions();
  }
}

extern "C" __attribute__((visibility("default")))
#if !SANITIZER_CAN_USE_PREINIT_ARRAY
// On ELF platforms, the constructor is invoked using .preinit_array (see below)
__attribute__((constructor(0)))
#endif
void __cfi_init() {
  SanitizerToolName = "CFI";
  InitializeFlags();

  uptr vma = GetMaxVirtualAddress();
  // Shadow is 2 -> 2**kShadowGranularity.
  uptr shadow_size = (vma >> (kShadowGranularity - 1)) + 1;
  VReport(1, "CFI: VMA size %zx, shadow size %zx\n", vma, shadow_size);
  void *shadow = MmapNoReserveOrDie(shadow_size, "CFI shadow");
  VReport(1, "CFI: shadow at %zx .. %zx\n", shadow,
          reinterpret_cast<uptr>(shadow) + shadow_size);
  __cfi_shadow = (uptr)shadow;
  init_shadow();

  __ubsan::InitAsPlugin();
}

#if SANITIZER_CAN_USE_PREINIT_ARRAY
// On ELF platforms, run cfi initialization before any other constructors.
// On other platforms we use the constructor attribute to arrange to run our
// initialization early.
extern "C" {
__attribute__((section(".preinit_array"),
               used)) void (*__cfi_preinit)(void) = __cfi_init;
}
#endif
<commit_msg>[cfi] Fix GCC build.<commit_after>//===-------- cfi.cc ------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the runtime support for the cross-DSO CFI.
//
//===----------------------------------------------------------------------===//

// FIXME: Intercept dlopen/dlclose.
// FIXME: Support diagnostic mode.
// FIXME: Harden:
//  * mprotect shadow, use mremap for updates
//  * something else equally important

#include <assert.h>
#include <elf.h>
#include <link.h>
#include <string.h>

typedef ElfW(Phdr) Elf_Phdr;
typedef ElfW(Ehdr) Elf_Ehdr;

#include "interception/interception.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flag_parser.h"
#include "ubsan/ubsan_init.h"
#include "ubsan/ubsan_flags.h"

static uptr __cfi_shadow;
static constexpr uptr kShadowGranularity = 12;
static constexpr uptr kShadowAlign = 1UL << kShadowGranularity; // 4096

static constexpr uint16_t kInvalidShadow = 0;
static constexpr uint16_t kUncheckedShadow = 0xFFFFU;

static uint16_t *mem_to_shadow(uptr x) {
  return (uint16_t *)(__cfi_shadow + ((x >> kShadowGranularity) << 1));
}

typedef int (*CFICheckFn)(uptr, void *);

class ShadowValue {
  uptr addr;
  uint16_t v;
  explicit ShadowValue(uptr addr, uint16_t v) : addr(addr), v(v) {}

public:
  bool is_invalid() const { return v == kInvalidShadow; }

  bool is_unchecked() const { return v == kUncheckedShadow; }

  CFICheckFn get_cfi_check() const {
    assert(!is_invalid() && !is_unchecked());
    uptr aligned_addr = addr & ~(kShadowAlign - 1);
    uptr p = aligned_addr - (((uptr)v - 1) << kShadowGranularity);
    return reinterpret_cast<CFICheckFn>(p);
  }

  // Load a shadow valud for the given application memory address.
  static const ShadowValue load(uptr addr) {
    return ShadowValue(addr, *mem_to_shadow(addr));
  }
};

static void fill_shadow_constant(uptr begin, uptr end, uint16_t v) {
  assert(v == kInvalidShadow || v == kUncheckedShadow);
  uint16_t *shadow_begin = mem_to_shadow(begin);
  uint16_t *shadow_end = mem_to_shadow(end - 1) + 1;
  memset(shadow_begin, v, (shadow_end - shadow_begin) * sizeof(*shadow_begin));
}

static void fill_shadow(uptr begin, uptr end, uptr cfi_check) {
  assert((cfi_check & (kShadowAlign - 1)) == 0);

  // Don't fill anything below cfi_check. We can not represent those addresses
  // in the shadow, and must make sure at codegen to place all valid call
  // targets above cfi_check.
  uptr p = Max(begin, cfi_check);
  uint16_t *s = mem_to_shadow(p);
  uint16_t *s_end = mem_to_shadow(end - 1) + 1;
  uint16_t sv = ((p - cfi_check) >> kShadowGranularity) + 1;
  for (; s < s_end; s++, sv++)
    *s = sv;

  // Sanity checks.
  uptr q = p & ~(kShadowAlign - 1);
  for (; q < end; q += kShadowAlign) {
    assert((uptr)ShadowValue::load(q).get_cfi_check() == cfi_check);
    assert((uptr)ShadowValue::load(q + kShadowAlign / 2).get_cfi_check() ==
           cfi_check);
    assert((uptr)ShadowValue::load(q + kShadowAlign - 1).get_cfi_check() ==
           cfi_check);
  }
}

// This is a workaround for a glibc bug:
// https://sourceware.org/bugzilla/show_bug.cgi?id=15199
// Other platforms can, hopefully, just do
//    dlopen(RTLD_NOLOAD | RTLD_LAZY)
//    dlsym("__cfi_check").
static uptr find_cfi_check_in_dso(dl_phdr_info *info) {
  const ElfW(Dyn) *dynamic = nullptr;
  for (int i = 0; i < info->dlpi_phnum; ++i) {
    if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) {
      dynamic =
          (const ElfW(Dyn) *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
      break;
    }
  }
  if (!dynamic) return 0;
  uptr strtab = 0, symtab = 0;
  for (const ElfW(Dyn) *p = dynamic; p->d_tag != PT_NULL; ++p) {
    if (p->d_tag == DT_SYMTAB)
      symtab = p->d_un.d_ptr;
    else if (p->d_tag == DT_STRTAB)
      strtab = p->d_un.d_ptr;
  }

  if (symtab > strtab) {
    VReport(1, "Can not handle: symtab > strtab (%p > %zx)\n", symtab, strtab);
    return 0;
  }

  // Verify that strtab and symtab are inside of the same LOAD segment.
  // This excludes VDSO, which has (very high) bogus strtab and symtab pointers.
  int phdr_idx;
  for (phdr_idx = 0; phdr_idx < info->dlpi_phnum; phdr_idx++) {
    const Elf_Phdr *phdr = &info->dlpi_phdr[phdr_idx];
    if (phdr->p_type == PT_LOAD) {
      uptr beg = info->dlpi_addr + phdr->p_vaddr;
      uptr end = beg + phdr->p_memsz;
      if (strtab >= beg && strtab < end && symtab >= beg && symtab < end)
        break;
    }
  }
  if (phdr_idx == info->dlpi_phnum) {
    // Nope, either different segments or just bogus pointers.
    // Can not handle this.
    VReport(1, "Can not handle: symtab %p, strtab %zx\n", symtab, strtab);
    return 0;
  }

  for (const ElfW(Sym) *p = (const ElfW(Sym) *)symtab; (ElfW(Addr))p < strtab;
       ++p) {
    char *name = (char*)(strtab + p->st_name);
    if (strcmp(name, "__cfi_check") == 0) {
      assert(p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC));
      uptr addr = info->dlpi_addr + p->st_value;
      return addr;
    }
  }
  return 0;
}

static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *data) {
  uptr cfi_check = find_cfi_check_in_dso(info);
  if (cfi_check)
    VReport(1, "Module '%s' __cfi_check %zx\n", info->dlpi_name, cfi_check);

  for (int i = 0; i < info->dlpi_phnum; i++) {
    const Elf_Phdr *phdr = &info->dlpi_phdr[i];
    if (phdr->p_type == PT_LOAD) {
      // Jump tables are in the executable segment.
      // VTables are in the non-executable one.
      // Need to fill shadow for both.
      // FIXME: reject writable if vtables are in the r/o segment. Depend on
      // PT_RELRO?
      uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
      uptr cur_end = cur_beg + phdr->p_memsz;
      if (cfi_check) {
        VReport(1, "   %zx .. %zx\n", cur_beg, cur_end);
        fill_shadow(cur_beg, cur_end, cfi_check ? cfi_check : (uptr)(-1));
      } else {
        fill_shadow_constant(cur_beg, cur_end, kInvalidShadow);
      }
    }
  }
  return 0;
}

// Fill shadow for the initial libraries.
static void init_shadow() {
  dl_iterate_phdr(dl_iterate_phdr_cb, nullptr);
}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void __cfi_slowpath(uptr CallSiteTypeId, void *Ptr) {
  uptr Addr = (uptr)Ptr;
  VReport(3, "__cfi_slowpath: %zx, %p\n", CallSiteTypeId, Ptr);
  ShadowValue sv = ShadowValue::load(Addr);
  if (sv.is_invalid()) {
    VReport(2, "CFI: invalid memory region for a function pointer (shadow==0): %p\n", Ptr);
    Die();
  }
  if (sv.is_unchecked()) {
    VReport(2, "CFI: unchecked call (shadow=FFFF): %p\n", Ptr);
    return;
  }
  CFICheckFn cfi_check = sv.get_cfi_check();
  VReport(2, "__cfi_check at %p\n", cfi_check);
  cfi_check(CallSiteTypeId, Ptr);
}

static void InitializeFlags() {
  SetCommonFlagsDefaults();
  __ubsan::Flags *uf = __ubsan::flags();
  uf->SetDefaults();

  FlagParser cfi_parser;
  RegisterCommonFlags(&cfi_parser);

  FlagParser ubsan_parser;
  __ubsan::RegisterUbsanFlags(&ubsan_parser, uf);
  RegisterCommonFlags(&ubsan_parser);

  const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions();
  ubsan_parser.ParseString(ubsan_default_options);

  cfi_parser.ParseString(GetEnv("CFI_OPTIONS"));
  ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS"));

  SetVerbosity(common_flags()->verbosity);

  if (Verbosity()) ReportUnrecognizedFlags();

  if (common_flags()->help) {
    cfi_parser.PrintFlagDescriptions();
  }
}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE
#if !SANITIZER_CAN_USE_PREINIT_ARRAY
// On ELF platforms, the constructor is invoked using .preinit_array (see below)
__attribute__((constructor(0)))
#endif
void __cfi_init() {
  SanitizerToolName = "CFI";
  InitializeFlags();

  uptr vma = GetMaxVirtualAddress();
  // Shadow is 2 -> 2**kShadowGranularity.
  uptr shadow_size = (vma >> (kShadowGranularity - 1)) + 1;
  VReport(1, "CFI: VMA size %zx, shadow size %zx\n", vma, shadow_size);
  void *shadow = MmapNoReserveOrDie(shadow_size, "CFI shadow");
  VReport(1, "CFI: shadow at %zx .. %zx\n", shadow,
          reinterpret_cast<uptr>(shadow) + shadow_size);
  __cfi_shadow = (uptr)shadow;
  init_shadow();

  __ubsan::InitAsPlugin();
}

#if SANITIZER_CAN_USE_PREINIT_ARRAY
// On ELF platforms, run cfi initialization before any other constructors.
// On other platforms we use the constructor attribute to arrange to run our
// initialization early.
extern "C" {
__attribute__((section(".preinit_array"),
               used)) void (*__cfi_preinit)(void) = __cfi_init;
}
#endif
<|endoftext|>


<commit_before>#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <unistd.h>
#include <sys/time.h>
#include <time.h>

#include "readjpeg.h"
typedef struct
{
        float r;
        float g;
        float b;
} pixel_t;
void cuda_function(int data_size_X, int data_size_Y, float* kernel, pixel_t* in, pixel_t* out, double* t0, double* t1);
void cuda_function2(int data_size_X, int data_size_Y, float* kernel, float* in, float* out, double* t0, double* t1);

void normalize( float * kernel ) {
  int sum = 0;
  for (int i = 0; i < 25; i++ ) {
        sum += kernel[i];
  }
  for (int i = 0; i < 25 && sum != 0; i++ ) {
        kernel[i] /= sum;
  }
}

void print_matrix(float *array, int num, int x_size){
    int a = 0;
    printf("%5.2f, ", array[a]);
    for (a = 1; a < num; a++){
        if (a%x_size == x_size-1){
            printf("%5.2f,\n", array[a]);
        } else{
            printf("%5.2f, ", array[a]);
        }
    }
    printf("\n");
}

void convert_to_pixel(pixel_t *out, frame_ptr in)
{
        for(int y = 0; y < in->image_height; y++)
        {
                for(int x = 0; x < in->image_width; x++)
        {
                int r = (int)in->row_pointers[y][in->num_components*x + 0 ];
                int g = (int)in->row_pointers[y][in->num_components*x + 1 ];
                int b = (int)in->row_pointers[y][in->num_components*x + 2 ];
                out[y*in->image_width+x].r = (float)r;
                out[y*in->image_width+x].g = (float)g;
                out[y*in->image_width+x].b = (float)b;

        }
        }
}

void convert_to_frame(frame_ptr out, pixel_t *in)
{
        for(int y = 0; y < out->image_height; y++)
        {
                for(int x = 0; x < out->image_width; x++)
        {
                int r = (int)in[y*out->image_width + x].r;
                int g = (int)in[y*out->image_width + x].g;
                int b = (int)in[y*out->image_width + x].b;
                out->row_pointers[y][out->num_components*x + 0 ] = r;
                out->row_pointers[y][out->num_components*x + 1 ] = g;
                out->row_pointers[y][out->num_components*x + 2 ] = b;
        }
        }
}
#define KERNX 5 //this is the x-size of the kernel. It will always be odd.
#define KERNY 5 //this is the y-size of the kernel. It will always be odd.

int main(int argc, char *argv[]){

float kernel_0[] = { 0, 0, 0, 0, 0, // "sharpen"
                                         0, 0,-1, 0, 0,
                                         0,-1, 5,-1, 0,
                                         0, 0,-1, 0, 0,
                                         0, 0, 0, 0, 0, }; normalize(kernel_0);
float kernel_1[]={ 1, 1, 1, 1, 1, // blur
                                   1, 1, 1, 1, 1,
                                   1, 1, 1, 1, 1,
                                   1, 1, 1, 1, 1,
                                   1, 1, 1, 1, 1, }; normalize(kernel_1);
float kernel_2[] = { 1, 1, 1, 1, 1, // weighted median filter
                                         2, 2, 2, 2, 2,
                                         3, 3, 3, 3, 3,
                                         2, 2, 2, 2, 2,
                                         1, 1, 1, 1, 1, };
float kernel_3[]={1,1,1,1,1, // weighted mean filter
                                  1,2,2,2,1,
                                  1,2,3,2,1,
                                  1,2,2,2,1,
                                  1,1,1,1,1, }; normalize(kernel_3);
float kernel_4[] = { 1, 4, 7, 4, 1, // gaussian
           4,16,26,16, 4,
           7,26,41,26, 7,
           4,16,26,16, 4,
           1, 4, 7, 4, 1, };
float kernel_5[] = { 0, 0, 0, 0, 0, // "emboss"
                                         0,-2,-1, 0, 0,
                                         0,-1, 1, 1, 0,
                                         0, 0, 1, 2, 0,
                                         0, 0, 0, 0, 0, };
float kernel_6[] = {-1,-1,-1,-1,-1, // "edge detect"
                                        -1,-1,-1,-1,-1,
                                        -1,-1,24,-1,-1,
                                        -1,-1,-1,-1,-1,
                                        -1,-1,-1,-1,-1, };
float* kernels[7] = {kernel_0, kernel_1, kernel_2, kernel_3, kernel_4,
                                        kernel_5, kernel_6};

        int c;
        int color = 0;
        char *inName = NULL;
        char *outName = NULL;
        int width = -1, height = -1;
        int kernel_num = 1;
        frame_ptr frame;

        pixel_t *inPix = NULL;
        pixel_t *outPix = NULL;

        //grab command line arguments
    while((c = getopt(argc, argv, "i:k:o:c"))!=-1)
    {
            switch(c)
            {
            case 'i':
                    inName = optarg;
                    break;
            case 'o':
                    outName = optarg;
                    break;
            case 'k':
                    kernel_num = atoi(optarg);
                    break;
            case 'c':
                    color = 1;
            }
    }

    //input file name and output names
    inName = inName==0 ? (char*)"cpt-kurt.jpg" : inName;
    outName = outName==0 ? (char*)"output.jpg" : outName;

    //read file
    frame = read_JPEG_file(inName);
    if(!frame){
                   printf("unable to read %s\n", inName);
        exit(-1);
    }

    width = frame->image_width;
    height = frame->image_height;

    inPix = new pixel_t[width*height];
    outPix = new pixel_t[width*height];

    convert_to_pixel(inPix, frame);

    float* inFloats = new float[width*height];
    float* outFloats2 = new float[width*height];
   for (int i=0; i<width*height; i++){
        outPix[i].r = 0;
        outPix[i].g = 0;
        outPix[i].b = 0;
        outFloats2[i] = 0;
        inFloats[i] = (inPix[i].r + inPix[i].g + inPix[i].b)/3;
        }
        float* kernel = kernels[kernel_num];

    double t0, t1;
    if(color == 1){
        cuda_function(width, height, kernel, inPix, outPix, &t0, &t1);
    } else {
        cuda_function2(width, height, kernel, inFloats, outFloats2, &t0, &t1);

    }
    printf("%g sec\n", t1-t0);
    if(color == 0) {
        for (int i=0; i<width*height; i++){
            outPix[i].r = outFloats2[i];
            outPix[i].g = outFloats2[i];
            outPix[i].b = outFloats2[i];
        }
    }
    convert_to_frame(frame, outPix);

    write_JPEG_file(outName,frame,75);
    destroy_frame(frame);

    delete [] inPix;
    delete [] outPix;
    return 0;
}
<commit_msg>Time stamps<commit_after>#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <unistd.h>
#include <sys/time.h>
#include <time.h>

#include "readjpeg.h"
typedef struct
{
        float r;
        float g;
        float b;
} pixel_t;
void cuda_function(int data_size_X, int data_size_Y, float* kernel, pixel_t* in, pixel_t* out, double* t0, double* t1);
void cuda_function2(int data_size_X, int data_size_Y, float* kernel, float* in, float* out, double* t0, double* t1);

void normalize( float * kernel ) {
  int sum = 0;
  for (int i = 0; i < 25; i++ ) {
        sum += kernel[i];
  }
  for (int i = 0; i < 25 && sum != 0; i++ ) {
        kernel[i] /= sum;
  }
}

void print_matrix(float *array, int num, int x_size){
    int a = 0;
    printf("%5.2f, ", array[a]);
    for (a = 1; a < num; a++){
        if (a%x_size == x_size-1){
            printf("%5.2f,\n", array[a]);
        } else{
            printf("%5.2f, ", array[a]);
        }
    }
    printf("\n");
}

void convert_to_pixel(pixel_t *out, frame_ptr in)
{
        for(int y = 0; y < in->image_height; y++)
        {
                for(int x = 0; x < in->image_width; x++)
        {
                int r = (int)in->row_pointers[y][in->num_components*x + 0 ];
                int g = (int)in->row_pointers[y][in->num_components*x + 1 ];
                int b = (int)in->row_pointers[y][in->num_components*x + 2 ];
                out[y*in->image_width+x].r = (float)r;
                out[y*in->image_width+x].g = (float)g;
                out[y*in->image_width+x].b = (float)b;

        }
        }
}

void convert_to_frame(frame_ptr out, pixel_t *in)
{
        for(int y = 0; y < out->image_height; y++)
        {
                for(int x = 0; x < out->image_width; x++)
        {
                int r = (int)in[y*out->image_width + x].r;
                int g = (int)in[y*out->image_width + x].g;
                int b = (int)in[y*out->image_width + x].b;
                out->row_pointers[y][out->num_components*x + 0 ] = r;
                out->row_pointers[y][out->num_components*x + 1 ] = g;
                out->row_pointers[y][out->num_components*x + 2 ] = b;
        }
        }
}
#define KERNX 5 //this is the x-size of the kernel. It will always be odd.
#define KERNY 5 //this is the y-size of the kernel. It will always be odd.

int main(int argc, char *argv[]){
        double program_start = timestamp();

float kernel_0[] = { 0, 0, 0, 0, 0, // "sharpen"
                                         0, 0,-1, 0, 0,
                                         0,-1, 5,-1, 0,
                                         0, 0,-1, 0, 0,
                                         0, 0, 0, 0, 0, }; normalize(kernel_0);
float kernel_1[]={ 1, 1, 1, 1, 1, // blur
                                   1, 1, 1, 1, 1,
                                   1, 1, 1, 1, 1,
                                   1, 1, 1, 1, 1,
                                   1, 1, 1, 1, 1, }; normalize(kernel_1);
float kernel_2[] = { 1, 1, 1, 1, 1, // weighted median filter
                                         2, 2, 2, 2, 2,
                                         3, 3, 3, 3, 3,
                                         2, 2, 2, 2, 2,
                                         1, 1, 1, 1, 1, };
float kernel_3[]={1,1,1,1,1, // weighted mean filter
                                  1,2,2,2,1,
                                  1,2,3,2,1,
                                  1,2,2,2,1,
                                  1,1,1,1,1, }; normalize(kernel_3);
float kernel_4[] = { 1, 4, 7, 4, 1, // gaussian
           4,16,26,16, 4,
           7,26,41,26, 7,
           4,16,26,16, 4,
           1, 4, 7, 4, 1, };
float kernel_5[] = { 0, 0, 0, 0, 0, // "emboss"
                                         0,-2,-1, 0, 0,
                                         0,-1, 1, 1, 0,
                                         0, 0, 1, 2, 0,
                                         0, 0, 0, 0, 0, };
float kernel_6[] = {-1,-1,-1,-1,-1, // "edge detect"
                                        -1,-1,-1,-1,-1,
                                        -1,-1,24,-1,-1,
                                        -1,-1,-1,-1,-1,
                                        -1,-1,-1,-1,-1, };
float* kernels[7] = {kernel_0, kernel_1, kernel_2, kernel_3, kernel_4,
                                        kernel_5, kernel_6};

        int c;
        int color = 0;
        char *inName = NULL;
        char *outName = NULL;
        int width = -1, height = -1;
        int kernel_num = 1;
        frame_ptr frame;

        pixel_t *inPix = NULL;
        pixel_t *outPix = NULL;

        //grab command line arguments
    while((c = getopt(argc, argv, "i:k:o:c"))!=-1)
    {
            switch(c)
            {
            case 'i':
                    inName = optarg;
                    break;
            case 'o':
                    outName = optarg;
                    break;
            case 'k':
                    kernel_num = atoi(optarg);
                    break;
            case 'c':
                    color = 1;
            }
    }

    //input file name and output names
    inName = inName==0 ? (char*)"cpt-kurt.jpg" : inName;
    outName = outName==0 ? (char*)"output.jpg" : outName;

    //read file
    frame = read_JPEG_file(inName);
    if(!frame){
                   printf("unable to read %s\n", inName);
        exit(-1);
    }

    width = frame->image_width;
    height = frame->image_height;

    inPix = new pixel_t[width*height];
    outPix = new pixel_t[width*height];

    convert_to_pixel(inPix, frame);

    float* inFloats = new float[width*height];
    float* outFloats2 = new float[width*height];
   for (int i=0; i<width*height; i++){
        outPix[i].r = 0;
        outPix[i].g = 0;
        outPix[i].b = 0;
        outFloats2[i] = 0;
        inFloats[i] = (inPix[i].r + inPix[i].g + inPix[i].b)/3;
        }
        float* kernel = kernels[kernel_num];

    double t0, t1;
    double thing1, thing2;
    if(color == 1){
        thing1 = timestamp();
        cuda_function(width, height, kernel, inPix, outPix, &t0, &t1);
        thing2 = timestamp();
    } else {
        thing1 = timestamp();
        cuda_function2(width, height, kernel, inFloats, outFloats2, &t0, &t1);
        thing2 = timestamp();
    }
    printf("%g sec whole function\n", thing2 - thing1);
    printf("%g sec kernel\n", t1-t0);
    if(color == 0) {
        for (int i=0; i<width*height; i++){
            outPix[i].r = outFloats2[i];
            outPix[i].g = outFloats2[i];
            outPix[i].b = outFloats2[i];
        }
    }
    convert_to_frame(frame, outPix);

    write_JPEG_file(outName,frame,75);
    destroy_frame(frame);

    delete [] inPix;
    delete [] outPix;
        double program_end = timestamp();
    printf("%g sec main function\n", program_end - program_start);
    return 0;
}
<|endoftext|>


<commit_before>#include "pathresolver.h"
#include <QDebug>
#include <QFile>
#include <QResource>

PathResolver::PathResolver(QObject *parent) : QObject(parent)
{

}

QString PathResolver::iconPath(const QString &iconName) const
{
#ifdef Q_OS_LINUX
    QString possiblePath = "qrc:/linux/images/linux/" + iconName + ".%1";
    return possiblePath.arg("png");
#else
    return "";
#endif
}
<commit_msg>Minor change.<commit_after>#include "pathresolver.h"
#include <QDebug>
#include <QFile>
#include <QResource>

PathResolver::PathResolver(QObject *parent) : QObject(parent)
{

}

QString PathResolver::iconPath(const QString &iconName) const
{
#ifdef Q_OS_ANDROID
    return "";
#endif
#ifdef Q_OS_LINUX
    QString possiblePath = "qrc:/linux/images/linux/" + iconName + ".%1";
    return possiblePath.arg("png");
#else
    return "";
#endif
}
<|endoftext|>


<commit_before>// Base header file.  Must be first.
#include <Include/PlatformDefinitions.hpp>

#include <cassert>
#include <fstream>
#include <iostream>
#include <strstream>

#include <util/PlatformUtils.hpp>

#include <PlatformSupport/DOMStringHelper.hpp>
#include <DOMSupport/DOMSupportDefault.hpp>

#include <XPath/XObjectFactoryDefault.hpp>
#include <XPath/XPathSupportDefault.hpp>
#include <XPath/XPathFactoryDefault.hpp>

#include <XSLT/StylesheetConstructionContextDefault.hpp>
#include <XSLT/StylesheetExecutionContextDefault.hpp>
#include <XSLT/StylesheetRoot.hpp>
#include <XSLT/XSLTEngineImpl.hpp>
#include <XSLT/XSLTInit.hpp>
#include <XSLT/XSLTInputSource.hpp>
#include <XSLT/XSLTProcessorEnvSupportDefault.hpp>
#include <XSLT/XSLTResultTarget.hpp>

#include <XercesParserLiaison/XercesParserLiaison.hpp>

#include <XercesPlatformSupport/TextFileOutputStream.hpp>
#include <XercesPlatformSupport/XercesDOMPrintWriter.hpp>

int
main(
			int				argc,
			const char*		/* argv */[])
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::cerr;
	using std::endl;
	using std::ifstream;
	using std::ostrstream;
	using std::string;
#endif

	if (argc != 1)
	{
		cerr << "Usage: CompileStylesheet"
			 << endl
			 << endl;
	}
	else
	{
		try
		{
			// Call the static initializer for Xerces...
			XMLPlatformUtils::Initialize();

			{
				// Initialize the Xalan XSLT subsystem...
				XSLTInit						theInit;

				// Create the support objects that are necessary for running the processor...
				DOMSupportDefault				theDOMSupport;
				XercesParserLiaison				theParserLiaison(theDOMSupport);
				XPathSupportDefault				theXPathSupport(theDOMSupport);
				XSLTProcessorEnvSupportDefault	theXSLTProcessorEnvSupport;
				XObjectFactoryDefault			theXObjectFactory;
				XPathFactoryDefault				theXPathFactory;

				// Create a processor...
				XSLTEngineImpl	theProcessor(
						theParserLiaison,
						theXPathSupport,
						theXSLTProcessorEnvSupport,
						theXObjectFactory,
						theXPathFactory);

				// Connect the processor to the support object...
				theXSLTProcessorEnvSupport.setProcessor(&theProcessor);

				// Create separate factory support objects so the stylesheet's
				// factory-created XPath instances are independent from the
				// processor's.
				XPathFactoryDefault				theStylesheetXPathFactory;

				// Create a stylesheet construction context, using the
				// stylesheet's factory support objects.
				StylesheetConstructionContextDefault	theConstructionContext(
							theProcessor,
							theXSLTProcessorEnvSupport,
							theStylesheetXPathFactory);

				// The execution context uses the same factory support objects as
				// the processor, since those objects have the same lifetime as
				// other objects created as a result of the execution.
				StylesheetExecutionContextDefault		theExecutionContext(
							theProcessor,
							theXSLTProcessorEnvSupport,
							theXPathSupport,
							theXObjectFactory);

				// Our input files.  The assumption is that the executable will be run
				// from same directory as the input files.
				const XalanDOMString		theXMLFileName("foo.xml");
				const XalanDOMString		theXSLFileName("foo.xsl");

				// Our stylesheet input source...
				XSLTInputSource			theStylesheetSource(c_wstr(theXSLFileName));

				// Ask the processor to create a StylesheetRoot for the specified
				// input XSL.  This is the compiled stylesheet.  We don't have to
				// delete it, since it is owned by the StylesheetConstructionContext
				// instance.
				StylesheetRoot* const	theStylesheetRoot =
					theProcessor.processStylesheet(
								theStylesheetSource,
								theConstructionContext);
				assert(theStylesheetRoot != 0);

				for (unsigned int i = 0; i < 10; i++)
				{
					theExecutionContext.setStylesheetRoot(theStylesheetRoot);

					// Buffers passed in to ostrstream.
					char		inBuffer[10];
					char		outBuffer[10];

					// Generate the input and output file names.
					ostrstream	theFormatterIn(inBuffer, sizeof(inBuffer));
					ostrstream	theFormatterOut(outBuffer, sizeof(outBuffer));

					theFormatterIn << "foo" << i + 1 << ".xml" << '\0';
					theFormatterOut << "foo" << i + 1 << ".out" << '\0';

					//Generate the XML input and output objects.
					XSLTInputSource		theInputSource(theFormatterIn.str());
					XSLTResultTarget	theResultTarget(theFormatterOut.str());

					// Do the tranformation...
					theProcessor.process(
						 theInputSource,
						 theResultTarget,
						 theExecutionContext);

					// Reset the processor and the execution context
					// so we can perform the next transformation.
					// Reset the parser liaison to clear out the
					// source document we just transformed.
					theProcessor.reset();
					theExecutionContext.reset();
					theParserLiaison.reset();
				}
			}

			// Call the static terminator for Xerces...
			XMLPlatformUtils::Terminate();
		}
		catch(...)
		{
			cerr << "Exception caught!!!"
				 << endl
				 << endl;
		}
	}

	return 0;
}
<commit_msg>No longer using string class...<commit_after>// Base header file.  Must be first.
#include <Include/PlatformDefinitions.hpp>

#include <cassert>
#include <fstream>
#include <iostream>
#include <strstream>

#include <util/PlatformUtils.hpp>

#include <PlatformSupport/DOMStringHelper.hpp>
#include <DOMSupport/DOMSupportDefault.hpp>

#include <XPath/XObjectFactoryDefault.hpp>
#include <XPath/XPathSupportDefault.hpp>
#include <XPath/XPathFactoryDefault.hpp>

#include <XSLT/StylesheetConstructionContextDefault.hpp>
#include <XSLT/StylesheetExecutionContextDefault.hpp>
#include <XSLT/StylesheetRoot.hpp>
#include <XSLT/XSLTEngineImpl.hpp>
#include <XSLT/XSLTInit.hpp>
#include <XSLT/XSLTInputSource.hpp>
#include <XSLT/XSLTProcessorEnvSupportDefault.hpp>
#include <XSLT/XSLTResultTarget.hpp>

#include <XercesParserLiaison/XercesParserLiaison.hpp>

#include <XercesPlatformSupport/TextFileOutputStream.hpp>
#include <XercesPlatformSupport/XercesDOMPrintWriter.hpp>

int
main(
			int				argc,
			const char*		/* argv */[])
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::cerr;
	using std::endl;
	using std::ifstream;
	using std::ostrstream;
#endif

	if (argc != 1)
	{
		cerr << "Usage: CompileStylesheet"
			 << endl
			 << endl;
	}
	else
	{
		try
		{
			// Call the static initializer for Xerces...
			XMLPlatformUtils::Initialize();

			{
				// Initialize the Xalan XSLT subsystem...
				XSLTInit						theInit;

				// Create the support objects that are necessary for running the processor...
				DOMSupportDefault				theDOMSupport;
				XercesParserLiaison				theParserLiaison(theDOMSupport);
				XPathSupportDefault				theXPathSupport(theDOMSupport);
				XSLTProcessorEnvSupportDefault	theXSLTProcessorEnvSupport;
				XObjectFactoryDefault			theXObjectFactory;
				XPathFactoryDefault				theXPathFactory;

				// Create a processor...
				XSLTEngineImpl	theProcessor(
						theParserLiaison,
						theXPathSupport,
						theXSLTProcessorEnvSupport,
						theXObjectFactory,
						theXPathFactory);

				// Connect the processor to the support object...
				theXSLTProcessorEnvSupport.setProcessor(&theProcessor);

				// Create separate factory support objects so the stylesheet's
				// factory-created XPath instances are independent from the
				// processor's.
				XPathFactoryDefault				theStylesheetXPathFactory;

				// Create a stylesheet construction context, using the
				// stylesheet's factory support objects.
				StylesheetConstructionContextDefault	theConstructionContext(
							theProcessor,
							theXSLTProcessorEnvSupport,
							theStylesheetXPathFactory);

				// The execution context uses the same factory support objects as
				// the processor, since those objects have the same lifetime as
				// other objects created as a result of the execution.
				StylesheetExecutionContextDefault		theExecutionContext(
							theProcessor,
							theXSLTProcessorEnvSupport,
							theXPathSupport,
							theXObjectFactory);

				// Our input files.  The assumption is that the executable will be run
				// from same directory as the input files.
				const XalanDOMString		theXMLFileName("foo.xml");
				const XalanDOMString		theXSLFileName("foo.xsl");

				// Our stylesheet input source...
				XSLTInputSource			theStylesheetSource(c_wstr(theXSLFileName));

				// Ask the processor to create a StylesheetRoot for the specified
				// input XSL.  This is the compiled stylesheet.  We don't have to
				// delete it, since it is owned by the StylesheetConstructionContext
				// instance.
				StylesheetRoot* const	theStylesheetRoot =
					theProcessor.processStylesheet(
								theStylesheetSource,
								theConstructionContext);
				assert(theStylesheetRoot != 0);

				for (unsigned int i = 0; i < 10; i++)
				{
					theExecutionContext.setStylesheetRoot(theStylesheetRoot);

					// Buffers passed in to ostrstream.
					char		inBuffer[10];
					char		outBuffer[10];

					// Generate the input and output file names.
					ostrstream	theFormatterIn(inBuffer, sizeof(inBuffer));
					ostrstream	theFormatterOut(outBuffer, sizeof(outBuffer));

					theFormatterIn << "foo" << i + 1 << ".xml" << '\0';
					theFormatterOut << "foo" << i + 1 << ".out" << '\0';

					//Generate the XML input and output objects.
					XSLTInputSource		theInputSource(theFormatterIn.str());
					XSLTResultTarget	theResultTarget(theFormatterOut.str());

					// Do the tranformation...
					theProcessor.process(
						 theInputSource,
						 theResultTarget,
						 theExecutionContext);

					// Reset the processor and the execution context
					// so we can perform the next transformation.
					// Reset the parser liaison to clear out the
					// source document we just transformed.
					theProcessor.reset();
					theExecutionContext.reset();
					theParserLiaison.reset();
				}
			}

			// Call the static terminator for Xerces...
			XMLPlatformUtils::Terminate();
		}
		catch(...)
		{
			cerr << "Exception caught!!!"
				 << endl
				 << endl;
		}
	}

	return 0;
}
<|endoftext|>