Commit f017d551 for tesseract
commit f017d551a8d955e8428be548858f688bd659b0d8
Author: Stefan Weil <sw@weilnetz.de>
Date: Thu Jun 18 18:19:50 2026 +0200
Replace char* parameter in SVEvent with std::string
Change SVEvent::parameter from manual char* management to std::string
for automatic memory management and safer string handling.
This eliminates:
- Manual new/delete in copy constructor
- strcpy without bounds checking
- Null pointer checks
Update all call sites:
- paramsd.cpp: WriteParams takes const char* (simplified with const_cast removed)
- pgedit.cpp, intproto.cpp, shapeclassifier.cpp: use .c_str() where needed
- colfind.cpp: nullptr check changed to .empty() check
Replace tprintf with tesserr stream in:
- intproto.cpp, shapeclassifier.cpp (eliminates need for .c_str())
Build verified successfully.
Assisted-by: minimax-m2.7 (MiniMax)
Signed-off-by: Stefan Weil <sw@weilnetz.de>
diff --git a/src/ccmain/paramsd.cpp b/src/ccmain/paramsd.cpp
index 14f220f8..21e28841 100644
--- a/src/ccmain/paramsd.cpp
+++ b/src/ccmain/paramsd.cpp
@@ -268,14 +268,13 @@ SVMenuNode *ParamsEditor::BuildListOfAllLeaves(tesseract::Tesseract *tess) {
// Event listener. Waits for SVET_POPUP events and processes them.
void ParamsEditor::Notify(const SVEvent *sve) {
if (sve->type == SVET_POPUP) { // only catch SVET_POPUP!
- char *param = sve->parameter;
if (sve->command_id == writeCommands[0]) {
- WriteParams(param, false);
+ WriteParams(sve->parameter, false);
} else if (sve->command_id == writeCommands[1]) {
- WriteParams(param, true);
+ WriteParams(sve->parameter, true);
} else {
ParamContent *vc = ParamContent::GetParamContentById(sve->command_id);
- vc->SetValue(param);
+ vc->SetValue(sve->parameter.c_str());
sv_window_->AddMessageF("Setting %s to %s", vc->GetName(), vc->GetValue().c_str());
}
}
@@ -315,10 +314,10 @@ ParamsEditor::ParamsEditor(tesseract::Tesseract *tess, ScrollView *sv) {
}
// Write all (changed_) parameters to a config file.
-void ParamsEditor::WriteParams(char *filename, bool changes_only) {
+void ParamsEditor::WriteParams(const std::string &filename, bool changes_only) {
FILE *fp; // input file
// if file exists
- if ((fp = fopen(filename, "rb")) != nullptr) {
+ if ((fp = fopen(filename.c_str(), "rb")) != nullptr) {
fclose(fp);
std::stringstream msg;
msg << "Overwrite file " << filename << "? (Y/N)";
@@ -328,9 +327,9 @@ void ParamsEditor::WriteParams(char *filename, bool changes_only) {
} // don't write
}
- fp = fopen(filename, "wb"); // can we write to it?
+ fp = fopen(filename.c_str(), "wb"); // can we write to it?
if (fp == nullptr) {
- sv_window_->AddMessageF("Can't write to file %s", filename);
+ sv_window_->AddMessageF("Can't write to file %s", filename.c_str());
return;
}
for (auto &iter : vcMap) {
diff --git a/src/ccmain/paramsd.h b/src/ccmain/paramsd.h
index f898d51b..e5fe36aa 100644
--- a/src/ccmain/paramsd.h
+++ b/src/ccmain/paramsd.h
@@ -26,6 +26,8 @@
# include "elst.h" // for ELIST_ITERATOR, ELISTIZEH, ELIST_LINK
# include "scrollview.h" // for ScrollView (ptr only), SVEvent (ptr only)
+#include <string>
+
namespace tesseract {
class SVMenuNode;
@@ -119,7 +121,7 @@ private:
SVMenuNode *BuildListOfAllLeaves(tesseract::Tesseract *tess);
// Write all (changed_) parameters to a config file.
- void WriteParams(char *filename, bool changes_only);
+ void WriteParams(const std::string &filename, bool changes_only);
ScrollView *sv_window_;
};
diff --git a/src/ccmain/pgedit.cpp b/src/ccmain/pgedit.cpp
index ccf85699..b3028a02 100644
--- a/src/ccmain/pgedit.cpp
+++ b/src/ccmain/pgedit.cpp
@@ -256,9 +256,9 @@ void PGEventHandler::Notify(const SVEvent *event) {
else if (event->type == SVET_EXIT) {
stillRunning = false;
} else if (event->type == SVET_MENU) {
- if (strcmp(event->parameter, "true") == 0) {
+ if (event->parameter == "true") {
myval = 'T';
- } else if (strcmp(event->parameter, "false") == 0) {
+ } else if (event->parameter == "false") {
myval = 'F';
}
tess_->process_cmd_win_event(event->command_id, &myval);
diff --git a/src/classify/intproto.cpp b/src/classify/intproto.cpp
index 0d2f3746..ced6263c 100644
--- a/src/classify/intproto.cpp
+++ b/src/classify/intproto.cpp
@@ -38,11 +38,13 @@
#endif
#include "helpers.h"
+#include "tesserrstream.h" // for tesserr
#include <algorithm>
#include <cassert>
#include <cmath> // for M_PI, std::floor
#include <cstdio>
+#include <cstdlib> // for strtol
namespace tesseract {
@@ -1174,22 +1176,30 @@ CLASS_ID Classify::GetClassToDebug(const char *Prompt, bool *adaptive_on, bool *
if (ev_type == SVET_POPUP) {
if (ev->command_id == IDA_SHAPE_INDEX) {
if (shape_table_ != nullptr) {
- *shape_id = atoi(ev->parameter);
+ char* endptr = nullptr;
+ long shape_id_long = strtol(ev->parameter.c_str(), &endptr, 10);
+ if (endptr == ev->parameter.c_str() || *endptr != '\0' ||
+ shape_id_long < INT_MIN || shape_id_long > INT_MAX) {
+ tesserr << "Invalid shape index: " << ev->parameter << "\n";
+ return INVALID_UNICHAR_ID;
+ }
+ *shape_id = static_cast<int>(shape_id_long);
*adaptive_on = false;
*pretrained_on = true;
if (*shape_id >= 0 && static_cast<unsigned>(*shape_id) < shape_table_->NumShapes()) {
int font_id;
shape_table_->GetFirstUnicharAndFont(*shape_id, &unichar_id, &font_id);
- tprintf("Shape %d, first unichar=%d, font=%d\n", *shape_id, unichar_id, font_id);
+ tesserr << "Shape " << *shape_id << ", first unichar=" << unichar_id
+ << ", font=" << font_id << "\n";
return unichar_id;
}
- tprintf("Shape index '%s' not found in shape table\n", ev->parameter);
+ tesserr << "Shape index '" << ev->parameter << "' not found in shape table\n";
} else {
- tprintf("No shape table loaded!\n");
+ tesserr << "No shape table loaded!\n";
}
} else {
- if (unicharset.contains_unichar(ev->parameter)) {
- unichar_id = unicharset.unichar_to_id(ev->parameter);
+ if (unicharset.contains_unichar(ev->parameter.c_str())) {
+ unichar_id = unicharset.unichar_to_id(ev->parameter.c_str());
if (ev->command_id == IDA_ADAPTIVE) {
*adaptive_on = true;
*pretrained_on = false;
@@ -1207,11 +1217,11 @@ CLASS_ID Classify::GetClassToDebug(const char *Prompt, bool *adaptive_on, bool *
}
for (unsigned s = 0; s < shape_table_->NumShapes(); ++s) {
if (shape_table_->GetShape(s).ContainsUnichar(unichar_id)) {
- tprintf("%s\n", shape_table_->DebugStr(s).c_str());
+ tesserr << shape_table_->DebugStr(s) << "\n";
}
}
} else {
- tprintf("Char class '%s' not found in unicharset", ev->parameter);
+ tesserr << "Char class '" << ev->parameter << "' not found in unicharset";
}
}
}
diff --git a/src/classify/shapeclassifier.cpp b/src/classify/shapeclassifier.cpp
index 96c8e02b..6e34c20d 100644
--- a/src/classify/shapeclassifier.cpp
+++ b/src/classify/shapeclassifier.cpp
@@ -30,7 +30,7 @@
#ifndef GRAPHICS_DISABLED
#include "svmnode.h"
#endif
-#include "tprintf.h"
+#include "tesserrstream.h" // for tesserr
#include "trainingsample.h"
namespace tesseract {
@@ -137,10 +137,10 @@ void ShapeClassifier::DebugDisplay(const TrainingSample &sample, Image page_pix,
auto ev = debug_win->AwaitEvent(SVET_ANY);
ev_type = ev->type;
if (ev_type == SVET_POPUP) {
- if (unicharset.contains_unichar(ev->parameter)) {
- unichar_id = unicharset.unichar_to_id(ev->parameter);
+ if (unicharset.contains_unichar(ev->parameter.c_str())) {
+ unichar_id = unicharset.unichar_to_id(ev->parameter.c_str());
} else {
- tprintf("Char class '%s' not found in unicharset", ev->parameter);
+ tesserr << "Char class '" << ev->parameter << "' not found in unicharset";
}
}
} while (unichar_id == old_unichar_id && ev_type != SVET_CLICK && ev_type != SVET_DESTROY);
diff --git a/src/textord/colfind.cpp b/src/textord/colfind.cpp
index 9e1ce820..8fec3241 100644
--- a/src/textord/colfind.cpp
+++ b/src/textord/colfind.cpp
@@ -477,8 +477,8 @@ int ColumnFinder::FindBlocks(PageSegMode pageseg_mode, Image scaled_color, int s
do {
waiting = false;
auto event = blocks_win_->AwaitEvent(SVET_ANY);
- if (event->type == SVET_INPUT && event->parameter != nullptr) {
- if (*event->parameter == 'd') {
+ if (event->type == SVET_INPUT && !event->parameter.empty()) {
+ if (event->parameter[0] == 'd') {
result = -1;
} else {
blocks->clear();
diff --git a/src/viewer/scrollview.cpp b/src/viewer/scrollview.cpp
index 054880b5..f34cb6e5 100644
--- a/src/viewer/scrollview.cpp
+++ b/src/viewer/scrollview.cpp
@@ -63,8 +63,7 @@ std::unique_ptr<SVEvent> SVEvent::copy() const {
auto any = std::unique_ptr<SVEvent>(new SVEvent);
any->command_id = command_id;
any->counter = counter;
- any->parameter = new char[strlen(parameter) + 1];
- strcpy(any->parameter, parameter);
+ any->parameter = parameter;
any->type = type;
any->x = x;
any->y = y;
@@ -114,10 +113,9 @@ void ScrollView::MessageReceiver() {
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->parameter = std::string(p, length);
+ if (length > 0 && cur->parameter.back() == '\n') { // remove the last \n
+ cur->parameter.pop_back();
}
cur->type = static_cast<SVEventType>(ev_type);
// Correct selection coordinates so x,y is the min pt and size is +ve.
@@ -719,8 +717,8 @@ char *ScrollView::ShowInputDialog(const char *msg) {
SendMsg("showInputDialog(\"%s\")", msg);
// wait till an input event (all others are thrown away)
auto ev = AwaitEvent(SVET_INPUT);
- char *p = new char[strlen(ev->parameter) + 1];
- strcpy(p, ev->parameter);
+ char *p = new char[ev->parameter.size() + 1];
+ std::strcpy(p, ev->parameter.c_str());
return p;
}
diff --git a/src/viewer/scrollview.h b/src/viewer/scrollview.h
index b2dc9b2f..b931436b 100644
--- a/src/viewer/scrollview.h
+++ b/src/viewer/scrollview.h
@@ -67,13 +67,10 @@ enum SVEventType {
};
struct SVEvent {
- ~SVEvent() {
- delete[] parameter;
- }
std::unique_ptr<SVEvent> copy() const;
SVEventType type = SVET_DESTROY; // What kind of event.
ScrollView *window = nullptr; // Window event relates to.
- char *parameter = nullptr; // Any string that might have been passed as argument.
+ std::string parameter; // Any string that might have been passed as argument.
int x = 0; // Coords of click or selection.
int y = 0;
int x_size = 0; // Size of selection.