<commit_before>/**********************************************************************
 * File:        baseapi.cpp
 * Description: Simple API for calling tesseract.
 * Author:      <NAME>
 * Created:     Fri Oct 06 15:35:01 PDT 2006
 *
 * (C) Copyright 2006, 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

#ifdef __linux__
#include <signal.h>
#endif

#if defined(_WIN32)
#ifdef _MSC_VER
#include "vcsversion.h"
#elif MINGW
// workaround for stdlib.h with -std=c++11 for _splitpath and _MAX_FNAME
#undef __STRICT_ANSI__
#endif  // _MSC_VER
#include <fcntl.h>
#include <io.h>
#else
#include <dirent.h>
#include <libgen.h>
#include <string.h>
#endif  // _WIN32

#include <fstream>
#include <iostream>
#include <iterator>
#include <memory>  // std::unique_ptr
#include <string>

#include "allheaders.h"

#include "baseapi.h"
#include "blobclass.h"
#include "resultiterator.h"
#include "mutableiterator.h"
#include "thresholder.h"
#include "tesseractclass.h"
#include "pageres.h"
#include "paragraphs.h"
#include "tessvars.h"
#include "control.h"
#include "dict.h"
#include "pgedit.h"
#include "paramsd.h"
#include "output.h"
#include "globaloc.h"
#include "globals.h"
#include "edgblob.h"
#include "equationdetect.h"
#include "tessbox.h"
#include "makerow.h"
#include "otsuthr.h"
#include "osdetect.h"
#include "params.h"
#include "renderer.h"
#include "strngs.h"
#include "openclwrapper.h"

BOOL_VAR(stream_filelist, FALSE, "Stream a filelist from stdin");

namespace tesseract {

/** Minimum sensible image size to be worth running tesseract. */
const int kMinRectSize = 10;
/** Character returned when Tesseract couldn't recognize as anything. */
const char kTesseractReject = '~';
/** Character used by UNLV error counter as a reject. */
const char kUNLVReject = '~';
/** Character used by UNLV as a suspect marker. */
const char kUNLVSuspect = '^';
/**
 * Filename used for input image file, from which to derive a name to search
 * for a possible UNLV zone file, if none is specified by SetInputName.
 */
const char* kInputFile = "noname.tif";
/**
 * Temp file used for storing current parameters before applying retry values.
 */
const char* kOldVarsFile = "failed_vars.txt";
/** Max string length of an int.  */
const int kMaxIntSize = 22;
/**
 * Minimum believable resolution. Used as a default if there is no other
 * information, as it is safer to under-estimate than over-estimate.
 */
const int kMinCredibleResolution = 70;
/** Maximum believable resolution.  */
const int kMaxCredibleResolution = 2400;
/** Default resolution.  */
const int kDefaultResolution = 300;

TessBaseAPI::TessBaseAPI()
    : tesseract_(nullptr),
      osd_tesseract_(nullptr),
      equ_detect_(nullptr),
      reader_(nullptr),
      // Thresholder is initialized to NULL here, but will be set before use by:
      // A constructor of a derived API,  SetThresholder(), or
      // created implicitly when used in InternalSetImage.
      thresholder_(nullptr),
      paragraph_models_(nullptr),
      block_list_(nullptr),
      page_res_(nullptr),
      input_file_(nullptr),
      output_file_(nullptr),
      datapath_(nullptr),
      language_(nullptr),
      last_oem_requested_(OEM_DEFAULT),
      recognition_done_(false),
      truth_cb_(NULL),
      rect_left_(0),
      rect_top_(0),
      rect_width_(0),
      rect_height_(0),
      image_width_(0),
      image_height_(0) {}

TessBaseAPI::~TessBaseAPI() {
  End();
}

/**
 * Returns the version identifier as a static string. Do not delete.
 */
const char* TessBaseAPI::Version() {
#if defined(GIT_REV) && (defined(DEBUG) || defined(_DEBUG))
  return GIT_REV;
#else
  return TESSERACT_VERSION_STR;
#endif
}

