<commit_before>////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2014, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <cmake.h>
#include <algorithm>
// If <iostream> is included, put it after <stdio.h>, because it includes
// <stdio.h>, and therefore would ignore the _WITH_GETLINE.
#ifdef FREEBSD
#define _WITH_GETLINE
#endif
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <Context.h>
#include <Hooks.h>
#include <text.h>

extern Context context;

////////////////////////////////////////////////////////////////////////////////
Hooks::Hooks ()
{
}

////////////////////////////////////////////////////////////////////////////////
Hooks::~Hooks ()
{
}

////////////////////////////////////////////////////////////////////////////////
void Hooks::initialize ()
{
  // Scan <rc.data.location>/hooks
  Directory d (context.config.get ("data.location"));
  d += "hooks";
  if (d.is_directory () &&
      d.readable ())
  {
    _scripts = d.list ();
    std::sort (_scripts.begin (), _scripts.end ());
  }
}

////////////////////////////////////////////////////////////////////////////////
// The on-launch event is triggered once, after initialization, before an
// processing occurs
//
// No input
//
// Output:
// - all emitted JSON lines must be fully-formed tasks
// - all emitted non-JSON lines are considered feedback messages
//
// Exit:
//   0 Means: - all emitted JSON lines are added/modifiied
//            - all emitted non-JSON lines become footnote entries
//   1 Means: - all emitted JSON lines are ignored
//            - all emitted non-JSON lines become error entries
//
void Hooks::onLaunch ()
{
  context.timer_hooks.start ();

  std::vector <std::string> matchingScripts = scripts ("on-launch");
  std::vector <std::string>::iterator i;
  for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i)
  {
    std::string output;
    int status = execute (*i, "", output);

    std::vector <std::string> lines;
    split (lines, output, '\n');
    std::vector <std::string>::iterator line;

    if (status == 0)
    {
      for (line = lines.begin (); line != lines.end (); ++line)
      {
        if (line->length () && (*line)[0] == '{')
        {
          Task newTask (*line);
          context.tdb2.add (newTask);
        }
        else
          context.header (*line);
      }
    }
    else
    {
      for (line = lines.begin (); line != lines.end (); ++line)
        context.error (*line);

      throw 0;  // This is how hooks silently terminate processing.
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// Input:
// - A read-only line of JSON for each task added/modified
//
// Output:
// - all emitted non-JSON lines are considered feedback messages
//
// Exit:
//   0 Means: - all emitted non-JSON lines become footnote entries
//   1 Means: - all emitted non-JSON lines become error entries
void Hooks::onExit ()
{
  context.timer_hooks.start ();

  std::vector <std::string> matchingScripts = scripts ("on-exit");
  std::vector <std::string>::iterator i;
  for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i)
  {
    std::string output;
    int status = execute (*i, "", output);

    std::vector <std::string> lines;
    split (lines, output, '\n');
    std::vector <std::string>::iterator line;

    if (status == 0)
    {
      for (line = lines.begin (); line != lines.end (); ++line)
      {
        if (line->length () && (*line)[0] == '{')
        {
          Task newTask (*line);
          context.tdb2.add (newTask);
        }
        else
          context.footnote (*line);
      }
    }
    else
    {
      for (line = lines.begin (); line != lines.end (); ++line)
        context.error (*line);
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// The on-add event is triggered separately for each task added
//
// Input:
// - A line of JSON for the task added
//
// Output:
// - all emitted JSON lines must be fully-formed tasks
// - all emitted non-JSON lines are considered feedback messages
//
// Exit:
//   0 Means: - all emitted JSON lines are added/modifiied
//            - all emitted non-JSON lines become footnote entries
//   1 Means: - all emitted JSON lines are ignored
//            - all emitted non-JSON lines become error entries
//
void Hooks::onAdd (Task& after)
{
  context.timer_hooks.start ();

  std::vector <std::string> matchingScripts = scripts ("on-add");
  std::vector <std::string>::iterator i;
  for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i)
  {
    std::string input = after.composeJSON () + "\n";
    std::string output;
    int status = execute (*i, input, output);

    std::vector <std::string> lines;
    split (lines, output, '\n');
    std::vector <std::string>::iterator line;

    if (status == 0)
    {
      bool first = true;
      for (line = lines.begin (); line != lines.end (); ++line)
      {
        if (line->length () && (*line)[0] == '{')
        {
          Task newTask (*line);

          if (first)
          {
            after = newTask;
            first = false;
          }
          else
            context.tdb2.add (newTask);
        }
        else
          context.footnote (*line);
      }
    }
    else
    {
      for (line = lines.begin (); line != lines.end (); ++line)
        context.error (*line);

      throw 0;  // This is how hooks silently terminate processing.
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// The on-modify event is triggered separately for each task added or modified
//
// Input:
// - A line of JSON for the original task
// - A line of JSON for the modified task
//
// Output:
// - all emitted JSON lines must be fully-formed tasks
// - all emitted non-JSON lines are considered feedback messages
//
// Exit:
//   0 Means: - all emitted JSON lines are added/modifiied
//            - all emitted non-JSON lines become footnote entries
//   1 Means: - all emitted JSON lines are ignored
//            - all emitted non-JSON lines become error entries
void Hooks::onModify (const Task& before, Task& after)
{
  context.timer_hooks.start ();

  std::vector <std::string> matchingScripts = scripts ("on-modify");
  std::vector <std::string>::iterator i;
  for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i)
  {
    std::string afterJSON = after.composeJSON ();
    std::string input = before.composeJSON ()
                      + "\n"
                      + afterJSON
                      + "\n";
    std::string output;
    int status = execute (*i, input, output);

    std::vector <std::string> lines;
    split (lines, output, '\n');
    std::vector <std::string>::iterator line;

    if (status == 0)
    {
      bool first = true;
      for (line = lines.begin (); line != lines.end (); ++line)
      {
        if (line->length () && (*line)[0] == '{')
        {
          Task newTask (*line);

          if (first)
          {
            after = newTask;
            first = false;
          }
          else
            context.tdb2.add (newTask);
        }
        else
          context.footnote (*line);
      }
    }
    else
    {
      for (line = lines.begin (); line != lines.end (); ++line)
        context.error (*line);

      throw 0;  // This is how hooks silently terminate processing.
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
std::vector <std::string> Hooks::list ()
{
  return _scripts;
}

////////////////////////////////////////////////////////////////////////////////
std::vector <std::string> Hooks::scripts (const std::string& event)
{
  std::vector <std::string> matching;
  std::vector <std::string>::iterator i;
  for (i = _scripts.begin (); i != _scripts.end (); ++i)
  {
    if (i->find ("/" + event) != std::string::npos)
    {
      File script (*i);
      if (script.executable ())
        matching.push_back (*i);
    }
  }

  return matching;
}

////////////////////////////////////////////////////////////////////////////////
int Hooks::execute (
  const std::string& command,
  const std::string& input,
  std::string& output)
{
  // TODO Improve error hnadling.
  // TODO Check errors.

  int pin[2], pout[2];
  pipe (pin);
  pipe (pout);

  pid_t pid = fork();
  if (!pid)
  {
    // This is only reached in the child
    dup2 (pin[0], STDIN_FILENO);
    dup2 (pout[1], STDOUT_FILENO);
    if (!execl (command.c_str (), command.c_str (), (char*) NULL))
      exit (1);
  }

  // This is only reached in the parent
  close (pin[0]);
  close (pout[1]);

  // Write input to fp.
  FILE* pinf = fdopen (pin[1], "w");
  if (input != "" &&
      input != "\n")
  {
    fputs (input.c_str (), pinf);
  }

  fclose (pinf);
  close (pin[1]);

  // Read output from fp.
  output = "";
  char* line = NULL;
  size_t len = 0;
  FILE* poutf = fdopen(pout[0], "r");
  while (getline (&line, &len, poutf) != -1)
  {
    output += line;
  }

  if (line)
    free (line);
  fclose (poutf);
  close (pout[0]);

  int status = -1;
  wait (&status);
  if (WIFEXITED (status))
    status = WEXITSTATUS (status);

  context.debug (format ("Hooks::execute {1} (status {2})", command, status));
  return status;
}

////////////////////////////////////////////////////////////////////////////////
<commit_msg>Hooks<commit_after>////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2014, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <cmake.h>
#include <algorithm>
// If <iostream> is included, put it after <stdio.h>, because it includes
// <stdio.h>, and therefore would ignore the _WITH_GETLINE.
#ifdef FREEBSD
#define _WITH_GETLINE
#endif
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <Context.h>
#include <Hooks.h>
#include <text.h>

extern Context context;

////////////////////////////////////////////////////////////////////////////////
Hooks::Hooks ()
{
}

////////////////////////////////////////////////////////////////////////////////
Hooks::~Hooks ()
{
}

////////////////////////////////////////////////////////////////////////////////
void Hooks::initialize ()
{
  // Scan <rc.data.location>/hooks
  Directory d (context.config.get ("data.location"));
  d += "hooks";
  if (d.is_directory () &&
      d.readable ())
  {
    _scripts = d.list ();
    std::sort (_scripts.begin (), _scripts.end ());
  }
}

////////////////////////////////////////////////////////////////////////////////
// The on-launch event is triggered once, after initialization, before an
// processing occurs
//
// No input
//
// Output:
// - all emitted JSON lines must be fully-formed tasks
// - all emitted non-JSON lines are considered feedback messages
//
// Exit:
//   0 Means: - all emitted JSON lines are added/modifiied
//            - all emitted non-JSON lines become footnote entries
//   1 Means: - all emitted JSON lines are ignored
//            - all emitted non-JSON lines become error entries
//
void Hooks::onLaunch ()
{
  context.timer_hooks.start ();

  std::vector <std::string> matchingScripts = scripts ("on-launch");
  std::vector <std::string>::iterator i;
  for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i)
  {
    std::string output;
    int status = execute (*i, "", output);

    std::vector <std::string> lines;
    split (lines, output, '\n');
    std::vector <std::string>::iterator line;

    if (status == 0)
    {
      for (line = lines.begin (); line != lines.end (); ++line)
      {
        if (line->length () && (*line)[0] == '{')
        {
          Task newTask (*line);
          context.tdb2.add (newTask);
        }
        else
          context.header (*line);
      }
    }
    else
    {
      for (line = lines.begin (); line != lines.end (); ++line)
        context.error (*line);

      throw 0;  // This is how hooks silently terminate processing.
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// Input:
// - A read-only line of JSON for each task added/modified
//
// Output:
// - all emitted non-JSON lines are considered feedback messages
//
// Exit:
//   0 Means: - all emitted non-JSON lines become footnote entries
//   1 Means: - all emitted non-JSON lines become error entries
void Hooks::onExit ()
{
  context.timer_hooks.start ();

  std::vector <std::string> matchingScripts = scripts ("on-exit");
  std::vector <std::string>::iterator i;
  for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i)
  {
    std::string output;
    int status = execute (*i, "", output);

    std::vector <std::string> lines;
    split (lines, output, '\n');
    std::vector <std::string>::iterator line;

    if (status == 0)
    {
      for (line = lines.begin (); line != lines.end (); ++line)
      {
        if (line->length () && (*line)[0] == '{')
        {
          Task newTask (*line);
          context.tdb2.add (newTask);
        }
        else
          context.footnote (*line);
      }
    }
    else
    {
      for (line = lines.begin (); line != lines.end (); ++line)
        context.error (*line);
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// The on-add event is triggered separately for each task added
//
// Input:
// - A line of JSON for the task added
//
// Output:
// - all emitted JSON lines must be fully-formed tasks
// - all emitted non-JSON lines are considered feedback messages
//
// Exit:
//   0 Means: - all emitted JSON lines are added/modifiied
//            - all emitted non-JSON lines become footnote entries
//   1 Means: - all emitted JSON lines are ignored
//            - all emitted non-JSON lines become error entries
//
void Hooks::onAdd (Task& after)
{
  context.timer_hooks.start ();

  std::vector <std::string> matchingScripts = scripts ("on-add");
  std::vector <std::string>::iterator i;
  for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i)
  {
    std::string input = after.composeJSON () + "\n";
    std::string output;
    int status = execute (*i, input, output);

    std::vector <std::string> lines;
    split (lines, output, '\n');
    std::vector <std::string>::iterator line;

    if (status == 0)
    {
      bool first = true;
      for (line = lines.begin (); line != lines.end (); ++line)
      {
        if (line->length () && (*line)[0] == '{')
        {
          Task newTask (*line);

          if (first)
          {
            after = newTask;
            first = false;
          }
          else
            context.tdb2.add (newTask);
        }
        else
          context.footnote (*line);
      }
    }
    else
    {
      for (line = lines.begin (); line != lines.end (); ++line)
        context.error (*line);

      throw 0;  // This is how hooks silently terminate processing.
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// The on-modify event is triggered separately for each task added or modified
//
// Input:
// - A line of JSON for the original task
// - A line of JSON for the modified task
//
// Output:
// - all emitted JSON lines must be fully-formed tasks
// - all emitted non-JSON lines are considered feedback messages
//
// Exit:
//   0 Means: - all emitted JSON lines are added/modifiied
//            - all emitted non-JSON lines become footnote entries
//   1 Means: - all emitted JSON lines are ignored
//            - all emitted non-JSON lines become error entries
void Hooks::onModify (const Task& before, Task& after)
{
  context.timer_hooks.start ();

  std::vector <std::string> matchingScripts = scripts ("on-modify");
  std::vector <std::string>::iterator i;
  for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i)
  {
    std::string afterJSON = after.composeJSON ();
    std::string input = before.composeJSON ()
                      + "\n"
                      + afterJSON
                      + "\n";
    std::string output;
    int status = execute (*i, input, output);

    std::vector <std::string> lines;
    split (lines, output, '\n');
    std::vector <std::string>::iterator line;

    if (status == 0)
    {
      bool first = true;
      for (line = lines.begin (); line != lines.end (); ++line)
      {
        if (line->length () && (*line)[0] == '{')
        {
          Task newTask (*line);

          if (first)
          {
            after = newTask;
            first = false;
          }
          else
            context.tdb2.add (newTask);
        }
        else
          context.footnote (*line);
      }
    }
    else
    {
      for (line = lines.begin (); line != lines.end (); ++line)
        context.error (*line);

      throw 0;  // This is how hooks silently terminate processing.
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
std::vector <std::string> Hooks::list ()
{
  return _scripts;
}

////////////////////////////////////////////////////////////////////////////////
std::vector <std::string> Hooks::scripts (const std::string& event)
{
  std::vector <std::string> matching;
  std::vector <std::string>::iterator i;
  for (i = _scripts.begin (); i != _scripts.end (); ++i)
  {
    if (i->find ("/" + event) != std::string::npos)
    {
      File script (*i);
      if (script.executable ())
        matching.push_back (*i);
    }
  }

  return matching;
}

////////////////////////////////////////////////////////////////////////////////
int Hooks::execute (
  const std::string& command,
  const std::string& input,
  std::string& output)
{
  // TODO Improve error hnadling.
  // TODO Check errors.

  int pin[2], pout[2];
  pipe (pin);
  pipe (pout);

  pid_t pid = fork();
  if (!pid)
  {
    // This is only reached in the child
    dup2 (pin[0], STDIN_FILENO);
    dup2 (pout[1], STDOUT_FILENO);
    if (!execl (command.c_str (), command.c_str (), (char*) NULL))
      exit (1);
  }

  // This is only reached in the parent
  close (pin[0]);
  close (pout[1]);

  // Write input to fp.
  FILE* pinf = fdopen (pin[1], "w");
  if (input != "" &&
      input != "\n")
  {
    fputs (input.c_str (), pinf);
  }

  fclose (pinf);
  close (pin[1]);

  // Read output from fp.
  output = "";
  char* line = NULL;
  size_t len = 0;
  FILE* poutf = fdopen(pout[0], "r");
  while (getline (&line, &len, poutf) != -1)
  {
    output += line;
  }

  free (line);
  line = NULL;
  fclose (poutf);
  close (pout[0]);

  int status = -1;
  wait (&status);
  if (WIFEXITED (status))
    status = WEXITSTATUS (status);

  context.debug (format ("Hooks::execute {1} (status {2})", command, status));
  return status;
}

////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>// This file was developed by Thomas Müller <thomas94@gmx.net>.
// It is published under the BSD 3-Clause License within the LICENSE file.

#include "../include/Image.h"
#include "../include/ThreadPool.h"

#include <ImfChannelList.h>
#include <ImfInputFile.h>
#include <ImfInputPart.h>
#include <ImfMultiPartInputFile.h>

#include <stb_image.h>

#include <algorithm>
#include <array>
#include <chrono>
#include <iostream>
#include <set>

using namespace std;

TEV_NAMESPACE_BEGIN

bool isExrFile(const string& filename) {
    ifstream f{filename, ios_base::binary};
    if (!f) {
        throw invalid_argument{tfm::format("File %s could not be opened.", filename)};
    }

    // Taken from http://www.openexr.com/ReadingAndWritingImageFiles.pdf
    char b[4];
    f.read(b, sizeof(b));
    return !!f && b[0] == 0x76 && b[1] == 0x2f && b[2] == 0x31 && b[3] == 0x01;
}

Image::Image(const string& filename, const string& extra)
: mName{tfm::format("%s:%s", filename, extra)} {
    if (isExrFile(filename)) {
        readExr(filename, extra);
    } else {
        readStbi(filename);
    }
}

string Image::shortName() {
    string result = mName;

    size_t slashPosition = result.find_last_of("/\\");
    if (slashPosition != string::npos) {
        result = result.substr(slashPosition + 1);
    }

    size_t colonPosition = result.find_last_of(":");
    if (colonPosition != string::npos) {
        result = result.substr(0, colonPosition);
    }

    return result;
}

vector<string> Image::channelsInLayer(string layerName) const {
    vector<string> result;

    if (layerName.empty()) {
        for (const auto& kv : mChannels) {
            if (kv.first.find(".") == string::npos) {
                result.emplace_back(kv.first);
            }
        }
    } else {
        for (const auto& kv : mChannels) {
            // If the layer name starts at the beginning, and
            // if no other dot is found after the end of the layer name,
            // then we have found a channel of this layer.
            if (kv.first.find(layerName) == 0 && kv.first.length() > layerName.length()) {
                const auto& channelWithoutLayer = kv.first.substr(layerName.length() + 1);
                if (channelWithoutLayer.find(".") == string::npos) {
                    result.emplace_back(kv.first);
                }
            }
        }
    }

    return result;
}

const GlTexture* Image::texture(const string& channelName) {
    auto iter = mTextures.find(channelName);
    if (iter != end(mTextures)) {
        return &iter->second;
    }

    const auto* chan = channel(channelName);
    if (!chan) {
        throw invalid_argument{tfm::format("Cannot obtain texture of channel %s, because the channel does not exist.", channelName)};
    }

    mTextures.emplace(channelName, GlTexture{});
    auto& texture = mTextures.at(channelName);
    texture.setData(chan->data(), mSize, 1);

    return &texture;
}

string Image::toString() const {
    string result = tfm::format("Path: %s\n\nResolution: (%d, %d)\n\nChannels:\n", mName, mSize.x(), mSize.y());

    auto localLayers = mLayers;
    transform(begin(localLayers), end(localLayers), begin(localLayers), [this](string layer) {
        auto channels = channelsInLayer(layer);
        transform(begin(channels), end(channels), begin(channels), [this](string channel) {
            return Channel::tail(channel);
        });
        if (layer.empty()) {
            layer = "<root>";
        }
        return layer + ": " + join(channels, ",");
    });

    return result + join(localLayers, "\n");
}

void Image::readStbi(const string& filename) {
    // No exr image? Try our best using stbi
    cout << "Loading "s + filename + " via STBI... ";
    auto start = chrono::system_clock::now();

    ThreadPool threadPool;

    int numChannels;
    auto data = stbi_loadf(filename.c_str(), &mSize.x(), &mSize.y(), &numChannels, 0);
    if (!data) {
        throw invalid_argument("Could not load texture data from file " + filename);
    }

    mNumChannels = static_cast<size_t>(numChannels);
    size_t numPixels = mSize.prod();

    vector<string> channelNames = {"R", "G", "B", "A"};

    vector<Channel> channels;
    for (size_t c = 0; c < mNumChannels; ++c) {
        string name = c < channelNames.size() ? channelNames[c] : to_string(c - channelNames.size());
        channels.emplace_back(name, mSize);
        channels.back().data().resize(numPixels);
    }

    threadPool.parallelFor(0, numPixels, [&](size_t i) {
        size_t baseIdx = i * mNumChannels;
        for (size_t c = 0; c < mNumChannels; ++c) {
            channels[c].data()[i] = data[baseIdx + c];
        }
    });

    stbi_image_free(data);

    for (auto& channel : channels) {
        string name = channel.name();
        mChannels.emplace(move(name), move(channel));
    }

    // STBI can not load layers, so all channels simply reside
    // within a topmost root layer.
    mLayers.emplace_back("");

    auto end = chrono::system_clock::now();
    chrono::duration<double> elapsedSeconds = end - start;

    cout << tfm::format("done after %.3f seconds.\n", elapsedSeconds.count());
}

void Image::readExr(const string& filename, const string& channelSubstr) {
    // OpenEXR for reading exr images
    cout << "Loading "s + filename + " via OpenEXR... ";
    auto start = chrono::system_clock::now();

    ThreadPool threadPool;

    Imf::MultiPartInputFile multiPartFile{filename.c_str()};
    int numParts = multiPartFile.parts();

    if (numParts <= 0) {
        throw invalid_argument{tfm::format("EXR image '%s' does not contain any parts.", filename)};
    }

    // Find the first part containing a channel that matches the given channelSubstr.
    int partIdx = 0;
    for (int i = 0; i < numParts; ++i) {
        Imf::InputPart part{multiPartFile, i};

        const Imf::ChannelList& imfChannels = part.header().channels();

        for (Imf::ChannelList::ConstIterator c = imfChannels.begin(); c != imfChannels.end(); ++c) {
            if (string{c.name()}.find(channelSubstr) != string::npos) {
                partIdx = i;
                goto l_foundPart;
            }
        }
    }
l_foundPart:

    Imf::InputPart file{multiPartFile, partIdx};
    Imath::Box2i dw = file.header().dataWindow();
    mSize.x() = dw.max.x - dw.min.x + 1;
    mSize.y() = dw.max.y - dw.min.y + 1;

    // Inline helper class for dealing with the raw channels loaded from an exr file.
    class RawChannel {
    public:
        RawChannel(string name, Imf::Channel imfChannel)
        : mName(name), mImfChannel(imfChannel) {
        }

        void resize(size_t size) {
            mData.resize(size * bytesPerPixel());
        }

        void registerWith(Imf::FrameBuffer& frameBuffer, const Imath::Box2i& dw) {
            int width = dw.max.x - dw.min.x + 1;

            frameBuffer.insert(mName.c_str(), Imf::Slice(
                mImfChannel.type,
                mData.data() - (dw.min.x + dw.min.y * width) * bytesPerPixel(),
                bytesPerPixel(), bytesPerPixel() * width,
                mImfChannel.xSampling, mImfChannel.ySampling, 0
            ));
        }

        void copyTo(Channel& channel, ThreadPool& threadPool) const {
            auto& dstData = channel.data();
            dstData.resize(mData.size() / bytesPerPixel());

            // The code in this switch statement may seem overly complicated, but it helps
            // the compiler optimize. This code is time-critical for large images.
            switch (mImfChannel.type) {
                case Imf::HALF:
                    threadPool.parallelForNoWait(0, dstData.size(), [&](size_t i) {
                        dstData[i] = static_cast<float>(*reinterpret_cast<const half*>(&mData[i * sizeof(half)]));
                    });
                    break;

                case Imf::FLOAT:
                    threadPool.parallelForNoWait(0, dstData.size(), [&](size_t i) {
                        dstData[i] = *reinterpret_cast<const float*>(&mData[i * sizeof(float)]);
                    });
                    break;

                case Imf::UINT:
                    threadPool.parallelForNoWait(0, dstData.size(), [&](size_t i) {
                        dstData[i] = static_cast<float>(*reinterpret_cast<const uint32_t*>(&mData[i * sizeof(uint32_t)]));
                    });
                    break;

                default:
                    throw runtime_error("Invalid pixel type encountered.");
            }
        }

        const auto& name() const {
            return mName;
        }

    private:
        int bytesPerPixel() const {
            switch (mImfChannel.type) {
                case Imf::HALF:  return sizeof(half);
                case Imf::FLOAT: return sizeof(float);
                case Imf::UINT:  return sizeof(uint32_t);
                default:
                    throw runtime_error("Invalid pixel type encountered.");
            }
        }

        string mName;
        Imf::Channel mImfChannel;
        vector<char> mData;
    };

    vector<RawChannel> rawChannels;
    Imf::FrameBuffer frameBuffer;

    const Imf::ChannelList& imfChannels = file.header().channels();
    set<string> layerNames;

    for (Imf::ChannelList::ConstIterator c = imfChannels.begin(); c != imfChannels.end(); ++c) {
        if (string{c.name()}.find(channelSubstr) != string::npos) {
            rawChannels.emplace_back(c.name(), c.channel().type);
            layerNames.insert(Channel::head(c.name()));
        }
    }

    if (rawChannels.empty()) {
        throw invalid_argument{tfm::format("No channels match '%s'.", channelSubstr)};
    }

    for (const string& layer : layerNames) {
        mLayers.emplace_back(layer);
    }

    threadPool.parallelFor(0, rawChannels.size(), [&](size_t i) {
        rawChannels[i].resize(mSize.prod());
    });

    for (size_t i = 0; i < rawChannels.size(); ++i) {
        rawChannels[i].registerWith(frameBuffer, dw);
    }

    file.setFrameBuffer(frameBuffer);
    file.readPixels(dw.min.y, dw.max.y);

    for (const auto& rawChannel : rawChannels) {
        mChannels.emplace(rawChannel.name(), Channel{rawChannel.name(), mSize});
    }

    for (size_t i = 0; i < rawChannels.size(); ++i) {
        rawChannels[i].copyTo(mChannels.at(rawChannels[i].name()), threadPool);
    }

    threadPool.waitUntilFinished();

    auto end = chrono::system_clock::now();
    chrono::duration<double> elapsedSeconds = end - start;

    cout << tfm::format("done after %.3f seconds.\n", elapsedSeconds.count());
}

shared_ptr<Image> tryLoadImage(string filename, string extra) {
    try {
        return make_shared<Image>(filename, extra);
    } catch (invalid_argument e) {
        tfm::format(cerr, "Could not load image from %s:%s - %s\n", filename, extra, e.what());
    } catch (Iex::BaseExc& e) {
        tfm::format(cerr, "Could not load image from %s:%s - %s\n", filename, extra, e.what());
    }

    return nullptr;
}

TEV_NAMESPACE_END
<commit_msg>Hotfix incorrect file path display<commit_after>// This file was developed by Thomas Müller <thomas94@gmx.net>.
// It is published under the BSD 3-Clause License within the LICENSE file.

#include "../include/Image.h"
#include "../include/ThreadPool.h"

#include <ImfChannelList.h>
#include <ImfInputFile.h>
#include <ImfInputPart.h>
#include <ImfMultiPartInputFile.h>

#include <stb_image.h>

#include <algorithm>
#include <array>
#include <chrono>
#include <iostream>
#include <set>

using namespace std;

TEV_NAMESPACE_BEGIN

bool isExrFile(const string& filename) {
    ifstream f{filename, ios_base::binary};
    if (!f) {
        throw invalid_argument{tfm::format("File %s could not be opened.", filename)};
    }

    // Taken from http://www.openexr.com/ReadingAndWritingImageFiles.pdf
    char b[4];
    f.read(b, sizeof(b));
    return !!f && b[0] == 0x76 && b[1] == 0x2f && b[2] == 0x31 && b[3] == 0x01;
}

Image::Image(const string& filename, const string& extra) {
    mName = filename;
    if (!extra.empty()) {
        mName += ":"s + extra;
    }

    if (isExrFile(filename)) {
        readExr(filename, extra);
    } else {
        readStbi(filename);
    }
}

string Image::shortName() {
    string result = mName;

    size_t slashPosition = result.find_last_of("/\\");
    if (slashPosition != string::npos) {
        result = result.substr(slashPosition + 1);
    }

    size_t colonPosition = result.find_last_of(":");
    if (colonPosition != string::npos) {
        result = result.substr(0, colonPosition);
    }

    return result;
}

vector<string> Image::channelsInLayer(string layerName) const {
    vector<string> result;

    if (layerName.empty()) {
        for (const auto& kv : mChannels) {
            if (kv.first.find(".") == string::npos) {
                result.emplace_back(kv.first);
            }
        }
    } else {
        for (const auto& kv : mChannels) {
            // If the layer name starts at the beginning, and
            // if no other dot is found after the end of the layer name,
            // then we have found a channel of this layer.
            if (kv.first.find(layerName) == 0 && kv.first.length() > layerName.length()) {
                const auto& channelWithoutLayer = kv.first.substr(layerName.length() + 1);
                if (channelWithoutLayer.find(".") == string::npos) {
                    result.emplace_back(kv.first);
                }
            }
        }
    }

    return result;
}

const GlTexture* Image::texture(const string& channelName) {
    auto iter = mTextures.find(channelName);
    if (iter != end(mTextures)) {
        return &iter->second;
    }

    const auto* chan = channel(channelName);
    if (!chan) {
        throw invalid_argument{tfm::format("Cannot obtain texture of channel %s, because the channel does not exist.", channelName)};
    }

    mTextures.emplace(channelName, GlTexture{});
    auto& texture = mTextures.at(channelName);
    texture.setData(chan->data(), mSize, 1);

    return &texture;
}

string Image::toString() const {
    string result = tfm::format("Path: %s\n\nResolution: (%d, %d)\n\nChannels:\n", mName, mSize.x(), mSize.y());

    auto localLayers = mLayers;
    transform(begin(localLayers), end(localLayers), begin(localLayers), [this](string layer) {
        auto channels = channelsInLayer(layer);
        transform(begin(channels), end(channels), begin(channels), [this](string channel) {
            return Channel::tail(channel);
        });
        if (layer.empty()) {
            layer = "<root>";
        }
        return layer + ": " + join(channels, ",");
    });

    return result + join(localLayers, "\n");
}

void Image::readStbi(const string& filename) {
    // No exr image? Try our best using stbi
    cout << "Loading "s + filename + " via STBI... ";
    auto start = chrono::system_clock::now();

    ThreadPool threadPool;

    int numChannels;
    auto data = stbi_loadf(filename.c_str(), &mSize.x(), &mSize.y(), &numChannels, 0);
    if (!data) {
        throw invalid_argument("Could not load texture data from file " + filename);
    }

    mNumChannels = static_cast<size_t>(numChannels);
    size_t numPixels = mSize.prod();

    vector<string> channelNames = {"R", "G", "B", "A"};

    vector<Channel> channels;
    for (size_t c = 0; c < mNumChannels; ++c) {
        string name = c < channelNames.size() ? channelNames[c] : to_string(c - channelNames.size());
        channels.emplace_back(name, mSize);
        channels.back().data().resize(numPixels);
    }

    threadPool.parallelFor(0, numPixels, [&](size_t i) {
        size_t baseIdx = i * mNumChannels;
        for (size_t c = 0; c < mNumChannels; ++c) {
            channels[c].data()[i] = data[baseIdx + c];
        }
    });

    stbi_image_free(data);

    for (auto& channel : channels) {
        string name = channel.name();
        mChannels.emplace(move(name), move(channel));
    }

    // STBI can not load layers, so all channels simply reside
    // within a topmost root layer.
    mLayers.emplace_back("");

    auto end = chrono::system_clock::now();
    chrono::duration<double> elapsedSeconds = end - start;

    cout << tfm::format("done after %.3f seconds.\n", elapsedSeconds.count());
}

void Image::readExr(const string& filename, const string& channelSubstr) {
    // OpenEXR for reading exr images
    cout << "Loading "s + filename + " via OpenEXR... ";
    auto start = chrono::system_clock::now();

    ThreadPool threadPool;

    Imf::MultiPartInputFile multiPartFile{filename.c_str()};
    int numParts = multiPartFile.parts();

    if (numParts <= 0) {
        throw invalid_argument{tfm::format("EXR image '%s' does not contain any parts.", filename)};
    }

    // Find the first part containing a channel that matches the given channelSubstr.
    int partIdx = 0;
    for (int i = 0; i < numParts; ++i) {
        Imf::InputPart part{multiPartFile, i};

        const Imf::ChannelList& imfChannels = part.header().channels();

        for (Imf::ChannelList::ConstIterator c = imfChannels.begin(); c != imfChannels.end(); ++c) {
            if (string{c.name()}.find(channelSubstr) != string::npos) {
                partIdx = i;
                goto l_foundPart;
            }
        }
    }
l_foundPart:

    Imf::InputPart file{multiPartFile, partIdx};
    Imath::Box2i dw = file.header().dataWindow();
    mSize.x() = dw.max.x - dw.min.x + 1;
    mSize.y() = dw.max.y - dw.min.y + 1;

    // Inline helper class for dealing with the raw channels loaded from an exr file.
    class RawChannel {
    public:
        RawChannel(string name, Imf::Channel imfChannel)
        : mName(name), mImfChannel(imfChannel) {
        }

        void resize(size_t size) {
            mData.resize(size * bytesPerPixel());
        }

        void registerWith(Imf::FrameBuffer& frameBuffer, const Imath::Box2i& dw) {
            int width = dw.max.x - dw.min.x + 1;

            frameBuffer.insert(mName.c_str(), Imf::Slice(
                mImfChannel.type,
                mData.data() - (dw.min.x + dw.min.y * width) * bytesPerPixel(),
                bytesPerPixel(), bytesPerPixel() * width,
                mImfChannel.xSampling, mImfChannel.ySampling, 0
            ));
        }

        void copyTo(Channel& channel, ThreadPool& threadPool) const {
            auto& dstData = channel.data();
            dstData.resize(mData.size() / bytesPerPixel());

            // The code in this switch statement may seem overly complicated, but it helps
            // the compiler optimize. This code is time-critical for large images.
            switch (mImfChannel.type) {
                case Imf::HALF:
                    threadPool.parallelForNoWait(0, dstData.size(), [&](size_t i) {
                        dstData[i] = static_cast<float>(*reinterpret_cast<const half*>(&mData[i * sizeof(half)]));
                    });
                    break;

                case Imf::FLOAT:
                    threadPool.parallelForNoWait(0, dstData.size(), [&](size_t i) {
                        dstData[i] = *reinterpret_cast<const float*>(&mData[i * sizeof(float)]);
                    });
                    break;

                case Imf::UINT:
                    threadPool.parallelForNoWait(0, dstData.size(), [&](size_t i) {
                        dstData[i] = static_cast<float>(*reinterpret_cast<const uint32_t*>(&mData[i * sizeof(uint32_t)]));
                    });
                    break;

                default:
                    throw runtime_error("Invalid pixel type encountered.");
            }
        }

        const auto& name() const {
            return mName;
        }

    private:
        int bytesPerPixel() const {
            switch (mImfChannel.type) {
                case Imf::HALF:  return sizeof(half);
                case Imf::FLOAT: return sizeof(float);
                case Imf::UINT:  return sizeof(uint32_t);
                default:
                    throw runtime_error("Invalid pixel type encountered.");
            }
        }

        string mName;
        Imf::Channel mImfChannel;
        vector<char> mData;
    };

    vector<RawChannel> rawChannels;
    Imf::FrameBuffer frameBuffer;

    const Imf::ChannelList& imfChannels = file.header().channels();
    set<string> layerNames;

    for (Imf::ChannelList::ConstIterator c = imfChannels.begin(); c != imfChannels.end(); ++c) {
        if (string{c.name()}.find(channelSubstr) != string::npos) {
            rawChannels.emplace_back(c.name(), c.channel().type);
            layerNames.insert(Channel::head(c.name()));
        }
    }

    if (rawChannels.empty()) {
        throw invalid_argument{tfm::format("No channels match '%s'.", channelSubstr)};
    }

    for (const string& layer : layerNames) {
        mLayers.emplace_back(layer);
    }

    threadPool.parallelFor(0, rawChannels.size(), [&](size_t i) {
        rawChannels[i].resize(mSize.prod());
    });

    for (size_t i = 0; i < rawChannels.size(); ++i) {
        rawChannels[i].registerWith(frameBuffer, dw);
    }

    file.setFrameBuffer(frameBuffer);
    file.readPixels(dw.min.y, dw.max.y);

    for (const auto& rawChannel : rawChannels) {
        mChannels.emplace(rawChannel.name(), Channel{rawChannel.name(), mSize});
    }

    for (size_t i = 0; i < rawChannels.size(); ++i) {
        rawChannels[i].copyTo(mChannels.at(rawChannels[i].name()), threadPool);
    }

    threadPool.waitUntilFinished();

    auto end = chrono::system_clock::now();
    chrono::duration<double> elapsedSeconds = end - start;

    cout << tfm::format("done after %.3f seconds.\n", elapsedSeconds.count());
}

shared_ptr<Image> tryLoadImage(string filename, string extra) {
    try {
        return make_shared<Image>(filename, extra);
    } catch (invalid_argument e) {
        tfm::format(cerr, "Could not load image from %s:%s - %s\n", filename, extra, e.what());
    } catch (Iex::BaseExc& e) {
        tfm::format(cerr, "Could not load image from %s:%s - %s\n", filename, extra, e.what());
    }

    return nullptr;
}

TEV_NAMESPACE_END
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: iderdll.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: tbe $ $Date: 2001-07-25 11:39:43 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _IDERDLL_HXX
#define _IDERDLL_HXX

class BasicIDEShell;
class BasicIDEData;

class BasicIDEDLL
{
    friend class BasicIDEShell;

    BasicIDEShell*  pShell;
    BasicIDEData*   pExtraData;

public:
                    BasicIDEDLL();
                    ~BasicIDEDLL();

    BasicIDEShell*  GetShell() const { return pShell; }
    BasicIDEData*   GetExtraData();
    static void     Init();
    static void     Exit();
    static void     LibInit();
    static void     LibExit();
    static BasicIDEDLL* GetDLL();
};

#define IDE_DLL()   BasicIDEDLL::GetDLL()

#endif //_IDERDLL_HXX
<commit_msg>INTEGRATION: CWS fwkq1 (1.2.104); FILE MERGED 2003/07/14 16:09:48 mba 1.2.104.1: #110843#: get rid of factories<commit_after>/*************************************************************************
 *
 *  $RCSfile: iderdll.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2003-09-19 08:28:52 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _IDERDLL_HXX
#define _IDERDLL_HXX

class BasicIDEShell;
class BasicIDEData;

class BasicIDEDLL
{
    friend class BasicIDEShell;

    BasicIDEShell*  pShell;
    BasicIDEData*   pExtraData;

public:
                    BasicIDEDLL();
                    ~BasicIDEDLL();

    BasicIDEShell*  GetShell() const { return pShell; }
    BasicIDEData*   GetExtraData();
    static void     Init();
    static void     Exit();
    static BasicIDEDLL* GetDLL();
};

#define IDE_DLL()   BasicIDEDLL::GetDLL()

#endif //_IDERDLL_HXX
<|endoftext|>


<commit_before>#include <QApplication>

#include "window.hpp"

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

  MainWindow w;

  w.setFixedSize(vwp_w, vwp_h);
  w.show();

  return a.exec();
}
<commit_msg>ui: force GLES context<commit_after>#include <QApplication>

#include "window.hpp"

int main(int argc, char *argv[])
{
  QSurfaceFormat fmt;
  fmt.setRenderableType(QSurfaceFormat::OpenGLES);
  QSurfaceFormat::setDefaultFormat(fmt);

  QApplication a(argc, argv);

  MainWindow w;
  w.setFixedSize(vwp_w, vwp_h);
  w.show();

  return a.exec();
}
<|endoftext|>


<commit_before>/*
 *
 *    Copyright (c) 2020 Project CHIP Authors
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#include <cinttypes>

#include "console/console.h"
#include "pw_sys_io/sys_io.h"
#include <cassert>
#include <zephyr.h>

extern "C" void pw_sys_io_Init()
{
    assert(console_init() == 0);
}

namespace pw::sys_io {

Status ReadByte(std::byte * dest)
{
    if (!dest)
        return Status::INVALID_ARGUMENT;

    const int c = console_getchar();
    *dest       = static_cast<std::byte>(c);
    return c < 0 ? Status::FAILED_PRECONDITION : Status::OK;
}

Status WriteByte(std::byte b)
{
    return console_putchar(static_cast<char>(b)) < 0 ? Status::FAILED_PRECONDITION : Status::OK;
}

// Writes a string using pw::sys_io, and add newline characters at the end.
StatusWithSize WriteLine(const std::string_view & s)
{
    size_t chars_written  = 0;
    StatusWithSize result = WriteBytes(std::as_bytes(std::span(s)));
    if (!result.ok())
    {
        return result;
    }
    chars_written += result.size();

    // Write trailing newline.
    result = WriteBytes(std::as_bytes(std::span("\r\n", 2)));
    chars_written += result.size();

    return StatusWithSize(result.status(), chars_written);
}

} // namespace pw::sys_io
<commit_msg>[nrfconnect] remove functional code from assert (#3628)<commit_after>/*
 *
 *    Copyright (c) 2020 Project CHIP Authors
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#include <cinttypes>

#include "console/console.h"
#include "pw_sys_io/sys_io.h"
#include <cassert>
#include <zephyr.h>

extern "C" void pw_sys_io_Init()
{
    int err = console_init();
    assert(err == 0);
}

namespace pw::sys_io {

Status ReadByte(std::byte * dest)
{
    if (!dest)
        return Status::INVALID_ARGUMENT;

    const int c = console_getchar();
    *dest       = static_cast<std::byte>(c);
    return c < 0 ? Status::FAILED_PRECONDITION : Status::OK;
}

Status WriteByte(std::byte b)
{
    return console_putchar(static_cast<char>(b)) < 0 ? Status::FAILED_PRECONDITION : Status::OK;
}

// Writes a string using pw::sys_io, and add newline characters at the end.
StatusWithSize WriteLine(const std::string_view & s)
{
    size_t chars_written  = 0;
    StatusWithSize result = WriteBytes(std::as_bytes(std::span(s)));
    if (!result.ok())
    {
        return result;
    }
    chars_written += result.size();

    // Write trailing newline.
    result = WriteBytes(std::as_bytes(std::span("\r\n", 2)));
    chars_written += result.size();

    return StatusWithSize(result.status(), chars_written);
}

} // namespace pw::sys_io
<|endoftext|>


<commit_before>// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#include "test.hpp"

#include <tao/pegtl/internal/demangle.hpp>

namespace TAO_PEGTL_NAMESPACE
{
   template< typename T >
   void test( const std::string& s )
   {
      TAO_PEGTL_TEST_ASSERT( internal::demangle< T >() == s );
   }

   void unit_test()
   {
#if defined( __GNUC__ ) && ( __GNUC__ == 9 ) || ( __GNUC_MINOR__ <= 2 )
      // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91155
      test< int >( "i" );
      test< double >( "d" );
      test< seq< bytes< 42 >, eof > >( "N3tao5pegtl3seqIJNS0_5bytesILj42EEENS0_3eofEEEE" );
#elif defined( _MSC_VER )
      test< int >( "int" );
      test< double >( "double" );
      test< seq< bytes< 42 >, eof > >( "struct tao::pegtl::seq<struct tao::pegtl::bytes<42>,struct tao::pegtl::eof>" );
#else
      test< int >( "int" );
      test< double >( "double" );
      test< seq< bytes< 42 >, eof > >( "tao::pegtl::seq<tao::pegtl::bytes<42>, tao::pegtl::eof>" );
#endif
   }

}  // namespace TAO_PEGTL_NAMESPACE

#include "main.hpp"
<commit_msg>Fix condition<commit_after>// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#include "test.hpp"

#include <tao/pegtl/internal/demangle.hpp>

namespace TAO_PEGTL_NAMESPACE
{
   template< typename T >
   void test( const std::string& s )
   {
      TAO_PEGTL_TEST_ASSERT( internal::demangle< T >() == s );
   }

   void unit_test()
   {
#if defined( __GNUC__ ) && ( __GNUC__ == 9 ) && ( __GNUC_MINOR__ <= 2 )
      // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91155
      test< int >( "i" );
      test< double >( "d" );
      test< seq< bytes< 42 >, eof > >( "N3tao5pegtl3seqIJNS0_5bytesILj42EEENS0_3eofEEEE" );
#elif defined( _MSC_VER )
      test< int >( "int" );
      test< double >( "double" );
      test< seq< bytes< 42 >, eof > >( "struct tao::pegtl::seq<struct tao::pegtl::bytes<42>,struct tao::pegtl::eof>" );
#else
      test< int >( "int" );
      test< double >( "double" );
      test< seq< bytes< 42 >, eof > >( "tao::pegtl::seq<tao::pegtl::bytes<42>, tao::pegtl::eof>" );
#endif
   }

}  // namespace TAO_PEGTL_NAMESPACE

#include "main.hpp"
<|endoftext|>


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

#include "tconstruct.hxx"
#include "http_cache.hxx"
#include "ResourceLoader.hxx"
#include "ResourceAddress.hxx"
#include "http_address.hxx"
#include "GrowingBuffer.hxx"
#include "header_parser.hxx"
#include "strmap.hxx"
#include "HttpResponseHandler.hxx"
#include "PInstance.hxx"
#include "fb_pool.hxx"
#include "istream/UnusedPtr.hxx"
#include "istream/istream.hxx"
#include "istream/istream_string.hxx"
#include "util/Cancellable.hxx"
#include "util/PrintException.hxx"

#include "util/Compiler.h"

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>

struct Request final : IstreamHandler {
    bool cached = false;
    http_method_t method = HTTP_METHOD_GET;
    const char *uri;
    const char *request_headers;

    http_status_t status = HTTP_STATUS_OK;
    const char *response_headers;
    const char *response_body;

    bool eof = false;
    size_t body_read = 0;

    constexpr Request(const char *_uri, const char *_request_headers,
                      const char *_response_headers,
                      const char *_response_body) noexcept
        :uri(_uri), request_headers(_request_headers),
         response_headers(_response_headers),
         response_body(_response_body) {}

    /* virtual methods from class IstreamHandler */
    size_t OnData(gcc_unused const void *data, size_t length) override {
        assert(body_read + length <= strlen(response_body));
        assert(memcmp(response_body + body_read, data, length) == 0);

        body_read += length;
        return length;
    }

    void OnEof() noexcept override {
        eof = true;
    }

    void OnError(std::exception_ptr) noexcept override {
        assert(false);
    }
};

#define DATE "Fri, 30 Jan 2009 10:53:30 GMT"
#define STAMP1 "Fri, 30 Jan 2009 08:53:30 GMT"
#define STAMP2 "Fri, 20 Jan 2009 08:53:30 GMT"
#define EXPIRES "Fri, 20 Jan 2029 08:53:30 GMT"

Request requests[] = {
    { "/foo", nullptr,
      "date: " DATE "\n"
      "last-modified: " STAMP1 "\n"
      "expires: " EXPIRES "\n"
      "vary: x-foo\n",
      "foo",
    },
    { "/foo", "x-foo: foo\n",
      "date: " DATE "\n"
      "last-modified: " STAMP2 "\n"
      "expires: " EXPIRES "\n"
      "vary: x-foo\n",
      "bar",
    },
    { "/query?string", nullptr,
      "date: " DATE "\n"
      "last-modified: " STAMP1 "\n",
      "foo",
    },
    { "/query?string2", nullptr,
      "date: " DATE "\n"
      "last-modified: " STAMP1 "\n"
      "expires: " EXPIRES "\n",
      "foo",
    },
};

static HttpCache *cache;
static unsigned current_request;
static bool got_request, got_response;
static bool validated;

static StringMap *
parse_headers(struct pool &pool, const char *raw)
{
    if (raw == NULL)
        return NULL;

    GrowingBuffer gb;
    StringMap *headers = strmap_new(&pool);
    gb.Write(raw);
    header_parse_buffer(pool, *headers, std::move(gb));

    return headers;
}

static StringMap *
parse_request_headers(struct pool &pool, const Request &request)
{
    return parse_headers(pool, request.request_headers);
}

static StringMap *
parse_response_headers(struct pool &pool, const Request &request)
{
    return parse_headers(pool, request.response_headers);
}

class MyResourceLoader final : public ResourceLoader {
public:
    /* virtual methods from class ResourceLoader */
    void SendRequest(struct pool &pool,
                     sticky_hash_t sticky_hash,
                     const char *site_name,
                     http_method_t method,
                     const ResourceAddress &address,
                     http_status_t status, StringMap &&headers,
                     UnusedIstreamPtr body, const char *body_etag,
                     HttpResponseHandler &handler,
                     CancellablePointer &cancel_ptr) override;
};

void
MyResourceLoader::SendRequest(struct pool &pool,
                              sticky_hash_t,
                              gcc_unused const char *site_name,
                              http_method_t method,
                              gcc_unused const ResourceAddress &address,
                              gcc_unused http_status_t status,
                              StringMap &&headers,
                              UnusedIstreamPtr body,
                              gcc_unused const char *body_etag,
                              HttpResponseHandler &handler,
                              gcc_unused CancellablePointer &cancel_ptr)
{
    const auto *request = &requests[current_request];
    StringMap *expected_rh;

    assert(!got_request);
    assert(!got_response);
    assert(method == request->method);

    got_request = true;

    validated = headers.Get("if-modified-since") != nullptr;

    expected_rh = parse_request_headers(pool, *request);
    if (expected_rh != NULL) {
        for (const auto &i : headers) {
            const char *value = headers.Get(i.key);
            assert(value != NULL);
            assert(strcmp(value, i.value) == 0);
        }
    }

    body.Clear();

    StringMap response_headers(pool);
    if (request->response_headers != NULL) {
        GrowingBuffer gb;
        gb.Write(request->response_headers);

        header_parse_buffer(pool, response_headers, std::move(gb));
    }

    UnusedIstreamPtr response_body;
    if (request->response_body != NULL)
        response_body = istream_string_new(pool, request->response_body);

    handler.InvokeResponse(request->status,
                           std::move(response_headers),
                           std::move(response_body));
}

struct Context final : HttpResponseHandler {
    struct pool &pool;

    explicit Context(struct pool &_pool):pool(_pool) {}

    /* virtual methods from class HttpResponseHandler */
    void OnHttpResponse(http_status_t status, StringMap &&headers,
                        UnusedIstreamPtr body) noexcept override;
    void OnHttpError(std::exception_ptr ep) noexcept override;
};

void
Context::OnHttpResponse(http_status_t status, StringMap &&headers,
                        UnusedIstreamPtr body) noexcept
{
    Request *request = &requests[current_request];
    StringMap *expected_rh;

    assert(status == request->status);

    expected_rh = parse_response_headers(pool, *request);
    if (expected_rh != NULL) {
        for (const auto &i : *expected_rh) {
            const char *value = headers.Get(i.key);
            assert(value != NULL);
            assert(strcmp(value, i.value) == 0);
        }
    }

    if (body) {
        request->body_read = 0;
        auto *b = body.Steal();
        b->SetHandler(*request);
        b->Read();
    }

    got_response = true;
}

void gcc_noreturn
Context::OnHttpError(std::exception_ptr ep) noexcept
{
    PrintException(ep);

    assert(false);
}

static void
run_cache_test(struct pool *root_pool, unsigned num, bool cached)
{
    const Request *request = &requests[num];
    struct pool *pool = pool_new_linear(root_pool, "t_http_cache", 8192);
    const auto uwa = MakeHttpAddress(request->uri).Host("foo");
    const ResourceAddress address(uwa);

    CancellablePointer cancel_ptr;

    current_request = num;

    StringMap headers(*pool);
    if (request->request_headers != NULL) {
        GrowingBuffer gb;
        gb.Write(request->request_headers);

        header_parse_buffer(*pool, headers, std::move(gb));
    }

    got_request = cached;
    got_response = false;

    Context context(*pool);
    http_cache_request(*cache, *pool, 0, nullptr,
                       request->method, address,
                       std::move(headers), nullptr,
                       context, cancel_ptr);
    pool_unref(pool);

    assert(got_request);
    assert(got_response);
}

int main(int argc, char **argv) {
    (void)argc;
    (void)argv;

    const ScopeFbPoolInit fb_pool_init;
    PInstance instance;

    MyResourceLoader resource_loader;

    cache = http_cache_new(instance.root_pool, 1024 * 1024,
                           instance.event_loop, resource_loader);

    /* request one resource, cold and warm cache */
    run_cache_test(instance.root_pool, 0, false);
    run_cache_test(instance.root_pool, 0, true);

    /* another resource, different header */
    run_cache_test(instance.root_pool, 1, false);
    run_cache_test(instance.root_pool, 1, true);

    /* see if the first resource is still cached */
    run_cache_test(instance.root_pool, 0, true);

    /* see if the second resource is still cached */
    run_cache_test(instance.root_pool, 1, true);

    /* query string: should not be cached */

    run_cache_test(instance.root_pool, 2, false);

    validated = false;
    run_cache_test(instance.root_pool, 2, false);
    assert(!validated);

    /* double check with a cacheable query string ("Expires" is
       set) */
    run_cache_test(instance.root_pool, 3, false);
    run_cache_test(instance.root_pool, 3, true);

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

#include "tconstruct.hxx"
#include "http_cache.hxx"
#include "ResourceLoader.hxx"
#include "ResourceAddress.hxx"
#include "http_address.hxx"
#include "GrowingBuffer.hxx"
#include "header_parser.hxx"
#include "strmap.hxx"
#include "HttpResponseHandler.hxx"
#include "PInstance.hxx"
#include "fb_pool.hxx"
#include "istream/UnusedPtr.hxx"
#include "istream/istream.hxx"
#include "istream/istream_string.hxx"
#include "util/Cancellable.hxx"
#include "util/PrintException.hxx"

#include "util/Compiler.h"

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>

struct Request final : IstreamHandler {
    bool cached = false;
    http_method_t method = HTTP_METHOD_GET;
    const char *uri;
    const char *request_headers;

    http_status_t status = HTTP_STATUS_OK;
    const char *response_headers;
    const char *response_body;

    bool eof = false;
    size_t body_read = 0;

    constexpr Request(const char *_uri, const char *_request_headers,
                      const char *_response_headers,
                      const char *_response_body) noexcept
        :uri(_uri), request_headers(_request_headers),
         response_headers(_response_headers),
         response_body(_response_body) {}

    /* virtual methods from class IstreamHandler */
    size_t OnData(gcc_unused const void *data, size_t length) override {
        assert(body_read + length <= strlen(response_body));
        assert(memcmp(response_body + body_read, data, length) == 0);

        body_read += length;
        return length;
    }

    void OnEof() noexcept override {
        eof = true;
    }

    void OnError(std::exception_ptr) noexcept override {
        assert(false);
    }
};

#define DATE "Fri, 30 Jan 2009 10:53:30 GMT"
#define STAMP1 "Fri, 30 Jan 2009 08:53:30 GMT"
#define STAMP2 "Fri, 20 Jan 2009 08:53:30 GMT"
#define EXPIRES "Fri, 20 Jan 2029 08:53:30 GMT"

static Request requests[] = {
    { "/foo", nullptr,
      "date: " DATE "\n"
      "last-modified: " STAMP1 "\n"
      "expires: " EXPIRES "\n"
      "vary: x-foo\n",
      "foo",
    },
    { "/foo", "x-foo: foo\n",
      "date: " DATE "\n"
      "last-modified: " STAMP2 "\n"
      "expires: " EXPIRES "\n"
      "vary: x-foo\n",
      "bar",
    },
    { "/query?string", nullptr,
      "date: " DATE "\n"
      "last-modified: " STAMP1 "\n",
      "foo",
    },
    { "/query?string2", nullptr,
      "date: " DATE "\n"
      "last-modified: " STAMP1 "\n"
      "expires: " EXPIRES "\n",
      "foo",
    },
};

static HttpCache *cache;
static unsigned current_request;
static bool got_request, got_response;
static bool validated;

static StringMap *
parse_headers(struct pool &pool, const char *raw)
{
    if (raw == NULL)
        return NULL;

    GrowingBuffer gb;
    StringMap *headers = strmap_new(&pool);
    gb.Write(raw);
    header_parse_buffer(pool, *headers, std::move(gb));

    return headers;
}

static StringMap *
parse_request_headers(struct pool &pool, const Request &request)
{
    return parse_headers(pool, request.request_headers);
}

static StringMap *
parse_response_headers(struct pool &pool, const Request &request)
{
    return parse_headers(pool, request.response_headers);
}

class MyResourceLoader final : public ResourceLoader {
public:
    /* virtual methods from class ResourceLoader */
    void SendRequest(struct pool &pool,
                     sticky_hash_t sticky_hash,
                     const char *site_name,
                     http_method_t method,
                     const ResourceAddress &address,
                     http_status_t status, StringMap &&headers,
                     UnusedIstreamPtr body, const char *body_etag,
                     HttpResponseHandler &handler,
                     CancellablePointer &cancel_ptr) override;
};

void
MyResourceLoader::SendRequest(struct pool &pool,
                              sticky_hash_t,
                              gcc_unused const char *site_name,
                              http_method_t method,
                              gcc_unused const ResourceAddress &address,
                              gcc_unused http_status_t status,
                              StringMap &&headers,
                              UnusedIstreamPtr body,
                              gcc_unused const char *body_etag,
                              HttpResponseHandler &handler,
                              gcc_unused CancellablePointer &cancel_ptr)
{
    const auto *request = &requests[current_request];
    StringMap *expected_rh;

    assert(!got_request);
    assert(!got_response);
    assert(method == request->method);

    got_request = true;

    validated = headers.Get("if-modified-since") != nullptr;

    expected_rh = parse_request_headers(pool, *request);
    if (expected_rh != NULL) {
        for (const auto &i : headers) {
            const char *value = headers.Get(i.key);
            assert(value != NULL);
            assert(strcmp(value, i.value) == 0);
        }
    }

    body.Clear();

    StringMap response_headers(pool);
    if (request->response_headers != NULL) {
        GrowingBuffer gb;
        gb.Write(request->response_headers);

        header_parse_buffer(pool, response_headers, std::move(gb));
    }

    UnusedIstreamPtr response_body;
    if (request->response_body != NULL)
        response_body = istream_string_new(pool, request->response_body);

    handler.InvokeResponse(request->status,
                           std::move(response_headers),
                           std::move(response_body));
}

struct Context final : HttpResponseHandler {
    struct pool &pool;

    explicit Context(struct pool &_pool):pool(_pool) {}

    /* virtual methods from class HttpResponseHandler */
    void OnHttpResponse(http_status_t status, StringMap &&headers,
                        UnusedIstreamPtr body) noexcept override;
    void OnHttpError(std::exception_ptr ep) noexcept override;
};

void
Context::OnHttpResponse(http_status_t status, StringMap &&headers,
                        UnusedIstreamPtr body) noexcept
{
    Request *request = &requests[current_request];
    StringMap *expected_rh;

    assert(status == request->status);

    expected_rh = parse_response_headers(pool, *request);
    if (expected_rh != NULL) {
        for (const auto &i : *expected_rh) {
            const char *value = headers.Get(i.key);
            assert(value != NULL);
            assert(strcmp(value, i.value) == 0);
        }
    }

    if (body) {
        request->body_read = 0;
        auto *b = body.Steal();
        b->SetHandler(*request);
        b->Read();
    }

    got_response = true;
}

void gcc_noreturn
Context::OnHttpError(std::exception_ptr ep) noexcept
{
    PrintException(ep);

    assert(false);
}

static void
run_cache_test(struct pool *root_pool, unsigned num, bool cached)
{
    const Request *request = &requests[num];
    struct pool *pool = pool_new_linear(root_pool, "t_http_cache", 8192);
    const auto uwa = MakeHttpAddress(request->uri).Host("foo");
    const ResourceAddress address(uwa);

    CancellablePointer cancel_ptr;

    current_request = num;

    StringMap headers(*pool);
    if (request->request_headers != NULL) {
        GrowingBuffer gb;
        gb.Write(request->request_headers);

        header_parse_buffer(*pool, headers, std::move(gb));
    }

    got_request = cached;
    got_response = false;

    Context context(*pool);
    http_cache_request(*cache, *pool, 0, nullptr,
                       request->method, address,
                       std::move(headers), nullptr,
                       context, cancel_ptr);
    pool_unref(pool);

    assert(got_request);
    assert(got_response);
}

int main(int argc, char **argv) {
    (void)argc;
    (void)argv;

    const ScopeFbPoolInit fb_pool_init;
    PInstance instance;

    MyResourceLoader resource_loader;

    cache = http_cache_new(instance.root_pool, 1024 * 1024,
                           instance.event_loop, resource_loader);

    /* request one resource, cold and warm cache */
    run_cache_test(instance.root_pool, 0, false);
    run_cache_test(instance.root_pool, 0, true);

    /* another resource, different header */
    run_cache_test(instance.root_pool, 1, false);
    run_cache_test(instance.root_pool, 1, true);

    /* see if the first resource is still cached */
    run_cache_test(instance.root_pool, 0, true);

    /* see if the second resource is still cached */
    run_cache_test(instance.root_pool, 1, true);

    /* query string: should not be cached */

    run_cache_test(instance.root_pool, 2, false);

    validated = false;
    run_cache_test(instance.root_pool, 2, false);
    assert(!validated);

    /* double check with a cacheable query string ("Expires" is
       set) */
    run_cache_test(instance.root_pool, 3, false);
    run_cache_test(instance.root_pool, 3, true);

    http_cache_close(cache);
}
<|endoftext|>


<commit_before>#include <cmath>

#include "qniteaxes.h"
#include "qniteaxis.h"
#include "qnitemapper.h"
#include "qnitezoompainter.h"
#include "qnitezoomtool.h"

QniteZoomTool::QniteZoomTool(QQuickItem *parent)
    : QniteTool{parent}, m_minZoomFactor{4}, m_pen{new QnitePen} {
  setAcceptedMouseButtons(Qt::RightButton);

  // Default pen style
  m_pen->setFill("#6EDCDCDC");
  m_pen->setStroke("#7E7E7E");
  m_pen->setWidth(1.0);

  connect(this, &QniteZoomTool::axesChanged, this,
          &QniteZoomTool::connectAxesBoundsSignals);

  connect(this, &QniteZoomTool::minZoomFactorChanged, this,
          &QniteZoomTool::updateEnabled);
}

QniteZoomTool::~QniteZoomTool() {}

QNanoQuickItemPainter *QniteZoomTool::createItemPainter() const {
  return new QniteZoomPainter;
}

void QniteZoomTool::reset() {
  auto xAxis = axes()->axisX();
  auto yAxis = axes()->axisY();

  xAxis->setLowerBound(m_baseZoomRect.x());
  xAxis->setUpperBound(m_baseZoomRect.width());
  yAxis->setLowerBound(m_baseZoomRect.y());
  yAxis->setUpperBound(m_baseZoomRect.height());
  setEnabled(true);
  update();
  axes()->updateArtists();
}

void QniteZoomTool::setMinZoomFactor(int factor) {
  if (m_minZoomFactor != factor) {
    m_minZoomFactor = factor;
    emit minZoomFactorChanged();
  }
}

void QniteZoomTool::mousePressEvent(QMouseEvent *event) {
  if (!isEnabled()) {
    return;
  }

  m_zoomRect.setTopLeft(event->pos());
}

void QniteZoomTool::mouseMoveEvent(QMouseEvent *event) {
  if (!isEnabled()) {
    return;
  }

  m_zoomRect.setBottomRight(event->pos());
  update();
}

void QniteZoomTool::mouseReleaseEvent(QMouseEvent *event) {
  if (m_zoomRect.isNull() || event->pos() == m_zoomRect.topLeft()) {
    return;
  }

  // Calculates new axes bounds and updates them
  auto yMin = qMin(m_zoomRect.top(), m_zoomRect.bottom());
  auto yMax = qMax(m_zoomRect.top(), m_zoomRect.bottom());

  auto yAxis = axes()->axisY();
  auto yMappedMin =
      yAxis->mapper()->mapTo(0, axes()->height(), yAxis->lowerBound(),
                             yAxis->upperBound(), yMin, yAxis->flip());
  auto yMappedMax =
      yAxis->mapper()->mapTo(0, axes()->height(), yAxis->lowerBound(),
                             yAxis->upperBound(), yMax, yAxis->flip());

  auto xMin = qMin(m_zoomRect.left(), m_zoomRect.right());
  auto xMax = qMax(m_zoomRect.left(), m_zoomRect.right());

  auto xAxis = axes()->axisX();
  auto xMappedMin =
      xAxis->mapper()->mapTo(0, axes()->width(), xAxis->lowerBound(),
                             xAxis->upperBound(), xMin, xAxis->flip());

  auto xMappedMax =
      xAxis->mapper()->mapTo(0, axes()->width(), xAxis->lowerBound(),
                             xAxis->upperBound(), xMax, xAxis->flip());

  yAxis->setLowerBound(qMin(yMappedMin, yMappedMax));
  yAxis->setUpperBound(qMax(yMappedMin, yMappedMax));
  xAxis->setLowerBound(qMin(xMappedMin, xMappedMax));
  xAxis->setUpperBound(qMax(xMappedMin, xMappedMax));

  m_zoomRect = QRectF{};

  update();
  axes()->updateArtists();

  // Disables tool if calculated bounds are smaller than the minimum zoom size
  auto minSize = minimumZoomSize();
  auto axisYSize = qAbs(yMappedMin - yMappedMax);
  auto axisXSize = qAbs(xMappedMin - xMappedMax);

  if (axisXSize <= minSize.width() || axisYSize <= minSize.height()) {
    setEnabled(false);
  }
}

void QniteZoomTool::connectAxesBoundsSignals() const {
  connect(axes(), &QniteAxes::xBoundsChanged, this,
          &QniteZoomTool::updateBaseZoomRectXBounds);
  connect(axes(), &QniteAxes::yBoundsChanged, this,
          &QniteZoomTool::updateBaseZoomRectYBounds);
  disconnect(this, &QniteZoomTool::axesChanged, this,
             &QniteZoomTool::connectAxesBoundsSignals);
}

void QniteZoomTool::updateBaseZoomRectXBounds() {
  auto xBounds = axes()->xBounds();
  m_baseZoomRect.setX(xBounds.first());
  m_baseZoomRect.setWidth(xBounds.last());
  disconnect(axes(), &QniteAxes::xBoundsChanged, this,
             &QniteZoomTool::updateBaseZoomRectXBounds);
}

void QniteZoomTool::updateBaseZoomRectYBounds() {
  auto yBounds = axes()->yBounds();
  m_baseZoomRect.setY(yBounds.first());
  m_baseZoomRect.setHeight(yBounds.last());
  disconnect(axes(), &QniteAxes::yBoundsChanged, this,
             &QniteZoomTool::updateBaseZoomRectYBounds);
}

QSizeF QniteZoomTool::minimumZoomSize() const {
  qreal factor = std::pow(10, m_minZoomFactor);
  return {qAbs(m_baseZoomRect.width() / factor),
          qAbs(m_baseZoomRect.height() / factor)};
}

void QniteZoomTool::updateEnabled() {
  // Disables tool if current bounds are smaller than the minimum zoom size,
  // enables it otherwise
  auto axisX = axes()->axisX();
  auto axisY = axes()->axisY();

  auto axisXSize = qAbs(axisX->lowerBound() - axisX->upperBound());
  auto axisYSize = qAbs(axisY->lowerBound() - axisY->upperBound());

  auto minSize = minimumZoomSize();
  auto enable = axisXSize > minSize.width() || axisYSize > minSize.height();
  setEnabled(enable);
}
<commit_msg>Fixed zoom rectangle being drawn when not necessary<commit_after>#include <cmath>

#include "qniteaxes.h"
#include "qniteaxis.h"
#include "qnitemapper.h"
#include "qnitezoompainter.h"
#include "qnitezoomtool.h"

QniteZoomTool::QniteZoomTool(QQuickItem *parent)
    : QniteTool{parent}, m_minZoomFactor{4}, m_pen{new QnitePen} {
  setAcceptedMouseButtons(Qt::RightButton);

  // Default pen style
  m_pen->setFill("#6EDCDCDC");
  m_pen->setStroke("#7E7E7E");
  m_pen->setWidth(1.0);

  connect(this, &QniteZoomTool::axesChanged, this,
          &QniteZoomTool::connectAxesBoundsSignals);

  connect(this, &QniteZoomTool::minZoomFactorChanged, this,
          &QniteZoomTool::updateEnabled);
}

QniteZoomTool::~QniteZoomTool() {}

QNanoQuickItemPainter *QniteZoomTool::createItemPainter() const {
  return new QniteZoomPainter;
}

void QniteZoomTool::reset() {
  auto xAxis = axes()->axisX();
  auto yAxis = axes()->axisY();

  xAxis->setLowerBound(m_baseZoomRect.x());
  xAxis->setUpperBound(m_baseZoomRect.width());
  yAxis->setLowerBound(m_baseZoomRect.y());
  yAxis->setUpperBound(m_baseZoomRect.height());
  setEnabled(true);
  update();
  axes()->updateArtists();
}

void QniteZoomTool::setMinZoomFactor(int factor) {
  if (m_minZoomFactor != factor) {
    m_minZoomFactor = factor;
    emit minZoomFactorChanged();
  }
}

void QniteZoomTool::mousePressEvent(QMouseEvent *event) {
  if (!isEnabled()) {
    return;
  }

  m_zoomRect.setTopLeft(event->pos());
}

void QniteZoomTool::mouseMoveEvent(QMouseEvent *event) {
  if (!isEnabled()) {
    return;
  }

  m_zoomRect.setBottomRight(event->pos());
  update();
}

void QniteZoomTool::mouseReleaseEvent(QMouseEvent *event) {
  if (m_zoomRect.isNull() || event->pos() == m_zoomRect.topLeft()) {
    m_zoomRect = QRectF{};
    return;
  }

  // Calculates new axes bounds and updates them
  auto yMin = qMin(m_zoomRect.top(), m_zoomRect.bottom());
  auto yMax = qMax(m_zoomRect.top(), m_zoomRect.bottom());

  auto yAxis = axes()->axisY();
  auto yMappedMin =
      yAxis->mapper()->mapTo(0, axes()->height(), yAxis->lowerBound(),
                             yAxis->upperBound(), yMin, yAxis->flip());
  auto yMappedMax =
      yAxis->mapper()->mapTo(0, axes()->height(), yAxis->lowerBound(),
                             yAxis->upperBound(), yMax, yAxis->flip());

  auto xMin = qMin(m_zoomRect.left(), m_zoomRect.right());
  auto xMax = qMax(m_zoomRect.left(), m_zoomRect.right());

  auto xAxis = axes()->axisX();
  auto xMappedMin =
      xAxis->mapper()->mapTo(0, axes()->width(), xAxis->lowerBound(),
                             xAxis->upperBound(), xMin, xAxis->flip());

  auto xMappedMax =
      xAxis->mapper()->mapTo(0, axes()->width(), xAxis->lowerBound(),
                             xAxis->upperBound(), xMax, xAxis->flip());

  yAxis->setLowerBound(qMin(yMappedMin, yMappedMax));
  yAxis->setUpperBound(qMax(yMappedMin, yMappedMax));
  xAxis->setLowerBound(qMin(xMappedMin, xMappedMax));
  xAxis->setUpperBound(qMax(xMappedMin, xMappedMax));

  m_zoomRect = QRectF{};

  update();
  axes()->updateArtists();

  // Disables tool if calculated bounds are smaller than the minimum zoom size
  auto minSize = minimumZoomSize();
  auto axisYSize = qAbs(yMappedMin - yMappedMax);
  auto axisXSize = qAbs(xMappedMin - xMappedMax);

  if (axisXSize <= minSize.width() || axisYSize <= minSize.height()) {
    setEnabled(false);
  }
}

void QniteZoomTool::connectAxesBoundsSignals() const {
  connect(axes(), &QniteAxes::xBoundsChanged, this,
          &QniteZoomTool::updateBaseZoomRectXBounds);
  connect(axes(), &QniteAxes::yBoundsChanged, this,
          &QniteZoomTool::updateBaseZoomRectYBounds);
  disconnect(this, &QniteZoomTool::axesChanged, this,
             &QniteZoomTool::connectAxesBoundsSignals);
}

void QniteZoomTool::updateBaseZoomRectXBounds() {
  auto xBounds = axes()->xBounds();
  m_baseZoomRect.setX(xBounds.first());
  m_baseZoomRect.setWidth(xBounds.last());
  disconnect(axes(), &QniteAxes::xBoundsChanged, this,
             &QniteZoomTool::updateBaseZoomRectXBounds);
}

void QniteZoomTool::updateBaseZoomRectYBounds() {
  auto yBounds = axes()->yBounds();
  m_baseZoomRect.setY(yBounds.first());
  m_baseZoomRect.setHeight(yBounds.last());
  disconnect(axes(), &QniteAxes::yBoundsChanged, this,
             &QniteZoomTool::updateBaseZoomRectYBounds);
}

QSizeF QniteZoomTool::minimumZoomSize() const {
  qreal factor = std::pow(10, m_minZoomFactor);
  return {qAbs(m_baseZoomRect.width() / factor),
          qAbs(m_baseZoomRect.height() / factor)};
}

void QniteZoomTool::updateEnabled() {
  // Disables tool if current bounds are smaller than the minimum zoom size,
  // enables it otherwise
  auto axisX = axes()->axisX();
  auto axisY = axes()->axisY();

  auto axisXSize = qAbs(axisX->lowerBound() - axisX->upperBound());
  auto axisYSize = qAbs(axisY->lowerBound() - axisY->upperBound());

  auto minSize = minimumZoomSize();
  auto enable = axisXSize > minSize.width() || axisYSize > minSize.height();
  setEnabled(enable);
}
<|endoftext|>


<commit_before>//! \file
/*
**  Copyright (C) - Triton
**
**  This program is under the terms of the LGPLv3 License.
*/

#ifndef TRITON_PIN_PYTHONBINDINGS_H
#define TRITON_PIN_PYTHONBINDINGS_H

#include <map>
#include <set>
#include <list>

#include <python2.7/Python.h>
#include <pin.H>

/* libTriton */
#include <api.hpp>
#include <tritonTypes.hpp>

/* pintool */
#include "trigger.hpp"
#include "snapshot.hpp"

//! \module The Tracer namespace
namespace tracer {
/*!
 *  \addtogroup tracer
 *  @{
 */

  //! \module The pintool namespace
  namespace pintool {
  /*!
   *  \ingroup tracer
   *  \addtogroup pintool
   *  @{
   */

    //! Lock / Unlock InsertCall
    extern Trigger analysisTrigger;

    //! Snapshot engine
    extern Snapshot snapshot;

    //! Python callbacks of the pintool module.
    extern PyMethodDef pintoolCallbacks[];

    //! The python script which will be executed by Pin.
    bool execScript(const char* fileName);

    //! The initialization of the Pin's Python env.
    void initBindings(void);

    extern std::string getImageName(triton::__uint address);

    //! \module The options namespace
    namespace options {
    /*!
     *  \ingroup pintool
     *  \addtogroup options
     *  @{
     */

      //! Kind of callback.
      enum cb_kind {
        CB_AFTER,           //!< After the instruction processing.
        CB_BEFORE,          //!< Before the instruction processing.
        CB_BEFORE_SYMPROC,  //!< Before the IR processing.
        CB_FINI,            //!< At the end of the execution.
        CB_ROUTINE_ENTRY,   //!< Before the routine processing.
        CB_ROUTINE_EXIT,    //!< After the routine processing.
        CB_SIGNALS,         //!< When a signal occurs.
        CB_SYSCALL_ENTRY,   //!< Before the syscall processing.
        CB_SYSCALL_EXIT,    //!< After the syscall processing.
        CB_IMAGE_LOAD,      //!< When an image is loaded.
      };

      //! Start analysis from a symbol.
      extern char* startAnalysisFromSymbol;

      //! Start analysis from the entry point.
      extern bool startAnalysisFromEntry;

      //! Start analysis from a symbol.
      extern std::set<triton::__uint> startAnalysisFromAddr;

      //! Start analysis from an offset.
      extern std::set<triton::__uint> startAnalysisFromOffset;

      //! Stop analysis from address.
      extern std::set<triton::__uint> stopAnalysisFromAddr;

      //! Stop analysis from an offset.
      extern std::set<triton::__uint> stopAnalysisFromOffset;

      //! Callback called after the instruction processing.
      extern PyObject* callbackAfter;

      //! Callback called before the instruction processing.
      extern PyObject* callbackBefore;

      //! Callback called before the IR processing.
      extern PyObject* callbackBeforeIRProc;

      //! Callback called at the end of the execution.
      extern PyObject* callbackFini;

      //! Callback called when a signal occurs.
      extern PyObject* callbackSignals;

      //! Callback called before the syscall processing.
      extern PyObject* callbackSyscallEntry;

      //! Callback called after the syscall processing.
      extern PyObject* callbackSyscallExit;

      //! Callback called when an image is loaded.
      extern PyObject* callbackImageLoad;

      //! Callback called before routine processing.
      extern std::map<const char*, PyObject*> callbackRoutineEntry;

      //! Callback callled after routine processing.
      extern std::map<const char*, PyObject*> callbackRoutineExit;

      //! An image white list.
      extern std::list<const char*> imageWhitelist;

      //! An image black list.
      extern std::list<const char*> imageBlacklist;

      //! TID focused during the JIT
      extern triton::uint32 targetThreadId;

    /*! @} End of options namespace */
    };

    //! \module The callbacks namespace
    namespace callbacks {
    /*!
     *  \ingroup pintool
     *  \addtogroup callback
     *  @{
     */

      //! Callback called after the instruction processing.
      void after(triton::arch::Instruction* inst);

      //! Callback called before the instruction processing.
      void before(triton::arch::Instruction* inst);

      //! Callback called before the IR processing.
      void beforeIRProc(triton::arch::Instruction* inst);

      //! Callback called at the end of the execution.
      void fini(void);

      //! Callback called before and after routine processing.
      void routine(triton::uint32 threadId, PyObject* callback);

      //! Callback called when a signal occurs.
      void signals(triton::uint32 threadId, triton::sint32 sig);

      //! Callback called before the syscall processing.
      void syscallEntry(triton::uint32 threadId, triton::uint32 std);

      //! Callback called after the syscall processing.
      void syscallExit(triton::uint32 threadId, triton::uint32 std);

      //! Callback called when an image is loaded.
      void imageLoad(std::string imagePath, triton::__uint imageBase, triton::__uint imageSize);

      //! Pre processing configuration.
      void preProcessing(triton::arch::Instruction* inst, triton::uint32 threadId);

      //! Post processing configuration.
      void postProcessing(triton::arch::Instruction* inst, triton::uint32 threadId);

    /*! @} End of callback namespace */
    };

  /*! @} End of pintool namespace */
  };
/*! @} End of tracer namespace */
};

#endif /* TRITON_PIN_PYTHONBINDINGS_H */
<commit_msg>Add doc<commit_after>//! \file
/*
**  Copyright (C) - Triton
**
**  This program is under the terms of the LGPLv3 License.
*/

#ifndef TRITON_PIN_PYTHONBINDINGS_H
#define TRITON_PIN_PYTHONBINDINGS_H

#include <map>
#include <set>
#include <list>

#include <python2.7/Python.h>
#include <pin.H>

/* libTriton */
#include <api.hpp>
#include <tritonTypes.hpp>

/* pintool */
#include "trigger.hpp"
#include "snapshot.hpp"

//! \module The Tracer namespace
namespace tracer {
/*!
 *  \addtogroup tracer
 *  @{
 */

  //! \module The pintool namespace
  namespace pintool {
  /*!
   *  \ingroup tracer
   *  \addtogroup pintool
   *  @{
   */

    //! Lock / Unlock InsertCall
    extern Trigger analysisTrigger;

    //! Snapshot engine
    extern Snapshot snapshot;

    //! Python callbacks of the pintool module.
    extern PyMethodDef pintoolCallbacks[];

    //! The python script which will be executed by Pin.
    bool execScript(const char* fileName);

    //! The initialization of the Pin's Python env.
    void initBindings(void);

    //! Image name from address
    extern std::string getImageName(triton::__uint address);

    //! \module The options namespace
    namespace options {
    /*!
     *  \ingroup pintool
     *  \addtogroup options
     *  @{
     */

      //! Kind of callback.
      enum cb_kind {
        CB_AFTER,           //!< After the instruction processing.
        CB_BEFORE,          //!< Before the instruction processing.
        CB_BEFORE_SYMPROC,  //!< Before the IR processing.
        CB_FINI,            //!< At the end of the execution.
        CB_ROUTINE_ENTRY,   //!< Before the routine processing.
        CB_ROUTINE_EXIT,    //!< After the routine processing.
        CB_SIGNALS,         //!< When a signal occurs.
        CB_SYSCALL_ENTRY,   //!< Before the syscall processing.
        CB_SYSCALL_EXIT,    //!< After the syscall processing.
        CB_IMAGE_LOAD,      //!< When an image is loaded.
      };

      //! Start analysis from a symbol.
      extern char* startAnalysisFromSymbol;

      //! Start analysis from the entry point.
      extern bool startAnalysisFromEntry;

      //! Start analysis from a symbol.
      extern std::set<triton::__uint> startAnalysisFromAddr;

      //! Start analysis from an offset.
      extern std::set<triton::__uint> startAnalysisFromOffset;

      //! Stop analysis from address.
      extern std::set<triton::__uint> stopAnalysisFromAddr;

      //! Stop analysis from an offset.
      extern std::set<triton::__uint> stopAnalysisFromOffset;

      //! Callback called after the instruction processing.
      extern PyObject* callbackAfter;

      //! Callback called before the instruction processing.
      extern PyObject* callbackBefore;

      //! Callback called before the IR processing.
      extern PyObject* callbackBeforeIRProc;

      //! Callback called at the end of the execution.
      extern PyObject* callbackFini;

      //! Callback called when a signal occurs.
      extern PyObject* callbackSignals;

      //! Callback called before the syscall processing.
      extern PyObject* callbackSyscallEntry;

      //! Callback called after the syscall processing.
      extern PyObject* callbackSyscallExit;

      //! Callback called when an image is loaded.
      extern PyObject* callbackImageLoad;

      //! Callback called before routine processing.
      extern std::map<const char*, PyObject*> callbackRoutineEntry;

      //! Callback callled after routine processing.
      extern std::map<const char*, PyObject*> callbackRoutineExit;

      //! An image white list.
      extern std::list<const char*> imageWhitelist;

      //! An image black list.
      extern std::list<const char*> imageBlacklist;

      //! TID focused during the JIT
      extern triton::uint32 targetThreadId;

    /*! @} End of options namespace */
    };

    //! \module The callbacks namespace
    namespace callbacks {
    /*!
     *  \ingroup pintool
     *  \addtogroup callback
     *  @{
     */

      //! Callback called after the instruction processing.
      void after(triton::arch::Instruction* inst);

      //! Callback called before the instruction processing.
      void before(triton::arch::Instruction* inst);

      //! Callback called before the IR processing.
      void beforeIRProc(triton::arch::Instruction* inst);

      //! Callback called at the end of the execution.
      void fini(void);

      //! Callback called before and after routine processing.
      void routine(triton::uint32 threadId, PyObject* callback);

      //! Callback called when a signal occurs.
      void signals(triton::uint32 threadId, triton::sint32 sig);

      //! Callback called before the syscall processing.
      void syscallEntry(triton::uint32 threadId, triton::uint32 std);

      //! Callback called after the syscall processing.
      void syscallExit(triton::uint32 threadId, triton::uint32 std);

      //! Callback called when an image is loaded.
      void imageLoad(std::string imagePath, triton::__uint imageBase, triton::__uint imageSize);

      //! Pre processing configuration.
      void preProcessing(triton::arch::Instruction* inst, triton::uint32 threadId);

      //! Post processing configuration.
      void postProcessing(triton::arch::Instruction* inst, triton::uint32 threadId);

    /*! @} End of callback namespace */
    };

  /*! @} End of pintool namespace */
  };
/*! @} End of tracer namespace */
};

#endif /* TRITON_PIN_PYTHONBINDINGS_H */
<|endoftext|>