<commit_before>#ifndef STAN_MATH_OPENCL_TRI_INVERSE_HPP
#define STAN_MATH_OPENCL_TRI_INVERSE_HPP

#ifdef STAN_OPENCL

#include <stan/math/opencl/matrix_cl.hpp>
#include <stan/math/opencl/matrix_cl_view.hpp>
#include <stan/math/opencl/kernels/diag_inv.hpp>
#include <stan/math/opencl/kernels/inv_lower_tri_multiply.hpp>
#include <stan/math/opencl/kernels/neg_rect_lower_tri_multiply.hpp>
#include <stan/math/opencl/err.hpp>
#include <stan/math/opencl/identity.hpp>
#include <stan/math/opencl/sub_block.hpp>
#include <stan/math/opencl/zeros.hpp>
#include <stan/math/opencl/kernel_generator.hpp>
#include <stan/math/prim/meta.hpp>
#include <cmath>
#include <string>
#include <vector>

namespace stan {
namespace math {
/** \ingroup opencl
 * Computes the inverse of a triangular matrix
 *
 * For a full guide to how this works and fits into Cholesky decompositions,
 * see the reference report
 *
 * here and kernel doc
 * here.
 *
 * @param A matrix on the OpenCL device
 * @return the inverse of A
 *
 * @throw std::invalid_argument if the matrix
 *    is not square
 */
template <matrix_cl_view matrix_view = matrix_cl_view::Entire, typename T,
          typename = require_floating_point_t<T>>
inline matrix_cl<T> tri_inverse(const matrix_cl<T>& A) {
  // if the triangular view is not specified use the triangularity of
  // the input matrix
  matrix_cl_view tri_view = matrix_view;
  if (matrix_view == matrix_cl_view::Entire
      || matrix_view == matrix_cl_view::Diagonal) {
    tri_view = A.view();
  }
  check_triangular("tri_inverse (OpenCL)", "A", A);
  check_square("tri_inverse (OpenCL)", "A", A);

  int thread_block_2D_dim = 32;
  int max_1D_thread_block_size = opencl_context.max_thread_block_size();
  // we split the input matrix to 32 blocks
  int thread_block_size_1D
      = (((A.rows() / 32) + thread_block_2D_dim - 1) / thread_block_2D_dim)
        * thread_block_2D_dim;
  if (max_1D_thread_block_size < thread_block_size_1D) {
    thread_block_size_1D = max_1D_thread_block_size;
  }
  int max_2D_thread_block_dim = std::sqrt(max_1D_thread_block_size);
  if (max_2D_thread_block_dim < thread_block_2D_dim) {
    thread_block_2D_dim = max_2D_thread_block_dim;
  }
  // for small size split in max 2 parts
  if (thread_block_size_1D < 64) {
    thread_block_size_1D = 32;
  }
  if (A.rows() < thread_block_size_1D) {
    thread_block_size_1D = A.rows();
  }

  // pad the input matrix
  int A_rows_padded
      = ((A.rows() + thread_block_size_1D - 1) / thread_block_size_1D)
        * thread_block_size_1D;

  matrix_cl<T> temp(A_rows_padded, A_rows_padded);
  matrix_cl<T> inv_padded(A_rows_padded, A_rows_padded);
  matrix_cl<T> inv_mat(A);
  matrix_cl<T> zero_mat(A_rows_padded - A.rows(), A_rows_padded);
  zero_mat.template zeros<stan::math::matrix_cl_view::Entire>();
  inv_padded.template zeros<stan::math::matrix_cl_view::Entire>();
  if (tri_view == matrix_cl_view::Upper) {
    inv_mat = transpose(inv_mat);
  }
  int work_per_thread
      = opencl_kernels::inv_lower_tri_multiply.make_functor.get_opts().at(
          "WORK_PER_THREAD");
  // the number of blocks in the first step
  // each block is inverted with using the regular forward substitution
  int parts = inv_padded.rows() / thread_block_size_1D;
  inv_padded.sub_block(inv_mat, 0, 0, 0, 0, inv_mat.rows(), inv_mat.rows());
  try {
    // create a batch of identity matrices to be used in the first step
    opencl_kernels::batch_identity(
        cl::NDRange(parts, thread_block_size_1D, thread_block_size_1D), temp,
        thread_block_size_1D, temp.size());
    // spawn parts thread blocks, each responsible for one block
    opencl_kernels::diag_inv(cl::NDRange(parts * thread_block_size_1D),
                             cl::NDRange(thread_block_size_1D), inv_padded,
                             temp, inv_padded.rows());
  } catch (cl::Error& e) {
    check_opencl_error("inverse step1", e);
  }
  // set the padded part of the matrix and the upper triangular to zeros
  inv_padded.sub_block(zero_mat, 0, 0, inv_mat.rows(), 0, zero_mat.rows(),
                       zero_mat.cols());
  inv_padded.template zeros_strict_tri<stan::math::matrix_cl_view::Upper>();
  if (parts == 1) {
    inv_mat.sub_block(inv_padded, 0, 0, 0, 0, inv_mat.rows(), inv_mat.rows());
    if (tri_view == matrix_cl_view::Upper) {
      inv_mat = transpose(inv_mat);
    }
    return inv_mat;
  }
  using std::ceil;
  parts = ceil(parts / 2.0);

  auto result_matrix_dim = thread_block_size_1D;
  auto thread_block_work2d_dim = thread_block_2D_dim / work_per_thread;
  auto ndrange_2d
      = cl::NDRange(thread_block_2D_dim, thread_block_work2d_dim, 1);
  while (parts > 0) {
    int result_matrix_dim_x = result_matrix_dim;
    // when calculating the last submatrix
    // we can reduce the size to the actual size (not the next power of 2)
    if (parts == 1 && (inv_padded.rows() - result_matrix_dim * 2) < 0) {
      result_matrix_dim_x = inv_padded.rows() - result_matrix_dim;
    }
    auto result_work_dim = result_matrix_dim / work_per_thread;
    auto result_ndrange
        = cl::NDRange(result_matrix_dim_x, result_work_dim, parts);
    opencl_kernels::inv_lower_tri_multiply(result_ndrange, ndrange_2d,
                                           inv_padded, temp, inv_padded.rows(),
                                           result_matrix_dim);
    opencl_kernels::neg_rect_lower_tri_multiply(
        result_ndrange, ndrange_2d, inv_padded, temp, inv_padded.rows(),
        result_matrix_dim);
    // if this is the last submatrix, end
    if (parts == 1) {
      parts = 0;
    } else {
      parts = ceil(parts / 2.0);
    }
    result_matrix_dim *= 2;
    // set the padded part and upper diagonal to zeros
    inv_padded.sub_block(zero_mat, 0, 0, inv_mat.rows(), 0, zero_mat.rows(),
                         zero_mat.cols());
    inv_padded.template zeros_strict_tri<stan::math::matrix_cl_view::Upper>();
  }
  // un-pad and return
  inv_mat.sub_block(inv_padded, 0, 0, 0, 0, inv_mat.rows(), inv_mat.rows());
  if (tri_view == matrix_cl_view::Upper) {
    inv_mat = transpose(inv_mat);
  }
  inv_mat.view(tri_view);
  return inv_mat;
}
}  // namespace math
}  // namespace stan

#endif
#endif
<commit_msg>fixed aliasing in tri_inverse<commit_after>#ifndef STAN_MATH_OPENCL_TRI_INVERSE_HPP
#define STAN_MATH_OPENCL_TRI_INVERSE_HPP

#ifdef STAN_OPENCL

#include <stan/math/opencl/matrix_cl.hpp>
#include <stan/math/opencl/matrix_cl_view.hpp>
#include <stan/math/opencl/kernels/diag_inv.hpp>
#include <stan/math/opencl/kernels/inv_lower_tri_multiply.hpp>
#include <stan/math/opencl/kernels/neg_rect_lower_tri_multiply.hpp>
#include <stan/math/opencl/err.hpp>
#include <stan/math/opencl/identity.hpp>
#include <stan/math/opencl/sub_block.hpp>
#include <stan/math/opencl/zeros.hpp>
#include <stan/math/opencl/kernel_generator.hpp>
#include <stan/math/prim/meta.hpp>
#include <cmath>
#include <string>
#include <vector>

namespace stan {
namespace math {
/** \ingroup opencl
 * Computes the inverse of a triangular matrix
 *
 * For a full guide to how this works and fits into Cholesky decompositions,
 * see the reference report
 *
 * here and kernel doc
 * here.
 *
 * @param A matrix on the OpenCL device
 * @return the inverse of A
 *
 * @throw std::invalid_argument if the matrix
 *    is not square
 */
template <matrix_cl_view matrix_view = matrix_cl_view::Entire, typename T,
          typename = require_floating_point_t<T>>
inline matrix_cl<T> tri_inverse(const matrix_cl<T>& A) {
  // if the triangular view is not specified use the triangularity of
  // the input matrix
  matrix_cl_view tri_view = matrix_view;
  if (matrix_view == matrix_cl_view::Entire
      || matrix_view == matrix_cl_view::Diagonal) {
    tri_view = A.view();
  }
  check_triangular("tri_inverse (OpenCL)", "A", A);
  check_square("tri_inverse (OpenCL)", "A", A);

  int thread_block_2D_dim = 32;
  int max_1D_thread_block_size = opencl_context.max_thread_block_size();
  // we split the input matrix to 32 blocks
  int thread_block_size_1D
      = (((A.rows() / 32) + thread_block_2D_dim - 1) / thread_block_2D_dim)
        * thread_block_2D_dim;
  if (max_1D_thread_block_size < thread_block_size_1D) {
    thread_block_size_1D = max_1D_thread_block_size;
  }
  int max_2D_thread_block_dim = std::sqrt(max_1D_thread_block_size);
  if (max_2D_thread_block_dim < thread_block_2D_dim) {
    thread_block_2D_dim = max_2D_thread_block_dim;
  }
  // for small size split in max 2 parts
  if (thread_block_size_1D < 64) {
    thread_block_size_1D = 32;
  }
  if (A.rows() < thread_block_size_1D) {
    thread_block_size_1D = A.rows();
  }

  // pad the input matrix
  int A_rows_padded
      = ((A.rows() + thread_block_size_1D - 1) / thread_block_size_1D)
        * thread_block_size_1D;

  matrix_cl<T> temp(A_rows_padded, A_rows_padded);
  matrix_cl<T> inv_padded(A_rows_padded, A_rows_padded);
  matrix_cl<T> inv_mat(A);
  matrix_cl<T> zero_mat(A_rows_padded - A.rows(), A_rows_padded);
  zero_mat.template zeros<stan::math::matrix_cl_view::Entire>();
  inv_padded.template zeros<stan::math::matrix_cl_view::Entire>();
  if (tri_view == matrix_cl_view::Upper) {
    inv_mat = transpose(inv_mat).eval();
  }
  int work_per_thread
      = opencl_kernels::inv_lower_tri_multiply.make_functor.get_opts().at(
          "WORK_PER_THREAD");
  // the number of blocks in the first step
  // each block is inverted with using the regular forward substitution
  int parts = inv_padded.rows() / thread_block_size_1D;
  inv_padded.sub_block(inv_mat, 0, 0, 0, 0, inv_mat.rows(), inv_mat.rows());
  try {
    // create a batch of identity matrices to be used in the first step
    opencl_kernels::batch_identity(
        cl::NDRange(parts, thread_block_size_1D, thread_block_size_1D), temp,
        thread_block_size_1D, temp.size());
    // spawn parts thread blocks, each responsible for one block
    opencl_kernels::diag_inv(cl::NDRange(parts * thread_block_size_1D),
                             cl::NDRange(thread_block_size_1D), inv_padded,
                             temp, inv_padded.rows());
  } catch (cl::Error& e) {
    check_opencl_error("inverse step1", e);
  }
  // set the padded part of the matrix and the upper triangular to zeros
  inv_padded.sub_block(zero_mat, 0, 0, inv_mat.rows(), 0, zero_mat.rows(),
                       zero_mat.cols());
  inv_padded.template zeros_strict_tri<stan::math::matrix_cl_view::Upper>();
  if (parts == 1) {
    inv_mat.sub_block(inv_padded, 0, 0, 0, 0, inv_mat.rows(), inv_mat.rows());
    if (tri_view == matrix_cl_view::Upper) {
      inv_mat = transpose(inv_mat).eval();
    }
    return inv_mat;
  }
  using std::ceil;
  parts = ceil(parts / 2.0);

  auto result_matrix_dim = thread_block_size_1D;
  auto thread_block_work2d_dim = thread_block_2D_dim / work_per_thread;
  auto ndrange_2d
      = cl::NDRange(thread_block_2D_dim, thread_block_work2d_dim, 1);
  while (parts > 0) {
    int result_matrix_dim_x = result_matrix_dim;
    // when calculating the last submatrix
    // we can reduce the size to the actual size (not the next power of 2)
    if (parts == 1 && (inv_padded.rows() - result_matrix_dim * 2) < 0) {
      result_matrix_dim_x = inv_padded.rows() - result_matrix_dim;
    }
    auto result_work_dim = result_matrix_dim / work_per_thread;
    auto result_ndrange
        = cl::NDRange(result_matrix_dim_x, result_work_dim, parts);
    opencl_kernels::inv_lower_tri_multiply(result_ndrange, ndrange_2d,
                                           inv_padded, temp, inv_padded.rows(),
                                           result_matrix_dim);
    opencl_kernels::neg_rect_lower_tri_multiply(
        result_ndrange, ndrange_2d, inv_padded, temp, inv_padded.rows(),
        result_matrix_dim);
    // if this is the last submatrix, end
    if (parts == 1) {
      parts = 0;
    } else {
      parts = ceil(parts / 2.0);
    }
    result_matrix_dim *= 2;
    // set the padded part and upper diagonal to zeros
    inv_padded.sub_block(zero_mat, 0, 0, inv_mat.rows(), 0, zero_mat.rows(),
                         zero_mat.cols());
    inv_padded.template zeros_strict_tri<stan::math::matrix_cl_view::Upper>();
  }
  // un-pad and return
  inv_mat.sub_block(inv_padded, 0, 0, 0, 0, inv_mat.rows(), inv_mat.rows());
  if (tri_view == matrix_cl_view::Upper) {
    inv_mat = transpose(inv_mat).eval();
  }
  inv_mat.view(tri_view);
  return inv_mat;
}
}  // namespace math
}  // namespace stan