/**
 * If compiled with OpenCL AND an available OpenCL
 * device is deemed faster than serial code, then
 * "device" is populated with the cl_device_id
 * and returns sizeof(cl_device_id)
 * otherwise *device=NULL and returns 0.
 */
#ifdef USE_OPENCL
#if USE_DEVICE_SELECTION
#include "opencl_device_selection.h"
#endif
#endif
size_t TessBaseAPI::getOpenCLDevice(void **data) {
#ifdef USE_OPENCL
#if USE_DEVICE_SELECTION
  ds_device device = OpenclDevice::getDeviceSelection();
  if (device.type == DS_DEVICE_OPENCL_DEVICE) {
    *data = new cl_device_id;
    memcpy(*data, &device.oclDeviceID, sizeof(cl_device_id));
    return sizeof(cl_device_id);
  }
#endif
#endif

  *data = NULL;
  return 0;
}

/**
 * Writes the thresholded image to stderr as a PBM file on receipt of a
 * SIGSEGV, SIGFPE, or SIGBUS signal. (Linux/Unix only).
 */
void TessBaseAPI::CatchSignals() {
#ifdef __linux__
  struct sigaction action;
  memset(&action, 0, sizeof(action));
  action.sa_handler = &signal_exit;
  action.sa_flags = SA_RESETHAND;
  sigaction(SIGSEGV, &action, NULL);
  sigaction(SIGFPE, &action, NULL);
  sigaction(SIGBUS, &action, NULL);
#else
  // Warn API users that an implementation is needed.
  tprintf("CatchSignals has no non-linux implementation!\n");
#endif
}

/**
 * Set the name of the input file. Needed only for training and
 * loading a UNLV zone file.
 */
void TessBaseAPI::SetInputName(const char* name) {
  if (input_file_ == NULL)
    input_file_ = new STRING(name);
  else
    *input_file_ = name;
}

/** Set the name of the output files. Needed only for debugging. */
void TessBaseAPI::SetOutputName(const char* name) {
  if (output_file_ == NULL)
    output_file_ = new STRING(name);
  else
    *output_file_ = name;
}

bool TessBaseAPI::SetVariable(const char* name, const char* value) {
  if (tesseract_ == NULL) tesseract_ = new Tesseract;
  return ParamUtils::SetParam(name, value, SET_PARAM_CONSTRAINT_NON_INIT_ONLY,
                              tesseract_->params());
}

bool TessBaseAPI::SetDebugVariable(const char* name, const char* value) {
  if (tesseract_ == NULL) tesseract_ = new Tesseract;
  return ParamUtils::SetParam(name, value, SET_PARAM_CONSTRAINT_DEBUG_ONLY,
                              tesseract_->params());
}

bool TessBaseAPI::GetIntVariable(const char *name, int *value) const {
  IntParam *p = ParamUtils::FindParam<IntParam>(
      name, GlobalParams()->int_params, tesseract_->params()->int_params);
  if (p == NULL) return false;
  *value = (inT32)(*p);
  return true;
}

bool TessBaseAPI::GetBoolVariable(const char *name, bool *value) const {
  BoolParam *p = ParamUtils::FindParam<BoolParam>(
      name, GlobalParams()->bool_params, tesseract_->params()->bool_params);
  if (p == NULL) return false;
  *value = (BOOL8)(*p);
  return true;
}

const char *TessBaseAPI::GetStringVariable(const char *name) const {
  StringParam *p = ParamUtils::FindParam<StringParam>(
      name, GlobalParams()->string_params, tesseract_->params()->string_params);
  return (p != NULL) ? p->string() : NULL;
}

bool TessBaseAPI::GetDoubleVariable(const char *name, double *value) const {
  DoubleParam *p = ParamUtils::FindParam<DoubleParam>(
      name, GlobalParams()->double_params, tesseract_->params()->double_params);
  if (p == NULL) return false;
  *value = (double)(*p);
  return true;
}

