Coverage Report

Created: 2026-07-20 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwps/src/lib/WPSTextParser.cpp
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
/* libwps
3
 * Version: MPL 2.0 / LGPLv2.1+
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * Major Contributor(s):
10
 * Copyright (C) 2009, 2011 Alonso Laurent (alonso@loria.fr)
11
 * Copyright (C) 2006, 2007 Andrew Ziem
12
 * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
13
 * Copyright (C) 2004 Marc Maurer (uwog@uwog.net)
14
 * Copyright (C) 2003-2005 William Lachance (william.lachance@sympatico.ca)
15
 *
16
 * For minor contributions see the git repository.
17
 *
18
 * Alternatively, the contents of this file may be used under the terms
19
 * of the GNU Lesser General Public License Version 2.1 or later
20
 * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
21
 * applicable instead of those above.
22
 *
23
 * For further information visit http://libwps.sourceforge.net
24
 */
25
26
#include <stdlib.h>
27
#include <string.h>
28
29
#include "libwps_internal.h"
30
31
#include "WPSParser.h"
32
33
#include "WPSTextParser.h"
34
35
////////////////////////////////////////////////////////////
36
// Constructor
37
////////////////////////////////////////////////////////////
38
WPSTextParser::WPSTextParser(WPSParser &parser, RVNGInputStreamPtr &input)
39
17.2k
  : m_version(0)
40
17.2k
  , m_input(input)
41
17.2k
  , m_mainParser(parser)
42
17.2k
  , m_textPositions(),
43
17.2k
    m_FODList()
44
17.2k
  , m_asciiFile(parser.ascii())
45
17.2k
{
46
17.2k
}
47
48
17.2k
WPSTextParser::~WPSTextParser() {}
49
50
51
int WPSTextParser::version() const
52
16.4M
{
53
16.4M
  if (m_version <= 0)
54
7.77k
    m_version=m_mainParser.version();
55
16.4M
  return m_version;
56
16.4M
}
57
58
WPSParser::NameMultiMap &WPSTextParser::getNameEntryMap()
59
3.45M
{
60
3.45M
  return m_mainParser.getNameEntryMap();
61
3.45M
}
62
63
WPSParser::NameMultiMap const &WPSTextParser::getNameEntryMap() const
64
6.02k
{
65
6.02k
  return m_mainParser.getNameEntryMap();
66
6.02k
}
67
68
////////////////////////////////////////////////////////////
69
// read data
70
////////////////////////////////////////////////////////////
71
bool WPSTextParser::readFDP(WPSEntry const &entry,
72
                            std::vector<DataFOD> &fods,
73
                            WPSTextParser::FDPParser parser)