#endif
#endif
<|endoftext|>


<commit_before>#include "MainFrame.h"
#include <algorithm>
#include <wx/log.h>
#include <wx/mstream.h>
#include <wx/button.h>
#include "ImageViewPanel.h"
#include "ZipEntry.h"
#include "FileEntry.h"

enum MainFrameIds { ID_DIRECTORY_TREE = 1, ID_IMAGE_BUTTON };

MainFrame::MainFrame() : wxFrame(NULL, wxID_ANY, "ZipPicView") {
  auto statusBar = CreateStatusBar();
  SetStatusText("Welcome to ZipPicView!");

  auto outerSizer = new wxBoxSizer(wxVERTICAL);
  auto toolSizer = new wxBoxSizer(wxHORIZONTAL);
  onTopChk = new wxCheckBox(this, wxID_ANY, "On Top");
  onTopChk->Bind(wxEVT_CHECKBOX, &MainFrame::OnOnTopChecked, this);
  notebook = new wxNotebook(this, wxID_ANY);

  currentFileCtrl =
      new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
                     wxDefaultSize, wxTE_READONLY);
  dirBrowseBtn = new wxButton(this, wxID_ANY, "Directory...");
  dirBrowseBtn->Bind(wxEVT_BUTTON, &MainFrame::OnDirBrowsePressed, this);
  zipBrowseBtn = new wxButton(this, wxID_ANY, "Zip...");
  zipBrowseBtn->Bind(wxEVT_BUTTON, &MainFrame::OnZipBrowsePressed, this);

  toolSizer->Add(currentFileCtrl, 1, wxEXPAND | wxALL);
  toolSizer->Add(dirBrowseBtn, 0, wxEXPAND | wxALL);
  toolSizer->Add(zipBrowseBtn, 0, wxEXPAND | wxALL);
  toolSizer->Add(onTopChk, 0, wxEXPAND | wxALL);

  outerSizer->Add(toolSizer, 0, wxEXPAND | wxALL, 5);
  outerSizer->Add(notebook, 1, wxEXPAND | wxALL, 5);

  splitter = new wxSplitterWindow(notebook, wxID_ANY);
  dirTree = new wxTreeCtrl(splitter, ID_DIRECTORY_TREE, wxDefaultPosition,
                           wxDefaultSize, wxTR_SINGLE | wxTR_NO_LINES |
                                              wxTR_FULL_ROW_HIGHLIGHT);
  dirTree->Bind(wxEVT_TREE_SEL_CHANGED, &MainFrame::OnTreeSelectionChanged,
                this, ID_DIRECTORY_TREE);
  dirTree->Bind(wxEVT_TREE_ITEM_COLLAPSING,
                [=](wxTreeEvent &event) { event.Veto(); }, ID_DIRECTORY_TREE);
  dirTree->SetMinSize({250, 250});

  auto rightWindow = new wxScrolledWindow(splitter, wxID_ANY);
  auto grid = new wxGridSizer(5);
  rightWindow->SetSizer(grid);
  rightWindow->SetScrollRate(10, 10);
  rightWindow->SetMinSize({250, 250});
  rightWindow->Bind(wxEVT_SIZE, &MainFrame::OnGridPanelSize, this);
  splitter->SplitVertically(dirTree, rightWindow, 250);

  notebook->AddPage(splitter, "Browse");

  SetMinSize({640, 480});
  SetSizer(outerSizer);
}

void MainFrame::BuildDirectoryTree() {
  auto root = dirTree->AddRoot(entry->Name(), -1, -1, new EntryItemData(entry));
  AddTreeItemsFromEntry(root, entry);
}

void MainFrame::AddTreeItemsFromEntry(const wxTreeItemId &itemId,
                                      Entry *entry) {
  for (auto childEntry : *entry) {
    if (!childEntry->IsDirectory())
      return;

    auto child = dirTree->AppendItem(itemId, childEntry->Name(), -1, -1,
                                     new EntryItemData(childEntry));

    AddTreeItemsFromEntry(child, childEntry);
  }
}

void MainFrame::OnTreeSelectionChanged(wxTreeEvent &event) {
  wxProgressDialog progressDlg("Loading", "Please Wait");

  auto treeItemId = event.GetItem();
  auto rootId = dirTree->GetRootItem();
  auto currentFileEntry =
      dynamic_cast<EntryItemData *>(dirTree->GetItemData(treeItemId))->Get();

  progressDlg.Pulse();
  auto gridPanel = dynamic_cast<wxScrolledWindow *>(splitter->GetWindow2());
  gridPanel->Show(false);
  auto grid = gridPanel->GetSizer();
  grid->Clear(true);

  for (auto childEntry : *currentFileEntry) {
    if (childEntry->IsDirectory())
      return;

    auto name = childEntry->Name();
    if (!(name.EndsWith(".jpg") || name.EndsWith(".jpeg") ||
          name.EndsWith(".png") || name.EndsWith(".gif")))
      return;

    auto image = childEntry->LoadImage();
    auto button = new wxButton(gridPanel, wxID_ANY);
    button->Bind(wxEVT_BUTTON, &MainFrame::OnImageButtonClick, this);

    int longerSide = image.GetWidth() > image.GetHeight() ? image.GetWidth()
                                                          : image.GetHeight();
    int width = 200 * image.GetWidth() / longerSide;
    int height = 200 * image.GetHeight() / longerSide;
    auto thumbnailImage = image.Scale(width, height, wxIMAGE_QUALITY_HIGH);

    button->SetBitmap(thumbnailImage, wxBOTTOM);
    button->SetClientObject(new EntryItemData(childEntry));
    button->SetMinSize({250, 250});

    auto btnSizer = new wxBoxSizer(wxVERTICAL);
    btnSizer->Add(button, 0, wxEXPAND);
    btnSizer->Add(new wxStaticText(gridPanel, wxID_ANY, childEntry->Name()));

    grid->Add(btnSizer, 0, wxALL | wxEXPAND, 5);
    progressDlg.Pulse();
  }

  grid->FitInside(gridPanel);
  gridPanel->Show(true);
  gridPanel->Scroll(0, 0);
  progressDlg.Update(100);
}

void MainFrame::OnImageButtonClick(wxCommandEvent &event) {
  auto button = dynamic_cast<wxButton *>(event.GetEventObject());
  auto clientData =
      dynamic_cast<wxStringClientData *>(button->GetClientObject());

  auto page = notebook->GetPageCount();
  auto childEntry =
      dynamic_cast<EntryItemData *>(button->GetClientObject())->Get();
  auto bitmapCtl = new ImageViewPanel(notebook, childEntry->LoadImage());
  notebook->AddPage(bitmapCtl, childEntry->Name());
  notebook->SetSelection(page);
}

void MainFrame::OnGridPanelSize(wxSizeEvent &event) {
  auto grid = dynamic_cast<wxGridSizer *>(splitter->GetWindow2()->GetSizer());
  auto size = event.GetSize();
  int col = (size.GetWidth() / 250);
  grid->SetCols(col > 0 ? col : 1);

  grid->FitInside(splitter->GetWindow2());
}

void MainFrame::OnOnTopChecked(wxCommandEvent &event) {
  auto style = GetWindowStyle();

  if (onTopChk->IsChecked()) {
    style += wxSTAY_ON_TOP;
  } else {
    style -= wxSTAY_ON_TOP;
  }
  SetWindowStyle(style);
}

void MainFrame::OnDirBrowsePressed(wxCommandEvent &event) {
  wxDirDialog dlg(NULL, "Choose directory", "",
                  wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
  if (dlg.ShowModal() == wxID_CANCEL)
    return;
  auto oldEntry = entry;
  auto path = dlg.GetPath() + wxFileName::GetPathSeparator();

  wxFileName filename(path);
  auto entry = FileEntry::Create(filename);
  SetEntry(entry);
  currentFileCtrl->SetLabelText(filename.GetFullPath());
}

void MainFrame::OnZipBrowsePressed(wxCommandEvent &event) {
  wxFileDialog dialog(this, _("Open ZIP file"), "", "",
                      "ZIP files (*.zip)|*.zip",
                      wxFD_OPEN | wxFD_FILE_MUST_EXIST);
  if (dialog.ShowModal() == wxID_CANCEL)
    return;

  auto path = dialog.GetPath();
  wxFileName filename(path);

  int error;
  auto zipFile = zip_open(path, ZIP_RDONLY, &error);

  if (zipFile == nullptr) {
    throw error;
  }

  auto entry = ZipEntry::Create(zipFile);
  SetEntry(entry);
  currentFileCtrl->SetLabelText(filename.GetFullPath());
}

void MainFrame::SetEntry(Entry *entry) {
  auto oldEntry = MainFrame::entry;
  MainFrame::entry = entry;

  dirTree->UnselectAll();
  dirTree->DeleteAllItems();

  BuildDirectoryTree();

  dirTree->SelectItem(dirTree->GetRootItem());
  dirTree->ExpandAll();

  if (oldEntry) {
    delete oldEntry;
  }
}
<commit_msg>Unicode filename handling (almost) properly.<commit_after>#include "MainFrame.h"
#include <algorithm>
#include <wx/log.h>
#include <wx/mstream.h>
#include <wx/button.h>
#include "ImageViewPanel.h"
#include "ZipEntry.h"
#include "FileEntry.h"

enum MainFrameIds { ID_DIRECTORY_TREE = 1, ID_IMAGE_BUTTON };

MainFrame::MainFrame() : wxFrame(NULL, wxID_ANY, "ZipPicView") {
  auto statusBar = CreateStatusBar();
  SetStatusText("Welcome to ZipPicView!");

  auto outerSizer = new wxBoxSizer(wxVERTICAL);
  auto toolSizer = new wxBoxSizer(wxHORIZONTAL);
  onTopChk = new wxCheckBox(this, wxID_ANY, "On Top");
  onTopChk->Bind(wxEVT_CHECKBOX, &MainFrame::OnOnTopChecked, this);
  notebook = new wxNotebook(this, wxID_ANY);

  currentFileCtrl =
      new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
                     wxDefaultSize, wxTE_READONLY);
  dirBrowseBtn = new wxButton(this, wxID_ANY, "Directory...");
  dirBrowseBtn->Bind(wxEVT_BUTTON, &MainFrame::OnDirBrowsePressed, this);
  zipBrowseBtn = new wxButton(this, wxID_ANY, "Zip...");
  zipBrowseBtn->Bind(wxEVT_BUTTON, &MainFrame::OnZipBrowsePressed, this);

  toolSizer->Add(currentFileCtrl, 1, wxEXPAND | wxALL);
  toolSizer->Add(dirBrowseBtn, 0, wxEXPAND | wxALL);
  toolSizer->Add(zipBrowseBtn, 0, wxEXPAND | wxALL);
  toolSizer->Add(onTopChk, 0, wxEXPAND | wxALL);

  outerSizer->Add(toolSizer, 0, wxEXPAND | wxALL, 5);
  outerSizer->Add(notebook, 1, wxEXPAND | wxALL, 5);

  splitter = new wxSplitterWindow(notebook, wxID_ANY);
  dirTree = new wxTreeCtrl(splitter, ID_DIRECTORY_TREE, wxDefaultPosition,
                           wxDefaultSize, wxTR_SINGLE | wxTR_NO_LINES |
                                              wxTR_FULL_ROW_HIGHLIGHT);
  dirTree->Bind(wxEVT_TREE_SEL_CHANGED, &MainFrame::OnTreeSelectionChanged,
                this, ID_DIRECTORY_TREE);
  dirTree->Bind(wxEVT_TREE_ITEM_COLLAPSING,
                [=](wxTreeEvent &event) { event.Veto(); }, ID_DIRECTORY_TREE);
  dirTree->SetMinSize({250, 250});

  auto rightWindow = new wxScrolledWindow(splitter, wxID_ANY);
  auto grid = new wxGridSizer(5);
  rightWindow->SetSizer(grid);
  rightWindow->SetScrollRate(10, 10);
  rightWindow->SetMinSize({250, 250});
  rightWindow->Bind(wxEVT_SIZE, &MainFrame::OnGridPanelSize, this);
  splitter->SplitVertically(dirTree, rightWindow, 250);

  notebook->AddPage(splitter, "Browse");

  SetMinSize({640, 480});
  SetSizer(outerSizer);
}

void MainFrame::BuildDirectoryTree() {
  auto root = dirTree->AddRoot(entry->Name(), -1, -1, new EntryItemData(entry));
  AddTreeItemsFromEntry(root, entry);
}