/** Get value of named variable as a string, if it exists. */
bool TessBaseAPI::GetVariableAsString(const char *name, STRING *val) {
  return ParamUtils::GetParamAsString(name, tesseract_->params(), val);
}

/** Print Tesseract parameters to the given file. */
void TessBaseAPI::PrintVariables(FILE *fp) const {
  ParamUtils::PrintParams(fp, tesseract_->params());
}

/**
 * The datapath must be the name of the data directory (no ending /) or
 * some other file in which the data directory resides (for instance argv[0].)
 * The language is (usually) an ISO 639-3 string or NULL will default to eng.
 * If numeric_mode is true, then only digits and Roman numerals will
 * be returned.
 * @return: 0 on success and -1 on initialization failure.
 */
int TessBaseAPI::Init(const char* datapath, const char* language,
                      OcrEngineMode oem, char **configs, int configs_size,
                      const GenericVector<STRING> *vars_vec,
                      const GenericVector<STRING> *vars_values,
                      bool set_only_non_debug_params) {
  return Init(datapath, 0, language, oem, configs, configs_size, vars_vec,
              vars_values, set_only_non_debug_params, nullptr);
}

// In-memory version reads the traineddata file directly from the given
// data[data_size] array. Also implements the version with a datapath in data,
// flagged by data_size = 0.
int TessBaseAPI::Init(const char* data, int data_size, const char* language,
                      OcrEngineMode oem, char** configs, int configs_size,
                      const GenericVector<STRING>* vars_vec,
                      const GenericVector<STRING>* vars_values,
                      bool set_only_non_debug_params, FileReader reader) {
  PERF_COUNT_START("TessBaseAPI::Init")
  // Default language is "eng".
  if (language == nullptr) language = "eng";
  STRING datapath = data_size == 0 ? data : language;
  // If the datapath, OcrEngineMode or the language have changed - start again.
  // Note that the language_ field stores the last requested language that was
  // initialized successfully, while tesseract_->lang stores the language
  // actually used. They differ only if the requested language was NULL, in
  // which case tesseract_->lang is set to the Tesseract default ("eng").
  if (tesseract_ != nullptr &&
      (datapath_ == nullptr || language_ == nullptr || *datapath_ != datapath ||
       last_oem_requested_ != oem ||
       (*language_ != language && tesseract_->lang != language))) {
    delete tesseract_;
    tesseract_ = nullptr;
  }
  // PERF_COUNT_SUB("delete tesseract_")
#ifdef USE_OPENCL
  OpenclDevice od;
  od.InitEnv();
#endif
  PERF_COUNT_SUB("OD::InitEnv()")
  bool reset_classifier = true;
  if (tesseract_ == nullptr) {
    reset_classifier = false;
    tesseract_ = new Tesseract;
    if (reader != nullptr) reader_ = reader;
    TessdataManager mgr(reader_);
    if (data_size != 0) {
      mgr.LoadMemBuffer(language, data, data_size);
    }
    if (tesseract_->init_tesseract(
            datapath.string(),
            output_file_ != nullptr ? output_file_->string() : nullptr,
            language, oem, configs, configs_size, vars_vec, vars_values,
            set_only_non_debug_params, &mgr) != 0) {
      return -1;
    }
  }
  PERF_COUNT_SUB("update tesseract_")
  // Update datapath and language requested for the last valid initialization.
  if (datapath_ == nullptr)
    datapath_ = new STRING(datapath);
  else
    *datapath_ = datapath;
  if ((strcmp(datapath_->string(), "") == 0) &&
      (strcmp(tesseract_->datadir.string(), "") != 0))
     *datapath_ = tesseract_->datadir;

  if (language_ == nullptr)
    language_ = new STRING(language);
  else
    *language_ = language;
  last_oem_requested_ = oem;
  // PERF_COUNT_SUB("update last_oem_requested_")
  // For same language and datapath, just reset the adaptive classifier.
  if (reset_classifier) {
    tesseract_->ResetAdaptiveClassifier();
    PERF_COUNT_SUB("tesseract_->ResetAdaptiveClassifier()")
  }
  PERF_COUNT_END
  return 0;
}

