<commit_before>#include <iostream>
#include <vector>

#include <opencv2/imgproc/imgproc.hpp>

#include "MainWindow.h"
#include "BookDataDialog.h"
#include <Exceptions.h>

MainWindow::MainWindow(void) :
  start_stop_button("Start"),
  find_button("Find book"),
  add_book_button("Add book"),
  stream_source(STREAM_SOURCE::CAMERA),
  source_label("Source:"),
  run(false),
  find(false),
  showing_image_thread(nullptr)
{
  set_title("Book recognition");
  set_size_request(800, 600);

  makeMenu();
  setFilters();

  Gtk::Menu_Helpers::MenuList& list_upd = source_menu.items();
  list_upd.push_back(Gtk::Menu_Helpers::MenuElem("Choose source..."));
  list_upd.push_back(
    Gtk::Menu_Helpers::MenuElem("From camera", sigc::bind(sigc::mem_fun(*this,
    &MainWindow::on_source_menu_changed), STREAM_SOURCE::CAMERA)));
  list_upd.push_back(
    Gtk::Menu_Helpers::MenuElem("From file", sigc::bind(sigc::mem_fun(*this,
    &MainWindow::on_source_menu_changed), STREAM_SOURCE::FILE)));

  dispatcher.connect([&]()
  {
    showing_image_mutex.lock();
    pixbuf = Gdk::Pixbuf::create_from_data(image.data, Gdk::COLORSPACE_RGB, false, 8, image.cols, image.rows, image.step);
    image_place.set(pixbuf);
    showing_image_mutex.unlock();
  });

  option_menu.set_menu(source_menu);

  start_stop_button.set_sensitive(false);
  add_book_button.set_sensitive(false);
  find_button.set_sensitive(false);

  add(main_box);
  main_box.pack_start(*(m_refUIManager->get_widget("/MenuBar")), Gtk::PACK_SHRINK);
  main_box.pack_start(image_event_box);
  main_box.pack_start(buttons_box, Gtk::PACK_SHRINK);
  main_box.pack_end(status_bar, Gtk::PACK_SHRINK);

  image_event_box.add(image_place);

  buttons_box.pack_end(start_stop_button);
  buttons_box.pack_start(source_label, Gtk::PACK_SHRINK);
  buttons_box.pack_start(option_menu, Gtk::PACK_SHRINK);
  buttons_box.pack_start(find_button, Gtk::PACK_SHRINK);
  buttons_box.pack_start(add_book_button, Gtk::PACK_SHRINK);

  start_stop_button.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_start_stop_button_clicked));
  find_button.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_find_button_clicked));
  add_book_button.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_add_book_button_clicked));
  image_event_box.signal_button_press_event().connect(sigc::mem_fun(*this, &MainWindow::on_on_image_place_clicked));

  //showing
  main_box.show();
  main_box.show_all_children(true);

  //control
  recognizer.setDatabase(&db);
}

MainWindow::~MainWindow(void)
{
}

void MainWindow::makeMenu()
{
  ui = "<ui>\n"
    "<menubar name='MenuBar'>\n"
    "<menu action='MenuFile'>\n"
    "<menuitem action='LoadDatabase' />\n"
    "<menuitem action='SaveDatabase' />\n"
    "<menuitem action='ClearDatabase' />\n"
    "<menuitem action='Quit' />\n"
    "</menu>\n"
    "</menubar>\n"
    "</ui>\n";

  m_refActionGroup = Gtk::ActionGroup::create();
  m_refActionGroup->add(Gtk::Action::create("MenuFile", "_File"));
  m_refActionGroup->add(Gtk::Action::create("Quit", "Exit"), sigc::mem_fun(*this, &MainWindow::on_quit_menu_item_clicked));
  m_refActionGroup->add(Gtk::Action::create("LoadDatabase", "_Load database"), sigc::mem_fun(*this, &MainWindow::on_load_database_menu_item_clicked));
  m_refActionGroup->add(Gtk::Action::create("SaveDatabase", "_Store database"), sigc::mem_fun(*this, &MainWindow::on_save_database_menu_item_clicked));
  m_refActionGroup->add(Gtk::Action::create("ClearDatabase", "_Clear database"), sigc::mem_fun(*this, &MainWindow::on_clear_database_menu_item_clicked));

  m_refUIManager = Gtk::UIManager::create();
  m_refUIManager->insert_action_group(m_refActionGroup);
  add_accel_group(m_refUIManager->get_accel_group());
  m_refUIManager->add_ui_from_string(ui);
}

void MainWindow::on_quit_menu_item_clicked()
{
  if (!canQuit())
  {
    hide();
  }
}

bool MainWindow::on_delete_event(GdkEventAny* event)
{
  //TODO: Dialog
  return canQuit();
}

bool MainWindow::canQuit()
{
  if (run)
  {
    Gtk::MessageDialog("You cannot quit during run").run();
    return true;
  }
  if (!db.isSaved())
  {
    Gtk::MessageDialog dialog(*this, "Do you want to store databese before quit?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO);
    dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);

    switch (dialog.run())
    {
    case Gtk::RESPONSE_YES:
      on_save_database_menu_item_clicked();
      break;
    case Gtk::RESPONSE_CANCEL:
      return true;
    }
  }
  return false;
}

void MainWindow::on_start_stop_button_clicked()
{
  find_button.set_sensitive(true);
  if (run) //stopping
  {
    find = run = false;
    std::this_thread::sleep_for(std::chrono::milliseconds(100)); //wait for other thread to finish
    showing_image_thread->join();
    delete showing_image_thread;
    showing_image_thread = nullptr;
    start_stop_button.set_label("Start");
    option_menu.set_sensitive(true);
    add_book_button.set_sensitive(true);
  }
  else //starting
  {
    run = true;
    //showing_image_thread = Glib::Thread::create(sigc::mem_fun(*this, &MainWindow::showing_frames), true);
    showing_image_thread = new std::thread(&MainWindow::showing_frames, this);
    start_stop_button.set_label("Stop");
    option_menu.set_sensitive(false);
    add_book_button.set_sensitive(false);
  }
}

void MainWindow::on_load_database_menu_item_clicked()
{
  if (run) //running
  {
    Gtk::MessageDialog("You can't load database while running").run();
    return;
  }
  Gtk::FileChooserDialog dialog("Choose a file", Gtk::FILE_CHOOSER_ACTION_OPEN);
  dialog.set_transient_for(*this);

  dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
  dialog.add_button("OK", Gtk::RESPONSE_OK);

  dialog.add_filter(xml_filter);
  dialog.add_filter(all_filter);

  if (dialog.run() == Gtk::RESPONSE_OK)
  {
    try {
      db.load(dialog.get_filename());
    } catch (BR::Exception * ex) {
      Gtk::MessageDialog(ex->getFullMessage().c_str()).run();
      return;
    }
  }
}

void MainWindow::on_save_database_menu_item_clicked()
{
  Gtk::FileChooserDialog dialog("Choose a file", Gtk::FILE_CHOOSER_ACTION_SAVE);
  dialog.set_transient_for(*this);

  dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
  dialog.add_button("OK", Gtk::RESPONSE_OK);

  dialog.add_filter(xml_filter);
  dialog.add_filter(all_filter);

  if (dialog.run() == Gtk::RESPONSE_OK)
  {
    std::string file = dialog.get_filename();
    if (file.substr(file.length() - 4) != ".xml")
    {
      file = file + ".xml";
    }
    db.save(file);
  }
}