void MainFrame::AddTreeItemsFromEntry(const wxTreeItemId &itemId,
                                      Entry *entry) {
  for (auto childEntry : *entry) {
    if (!childEntry->IsDirectory())
      return;

    auto child = dirTree->AppendItem(itemId, childEntry->Name(), -1, -1,
                                     new EntryItemData(childEntry));

    AddTreeItemsFromEntry(child, childEntry);
  }
}

void MainFrame::OnTreeSelectionChanged(wxTreeEvent &event) {
  wxProgressDialog progressDlg("Loading", "Please Wait");

  auto treeItemId = event.GetItem();
  auto rootId = dirTree->GetRootItem();
  auto currentFileEntry =
      dynamic_cast<EntryItemData *>(dirTree->GetItemData(treeItemId))->Get();

  progressDlg.Pulse();
  auto gridPanel = dynamic_cast<wxScrolledWindow *>(splitter->GetWindow2());
  gridPanel->Show(false);
  auto grid = gridPanel->GetSizer();
  grid->Clear(true);

  for (auto childEntry : *currentFileEntry) {
    if (childEntry->IsDirectory())
      return;

    auto name = childEntry->Name();
    if (!(name.EndsWith(".jpg") || name.EndsWith(".jpeg") ||
          name.EndsWith(".png") || name.EndsWith(".gif")))
      return;

    auto image = childEntry->LoadImage();
    auto button = new wxButton(gridPanel, wxID_ANY);
    button->Bind(wxEVT_BUTTON, &MainFrame::OnImageButtonClick, this);

    int longerSide = image.GetWidth() > image.GetHeight() ? image.GetWidth()
                                                          : image.GetHeight();
    int width = 200 * image.GetWidth() / longerSide;
    int height = 200 * image.GetHeight() / longerSide;
    auto thumbnailImage = image.Scale(width, height, wxIMAGE_QUALITY_HIGH);

    button->SetBitmap(thumbnailImage, wxBOTTOM);
    button->SetClientObject(new EntryItemData(childEntry));
    button->SetMinSize({250, 250});

    auto btnSizer = new wxBoxSizer(wxVERTICAL);
    btnSizer->Add(button, 0, wxEXPAND);
    btnSizer->Add(new wxStaticText(gridPanel, wxID_ANY, childEntry->Name()));

    grid->Add(btnSizer, 0, wxALL | wxEXPAND, 5);
    progressDlg.Pulse();
  }

  grid->FitInside(gridPanel);
  gridPanel->Show(true);
  gridPanel->Scroll(0, 0);
  progressDlg.Update(100);
}

void MainFrame::OnImageButtonClick(wxCommandEvent &event) {
  auto button = dynamic_cast<wxButton *>(event.GetEventObject());
  auto clientData =
      dynamic_cast<wxStringClientData *>(button->GetClientObject());

  auto page = notebook->GetPageCount();
  auto childEntry =
      dynamic_cast<EntryItemData *>(button->GetClientObject())->Get();
  auto bitmapCtl = new ImageViewPanel(notebook, childEntry->LoadImage());
  notebook->AddPage(bitmapCtl, childEntry->Name());
  notebook->SetSelection(page);
}

void MainFrame::OnGridPanelSize(wxSizeEvent &event) {
  auto grid = dynamic_cast<wxGridSizer *>(splitter->GetWindow2()->GetSizer());
  auto size = event.GetSize();
  int col = (size.GetWidth() / 250);
  grid->SetCols(col > 0 ? col : 1);

  grid->FitInside(splitter->GetWindow2());
}

void MainFrame::OnOnTopChecked(wxCommandEvent &event) {
  auto style = GetWindowStyle();

  if (onTopChk->IsChecked()) {
    style += wxSTAY_ON_TOP;
  } else {
    style -= wxSTAY_ON_TOP;
  }
  SetWindowStyle(style);
}