/**
 * Returns the languages string used in the last valid initialization.
 * If the last initialization specified "deu+hin" then that will be
 * returned. If hin loaded eng automatically as well, then that will
 * not be included in this list. To find the languages actually
 * loaded use GetLoadedLanguagesAsVector.
 * The returned string should NOT be deleted.
 */
const char* TessBaseAPI::GetInitLanguagesAsString() const {
  return (language_ == NULL || language_->string() == NULL) ?
      "" : language_->string();
}

/**
 * Returns the loaded languages in the vector of STRINGs.
 * Includes all languages loaded by the last Init, including those loaded
 * as dependencies of other loaded languages.
 */
void TessBaseAPI::GetLoadedLanguagesAsVector(
    GenericVector<STRING>* langs) const {
  langs->clear();
  if (tesseract_ != NULL) {
    langs->push_back(tesseract_->lang);
    int num_subs = tesseract_->num_sub_langs();
    for (int i = 0; i < num_subs; ++i)
      langs->push_back(tesseract_->get_sub_lang(i)->lang);
  }
}

/**
 * Returns the available languages in the vector of STRINGs.
 */
void TessBaseAPI::GetAvailableLanguagesAsVector(
    GenericVector<STRING>* langs) const {
  langs->clear();
  if (tesseract_ != NULL) {
#ifdef _WIN32
    STRING pattern = tesseract_->datadir + "/*." + kTrainedDataSuffix;
    char fname[_MAX_FNAME];
    WIN32_FIND_DATA data;
    BOOL result = TRUE;
    HANDLE handle = FindFirstFile(pattern.string(), &data);
    if (handle != INVALID_HANDLE_VALUE) {
      for (; result; result = FindNextFile(handle, &data)) {
        _splitpath(data.cFileName, NULL, NULL, fname, NULL);
        langs->push_back(STRING(fname));
      }
      FindClose(handle);
    }
#else  // _WIN32
    DIR *dir;
    struct dirent *dirent;
    char *dot;

    STRING extension = STRING(".") + kTrainedDataSuffix;

    dir = opendir(tesseract_->datadir.string());
    if (dir != NULL) {
      while ((dirent = readdir(dir))) {
        // Skip '.', '..', and hidden files
        if (dirent->d_name[0] != '.') {
          if (strstr(dirent->d_name, extension.string()) != NULL) {
            dot = strrchr(dirent->d_name, '.');
            // This ensures that .traineddata is at the end of the file name
            if (strncmp(dot, extension.string(),
                        strlen(extension.string())) == 0) {
              *dot = '\0';
              langs->push_back(STRING(dirent->d_name));
            }
          }
        }
      }
      closedir(dir);
    }
#endif
  }
}

/**
 * Init only the lang model component of Tesseract. The only functions
 * that work after this init are SetVariable and IsValidWord.
 * WARNING: temporary! This function will be removed from here and placed
 * in a separate API at some future time.
 */