74
2.55M
{
75
2.55M
  RVNGInputStreamPtr input = getInput();
76
2.55M
  if (entry.length() <= 0 || entry.begin() <= 0)
77
439k
  {
78
439k
    WPS_DEBUG_MSG(("WPSTextParser::readFDP: warning: FDP entry unintialized\n"));
79
439k
    return false;
80
439k
  }
81
82
2.11M
  entry.setParsed();
83
2.11M
  long page_offset = entry.begin();
84
2.11M
  long length = entry.length();
85
2.11M
  long endPage = entry.end();
86
87
2.11M
  bool smallFDP = version() < 5;
88
2.11M
  int deplSize = smallFDP ? 1 : 2;
89
2.11M
  int headerSize = smallFDP ? 4 : 8;
90
91
2.11M
  if (length < headerSize)
92
13.6k
  {
93
13.6k
    WPS_DEBUG_MSG(("WPSTextParser::readFDP: warning: FDP offset=0x%lx, length=0x%lx\n",
94
13.6k
                   static_cast<unsigned long>(page_offset), static_cast<unsigned long>(length)));
95
13.6k
    return false;
96
13.6k
  }
97
98
2.10M
  libwps::DebugStream f, f2;
99
2.10M
  if (smallFDP)
100
48.0k
  {
101
48.0k
    endPage--;
102
48.0k
    input->seek(endPage, librevenge::RVNG_SEEK_SET);
103
48.0k
  }
104
2.05M
  else
105
2.05M
    input->seek(page_offset, librevenge::RVNG_SEEK_SET);
106
2.10M
  uint16_t cfod = deplSize == 1 ? uint16_t(libwps::readU8(m_input)) : libwps::readU16(m_input);
107
108
2.10M
  f << "FDP: N="<<int(cfod);
109
2.10M
  if (smallFDP) input->seek(page_offset, librevenge::RVNG_SEEK_SET);
110
2.05M
  else f << ", unk=" << libwps::read16(m_input);
111
112
2.10M
  if (headerSize+(4+deplSize)*static_cast<long>(cfod) > length)
113
120k
  {
114
120k
    WPS_DEBUG_MSG(("WPSTextParser::readFDP: error: cfod = %i (0x%X)\n", cfod, unsigned(cfod)));
115
120k
    return false;
116
120k
  }
117
118
1.98M
  auto firstFod = int(fods.size());
119
1.98M
  long lastLimit = firstFod ? fods.back().m_pos : 0;
120
121
1.98M
  long lastReadPos = 0L;
122
123
1.98M
  DataFOD::Type type = DataFOD::ATTR_UNKN;
124
1.98M
  if (entry.hasType("FDPC")) type = DataFOD::ATTR_TEXT;
125
1.16M
  else if (entry.hasType("FDPP")) type = DataFOD::ATTR_PARAG;
126
86
  else
127
86
  {
128
86
    WPS_DEBUG_MSG(("WPSTextParser::readFDP: FDP error: unknown type = '%s'\n", entry.type().c_str()));
129
86
  }
130
131
  /* Read array of fcLim of FODs.  The fcLim refers to the offset of the
132
     last character covered by the formatting. */
133
6.14M
  for (int i = 0; i <= cfod; ++i)
134
4.25M
  {
135
4.25M
    DataFOD fod;
136
4.25M
    fod.m_type = type;
137
4.25M
    fod.m_pos = long(libwps::readU32(m_input));
138
4.25M
    if (fod.m_pos == 0) fod.m_pos=m_textPositions.begin();
139
140
    /* check that fcLim is not too large */
141
4.25M
    if (fod.m_pos > m_textPositions.end())
142
75.7k
    {
143
75.7k
      WPS_DEBUG_MSG(("WPSTextParser::readFDP: error: length of 'text selection' %ld > "
144
75.7k
                     "total text length %ld\n", fod.m_pos, m_textPositions.end()));
145
75.7k
      return false;
146
75.7k
    }
147
148
    /* check that pos is monotonic */
149
4.18M
    if (lastLimit > fod.m_pos)
150
23.3k
    {
151
23.3k
      WPS_DEBUG_MSG(("WPSTextParser::readFDP: error: character position list must "
152
23.3k
                     "be monotonic, but found %ld, %ld\n", lastLimit, fod.m_pos));
153
23.3k
      return false;
154
23.3k
    }
155
156
4.15M
    lastLimit = fod.m_pos;
157
158
4.15M
    if (i != cfod)
159
2.27M
      fods.push_back(fod);
160
1.88M
    else // ignore the last text position
161
1.88M
      lastReadPos = fod.m_pos;
162
4.15M
  }
163
164
1.88M
  std::vector<DataFOD>::iterator fods_iter;
165
  /* Read array of bfprop of FODs.  The bfprop is the offset where
166
     the FPROP is located. */
167
1.88M
  f << ", Tpos:defP=(";
168
3.90M
  for (fods_iter = fods.begin() + firstFod; fods_iter!= fods.end(); ++fods_iter)
169
2.06M
  {
170
2.06M
    unsigned depl = deplSize == 1 ? libwps::readU8(m_input) : libwps::readU16(m_input);
171
    /* check size of bfprop  */
172
2.06M
    if ((depl < unsigned(headerSize+(4+deplSize)*cfod) && depl > 0) ||
173
2.05M
            page_offset+long(depl)  > endPage)
174
36.3k
    {
175
36.3k
      WPS_DEBUG_MSG(("WPSTextParser::readFDP: error: pos of bfprop is bad "
176
36.3k
                     "%u (0x%X)\n", depl, depl));
177
36.3k
      return false;
178
36.3k
    }
179
180
2.02M
    if (depl)
181
1.95M
      (*fods_iter).m_defPos = long(depl) + page_offset;
182
2.02M
  }
183
1.84M
  ascii().addPos(input->tell());
184
185
1.84M
  std::map<long,int> mapPtr;
186
1.84M
  bool smallSzInProp = smallFDP;
187
3.74M
  for (fods_iter = fods.begin() + firstFod; fods_iter!= fods.end(); ++fods_iter)
188
1.98M
  {
189
1.98M
    long pos = (*fods_iter).m_defPos;
190
1.98M
    f << std::hex << (*fods_iter).m_pos << std::dec << ":";
191
1.98M
    if (pos == 0)
192
64.0k
    {
193
64.0k
      f << "_, ";
194
64.0k
      continue;
195
64.0k
    }
196
197
1.92M
    auto it= mapPtr.find(pos);
198
1.92M
    if (it != mapPtr.end())
199
61.4k
    {
200
61.4k
      (*fods_iter).m_id = mapPtr[pos];
201
61.4k
      f << entry.type() << (*fods_iter).m_id << ", ";
202
61.4k
      continue;
203
61.4k
    }
204
205
1.86M
    input->seek(pos, librevenge::RVNG_SEEK_SET);
206
1.86M
    int szProp = smallSzInProp ? libwps::readU8(m_input) : libwps::readU16(m_input);
207
1.86M
    if (smallSzInProp) szProp++;
208
1.86M
    if (szProp == 0)
209
54.5k
    {
210
54.5k
      WPS_DEBUG_MSG(("WPSTextParser::readFDP: error: 0 == szProp at file offset 0x%lx\n", static_cast<unsigned long>(input->tell()-1)));
211
54.5k
      return false;
212
54.5k
    }
213
1.80M
    long endPos = pos+szProp;
214
1.80M
    if (endPos > endPage)
215
33.2k
    {
216
33.2k
      WPS_DEBUG_MSG(("WPSTextParser::readFDP: error: cch = %d, too large\n", szProp));
217
33.2k
      return false;
218
33.2k
    }
219
220
1.77M
    int id=0;
221
1.77M
    std::string mess;
222
1.77M
    if (parser &&(this->*parser)(endPos, id, mess))
223
1.72M
    {
224
1.72M
      (*fods_iter).m_id = mapPtr[pos] = id;
225
226
1.72M
      f2.str("");
227
1.72M
      f2 << entry.type()  << id <<":" << mess;
228
1.72M
      ascii().addPos(pos);
229
1.72M
      ascii().addNote(f2.str().c_str());
230
1.72M
      pos = input->tell();
231
1.72M
    }
232
1.77M
    f << entry.type() << (*fods_iter).m_id << ", ";
233
1.77M
    if (pos != endPos)
234
83.6k
    {
235
83.6k
      f2.str("");
236
83.6k
      f2 << entry.type() << "###";
237
83.6k
      ascii().addPos(pos);
238
83.6k
      ascii().addNote(f2.str().c_str());
239
83.6k
    }
240
1.77M
  }
241
1.75M
  f << "), lstPos=" << std::hex << lastReadPos << std::dec << ", ";
242
243
1.75M
  ascii().addPos(page_offset);
244
1.75M
  ascii().addNote(f.str().c_str());
245
246
  /* go to end of page */
247
1.75M
  input->seek(endPage, librevenge::RVNG_SEEK_SET);
248
249
1.75M
  return m_textPositions.end() > lastReadPos;
250
1.84M
}
251
252
std::vector<WPSTextParser::DataFOD> WPSTextParser::mergeSortedFODLists
253
(std::vector<WPSTextParser::DataFOD> const &lst1,
254
 std::vector<WPSTextParser::DataFOD> const &lst2) const
255
1.04M
{
256
1.04M
  std::vector<WPSTextParser::DataFOD> res;
257
  // we regroup these two lists in one list
258
1.04M
  size_t num1 = lst1.size(), i1 = 0;
259
1.04M
  size_t num2 = lst2.size(), i2 = 0;
260
261
646M
  while (i1 < num1 || i2 < num2)
262
645M
  {
263
645M
    DataFOD val;
264
645M
    if (i2 == num2) val = lst1[i1++];
265
644M
    else if (i1 == num1 || lst2[i2].m_pos < lst1[i1].m_pos)
266
7.55M
      val = lst2[i2++];
267
637M
    else val = lst1[i1++];
268
269
645M
    if (val.m_pos < m_textPositions.begin() || val.m_pos > m_textPositions.end())
270
6.60M
      continue;
271
272
638M
    res.push_back(val);
273
638M
  }
274
1.04M
  return res;
275
1.04M
}
276
/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */