new file mode 100644
@@ -0,0 +1,1255 @@
+From fc1c711cb5f769546c6b31cc688bf0ee7f0c1dbc Mon Sep 17 00:00:00 2001
+From: Sune Vuorela <sune@vuorela.dk>
+Date: Thu, 1 Feb 2024 19:11:03 +0000
+Subject: [PATCH] More unicode vectors; fewer raw pointers
+
+Conflicts:-qt5/tests/check_utf8document.cpp and qt6/tests/check_utf8document.cpp
+ files are not presented in this code version. We ignore them.
+ -In file utils/pdfsig.cc TextStringToUTF8 API don't exist
+ in this code version. We ignore them.
+
+CVE: CVE-2024-6239
+Upstream-Status: Backport [https://gitlab.freedesktop.org/poppler/poppler/-/commit/fc1c711cb5f769546c6b31cc688bf0ee7f0c1dbc]
+
+Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
+---
+ cpp/poppler-toc.cpp | 5 +-
+ glib/poppler-document.cc | 3 +-
+ poppler/CharCodeToUnicode.cc | 113 +++++++++------------------
+ poppler/CharCodeToUnicode.h | 12 ++-
+ poppler/DateInfo.cc | 10 +--
+ poppler/JSInfo.cc | 9 +--
+ poppler/Outline.cc | 12 +--
+ poppler/Outline.h | 7 +-
+ poppler/TextOutputDev.cc | 8 +-
+ poppler/UTF.cc | 78 ++++++++----------
+ poppler/UTF.h | 11 ++-
+ qt5/src/poppler-outline.cc | 2 +-
+ qt5/src/poppler-private.cc | 13 ++-
+ qt5/src/poppler-private.h | 1 +
+ qt5/tests/check_internal_outline.cpp | 6 +-
+ qt5/tests/check_utf_conversion.cpp | 24 +++---
+ qt6/src/poppler-outline.cc | 2 +-
+ qt6/src/poppler-private.cc | 5 ++
+ qt6/src/poppler-private.h | 1 +
+ qt6/tests/check_internal_outline.cpp | 6 +-
+ qt6/tests/check_utf_conversion.cpp | 24 +++---
+ utils/HtmlFonts.cc | 4 +-
+ utils/HtmlFonts.h | 2 +-
+ utils/HtmlOutputDev.cc | 38 ++++-----
+ utils/HtmlOutputDev.h | 2 +-
+ utils/pdfinfo.cc | 8 +-
+ utils/pdftohtml.cc | 25 +++---
+ 27 files changed, 180 insertions(+), 251 deletions(-)
+
+diff --git a/cpp/poppler-toc.cpp b/cpp/poppler-toc.cpp
+index c79abde..ed3a983 100644
+--- a/cpp/poppler-toc.cpp
++++ b/cpp/poppler-toc.cpp
+@@ -61,9 +61,8 @@ toc_item_private::~toc_item_private()
+
+ void toc_item_private::load(const OutlineItem *item)
+ {
+- const Unicode *title_unicode = item->getTitle();
+- const int title_length = item->getTitleLength();
+- title = detail::unicode_to_ustring(title_unicode, title_length);
++ const std::vector<Unicode> &title_unicode = item->getTitle();
++ title = detail::unicode_to_ustring(title_unicode.data(), title_unicode.size());
+ is_open = item->isOpen();
+ }
+
+diff --git a/glib/poppler-document.cc b/glib/poppler-document.cc
+index 7796f5a..be8cea1 100644
+--- a/glib/poppler-document.cc
++++ b/glib/poppler-document.cc
+@@ -2773,7 +2773,8 @@ PopplerAction *poppler_index_iter_get_action(PopplerIndexIter *iter)
+ item = (*iter->items)[iter->index];
+ link_action = item->getAction();
+
+- title = unicode_to_char(item->getTitle(), item->getTitleLength());
++ const std::vector<Unicode> &itemTitle = item->getTitle();
++ title = unicode_to_char(itemTitle.data(), itemTitle.size());
+
+ action = _poppler_action_new(iter->document, link_action, title);
+ g_free(title);
+diff --git a/poppler/CharCodeToUnicode.cc b/poppler/CharCodeToUnicode.cc
+index cd00937..d9ef019 100644
+--- a/poppler/CharCodeToUnicode.cc
++++ b/poppler/CharCodeToUnicode.cc
+@@ -38,6 +38,7 @@
+
+ #include <cstdio>
+ #include <cstring>
++#include <functional>
+ #include "goo/glibc.h"
+ #include "goo/gmem.h"
+ #include "goo/gfile.h"
+@@ -51,13 +52,6 @@
+
+ //------------------------------------------------------------------------
+
+-struct CharCodeToUnicodeString
+-{
+- CharCode c;
+- Unicode *u;
+- int len;
+-};
+-
+ //------------------------------------------------------------------------
+
+ static int getCharFromString(void *data)
+@@ -162,7 +156,7 @@ CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(const char *fileName, co
+ }
+ fclose(f);
+
+- ctu = new CharCodeToUnicode(collection->toStr(), mapA, mapLenA, true, nullptr, 0, 0);
++ ctu = new CharCodeToUnicode(collection->toStr(), mapA, mapLenA, true, {});
+ gfree(mapA);
+ return ctu;
+ }
+@@ -171,8 +165,7 @@ CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode(const GooString *fil
+ {
+ FILE *f;
+ Unicode *mapA;
+- CharCodeToUnicodeString *sMapA;
+- CharCode size, oldSize, len, sMapSizeA, sMapLenA;
++ CharCode size, oldSize, len;
+ char buf[256];
+ char *tok;
+ Unicode u0;
+@@ -192,8 +185,7 @@ CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode(const GooString *fil
+ mapA = (Unicode *)gmallocn(size, sizeof(Unicode));
+ memset(mapA, 0, size * sizeof(Unicode));
+ len = 0;
+- sMapA = nullptr;
+- sMapSizeA = sMapLenA = 0;
++ std::vector<CharCodeToUnicodeString> sMapA;
+
+ line = 0;
+ while (getLine(buf, sizeof(buf), f)) {
+@@ -230,17 +222,12 @@ CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode(const GooString *fil
+ mapA[u0] = uBuf[0];
+ } else {
+ mapA[u0] = 0;
+- if (sMapLenA == sMapSizeA) {
+- sMapSizeA += 16;
+- sMapA = (CharCodeToUnicodeString *)greallocn(sMapA, sMapSizeA, sizeof(CharCodeToUnicodeString));
+- }
+- sMapA[sMapLenA].c = u0;
+- sMapA[sMapLenA].u = (Unicode *)gmallocn(n, sizeof(Unicode));
++ std::vector<Unicode> u;
++ u.reserve(n);
+ for (i = 0; i < n; ++i) {
+- sMapA[sMapLenA].u[i] = uBuf[i];
++ u.push_back(uBuf[i]);
+ }
+- sMapA[sMapLenA].len = n;
+- ++sMapLenA;
++ sMapA.push_back({ u0, std::move(u) });
+ }
+ if (u0 >= len) {
+ len = u0 + 1;
+@@ -248,7 +235,7 @@ CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode(const GooString *fil
+ }
+ fclose(f);
+
+- ctu = new CharCodeToUnicode(fileName->toStr(), mapA, len, true, sMapA, sMapLenA, sMapSizeA);
++ ctu = new CharCodeToUnicode(fileName->toStr(), mapA, len, true, std::move(sMapA));
+ gfree(mapA);
+ gfree(uBuf);
+ return ctu;
+@@ -256,7 +243,7 @@ CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode(const GooString *fil
+
+ CharCodeToUnicode *CharCodeToUnicode::make8BitToUnicode(Unicode *toUnicode)
+ {
+- return new CharCodeToUnicode({}, toUnicode, 256, true, nullptr, 0, 0);
++ return new CharCodeToUnicode({}, toUnicode, 256, true, {});
+ }
+
+ CharCodeToUnicode *CharCodeToUnicode::parseCMap(const GooString *buf, int nBits)
+@@ -512,25 +499,18 @@ void CharCodeToUnicode::addMapping(CharCode code, char *uStr, int n, int offset)
+ map[code] = 0xfffd;
+ }
+ } else {
+- if (sMapLen >= sMapSize) {
+- sMapSize = sMapSize + 16;
+- sMap = (CharCodeToUnicodeString *)greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString));
+- }
+ map[code] = 0;
+- sMap[sMapLen].c = code;
+ int utf16Len = n / 4;
+- Unicode *utf16 = (Unicode *)gmallocn(utf16Len, sizeof(Unicode));
++ std::vector<Unicode> utf16(utf16Len);
++ utf16.resize(utf16Len);
+ for (j = 0; j < utf16Len; ++j) {
+ if (!parseHex(uStr + j * 4, 4, &utf16[j])) {
+- gfree(utf16);
+ error(errSyntaxWarning, -1, "Illegal entry in ToUnicode CMap");
+ return;
+ }
+ }
+ utf16[utf16Len - 1] += offset;
+- sMap[sMapLen].len = UTF16toUCS4(utf16, utf16Len, &sMap[sMapLen].u);
+- gfree(utf16);
+- ++sMapLen;
++ sMap.push_back({ code, UTF16toUCS4(utf16.data(), utf16.size()) });
+ }
+ }
+
+@@ -561,8 +541,6 @@ CharCodeToUnicode::CharCodeToUnicode()
+ {
+ map = nullptr;
+ mapLen = 0;
+- sMap = nullptr;
+- sMapLen = sMapSize = 0;
+ refCnt = 1;
+ isIdentity = false;
+ }
+@@ -576,13 +554,11 @@ CharCodeToUnicode::CharCodeToUnicode(const std::optional<std::string> &tagA) : t
+ for (i = 0; i < mapLen; ++i) {
+ map[i] = 0;
+ }
+- sMap = nullptr;
+- sMapLen = sMapSize = 0;
+ refCnt = 1;
+ isIdentity = false;
+ }
+
+-CharCodeToUnicode::CharCodeToUnicode(const std::optional<std::string> &tagA, Unicode *mapA, CharCode mapLenA, bool copyMap, CharCodeToUnicodeString *sMapA, int sMapLenA, int sMapSizeA) : tag(tagA)
++CharCodeToUnicode::CharCodeToUnicode(const std::optional<std::string> &tagA, Unicode *mapA, CharCode mapLenA, bool copyMap, std::vector<CharCodeToUnicodeString> &&sMapA) : tag(tagA)
+ {
+ mapLen = mapLenA;
+ if (copyMap) {
+@@ -591,9 +567,7 @@ CharCodeToUnicode::CharCodeToUnicode(const std::optional<std::string> &tagA, Uni
+ } else {
+ map = mapA;
+ }
+- sMap = sMapA;
+- sMapLen = sMapLenA;
+- sMapSize = sMapSizeA;
++ sMap = std::move(sMapA);
+ refCnt = 1;
+ isIdentity = false;
+ }
+@@ -601,12 +575,6 @@ CharCodeToUnicode::CharCodeToUnicode(const std::optional<std::string> &tagA, Uni
+ CharCodeToUnicode::~CharCodeToUnicode()
+ {
+ gfree(map);
+- if (sMap) {
+- for (int i = 0; i < sMapLen; ++i) {
+- gfree(sMap[i].u);
+- }
+- gfree(sMap);
+- }
+ }
+
+ void CharCodeToUnicode::incRefCnt()
+@@ -628,7 +596,8 @@ bool CharCodeToUnicode::match(const GooString *tagA)
+
+ void CharCodeToUnicode::setMapping(CharCode c, Unicode *u, int len)
+ {
+- int i, j;
++ size_t i;
++ int j;
+
+ if (!map || isIdentity) {
+ return;
+@@ -636,28 +605,26 @@ void CharCodeToUnicode::setMapping(CharCode c, Unicode *u, int len)
+ if (len == 1) {
+ map[c] = u[0];
+ } else {
+- for (i = 0; i < sMapLen; ++i) {
++ std::optional<std::reference_wrapper<CharCodeToUnicodeString>> element;
++ for (i = 0; i < sMap.size(); ++i) {
+ if (sMap[i].c == c) {
+- gfree(sMap[i].u);
++ sMap[i].u.clear();
++ element = std::ref(sMap[i]);
+ break;
+ }
+ }
+- if (i == sMapLen) {
+- if (sMapLen == sMapSize) {
+- sMapSize += 8;
+- sMap = (CharCodeToUnicodeString *)greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString));
+- }
+- ++sMapLen;
++ if (!element) {
++ sMap.emplace_back(CharCodeToUnicodeString { c, {} });
++ element = std::ref(sMap.back());
+ }
+ map[c] = 0;
+- sMap[i].c = c;
+- sMap[i].len = len;
+- sMap[i].u = (Unicode *)gmallocn(len, sizeof(Unicode));
++ element->get().c = c;
++ element->get().u.reserve(len);
+ for (j = 0; j < len; ++j) {
+ if (UnicodeIsValid(u[j])) {
+- sMap[i].u[j] = u[j];
++ element->get().u.push_back(u[j]);
+ } else {
+- sMap[i].u[j] = 0xfffd;
++ element->get().u.push_back(0xfffd);
+ }
+ }
+ }
+@@ -665,8 +632,6 @@ void CharCodeToUnicode::setMapping(CharCode c, Unicode *u, int len)
+
+ int CharCodeToUnicode::mapToUnicode(CharCode c, Unicode const **u) const
+ {
+- int i;
+-
+ if (isIdentity) {
+ map[0] = (Unicode)c;
+ *u = map;
+@@ -679,10 +644,10 @@ int CharCodeToUnicode::mapToUnicode(CharCode c, Unicode const **u) const
+ *u = &map[c];
+ return 1;
+ }
+- for (i = sMapLen - 1; i >= 0; --i) { // in reverse so CMap takes precedence
+- if (sMap[i].c == c) {
+- *u = sMap[i].u;
+- return sMap[i].len;
++ for (auto i = sMap.size(); i > 0; --i) { // in reverse so CMap takes precedence
++ if (sMap[i - 1].c == c) {
++ *u = sMap[i - 1].u.data();
++ return sMap[i - 1].u.size();
+ }
+ }
+ return 0;
+@@ -704,24 +669,24 @@ int CharCodeToUnicode::mapToCharCode(const Unicode *u, CharCode *c, int usize) c
+ }
+ *c = 'x';
+ } else {
+- int i, j;
++ size_t j;
+ // for each entry in the sMap
+- for (i = 0; i < sMapLen; i++) {
++ for (const auto &element : sMap) {
+ // if the entry's unicode length isn't the same are usize, the strings
+ // are obviously different
+- if (sMap[i].len != usize) {
++ if (element.u.size() != size_t(usize)) {
+ continue;
+ }
+ // compare the string char by char
+- for (j = 0; j < sMap[i].len; j++) {
+- if (sMap[i].u[j] != u[j]) {
++ for (j = 0; j < element.u.size(); j++) {
++ if (element.u[j] != u[j]) {
+ break;
+ }
+ }
+
+ // we have the same strings
+- if (j == sMap[i].len) {
+- *c = sMap[i].c;
++ if (j == element.u.size()) {
++ *c = element.c;
+ return 1;
+ }
+ }
+diff --git a/poppler/CharCodeToUnicode.h b/poppler/CharCodeToUnicode.h
+index 596d44d..9aa2571 100644
+--- a/poppler/CharCodeToUnicode.h
++++ b/poppler/CharCodeToUnicode.h
+@@ -33,11 +33,11 @@
+
+ #include <atomic>
+ #include <optional>
++#include <vector>
+
+ #include "poppler-config.h"
+ #include "CharTypes.h"
+
+-struct CharCodeToUnicodeString;
+ class GooString;
+
+ //------------------------------------------------------------------------
+@@ -100,18 +100,22 @@ public:
+ CharCode getLength() const { return mapLen; }
+
+ private:
++ struct CharCodeToUnicodeString
++ {
++ CharCode c;
++ std::vector<Unicode> u;
++ };
+ bool parseCMap1(int (*getCharFunc)(void *), void *data, int nBits);
+ void addMapping(CharCode code, char *uStr, int n, int offset);
+ void addMappingInt(CharCode code, Unicode u);
+ CharCodeToUnicode();
+ explicit CharCodeToUnicode(const std::optional<std::string> &tagA);
+- CharCodeToUnicode(const std::optional<std::string> &tagA, Unicode *mapA, CharCode mapLenA, bool copyMap, CharCodeToUnicodeString *sMapA, int sMapLenA, int sMapSizeA);
++ CharCodeToUnicode(const std::optional<std::string> &tagA, Unicode *mapA, CharCode mapLenA, bool copyMap, std::vector<CharCodeToUnicodeString> &&sMapA);
+
+ const std::optional<std::string> tag;
+ Unicode *map;
+ CharCode mapLen;
+- CharCodeToUnicodeString *sMap;
+- int sMapLen, sMapSize;
++ std::vector<CharCodeToUnicodeString> sMap;
+ std::atomic_int refCnt;
+ bool isIdentity;
+ };
+diff --git a/poppler/DateInfo.cc b/poppler/DateInfo.cc
+index 36e9804..d62cc78 100644
+--- a/poppler/DateInfo.cc
++++ b/poppler/DateInfo.cc
+@@ -36,16 +36,14 @@
+ /* See PDF Reference 1.3, Section 3.8.2 for PDF Date representation */
+ bool parseDateString(const GooString *date, int *year, int *month, int *day, int *hour, int *minute, int *second, char *tz, int *tzHour, int *tzMinute)
+ {
+- Unicode *u;
+- int len = TextStringToUCS4(date->toStr(), &u);
++ std::vector<Unicode> u = TextStringToUCS4(date->toStr());
+ GooString s;
+- for (int i = 0; i < len; i++) {
++ for (auto &c : u) {
+ // Ignore any non ASCII characters
+- if (u[i] < 128) {
+- s.append(u[i]);
++ if (c < 128) {
++ s.append(c);
+ }
+ }
+- gfree(u);
+ const char *dateString = s.c_str();
+
+ if (strlen(dateString) < 2) {
+diff --git a/poppler/JSInfo.cc b/poppler/JSInfo.cc
+index bc6992c..6607085 100644
+--- a/poppler/JSInfo.cc
++++ b/poppler/JSInfo.cc
+@@ -38,20 +38,17 @@ JSInfo::~JSInfo() { }
+
+ void JSInfo::printJS(const GooString *js)
+ {
+- Unicode *u = nullptr;
+ char buf[8];
+- int i, n, len;
+
+ if (!js || !js->c_str()) {
+ return;
+ }
+
+- len = TextStringToUCS4(js->toStr(), &u);
+- for (i = 0; i < len; i++) {
+- n = uniMap->mapUnicode(u[i], buf, sizeof(buf));
++ std::vector<Unicode> u = TextStringToUCS4(js->toStr());
++ for (auto &c : u) {
++ int n = uniMap->mapUnicode(c, buf, sizeof(buf));
+ fwrite(buf, 1, n, file);
+ }
+- gfree(u);
+ }
+
+ void JSInfo::scanLinkAction(LinkAction *link, const char *action)
+diff --git a/poppler/Outline.cc b/poppler/Outline.cc
+index 4c68be9..086c104 100644
+--- a/poppler/Outline.cc
++++ b/poppler/Outline.cc
+@@ -407,15 +407,12 @@ OutlineItem::OutlineItem(const Dict *dict, Ref refA, OutlineItem *parentA, XRef
+ parent = parentA;
+ xref = xrefA;
+ doc = docA;
+- title = nullptr;
+ kids = nullptr;
+
+ obj1 = dict->lookup("Title");
+ if (obj1.isString()) {
+ const GooString *s = obj1.getString();
+- titleLen = TextStringToUCS4(s->toStr(), &title);
+- } else {
+- titleLen = 0;
++ title = TextStringToUCS4(s->toStr());
+ }
+
+ obj1 = dict->lookup("Dest");
+@@ -446,9 +443,6 @@ OutlineItem::~OutlineItem()
+ delete kids;
+ kids = nullptr;
+ }
+- if (title) {
+- gfree(title);
+- }
+ }
+
+ std::vector<OutlineItem *> *OutlineItem::readItemList(OutlineItem *parent, const Object *firstItemRef, XRef *xrefA, PDFDoc *docA)
+@@ -494,11 +488,9 @@ void OutlineItem::open()
+
+ void OutlineItem::setTitle(const std::string &titleA)
+ {
+- gfree(title);
+-
+ Object dict = xref->fetch(ref);
+ GooString *g = new GooString(titleA);
+- titleLen = TextStringToUCS4(g->toStr(), &title);
++ title = TextStringToUCS4(g->toStr());
+ dict.dictSet("Title", Object(g));
+ xref->setModifiedObject(&dict, ref);
+ }
+diff --git a/poppler/Outline.h b/poppler/Outline.h
+index a301604..af431f6 100644
+--- a/poppler/Outline.h
++++ b/poppler/Outline.h
+@@ -27,6 +27,7 @@
+ #define OUTLINE_H
+
+ #include <memory>
++#include <vector>
+ #include "Object.h"
+ #include "CharTypes.h"
+ #include "poppler_private_export.h"
+@@ -91,9 +92,8 @@ public:
+ OutlineItem(const OutlineItem &) = delete;
+ OutlineItem &operator=(const OutlineItem &) = delete;
+ static std::vector<OutlineItem *> *readItemList(OutlineItem *parent, const Object *firstItemRef, XRef *xrefA, PDFDoc *docA);
+- const Unicode *getTitle() const { return title; }
++ const std::vector<Unicode> &getTitle() const { return title; }
+ void setTitle(const std::string &titleA);
+- int getTitleLength() const { return titleLen; }
+ bool setPageDest(int i);
+ // OutlineItem keeps the ownership of the action
+ const LinkAction *getAction() const { return action.get(); }
+@@ -112,8 +112,7 @@ private:
+ OutlineItem *parent;
+ PDFDoc *doc;
+ XRef *xref;
+- Unicode *title;
+- int titleLen;
++ std::vector<Unicode> title;
+ std::unique_ptr<LinkAction> action;
+ bool startsOpen;
+ std::vector<OutlineItem *> *kids; // nullptr if this item is closed or has no kids
+diff --git a/poppler/TextOutputDev.cc b/poppler/TextOutputDev.cc
+index 439143c..5d75900 100644
+--- a/poppler/TextOutputDev.cc
++++ b/poppler/TextOutputDev.cc
+@@ -5661,15 +5661,11 @@ void ActualText::end(const GfxState *state)
+ // extents of all the glyphs inside the span
+
+ if (actualTextNBytes) {
+- Unicode *uni = nullptr;
+- int length;
+-
+ // now that we have the position info for all of the text inside
+ // the marked content span, we feed the "ActualText" back through
+ // text->addChar()
+- length = TextStringToUCS4(actualText->toStr(), &uni);
+- text->addChar(state, actualTextX0, actualTextY0, actualTextX1 - actualTextX0, actualTextY1 - actualTextY0, 0, actualTextNBytes, uni, length);
+- gfree(uni);
++ std::vector<Unicode> uni = TextStringToUCS4(actualText->toStr());
++ text->addChar(state, actualTextX0, actualTextY0, actualTextX1 - actualTextX0, actualTextY1 - actualTextY0, 0, actualTextNBytes, uni.data(), uni.size());
+ }
+
+ delete actualText;
+diff --git a/poppler/UTF.cc b/poppler/UTF.cc
+index 9b1bf95..eb542eb 100644
+--- a/poppler/UTF.cc
++++ b/poppler/UTF.cc
+@@ -42,65 +42,52 @@ bool UnicodeIsValid(Unicode ucs4)
+ return (ucs4 < 0x110000) && ((ucs4 & 0xfffff800) != 0xd800) && (ucs4 < 0xfdd0 || ucs4 > 0xfdef) && ((ucs4 & 0xfffe) != 0xfffe);
+ }
+
+-int UTF16toUCS4(const Unicode *utf16, int utf16Len, Unicode **ucs4_out)
++std::vector<Unicode> UTF16toUCS4(const Unicode *utf16, int utf16Len)
+ {
+- int i, n, len;
+- Unicode *u;
+-
+ // count characters
+- len = 0;
+- for (i = 0; i < utf16Len; i++) {
++ int len = 0;
++ for (int i = 0; i < utf16Len; i++) {
+ if (utf16[i] >= 0xd800 && utf16[i] < 0xdc00 && i + 1 < utf16Len && utf16[i + 1] >= 0xdc00 && utf16[i + 1] < 0xe000) {
+ i++; /* surrogate pair */
+ }
+ len++;
+ }
+- if (ucs4_out == nullptr) {
+- return len;
+- }
+-
+- u = (Unicode *)gmallocn(len, sizeof(Unicode));
+- n = 0;
++ std::vector<Unicode> u;
++ u.reserve(len);
+ // convert string
+- for (i = 0; i < utf16Len; i++) {
++ for (int i = 0; i < utf16Len; i++) {
+ if (utf16[i] >= 0xd800 && utf16[i] < 0xdc00) { /* surrogate pair */
+ if (i + 1 < utf16Len && utf16[i + 1] >= 0xdc00 && utf16[i + 1] < 0xe000) {
+ /* next code is a low surrogate */
+- u[n] = (((utf16[i] & 0x3ff) << 10) | (utf16[i + 1] & 0x3ff)) + 0x10000;
++ u.push_back((((utf16[i] & 0x3ff) << 10) | (utf16[i + 1] & 0x3ff)) + 0x10000);
+ ++i;
+ } else {
+ /* missing low surrogate
+ replace it with REPLACEMENT CHARACTER (U+FFFD) */
+- u[n] = 0xfffd;
++ u.push_back(0xfffd);
+ }
+ } else if (utf16[i] >= 0xdc00 && utf16[i] < 0xe000) {
+ /* invalid low surrogate
+ replace it with REPLACEMENT CHARACTER (U+FFFD) */
+- u[n] = 0xfffd;
++ u.push_back(0xfffd);
+ } else {
+- u[n] = utf16[i];
++ u.push_back(utf16[i]);
+ }
+- if (!UnicodeIsValid(u[n])) {
+- u[n] = 0xfffd;
++ if (!UnicodeIsValid(u.back())) {
++ u.back() = 0xfffd;
+ }
+- n++;
+ }
+- *ucs4_out = u;
+- return len;
++ return u;
+ }
+
+-int TextStringToUCS4(const std::string &textStr, Unicode **ucs4)
++std::vector<Unicode> TextStringToUCS4(const std::string &textStr)
+ {
+- int i, len;
+- const char *s;
+- Unicode *u;
+ bool isUnicode, isUnicodeLE;
+
+- len = textStr.size();
+- s = textStr.c_str();
++ int len = textStr.size();
++ const std::string &s = textStr;
+ if (len == 0) {
+- *ucs4 = nullptr;
+- return 0;
++ return {};
+ }
+
+ if (GooString::hasUnicodeMarker(textStr)) {
+@@ -115,30 +102,30 @@ int TextStringToUCS4(const std::string &textStr, Unicode **ucs4)
+ }
+
+ if (isUnicode || isUnicodeLE) {
+- Unicode *utf16;
+ len = len / 2 - 1;
+ if (len > 0) {
+- utf16 = new Unicode[len];
+- for (i = 0; i < len; i++) {
++ std::vector<Unicode> utf16;
++ utf16.reserve(len);
++ for (int i = 0; i < len; i++) {
+ if (isUnicode) {
+- utf16[i] = (s[2 + i * 2] & 0xff) << 8 | (s[3 + i * 2] & 0xff);
++ utf16.push_back((s[2 + i * 2] & 0xff) << 8 | (s[3 + i * 2] & 0xff));
+ } else { // UnicodeLE
+- utf16[i] = (s[3 + i * 2] & 0xff) << 8 | (s[2 + i * 2] & 0xff);
++ utf16.push_back((s[3 + i * 2] & 0xff) << 8 | (s[2 + i * 2] & 0xff));
+ }
+ }
+- len = UTF16toUCS4(utf16, len, &u);
+- delete[] utf16;
++ return UTF16toUCS4(utf16.data(), utf16.size());
++
+ } else {
+- u = nullptr;
++ return {};
+ }
+ } else {
+- u = (Unicode *)gmallocn(len, sizeof(Unicode));
+- for (i = 0; i < len; i++) {
+- u[i] = pdfDocEncoding[s[i] & 0xff];
++ std::vector<Unicode> u;
++ u.reserve(len);
++ for (int i = 0; i < len; i++) {
++ u.push_back(pdfDocEncoding[s[i] & 0xff]);
+ }
++ return u;
+ }
+- *ucs4 = u;
+- return len;
+ }
+
+ bool UnicodeIsWhitespace(Unicode ucs4)
+@@ -549,7 +536,10 @@ void unicodeToAscii7(const Unicode *in, int len, Unicode **ucs4_out, int *out_le
+ }
+ }
+
+- *out_len = TextStringToUCS4(str, ucs4_out);
++ std::vector<Unicode> ucs4 = TextStringToUCS4(str);
++ *out_len = ucs4.size();
++ *ucs4_out = (Unicode *)gmallocn(ucs4.size(), sizeof(Unicode));
++ memcpy(*ucs4_out, ucs4.data(), ucs4.size() * sizeof(Unicode));
+
+ if (indices) {
+ idx[k] = in_idx[len];
+diff --git a/poppler/UTF.h b/poppler/UTF.h
+index 626c686..bfc5f65 100644
+--- a/poppler/UTF.h
++++ b/poppler/UTF.h
+@@ -19,6 +19,7 @@
+ #include <cstdint>
+ #include <climits>
+ #include <memory>
++#include <vector>
+
+ #include "goo/GooString.h"
+ #include "CharTypes.h"
+@@ -27,16 +28,14 @@
+ // Convert a UTF-16 string to a UCS-4
+ // utf16 - utf16 bytes
+ // utf16_len - number of UTF-16 characters
+-// ucs4_out - if not NULL, allocates and returns UCS-4 string. Free with gfree.
+ // returns number of UCS-4 characters
+-int UTF16toUCS4(const Unicode *utf16, int utf16Len, Unicode **ucs4_out);
++std::vector<Unicode> UTF16toUCS4(const Unicode *utf16, int utf16Len);
+
+ // Convert a PDF Text String to UCS-4
+ // s - PDF text string
+-// ucs4 - if the number of UCS-4 characters is > 0, allocates and
+-// returns UCS-4 string. Free with gfree.
+-// returns number of UCS-4 characters
+-int POPPLER_PRIVATE_EXPORT TextStringToUCS4(const std::string &textStr, Unicode **ucs4);
++// returns UCS-4 characters
++// Convert a PDF text string to UCS-4
++std::vector<Unicode> POPPLER_PRIVATE_EXPORT TextStringToUCS4(const std::string &textStr);
+
+ // check if UCS-4 character is valid
+ bool UnicodeIsValid(Unicode ucs4);
+diff --git a/qt5/src/poppler-outline.cc b/qt5/src/poppler-outline.cc
+index 5ff7e37..2f6ef2d 100644
+--- a/qt5/src/poppler-outline.cc
++++ b/qt5/src/poppler-outline.cc
+@@ -78,7 +78,7 @@ QString OutlineItem::name() const
+
+ if (name.isEmpty()) {
+ if (const ::OutlineItem *data = m_data->data) {
+- name = unicodeToQString(data->getTitle(), data->getTitleLength());
++ name = unicodeToQString(data->getTitle());
+ }
+ }
+
+diff --git a/qt5/src/poppler-private.cc b/qt5/src/poppler-private.cc
+index 228d8e8..54df79f 100644
+--- a/qt5/src/poppler-private.cc
++++ b/qt5/src/poppler-private.cc
+@@ -94,6 +94,11 @@ QString unicodeToQString(const Unicode *u, int len)
+ return QString::fromUtf8(convertedStr.c_str(), convertedStr.getLength());
+ }
+
++QString unicodeToQString(const std::vector<Unicode> &u)
++{
++ return unicodeToQString(u.data(), u.size());
++}
++
+ QString UnicodeParsedString(const GooString *s1)
+ {
+ return (s1) ? UnicodeParsedString(s1->toStr()) : QString();
+@@ -266,13 +271,7 @@ void DocumentData::addTocChildren(QDomDocument *docSyn, QDomNode *parent, const
+ // iterate over every object in 'items'
+
+ // 1. create element using outlineItem's title as tagName
+- QString name;
+- const Unicode *uniChar = outlineItem->getTitle();
+- int titleLength = outlineItem->getTitleLength();
+- name = unicodeToQString(uniChar, titleLength);
+- if (name.isEmpty()) {
+- continue;
+- }
++ QString name = unicodeToQString(outlineItem->getTitle());
+
+ QDomElement item = docSyn->createElement(name);
+ parent->appendChild(item);
+diff --git a/qt5/src/poppler-private.h b/qt5/src/poppler-private.h
+index 39dfb6b..bba5bd7 100644
+--- a/qt5/src/poppler-private.h
++++ b/qt5/src/poppler-private.h
+@@ -73,6 +73,7 @@ namespace Poppler {
+
+ /* borrowed from kpdf */
+ POPPLER_QT5_EXPORT QString unicodeToQString(const Unicode *u, int len);
++POPPLER_QT5_EXPORT QString unicodeToQString(const std::vector<Unicode> &u);
+
+ POPPLER_QT5_EXPORT QString UnicodeParsedString(const GooString *s1);
+
+diff --git a/qt5/tests/check_internal_outline.cpp b/qt5/tests/check_internal_outline.cpp
+index c12b604..5db6bf4 100644
+--- a/qt5/tests/check_internal_outline.cpp
++++ b/qt5/tests/check_internal_outline.cpp
+@@ -56,10 +56,10 @@ void TestInternalOutline::testCreateOutline()
+
+ static std::string getTitle(const OutlineItem *item)
+ {
+- const Unicode *u = item->getTitle();
++ std::vector<Unicode> u = item->getTitle();
+ std::string s;
+- for (int i = 0; i < item->getTitleLength(); i++) {
+- s.append(1, (char)u[i]);
++ for (auto &c : u) {
++ s.append(1, (char)(c));
+ }
+ return s;
+ }
+diff --git a/qt5/tests/check_utf_conversion.cpp b/qt5/tests/check_utf_conversion.cpp
+index 73c684e..b00f080 100644
+--- a/qt5/tests/check_utf_conversion.cpp
++++ b/qt5/tests/check_utf_conversion.cpp
+@@ -133,16 +133,13 @@ void TestUTFConversion::testUnicodeToAscii7()
+ // malloc() always returns 8-byte aligned memory addresses.
+ GooString *goo = Poppler::QStringToUnicodeGooString(QString::fromUtf8("®©©©©©©©©©©©©©©©©©©©©")); // clazy:exclude=qstring-allocations
+
+- Unicode *in;
+- const int in_len = TextStringToUCS4(goo->toStr(), &in);
++ const std::vector<Unicode> in = TextStringToUCS4(goo->toStr());
+
+ delete goo;
+
+ int in_norm_len;
+ int *in_norm_idx;
+- Unicode *in_norm = unicodeNormalizeNFKC(in, in_len, &in_norm_len, &in_norm_idx, true);
+-
+- free(in);
++ Unicode *in_norm = unicodeNormalizeNFKC(in.data(), in.size(), &in_norm_len, &in_norm_idx, true);
+
+ Unicode *out;
+ int out_len;
+@@ -174,25 +171,24 @@ void TestUTFConversion::testUnicodeLittleEndian()
+ // Let's assert both GooString's are different
+ QVERIFY(GooUTF16LE != GooUTF16BE);
+
+- Unicode *UCS4fromLE, *UCS4fromBE;
+- const int len1 = TextStringToUCS4(GooUTF16LE, &UCS4fromLE);
+- const int len2 = TextStringToUCS4(GooUTF16BE, &UCS4fromBE);
++ const std::vector<Unicode> UCS4fromLE = TextStringToUCS4(GooUTF16LE);
++ const std::vector<Unicode> UCS4fromBE = TextStringToUCS4(GooUTF16BE);
+
+ // len is 4 because TextStringToUCS4() removes the two leading Byte Order Mark (BOM) code points
+- QCOMPARE(len1, len2);
+- QCOMPARE(len1, 4);
++ QCOMPARE(UCS4fromLE.size(), UCS4fromBE.size());
++ QCOMPARE(UCS4fromLE.size(), 4);
+
+ // Check that now after conversion, UCS4fromLE and UCS4fromBE are now the same
+- for (int i = 0; i < len1; i++) {
++ for (size_t i = 0; i < UCS4fromLE.size(); i++) {
+ QCOMPARE(UCS4fromLE[i], UCS4fromBE[i]);
+ }
+
+ const QString expected = QString::fromUtf8("HI!☑"); // clazy:exclude=qstring-allocations
+
+ // Do some final verifications, checking the strings to be "HI!"
+- QVERIFY(*UCS4fromLE == *UCS4fromBE);
+- QVERIFY(compare(UCS4fromLE, expected.utf16(), len1));
+- QVERIFY(compare(UCS4fromBE, expected.utf16(), len1));
++ QVERIFY(UCS4fromLE == UCS4fromBE);
++ QVERIFY(compare(UCS4fromLE.data(), expected.utf16(), UCS4fromLE.size()));
++ QVERIFY(compare(UCS4fromBE.data(), expected.utf16(), UCS4fromLE.size()));
+ }
+
+ QTEST_GUILESS_MAIN(TestUTFConversion)
+diff --git a/qt6/src/poppler-outline.cc b/qt6/src/poppler-outline.cc
+index f5ba2a9..2bc0d30 100644
+--- a/qt6/src/poppler-outline.cc
++++ b/qt6/src/poppler-outline.cc
+@@ -78,7 +78,7 @@ QString OutlineItem::name() const
+
+ if (name.isEmpty()) {
+ if (const ::OutlineItem *data = m_data->data) {
+- name = unicodeToQString(data->getTitle(), data->getTitleLength());
++ name = unicodeToQString(data->getTitle());
+ }
+ }
+
+diff --git a/qt6/src/poppler-private.cc b/qt6/src/poppler-private.cc
+index 91d1725..2cb2396 100644
+--- a/qt6/src/poppler-private.cc
++++ b/qt6/src/poppler-private.cc
+@@ -94,6 +94,11 @@ QString unicodeToQString(const Unicode *u, int len)
+ return QString::fromUtf8(convertedStr.c_str(), convertedStr.getLength());
+ }
+
++QString unicodeToQString(const std::vector<Unicode> &u)
++{
++ return unicodeToQString(u.data(), u.size());
++}
++
+ QString UnicodeParsedString(const GooString *s1)
+ {
+ return (s1) ? UnicodeParsedString(s1->toStr()) : QString();
+diff --git a/qt6/src/poppler-private.h b/qt6/src/poppler-private.h
+index d1f7335..a3117a6 100644
+--- a/qt6/src/poppler-private.h
++++ b/qt6/src/poppler-private.h
+@@ -72,6 +72,7 @@ namespace Poppler {
+
+ /* borrowed from kpdf */
+ POPPLER_QT6_EXPORT QString unicodeToQString(const Unicode *u, int len);
++POPPLER_QT6_EXPORT QString unicodeToQString(const std::vector<Unicode> &u);
+
+ POPPLER_QT6_EXPORT QString UnicodeParsedString(const GooString *s1);
+
+diff --git a/qt6/tests/check_internal_outline.cpp b/qt6/tests/check_internal_outline.cpp
+index c12b604..d23e773 100644
+--- a/qt6/tests/check_internal_outline.cpp
++++ b/qt6/tests/check_internal_outline.cpp
+@@ -56,10 +56,10 @@ void TestInternalOutline::testCreateOutline()
+
+ static std::string getTitle(const OutlineItem *item)
+ {
+- const Unicode *u = item->getTitle();
++ const std::vector<Unicode> &u = item->getTitle();
+ std::string s;
+- for (int i = 0; i < item->getTitleLength(); i++) {
+- s.append(1, (char)u[i]);
++ for (const auto &c : u) {
++ s.append(1, (char)(c));
+ }
+ return s;
+ }
+diff --git a/qt6/tests/check_utf_conversion.cpp b/qt6/tests/check_utf_conversion.cpp
+index 2cac758..e7f35ea 100644
+--- a/qt6/tests/check_utf_conversion.cpp
++++ b/qt6/tests/check_utf_conversion.cpp
+@@ -131,16 +131,13 @@ void TestUTFConversion::testUnicodeToAscii7()
+ // malloc() always returns 8-byte aligned memory addresses.
+ GooString *goo = Poppler::QStringToUnicodeGooString(QString::fromUtf8("®©©©©©©©©©©©©©©©©©©©©")); // clazy:exclude=qstring-allocations
+
+- Unicode *in;
+- const int in_len = TextStringToUCS4(goo->toStr(), &in);
++ const std::vector<Unicode> in = TextStringToUCS4(goo->toStr());
+
+ delete goo;
+
+ int in_norm_len;
+ int *in_norm_idx;
+- Unicode *in_norm = unicodeNormalizeNFKC(in, in_len, &in_norm_len, &in_norm_idx, true);
+-
+- free(in);
++ Unicode *in_norm = unicodeNormalizeNFKC(in.data(), in.size(), &in_norm_len, &in_norm_idx, true);
+
+ Unicode *out;
+ int out_len;
+@@ -172,25 +169,24 @@ void TestUTFConversion::testUnicodeLittleEndian()
+ // Let's assert both GooString's are different
+ QVERIFY(GooUTF16LE != GooUTF16BE);
+
+- Unicode *UCS4fromLE, *UCS4fromBE;
+- const int len1 = TextStringToUCS4(GooUTF16LE, &UCS4fromLE);
+- const int len2 = TextStringToUCS4(GooUTF16BE, &UCS4fromBE);
++ const std::vector<Unicode> UCS4fromLE = TextStringToUCS4(GooUTF16LE);
++ const std::vector<Unicode> UCS4fromBE = TextStringToUCS4(GooUTF16BE);
+
+ // len is 4 because TextStringToUCS4() removes the two leading Byte Order Mark (BOM) code points
+- QCOMPARE(len1, len2);
+- QCOMPARE(len1, 4);
++ QCOMPARE(UCS4fromLE.size(), UCS4fromBE.size());
++ QCOMPARE(UCS4fromLE.size(), 4);
+
+ // Check that now after conversion, UCS4fromLE and UCS4fromBE are now the same
+- for (int i = 0; i < len1; i++) {
++ for (size_t i = 0; i < UCS4fromLE.size(); i++) {
+ QCOMPARE(UCS4fromLE[i], UCS4fromBE[i]);
+ }
+
+ const QString expected = QStringLiteral("HI!☑");
+
+ // Do some final verifications, checking the strings to be "HI!"
+- QVERIFY(*UCS4fromLE == *UCS4fromBE);
+- QVERIFY(compare(UCS4fromLE, expected.utf16(), len1));
+- QVERIFY(compare(UCS4fromBE, expected.utf16(), len1));
++ QVERIFY(UCS4fromLE == UCS4fromBE);
++ QVERIFY(compare(UCS4fromLE.data(), expected.utf16(), UCS4fromLE.size()));
++ QVERIFY(compare(UCS4fromBE.data(), expected.utf16(), UCS4fromBE.size()));
+ }
+
+ QTEST_GUILESS_MAIN(TestUTFConversion)
+diff --git a/utils/HtmlFonts.cc b/utils/HtmlFonts.cc
+index ca7d4a4..9f25621 100644
+--- a/utils/HtmlFonts.cc
++++ b/utils/HtmlFonts.cc
+@@ -230,9 +230,9 @@ GooString *HtmlFont::getFullName()
+ }
+
+ // this method if plain wrong todo
+-GooString *HtmlFont::HtmlFilter(const Unicode *u, int uLen)
++std::unique_ptr<GooString> HtmlFont::HtmlFilter(const Unicode *u, int uLen)
+ {
+- GooString *tmp = new GooString();
++ auto tmp = std::make_unique<GooString>();
+ const UnicodeMap *uMap;
+ char buf[8];
+ int n;
+diff --git a/utils/HtmlFonts.h b/utils/HtmlFonts.h
+index ca4ae54..74cdca0 100644
+--- a/utils/HtmlFonts.h
++++ b/utils/HtmlFonts.h
+@@ -104,7 +104,7 @@ public:
+ }
+ const double *getRotMat() const { return rotSkewMat; }
+ GooString *getFontName();
+- static GooString *HtmlFilter(const Unicode *u, int uLen); // char* s);
++ static std::unique_ptr<GooString> HtmlFilter(const Unicode *u, int uLen); // char* s);
+ bool isEqual(const HtmlFont &x) const;
+ bool isEqualIgnoreBold(const HtmlFont &x) const;
+ void print() const { printf("font: %s (%s) %d %s%s\n", FontName->c_str(), familyName.c_str(), size, bold ? "bold " : "", italic ? "italic " : ""); };
+diff --git a/utils/HtmlOutputDev.cc b/utils/HtmlOutputDev.cc
+index 8a16e00..71fe672 100644
+--- a/utils/HtmlOutputDev.cc
++++ b/utils/HtmlOutputDev.cc
+@@ -127,11 +127,11 @@ static bool debug = false;
+
+ #if 0
+ static GooString* Dirname(GooString* str){
+-
++
+ char *p=str->c_str();
+ int len=str->getLength();
+ for (int i=len-1;i>=0;i--)
+- if (*(p+i)==SLASH)
++ if (*(p+i)==SLASH)
+ return new GooString(p,i+1);
+ return new GooString();
+ }
+@@ -222,14 +222,13 @@ HtmlString::HtmlString(GfxState *state, double fontSize, HtmlFontAccu *_fonts) :
+ len = size = 0;
+ yxNext = nullptr;
+ xyNext = nullptr;
+- htext = new GooString();
++ htext = std::make_unique<GooString>();
+ dir = textDirUnknown;
+ }
+
+ HtmlString::~HtmlString()
+ {
+ gfree(text);
+- delete htext;
+ gfree(xRight);
+ }
+
+@@ -340,7 +339,6 @@ void HtmlPage::beginString(GfxState *state, const GooString *s)
+ void HtmlPage::conv()
+ {
+ for (HtmlString *tmp = yxStrings; tmp; tmp = tmp->yxNext) {
+- delete tmp->htext;
+ tmp->htext = HtmlFont::HtmlFilter(tmp->text, tmp->len);
+
+ int linkIndex = 0;
+@@ -636,7 +634,7 @@ void HtmlPage::coalesce()
+ bool finish_a = switch_links && hlink1 != nullptr;
+ bool finish_italic = hfont1->isItalic() && (!hfont2->isItalic() || finish_a);
+ bool finish_bold = hfont1->isBold() && (!hfont2->isBold() || finish_a || finish_italic);
+- CloseTags(str1->htext, finish_a, finish_italic, finish_bold);
++ CloseTags(str1->htext.get(), finish_a, finish_italic, finish_bold);
+ if (switch_links && hlink2 != nullptr) {
+ GooString *ls = hlink2->getLinkStart();
+ str1->htext->append(ls);
+@@ -649,7 +647,7 @@ void HtmlPage::coalesce()
+ str1->htext->append("<b>", 3);
+ }
+
+- str1->htext->append(str2->htext);
++ str1->htext->append(str2->htext.get());
+ // str1 now contains href for link of str2 (if it is defined)
+ str1->link = str2->link;
+ hfont1 = hfont2;
+@@ -666,7 +664,7 @@ void HtmlPage::coalesce()
+ bool finish_a = str1->getLink() != nullptr;
+ bool finish_bold = hfont1->isBold();
+ bool finish_italic = hfont1->isItalic();
+- CloseTags(str1->htext, finish_a, finish_italic, finish_bold);
++ CloseTags(str1->htext.get(), finish_a, finish_italic, finish_bold);
+
+ str1->xMin = curX;
+ str1->yMin = curY;
+@@ -693,14 +691,14 @@ void HtmlPage::coalesce()
+ bool finish_bold = hfont1->isBold();
+ bool finish_italic = hfont1->isItalic();
+ bool finish_a = str1->getLink() != nullptr;
+- CloseTags(str1->htext, finish_a, finish_italic, finish_bold);
++ CloseTags(str1->htext.get(), finish_a, finish_italic, finish_bold);
+
+ #if 0 //~ for debugging
+ for (str1 = yxStrings; str1; str1 = str1->yxNext) {
+ printf("x=%3d..%3d y=%3d..%3d size=%2d ",
+ (int)str1->xMin, (int)str1->xMax, (int)str1->yMin, (int)str1->yMax,
+ (int)(str1->yMax - str1->yMin));
+- printf("'%s'\n", str1->htext->c_str());
++ printf("'%s'\n", str1->htext->c_str());
+ }
+ printf("\n------------------------------------------------------------\n\n");
+ #endif
+@@ -1220,10 +1218,10 @@ void HtmlOutputDev::startPage(int pageNumA, GfxState *state, XRef *xref)
+ exit(1);
+ }
+ delete fname;
+- // if(state->getRotation()!=0)
++ // if(state->getRotation()!=0)
+ // fprintf(tin,"ROTATE=%d rotate %d neg %d neg translate\n",state->getRotation(),state->getX1(),-state->getY1());
+- // else
+- fprintf(tin,"ROTATE=%d neg %d neg translate\n",state->getX1(),state->getY1());
++ // else
++ fprintf(tin,"ROTATE=%d neg %d neg translate\n",state->getX1(),state->getY1());
+ }
+ }
+ #endif
+@@ -1718,10 +1716,11 @@ bool HtmlOutputDev::newHtmlOutlineLevel(FILE *output, const std::vector<OutlineI
+ fputs("<ul>\n", output);
+
+ for (OutlineItem *item : *outlines) {
+- GooString *titleStr = HtmlFont::HtmlFilter(item->getTitle(), item->getTitleLength());
++ const auto &title = item->getTitle();
++ std::unique_ptr<GooString> titleStr = HtmlFont::HtmlFilter(title.data(), title.size());
+
+ GooString *linkName = nullptr;
+- ;
++
+ const int itemPage = getOutlinePageNum(item);
+ if (itemPage > 0) {
+ /* complex simple
+@@ -1748,12 +1747,13 @@ bool HtmlOutputDev::newHtmlOutlineLevel(FILE *output, const std::vector<OutlineI
+ if (linkName) {
+ fprintf(output, "<a href=\"%s\">", linkName->c_str());
+ }
+- fputs(titleStr->c_str(), output);
++ if (titleStr) {
++ fputs(titleStr->c_str(), output);
++ }
+ if (linkName) {
+ fputs("</a>", output);
+ delete linkName;
+ }
+- delete titleStr;
+ atLeastOne = true;
+
+ item->open();
+@@ -1773,14 +1773,14 @@ void HtmlOutputDev::newXmlOutlineLevel(FILE *output, const std::vector<OutlineIt
+ fputs("<outline>\n", output);
+
+ for (OutlineItem *item : *outlines) {
+- GooString *titleStr = HtmlFont::HtmlFilter(item->getTitle(), item->getTitleLength());
++ const std::vector<Unicode> &title = item->getTitle();
++ auto titleStr = HtmlFont::HtmlFilter(title.data(), title.size());
+ const int itemPage = getOutlinePageNum(item);
+ if (itemPage > 0) {
+ fprintf(output, "<item page=\"%d\">%s</item>\n", itemPage, titleStr->c_str());
+ } else {
+ fprintf(output, "<item>%s</item>\n", titleStr->c_str());
+ }
+- delete titleStr;
+
+ item->open();
+ if (item->hasKids() && item->getKids()) {
+diff --git a/utils/HtmlOutputDev.h b/utils/HtmlOutputDev.h
+index c7b08d1..e490eff 100644
+--- a/utils/HtmlOutputDev.h
++++ b/utils/HtmlOutputDev.h
+@@ -95,7 +95,7 @@ private:
+ HtmlString *yxNext; // next string in y-major order
+ HtmlString *xyNext; // next string in x-major order
+ int fontpos;
+- GooString *htext;
++ std::unique_ptr<GooString> htext;
+ int len; // length of text and xRight
+ int size; // size of text and xRight arrays
+ UnicodeTextDirection dir; // direction (left to right/right to left)
+diff --git a/utils/pdfinfo.cc b/utils/pdfinfo.cc
+index 7a7fc78..a446c3c 100644
+--- a/utils/pdfinfo.cc
++++ b/utils/pdfinfo.cc
+@@ -114,14 +114,12 @@ static const ArgDesc argDesc[] = { { "-f", argInt, &firstPage, 0, "first page to
+
+ static void printTextString(const GooString *s, const UnicodeMap *uMap)
+ {
+- Unicode *u;
+ char buf[8];
+- int len = TextStringToUCS4(s->toStr(), &u);
+- for (int i = 0; i < len; i++) {
+- int n = uMap->mapUnicode(u[i], buf, sizeof(buf));
++ std::vector<Unicode> u = TextStringToUCS4(s->toStr());
++ for (const auto &c : u) {
++ int n = uMap->mapUnicode(c, buf, sizeof(buf));
+ fwrite(buf, 1, n, stdout);
+ }
+- gfree(u);
+ }
+
+ static void printUCS4String(const Unicode *u, int len, const UnicodeMap *uMap)
+diff --git a/utils/pdftohtml.cc b/utils/pdftohtml.cc
+index 97b141a..d7c0889 100644
+--- a/utils/pdftohtml.cc
++++ b/utils/pdftohtml.cc
+@@ -99,7 +99,7 @@ static char ownerPassword[33] = "";
+ static char userPassword[33] = "";
+ static bool printVersion = false;
+
+-static GooString *getInfoString(Dict *infoDict, const char *key);
++static std::unique_ptr<GooString> getInfoString(Dict *infoDict, const char *key);
+ static GooString *getInfoDate(Dict *infoDict, const char *key);
+
+ static char textEncName[128] = "";
+@@ -158,8 +158,11 @@ int main(int argc, char *argv[])
+ {
+ std::unique_ptr<PDFDoc> doc;
+ GooString *fileName = nullptr;
+- GooString *docTitle = nullptr;
+- GooString *author = nullptr, *keywords = nullptr, *subject = nullptr, *date = nullptr;
++ std::unique_ptr<GooString> docTitle;
++ std::unique_ptr<GooString> author;
++ std::unique_ptr<GooString> keywords;
++ std::unique_ptr<GooString> subject;
++ GooString *date = nullptr;
+ GooString *htmlFileName = nullptr;
+ HtmlOutputDev *htmlOut = nullptr;
+ SplashOutputDev *splashOut = nullptr;
+@@ -317,7 +320,7 @@ int main(int argc, char *argv[])
+ }
+ }
+ if (!docTitle) {
+- docTitle = new GooString(htmlFileName);
++ docTitle = std::make_unique<GooString>(htmlFileName);
+ }
+
+ if (!singleHtml) {
+@@ -330,16 +333,6 @@ int main(int argc, char *argv[])
+ // write text file
+ htmlOut = new HtmlOutputDev(doc->getCatalog(), htmlFileName->c_str(), docTitle->c_str(), author ? author->c_str() : nullptr, keywords ? keywords->c_str() : nullptr, subject ? subject->c_str() : nullptr, date ? date->c_str() : nullptr,
+ rawOrder, firstPage, doOutline);
+- delete docTitle;
+- if (author) {
+- delete author;
+- }
+- if (keywords) {
+- delete keywords;
+- }
+- if (subject) {
+- delete subject;
+- }
+ if (date) {
+ delete date;
+ }
+@@ -397,7 +390,7 @@ error:
+ return exit_status;
+ }
+
+-static GooString *getInfoString(Dict *infoDict, const char *key)
++static std::unique_ptr<GooString> getInfoString(Dict *infoDict, const char *key)
+ {
+ Object obj;
+ // Raw value as read from PDF (may be in pdfDocEncoding or UCS2)
+@@ -406,7 +399,7 @@ static GooString *getInfoString(Dict *infoDict, const char *key)
+ Unicode *unicodeString;
+ int unicodeLength;
+ // Value HTML escaped and converted to desired encoding
+- GooString *encodedString = nullptr;
++ std::unique_ptr<GooString> encodedString;
+ // Is rawString UCS2 (as opposed to pdfDocEncoding)
+ bool isUnicode;
+
+--
+2.40.0
+
new file mode 100644
@@ -0,0 +1,112 @@
+From 0554731052d1a97745cb179ab0d45620589dd9c4 Mon Sep 17 00:00:00 2001
+From: Albert Astals Cid <aacid@kde.org>
+Date: Fri, 7 Jun 2024 00:54:55 +0200
+Subject: [PATCH] pdfinfo: Fix crash in broken documents when using -dests
+
+CVE: CVE-2024-6239
+Upstream-Status: Backport [https://gitlab.freedesktop.org/poppler/poppler/-/commit/0554731052d1a97745cb179ab0d45620589dd9c4]
+
+Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
+---
+ utils/pdfinfo.cc | 35 +++++++++++++++--------------------
+ 1 file changed, 15 insertions(+), 20 deletions(-)
+
+diff --git a/utils/pdfinfo.cc b/utils/pdfinfo.cc
+index a446c3c..4b9166f 100644
+--- a/utils/pdfinfo.cc
++++ b/utils/pdfinfo.cc
+@@ -15,7 +15,7 @@
+ // under GPL version 2 or later
+ //
+ // Copyright (C) 2006 Dom Lachowicz <cinamod@hotmail.com>
+-// Copyright (C) 2007-2010, 2012, 2016-2022 Albert Astals Cid <aacid@kde.org>
++// Copyright (C) 2007-2010, 2012, 2016-2022, 2024 Albert Astals Cid <aacid@kde.org>
+ // Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
+ // Copyright (C) 2011 Vittal Aithal <vittal.aithal@cognidox.com>
+ // Copyright (C) 2012, 2013, 2016-2018, 2021 Adrian Johnson <ajohnson@redneon.com>
+@@ -112,16 +112,21 @@ static const ArgDesc argDesc[] = { { "-f", argInt, &firstPage, 0, "first page to
+ { "-?", argFlag, &printHelp, 0, "print usage information" },
+ {} };
+
+-static void printTextString(const GooString *s, const UnicodeMap *uMap)
++static void printStdTextString(const std::string &s, const UnicodeMap *uMap)
+ {
+ char buf[8];
+- std::vector<Unicode> u = TextStringToUCS4(s->toStr());
++ const std::vector<Unicode> u = TextStringToUCS4(s);
+ for (const auto &c : u) {
+ int n = uMap->mapUnicode(c, buf, sizeof(buf));
+ fwrite(buf, 1, n, stdout);
+ }
+ }
+
++static void printTextString(const GooString *s, const UnicodeMap *uMap)
++{
++ printStdTextString(s->toStr(), uMap);
++}
++
+ static void printUCS4String(const Unicode *u, int len, const UnicodeMap *uMap)
+ {
+ char buf[8];
+@@ -293,11 +298,6 @@ static void printStruct(const StructElement *element, unsigned indent)
+ }
+ }
+
+-struct GooStringCompare
+-{
+- bool operator()(GooString *lhs, GooString *rhs) const { return lhs->cmp(const_cast<GooString *>(rhs)) < 0; }
+-};
+-
+ static void printLinkDest(const std::unique_ptr<LinkDest> &dest)
+ {
+ GooString s;
+@@ -368,29 +368,25 @@ static void printLinkDest(const std::unique_ptr<LinkDest> &dest)
+
+ static void printDestinations(PDFDoc *doc, const UnicodeMap *uMap)
+ {
+- std::map<Ref, std::map<GooString *, std::unique_ptr<LinkDest>, GooStringCompare>> map;
++ std::map<Ref, std::map<std::string, std::unique_ptr<LinkDest>>> map;
+
+ int numDests = doc->getCatalog()->numDestNameTree();
+ for (int i = 0; i < numDests; i++) {
+- GooString *name = new GooString(doc->getCatalog()->getDestNameTreeName(i));
++ const GooString *name = doc->getCatalog()->getDestNameTreeName(i);
+ std::unique_ptr<LinkDest> dest = doc->getCatalog()->getDestNameTreeDest(i);
+- if (dest && dest->isPageRef()) {
++ if (name && dest && dest->isPageRef()) {
+ Ref pageRef = dest->getPageRef();
+- map[pageRef].insert(std::make_pair(name, std::move(dest)));
+- } else {
+- delete name;
++ map[pageRef].insert(std::make_pair(name->toStr(), std::move(dest)));
+ }
+ }
+
+ numDests = doc->getCatalog()->numDests();
+ for (int i = 0; i < numDests; i++) {
+- GooString *name = new GooString(doc->getCatalog()->getDestsName(i));
++ const char *name = doc->getCatalog()->getDestsName(i);
+ std::unique_ptr<LinkDest> dest = doc->getCatalog()->getDestsDest(i);
+- if (dest && dest->isPageRef()) {
++ if (name && dest && dest->isPageRef()) {
+ Ref pageRef = dest->getPageRef();
+ map[pageRef].insert(std::make_pair(name, std::move(dest)));
+- } else {
+- delete name;
+ }
+ }
+
+@@ -404,9 +400,8 @@ static void printDestinations(PDFDoc *doc, const UnicodeMap *uMap)
+ printf("%4d ", i);
+ printLinkDest(it.second);
+ printf(" \"");
+- printTextString(it.first, uMap);
++ printStdTextString(it.first, uMap);
+ printf("\"\n");
+- delete it.first;
+ }
+ }
+ }
+--
+2.40.0
+
@@ -7,7 +7,9 @@ SRC_URI = "http://poppler.freedesktop.org/${BP}.tar.xz \
file://0001-Do-not-overwrite-all-our-build-flags.patch \
file://basename-include.patch \
file://0001-JBIG2Stream-Fix-crash-on-broken-file.patch \
- file://CVE-2023-34872.patch \
+ file://CVE-2023-34872.patch \
+ file://CVE-2024-6239-0001.patch \
+ file://CVE-2024-6239-0002.patch \
"
SRC_URI[sha256sum] = "813fb4b90e7bda63df53205c548602bae728887a60f4048aae4dbd9b1927deff"