void MainWindow::on_clear_database_menu_item_clicked()
{
  if (Gtk::MessageDialog(*this, "Do you want to clear current database?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO).run() == Gtk::RESPONSE_YES)
  {
    db.clear();
  }
}

void MainWindow::on_source_menu_changed(STREAM_SOURCE source)
{
  start_stop_button.set_sensitive(true);
  add_book_button.set_sensitive(false);
  switch (source)
  {
  case STREAM_SOURCE::CAMERA:
    recognizer.open(0);
    status_bar.push("Reading from camera...");
    break;
  case STREAM_SOURCE::FILE:
    Gtk::FileChooserDialog dialog("Choose a video file", Gtk::FILE_CHOOSER_ACTION_SAVE);
    dialog.set_transient_for(*this);
    dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
    dialog.add_button("OK", Gtk::RESPONSE_OK);
    dialog.add_filter(video_filter);
    dialog.add_filter(all_filter);
    if (dialog.run() == Gtk::RESPONSE_OK)
    {
      recognizer.open(dialog.get_filename());
      status_bar.push((std::string("Reading file: ") + dialog.get_filename()).c_str());
    }
    break;
  }
}

void MainWindow::setFilters()
{
  xml_filter.set_name("XML files");
  xml_filter.add_mime_type("text/xml");
  xml_filter.add_mime_type("application/xml");

  all_filter.set_name("Any files");
  all_filter.add_pattern("*");

  video_filter.set_name("Video files");
  video_filter.add_mime_type("video/mpeg");
  video_filter.add_mime_type("video/mp4");
  video_filter.add_mime_type("video/quicktime");
  video_filter.add_mime_type("video/x-ms-wmv");
  video_filter.add_mime_type("video/ogg");
  video_filter.add_mime_type("video/webm");
  video_filter.add_mime_type("video/x-flv");
}

void MainWindow::showing_frames()
{
  cv::Mat tmp;
  try
  {
  while (run)
  {
//    gdk_threads_enter();
    getFrame(false);
  //  gdk_threads_leave();
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
  }
  }
  catch (...) //in case when video is over
  {
    Gtk::MessageDialog("Video reached end\n").run();
    //on_start_stop_button_clicked();
    //gdk_threads_leave();
  }
}

bool MainWindow::on_on_image_place_clicked(GdkEventButton * button)
{
  if (!read_image)
  {
    return true;
  }
  static int count = 0;
  static std::vector<cv::Point2f> points(4);
  points[count] = cv::Point2f(button->x, button->y);
  if (++count == 4)
  {
    count = 0;
    read_image = false;
    BookDataDialog bdd;
    if (bdd.run() == Gtk::RESPONSE_OK)
    {
      cv::Mat imageBGR;
      cv::cvtColor(image, imageBGR, CV_RGB2BGR);
      db.fixAndAdd(imageBGR, points, bdd.getTitle(), bdd.getAuthor(), bdd.getISBN());
      status_bar.push("Book was added to database");
    }
  }

  return true;
}

void MainWindow::on_add_book_button_clicked()
{
  read_image = true;
}

void MainWindow::on_find_button_clicked()
{
  on_start_stop_button_clicked();
  try {
    getFrame(true);
    const BR::Book * book;
    if ((book = recognizer.getCurrentBook()) != nullptr) {
      status_bar.push(("Found book: " + book->toString()).c_str());
      recognizer.hold(false);
    }
  } catch(BR::EmptyDatabaseException * ex) {
    Gtk::MessageDialog(ex->getFullMessage()).run();
  }
}

void MainWindow::getFrame(bool find_book)
{
  recognizer.next(find_book);
  cv::Mat tmp;
  cv::cvtColor(recognizer.getCurrentFrame(false), tmp, CV_BGR2RGB);
  showing_image_mutex.lock();
  cv::resize(tmp, image, cv::Size(image_event_box.get_width(), image_event_box.get_height()));
//  pixbuf = Gdk::Pixbuf::create_from_data(image.data, Gdk::COLORSPACE_RGB, false, 8, image.cols, image.rows, image.step);
  //image_place.set(pixbuf);
  //image_place.queue_draw();
  showing_image_mutex.unlock();
  dispatcher.emit();
  //showing_image_mutex.unlock();
  //dispatcher.emit();
  //std::this_thread::yield();
}

<commit_msg>Turn on drawing outline<commit_after>#include <iostream>
#include <vector>

#include <opencv2/imgproc/imgproc.hpp>

#include "MainWindow.h"
#include "BookDataDialog.h"
#include <Exceptions.h>

MainWindow::MainWindow(void) :
  start_stop_button("Start"),
  find_button("Find book"),
  add_book_button("Add book"),
  stream_source(STREAM_SOURCE::CAMERA),
  source_label("Source:"),
  run(false),
  find(false),
  showing_image_thread(nullptr)
{
  set_title("Book recognition");
  set_size_request(800, 600);

  makeMenu();
  setFilters();

  Gtk::Menu_Helpers::MenuList& list_upd = source_menu.items();
  list_upd.push_back(Gtk::Menu_Helpers::MenuElem("Choose source..."));
  list_upd.push_back(
    Gtk::Menu_Helpers::MenuElem("From camera", sigc::bind(sigc::mem_fun(*this,
    &MainWindow::on_source_menu_changed), STREAM_SOURCE::CAMERA)));
  list_upd.push_back(
    Gtk::Menu_Helpers::MenuElem("From file", sigc::bind(sigc::mem_fun(*this,
    &MainWindow::on_source_menu_changed), STREAM_SOURCE::FILE)));

  dispatcher.connect([&]()
  {
    showing_image_mutex.lock();
    pixbuf = Gdk::Pixbuf::create_from_data(image.data, Gdk::COLORSPACE_RGB, false, 8, image.cols, image.rows, image.step);
    image_place.set(pixbuf);
    showing_image_mutex.unlock();
  });

  option_menu.set_menu(source_menu);

  start_stop_button.set_sensitive(false);
  add_book_button.set_sensitive(false);
  find_button.set_sensitive(false);

  add(main_box);
  main_box.pack_start(*(m_refUIManager->get_widget("/MenuBar")), Gtk::PACK_SHRINK);
  main_box.pack_start(image_event_box);
  main_box.pack_start(buttons_box, Gtk::PACK_SHRINK);
  main_box.pack_end(status_bar, Gtk::PACK_SHRINK);

  image_event_box.add(image_place);

  buttons_box.pack_end(start_stop_button);
  buttons_box.pack_start(source_label, Gtk::PACK_SHRINK);
  buttons_box.pack_start(option_menu, Gtk::PACK_SHRINK);
  buttons_box.pack_start(find_button, Gtk::PACK_SHRINK);
  buttons_box.pack_start(add_book_button, Gtk::PACK_SHRINK);

  start_stop_button.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_start_stop_button_clicked));
  find_button.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_find_button_clicked));
  add_book_button.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_add_book_button_clicked));
  image_event_box.signal_button_press_event().connect(sigc::mem_fun(*this, &MainWindow::on_on_image_place_clicked));

  //showing
  main_box.show();
  main_box.show_all_children(true);

  //control
  recognizer.setDatabase(&db);
}

MainWindow::~MainWindow(void)
{
}

void MainWindow::makeMenu()
{
  ui = "<ui>\n"
    "<menubar name='MenuBar'>\n"
    "<menu action='MenuFile'>\n"
    "<menuitem action='LoadDatabase' />\n"
    "<menuitem action='SaveDatabase' />\n"
    "<menuitem action='ClearDatabase' />\n"
    "<menuitem action='Quit' />\n"
    "</menu>\n"
    "</menubar>\n"
    "</ui>\n";

  m_refActionGroup = Gtk::ActionGroup::create();
  m_refActionGroup->add(Gtk::Action::create("MenuFile", "_File"));
  m_refActionGroup->add(Gtk::Action::create("Quit", "Exit"), sigc::mem_fun(*this, &MainWindow::on_quit_menu_item_clicked));
  m_refActionGroup->add(Gtk::Action::create("LoadDatabase", "_Load database"), sigc::mem_fun(*this, &MainWindow::on_load_database_menu_item_clicked));
  m_refActionGroup->add(Gtk::Action::create("SaveDatabase", "_Store database"), sigc::mem_fun(*this, &MainWindow::on_save_database_menu_item_clicked));
  m_refActionGroup->add(Gtk::Action::create("ClearDatabase", "_Clear database"), sigc::mem_fun(*this, &MainWindow::on_clear_database_menu_item_clicked));

  m_refUIManager = Gtk::UIManager::create();
  m_refUIManager->insert_action_group(m_refActionGroup);
  add_accel_group(m_refUIManager->get_accel_group());
  m_refUIManager->add_ui_from_string(ui);
}

void MainWindow::on_quit_menu_item_clicked()
{
  if (!canQuit())
  {
    hide();
  }
}

bool MainWindow::on_delete_event(GdkEventAny* event)
{
  //TODO: Dialog
  return canQuit();
}

bool MainWindow::canQuit()
{
  if (run)
  {
    Gtk::MessageDialog("You cannot quit during run").run();
    return true;
  }
  if (!db.isSaved())
  {
    Gtk::MessageDialog dialog(*this, "Do you want to store databese before quit?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO);
    dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);

    switch (dialog.run())
    {
    case Gtk::RESPONSE_YES:
      on_save_database_menu_item_clicked();
      break;
    case Gtk::RESPONSE_CANCEL:
      return true;
    }
  }
  return false;
}

void MainWindow::on_start_stop_button_clicked()
{
  find_button.set_sensitive(true);
  if (run) //stopping
  {
    find = run = false;
    std::this_thread::sleep_for(std::chrono::milliseconds(100)); //wait for other thread to finish
    showing_image_thread->join();
    delete showing_image_thread;
    showing_image_thread = nullptr;
    start_stop_button.set_label("Start");
    option_menu.set_sensitive(true);
    add_book_button.set_sensitive(true);
  }
  else //starting
  {
    run = true;
    //showing_image_thread = Glib::Thread::create(sigc::mem_fun(*this, &MainWindow::showing_frames), true);
    showing_image_thread = new std::thread(&MainWindow::showing_frames, this);
    start_stop_button.set_label("Stop");
    option_menu.set_sensitive(false);
    add_book_button.set_sensitive(false);
  }
}

void MainWindow::on_load_database_menu_item_clicked()
{
  if (run) //running
  {
    Gtk::MessageDialog("You can't load database while running").run();
    return;
  }
  Gtk::FileChooserDialog dialog("Choose a file", Gtk::FILE_CHOOSER_ACTION_OPEN);
  dialog.set_transient_for(*this);

  dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
  dialog.add_button("OK", Gtk::RESPONSE_OK);

  dialog.add_filter(xml_filter);
  dialog.add_filter(all_filter);

  if (dialog.run() == Gtk::RESPONSE_OK)
  {
    try {
      db.load(dialog.get_filename());
    } catch (BR::Exception * ex) {
      Gtk::MessageDialog(ex->getFullMessage().c_str()).run();
      return;
    }
  }
}

void MainWindow::on_save_database_menu_item_clicked()
{
  Gtk::FileChooserDialog dialog("Choose a file", Gtk::FILE_CHOOSER_ACTION_SAVE);
  dialog.set_transient_for(*this);

  dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
  dialog.add_button("OK", Gtk::RESPONSE_OK);

  dialog.add_filter(xml_filter);
  dialog.add_filter(all_filter);

  if (dialog.run() == Gtk::RESPONSE_OK)
  {
    std::string file = dialog.get_filename();
    if (file.substr(file.length() - 4) != ".xml")
    {
      file = file + ".xml";
    }
    db.save(file);
  }
}

