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

// Include automatically generated configuration file if running autoconf.
#ifdef HAVE_CONFIG_H
#  include "config_auto.h"
#endif

#include "scrollview.h"

#include "svutil.h" // for SVNetwork

#include <allheaders.h>

#include <algorithm>
#include <climits>
#include <cstdarg>
#include <cstring>
#include <map>
#include <mutex> // for std::mutex
#include <string>
#include <thread> // for std::thread
#include <utility>
#include <vector>

namespace tesseract {

const int kSvPort = 8461;
const int kMaxMsgSize = 4096;
const int kMaxIntPairSize = 45; // Holds %d,%d, for up to 64 bit.

struct SVPolyLineBuffer {
  bool empty; // Independent indicator to allow SendMsg to call SendPolygon.
  std::vector<int> xcoords;
  std::vector<int> ycoords;
};

// A map between the window IDs and their corresponding pointers.
static std::map<int, ScrollView *> svmap;
static std::mutex *svmap_mu;
// A map of all semaphores waiting for a specific event on a specific window.
static std::map<std::pair<ScrollView *, SVEventType>, std::pair<SVSemaphore *, SVEvent *>>
    waiting_for_events;
static std::mutex *waiting_for_events_mu;

SVEvent *SVEvent::copy() {
  auto *any = new SVEvent;
  any->command_id = command_id;
  any->counter = counter;
  any->parameter = new char[strlen(parameter) + 1];
  strcpy(any->parameter, parameter);
  any->type = type;
  any->x = x;
  any->y = y;
  any->x_size = x_size;
  any->y_size = y_size;
  any->window = window;
  return any;
}

// Destructor.
// It is defined here, so the compiler can create a single vtable
// instead of weak vtables in every compilation unit.
SVEventHandler::~SVEventHandler() = default;

#ifndef GRAPHICS_DISABLED
/// This is the main loop which handles the ScrollView-logic from the server
/// to the client. It basically loops through messages, parses them to events
/// and distributes it to the waiting handlers.
/// It is run from a different thread and synchronizes via SVSync.
void ScrollView::MessageReceiver() {
  int counter_event_id = 0; // ongoing counter
  char *message = nullptr;
  // Wait until a new message appears in the input stream_.
  do {
    message = ScrollView::GetStream()->Receive();
  } while (message == nullptr);

  // This is the main loop which iterates until the server is dead (strlen =
  // -1). It basically parses for 3 different messagetypes and then distributes
  // the events accordingly.
  while (true) {
    // The new event we create.
    auto *cur = new SVEvent;
    // The ID of the corresponding window.
    int window_id;

    int ev_type;

    int n;
    // Fill the new SVEvent properly.
    sscanf(message, "%d,%d,%d,%d,%d,%d,%d,%n", &window_id, &ev_type, &cur->x, &cur->y, &cur->x_size,
           &cur->y_size, &cur->command_id, &n);
    char *p = (message + n);

    svmap_mu->lock();
    cur->window = svmap[window_id];

    if (cur->window != nullptr) {
      auto length = strlen(p);
      cur->parameter = new char[length + 1];
      strcpy(cur->parameter, p);
      if (length > 0) { // remove the last \n
        cur->parameter[length - 1] = '\0';
      }
      cur->type = static_cast<SVEventType>(ev_type);
      // Correct selection coordinates so x,y is the min pt and size is +ve.
      if (cur->x_size > 0) {
        cur->x -= cur->x_size;
      } else {
        cur->x_size = -cur->x_size;
      }
      if (cur->y_size > 0) {
        cur->y -= cur->y_size;
      } else {
        cur->y_size = -cur->y_size;
      }
      // Returned y will be the bottom-left if y is reversed.
      if (cur->window->y_axis_is_reversed_) {
        cur->y = cur->window->TranslateYCoordinate(cur->y + cur->y_size);
      }
      cur->counter = counter_event_id;
      // Increase by 2 since we will also create an SVET_ANY event from cur,
      // which will have a counter_id of cur + 1 (and thus gets processed
      // after cur).
      counter_event_id += 2;

      // In case of an SVET_EXIT event, quit the whole application.
      if (ev_type == SVET_EXIT) {
        ScrollView::Exit();
      }

      // Place two copies of it in the table for the window.
      cur->window->SetEvent(cur);

      // Check if any of the threads currently waiting want it.
      std::pair<ScrollView *, SVEventType> awaiting_list(cur->window, cur->type);
      std::pair<ScrollView *, SVEventType> awaiting_list_any(cur->window, SVET_ANY);
      std::pair<ScrollView *, SVEventType> awaiting_list_any_window((ScrollView *)nullptr,
                                                                    SVET_ANY);
      waiting_for_events_mu->lock();
      if (waiting_for_events.count(awaiting_list) > 0) {
        waiting_for_events[awaiting_list].second = cur;
        waiting_for_events[awaiting_list].first->Signal();
      } else if (waiting_for_events.count(awaiting_list_any) > 0) {
        waiting_for_events[awaiting_list_any].second = cur;
        waiting_for_events[awaiting_list_any].first->Signal();
      } else if (waiting_for_events.count(awaiting_list_any_window) > 0) {
        waiting_for_events[awaiting_list_any_window].second = cur;
        waiting_for_events[awaiting_list_any_window].first->Signal();
      } else {
        // No one wanted it, so delete it.
        delete cur;
      }
      waiting_for_events_mu->unlock();
      // Signal the corresponding semaphore twice (for both copies).
      ScrollView *sv = svmap[window_id];
      if (sv != nullptr) {
        sv->Signal();
        sv->Signal();
      }
    } else {
      delete cur; // Applied to no window.
    }
    svmap_mu->unlock();

    // Wait until a new message appears in the input stream_.
    do {
      message = ScrollView::GetStream()->Receive();
    } while (message == nullptr);
  }
}

// Table to implement the color index values in the old system.
static const uint8_t table_colors[ScrollView::GREEN_YELLOW + 1][4] = {
    {0, 0, 0, 0},         // NONE (transparent)
    {0, 0, 0, 255},       // BLACK.
    {255, 255, 255, 255}, // WHITE.
    {255, 0, 0, 255},     // RED.
    {255, 255, 0, 255},   // YELLOW.
    {0, 255, 0, 255},     // GREEN.<commit_msg>ScrollView: Fix memory leak and modernize code<commit_after>///////////////////////////////////////////////////////////////////////
// File:        scrollview.cpp
// Description: ScrollView
// Author:      <NAME>
//
// (C) Copyright 2007, Google Inc.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////
//

// Include automatically generated configuration file if running autoconf.
#ifdef HAVE_CONFIG_H
#  include "config_auto.h"
#endif

#include "scrollview.h"

#include "svutil.h" // for SVNetwork

#include <allheaders.h>

#include <algorithm>
#include <climits>
#include <cstdarg>
#include <cstring>
#include <map>
#include <memory> // for std::unique_ptr
#include <mutex> // for std::mutex
#include <string>
#include <thread> // for std::thread
#include <utility>
#include <vector>

namespace tesseract {

const int kSvPort = 8461;
const int kMaxMsgSize = 4096;
const int kMaxIntPairSize = 45; // Holds %d,%d, for up to 64 bit.

struct SVPolyLineBuffer {
  bool empty; // Independent indicator to allow SendMsg to call SendPolygon.
  std::vector<int> xcoords;
  std::vector<int> ycoords;
};

// A map between the window IDs and their corresponding pointers.
static std::map<int, ScrollView *> svmap;
static std::mutex *svmap_mu;
// A map of all semaphores waiting for a specific event on a specific window.
static std::map<std::pair<ScrollView *, SVEventType>, std::pair<SVSemaphore *, SVEvent *>>
    waiting_for_events;
static std::mutex *waiting_for_events_mu;

SVEvent *SVEvent::copy() {
  auto *any = new SVEvent;
  any->command_id = command_id;
  any->counter = counter;
  any->parameter = new char[strlen(parameter) + 1];
  strcpy(any->parameter, parameter);
  any->type = type;
  any->x = x;
  any->y = y;
  any->x_size = x_size;
  any->y_size = y_size;
  any->window = window;
  return any;
}

// Destructor.
// It is defined here, so the compiler can create a single vtable
// instead of weak vtables in every compilation unit.
SVEventHandler::~SVEventHandler() = default;

#ifndef GRAPHICS_DISABLED
/// This is the main loop which handles the ScrollView-logic from the server
/// to the client. It basically loops through messages, parses them to events
/// and distributes it to the waiting handlers.
/// It is run from a different thread and synchronizes via SVSync.
void ScrollView::MessageReceiver() {
  int counter_event_id = 0; // ongoing counter
  char *message = nullptr;
  // Wait until a new message appears in the input stream_.
  do {
    message = ScrollView::GetStream()->Receive();
  } while (message == nullptr);

  // This is the main loop which iterates until the server is dead (strlen =
  // -1). It basically parses for 3 different messagetypes and then distributes
  // the events accordingly.
  while (true) {
    // The new event we create.
    std::unique_ptr<SVEvent> cur(new SVEvent);
    // The ID of the corresponding window.
    int window_id;

    int ev_type;

    int n;
    // Fill the new SVEvent properly.
    sscanf(message, "%d,%d,%d,%d,%d,%d,%d,%n", &window_id, &ev_type, &cur->x, &cur->y, &cur->x_size,
           &cur->y_size, &cur->command_id, &n);
    char *p = (message + n);

    svmap_mu->lock();
    cur->window = svmap[window_id];

    if (cur->window != nullptr) {
      auto length = strlen(p);
      cur->parameter = new char[length + 1];
      strcpy(cur->parameter, p);
      if (length > 0) { // remove the last \n
        cur->parameter[length - 1] = '\0';
      }
      cur->type = static_cast<SVEventType>(ev_type);
      // Correct selection coordinates so x,y is the min pt and size is +ve.
      if (cur->x_size > 0) {
        cur->x -= cur->x_size;
      } else {
        cur->x_size = -cur->x_size;
      }
      if (cur->y_size > 0) {
        cur->y -= cur->y_size;
      } else {
        cur->y_size = -cur->y_size;
      }
      // Returned y will be the bottom-left if y is reversed.
      if (cur->window->y_axis_is_reversed_) {
        cur->y = cur->window->TranslateYCoordinate(cur->y + cur->y_size);
      }
      cur->counter = counter_event_id;
      // Increase by 2 since we will also create an SVET_ANY event from cur,
      // which will have a counter_id of cur + 1 (and thus gets processed
      // after cur).
      counter_event_id += 2;

      // In case of an SVET_EXIT event, quit the whole application.
      if (ev_type == SVET_EXIT) {
        SendRawMessage("svmain:exit()");
        break;
      }

      // Place two copies of it in the table for the window.
      cur->window->SetEvent(cur.get());

      // Check if any of the threads currently waiting want it.
      std::pair<ScrollView *, SVEventType> awaiting_list(cur->window, cur->type);
      std::pair<ScrollView *, SVEventType> awaiting_list_any(cur->window, SVET_ANY);
      std::pair<ScrollView *, SVEventType> awaiting_list_any_window((ScrollView *)nullptr,
                                                                    SVET_ANY);
      waiting_for_events_mu->lock();
      if (waiting_for_events.count(awaiting_list) > 0) {
        waiting_for_events[awaiting_list].second = cur.get();
        waiting_for_events[awaiting_list].first->Signal();
      } else if (waiting_for_events.count(awaiting_list_any) > 0) {
        waiting_for_events[awaiting_list_any].second = cur.get();
        waiting_for_events[awaiting_list_any].first->Signal();
      } else if (waiting_for_events.count(awaiting_list_any_window) > 0) {
        waiting_for_events[awaiting_list_any_window].second = cur.get();
        waiting_for_events[awaiting_list_any_window].first->Signal();
      }
      waiting_for_events_mu->unlock();
      // Signal the corresponding semaphore twice (for both copies).
      ScrollView *sv = svmap[window_id];
      if (sv != nullptr) {
        sv->Signal();
        sv->Signal();
      }
    }
    svmap_mu->unlock();

    // Wait until a new message appears in the input stream_.
    do {
      message = ScrollView::GetStream()->Receive();
    } while (message == nullptr);
  }
}

// Table to implement the color index values in the old system.
static const uint8_t table_colors[ScrollView::GREEN_YELLOW + 1][4] = {
    {0, 0, 0, 0},         // NONE (transparent)
    {0, 0, 0, 255},       // BLACK.
    {255, 255, 255, 255}, // WHITE.
    {255, 0, 0, 255},     // RED.
    {255, 255, 0, 255},   // YELLOW.
    {0, 255, 0, 255},     // GREEN.
{'fraction_non_alphanumeric': 0.14346879535558782, 'fraction_numerical': 0.012626995645863571, 'mean_word_length': 2.636147757255937, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 171, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4089532', 'n_tokens_mistral': 4407, 'n_tokens_neox': 4227, 'n_words': 1340}