Commit 7e61e345 for tesseract

commit 7e61e3457de8809fbc60400d82690b8e9e46be2e
Author: Stefan Weil <sw@weilnetz.de>
Date:   Sun Jul 12 20:58:35 2026 +0200

    Fix Skip bounds and unicharcompress unsigned call sites

    - TFile::Skip: reject if the skip would move offset_ past the end of
      the in-memory buffer, preventing later reads from computing
      data_->size() - offset_ with unsigned underflow.
    - unicharcompress.cpp: change all loop variables and locals that
      receive RecodedCharID::length() to uint32_t to match the return
      type, and restructure the code.length() - 1 pattern to avoid
      unsigned wraparound.

    Assisted-by: OpenCode / big-pickle (opencode)
    Reported-by: GitHub Copilot
    Signed-off-by: Stefan Weil <stweil@tessus.org>

diff --git a/src/ccutil/serialis.cpp b/src/ccutil/serialis.cpp
index cb663094..f750823a 100644
--- a/src/ccutil/serialis.cpp
+++ b/src/ccutil/serialis.cpp
@@ -143,6 +143,10 @@ bool TFile::Serialize(const std::vector<char> &data) {
 }

 bool TFile::Skip(size_t count) {
+  if (data_ != nullptr && offset_ + count > data_->size()) {
+    offset_ = data_->size();
+    return false;
+  }
   offset_ += count;
   return true;
 }
diff --git a/src/ccutil/unicharcompress.cpp b/src/ccutil/unicharcompress.cpp
index d5efccab..f909f76e 100644
--- a/src/ccutil/unicharcompress.cpp
+++ b/src/ccutil/unicharcompress.cpp
@@ -180,7 +180,7 @@ bool UnicharCompress::ComputeEncoding(const UNICHARSET &unicharset, int null_id,
         // Add the direct_set unichar-ids of the unicodes in sequence to the
         // code.
         for (int uni : unicodes) {
-          int position = code.length();
+          uint32_t position = code.length();
           if (position >= RecodedCharID::kMaxCodeLen) {
             tprintf("Unichar %d=%s is too long to encode!!\n", u, unicharset.id_to_unichar(u));
             return false;
@@ -259,7 +259,7 @@ void UnicharCompress::DefragmentCodeValues(int encoded_null) {
   std::vector<int> offsets(code_range_);
   // Find which codes are used
   for (auto &code : encoder_) {
-    for (int i = 0; i < code.length(); ++i) {
+    for (uint32_t i = 0; i < code.length(); ++i) {
       offsets[code(i)] = 1;
     }
   }
@@ -303,8 +303,8 @@ int UnicharCompress::EncodeUnichar(unsigned unichar_id, RecodedCharID *code) con
 // Decodes code, returning the original unichar-id, or
 // INVALID_UNICHAR_ID if the input is invalid.
 int UnicharCompress::DecodeUnichar(const RecodedCharID &code) const {
-  int len = code.length();
-  if (len <= 0 || len > RecodedCharID::kMaxCodeLen) {
+  uint32_t len = code.length();
+  if (len == 0 || len > RecodedCharID::kMaxCodeLen) {
     return INVALID_UNICHAR_ID;
   }
   auto it = decoder_.find(code);
@@ -345,7 +345,7 @@ std::string UnicharCompress::GetEncodingAsString(const UNICHARSET &unicharset) c
       continue;
     }
     encoding += std::to_string(code(0));
-    for (int i = 1; i < code.length(); ++i) {
+    for (uint32_t i = 1; i < code.length(); ++i) {
       encoding += "," + std::to_string(code(i));
     }
     encoding += "\t";
@@ -383,7 +383,7 @@ bool UnicharCompress::DecomposeHangul(int unicode, int *leading, int *vowel, int
 void UnicharCompress::ComputeCodeRange() {
   code_range_ = -1;
   for (auto &code : encoder_) {
-    for (int i = 0; i < code.length(); ++i) {
+    for (uint32_t i = 0; i < code.length(); ++i) {
       if (code(i) > code_range_) {
         code_range_ = code(i);
       }
@@ -402,14 +402,19 @@ void UnicharCompress::SetupDecoder() {
     decoder_[code] = c;
     is_valid_start_[code(0)] = true;
     RecodedCharID prefix = code;
-    int len = code.length() - 1;
+    uint32_t len = code.length();
+    if (len == 0) {
+      continue;
+    }
+    --len;
     prefix.Truncate(len);
     auto final_it = final_codes_.find(prefix);
     if (final_it == final_codes_.end()) {
       auto *code_list = new std::vector<int>;
       code_list->push_back(code(len));
       final_codes_[prefix] = code_list;
-      while (--len >= 0) {
+      while (len > 0) {
+        --len;
         prefix.Truncate(len);
         auto next_it = next_codes_.find(prefix);
         if (next_it == next_codes_.end()) {