void MainWindow::on_clear_database_menu_item_clicked()
{
  if (Gtk::MessageDialog(*this, "Do you want to clear current database?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO).run() == Gtk::RESPONSE_YES)
  {
    db.clear();
  }
}

void MainWindow::on_source_menu_changed(STREAM_SOURCE source)
{
  start_stop_button.set_sensitive(true);
  add_book_button.set_sensitive(false);
  switch (source)
  {
  case STREAM_SOURCE::CAMERA:
    recognizer.open(0);
    status_bar.push("Reading from camera...");
    break;
  case STREAM_SOURCE::FILE:
    Gtk::FileChooserDialog dialog("Choose a video file", Gtk::FILE_CHOOSER_ACTION_SAVE);
    dialog.set_transient_for(*this);
    dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
    dialog.add_button("OK", Gtk::RESPONSE_OK);
    dialog.add_filter(video_filter);
    dialog.add_filter(all_filter);
    if (dialog.run() == Gtk::RESPONSE_OK)
    {
      recognizer.open(dialog.get_filename());
      status_bar.push((std::string("Reading file: ") + dialog.get_filename()).c_str());
    }
    break;
  }
}

void MainWindow::setFilters()
{
  xml_filter.set_name("XML files");
  xml_filter.add_mime_type("text/xml");
  xml_filter.add_mime_type("application/xml");

  all_filter.set_name("Any files");
  all_filter.add_pattern("*");

  video_filter.set_name("Video files");
  video_filter.add_mime_type("video/mpeg");
  video_filter.add_mime_type("video/mp4");
  video_filter.add_mime_type("video/quicktime");
  video_filter.add_mime_type("video/x-ms-wmv");
  video_filter.add_mime_type("video/ogg");
  video_filter.add_mime_type("video/webm");
  video_filter.add_mime_type("video/x-flv");
}

void MainWindow::showing_frames()
{
  cv::Mat tmp;
  try
  {
  while (run)
  {
//    gdk_threads_enter();
    getFrame(false);
  //  gdk_threads_leave();
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
  }
  }
  catch (...) //in case when video is over
  {
    Gtk::MessageDialog("Video reached end\n").run();
    //on_start_stop_button_clicked();
    //gdk_threads_leave();
  }
}

bool MainWindow::on_on_image_place_clicked(GdkEventButton * button)
{
  if (!read_image)
  {
    return true;
  }
  static int count = 0;
  static std::vector<cv::Point2f> points(4);
  points[count] = cv::Point2f(button->x, button->y);
  if (++count == 4)
  {
    count = 0;
    read_image = false;
    BookDataDialog bdd;
    if (bdd.run() == Gtk::RESPONSE_OK)
    {
      cv::Mat imageBGR;
      cv::cvtColor(image, imageBGR, CV_RGB2BGR);
      db.fixAndAdd(imageBGR, points, bdd.getTitle(), bdd.getAuthor(), bdd.getISBN());
      status_bar.push("Book was added to database");
    }
  }

  return true;
}

void MainWindow::on_add_book_button_clicked()
{
  read_image = true;
}

void MainWindow::on_find_button_clicked()
{
  on_start_stop_button_clicked();
  try {
    getFrame(true);
    const BR::Book * book;
    if ((book = recognizer.getCurrentBook()) != nullptr) {
      status_bar.push(("Found book: " + book->toString()).c_str());
      recognizer.hold(false);
    }
  } catch(BR::EmptyDatabaseException * ex) {
    Gtk::MessageDialog(ex->getFullMessage()).run();
  }
}

void MainWindow::getFrame(bool find_book)
{
  recognizer.next(find_book);
  cv::Mat tmp;
  cv::cvtColor(recognizer.getCurrentFrame(true), tmp, CV_BGR2RGB);
  showing_image_mutex.lock();
  cv::resize(tmp, image, cv::Size(image_event_box.get_width(), image_event_box.get_height()));
//  pixbuf = Gdk::Pixbuf::create_from_data(image.data, Gdk::COLORSPACE_RGB, false, 8, image.cols, image.rows, image.step);
  //image_place.set(pixbuf);
  //image_place.queue_draw();
  showing_image_mutex.unlock();
  dispatcher.emit();
  //showing_image_mutex.unlock();
  //dispatcher.emit();
  //std::this_thread::yield();
}

<|endoftext|>


<commit_before>#include <nan.h>
#include <iostream>
#include <string>
#include <sstream>
#include <map>
#include <stdlib.h>
#include <stdio.h>

#include <poppler/qt5/poppler-form.h>
#include <poppler/qt5/poppler-qt5.h>

#include <cairo/cairo.h>
#include <cairo/cairo-pdf.h>

#include <QtCore/QBuffer>
#include <QtCore/QFile>
#include <QtGui/QImage>

#include "NodePoppler.h"    // NOLINT(build/include)

using namespace std;
using v8::Number;
using v8::String;
using v8::Local;
using v8::Object;
using v8::Array;
using v8::Value;
using v8::Boolean;

inline bool fileExists (const std::string& name) {
  if (FILE *file = fopen(name.c_str(), "r")) {
    fclose(file);
    return true;
  } else {
    return false;
  }
}

// Cairo write and read functions (to QBuffer)
static cairo_status_t readPngFromBuffer(void *closure, unsigned char *data, unsigned int length) {
  QBuffer *myBuffer = (QBuffer *)closure;
  size_t bytes_read;
  bytes_read = myBuffer->read((char *)data, length);
  if (bytes_read != length)
    return CAIRO_STATUS_READ_ERROR;

  return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t writePngToBuffer(void *closure, const unsigned char *data, unsigned int length) {
  QBuffer *myBuffer = (QBuffer *)closure;
  size_t bytes_wrote;
  bytes_wrote = myBuffer->write((char *)data, length);
  if (bytes_wrote != length)
    return CAIRO_STATUS_READ_ERROR;

  return CAIRO_STATUS_SUCCESS;
}

void createPdf(QBuffer *buffer, Poppler::Document *document) {
  ostringstream ss;

  Poppler::PDFConverter *converter = document->pdfConverter();
  converter->setPDFOptions(converter->pdfOptions() | Poppler::PDFConverter::WithChanges);
  converter->setOutputDevice(buffer);
  if (!converter->convert()) {
    // enum Error
    // {
    //     NoError,
    //     FileLockedError,
    //     OpenOutputError,
    //     NotSupportedInputFileError
    // };
    ss << "Error occurred when converting PDF: " << converter->lastError();
    delete converter;
    throw ss.str();
  }
  delete converter;
}

void createImgPdf(QBuffer *buffer, Poppler::Document *document) {
  // Calculate max page sizes. The output PDF will have its size set to max width/height.
  double maxWidth = 0;
  double maxHeight = 0;

  int n = document->numPages();

  for (int i = 0; i < n; i += 1) {
    Poppler::Page *page = document->page(i);

    QSizeF size = page->pageSizeF();

    if (size.height() > maxHeight)
      maxHeight = size.height();

    if (size.width() > maxWidth)
      maxWidth = size.width();
  }

  // Initialize Cairo writing surface, and since we have images at 360 DPI, we'll set scaling.
  cairo_surface_t *surface = cairo_pdf_surface_create_for_stream(writePngToBuffer, buffer, maxWidth, maxHeight);
  cairo_t *cr = cairo_create(surface);
  cairo_scale(cr, 0.2, 0.2);

  for (int i = 0; i < n; i += 1) {
    Poppler::Page *page = document->page(i);

    // Save the page as PNG image to buffer. (We could use QFile if we want to save images to files)
    QBuffer *pageImage = new QBuffer();
    pageImage->open(QIODevice::ReadWrite);
    QImage img = page->renderToImage(360, 360);
    img.save(pageImage, "png");
    pageImage->seek(0);  // Reading does not work if we don't reset the pointer

    // Ookay, let's try to make new page out of the image
    cairo_surface_t *drawImageSurface = cairo_image_surface_create_from_png_stream(readPngFromBuffer, pageImage);
    cairo_set_source_surface(cr, drawImageSurface, 0, 0);
    cairo_paint(cr);
    cairo_surface_destroy(drawImageSurface);

    // Create new page if multipage document
    if (n > 0) {
      cairo_surface_show_page(surface);
      if (cr != NULL) {
        cairo_destroy(cr);
      }
      cr = cairo_create(surface);
      cairo_scale(cr, 0.2, 0.2);
    }

    pageImage->close();
    delete pageImage;

    delete page;
  }

  // Close Cairo
  cairo_destroy(cr);
  cairo_surface_finish(surface);
  cairo_surface_destroy (surface);
}

WriteFieldsParams v8ParamsToCpp(const Nan::FunctionCallbackInfo<v8::Value>& args) {
  Local<Object> parameters;
  string saveFormat = "imgpdf";
  map<string, string> fields;

  String::Utf8Value sourcePdfFileNameParam(args[0]->ToString());
  string sourcePdfFileName = string(*sourcePdfFileNameParam);

  Local<Object> changeFields = args[1]->ToObject();
  Local<String> saveStr = Nan::New("save").ToLocalChecked();

  // Check if any configuration parameters
  if (args.Length() > 2) {
    parameters = args[2]->ToObject();
    Local<Value> saveParam = Nan::Get(parameters, saveStr).ToLocalChecked();
    if (!saveParam->IsUndefined()) {
      String::Utf8Value saveFormatParam(Nan::Get(parameters, saveStr).ToLocalChecked());
      saveFormat = string(*saveFormatParam);
    }
  }

  // Convert form fields to c++ map
  Local<Array> fieldArray = changeFields->GetPropertyNames();
  for (uint32_t i = 0; i < fieldArray->Length(); i += 1) {
    Local<Value> name = fieldArray->Get(i);
    Local<Value> value = changeFields->Get(name);
    fields[std::string(*String::Utf8Value(name))] = std::string(*String::Utf8Value(value));
  }

  // Create and return PDF
  struct WriteFieldsParams params(sourcePdfFileName, saveFormat, fields);
  return params;
}

// Pdf creator that is not dependent on V8 internals (safe at async?)
QBuffer *writePdfFields(struct WriteFieldsParams params) {

  ostringstream ss;
  // If source file does not exist, throw error and return false
  if (!fileExists(params.sourcePdfFileName)) {
    ss << "File \"" << params.sourcePdfFileName << "\" does not exist";
    throw ss.str();
  }

  // Open document and return false and throw error if something goes wrong
  Poppler::Document *document = Poppler::Document::load(QString::fromStdString(params.sourcePdfFileName));
  if (document == NULL) {
    ss << "Error occurred when reading \"" << params.sourcePdfFileName << "\"";
    throw ss.str();
  }

  // Fill form
  int n = document->numPages();
  stringstream idSS;
  for (int i = 0; i < n; i += 1) {
    Poppler::Page *page = document->page(i);
    QList<Poppler::FormField *> formFields = page->formFields();

    foreach (Poppler::FormField *field, formFields) {
      string fieldName = field->fullyQualifiedName().toStdString();
      // Support writing fields by both fieldName and id.
      // If fieldName is not present in params, try id.
      if (params.fields.count(fieldName) == 0) {
        idSS << field->id();
        fieldName = idSS.str();
        idSS.str("");
        idSS.clear();
      }
      if (!field->isReadOnly() && field->isVisible() && params.fields.count(fieldName) ) {
        // Text
        if (field->type() == Poppler::FormField::FormText) {
          Poppler::FormFieldText *textField = (Poppler::FormFieldText *) field;
          textField->setText(QString::fromUtf8(params.fields[fieldName].c_str()));
        }

        // Choice
        if (field->type() == Poppler::FormField::FormChoice) {
          Poppler::FormFieldChoice *choiceField = (Poppler::FormFieldChoice *) field;
          if (choiceField->isEditable()) {
            choiceField->setEditChoice(QString::fromUtf8(params.fields[fieldName].c_str()));
          }
          else {
            QStringList possibleChoices = choiceField->choices();
            QString proposedChoice = QString::fromUtf8(params.fields[fieldName].c_str());
            int index = possibleChoices.indexOf(proposedChoice);
            if (index >= 0) {
              QList<int> choiceList;
              choiceList << index;
              choiceField->setCurrentChoices(choiceList);
            }
          }
        }

        // Button
        // ! TODO ! Note. Poppler doesn't support checkboxes with hashtag names (aka using exportValue).
        if (field->type() == Poppler::FormField::FormButton) {
          Poppler::FormFieldButton *buttonField = (Poppler::FormFieldButton *) field;
          if (params.fields[fieldName].compare("true") == 0) {
            buttonField->setState(true);
          }
          else {
            buttonField->setState(false);
          }
        }
      }
    }

    qDeleteAll(formFields);
    delete page;
  }

  // Now save and return the document
  QBuffer *bufferDevice = new QBuffer();
  bufferDevice->open(QIODevice::ReadWrite);

  // Get save parameters
  if (params.saveFormat == "imgpdf") {
    createImgPdf(bufferDevice, document);
  }
  else {
    createPdf(bufferDevice, document);
  }

  delete document;

  return bufferDevice;
}

//***********************************
//
// Node.js methods
//
//***********************************

// Read PDF form fields
NAN_METHOD(ReadSync) {

  // expect a number as the first argument
  Nan::Utf8String *fileName = new Nan::Utf8String(info[0]);
  ostringstream ss;
  int n = 0;

  // If file does not exist, throw error and return false
  if (!fileExists(**fileName)) {
    ss << "File \"" << **fileName << "\" does not exist";
    Nan::ThrowError(Nan::New<String>(ss.str()).ToLocalChecked());
    info.GetReturnValue().Set(Nan::False());
  }

  // Open document and return false and throw error if something goes wrong
  Poppler::Document *document = Poppler::Document::load(**fileName);
  if (document != NULL) {
    // Get field list
    n = document->numPages();
  } else {
    ss << "Error occurred when reading \"" << **fileName << "\"";
    Nan::ThrowError(Nan::New<String>(ss.str()).ToLocalChecked());
    info.GetReturnValue().Set(Nan::False());
  }

  delete fileName;

  // Store field value objects to v8 array
  Local<Array> fieldArray = Nan::New<Array>();
  int fieldNum = 0;

  for (int i = 0; i < n; i += 1) {
    Poppler::Page *page = document->page(i);
    QList<Poppler::FormField *> formFields = page->formFields();

    foreach (Poppler::FormField *field, formFields) {

      if (!field->isReadOnly() && field->isVisible()) {

        // Make JavaScript object out of the fieldnames
        Local<Object> obj = Nan::New<Object>();
        Nan::Set(obj, Nan::New<String>("name").ToLocalChecked(), Nan::New<String>(field->fullyQualifiedName().toStdString()).ToLocalChecked());
        Nan::Set(obj, Nan::New<String>("page").ToLocalChecked(), Nan::New<Number>(i));

        // ! TODO ! Note. Poppler doesn't support checkboxes with hashtag names (aka using exportValue).
        string fieldType;
        // Set default value undefined
        Nan::Set(obj, Nan::New<String>("value").ToLocalChecked(), Nan::Undefined());
        Poppler::FormFieldButton *myButton;
        Poppler::FormFieldChoice *myChoice;

        Nan::Set(obj, Nan::New<String>("id").ToLocalChecked(), Nan::New<Number>(field->id()));
        switch (field->type()) {

          // FormButton
          case Poppler::FormField::FormButton:
            myButton = (Poppler::FormFieldButton *)field;
            switch (myButton->buttonType()) {
              // Push
              case Poppler::FormFieldButton::Push:        fieldType = "push_button";     break;
              case Poppler::FormFieldButton::CheckBox:
                fieldType = "checkbox";
                Nan::Set(obj, Nan::New<String>("value").ToLocalChecked(), Nan::New<Boolean>(myButton->state()));
                break;
              case Poppler::FormFieldButton::Radio:       fieldType = "radio";           break;
            }
            break;

          // FormText
          case Poppler::FormField::FormText:
            Nan::Set(obj, Nan::New<String>("value").ToLocalChecked(), Nan::New<String>(((Poppler::FormFieldText *)field)->text().toStdString()).ToLocalChecked());
            fieldType = "text";
            break;

          // FormChoice
          case Poppler::FormField::FormChoice: {
            Local<Array> choiceArray = Nan::New<Array>();
            myChoice = (Poppler::FormFieldChoice *)field;
            QStringList possibleChoices = myChoice->choices();
            for (int i = 0; i < possibleChoices.size(); i++) {
              Nan::Set(choiceArray, i, Nan::New<String>(possibleChoices.at(i).toStdString()).ToLocalChecked());
            }
            Nan::Set(obj, Nan::New<String>("choices").ToLocalChecked(), choiceArray);
            switch (myChoice->choiceType()) {
              case Poppler::FormFieldChoice::ComboBox:    fieldType = "combobox";       break;
              case Poppler::FormFieldChoice::ListBox:     fieldType = "listbox";        break;
            }
            break;
          }

          // FormSignature
          case Poppler::FormField::FormSignature:         fieldType = "formsignature";  break;

          default:
            fieldType = "undefined";
            break;
        }

        Nan::Set(obj, Nan::New<String>("type").ToLocalChecked(), Nan::New<String>(fieldType.c_str()).ToLocalChecked());

        fieldArray->Set(fieldNum, obj);
        fieldNum++;

      }
    }

    qDeleteAll(formFields);
    delete page;
  }

  info.GetReturnValue().Set(fieldArray);

  delete document;
}

// Write PDF form fields
NAN_METHOD(WriteSync) {

  // Check and return parameters given at JavaScript function call
  WriteFieldsParams params = v8ParamsToCpp(info);

  // Create and return pdf
  try
  {
    QBuffer *buffer = writePdfFields(params);
    Local<Object> returnPdf = Nan::CopyBuffer((char *)buffer->data().data(), buffer->size()).ToLocalChecked();
    buffer->close();
    delete buffer;
    info.GetReturnValue().Set(returnPdf);
  }
  catch (string error)
  {
    Nan::ThrowError(Nan::New<String>(error).ToLocalChecked());
    info.GetReturnValue().Set(Nan::Null());
  }
}
<commit_msg>Adding support for Radio Button fill<commit_after>#include <nan.h>
#include <iostream>
#include <string>
#include <sstream>
#include <map>
#include <stdlib.h>
#include <stdio.h>

#include <poppler/qt5/poppler-form.h>
#include <poppler/qt5/poppler-qt5.h>

#include <cairo/cairo.h>
#include <cairo/cairo-pdf.h>

#include <QtCore/QBuffer>
#include <QtCore/QFile>
#include <QtGui/QImage>

#include "NodePoppler.h"    // NOLINT(build/include)

using namespace std;
using v8::Number;
using v8::String;
using v8::Local;
using v8::Object;
using v8::Array;
using v8::Value;
using v8::Boolean;

inline bool fileExists(const std::string& name) {
	if (FILE *file = fopen(name.c_str(), "r")) {
		fclose(file);
		return true;
	}
	else {
		return false;
	}
}

// Cairo write and read functions (to QBuffer)
static cairo_status_t readPngFromBuffer(void *closure, unsigned char *data, unsigned int length) {
	QBuffer *myBuffer = (QBuffer *)closure;
	size_t bytes_read;
	bytes_read = myBuffer->read((char *)data, length);
	if (bytes_read != length)
		return CAIRO_STATUS_READ_ERROR;

	return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t writePngToBuffer(void *closure, const unsigned char *data, unsigned int length) {
	QBuffer *myBuffer = (QBuffer *)closure;
	size_t bytes_wrote;
	bytes_wrote = myBuffer->write((char *)data, length);
	if (bytes_wrote != length)
		return CAIRO_STATUS_READ_ERROR;

	return CAIRO_STATUS_SUCCESS;
}

void createPdf(QBuffer *buffer, Poppler::Document *document) {
	ostringstream ss;

	Poppler::PDFConverter *converter = document->pdfConverter();
	converter->setPDFOptions(converter->pdfOptions() | Poppler::PDFConverter::WithChanges);
	converter->setOutputDevice(buffer);
	if (!converter->convert()) {
		// enum Error
		// {
		//     NoError,
		//     FileLockedError,
		//     OpenOutputError,
		//     NotSupportedInputFileError
		// };
		ss << "Error occurred when converting PDF: " << converter->lastError();
		delete converter;
		throw ss.str();
	}
	delete converter;
}

void createImgPdf(QBuffer *buffer, Poppler::Document *document) {
	// Calculate max page sizes. The output PDF will have its size set to max width/height.
	double maxWidth = 0;
	double maxHeight = 0;

	int n = document->numPages();

	for (int i = 0; i < n; i += 1) {
		Poppler::Page *page = document->page(i);

		QSizeF size = page->pageSizeF();

		if (size.height() > maxHeight)
			maxHeight = size.height();

		if (size.width() > maxWidth)
			maxWidth = size.width();
	}

	// Initialize Cairo writing surface, and since we have images at 360 DPI, we'll set scaling.
	cairo_surface_t *surface = cairo_pdf_surface_create_for_stream(writePngToBuffer, buffer, maxWidth, maxHeight);
	cairo_t *cr = cairo_create(surface);
	cairo_scale(cr, 0.2, 0.2);

	for (int i = 0; i < n; i += 1) {
		Poppler::Page *page = document->page(i);

		// Save the page as PNG image to buffer. (We could use QFile if we want to save images to files)
		QBuffer *pageImage = new QBuffer();
		pageImage->open(QIODevice::ReadWrite);
		QImage img = page->renderToImage(360, 360);
		img.save(pageImage, "png");
		pageImage->seek(0);  // Reading does not work if we don't reset the pointer

							 // Ookay, let's try to make new page out of the image
		cairo_surface_t *drawImageSurface = cairo_image_surface_create_from_png_stream(readPngFromBuffer, pageImage);
		cairo_set_source_surface(cr, drawImageSurface, 0, 0);
		cairo_paint(cr);
		cairo_surface_destroy(drawImageSurface);

		// Create new page if multipage document
		if (n > 0) {
			cairo_surface_show_page(surface);
			if (cr != NULL) {
				cairo_destroy(cr);
			}
			cr = cairo_create(surface);
			cairo_scale(cr, 0.2, 0.2);
		}

		pageImage->close();
		delete pageImage;

		delete page;
	}

	// Close Cairo
	cairo_destroy(cr);
	cairo_surface_finish(surface);
	cairo_surface_destroy(surface);
}

WriteFieldsParams v8ParamsToCpp(const Nan::FunctionCallbackInfo<v8::Value>& args) {
	Local<Object> parameters;
	string saveFormat = "imgpdf";
	map<string, string> fields;

	String::Utf8Value sourcePdfFileNameParam(args[0]->ToString());
	string sourcePdfFileName = string(*sourcePdfFileNameParam);

	Local<Object> changeFields = args[1]->ToObject();
	Local<String> saveStr = Nan::New("save").ToLocalChecked();

	// Check if any configuration parameters
	if (args.Length() > 2) {
		parameters = args[2]->ToObject();
		Local<Value> saveParam = Nan::Get(parameters, saveStr).ToLocalChecked();
		if (!saveParam->IsUndefined()) {
			String::Utf8Value saveFormatParam(Nan::Get(parameters, saveStr).ToLocalChecked());
			saveFormat = string(*saveFormatParam);
		}
	}

	// Convert form fields to c++ map
	Local<Array> fieldArray = changeFields->GetPropertyNames();
	for (uint32_t i = 0; i < fieldArray->Length(); i += 1) {
		Local<Value> name = fieldArray->Get(i);
		Local<Value> value = changeFields->Get(name);
		fields[std::string(*String::Utf8Value(name))] = std::string(*String::Utf8Value(value));
	}

	// Create and return PDF
	struct WriteFieldsParams params(sourcePdfFileName, saveFormat, fields);
	return params;
}

// Pdf creator that is not dependent on V8 internals (safe at async?)
QBuffer *writePdfFields(struct WriteFieldsParams params) {

	ostringstream ss;
	// If source file does not exist, throw error and return false
	if (!fileExists(params.sourcePdfFileName)) {
		ss << "File \"" << params.sourcePdfFileName << "\" does not exist";
		throw ss.str();
	}

	// Open document and return false and throw error if something goes wrong
	Poppler::Document *document = Poppler::Document::load(QString::fromStdString(params.sourcePdfFileName));
	if (document == NULL) {
		ss << "Error occurred when reading \"" << params.sourcePdfFileName << "\"";
		throw ss.str();
	}

	// Fill form
	int n = document->numPages();
	stringstream idSS;
	for (int i = 0; i < n; i += 1) {
		Poppler::Page *page = document->page(i);
		QList<Poppler::FormField *> formFields = page->formFields();

		foreach(Poppler::FormField *field, formFields) {
			string fieldName = field->fullyQualifiedName().toStdString();
			// Support writing fields by both fieldName and id.
			// If fieldName is not present in params, try id.
			if (params.fields.count(fieldName) == 0) {
				idSS << field->id();
				fieldName = idSS.str();
				idSS.str("");
				idSS.clear();
			}
			if (!field->isReadOnly() && field->isVisible() && params.fields.count(fieldName)) {
				// Text
				if (field->type() == Poppler::FormField::FormText) {
					Poppler::FormFieldText *textField = (Poppler::FormFieldText *) field;
					textField->setText(QString::fromUtf8(params.fields[fieldName].c_str()));
				}

				// Choice
				if (field->type() == Poppler::FormField::FormChoice) {
					Poppler::FormFieldChoice *choiceField = (Poppler::FormFieldChoice *) field;
					if (choiceField->isEditable()) {
						choiceField->setEditChoice(QString::fromUtf8(params.fields[fieldName].c_str()));
					}
					else {
						QStringList possibleChoices = choiceField->choices();
						QString proposedChoice = QString::fromUtf8(params.fields[fieldName].c_str());
						int index = possibleChoices.indexOf(proposedChoice);
						if (index >= 0) {
							QList<int> choiceList;
							choiceList << index;
							choiceField->setCurrentChoices(choiceList);
						}
					}
				}

				// Button
				// ! TODO ! Note. Poppler doesn't support checkboxes with hashtag names (aka using exportValue).
				if (field->type() == Poppler::FormField::FormButton) {
					Poppler::FormFieldButton* myButton = (Poppler::FormFieldButton *)field;
					switch (myButton->buttonType()) {
						// Push
					case Poppler::FormFieldButton::Push:     break;
					case Poppler::FormFieldButton::CheckBox:
						if (params.fields[fieldName].compare("true") == 0) {
							myButton->setState(true);
						}
						else {
							myButton->setState(false);
						}
						break;
					case Poppler::FormFieldButton::Radio:
						if (params.fields[fieldName].compare(myButton->caption().toUtf8().constData()) == 0) {
							myButton->setState(true);
						}
						else {
							myButton->setState(false);
						}
						break;
					}
				}
			}
		}

		qDeleteAll(formFields);
		delete page;
	}

	// Now save and return the document
	QBuffer *bufferDevice = new QBuffer();
	bufferDevice->open(QIODevice::ReadWrite);

	// Get save parameters
	if (params.saveFormat == "imgpdf") {
		createImgPdf(bufferDevice, document);
	}
	else {
		createPdf(bufferDevice, document);
	}

	delete document;

	return bufferDevice;
}

//***********************************
//
// Node.js methods
//
//***********************************

// Read PDF form fields
NAN_METHOD(ReadSync) {

	// expect a number as the first argument
	Nan::Utf8String *fileName = new Nan::Utf8String(info[0]);
	ostringstream ss;
	int n = 0;

	// If file does not exist, throw error and return false
	if (!fileExists(**fileName)) {
		ss << "File \"" << **fileName << "\" does not exist";
		Nan::ThrowError(Nan::New<String>(ss.str()).ToLocalChecked());
		info.GetReturnValue().Set(Nan::False());
	}

	// Open document and return false and throw error if something goes wrong
	Poppler::Document *document = Poppler::Document::load(**fileName);
	if (document != NULL) {
		// Get field list
		n = document->numPages();
	}
	else {
		ss << "Error occurred when reading \"" << **fileName << "\"";
		Nan::ThrowError(Nan::New<String>(ss.str()).ToLocalChecked());
		info.GetReturnValue().Set(Nan::False());
	}

	delete fileName;

	// Store field value objects to v8 array
	Local<Array> fieldArray = Nan::New<Array>();
	int fieldNum = 0;

	for (int i = 0; i < n; i += 1) {
		Poppler::Page *page = document->page(i);
		QList<Poppler::FormField *> formFields = page->formFields();

		foreach(Poppler::FormField *field, formFields) {

			if (!field->isReadOnly() && field->isVisible()) {

				// Make JavaScript object out of the fieldnames
				Local<Object> obj = Nan::New<Object>();
				Nan::Set(obj, Nan::New<String>("name").ToLocalChecked(), Nan::New<String>(field->fullyQualifiedName().toStdString()).ToLocalChecked());
				Nan::Set(obj, Nan::New<String>("page").ToLocalChecked(), Nan::New<Number>(i));

				// ! TODO ! Note. Poppler doesn't support checkboxes with hashtag names (aka using exportValue).
				string fieldType;
				// Set default value undefined
				Nan::Set(obj, Nan::New<String>("value").ToLocalChecked(), Nan::Undefined());
				Poppler::FormFieldButton *myButton;
				Poppler::FormFieldChoice *myChoice;

				Nan::Set(obj, Nan::New<String>("id").ToLocalChecked(), Nan::New<Number>(field->id()));
				switch (field->type()) {

					// FormButton
				case Poppler::FormField::FormButton:
					myButton = (Poppler::FormFieldButton *)field;
					switch (myButton->buttonType()) {
						// Push
					case Poppler::FormFieldButton::Push:        fieldType = "push_button";     break;
					case Poppler::FormFieldButton::CheckBox:
						fieldType = "checkbox";
						Nan::Set(obj, Nan::New<String>("value").ToLocalChecked(), Nan::New<Boolean>(myButton->state()));
						break;
					case Poppler::FormFieldButton::Radio:       fieldType = "radio";           break;
					}
					break;

					// FormText
				case Poppler::FormField::FormText:
					Nan::Set(obj, Nan::New<String>("value").ToLocalChecked(), Nan::New<String>(((Poppler::FormFieldText *)field)->text().toStdString()).ToLocalChecked());
					fieldType = "text";
					break;

					// FormChoice
				case Poppler::FormField::FormChoice: {
					Local<Array> choiceArray = Nan::New<Array>();
					myChoice = (Poppler::FormFieldChoice *)field;
					QStringList possibleChoices = myChoice->choices();
					for (int i = 0; i < possibleChoices.size(); i++) {
						Nan::Set(choiceArray, i, Nan::New<String>(possibleChoices.at(i).toStdString()).ToLocalChecked());
					}
					Nan::Set(obj, Nan::New<String>("choices").ToLocalChecked(), choiceArray);
					switch (myChoice->choiceType()) {
					case Poppler::FormFieldChoice::ComboBox:    fieldType = "combobox";       break;
					case Poppler::FormFieldChoice::ListBox:     fieldType = "listbox";        break;
					}
					break;
				}

													 // FormSignature
				case Poppler::FormField::FormSignature:         fieldType = "formsignature";  break;

				default:
					fieldType = "undefined";
					break;
				}

				Nan::Set(obj, Nan::New<String>("type").ToLocalChecked(), Nan::New<String>(fieldType.c_str()).ToLocalChecked());

				fieldArray->Set(fieldNum, obj);
				fieldNum++;

			}
		}

		qDeleteAll(formFields);
		delete page;
	}

	info.GetReturnValue().Set(fieldArray);

	delete document;
}

// Write PDF form fields
NAN_METHOD(WriteSync) {

	// Check and return parameters given at JavaScript function call
	WriteFieldsParams params = v8ParamsToCpp(info);

	// Create and return pdf
	try
	{
		QBuffer *buffer = writePdfFields(params);
		Local<Object> returnPdf = Nan::CopyBuffer((char *)buffer->data().data(), buffer->size()).ToLocalChecked();
		buffer->close();
		delete buffer;
		info.GetReturnValue().Set(returnPdf);
	}
	catch (string error)
	{
		Nan::ThrowError(Nan::New<String>(error).ToLocalChecked());
		info.GetReturnValue().Set(Nan::Null());
	}
}
<|endoftext|>


<commit_before>#include "RFormatter.h"
#include "RFlashStringRef.h"
#include "RStringRef.h"
#include "RConstStringRef.h"
#include <Print.h>

RFormatter::RFormatter(Print *print)
  : mPrint(print), mFormat(NULL), mFormatIndex(0)
{
}

RFormatter &
RFormatter::operator ()(const char *format)
{
  mFormat.reset(new RConstStringRef(format));
  // If this message does not have any format mark, we just print the
  // whole string.
  printBeforeNextMark();
  return *this;
}

RFormatter &
RFormatter::operator ()(const rfchar *format)
{
  mFormat.reset(new RFlashStringRef(format));
  // If this message does not have any format mark, we just print the
  // whole string.
  printBeforeNextMark();
  return *this;
}

RFormatter &
RFormatter::operator ()(const String *format)
{
  mFormat.reset(new RStringRef(format));
  // If this message does not have any format mark, we just print the
  // whole string.
  printBeforeNextMark();
  return *this;
}

bool
RFormatter::printBeforeNextMark()
{
  if(!mFormat)
  {
    // Do nothing if don't have a format string
    return false;
  }

  char c;
  char nextChar;

  while(1)
  {
    c = mFormat->charAt(mFormatIndex);

    if('\0' == c)
    {
      break;
    }

    if('%' == c)
    {
      ++mFormatIndex;

      nextChar = mFormat->charAt(mFormatIndex);

      if('%' == nextChar)
      {
        // '%%' means one '%'
        mPrint->write(nextChar);
        ++mFormatIndex;
      }
      else if('s' == nextChar)
      {
        // Found replacement mark : "%s"
        --mFormatIndex;  // Jump to forward "%"
        return true;
      }
      else if('\0' == nextChar)
      {
        mPrint->write(c);
        break;
      }
      else
      {
        mPrint->write(c);
        mPrint->write(nextChar);
        ++mFormatIndex;
      }
    }
    else
    {
      mPrint->write(c);
      ++mFormatIndex;
    }
  }

  // The format finished.
  // Free the string reference object as soon as possible, because we are
  // running on resource limitted system.
  mFormat.clear();

  return false;
}
<commit_msg>RFormatter: Not working after second time<commit_after>#include "RFormatter.h"
#include "RFlashStringRef.h"
#include "RStringRef.h"
#include "RConstStringRef.h"
#include <Print.h>

RFormatter::RFormatter(Print *print)
  : mPrint(print), mFormat(NULL), mFormatIndex(0)
{
}

RFormatter &
RFormatter::operator ()(const char *format)
{
  mFormat.reset(new RConstStringRef(format));
  // If this message does not have any format mark, we just print the
  // whole string.
  printBeforeNextMark();
  return *this;
}

RFormatter &
RFormatter::operator ()(const rfchar *format)
{
  mFormat.reset(new RFlashStringRef(format));
  // If this message does not have any format mark, we just print the
  // whole string.
  printBeforeNextMark();
  return *this;
}

RFormatter &
RFormatter::operator ()(const String *format)
{
  mFormat.reset(new RStringRef(format));
  // If this message does not have any format mark, we just print the
  // whole string.
  printBeforeNextMark();
  return *this;
}

bool
RFormatter::printBeforeNextMark()
{
  if(!mFormat)
  {
    // Do nothing if don't have a format string
    return false;
  }

  char c;
  char nextChar;

  while(1)
  {
    c = mFormat->charAt(mFormatIndex);

    if('\0' == c)
    {
      break;
    }

    if('%' == c)
    {
      ++mFormatIndex;

      nextChar = mFormat->charAt(mFormatIndex);

      if('%' == nextChar)
      {
        // '%%' means one '%'
        mPrint->write(nextChar);
        ++mFormatIndex;
      }
      else if('s' == nextChar)
      {
        // Found replacement mark : "%s"
        --mFormatIndex;  // Jump to forward "%"
        return true;
      }
      else if('\0' == nextChar)
      {
        mPrint->write(c);
        break;
      }
      else
      {
        mPrint->write(c);
        mPrint->write(nextChar);
        ++mFormatIndex;
      }
    }
    else
    {
      mPrint->write(c);
      ++mFormatIndex;
    }
  }

  // The format finished.
  // Free the string reference object as soon as possible, because we are
  // running on resource limitted system.
  mFormat.clear();
  mFormatIndex = 0;

  return false;
}
<|endoftext|>


<commit_before>/*
  User Server code for CMPT 276 Group Assignment, Spring 2016.

  This server manages a user’s social networking session.

  This server supports sign on/off, add friend, unfriend, update status,
  get user's friend list.

  This server handles disallowed method malformed request.
*/

#include <exception>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <string>

#include <cpprest/base_uri.h>
#include <cpprest/http_listener.h>
#include <cpprest/json.h>

#include <pplx/pplxtasks.h>

#include <was/common.h>
#include <was/storage_account.h>
#include <was/table.h>

#include "../include/TableCache.h"

#include "../include/azure_keys.h"

#include "../include/ServerUtils.h"

#include "../include/UserUtils.h"

using azure::storage::cloud_storage_account;
using azure::storage::storage_credentials;
using azure::storage::storage_exception;
using azure::storage::cloud_table;
using azure::storage::cloud_table_client;
using azure::storage::edm_type;
using azure::storage::entity_property;
using azure::storage::table_entity;
using azure::storage::table_operation;
using azure::storage::table_query;
using azure::storage::table_query_iterator;
using azure::storage::table_result;

using pplx::extensibility::critical_section_t;
using pplx::extensibility::scoped_critical_section_t;

using std::cin;
using std::cout;
using std::endl;
using std::getline;
using std::make_pair;
using std::pair;
using std::string;
using std::unordered_map;
using std::vector;

using web::http::http_headers;
using web::http::http_request;
using web::http::methods;
using web::http::status_codes;
using web::http::uri;

using web::json::value;

using web::http::experimental::listener::http_listener;

using prop_vals_t = vector<pair<string,value>>;

constexpr const char* def_url = "http://localhost:34572";

const string sign_on {"SignOn"}; //POST
const string sign_off {"SignOff"}; //POST

const string add_friend {"AddFriend"}; // PUT
const string unfriend {"UnFriend"}; //PUT
const string update_status {"UpdateStatus"}; //PUT

const string get_friend_list {"ReadFriendList"}; //GET

bool check_active (string userid){
  bool active = true;

  if(true /*token DNE*/) {
    active = false;
  }

  if(true /*entry DNE*/) {
    active = false;
  }

  return active;

}

void handle_post (http_request message){
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);

  if(true/*basic criteria*/){}
  else if (paths[0] == sign_on) {}
  else if (paths[0] == sign_off) {}
  else {
    // malformed request
    vector<value> vec;
    message.reply(status_codes::BadRequest, value::array(vec));
    return;
  }
}

void handle_put (http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);

  if(true/*basic criteria*/){}
  else if (paths[0] == add_friend) {}
  else if (paths[0] == unfriend) {}
  else if (paths[0] == update_status) {}
  else {
    // malformed request
    vector<value> vec;
    message.reply(status_codes::BadRequest, value::array(vec));
    return;
  }
}

void handle_get (http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);
  vector<value> vec;

  if (paths.size() < 2 || paths[0] != get_friend_list) {
    // malformed request
    message.reply(status_codes::BadRequest, value::array(vec));
    return;
  }

  const string userid = paths[1]; // obtains userid (parameter)

  // user not signed in -- The auth server does not return a token and the expected record doesn't exist in DataTable
  bool active = check_active(userid);

  if(!active) {
    message.reply(status_codes::Forbidden, value::array(vec));
    return;
  }
  else{ // if user is active
    // reads friends and parse

    message.reply(status_codes::OK, value::array(vec));
    return;
  }
}

int main (int argc, char const * argv[]) {
  cout << "Opening listener" << endl;
  http_listener listener {def_url};
  listener.support(methods::GET, &handle_get); // Get user's friend list
  listener.support(methods::POST, &handle_post); // SignOn, SignOff
  listener.support(methods::PUT, &handle_put); // Add friend, Unfriend, Update Status
  /*TO DO: Disallowed method*/
  listener.open().wait(); // Wait for listener to complete starting

  cout << "Enter carriage return to stop server." << endl;
  string line;
  getline(std::cin, line);

  // Shut it down
  listener.close().wait();
  cout << "Closed" << endl;
}
<commit_msg>commit before pulling and merging from master<commit_after>/*
  User Server code for CMPT 276 Group Assignment, Spring 2016.

  This server manages a user’s social networking session.

  This server supports sign on/off, add friend, unfriend, update status,
  get user's friend list.

  This server handles disallowed method malformed request.
*/

#include <exception>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <cpprest/http_listener.h>
#include <cpprest/json.h>
#include <string>

#include <cpprest/base_uri.h>

#include <pplx/pplxtasks.h>

#include <was/common.h>
#include <was/storage_account.h>
#include <was/table.h>

#include "../include/TableCache.h"

#include "../include/azure_keys.h"

#include "../include/ServerUtils.h"

#include "../include/UserUtils.h"

// Do we need to?

using azure::storage::cloud_storage_account;
using azure::storage::storage_credentials;
using azure::storage::storage_exception;
using azure::storage::cloud_table;
using azure::storage::cloud_table_client;
using azure::storage::edm_type;
using azure::storage::entity_property;
using azure::storage::table_entity;
using azure::storage::table_operation;
using azure::storage::table_query;
using azure::storage::table_query_iterator;
using azure::storage::table_result;

using pplx::extensibility::critical_section_t;
using pplx::extensibility::scoped_critical_section_t;

using std::cin;
using std::cout;
using std::endl;
using std::getline;
using std::make_pair;
using std::pair;
using std::string;
using std::unordered_map;
using std::vector;

using web::http::http_headers;
using web::http::http_request;
using web::http::methods;
using web::http::status_codes;
using web::http::uri;

using web::json::value;

using web::http::experimental::listener::http_listener;

using prop_vals_t = vector<pair<string,value>>;

constexpr const char* def_url = "http://localhost:34572";

const string sign_on {"SignOn"}; //POST
const string sign_off {"SignOff"}; //POST

const string add_friend {"AddFriend"}; // PUT
const string unfriend {"UnFriend"}; //PUT
const string update_status {"UpdateStatus"}; //PUT

const string get_friend_list {"ReadFriendList"}; //GET

bool check_active (string userid){
  bool active = true;

  if(true /*token DNE*/) {
    active = false;
  }

  if(true /*entry DNE*/) {
    active = false;
  }

  return active;
}

void handle_post (http_request message){
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);

  if(true/*basic criteria*/){}
  else if (paths[0] == sign_on) {}
  else if (paths[0] == sign_off) {}
  else {
    // malformed request
    vector<value> vec;
    message.reply(status_codes::BadRequest, value::array(vec));
    return;
  }
}