int TessBaseAPI::InitLangMod(const char* datapath, const char* language) {
  if (tesseract_ == NULL)
    tesseract_ = new Tesseract;
  else
    ParamUtils::ResetToDefaults(tesseract_->params());
  TessdataManager mgr;
  return tesseract_->init_tesseract_lm(datapath, NULL, language, &mgr);<commit_msg>List available languages recursively<commit_after>/**********************************************************************
 * File:        baseapi.cpp
 * Description: Simple API for calling tesseract.
 * Author:      <NAME>
 * Created:     Fri Oct 06 15:35:01 PDT 2006
 *
 * (C) Copyright 2006, 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

#ifdef __linux__
#include <signal.h>
#endif

#if defined(_WIN32)
#ifdef _MSC_VER
#include "vcsversion.h"
#elif MINGW
// workaround for stdlib.h with -std=c++11 for _splitpath and _MAX_FNAME
#undef __STRICT_ANSI__
#endif  // _MSC_VER
#include <fcntl.h>
#include <io.h>
#else
#include <dirent.h>
#include <libgen.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#endif  // _WIN32

#include <fstream>
#include <iostream>
#include <iterator>
#include <memory>  // std::unique_ptr
#include <string>

#include "allheaders.h"

#include "baseapi.h"
#include "blobclass.h"
#include "resultiterator.h"
#include "mutableiterator.h"
#include "thresholder.h"
#include "tesseractclass.h"
#include "pageres.h"
#include "paragraphs.h"
#include "tessvars.h"
#include "control.h"
#include "dict.h"
#include "pgedit.h"
#include "paramsd.h"
#include "output.h"
#include "globaloc.h"
#include "globals.h"
#include "edgblob.h"
#include "equationdetect.h"
#include "tessbox.h"
#include "makerow.h"
#include "otsuthr.h"
#include "osdetect.h"
#include "params.h"
#include "renderer.h"
#include "strngs.h"
#include "openclwrapper.h"

BOOL_VAR(stream_filelist, FALSE, "Stream a filelist from stdin");

namespace tesseract {

/** Minimum sensible image size to be worth running tesseract. */
const int kMinRectSize = 10;
/** Character returned when Tesseract couldn't recognize as anything. */
const char kTesseractReject = '~';
/** Character used by UNLV error counter as a reject. */
const char kUNLVReject = '~';
/** Character used by UNLV as a suspect marker. */
const char kUNLVSuspect = '^';
/**
 * Filename used for input image file, from which to derive a name to search
 * for a possible UNLV zone file, if none is specified by SetInputName.
 */
const char* kInputFile = "noname.tif";
/**
 * Temp file used for storing current parameters before applying retry values.
 */
const char* kOldVarsFile = "failed_vars.txt";
/** Max string length of an int.  */
const int kMaxIntSize = 22;
/**
 * Minimum believable resolution. Used as a default if there is no other
 * information, as it is safer to under-estimate than over-estimate.
 */
const int kMinCredibleResolution = 70;
/** Maximum believable resolution.  */
const int kMaxCredibleResolution = 2400;
/** Default resolution.  */
const int kDefaultResolution = 300;

/* Add all available languages recursively.
*/
static void addAvailableLanguages(const STRING &datadir, const STRING &base,
                                  GenericVector<STRING>* langs)
{
  const STRING base2 = (base.string()[0] == '\0') ? base : base + "/";
  const size_t extlen = sizeof(kTrainedDataSuffix);
#ifdef _WIN32
    WIN32_FIND_DATA data;
    HANDLE handle = FindFirstFile((datadir + base2 + "*").string(), &data);
    if (handle != INVALID_HANDLE_VALUE) {
      BOOL result = TRUE;
      for (; result;) {
        char *name = data.cFileName;
        // Skip '.', '..', and hidden files
        if (name[0] != '.') {
          if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ==
              FILE_ATTRIBUTE_DIRECTORY) {
            addAvailableLanguages(datadir, base2 + name, langs);
          } else {
            size_t len = strlen(name);
            if (len > extlen && name[len - extlen] == '.' &&
                strcmp(&name[len - extlen + 1], kTrainedDataSuffix) == 0) {
              name[len - extlen] = '\0';
              langs->push_back(base2 + name);
            }
          }
        }
        result = FindNextFile(handle, &data);
      }
      FindClose(handle);
    }
#else  // _WIN32
  DIR* dir = opendir((datadir + base).string());
  if (dir != NULL) {
    dirent *de;
    while ((de = readdir(dir))) {
      char *name = de->d_name;
      // Skip '.', '..', and hidden files
      if (name[0] != '.') {
        struct stat st;
        if (stat((datadir + base2 + name).string(), &st) == 0 &&
            (st.st_mode & S_IFDIR) == S_IFDIR) {
          addAvailableLanguages(datadir, base2 + name, langs);
        } else {
          size_t len = strlen(name);
          if (len > extlen && name[len - extlen] == '.' &&
              strcmp(&name[len - extlen + 1], kTrainedDataSuffix) == 0) {
            name[len - extlen] = '\0';
            langs->push_back(base2 + name);
          }
        }
      }
    }
    closedir(dir);
  }
#endif
}