void MainFrame::OnDirBrowsePressed(wxCommandEvent &event) {
  wxDirDialog dlg(NULL, "Choose directory", "",
                  wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
  if (dlg.ShowModal() == wxID_CANCEL)
    return;
  auto oldEntry = entry;
  auto path = dlg.GetPath() + wxFileName::GetPathSeparator();

  wxFileName filename(path);
  auto entry = FileEntry::Create(filename);
  SetEntry(entry);
  currentFileCtrl->SetLabelText(filename.GetFullPath());
}

void MainFrame::OnZipBrowsePressed(wxCommandEvent &event) {
  wxFileDialog dialog(this, _("Open ZIP file"), "", "",
                      "ZIP files (*.zip)|*.zip",
                      wxFD_OPEN | wxFD_FILE_MUST_EXIST);
  if (dialog.ShowModal() == wxID_CANCEL)
    return;

  auto path = dialog.GetPath();
  wxFileName filename(path);
  wxFile file(path);

  int error;
  auto zipFile = zip_fdopen(file.fd(), ZIP_RDONLY, &error);
  // auto zipFile = zip_open(path.ToUTF8(), ZIP_RDONLY, &error);

  if (zipFile == nullptr) {
    throw error;
  }

  auto entry = ZipEntry::Create(zipFile);
  SetEntry(entry);
  currentFileCtrl->SetLabelText(filename.GetFullPath());
}

void MainFrame::SetEntry(Entry *entry) {
  auto oldEntry = MainFrame::entry;
  MainFrame::entry = entry;

  dirTree->UnselectAll();
  dirTree->DeleteAllItems();

  BuildDirectoryTree();

  dirTree->SelectItem(dirTree->GetRootItem());
  dirTree->ExpandAll();

  if (oldEntry) {
    delete oldEntry;
  }
}
<|endoftext|>


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

// Standard C++ library includes

// 3rd party library includes
#include <SDL.h>

// FIFE includes
// These includes are split up in two parts, separated by one empty line
// First block: files included from the FIFE root src directory
// Second block: files included from the same folder
#include "util/structures/rect.h"
#include "util/time/timemanager.h"
#include "util/log/logger.h"
#include "video/imagemanager.h"

#include "animation.h"
#include "image.h"
#include "renderbackend.h"
#include "cursor.h"

namespace FIFE {
	/** Logger to use for this source file.
	 *  @relates Logger
	 */
	static Logger _log(LM_CURSOR);

	Cursor::Cursor(RenderBackend* renderbackend):
		m_cursor_id(NC_ARROW),
		m_cursor_type(CURSOR_NATIVE),
		m_drag_type(CURSOR_NONE),
		m_native_cursor(NULL),
		m_renderbackend(renderbackend),
		m_animtime(0),
		m_drag_animtime(0),
		m_drag_offset_x(0),
		m_drag_offset_y(0),
		m_mx(0),
		m_my(0),
		m_timemanager(TimeManager::instance()),
		m_invalidated(false),
		m_native_image_cursor_enabled(false) {
		assert(m_timemanager);
		set(m_cursor_id);
	}

	void Cursor::set(uint32_t cursor_id) {
		m_cursor_type = CURSOR_NATIVE;

		if (!SDL_ShowCursor(1)) {
			SDL_PumpEvents();
		}
		setNativeCursor(cursor_id);

		m_cursor_image.reset();
		m_cursor_animation.reset();
	}

	void Cursor::set(ImagePtr image) {
		assert(image != 0);

		m_cursor_image = image;
		m_cursor_type = CURSOR_IMAGE;

		if (m_native_image_cursor_enabled) {
			setNativeImageCursor(image);
			if (!SDL_ShowCursor(1)) {
				SDL_PumpEvents();
			}
		}
		else if (SDL_ShowCursor(0)) {
			SDL_PumpEvents();
		}

		m_cursor_id = NC_ARROW;
		m_cursor_animation.reset();
	}

	void Cursor::set(AnimationPtr anim) {
		assert(anim != 0);

		m_cursor_animation = anim;
		m_cursor_type = CURSOR_ANIMATION;

		if (m_native_image_cursor_enabled) {
			setNativeImageCursor(anim->getFrameByTimestamp(0));
			if (!SDL_ShowCursor(1)) {
				SDL_PumpEvents();
			}
		}
		else if (SDL_ShowCursor(0)) {
			SDL_PumpEvents();
		}
		m_animtime = m_timemanager->getTime();

		m_cursor_id = NC_ARROW;
		m_cursor_image.reset();
	}

	void Cursor::setDrag(ImagePtr image, int32_t drag_offset_x, int32_t drag_offset_y) {
		assert(image != 0);

		m_cursor_drag_image = image;
		m_drag_type = CURSOR_IMAGE;
		m_drag_offset_x = drag_offset_x;
		m_drag_offset_y = drag_offset_y;

		m_cursor_drag_animation.reset();
	}

	void Cursor::setDrag(AnimationPtr anim, int32_t drag_offset_x, int32_t drag_offset_y) {
		assert(anim != 0);

		m_cursor_drag_animation = anim;
		m_drag_type = CURSOR_ANIMATION;
		m_drag_offset_x = drag_offset_x;
		m_drag_offset_y = drag_offset_y;

		m_drag_animtime = m_timemanager->getTime();

		m_cursor_drag_image.reset();
	}

	void Cursor::resetDrag() {
		m_drag_type = CURSOR_NONE;

		m_drag_animtime = 0;
		m_drag_offset_x = 0;
		m_drag_offset_y = 0;

		m_cursor_drag_animation.reset();
		m_cursor_drag_image.reset();
	}

    void Cursor::setPosition(uint32_t x, uint32_t y) {
		m_mx = x;
		m_my = y;
		SDL_WarpMouseInWindow(RenderBackend::instance()->getWindow(), m_mx, m_my);
	}

    void Cursor::getPosition(int32_t* x, int32_t* y) {
        *x = m_mx;
        *y = m_my;
    }

	void Cursor::invalidate() {
		if (m_native_cursor != NULL) {
			SDL_FreeCursor(m_native_cursor);
			m_native_cursor = NULL;
			m_native_cursor_image.reset();

			m_invalidated = true;
		}
	}

	void Cursor::draw() {
		if (m_invalidated) {
			if (m_cursor_type == CURSOR_NATIVE ) {
				set(m_cursor_id);
			}
			else if (m_native_image_cursor_enabled) {
				if (m_cursor_type == CURSOR_IMAGE ) {
					set(m_cursor_image);
				}
				else if (m_cursor_type == CURSOR_ANIMATION ) {
					set(m_cursor_animation);
				}
			}

			m_invalidated = false;
		}

		SDL_GetMouseState(&m_mx, &m_my);
		if ((m_cursor_type == CURSOR_NATIVE) && (m_drag_type == CURSOR_NONE)) {
			return;
		}

		// render possible drag image
		ImagePtr img;
		if (m_drag_type == CURSOR_IMAGE) {
			img = m_cursor_drag_image;
		}
		else if (m_drag_type == CURSOR_ANIMATION) {
			int32_t animtime = (m_timemanager->getTime() - m_drag_animtime) % m_cursor_drag_animation->getDuration();
			img = m_cursor_drag_animation->getFrameByTimestamp(animtime);
		}

		if (img != 0) {
			Rect area(m_mx + m_drag_offset_x + img->getXShift(), m_my + m_drag_offset_y + img->getYShift(), img->getWidth(), img->getHeight());
			m_renderbackend->pushClipArea(area, false);
			img->render(area);
			m_renderbackend->renderVertexArrays();
			m_renderbackend->popClipArea();
		}

		ImagePtr img2;
		// render possible cursor image
		if (m_cursor_type == CURSOR_IMAGE) {
			img2 = m_cursor_image;
		}
		else if (m_cursor_type == CURSOR_ANIMATION) {
			int32_t animtime = (m_timemanager->getTime() - m_animtime) % m_cursor_animation->getDuration();
			img2 = m_cursor_animation->getFrameByTimestamp(animtime);
		}

		if (img2 != 0) {
			if (m_native_image_cursor_enabled) {
				setNativeImageCursor(img2);
			} else {
				Rect area(m_mx + img2->getXShift(), m_my + img2->getYShift(), img2->getWidth(), img2->getHeight());
				m_renderbackend->pushClipArea(area, false);
				img2->render(area);
				m_renderbackend->renderVertexArrays();
				m_renderbackend->popClipArea();
			}
		}
	}

	uint32_t Cursor::getNativeId(uint32_t cursor_id) {
		switch (cursor_id) {
			case NC_ARROW:
				return SDL_SYSTEM_CURSOR_ARROW;
			case NC_IBEAM:
				return SDL_SYSTEM_CURSOR_IBEAM;
			case NC_WAIT:
				return SDL_SYSTEM_CURSOR_WAIT;
			case NC_CROSS:
				return SDL_SYSTEM_CURSOR_CROSSHAIR;
			case NC_WAITARROW:
				return SDL_SYSTEM_CURSOR_WAITARROW;
			case NC_RESIZENWSE:
				return SDL_SYSTEM_CURSOR_SIZENWSE;
			case NC_RESIZENESW:
				return SDL_SYSTEM_CURSOR_SIZENESW;
			case NC_RESIZEWE:
				return SDL_SYSTEM_CURSOR_SIZEWE;
			case NC_RESIZENS:
				return SDL_SYSTEM_CURSOR_SIZENS;
			case NC_RESIZEALL:
				return SDL_SYSTEM_CURSOR_SIZEALL;
			case NC_NO:
				return SDL_SYSTEM_CURSOR_NO;
			case NC_HAND:
				return SDL_SYSTEM_CURSOR_HAND;
		}
		return cursor_id;
	}

	void Cursor::setNativeCursor(uint32_t cursor_id) {
		cursor_id = getNativeId(cursor_id);
		SDL_Cursor* cursor = SDL_CreateSystemCursor(static_cast<SDL_SystemCursor>(cursor_id));
		if (!cursor) {
			FL_WARN(_log, "No cursor matching cursor_id was found.");
			return;
		}
		SDL_SetCursor(cursor);
		if (m_native_cursor != NULL) {
			SDL_FreeCursor(m_native_cursor);
		}
		m_native_cursor = cursor;
	}

	void Cursor::setNativeImageCursor(ImagePtr image) {
		if (image == m_native_cursor_image) {
			return;
		}

		ImagePtr temp_image = image;
		if (image->isSharedImage()) {
			temp_image = ImageManager::instance()->create();
			temp_image->copySubimage(0, 0, image);
		}

		SDL_Cursor* cursor = SDL_CreateColorCursor(temp_image->getSurface(), -image->getXShift(), -image->getYShift());
		if (cursor == NULL) {
			FL_WARN(_log, LMsg("SDL_CreateColorCursor: \"") << SDL_GetError();
			if (image->isSharedImage()) {
				ImageManager::instance()->remove(temp_image);
			}
			return;
		}
		SDL_SetCursor(cursor);
		m_native_cursor_image = image;

		if (image->isSharedImage()) {
			ImageManager::instance()->remove(temp_image);
		}
		if (m_native_cursor != NULL) {
			SDL_FreeCursor(m_native_cursor);
		}
		m_native_cursor = cursor;
	}

	void Cursor::setNativeImageCursorEnabled(bool native_image_cursor_enabled) {
		if (m_native_image_cursor_enabled != native_image_cursor_enabled) {
			m_native_image_cursor_enabled = native_image_cursor_enabled;
			if (m_cursor_type == CURSOR_IMAGE ) {
				set(m_cursor_image);
			}
			else if (m_cursor_type == CURSOR_ANIMATION ) {
				set(m_cursor_animation);
			}
		}
	}

	bool Cursor::isNativeImageCursorEnabled() const {
		return m_native_image_cursor_enabled;
	}
}
<commit_msg>Fall back to software cursor if SDL_CreateColorCursor() fails<commit_after>/***************************************************************************
 *   Copyright (C) 2005-2017 by the FIFE team                              *
 *   http://www.fifengine.net                                              *
 *   This file is part of FIFE.                                            *
 *                                                                         *
 *   FIFE is free software; you can redistribute it and/or                 *
 *   modify it under the terms of the GNU Lesser General Public            *
 *   License as published by the Free Software Foundation; either          *
 *   version 2.1 of the License, or (at your option) any later version.    *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
 ***************************************************************************/

// Standard C++ library includes

// 3rd party library includes
#include <SDL.h>

// FIFE includes
// These includes are split up in two parts, separated by one empty line
// First block: files included from the FIFE root src directory
// Second block: files included from the same folder
#include "util/structures/rect.h"
#include "util/time/timemanager.h"
#include "util/log/logger.h"
#include "video/imagemanager.h"

#include "animation.h"
#include "image.h"
#include "renderbackend.h"
#include "cursor.h"

namespace FIFE {
	/** Logger to use for this source file.
	 *  @relates Logger
	 */
	static Logger _log(LM_CURSOR);

	Cursor::Cursor(RenderBackend* renderbackend):
		m_cursor_id(NC_ARROW),
		m_cursor_type(CURSOR_NATIVE),
		m_drag_type(CURSOR_NONE),
		m_native_cursor(NULL),
		m_renderbackend(renderbackend),
		m_animtime(0),
		m_drag_animtime(0),
		m_drag_offset_x(0),
		m_drag_offset_y(0),
		m_mx(0),
		m_my(0),
		m_timemanager(TimeManager::instance()),
		m_invalidated(false),
		m_native_image_cursor_enabled(false) {
		assert(m_timemanager);
		set(m_cursor_id);
	}

	void Cursor::set(uint32_t cursor_id) {
		m_cursor_type = CURSOR_NATIVE;

		if (!SDL_ShowCursor(1)) {
			SDL_PumpEvents();
		}
		setNativeCursor(cursor_id);

		m_cursor_image.reset();
		m_cursor_animation.reset();
	}

	void Cursor::set(ImagePtr image) {
		assert(image != 0);

		m_cursor_image = image;
		m_cursor_type = CURSOR_IMAGE;

		if (m_native_image_cursor_enabled) {
			setNativeImageCursor(image);
			if (!SDL_ShowCursor(1)) {
				SDL_PumpEvents();
			}
		}
		else if (SDL_ShowCursor(0)) {
			SDL_PumpEvents();
		}

		m_cursor_id = NC_ARROW;
		m_cursor_animation.reset();
	}

	void Cursor::set(AnimationPtr anim) {
		assert(anim != 0);

		m_cursor_animation = anim;
		m_cursor_type = CURSOR_ANIMATION;

		if (m_native_image_cursor_enabled) {
			setNativeImageCursor(anim->getFrameByTimestamp(0));
			if (!SDL_ShowCursor(1)) {
				SDL_PumpEvents();
			}
		}
		else if (SDL_ShowCursor(0)) {
			SDL_PumpEvents();
		}
		m_animtime = m_timemanager->getTime();

		m_cursor_id = NC_ARROW;
		m_cursor_image.reset();
	}

	void Cursor::setDrag(ImagePtr image, int32_t drag_offset_x, int32_t drag_offset_y) {
		assert(image != 0);

		m_cursor_drag_image = image;
		m_drag_type = CURSOR_IMAGE;
		m_drag_offset_x = drag_offset_x;
		m_drag_offset_y = drag_offset_y;

		m_cursor_drag_animation.reset();
	}

	void Cursor::setDrag(AnimationPtr anim, int32_t drag_offset_x, int32_t drag_offset_y) {
		assert(anim != 0);

		m_cursor_drag_animation = anim;
		m_drag_type = CURSOR_ANIMATION;
		m_drag_offset_x = drag_offset_x;
		m_drag_offset_y = drag_offset_y;

		m_drag_animtime = m_timemanager->getTime();

		m_cursor_drag_image.reset();
	}

	void Cursor::resetDrag() {
		m_drag_type = CURSOR_NONE;

		m_drag_animtime = 0;
		m_drag_offset_x = 0;
		m_drag_offset_y = 0;

		m_cursor_drag_animation.reset();
		m_cursor_drag_image.reset();
	}

    void Cursor::setPosition(uint32_t x, uint32_t y) {
		m_mx = x;
		m_my = y;
		SDL_WarpMouseInWindow(RenderBackend::instance()->getWindow(), m_mx, m_my);
	}

    void Cursor::getPosition(int32_t* x, int32_t* y) {
        *x = m_mx;
        *y = m_my;
    }

	void Cursor::invalidate() {
		if (m_native_cursor != NULL) {
			SDL_FreeCursor(m_native_cursor);
			m_native_cursor = NULL;
			m_native_cursor_image.reset();

			m_invalidated = true;
		}
	}

	void Cursor::draw() {
		if (m_invalidated) {
			if (m_cursor_type == CURSOR_NATIVE ) {
				set(m_cursor_id);
			}
			else if (m_native_image_cursor_enabled) {
				if (m_cursor_type == CURSOR_IMAGE ) {
					set(m_cursor_image);
				}
				else if (m_cursor_type == CURSOR_ANIMATION ) {
					set(m_cursor_animation);
				}
			}

			m_invalidated = false;
		}

		SDL_GetMouseState(&m_mx, &m_my);
		if ((m_cursor_type == CURSOR_NATIVE) && (m_drag_type == CURSOR_NONE)) {
			return;
		}

		// render possible drag image
		ImagePtr img;
		if (m_drag_type == CURSOR_IMAGE) {
			img = m_cursor_drag_image;
		}
		else if (m_drag_type == CURSOR_ANIMATION) {
			int32_t animtime = (m_timemanager->getTime() - m_drag_animtime) % m_cursor_drag_animation->getDuration();
			img = m_cursor_drag_animation->getFrameByTimestamp(animtime);
		}

		if (img != 0) {
			Rect area(m_mx + m_drag_offset_x + img->getXShift(), m_my + m_drag_offset_y + img->getYShift(), img->getWidth(), img->getHeight());
			m_renderbackend->pushClipArea(area, false);
			img->render(area);
			m_renderbackend->renderVertexArrays();
			m_renderbackend->popClipArea();
		}

		ImagePtr img2;
		// render possible cursor image
		if (m_cursor_type == CURSOR_IMAGE) {
			img2 = m_cursor_image;
		}
		else if (m_cursor_type == CURSOR_ANIMATION) {
			int32_t animtime = (m_timemanager->getTime() - m_animtime) % m_cursor_animation->getDuration();
			img2 = m_cursor_animation->getFrameByTimestamp(animtime);
		}

		if (img2 != 0) {
			if (m_native_image_cursor_enabled) {
				setNativeImageCursor(img2);
			} else {
				Rect area(m_mx + img2->getXShift(), m_my + img2->getYShift(), img2->getWidth(), img2->getHeight());
				m_renderbackend->pushClipArea(area, false);
				img2->render(area);
				m_renderbackend->renderVertexArrays();
				m_renderbackend->popClipArea();
			}
		}
	}

	uint32_t Cursor::getNativeId(uint32_t cursor_id) {
		switch (cursor_id) {
			case NC_ARROW:
				return SDL_SYSTEM_CURSOR_ARROW;
			case NC_IBEAM:
				return SDL_SYSTEM_CURSOR_IBEAM;
			case NC_WAIT:
				return SDL_SYSTEM_CURSOR_WAIT;
			case NC_CROSS:
				return SDL_SYSTEM_CURSOR_CROSSHAIR;
			case NC_WAITARROW:
				return SDL_SYSTEM_CURSOR_WAITARROW;
			case NC_RESIZENWSE:
				return SDL_SYSTEM_CURSOR_SIZENWSE;
			case NC_RESIZENESW:
				return SDL_SYSTEM_CURSOR_SIZENESW;
			case NC_RESIZEWE:
				return SDL_SYSTEM_CURSOR_SIZEWE;
			case NC_RESIZENS:
				return SDL_SYSTEM_CURSOR_SIZENS;
			case NC_RESIZEALL:
				return SDL_SYSTEM_CURSOR_SIZEALL;
			case NC_NO:
				return SDL_SYSTEM_CURSOR_NO;
			case NC_HAND:
				return SDL_SYSTEM_CURSOR_HAND;
		}
		return cursor_id;
	}

	void Cursor::setNativeCursor(uint32_t cursor_id) {
		cursor_id = getNativeId(cursor_id);
		SDL_Cursor* cursor = SDL_CreateSystemCursor(static_cast<SDL_SystemCursor>(cursor_id));
		if (!cursor) {
			FL_WARN(_log, "No cursor matching cursor_id was found.");
			return;
		}
		SDL_SetCursor(cursor);
		if (m_native_cursor != NULL) {
			SDL_FreeCursor(m_native_cursor);
		}
		m_native_cursor = cursor;
	}

	void Cursor::setNativeImageCursor(ImagePtr image) {
		if (image == m_native_cursor_image) {
			return;
		}

		ImagePtr temp_image = image;
		if (image->isSharedImage()) {
			temp_image = ImageManager::instance()->create();
			temp_image->copySubimage(0, 0, image);
		}

		SDL_Cursor* cursor = SDL_CreateColorCursor(temp_image->getSurface(), -image->getXShift(), -image->getYShift());
		if (cursor == NULL) {
			FL_WARN(_log, LMsg("SDL_CreateColorCursor: \"") << SDL_GetError() << "\". Falling back to software cursor.");
			if (image->isSharedImage()) {
				ImageManager::instance()->remove(temp_image);
			}
			setNativeImageCursorEnabled(false);
			return;
		}
		SDL_SetCursor(cursor);
		m_native_cursor_image = image;

		if (image->isSharedImage()) {
			ImageManager::instance()->remove(temp_image);
		}
		if (m_native_cursor != NULL) {
			SDL_FreeCursor(m_native_cursor);
		}
		m_native_cursor = cursor;
	}

	void Cursor::setNativeImageCursorEnabled(bool native_image_cursor_enabled) {
		if (m_native_image_cursor_enabled != native_image_cursor_enabled) {
			m_native_image_cursor_enabled = native_image_cursor_enabled;
			if (m_cursor_type == CURSOR_IMAGE ) {
				set(m_cursor_image);
			}
			else if (m_cursor_type == CURSOR_ANIMATION ) {
				set(m_cursor_animation);
			}
		}
	}

	bool Cursor::isNativeImageCursorEnabled() const {
		return m_native_image_cursor_enabled;
	}
}
<|endoftext|>


<commit_before>//===- BugDriver.cpp - Top-Level BugPoint class implementation ------------===//
//
// This class contains all of the shared state and information that is used by
// the BugPoint tool to track down errors in optimizations.  This class is the
// main driver class that invokes all sub-functionality.
//
//===----------------------------------------------------------------------===//

#include "BugDriver.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Assembly/Parser.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Transforms/Utils/Linker.h"
#include "Support/CommandLine.h"
#include "Support/FileUtilities.h"
#include <memory>

// Anonymous namespace to define command line options for debugging.
//
namespace {
  // Output - The user can specify a file containing the expected output of the
  // program.  If this filename is set, it is used as the reference diff source,
  // otherwise the raw input run through an interpreter is used as the reference
  // source.
  //
  cl::opt<std::string>
  OutputFile("output", cl::desc("Specify a reference program output "
                                "(for miscompilation detection)"));

  enum DebugType { DebugCompile, DebugCodegen };
  cl::opt<DebugType>
  DebugMode("mode", cl::desc("Debug mode for bugpoint:"), cl::Prefix,
            cl::values(clEnumValN(DebugCompile, "compile", "  Compilation"),
                       clEnumValN(DebugCodegen, "codegen", "  Code generation"),
                       0),
            cl::init(DebugCompile));
}

/// getPassesString - Turn a list of passes into a string which indicates the
/// command line options that must be passed to add the passes.
///
std::string getPassesString(const std::vector<const PassInfo*> &Passes) {
  std::string Result;
  for (unsigned i = 0, e = Passes.size(); i != e; ++i) {
    if (i) Result += " ";
    Result += "-";
    Result += Passes[i]->getPassArgument();
  }
  return Result;
}

// DeleteFunctionBody - "Remove" the function by deleting all of its basic
// blocks, making it external.
//
void DeleteFunctionBody(Function *F) {
  // delete the body of the function...
  F->deleteBody();
  assert(F->isExternal() && "This didn't make the function external!");
}

BugDriver::BugDriver(const char *toolname)
  : ToolName(toolname), ReferenceOutputFile(OutputFile),
    Program(0), Interpreter(0), cbe(0), gcc(0) {}

/// ParseInputFile - Given a bytecode or assembly input filename, parse and
/// return it, or return null if not possible.
///
Module *BugDriver::ParseInputFile(const std::string &InputFilename) const {
  Module *Result = 0;
  try {
    Result = ParseBytecodeFile(InputFilename);
    if (!Result && !(Result = ParseAssemblyFile(InputFilename))){
      std::cerr << ToolName << ": could not read input file '"
                << InputFilename << "'!\n";
    }
  } catch (const ParseException &E) {
    std::cerr << ToolName << ": " << E.getMessage() << "\n";
    Result = 0;
  }
  return Result;
}

// This method takes the specified list of LLVM input files, attempts to load
// them, either as assembly or bytecode, then link them together. It returns
// true on failure (if, for example, an input bytecode file could not be
// parsed), and false on success.
//
bool BugDriver::addSources(const std::vector<std::string> &Filenames) {
  assert(Program == 0 && "Cannot call addSources multiple times!");
  assert(!Filenames.empty() && "Must specify at least on input filename!");

  // Load the first input file...
  Program = ParseInputFile(Filenames[0]);
  if (Program == 0) return true;
  std::cout << "Read input file      : '" << Filenames[0] << "'\n";

  for (unsigned i = 1, e = Filenames.size(); i != e; ++i) {
    std::auto_ptr<Module> M(ParseInputFile(Filenames[i]));
    if (M.get() == 0) return true;

    std::cout << "Linking in input file: '" << Filenames[i] << "'\n";
    std::string ErrorMessage;
    if (LinkModules(Program, M.get(), &ErrorMessage)) {
      std::cerr << ToolName << ": error linking in '" << Filenames[i] << "': "
                << ErrorMessage << "\n";
      return true;
    }
  }

  std::cout << "*** All input ok\n";

  // All input files read successfully!
  return false;
}

/// run - The top level method that is invoked after all of the instance
/// variables are set up from command line arguments.
///
bool BugDriver::run() {
  // The first thing that we must do is determine what the problem is.  Does the
  // optimization series crash the compiler, or does it produce illegal code? We
  // make the top-level decision by trying to run all of the passes on the the
  // input program, which should generate a bytecode file.  If it does generate
  // a bytecode file, then we know the compiler didn't crash, so try to diagnose
  // a miscompilation.
  //
  std::cout << "Running selected passes on program to test for crash: ";
  if (runPasses(PassesToRun))
    return debugCrash();

  std::cout << "Checking for a miscompilation...\n";

  // Set up the execution environment, selecting a method to run LLVM bytecode.
  if (initializeExecutionEnvironment()) return true;

  // Run the raw input to see where we are coming from.  If a reference output
  // was specified, make sure that the raw output matches it.  If not, it's a
  // problem in the front-end or the code generator.
  //
  bool CreatedOutput = false;
  if (ReferenceOutputFile.empty()) {
    std::cout << "Generating reference output from raw program...";
    if (DebugCodegen) {
      ReferenceOutputFile = executeProgramWithCBE("bugpoint.reference.out");
    } else {
      ReferenceOutputFile = executeProgram("bugpoint.reference.out");
    }
    CreatedOutput = true;
    std::cout << "Reference output is: " << ReferenceOutputFile << "\n";
  }

  bool Result;
  switch (DebugMode) {
  default: assert(0 && "Bad value for DebugMode!");
  case DebugCompile:
    std::cout << "\n*** Debugging miscompilation!\n";
    Result = debugMiscompilation();
    break;
  case DebugCodegen:
    std::cout << "Debugging code generator problem!\n";
    Result = debugCodeGenerator();
  }

  if (CreatedOutput) removeFile(ReferenceOutputFile);
  return Result;
}

void BugDriver::PrintFunctionList(const std::vector<Function*> &Funcs)
{
  for (unsigned i = 0, e = Funcs.size(); i != e; ++i) {
    if (i) std::cout << ", ";
    std::cout << Funcs[i]->getName();
  }
}
<commit_msg>Unbreak code generator debug mode<commit_after>//===- BugDriver.cpp - Top-Level BugPoint class implementation ------------===//
//
// This class contains all of the shared state and information that is used by
// the BugPoint tool to track down errors in optimizations.  This class is the
// main driver class that invokes all sub-functionality.
//
//===----------------------------------------------------------------------===//

#include "BugDriver.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Assembly/Parser.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Transforms/Utils/Linker.h"
#include "Support/CommandLine.h"
#include "Support/FileUtilities.h"
#include <memory>

// Anonymous namespace to define command line options for debugging.
//
namespace {
  // Output - The user can specify a file containing the expected output of the
  // program.  If this filename is set, it is used as the reference diff source,
  // otherwise the raw input run through an interpreter is used as the reference
  // source.
  //
  cl::opt<std::string>
  OutputFile("output", cl::desc("Specify a reference program output "
                                "(for miscompilation detection)"));

  enum DebugType { DebugCompile, DebugCodegen };
  cl::opt<DebugType>
  DebugMode("mode", cl::desc("Debug mode for bugpoint:"), cl::Prefix,
            cl::values(clEnumValN(DebugCompile, "compile", "  Compilation"),
                       clEnumValN(DebugCodegen, "codegen", "  Code generation"),
                       0),
            cl::init(DebugCompile));
}

/// getPassesString - Turn a list of passes into a string which indicates the
/// command line options that must be passed to add the passes.
///
std::string getPassesString(const std::vector<const PassInfo*> &Passes) {
  std::string Result;
  for (unsigned i = 0, e = Passes.size(); i != e; ++i) {
    if (i) Result += " ";
    Result += "-";
    Result += Passes[i]->getPassArgument();
  }
  return Result;
}

// DeleteFunctionBody - "Remove" the function by deleting all of its basic
// blocks, making it external.
//
void DeleteFunctionBody(Function *F) {
  // delete the body of the function...
  F->deleteBody();
  assert(F->isExternal() && "This didn't make the function external!");
}

BugDriver::BugDriver(const char *toolname)
  : ToolName(toolname), ReferenceOutputFile(OutputFile),
    Program(0), Interpreter(0), cbe(0), gcc(0) {}

/// ParseInputFile - Given a bytecode or assembly input filename, parse and
/// return it, or return null if not possible.
///
Module *BugDriver::ParseInputFile(const std::string &InputFilename) const {
  Module *Result = 0;
  try {
    Result = ParseBytecodeFile(InputFilename);
    if (!Result && !(Result = ParseAssemblyFile(InputFilename))){
      std::cerr << ToolName << ": could not read input file '"
                << InputFilename << "'!\n";
    }
  } catch (const ParseException &E) {
    std::cerr << ToolName << ": " << E.getMessage() << "\n";
    Result = 0;
  }
  return Result;
}

// This method takes the specified list of LLVM input files, attempts to load
// them, either as assembly or bytecode, then link them together. It returns
// true on failure (if, for example, an input bytecode file could not be
// parsed), and false on success.
//
bool BugDriver::addSources(const std::vector<std::string> &Filenames) {
  assert(Program == 0 && "Cannot call addSources multiple times!");
  assert(!Filenames.empty() && "Must specify at least on input filename!");

  // Load the first input file...
  Program = ParseInputFile(Filenames[0]);
  if (Program == 0) return true;
  std::cout << "Read input file      : '" << Filenames[0] << "'\n";

  for (unsigned i = 1, e = Filenames.size(); i != e; ++i) {
    std::auto_ptr<Module> M(ParseInputFile(Filenames[i]));
    if (M.get() == 0) return true;

    std::cout << "Linking in input file: '" << Filenames[i] << "'\n";
    std::string ErrorMessage;
    if (LinkModules(Program, M.get(), &ErrorMessage)) {
      std::cerr << ToolName << ": error linking in '" << Filenames[i] << "': "
                << ErrorMessage << "\n";
      return true;
    }
  }

  std::cout << "*** All input ok\n";

  // All input files read successfully!
  return false;
}

/// run - The top level method that is invoked after all of the instance
/// variables are set up from command line arguments.
///
bool BugDriver::run() {
  // The first thing that we must do is determine what the problem is.  Does the
  // optimization series crash the compiler, or does it produce illegal code? We
  // make the top-level decision by trying to run all of the passes on the the
  // input program, which should generate a bytecode file.  If it does generate
  // a bytecode file, then we know the compiler didn't crash, so try to diagnose
  // a miscompilation.
  //
  if (!PassesToRun.empty()) {
    std::cout << "Running selected passes on program to test for crash: ";
    if (runPasses(PassesToRun))
      return debugCrash();
  }

  std::cout << "Checking for a miscompilation...\n";

  // Set up the execution environment, selecting a method to run LLVM bytecode.
  if (initializeExecutionEnvironment()) return true;

  // Run the raw input to see where we are coming from.  If a reference output
  // was specified, make sure that the raw output matches it.  If not, it's a
  // problem in the front-end or the code generator.
  //
  bool CreatedOutput = false;
  if (ReferenceOutputFile.empty()) {
    std::cout << "Generating reference output from raw program...";
    if (DebugCodegen) {
      ReferenceOutputFile = executeProgramWithCBE("bugpoint.reference.out");
    } else {
      ReferenceOutputFile = executeProgram("bugpoint.reference.out");
    }
    CreatedOutput = true;
    std::cout << "Reference output is: " << ReferenceOutputFile << "\n";
  }

  bool Result;
  switch (DebugMode) {
  default: assert(0 && "Bad value for DebugMode!");
  case DebugCompile:
    std::cout << "\n*** Debugging miscompilation!\n";
    Result = debugMiscompilation();
    break;
  case DebugCodegen:
    std::cout << "Debugging code generator problem!\n";
    Result = debugCodeGenerator();
  }

  if (CreatedOutput) removeFile(ReferenceOutputFile);
  return Result;
}

void BugDriver::PrintFunctionList(const std::vector<Function*> &Funcs)
{
  for (unsigned i = 0, e = Funcs.size(); i != e; ++i) {
    if (i) std::cout << ", ";
    std::cout << Funcs[i]->getName();
  }
}
<|endoftext|>


<commit_before>//
// Logarithm.cpp
// Calculator
//
// Created by Gavin Scheele on 3/27/14.
// Copyright (c) 2014 Gavin Scheele. All rights reserved.
//

#include "Logarithm.h"
using namespace std;
#include <string>

//constructor for int base with an int operand
Logarithm::Logarithm(int base, int operand){
    if (operand == 0){
    throw runtime_error("Logarithms of 0 are undefined.");
    }
    if (operand < 0) {
    throw runtime_error("Logarithms of negative numbers are undefined.");
    }
    this->type = "logarithm";
    this->base = base;
    this->operand = operand;
    this->eOperand = new Integer(operand);
    this->eBase = new Integer(base);

}

//constructor for expression base and or expression operand
Logarithm::Logarithm(Expression* eBase, Expression* eOperand){
    this->type = "logarithm";
    this->eBase = eBase;
    this->eOperand = eOperand;

}
//get-set methods below
int Logarithm::getBase(){
	return base;
}
int Logarithm::getOperand(){
	return operand;
}
Expression* Logarithm::getEBase(){
	return eBase;
}
Expression* Logarithm::getEOperand(){
	return eOperand;
}

void Logarithm::setBase(Expression* x){
	this->eBase = x;
}
void Logarithm::setOperand(Expression* x){
	this->eOperand = x;
}

Logarithm::~Logarithm(){
    delete this;
}

Expression* Logarithm::simplifyOperand(){
    Expression* e = this->eOperand;
    e->exp = e->toString();
    string operand1 = e->exp;
    cout<<operand1;
        char asterick = '*';
        char slash = '/';
        vector<int> position;
        vector<char> symbols;
        int length = operand1.length();
        for(int i = 0; i < length; i++)
        {
            if(operand1.at(i)== (asterick) || operand1.at(i)== slash){
                position.push_back(i);
                position.push_back(operand1.at(i));
                cout<<i<<endl;
            }
        }
        string number = "";
        vector<Expression* > logs;
        for(int j =0; j<=position.size();j++){
                int positionofop = position.at(j);
                string number = operand1.substr(j,positionofop-2);
                Solver* s = new Solver();
                Expression* e = s->bindToExpressionType(number);
                Logarithm* simpleLog = (Logarithm*)e;
                simpleLog->simplify();
                logs.push_back(e);

        }

        Expression* endlog = new Integer(0);
         endlog->type = "multiple";
          stringstream endlogexp;
          for(int k = 0; k<logs.size(); k++){
            endlogexp<<*logs.at(k);
            if(k+1 < logs.size()&& symbols.at(k == asterick)){
                endlogexp<< " " << "+" << " ";
            }
            if(k+1 < logs.size()&& symbols.at(k == slash)){
                endlogexp<< " " << "-" << " ";
            }
            }
        endlog->exp = endlogexp.str();
        return endlog;

}
Expression* Logarithm::simplify(){

        if(eOperand->type == "euler")
        {

            if(eBase->type == "euler"){
                Integer* answer = new Integer(1);
                return answer;
            }
            else{
                Logarithm* answer = new Logarithm(eBase, eOperand);
                return answer;
            }

        }

        if(eOperand->type == "pi")
        {
             if(eBase->type == "pi"){
                Integer* answer = new Integer(1);
                return answer;
            }
            else{
                Logarithm* answer = new Logarithm(eBase, eOperand);
                return answer;
            }

        }

       if(eOperand->type == "integer"){
        vector<int> primefactors = primeFactorization(operand);//Create a vector of all the prime factors of the operand
        size_t size1 = primefactors.size();//gets the size of this vector
        vector<Expression *> seperatedLogs(size1);//creates another vector of type expression to save all of the separated Logs has the same size of the number of prime factors

        for(int i = 0 ; i < size1; i++){
            seperatedLogs.at(i) = new Logarithm(this->eBase, new Integer(primefactors.at(i)));//assigns values to each seperatedlog with the same base and operands of the prime factorization
            }

       for(int j= 0; j <size1; j++){
    	if (seperatedLogs.at(j)->type == "logarithm") {//checks to see if the value at seperated log is a log type
            Logarithm* a = (Logarithm *)seperatedLogs.at(j);
            Logarithm* log = new Logarithm(a->getEBase(),a->getEOperand());
            if(log->eBase->type == log->eOperand->type && log->eBase->type == "integer"){ //makes sure the ebase and eoperand are of the same type
                Integer* b = (Integer *)(log->eBase);
                Integer* c = (Integer *)(log->eOperand);
                if (b->getValue() == c->getValue()){// checks to see if the ebase and the eOperand are the same
                    Integer* inte= new Integer(1);//returns one if they are the same
                    seperatedLogs.at(j) = inte;//assigns 1 to the value of seperated log at j

                }
                }
    	}
    	}

       Expression * answer;//creates a new variable called answer
       if(size1 >= 2){// if the size is two or higher
        answer = seperatedLogs.at(0)->add(seperatedLogs.at(1));// add the first two together
       }
       else{//if the size is just 1
        answer = seperatedLogs.at(0);//the answer is the first one
       }

       for(int k = 2; k<size1; k++){
            answer = answer->add(seperatedLogs.at(k));//keeps adding elements of seperated log to answer

       }
       Integer* size2 = new Integer((int)size1);
       Integer* answerint = (Integer *)answer;
       if(answerint->getValue()==size2->getValue())
       {
           return answer;
       }
       else if(size1 == 1){
        return this;
       }
       else
       {
          Expression* e = new Integer(answerint->getValue());
          e->type = "multiple";
          stringstream s;
          for(int l = 0; l<size1; l++){
            s<<*seperatedLogs.at(l);
            if(l+1 < size1){
                s<< " " << "+" << " ";
            }
            }
        e->exp = s.str();
        //cout<<e->exp;
        return e;
       }
       }

       throw runtime_error("invalid entry");
       return this;
}

//creates vector of prime factors of n to be used in the simplify method
vector<int> Logarithm::primeFactorization(int n) {
    int k = 0;
    vector<int> factors;
    while (n%2 == 0) {
        factors.push_back(2);
        n = n/2;
    }
    for (int i = 3; i <= sqrt(n); i = i + 2) {
        while (n%i == 0) {
            factors.push_back(i);
            k++;
            n = n/i;
        }
    }
    if (n > 2) {
        factors.push_back(n);
    }
    return factors;
}

Expression* Logarithm::add(Expression* a){
    return this;
}
Expression* Logarithm::subtract(Expression* a){
    Logarithm* c = this;
    Logarithm* b = (Logarithm *) a;
    if(c->eBase->type == b->eBase->type && c->eOperand->type == b->eOperand->type) {
    	if (c->getEBase() == b->getEBase() && c->getEOperand() == b->getEOperand()){
    		Expression* answer = new Integer(0);
    		return answer;
    	}
    }
    return c;
}

Expression* Logarithm::multiply(Expression* a){
    Logarithm* c = this;
    Logarithm* b = (Logarithm *) a;
    if(c->eBase->type == b->eBase->type && c->eOperand->type == b->eOperand->type) {
    	if (c->getEBase() == b->getEBase() && c->getEOperand() == b->getEOperand()){
    		Exponential* answer = new Exponential(this, new Rational(2,1));
    		return answer;
    	}
    }
   return c;
}
Expression* Logarithm::divide(Expression* a){//this set up is "this" divided by a so if this = log11 and a = log3 it would be log11/log3
    Logarithm* c = this;
    Logarithm* b = (Logarithm *) a;
    if(c->eBase->type == b->eBase->type && c->getEBase() == b->getEBase()) {
        Expression* numeratorOperand = c->getEOperand();
        Expression* denominatorOperand = b->getEOperand();
        Logarithm* answer = new Logarithm(denominatorOperand, numeratorOperand);
        return answer;
    }

    return c;
}
ostream& Logarithm::print(std::ostream& output) const{
    output << "Log_" << *eBase << ":" << *eOperand<< endl;

    return output;
}
string Logarithm::toString(){
    stringstream ss;
    ss << "Log_" << *this->eBase << ":" << *this->eOperand;

    return ss.str();
};
<commit_msg>stuff<commit_after>//
// Logarithm.cpp
// Calculator
//
// Created by Gavin Scheele on 3/27/14.
// Copyright (c) 2014 Gavin Scheele. All rights reserved.
//

#include "Logarithm.h"
using namespace std;
#include <string>

//constructor for int base with an int operand
Logarithm::Logarithm(int base, int operand){
    if (operand == 0){
    throw runtime_error("Logarithms of 0 are undefined.");
    }
    if (operand < 0) {
    throw runtime_error("Logarithms of negative numbers are undefined.");
    }
    this->type = "logarithm";
    this->base = base;
    this->operand = operand;
    this->eOperand = new Integer(operand);
    this->eBase = new Integer(base);

}

//constructor for expression base and or expression operand
Logarithm::Logarithm(Expression* eBase, Expression* eOperand){
    this->type = "logarithm";
    this->eBase = eBase;
    this->eOperand = eOperand;

}
//get-set methods below
int Logarithm::getBase(){
	return base;
}
int Logarithm::getOperand(){
	return operand;
}
Expression* Logarithm::getEBase(){
	return eBase;
}
Expression* Logarithm::getEOperand(){
	return eOperand;
}

void Logarithm::setBase(Expression* x){
	this->eBase = x;
}
void Logarithm::setOperand(Expression* x){
	this->eOperand = x;
}

Logarithm::~Logarithm(){
    delete this;
}

Expression* Logarithm::simplifyOperand(){
    Expression* e = this->eOperand;
    e->exp = e->toString();
    string operand1 = e->exp;
    cout<<operand1;
        char asterick = '*';
        char slash = '/';
        vector<int> position;
        vector<char> symbols;
        int length = operand1.length();
        for(int i = 0; i < length; i++)
        {
            if(operand1.at(i)== (asterick) || operand1.at(i)== slash){
                position.push_back(i);
                position.push_back(operand1.at(i));
                cout<<i<<endl;
            }
        }
        string number = "";
        vector<Expression* > logs;
        for(int j =0; j<=position.size();j++){
                int positionofop = position.at(j);
                string number = operand1.substr(j,positionofop-2);
                Solver* s = new Solver();
                Expression* e = s->bindToExpressionType(number);
                Logarithm* simpleLog = (Logarithm*)e;
                simpleLog->simplify();
                logs.push_back(e);

        }

        Expression* endlog = new Integer(0);
         endlog->type = "multiple";
          stringstream endlogexp;
          for(int k = 0; k<logs.size(); k++){
            endlogexp<<*logs.at(k);
            if(k+1 < logs.size()&& symbols.at(k == asterick)){
                endlogexp<< " " << "+" << " ";
            }
            if(k+1 < logs.size()&& symbols.at(k == slash)){
                endlogexp<< " " << "-" << " ";
            }
            }
        endlog->exp = endlogexp.str();
        return endlog;

}
Expression* Logarithm::simplify(){

        if(eOperand->type == "euler")
        {

            if(eBase->type == "euler"){
                Integer* answer = new Integer(1);
                return answer;
            }
            else{
                Logarithm* answer = new Logarithm(eBase, eOperand);
                return answer;
            }

        }

        if(eOperand->type == "pi")
        {
             if(eBase->type == "pi"){
                Integer* answer = new Integer(1);
                return answer;
            }
            else{
                Logarithm* answer = new Logarithm(eBase, eOperand);
                return answer;
            }

        }

       if(eOperand->type == "integer"){

        vector<int> primefactors = primeFactorization(operand);//Create a vector of all the prime factors of the operand
        size_t size1 = primefactors.size();//gets the size of this vector
        vector<Expression *> seperatedLogs(size1);//creates another vector of type expression to save all of the separated Logs has the same size of the number of prime factors

        for(int i = 0 ; i < size1; i++){
            seperatedLogs.at(i) = new Logarithm(this->eBase, new Integer(primefactors.at(i)));//assigns values to each seperatedlog with the same base and operands of the prime factorization
            }

       for(int j= 0; j <size1; j++){

    	if (seperatedLogs.at(j)->type == "logarithm") {//checks to see if the value at seperated log is a log type
            Logarithm* a = (Logarithm *)seperatedLogs.at(j);
            Logarithm* log = new Logarithm(a->getEBase(),a->getEOperand());
            if(log->eBase->type == log->eOperand->type && log->eBase->type == "integer"){ //makes sure the ebase and eoperand are of the same type
                Integer* b = (Integer *)(log->eBase);
                Integer* c = (Integer *)(log->eOperand);
                if (b->getValue() == c->getValue()){// checks to see if the ebase and the eOperand are the same
                    Integer* inte= new Integer(1);//returns one if they are the same
                    seperatedLogs.at(j) = inte;//assigns 1 to the value of seperated log at j

                }
                }
    	}
    	}

       Expression * answer;//creates a new variable called answer
       if(size1 >= 2){// if the size is two or higher
        answer = seperatedLogs.at(0)->add(seperatedLogs.at(1));// add the first two together
       }
       else{//if the size is just 1
        answer = seperatedLogs.at(0);//the answer is the first one
       }

       for(int k = 2; k<size1; k++){
            answer = answer->add(seperatedLogs.at(k));//keeps adding elements of seperated log to answer

       }
       Integer* size2 = new Integer((int)size1);
       Integer* answerint = (Integer *)answer;
       if(answerint->getValue()==size2->getValue())
       {
           return answer;
       }
       else if(size1 == 1){
        return this;
       }
       else
       {
          Expression* e = new Integer(answerint->getValue());
          e->type = "multiple";
          stringstream s;
          for(int l = 0; l<size1; l++){
            s<<*seperatedLogs.at(l);
            if(l+1 < size1){
                s<< " " << "+" << " ";
            }
            }
        e->exp = s.str();
        cout<<e->exp;
        return e;
       }
       }

       throw runtime_error("invalid entry");
       return this;
}

//creates vector of prime factors of n to be used in the simplify method
vector<int> Logarithm::primeFactorization(int n) {
    int k = 0;
    vector<int> factors;
    while (n%2 == 0) {
        factors.push_back(2);
        n = n/2;
    }
    for (int i = 3; i <= sqrt(n); i = i + 2) {
        while (n%i == 0) {
            factors.push_back(i);
            k++;
            n = n/i;
        }
    }
    if (n > 2) {
        factors.push_back(n);
    }
    return factors;
}

Expression* Logarithm::add(Expression* a){
    return this;
}
Expression* Logarithm::subtract(Expression* a){
    Logarithm* c = this;
    Logarithm* b = (Logarithm *) a;
    if(c->eBase->type == b->eBase->type && c->eOperand->type == b->eOperand->type) {
    	if (c->getEBase() == b->getEBase() && c->getEOperand() == b->getEOperand()){
    		Expression* answer = new Integer(0);
    		return answer;
    	}
    }
    return c;
}

Expression* Logarithm::multiply(Expression* a){
    Logarithm* c = this;
    Logarithm* b = (Logarithm *) a;
    if(c->eBase->type == b->eBase->type && c->eOperand->type == b->eOperand->type) {
    	if (c->getEBase() == b->getEBase() && c->getEOperand() == b->getEOperand()){
    		Exponential* answer = new Exponential(this, new Rational(2,1));
    		return answer;
    	}
    }
   return c;
}
Expression* Logarithm::divide(Expression* a){//this set up is "this" divided by a so if this = log11 and a = log3 it would be log11/log3
    Logarithm* c = this;
    Logarithm* b = (Logarithm *) a;
    if(c->eBase->type == b->eBase->type && c->getEBase() == b->getEBase()) {
        Expression* numeratorOperand = c->getEOperand();
        Expression* denominatorOperand = b->getEOperand();
        Logarithm* answer = new Logarithm(denominatorOperand, numeratorOperand);
        return answer;
    }

    return c;
}
ostream& Logarithm::print(std::ostream& output) const{
    output << "Log_" << *eBase << ":" << *eOperand<< endl;

    return output;
}
string Logarithm::toString(){
    stringstream ss;
    ss << "Log_" << *this->eBase << ":" << *this->eOperand;

    return ss.str();
};
<|endoftext|>


<commit_before>// Copyright 2014 BVLC and contributors.

#include <glog/logging.h>
#include <leveldb/db.h>
#include <stdint.h>

#include <algorithm>
#include <string>

#include "caffe/proto/caffe.pb.h"
#include "caffe/util/io.hpp"

using caffe::Datum;
using caffe::BlobProto;
using std::max;

int main(int argc, char** argv) {
  ::google::InitGoogleLogging(argv[0]);
  if (argc != 3) {
    LOG(ERROR) << "Usage: compute_image_mean input_leveldb output_file";
    return 1;
  }

  leveldb::DB* db;
  leveldb::Options options;
  options.create_if_missing = false;

  LOG(INFO) << "Opening leveldb " << argv[1];
  leveldb::Status status = leveldb::DB::Open(
      options, argv[1], &db);
  CHECK(status.ok()) << "Failed to open leveldb " << argv[1];

  leveldb::ReadOptions read_options;
  read_options.fill_cache = false;
  leveldb::Iterator* it = db->NewIterator(read_options);
  it->SeekToFirst();
  Datum datum;
  BlobProto sum_blob;
  int count = 0;
  datum.ParseFromString(it->value().ToString());
  sum_blob.set_num(1);
  sum_blob.set_channels(datum.channels());
  sum_blob.set_height(datum.height());
  sum_blob.set_width(datum.width());
  const int data_size = datum.channels() * datum.height() * datum.width();
  int size_in_datum = std::max<int>(datum.data().size(),
                                    datum.float_data_size());
  for (int i = 0; i < size_in_datum; ++i) {
    sum_blob.add_data(0.);
  }
  LOG(INFO) << "Starting Iteration";
  for (it->SeekToFirst(); it->Valid(); it->Next()) {
    // just a dummy operation
    datum.ParseFromString(it->value().ToString());
    const string& data = datum.data();
    size_in_datum = std::max<int>(datum.data().size(), datum.float_data_size());
    CHECK_EQ(size_in_datum, data_size) << "Incorrect data field size " <<
        size_in_datum;
    if (data.size() != 0) {
      for (int i = 0; i < size_in_datum; ++i) {
        sum_blob.set_data(i, sum_blob.data(i) + (uint8_t)data[i]);
      }
    } else {
      for (int i = 0; i < size_in_datum; ++i) {
        sum_blob.set_data(i, sum_blob.data(i) +
            static_cast<float>(datum.float_data(i)));
      }
    }
    ++count;
    if (count % 10000 == 0) {
      LOG(ERROR) << "Processed " << count << " files.";
    }
  }
  if (count % 10000 != 0) {
    LOG(ERROR) << "Processed " << count << " files.";
  }
  for (int i = 0; i < sum_blob.data_size(); ++i) {
    sum_blob.set_data(i, sum_blob.data(i) / count);
  }
  // Write to disk
  LOG(INFO) << "Write to " << argv[2];
  WriteProtoToBinaryFile(sum_blob, argv[2]);

  delete db;
  return 0;
}
<commit_msg>add lmdb support for compute_image_mean<commit_after>// Copyright 2014 BVLC and contributors.

#include <glog/logging.h>
#include <leveldb/db.h>
#include <lmdb.h>
#include <stdint.h>

#include <algorithm>
#include <string>

#include "caffe/proto/caffe.pb.h"
#include "caffe/util/io.hpp"

using caffe::Datum;
using caffe::BlobProto;
using std::max;

int main(int argc, char** argv) {
  ::google::InitGoogleLogging(argv[0]);
  if (argc < 3 || argc > 4) {
    LOG(ERROR) << "Usage: compute_image_mean input_leveldb output_file"
               << " db_backend[leveldb or lmdb]";
    return 1;
  }

  string db_backend = "leveldb";
  if (argc == 4) {
    db_backend = string(argv[3]);
  }

  // leveldb
  leveldb::DB* db;
  leveldb::Options options;
  options.create_if_missing = false;
  leveldb::Iterator* it;
  // lmdb
  MDB_env* mdb_env;
  MDB_dbi mdb_dbi;
  MDB_val mdb_key, mdb_value;
  MDB_txn* mdb_txn;
  MDB_cursor* mdb_cursor;

  // Open db
  if (db_backend == "leveldb") {  // leveldb
    LOG(INFO) << "Opening leveldb " << argv[1];
    leveldb::Status status = leveldb::DB::Open(
        options, argv[1], &db);
    CHECK(status.ok()) << "Failed to open leveldb " << argv[1];
    leveldb::ReadOptions read_options;
    read_options.fill_cache = false;
    it = db->NewIterator(read_options);
    it->SeekToFirst();
  } else if (db_backend == "lmdb") {  // lmdb
    LOG(INFO) << "Opening lmdb " << argv[1];
    CHECK_EQ(mdb_env_create(&mdb_env), MDB_SUCCESS) << "mdb_env_create failed";
    CHECK_EQ(mdb_env_set_mapsize(mdb_env, 1099511627776), MDB_SUCCESS); // 1TB
    CHECK_EQ(mdb_env_open(mdb_env, argv[1], MDB_RDONLY, 0664),
        MDB_SUCCESS) << "mdb_env_open failed";
    CHECK_EQ(mdb_txn_begin(mdb_env, NULL, MDB_RDONLY, &mdb_txn), MDB_SUCCESS)
        << "mdb_txn_begin failed";
    CHECK_EQ(mdb_open(mdb_txn, NULL, 0, &mdb_dbi), MDB_SUCCESS)
        << "mdb_open failed";
    CHECK_EQ(mdb_cursor_open(mdb_txn, mdb_dbi, &mdb_cursor), MDB_SUCCESS)
        << "mdb_cursor_open failed";
    CHECK_EQ(mdb_cursor_get(mdb_cursor, &mdb_key, &mdb_value, MDB_FIRST),
        MDB_SUCCESS);
  } else {
    LOG(FATAL) << "Unknown db backend " << db_backend;
  }

  Datum datum;
  BlobProto sum_blob;
  int count = 0;
  // load first datum
  if (db_backend == "leveldb") {
    datum.ParseFromString(it->value().ToString());
  } else if (db_backend == "lmdb") {
    datum.ParseFromArray(mdb_value.mv_data, mdb_value.mv_size);
  } else {
    LOG(FATAL) << "Unknown db backend " << db_backend;
  }

  sum_blob.set_num(1);
  sum_blob.set_channels(datum.channels());
  sum_blob.set_height(datum.height());
  sum_blob.set_width(datum.width());
  const int data_size = datum.channels() * datum.height() * datum.width();
  int size_in_datum = std::max<int>(datum.data().size(),
                                    datum.float_data_size());
  for (int i = 0; i < size_in_datum; ++i) {
    sum_blob.add_data(0.);
  }
  LOG(INFO) << "Starting Iteration";
  if (db_backend == "leveldb") {  // leveldb
    for (it->SeekToFirst(); it->Valid(); it->Next()) {
      // just a dummy operation
      datum.ParseFromString(it->value().ToString());
      const string& data = datum.data();
      size_in_datum = std::max<int>(datum.data().size(),
          datum.float_data_size());
      CHECK_EQ(size_in_datum, data_size) << "Incorrect data field size " <<
          size_in_datum;
      if (data.size() != 0) {
        for (int i = 0; i < size_in_datum; ++i) {
          sum_blob.set_data(i, sum_blob.data(i) + (uint8_t)data[i]);
        }
      } else {
        for (int i = 0; i < size_in_datum; ++i) {
          sum_blob.set_data(i, sum_blob.data(i) +
              static_cast<float>(datum.float_data(i)));
        }
      }
      ++count;
      if (count % 10000 == 0) {
        LOG(ERROR) << "Processed " << count << " files.";
      }
    }
  } else if (db_backend == "lmdb") {  // lmdb
    CHECK_EQ(mdb_cursor_get(mdb_cursor, &mdb_key, &mdb_value, MDB_FIRST),
        MDB_SUCCESS);
    do {
      // just a dummy operation
      datum.ParseFromArray(mdb_value.mv_data, mdb_value.mv_size);
      const string& data = datum.data();
      size_in_datum = std::max<int>(datum.data().size(),
          datum.float_data_size());
      CHECK_EQ(size_in_datum, data_size) << "Incorrect data field size " <<
          size_in_datum;
      if (data.size() != 0) {
        for (int i = 0; i < size_in_datum; ++i) {
          sum_blob.set_data(i, sum_blob.data(i) + (uint8_t)data[i]);
        }
      } else {
        for (int i = 0; i < size_in_datum; ++i) {
          sum_blob.set_data(i, sum_blob.data(i) +
              static_cast<float>(datum.float_data(i)));
        }
      }
      ++count;
      if (count % 10000 == 0) {
        LOG(ERROR) << "Processed " << count << " files.";
      }
    } while (mdb_cursor_get(mdb_cursor, &mdb_key, &mdb_value, MDB_NEXT)
        == MDB_SUCCESS);
  } else {
    LOG(FATAL) << "Unknown db backend " << db_backend;
  }

  if (count % 10000 != 0) {
    LOG(ERROR) << "Processed " << count << " files.";
  }
  for (int i = 0; i < sum_blob.data_size(); ++i) {
    sum_blob.set_data(i, sum_blob.data(i) / count);
  }
  // Write to disk
  LOG(INFO) << "Write to " << argv[2];
  WriteProtoToBinaryFile(sum_blob, argv[2]);

  // Clean up
  if (db_backend == "leveldb") {
    delete db;
  } else if (db_backend == "lmdb") {
    mdb_cursor_close(mdb_cursor);
    mdb_close(mdb_env, mdb_dbi);
    mdb_txn_abort(mdb_txn);
    mdb_env_close(mdb_env);
  } else {
    LOG(FATAL) << "Unknown db backend " << db_backend;
  }
  return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright © 2011 Stéphane Raimbault <stephane.raimbault@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 Public License for more details.
 *
 * You should have received a copy of the GNU Lesser Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 * This library implements the Modbus protocol.
 * http://libmodbus.org/
 */

#include <inttypes.h>

#include "WProgram.h"
#include "Modbusino.h"

#define _MODBUS_RTU_SLAVE              0
#define _MODBUS_RTU_FUNCTION           1
#define _MODBUS_RTU_PRESET_REQ_LENGTH  6
#define _MODBUS_RTU_PRESET_RSP_LENGTH  2

#define _MODBUS_RTU_CHECKSUM_LENGTH    2

#define _MODBUSINO_RTU_MAX_ADU_LENGTH  128

/* Supported function codes */
#define _FC_READ_HOLDING_REGISTERS    0x03
#define _FC_WRITE_MULTIPLE_REGISTERS  0x10

enum {
    _STEP_FUNCTION = 0x01,
    _STEP_META,
    _STEP_DATA
};

static uint16_t crc16(uint8_t *req, uint8_t req_length)
{
    uint8_t j;
    uint16_t crc;

    crc = 0xFFFF;
    while (req_length--) {
	crc = crc ^ *req++;
	for (j=0; j < 8; j++) {
	    if (crc & 0x0001)
		crc = (crc >> 1) ^ 0xA001;
	    else
		crc = crc >> 1;
	}
    }

    return (crc << 8  | crc >> 8);
}

ModbusinoSlave::ModbusinoSlave(uint8_t slave) {
    _slave = slave;
}

void ModbusinoSlave::setup(long baud) {
    Serial.begin(baud);
}

static int check_integrity(uint8_t *msg, uint8_t msg_length)
{
    uint16_t crc_calculated;
    uint16_t crc_received;

    if (msg_length < 2)
	return -1;

    crc_calculated = crc16(msg, msg_length - 2);
    crc_received = (msg[msg_length - 2] << 8) | msg[msg_length - 1];

    /* Check CRC of msg */
    if (crc_calculated == crc_received) {
        return msg_length;
    } else {
        return -1;
    }
}

static int build_response_basis(uint8_t slave, uint8_t function,
				uint8_t* rsp)
{
    rsp[0] = slave;
    rsp[1] = function;

    return _MODBUS_RTU_PRESET_RSP_LENGTH;
}

static void send_msg(uint8_t *msg, uint8_t msg_length)
{
    uint16_t crc = crc16(msg, msg_length);

    msg[msg_length++] = crc >> 8;
    msg[msg_length++] = crc & 0x00FF;

    Serial.write(msg, msg_length);
}

static uint8_t response_exception(uint8_t slave, uint8_t function,
				  uint8_t exception_code,
				  uint8_t *rsp)
{
    uint8_t rsp_length;

    rsp_length = build_response_basis(slave, function + 0x80, rsp);

    /* Positive exception code */
    rsp[rsp_length++] = exception_code;

    return rsp_length;
}

static void flush(void)
{
    /* Wait a moment to receive the remaining garbage */
    while (Serial.available()) {
	Serial.flush();
	delay(3);
    }
}

static int receive(uint8_t *req, uint8_t _slave)
{
    uint8_t i;
    uint8_t length_to_read;
    uint8_t req_index;
    uint8_t step;
    uint8_t function;

    /* We need to analyse the message step by step.  At the first step, we want
     * to reach the function code because all packets contain this
     * information. */
    step = _STEP_FUNCTION;
    length_to_read = _MODBUS_RTU_FUNCTION + 1;

    req_index = 0;
    while (length_to_read != 0) {

	/* The timeout is defined to ~10 ms between each bytes.  Precision is
	   not that important so I rather to avoid millis() to apply the KISS
	   principle (millis overflows after 50 days, etc) */
        if (!Serial.available()) {
	    i = 0;
	    while (!Serial.available()) {
		delay(1);
		if (++i == 10) {
		    /* Too late, bye */
		    return -1;
		}
	    }
        }

	req[req_index] = Serial.read();

        /* Moves the pointer to receive other data */
	req_index++;

        /* Computes remaining bytes */
        length_to_read--;

        if (length_to_read == 0) {
            switch (step) {
            case _STEP_FUNCTION:
                /* Function code position */
		function = req[_MODBUS_RTU_FUNCTION];
		if (function == _FC_READ_HOLDING_REGISTERS) {
		    length_to_read = 4;
		} else if (function == _FC_WRITE_MULTIPLE_REGISTERS) {
		    length_to_read = 5;
		} else {
		    /* Wait a moment to receive the remaining garbage */
		    flush();
		    if (_slave == req[_MODBUS_RTU_SLAVE]) {
			/* It's for me so send an exception (reuse req) */
			uint8_t rsp_length = response_exception(
			    _slave, function,
			    MODBUS_EXCEPTION_ILLEGAL_FUNCTION,
			    req);
			send_msg(req, rsp_length);
			return - 1 - MODBUS_EXCEPTION_ILLEGAL_FUNCTION;
		    }

		    return -1;
		}
		step = _STEP_META;
		break;
            case _STEP_META:
		length_to_read = _MODBUS_RTU_CHECKSUM_LENGTH;

		if (function == _FC_WRITE_MULTIPLE_REGISTERS)
		    length_to_read += req[_MODBUS_RTU_FUNCTION + 5];

                if ((req_index + length_to_read) > _MODBUSINO_RTU_MAX_ADU_LENGTH) {
		    flush();
		    if (_slave == req[_MODBUS_RTU_SLAVE]) {
			/* It's for me so send an exception (reuse req) */
			uint8_t rsp_length = response_exception(
			    _slave, function,
			    MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
			    req);
			send_msg(req, rsp_length);
			return - 1 - MODBUS_EXCEPTION_ILLEGAL_FUNCTION;
		    }
		    return -1;
                }
                step = _STEP_DATA;
                break;
            default:
                break;
            }
        }
    }

    return check_integrity(req, req_index);
}

static void reply(uint16_t *tab_reg, uint8_t nb_reg,
		  uint8_t *req, uint8_t req_length, uint8_t _slave)
{
    uint8_t slave = req[_MODBUS_RTU_SLAVE];
    uint8_t function = req[_MODBUS_RTU_FUNCTION];
    uint16_t address = (req[_MODBUS_RTU_FUNCTION + 1] << 8) +
	req[_MODBUS_RTU_FUNCTION + 2];
    uint16_t nb = (req[_MODBUS_RTU_FUNCTION + 3] << 8) +
	req[_MODBUS_RTU_FUNCTION + 4];
    uint8_t rsp[_MODBUSINO_RTU_MAX_ADU_LENGTH];
    uint8_t rsp_length = 0;

    if (slave != _slave) {
	return;
    }

    if (address + nb > nb_reg) {
	rsp_length = response_exception(
	    slave, function,
	    MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
    }

    req_length -= _MODBUS_RTU_CHECKSUM_LENGTH;

    if (function == _FC_READ_HOLDING_REGISTERS) {
	uint8_t i;
	rsp_length = build_response_basis(slave, function, rsp);
	rsp[rsp_length++] = nb << 1;
	for (i = address; i < address + nb; i++) {
	    rsp[rsp_length++] = tab_reg[i] >> 8;
	    rsp[rsp_length++] = tab_reg[i] & 0xFF;
	}
    } else {
	int i, j;

	for (i = address, j = 6; i < address + nb; i++, j += 2) {
	    /* 6 and 7 = first value */
	    tab_reg[i] = (req[_MODBUS_RTU_FUNCTION + j] << 8) +
		req[_MODBUS_RTU_FUNCTION + j + 1];
	}

	rsp_length = build_response_basis(slave, function, rsp);
	/* 4 to copy the address (2) and the no. of registers */
	memcpy(rsp + rsp_length, req + rsp_length, 4);
	rsp_length += 4;
    }

    send_msg(rsp, rsp_length);
}

int ModbusinoSlave::loop(uint16_t* tab_reg, uint8_t nb_reg)
{
    int rc;
    uint8_t req[_MODBUSINO_RTU_MAX_ADU_LENGTH];

    if (Serial.available()) {
	rc = receive(req, _slave);
	if (rc > 0) {
	    reply(tab_reg, nb_reg, req, rc, _slave);
	}
    }

    /* Returns a positive value if successful,
       0 if a slave filtering has occured,
       -1 if an undefined error has occured,
       -2 for MODBUS_EXCEPTION_ILLEGAL_FUNCTION
       etc */
    return rc;
}
<commit_msg>Avoid getting stuck on a line saturated by garbage<commit_after>/*
 * Copyright © 2011 Stéphane Raimbault <stephane.raimbault@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 Public License for more details.
 *
 * You should have received a copy of the GNU Lesser Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 * This library implements the Modbus protocol.
 * http://libmodbus.org/
 */

#include <inttypes.h>

#include "WProgram.h"
#include "Modbusino.h"

#define _MODBUS_RTU_SLAVE              0
#define _MODBUS_RTU_FUNCTION           1
#define _MODBUS_RTU_PRESET_REQ_LENGTH  6
#define _MODBUS_RTU_PRESET_RSP_LENGTH  2

#define _MODBUS_RTU_CHECKSUM_LENGTH    2

#define _MODBUSINO_RTU_MAX_ADU_LENGTH  128

/* Supported function codes */
#define _FC_READ_HOLDING_REGISTERS    0x03
#define _FC_WRITE_MULTIPLE_REGISTERS  0x10

enum {
    _STEP_FUNCTION = 0x01,
    _STEP_META,
    _STEP_DATA
};

static uint16_t crc16(uint8_t *req, uint8_t req_length)
{
    uint8_t j;
    uint16_t crc;

    crc = 0xFFFF;
    while (req_length--) {
	crc = crc ^ *req++;
	for (j=0; j < 8; j++) {
	    if (crc & 0x0001)
		crc = (crc >> 1) ^ 0xA001;
	    else
		crc = crc >> 1;
	}
    }

    return (crc << 8  | crc >> 8);
}

ModbusinoSlave::ModbusinoSlave(uint8_t slave) {
    _slave = slave;
}

void ModbusinoSlave::setup(long baud) {
    Serial.begin(baud);
}

static int check_integrity(uint8_t *msg, uint8_t msg_length)
{
    uint16_t crc_calculated;
    uint16_t crc_received;

    if (msg_length < 2)
	return -1;

    crc_calculated = crc16(msg, msg_length - 2);
    crc_received = (msg[msg_length - 2] << 8) | msg[msg_length - 1];

    /* Check CRC of msg */
    if (crc_calculated == crc_received) {
        return msg_length;
    } else {
        return -1;
    }
}

static int build_response_basis(uint8_t slave, uint8_t function,
				uint8_t* rsp)
{
    rsp[0] = slave;
    rsp[1] = function;

    return _MODBUS_RTU_PRESET_RSP_LENGTH;
}

static void send_msg(uint8_t *msg, uint8_t msg_length)
{
    uint16_t crc = crc16(msg, msg_length);

    msg[msg_length++] = crc >> 8;
    msg[msg_length++] = crc & 0x00FF;

    Serial.write(msg, msg_length);
}

static uint8_t response_exception(uint8_t slave, uint8_t function,
				  uint8_t exception_code,
				  uint8_t *rsp)
{
    uint8_t rsp_length;

    rsp_length = build_response_basis(slave, function + 0x80, rsp);

    /* Positive exception code */
    rsp[rsp_length++] = exception_code;

    return rsp_length;
}

static void flush(void)
{
    uint8_t i = 0;

    /* Wait a moment to receive the remaining garbage but avoid getting stuck
     * because the line is saturated */
    while (Serial.available() && i++ < 10) {
	Serial.flush();
	delay(3);
    }
}

static int receive(uint8_t *req, uint8_t _slave)
{
    uint8_t i;
    uint8_t length_to_read;
    uint8_t req_index;
    uint8_t step;
    uint8_t function;

    /* We need to analyse the message step by step.  At the first step, we want
     * to reach the function code because all packets contain this
     * information. */
    step = _STEP_FUNCTION;
    length_to_read = _MODBUS_RTU_FUNCTION + 1;

    req_index = 0;
    while (length_to_read != 0) {

	/* The timeout is defined to ~10 ms between each bytes.  Precision is
	   not that important so I rather to avoid millis() to apply the KISS
	   principle (millis overflows after 50 days, etc) */
        if (!Serial.available()) {
	    i = 0;
	    while (!Serial.available()) {
		delay(1);
		if (++i == 10) {
		    /* Too late, bye */
		    return -1;
		}
	    }
        }

	req[req_index] = Serial.read();

        /* Moves the pointer to receive other data */
	req_index++;

        /* Computes remaining bytes */
        length_to_read--;

        if (length_to_read == 0) {
            switch (step) {
            case _STEP_FUNCTION:
                /* Function code position */
		function = req[_MODBUS_RTU_FUNCTION];
		if (function == _FC_READ_HOLDING_REGISTERS) {
		    length_to_read = 4;
		} else if (function == _FC_WRITE_MULTIPLE_REGISTERS) {
		    length_to_read = 5;
		} else {
		    /* Wait a moment to receive the remaining garbage */
		    flush();
		    if (_slave == req[_MODBUS_RTU_SLAVE]) {
			/* It's for me so send an exception (reuse req) */
			uint8_t rsp_length = response_exception(
			    _slave, function,
			    MODBUS_EXCEPTION_ILLEGAL_FUNCTION,
			    req);
			send_msg(req, rsp_length);
			return - 1 - MODBUS_EXCEPTION_ILLEGAL_FUNCTION;
		    }

		    return -1;
		}
		step = _STEP_META;
		break;
            case _STEP_META:
		length_to_read = _MODBUS_RTU_CHECKSUM_LENGTH;

		if (function == _FC_WRITE_MULTIPLE_REGISTERS)
		    length_to_read += req[_MODBUS_RTU_FUNCTION + 5];

                if ((req_index + length_to_read) > _MODBUSINO_RTU_MAX_ADU_LENGTH) {
		    flush();
		    if (_slave == req[_MODBUS_RTU_SLAVE]) {
			/* It's for me so send an exception (reuse req) */
			uint8_t rsp_length = response_exception(
			    _slave, function,
			    MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
			    req);
			send_msg(req, rsp_length);
			return - 1 - MODBUS_EXCEPTION_ILLEGAL_FUNCTION;
		    }
		    return -1;
                }
                step = _STEP_DATA;
                break;
            default:
                break;
            }
        }
    }

    return check_integrity(req, req_index);
}

static void reply(uint16_t *tab_reg, uint8_t nb_reg,
		  uint8_t *req, uint8_t req_length, uint8_t _slave)
{
    uint8_t slave = req[_MODBUS_RTU_SLAVE];
    uint8_t function = req[_MODBUS_RTU_FUNCTION];
    uint16_t address = (req[_MODBUS_RTU_FUNCTION + 1] << 8) +
	req[_MODBUS_RTU_FUNCTION + 2];
    uint16_t nb = (req[_MODBUS_RTU_FUNCTION + 3] << 8) +
	req[_MODBUS_RTU_FUNCTION + 4];
    uint8_t rsp[_MODBUSINO_RTU_MAX_ADU_LENGTH];
    uint8_t rsp_length = 0;

    if (slave != _slave) {
	return;
    }

    if (address + nb > nb_reg) {
	rsp_length = response_exception(
	    slave, function,
	    MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
    }

    req_length -= _MODBUS_RTU_CHECKSUM_LENGTH;

    if (function == _FC_READ_HOLDING_REGISTERS) {
	uint8_t i;
	rsp_length = build_response_basis(slave, function, rsp);
	rsp[rsp_length++] = nb << 1;
	for (i = address; i < address + nb; i++) {
	    rsp[rsp_length++] = tab_reg[i] >> 8;
	    rsp[rsp_length++] = tab_reg[i] & 0xFF;
	}
    } else {
	int i, j;

	for (i = address, j = 6; i < address + nb; i++, j += 2) {
	    /* 6 and 7 = first value */
	    tab_reg[i] = (req[_MODBUS_RTU_FUNCTION + j] << 8) +
		req[_MODBUS_RTU_FUNCTION + j + 1];
	}

	rsp_length = build_response_basis(slave, function, rsp);
	/* 4 to copy the address (2) and the no. of registers */
	memcpy(rsp + rsp_length, req + rsp_length, 4);
	rsp_length += 4;
    }

    send_msg(rsp, rsp_length);
}

int ModbusinoSlave::loop(uint16_t* tab_reg, uint8_t nb_reg)
{
    int rc;
    uint8_t req[_MODBUSINO_RTU_MAX_ADU_LENGTH];

    if (Serial.available()) {
	rc = receive(req, _slave);
	if (rc > 0) {
	    reply(tab_reg, nb_reg, req, rc, _slave);
	}
    }

    /* Returns a positive value if successful,
       0 if a slave filtering has occured,
       -1 if an undefined error has occured,
       -2 for MODBUS_EXCEPTION_ILLEGAL_FUNCTION
       etc */
    return rc;
}
<|endoftext|>