void handle_put (http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);

  if(true/*basic criteria*/){}
  else if (paths[0] == add_friend) {}
  else if (paths[0] == unfriend) {}
  else if (paths[0] == update_status) {}
  else {
    // malformed request
    vector<value> vec;
    message.reply(status_codes::BadRequest, value::array(vec));
    return;
  }
}

void handle_get (http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);
  vector<value> vec;

  if (paths.size() != 2 || paths[0] != get_friend_list) {
    // malformed request
    message.reply(status_codes::BadRequest, value::array(vec));
    return;
  }

  const string userid = paths[1]; // obtains userid (parameter)

  // user not signed in -- The auth server does not return a token and the expected record doesn't exist in DataTable
  bool active = check_active(userid);

  if(!active) {
    message.reply(status_codes::Forbidden, value::array(vec));
    return;
  }
  else{ // if user is active
    // reads friends and parse

    message.reply(status_codes::OK, value::array(vec));
    return;
  }
}

int main (int argc, char const * argv[]) {
  cout << "Opening listener" << endl;
  http_listener listener {def_url};
  listener.support(methods::GET, &handle_get); // Get user's friend list
  listener.support(methods::POST, &handle_post); // SignOn, SignOff
  listener.support(methods::PUT, &handle_put); // Add friend, Unfriend, Update Status
  /*TO DO: Disallowed method*/
  listener.open().wait(); // Wait for listener to complete starting

  cout << "Enter carriage return to stop server." << endl;
  string line;
  getline(std::cin, line);

  // Shut it down
  listener.close().wait();
  cout << "Closed" << endl;
}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2013 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "allocators.h"