TessBaseAPI::TessBaseAPI()
    : tesseract_(nullptr),
      osd_tesseract_(nullptr),
      equ_detect_(nullptr),
      reader_(nullptr),
      // Thresholder is initialized to NULL here, but will be set before use by:
      // A constructor of a derived API,  SetThresholder(), or
      // created implicitly when used in InternalSetImage.
      thresholder_(nullptr),
      paragraph_models_(nullptr),
      block_list_(nullptr),
      page_res_(nullptr),
      input_file_(nullptr),
      output_file_(nullptr),
      datapath_(nullptr),
      language_(nullptr),
      last_oem_requested_(OEM_DEFAULT),
      recognition_done_(false),
      truth_cb_(NULL),
      rect_left_(0),
      rect_top_(0),
      rect_width_(0),
      rect_height_(0),
      image_width_(0),
      image_height_(0) {}

TessBaseAPI::~TessBaseAPI() {
  End();
}

/**
 * Returns the version identifier as a static string. Do not delete.
 */
const char* TessBaseAPI::Version() {
#if defined(GIT_REV) && (defined(DEBUG) || defined(_DEBUG))
  return GIT_REV;
#else
  return TESSERACT_VERSION_STR;
#endif
}

/**
 * If compiled with OpenCL AND an available OpenCL
 * device is deemed faster than serial code, then
 * "device" is populated with the cl_device_id
 * and returns sizeof(cl_device_id)
 * otherwise *device=NULL and returns 0.
 */
#ifdef USE_OPENCL
#if USE_DEVICE_SELECTION
#include "opencl_device_selection.h"
#endif
#endif
size_t TessBaseAPI::getOpenCLDevice(void **data) {
#ifdef USE_OPENCL
#if USE_DEVICE_SELECTION
  ds_device device = OpenclDevice::getDeviceSelection();
  if (device.type == DS_DEVICE_OPENCL_DEVICE) {
    *data = new cl_device_id;
    memcpy(*data, &device.oclDeviceID, sizeof(cl_device_id));
    return sizeof(cl_device_id);
  }
#endif
#endif

  *data = NULL;
  return 0;
}

/**
 * Writes the thresholded image to stderr as a PBM file on receipt of a
 * SIGSEGV, SIGFPE, or SIGBUS signal. (Linux/Unix only).
 */
void TessBaseAPI::CatchSignals() {
#ifdef __linux__
  struct sigaction action;
  memset(&action, 0, sizeof(action));
  action.sa_handler = &signal_exit;
  action.sa_flags = SA_RESETHAND;
  sigaction(SIGSEGV, &action, NULL);
  sigaction(SIGFPE, &action, NULL);
  sigaction(SIGBUS, &action, NULL);
#else
  // Warn API users that an implementation is needed.
  tprintf("CatchSignals has no non-linux implementation!\n");
#endif
}

/**
 * Set the name of the input file. Needed only for training and
 * loading a UNLV zone file.
 */
void TessBaseAPI::SetInputName(const char* name) {
  if (input_file_ == NULL)
    input_file_ = new STRING(name);
  else
    *input_file_ = name;
}

/** Set the name of the output files. Needed only for debugging. */
void TessBaseAPI::SetOutputName(const char* name) {
  if (output_file_ == NULL)
    output_file_ = new STRING(name);
  else
    *output_file_ = name;
}

bool TessBaseAPI::SetVariable(const char* name, const char* value) {
  if (tesseract_ == NULL) tesseract_ = new Tesseract;
  return ParamUtils::SetParam(name, value, SET_PARAM_CONSTRAINT_NON_INIT_ONLY,
                              tesseract_->params());
}

bool TessBaseAPI::SetDebugVariable(const char* name, const char* value) {
  if (tesseract_ == NULL) tesseract_ = new Tesseract;
  return ParamUtils::SetParam(name, value, SET_PARAM_CONSTRAINT_DEBUG_ONLY,
                              tesseract_->params());
}

bool TessBaseAPI::GetIntVariable(const char *name, int *value) const {
  IntParam *p = ParamUtils::FindParam<IntParam>(
      name, GlobalParams()->int_params, tesseract_->params()->int_params);
  if (p == NULL) return false;
  *value = (inT32)(*p);
  return true;
}

bool TessBaseAPI::GetBoolVariable(const char *name, bool *value) const {
  BoolParam *p = ParamUtils::FindParam<BoolParam>(
      name, GlobalParams()->bool_params, tesseract_->params()->bool_params);
  if (p == NULL) return false;
  *value = (BOOL8)(*p);
  return true;
}

const char *TessBaseAPI::GetStringVariable(const char *name) const {
  StringParam *p = ParamUtils::FindParam<StringParam>(
      name, GlobalParams()->string_params, tesseract_->params()->string_params);
  return (p != NULL) ? p->string() : NULL;
}

bool TessBaseAPI::GetDoubleVariable(const char *name, double *value) const {
  DoubleParam *p = ParamUtils::FindParam<DoubleParam>(
      name, GlobalParams()->double_params, tesseract_->params()->double_params);
  if (p == NULL) return false;
  *value = (double)(*p);
  return true;
}

/** Get value of named variable as a string, if it exists. */
bool TessBaseAPI::GetVariableAsString(const char *name, STRING *val) {
  return ParamUtils::GetParamAsString(name, tesseract_->params(), val);
}

/** Print Tesseract parameters to the given file. */
void TessBaseAPI::PrintVariables(FILE *fp) const {
  ParamUtils::PrintParams(fp, tesseract_->params());
}

/**
 * The datapath must be the name of the data directory (no ending /) or
 * some other file in which the data directory resides (for instance argv[0].)
 * The language is (usually) an ISO 639-3 string or NULL will default to eng.
 * If numeric_mode is true, then only digits and Roman numerals will
 * be returned.
 * @return: 0 on success and -1 on initialization failure.
 */
int TessBaseAPI::Init(const char* datapath, const char* language,
                      OcrEngineMode oem, char **configs, int configs_size,
                      const GenericVector<STRING> *vars_vec,
                      const GenericVector<STRING> *vars_values,
                      bool set_only_non_debug_params) {
  return Init(datapath, 0, language, oem, configs, configs_size, vars_vec,
              vars_values, set_only_non_debug_params, nullptr);
}