#ifdef WIN32
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0501
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
// This is used to attempt to keep keying material out of swap
// Note that VirtualLock does not provide this as a guarantee on Windows,
// but, in practice, memory that has been VirtualLock'd almost never gets written to
// the pagefile except in rare circumstances where memory is extremely low.
#else
#include <sys/mman.h>
#include <limits.h> // for PAGESIZE
#include <unistd.h> // for sysconf
#endif

LockedPageManager* LockedPageManager::_instance = NULL;
boost::once_flag LockedPageManager::init_flag = BOOST_ONCE_INIT;

/** Determine system page size in bytes */
static inline size_t GetSystemPageSize()
{
    size_t page_size;
#if defined(WIN32)
    SYSTEM_INFO sSysInfo;
    GetSystemInfo(&sSysInfo);
    page_size = sSysInfo.dwPageSize;
#elif defined(PAGESIZE) // defined in limits.h
    page_size = PAGESIZE;
#else // assume some POSIX OS
    page_size = sysconf(_SC_PAGESIZE);
#endif
    return page_size;
}

bool MemoryPageLocker::Lock(const void *addr, size_t len)
{
#ifdef WIN32
    return VirtualLock(const_cast<void*>(addr), len);
#else
    return mlock(addr, len) == 0;
#endif
}