// In-memory version reads the traineddata file directly from the given
// data[data_size] array. Also implements the version with a datapath in data,
// flagged by data_size = 0.
int TessBaseAPI::Init(const char* data, int data_size, const char* language,
                      OcrEngineMode oem, char** configs, int configs_size,
                      const GenericVector<STRING>* vars_vec,
                      const GenericVector<STRING>* vars_values,
                      bool set_only_non_debug_params, FileReader reader) {
  PERF_COUNT_START("TessBaseAPI::Init")
  // Default language is "eng".
  if (language == nullptr) language = "eng";
  STRING datapath = data_size == 0 ? data : language;
  // If the datapath, OcrEngineMode or the language have changed - start again.
  // Note that the language_ field stores the last requested language that was
  // initialized successfully, while tesseract_->lang stores the language
  // actually used. They differ only if the requested language was NULL, in
  // which case tesseract_->lang is set to the Tesseract default ("eng").
  if (tesseract_ != nullptr &&
      (datapath_ == nullptr || language_ == nullptr || *datapath_ != datapath ||
       last_oem_requested_ != oem ||
       (*language_ != language && tesseract_->lang != language))) {
    delete tesseract_;
    tesseract_ = nullptr;
  }
  // PERF_COUNT_SUB("delete tesseract_")
#ifdef USE_OPENCL
  OpenclDevice od;
  od.InitEnv();
#endif
  PERF_COUNT_SUB("OD::InitEnv()")
  bool reset_classifier = true;
  if (tesseract_ == nullptr) {
    reset_classifier = false;
    tesseract_ = new Tesseract;
    if (reader != nullptr) reader_ = reader;
    TessdataManager mgr(reader_);
    if (data_size != 0) {
      mgr.LoadMemBuffer(language, data, data_size);
    }
    if (tesseract_->init_tesseract(
            datapath.string(),
            output_file_ != nullptr ? output_file_->string() : nullptr,
            language, oem, configs, configs_size, vars_vec, vars_values,
            set_only_non_debug_params, &mgr) != 0) {
      return -1;
    }
  }
  PERF_COUNT_SUB("update tesseract_")
  // Update datapath and language requested for the last valid initialization.
  if (datapath_ == nullptr)
    datapath_ = new STRING(datapath);
  else
    *datapath_ = datapath;
  if ((strcmp(datapath_->string(), "") == 0) &&
      (strcmp(tesseract_->datadir.string(), "") != 0))
     *datapath_ = tesseract_->datadir;

  if (language_ == nullptr)
    language_ = new STRING(language);
  else
    *language_ = language;
  last_oem_requested_ = oem;
  // PERF_COUNT_SUB("update last_oem_requested_")
  // For same language and datapath, just reset the adaptive classifier.
  if (reset_classifier) {
    tesseract_->ResetAdaptiveClassifier();
    PERF_COUNT_SUB("tesseract_->ResetAdaptiveClassifier()")
  }
  PERF_COUNT_END
  return 0;
}

/**
 * Returns the languages string used in the last valid initialization.
 * If the last initialization specified "deu+hin" then that will be
 * returned. If hin loaded eng automatically as well, then that will
 * not be included in this list. To find the languages actually
 * loaded use GetLoadedLanguagesAsVector.
 * The returned string should NOT be deleted.
 */
const char* TessBaseAPI::GetInitLanguagesAsString() const {
  return (language_ == NULL || language_->string() == NULL) ?
      "" : language_->string();
}

/**
 * Returns the loaded languages in the vector of STRINGs.
 * Includes all languages loaded by the last Init, including those loaded
 * as dependencies of other loaded languages.
 */
void TessBaseAPI::GetLoadedLanguagesAsVector(
    GenericVector<STRING>* langs) const {
  langs->clear();
  if (tesseract_ != NULL) {
    langs->push_back(tesseract_->lang);
    int num_subs = tesseract_->num_sub_langs();
    for (int i = 0; i < num_subs; ++i)
      langs->push_back(tesseract_->get_sub_lang(i)->lang);
  }
}

/**
 * Returns the available languages in the vector of STRINGs.
 */
void TessBaseAPI::GetAvailableLanguagesAsVector(
    GenericVector<STRING>* langs) const {
  langs->clear();
  if (tesseract_ != NULL) {
    addAvailableLanguages(tesseract_->datadir, "", langs);
  }
}

/**
 * Init only the lang model component of Tesseract. The only functions
 * that work after this init are SetVariable and IsValidWord.
 * WARNING: temporary! This function will be removed from here and placed
 * in a separate API at some future time.
 */
int TessBaseAPI::InitLangMod(const char* datapath, const char* language) {
  if (tesseract_ == NULL)
    tesseract_ = new Tesseract;
  else
    ParamUtils::ResetToDefaults(tesseract_->params());
  TessdataManager mgr;
  return tesseract_->init_tesseract_lm(datapath, NULL, language, &mgr);
{'fraction_non_alphanumeric': 0.1259201099224654, 'fraction_numerical': 0.0055288382896587825, 'mean_word_length': 3.5946189688862167, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 143, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2525065', 'n_tokens_mistral': 9737, 'n_tokens_neox': 9617, 'n_words': 2841}