bool MemoryPageLocker::Unlock(const void *addr, size_t len)
{
#ifdef WIN32
    return VirtualUnlock(const_cast<void*>(addr), len);
#else
    return munlock(addr, len) == 0;
#endif
}

LockedPageManager::LockedPageManager() : LockedPageManagerBase<MemoryPageLocker>(GetSystemPageSize())
{
}
<commit_msg>Fixing compiler warning C4800 in allocators.cpp<commit_after>// Copyright (c) 2009-2013 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "allocators.h"

#ifdef WIN32
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0501
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
// This is used to attempt to keep keying material out of swap
// Note that VirtualLock does not provide this as a guarantee on Windows,
// but, in practice, memory that has been VirtualLock'd almost never gets written to
// the pagefile except in rare circumstances where memory is extremely low.
#else
#include <sys/mman.h>
#include <limits.h> // for PAGESIZE
#include <unistd.h> // for sysconf
#endif

LockedPageManager* LockedPageManager::_instance = NULL;
boost::once_flag LockedPageManager::init_flag = BOOST_ONCE_INIT;

/** Determine system page size in bytes */
static inline size_t GetSystemPageSize()
{
    size_t page_size;
#if defined(WIN32)
    SYSTEM_INFO sSysInfo;
    GetSystemInfo(&sSysInfo);
    page_size = sSysInfo.dwPageSize;
#elif defined(PAGESIZE) // defined in limits.h
    page_size = PAGESIZE;
#else // assume some POSIX OS
    page_size = sysconf(_SC_PAGESIZE);
#endif
    return page_size;
}

bool MemoryPageLocker::Lock(const void *addr, size_t len)
{
#ifdef WIN32
    return VirtualLock(const_cast<void*>(addr), len) != 0;
#else
    return mlock(addr, len) == 0;
#endif
}

bool MemoryPageLocker::Unlock(const void *addr, size_t len)
{
#ifdef WIN32
    return VirtualUnlock(const_cast<void*>(addr), len) != 0;
#else
    return munlock(addr, len) == 0;
#endif
}

LockedPageManager::LockedPageManager() : LockedPageManagerBase<MemoryPageLocker>(GetSystemPageSize())
{
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "third_party/zlib/google/zip.h"
#include "third_party/zlib/zlib.h"
#include "content/nw/src/api/app/app.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/values.h"
#include "content/nw/src/api/api_messages.h"
#include "content/nw/src/browser/native_window.h"
#include "content/nw/src/browser/net_disk_cache_remover.h"
#include "content/nw/src/nw_package.h"
#include "content/nw/src/nw_shell.h"
#include "content/nw/src/shell_browser_context.h"
#include "content/common/view_messages.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/render_process_host.h"
#if defined(OS_WIN)
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <stdio.h>
#endif

using base::MessageLoop;
using content::Shell;
using content::ShellBrowserContext;
using content::RenderProcessHost;

namespace api {

namespace {

// Get render process host.
RenderProcessHost* GetRenderProcessHost() {
  RenderProcessHost* render_process_host = NULL;
  std::vector<Shell*> windows = Shell::windows();
  for (size_t i = 0; i < windows.size(); ++i) {
    if (!windows[i]->is_devtools()) {
      render_process_host = windows[i]->web_contents()->GetRenderProcessHost();
      break;
    }
  }

  return render_process_host;
}

void GetRenderProcessHosts(std::set<RenderProcessHost*>& rphs) {
  RenderProcessHost* render_process_host = NULL;
  std::vector<Shell*> windows = Shell::windows();
  for (size_t i = 0; i < windows.size(); ++i) {
    if (!windows[i]->is_devtools()) {
      render_process_host = windows[i]->web_contents()->GetRenderProcessHost();
      rphs.insert(render_process_host);
    }
  }
}

}  // namespace

// static
void App::Call(const std::string& method,
               const base::ListValue& arguments) {
  if (method == "Quit") {
    Quit();
    return;
  } else if (method == "CloseAllWindows") {
    CloseAllWindows();
    return;
  }
  NOTREACHED() << "Calling unknown method " << method << " of App";
}

// static
void App::Call(Shell* shell,
               const std::string& method,
               const base::ListValue& arguments,
               base::ListValue* result) {
  if (method == "GetDataPath") {
    ShellBrowserContext* browser_context =
      static_cast<ShellBrowserContext*>(shell->web_contents()->GetBrowserContext());
    result->AppendString(browser_context->GetPath().value());
    return;
  }else if (method == "GetArgv") {
    nw::Package* package = shell->GetPackage();
    CommandLine* command_line = CommandLine::ForCurrentProcess();
    CommandLine::StringVector args = command_line->GetArgs();
    CommandLine::StringVector argv = command_line->original_argv();

    // Ignore first non-switch arg if it's not a standalone package.
    bool ignore_arg = !package->self_extract();
    for (unsigned i = 1; i < argv.size(); ++i) {
      if (ignore_arg && argv[i] == args[0]) {
        ignore_arg = false;
        continue;
      }

      result->AppendString(argv[i]);
    }

    return;
  } else if (method == "Zip") {
    std::string zipdir;
    std::string zipfile;
    arguments.GetString(0,&zipdir);
    arguments.GetString(1,&zipfile);
    result->AppendBoolean(zip::Zip(base::FilePath::FromUTF8Unsafe(zipdir), base::FilePath::FromUTF8Unsafe(zipfile), true));
    return;
  } else if (method == "Unzip") {
    std::string zipfile;
    std::string zipdir;
    arguments.GetString(0,&zipfile);
    arguments.GetString(1,&zipdir);
    result->AppendBoolean(zip::Unzip(base::FilePath::FromUTF8Unsafe(zipfile), base::FilePath::FromUTF8Unsafe(zipdir)));
    return;
  } else if (method == "Gzip") {
	  std::string ssrc;
	  std::string sdst;
	  unsigned char buffer[0x1000];
	  int bytes_read = 1, bytes_written = 1;

	  arguments.GetString(0,&ssrc);
	  arguments.GetString(1,&sdst);
#if defined(OS_WIN)
    int src = _open(ssrc.c_str(), _O_RDONLY);
	  int dst = _open(sdst.c_str(), _O_WRONLY|_O_CREAT|_O_TRUNC);
#else
    int src = open(ssrc.c_str(), O_RDONLY);
	  int dst = open(sdst.c_str(), O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
#endif
	  gzFile zDst = gzdopen(dst, "w");

	  if(zDst == NULL || src == -1) {
		  result->AppendBoolean(false);
		  return;
	  }

	  while(bytes_read > 0 && bytes_written > 0) {
#if defined(OS_WIN)
      bytes_read = _read(src,&buffer,0x1000);
#else
		  bytes_read = read(src,&buffer,0x1000);
#endif
		  bytes_written = gzwrite(zDst,&buffer,bytes_read);
	  }
#if defined(OS_WIN)
	  _close(src);
#else
    close(src);
#endif
	  gzflush(zDst, Z_FINISH);
	  gzclose(zDst);
	  result->AppendBoolean(bytes_read != -1 && bytes_written != -1);
	  return;
  } else if (method == "Ungzip") {
	  std::string ssrc;
	  std::string sdst;
	  unsigned char buffer[0x1000];
	  int bytes_read = 1, bytes_written = 1, eof = 0;

	  arguments.GetString(0,&ssrc);
	  arguments.GetString(1,&sdst);

#if defined(OS_WIN)
    int src = _open(ssrc.c_str(), _O_RDONLY);
	  int dst = _open(sdst.c_str(), _O_WRONLY|_O_CREAT|_O_TRUNC);
#else
	  int src = open(ssrc.c_str(), O_RDONLY);
	  int dst = open(sdst.c_str(), O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
#endif
	  gzFile zSrc = gzdopen(src, "r");

	  if(zSrc == NULL || dst == -1) {
		  result->AppendBoolean(false);
		  return;
	  }

	  while(eof == 0 &&
			bytes_read > 0 &&
			bytes_written > 0) {
		  bytes_read = gzread(zSrc,&buffer,0x1000);
#if defined(OS_WIN)
		  bytes_written = _write(dst,&buffer,bytes_read);
#else
      bytes_written = write(dst,&buffer,bytes_read);
#endif
		  eof = gzeof(zSrc);
	  }
#if defined(OS_WIN)
	  _close(dst);
#else
    close(dst);
#endif
	  gzclose(zSrc);
	  result->AppendBoolean(eof==1);
	  return;
  } else if (method == "ClearCache") {
    ClearCache(GetRenderProcessHost());
  } else if (method == "GetPackage") {
    result->AppendString(shell->GetPackage()->package_string());
    return;
  }

  NOTREACHED() << "Calling unknown sync method " << method << " of App";
}

// static
void App::CloseAllWindows(bool force) {
  std::vector<Shell*> windows = Shell::windows();

  for (size_t i = 0; i < windows.size(); ++i) {
    // Only send close event to browser windows, since devtools windows will
    // be automatically closed.
    if (!windows[i]->is_devtools()) {
      // If there is no js object bound to the window, then just close.
      if (force || windows[i]->ShouldCloseWindow())
        // we used to delete the Shell object here
        // but it should be deleted on native window destruction
        windows[i]->window()->Close();
    }
  }
  if (force) {
    // in a special force close case, since we're going to exit the
    // main loop soon, we should delete the shell object asap so the
    // render widget can be closed on the renderer side
    windows = Shell::windows();
    for (size_t i = 0; i < windows.size(); ++i) {
      if (!windows[i]->is_devtools())
        delete windows[i];
    }
  }
}

// static
void App::Quit(RenderProcessHost* render_process_host) {
  // Send the quit message.
  int no_use;
  if (render_process_host) {
    render_process_host->Send(new ViewMsg_WillQuit(&no_use));
  }else{
    std::set<RenderProcessHost*> rphs;
    std::set<RenderProcessHost*>::iterator it;

    GetRenderProcessHosts(rphs);
    for (it = rphs.begin(); it != rphs.end(); it++) {
      RenderProcessHost* rph = *it;
      DCHECK(rph != NULL);

      rph->Send(new ViewMsg_WillQuit(&no_use));
    }
    CloseAllWindows(true);
  }
  // Then quit.
  MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
}

// static
void App::EmitOpenEvent(const std::string& path) {
  std::set<RenderProcessHost*> rphs;
  std::set<RenderProcessHost*>::iterator it;

  GetRenderProcessHosts(rphs);
  for (it = rphs.begin(); it != rphs.end(); it++) {
    RenderProcessHost* rph = *it;
    DCHECK(rph != NULL);

    rph->Send(new ShellViewMsg_Open(path));
  }
}

void App::ClearCache(content::RenderProcessHost* render_process_host) {
  render_process_host->Send(new ShellViewMsg_ClearCache());
  nw::RemoveHttpDiskCache(render_process_host->GetBrowserContext(),
                          render_process_host->GetID());
}

}  // namespace api
<commit_msg>Changes to gzip buffer to fix not writing footer properly<commit_after>// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "third_party/zlib/google/zip.h"
#include "third_party/zlib/zlib.h"
#include "content/nw/src/api/app/app.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/values.h"
#include "content/nw/src/api/api_messages.h"
#include "content/nw/src/browser/native_window.h"
#include "content/nw/src/browser/net_disk_cache_remover.h"
#include "content/nw/src/nw_package.h"
#include "content/nw/src/nw_shell.h"
#include "content/nw/src/shell_browser_context.h"
#include "content/common/view_messages.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/render_process_host.h"
#if defined(OS_WIN)
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <stdio.h>
#endif

using base::MessageLoop;
using content::Shell;
using content::ShellBrowserContext;
using content::RenderProcessHost;

namespace api {

namespace {

// Get render process host.
RenderProcessHost* GetRenderProcessHost() {
  RenderProcessHost* render_process_host = NULL;
  std::vector<Shell*> windows = Shell::windows();
  for (size_t i = 0; i < windows.size(); ++i) {
    if (!windows[i]->is_devtools()) {
      render_process_host = windows[i]->web_contents()->GetRenderProcessHost();
      break;
    }
  }

  return render_process_host;
}

void GetRenderProcessHosts(std::set<RenderProcessHost*>& rphs) {
  RenderProcessHost* render_process_host = NULL;
  std::vector<Shell*> windows = Shell::windows();
  for (size_t i = 0; i < windows.size(); ++i) {
    if (!windows[i]->is_devtools()) {
      render_process_host = windows[i]->web_contents()->GetRenderProcessHost();
      rphs.insert(render_process_host);
    }
  }
}

}  // namespace

// static
void App::Call(const std::string& method,
               const base::ListValue& arguments) {
  if (method == "Quit") {
    Quit();
    return;
  } else if (method == "CloseAllWindows") {
    CloseAllWindows();
    return;
  }
  NOTREACHED() << "Calling unknown method " << method << " of App";
}

// static
void App::Call(Shell* shell,
               const std::string& method,
               const base::ListValue& arguments,
               base::ListValue* result) {
  if (method == "GetDataPath") {
    ShellBrowserContext* browser_context =
      static_cast<ShellBrowserContext*>(shell->web_contents()->GetBrowserContext());
    result->AppendString(browser_context->GetPath().value());
    return;
  }else if (method == "GetArgv") {
    nw::Package* package = shell->GetPackage();
    CommandLine* command_line = CommandLine::ForCurrentProcess();
    CommandLine::StringVector args = command_line->GetArgs();
    CommandLine::StringVector argv = command_line->original_argv();

    // Ignore first non-switch arg if it's not a standalone package.
    bool ignore_arg = !package->self_extract();
    for (unsigned i = 1; i < argv.size(); ++i) {
      if (ignore_arg && argv[i] == args[0]) {
        ignore_arg = false;
        continue;
      }

      result->AppendString(argv[i]);
    }

    return;
  } else if (method == "Zip") {
    std::string zipdir;
    std::string zipfile;
    arguments.GetString(0,&zipdir);
    arguments.GetString(1,&zipfile);
    result->AppendBoolean(zip::Zip(base::FilePath::FromUTF8Unsafe(zipdir), base::FilePath::FromUTF8Unsafe(zipfile), true));
    return;
  } else if (method == "Unzip") {
    std::string zipfile;
    std::string zipdir;
    arguments.GetString(0,&zipfile);
    arguments.GetString(1,&zipdir);
    result->AppendBoolean(zip::Unzip(base::FilePath::FromUTF8Unsafe(zipfile), base::FilePath::FromUTF8Unsafe(zipdir)));
    return;
  } else if (method == "Gzip") {
	  std::string ssrc;
	  std::string sdst;
	  unsigned char buffer[0x1000];
	  int bytes_read = 1, bytes_written = 1;

	  arguments.GetString(0,&ssrc);
	  arguments.GetString(1,&sdst);
#if defined(OS_WIN)
	  int src = _open(ssrc.c_str(), _O_RDONLY);
	  int dst = _open(sdst.c_str(), _O_WRONLY|_O_CREAT|_O_TRUNC);
#else
	  int src = open(ssrc.c_str(), O_RDONLY);
	  int dst = open(sdst.c_str(), O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
#endif
	  gzFile zDst = gzdopen(dst, "w");
	  if(gzbuffer(zDst, 0x1000)==-1) {
		  result->AppendBoolean(false);
		  return;
	  }
	  if(gzsetparams(zDst, Z_BEST_COMPRESSION, Z_DEFAULT_STRATEGY) != Z_OK) {
		  result->AppendBoolean(false);
		  return;
	  }
	  if(zDst == NULL || src == -1) {
		  result->AppendBoolean(false);
		  return;
	  }

	  while(bytes_read > 0 && bytes_written > 0) {
#if defined(OS_WIN)
		  bytes_read = _read(src,&buffer,0x1000);
#else
		  bytes_read = read(src,&buffer,0x1000);
#endif
		  bytes_written = gzwrite(zDst,&buffer,bytes_read);
	  }
#if defined(OS_WIN)
	  _close(src);
#else
	  close(src);
#endif
	  //gzflush(zDst, Z_FINISH);
	  gzclose(zDst);
	  result->AppendBoolean(bytes_read != -1 && bytes_written != -1);
	  return;
  } else if (method == "Ungzip") {
	  std::string ssrc;
	  std::string sdst;
	  unsigned char buffer[0x1000];
	  int bytes_read = 1, bytes_written = 1, eof = 0;

	  arguments.GetString(0,&ssrc);
	  arguments.GetString(1,&sdst);

#if defined(OS_WIN)
    int src = _open(ssrc.c_str(), _O_RDONLY);
	  int dst = _open(sdst.c_str(), _O_WRONLY|_O_CREAT|_O_TRUNC);
#else
	  int src = open(ssrc.c_str(), O_RDONLY);
	  int dst = open(sdst.c_str(), O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
#endif
	  gzFile zSrc = gzdopen(src, "r");
	  if(gzbuffer(zSrc, 0x1000)==-1) {
		  result->AppendBoolean(false);
		  return;
	  }

	  if(zSrc == NULL || dst == -1) {
		  result->AppendBoolean(false);
		  return;
	  }

	  while(eof == 0 &&
			bytes_read > 0 &&
			bytes_written > 0) {
		  bytes_read = gzread(zSrc,&buffer,0x1000);
#if defined(OS_WIN)
		  bytes_written = _write(dst,&buffer,bytes_read);
#else
		  bytes_written = write(dst,&buffer,bytes_read);
#endif
		  eof = gzeof(zSrc);
	  }
#if defined(OS_WIN)
	  _close(dst);
#else
	  close(dst);
#endif
	  gzclose(zSrc);
	  result->AppendBoolean(eof==1);
	  return;
  } else if (method == "ClearCache") {
    ClearCache(GetRenderProcessHost());
  } else if (method == "GetPackage") {
    result->AppendString(shell->GetPackage()->package_string());
    return;
  }

  NOTREACHED() << "Calling unknown sync method " << method << " of App";
}

// static
void App::CloseAllWindows(bool force) {
  std::vector<Shell*> windows = Shell::windows();

  for (size_t i = 0; i < windows.size(); ++i) {
    // Only send close event to browser windows, since devtools windows will
    // be automatically closed.
    if (!windows[i]->is_devtools()) {
      // If there is no js object bound to the window, then just close.
      if (force || windows[i]->ShouldCloseWindow())
        // we used to delete the Shell object here
        // but it should be deleted on native window destruction
        windows[i]->window()->Close();
    }
  }
  if (force) {
    // in a special force close case, since we're going to exit the
    // main loop soon, we should delete the shell object asap so the
    // render widget can be closed on the renderer side
    windows = Shell::windows();
    for (size_t i = 0; i < windows.size(); ++i) {
      if (!windows[i]->is_devtools())
        delete windows[i];
    }
  }
}

// static
void App::Quit(RenderProcessHost* render_process_host) {
  // Send the quit message.
  int no_use;
  if (render_process_host) {
    render_process_host->Send(new ViewMsg_WillQuit(&no_use));
  }else{
    std::set<RenderProcessHost*> rphs;
    std::set<RenderProcessHost*>::iterator it;

    GetRenderProcessHosts(rphs);
    for (it = rphs.begin(); it != rphs.end(); it++) {
      RenderProcessHost* rph = *it;
      DCHECK(rph != NULL);

      rph->Send(new ViewMsg_WillQuit(&no_use));
    }
    CloseAllWindows(true);
  }
  // Then quit.
  MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
}

// static
void App::EmitOpenEvent(const std::string& path) {
  std::set<RenderProcessHost*> rphs;
  std::set<RenderProcessHost*>::iterator it;

  GetRenderProcessHosts(rphs);
  for (it = rphs.begin(); it != rphs.end(); it++) {
    RenderProcessHost* rph = *it;
    DCHECK(rph != NULL);

    rph->Send(new ShellViewMsg_Open(path));
  }
}

void App::ClearCache(content::RenderProcessHost* render_process_host) {
  render_process_host->Send(new ShellViewMsg_ClearCache());
  nw::RemoveHttpDiskCache(render_process_host->GetBrowserContext(),
                          render_process_host->GetID());
}

}  // namespace api
<|endoftext|>