Coverage Report

Created: 2026-04-29 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libstaroffice/src/lib/STOFFPropertyHandler.cxx
Line
Count
Source
1
/* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
2
3
/* libstaroffice
4
* Version: MPL 2.0 / LGPLv2+
5
*
6
* The contents of this file are subject to the Mozilla Public License Version
7
* 2.0 (the "License"); you may not use this file except in compliance with
8
* the License or as specified alternatively below. You may obtain a copy of
9
* the License at http://www.mozilla.org/MPL/
10
*
11
* Software distributed under the License is distributed on an "AS IS" basis,
12
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
* for the specific language governing rights and limitations under the
14
* License.
15
*
16
* Major Contributor(s):
17
* Copyright (C) 2002 William Lachance (wrlach@gmail.com)
18
* Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
19
* Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
20
* Copyright (C) 2006, 2007 Andrew Ziem
21
* Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
22
*
23
*
24
* All Rights Reserved.
25
*
26
* For minor contributions see the git repository.
27
*
28
* Alternatively, the contents of this file may be used under the terms of
29
* the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
30
* in which case the provisions of the LGPLv2+ are applicable
31
* instead of those above.
32
*/
33
34
/* This header contains code specific to a small picture
35
 */
36
#include <iostream>
37
#include <sstream>
38
#include <string.h>
39
40
#include <stack>
41
42
#include "libstaroffice_internal.hxx"
43
44
#include <librevenge/librevenge.h>
45
#include <librevenge-stream/librevenge-stream.h>
46
#include <libstaroffice/libstaroffice.hxx>
47
48
#include "STOFFPropertyHandler.hxx"
49
50
////////////////////////////////////////////////////
51
//
52
// STOFFPropertyHandlerEncoder
53
//
54
////////////////////////////////////////////////////
55
STOFFPropertyHandlerEncoder::STOFFPropertyHandlerEncoder()
56
2.98k
  : m_f(std::ios::in | std::ios::out | std::ios::binary)
57
2.98k
{
58
2.98k
}
59
60
void STOFFPropertyHandlerEncoder::insertElement(const char *psName)
61
48.3k
{
62
48.3k
  m_f << 'E';
63
48.3k
  writeString(psName);
64
48.3k
}
65
66
void STOFFPropertyHandlerEncoder::insertElement
67
(const char *psName, const librevenge::RVNGPropertyList &xPropList)
68
127k
{
69
127k
  m_f << 'S';
70
127k
  writeString(psName);
71
127k
  writePropertyList(xPropList);
72
127k
}
73
74
void STOFFPropertyHandlerEncoder::characters(librevenge::RVNGString const &sCharacters)
75
7.29k
{
76
7.29k
  if (sCharacters.len()==0) return;
77
7.29k
  m_f << 'T';
78
7.29k
  writeString(sCharacters);
79
7.29k
}
80
81
void STOFFPropertyHandlerEncoder::writeString(const librevenge::RVNGString &string)
82
2.66M
{
83
2.66M
  unsigned long sz = string.size()+1;
84
2.66M
  writeLong(long(sz));
85
2.66M
  m_f.write(string.cstr(), int(sz));
86
2.66M
}
87
88
void STOFFPropertyHandlerEncoder::writeLong(long val)
89
2.92M
{
90
2.92M
  auto value=static_cast<int32_t>(val);
91
2.92M
  unsigned char const allValue[]= {static_cast<unsigned char>(value&0xFF), static_cast<unsigned char>((value>>8)&0xFF), static_cast<unsigned char>((value>>16)&0xFF), static_cast<unsigned char>((value>>24)&0xFF)};
92
2.92M
  m_f.write(reinterpret_cast<const char *>(allValue), 4);
93
2.92M
}
94
95
void STOFFPropertyHandlerEncoder::writeProperty(const char *key, const librevenge::RVNGProperty &prop)
96
1.23M
{
97
1.23M
  if (!key) {
98
0
    STOFF_DEBUG_MSG(("STOFFPropertyHandlerEncoder::writeProperty: key is NULL\n"));
99
0
    return;
100
0
  }
101
1.23M
  writeString(key);
102
1.23M
  writeString(prop.getStr());
103
1.23M
}
104
105
void STOFFPropertyHandlerEncoder::writePropertyList(const librevenge::RVNGPropertyList &xPropList)
106
231k
{
107
231k
  librevenge::RVNGPropertyList::Iter i(xPropList);
108
231k
  long numElt = 0;
109
1.48M
  for (i.rewind(); i.next();) numElt++;
110
231k
  writeLong(numElt);
111
1.48M
  for (i.rewind(); i.next();) {
112
1.25M
    auto const *child=xPropList.child(i.key());
113
1.25M
    if (!child) {
114
1.23M
      m_f << 'p';
115
1.23M
      writeProperty(i.key(),*i());
116
1.23M
      continue;
117
1.23M
    }
118
21.7k
    m_f << 'v';
119
21.7k
    writeString(i.key());
120
21.7k
    writePropertyListVector(*child);
121
21.7k
  }
122
231k
}
123
124
void STOFFPropertyHandlerEncoder::writePropertyListVector(const librevenge::RVNGPropertyListVector &vect)
125
21.7k
{
126
21.7k
  writeLong(long(vect.count()));
127
125k
  for (unsigned long i=0; i < vect.count(); i++)
128
103k
    writePropertyList(vect[i]);
129
21.7k
}
130
131
bool STOFFPropertyHandlerEncoder::getData(librevenge::RVNGBinaryData &data)
132
2.97k
{
133
2.97k
  data.clear();
134
2.97k
  std::string d=m_f.str();
135
2.97k
  if (d.length() == 0) return false;
136
2.97k
  data.append(reinterpret_cast<const unsigned char *>(d.c_str()), d.length());
137
2.97k
  return true;
138
2.97k
}
139
140
/* \brief Internal: the property decoder
141
 *
142
 * \note see STOFFPropertyHandlerEncoder for the format
143
*/
144
class STOFFPropertyHandlerDecoder
145
{
146
public:
147
  //! constructor given a STOFFPropertyHandler
148
0
  explicit STOFFPropertyHandlerDecoder(STOFFPropertyHandler *hdl=nullptr):m_handler(hdl) {}
149
150
  //! tries to read the data
151
  bool readData(librevenge::RVNGBinaryData const &encoded)
152
0
  {
153
0
    try {
154
0
      auto *inp = const_cast<librevenge::RVNGInputStream *>(encoded.getDataStream());
155
0
      if (!inp) return false;
156
157
0
      while (!inp->isEnd()) {
158
0
        unsigned const char *c;
159
0
        unsigned long numRead;
160
161
0
        c = inp->read(1,numRead);
162
0
        if (!c || numRead != 1) {
163
0
          STOFF_DEBUG_MSG(("STOFFPropertyHandlerDecoder: can not read data type \n"));
164
0
          return false;
165
0
        }
166
0
        switch (*c) {
167
0
        case 'E':
168
0
          if (!readInsertElement(*inp)) return false;
169
0
          break;
170
0
        case 'S':
171
0
          if (!readInsertElementWithList(*inp)) return false;
172
0
          break;
173
0
        case 'T':
174
0
          if (!readCharacters(*inp)) return false;
175
0
          break;
176
0
        default:
177
0
          STOFF_DEBUG_MSG(("STOFFPropertyHandlerDecoder: unknown type='%c' \n", *c));
178
0
          return false;
179
0
        }
180
0
      }
181
0
    }
182
0
    catch (...) {
183
0
      return false;
184
0
    }
185
0
    return true;
186
0
  }
187
188
protected:
189
  //! reads an simple element
190
  bool readInsertElement(librevenge::RVNGInputStream &input)
191
0
  {
192
0
    librevenge::RVNGString s;
193
0
    if (!readString(input, s)) return false;
194
195
0
    if (s.empty()) {
196
0
      STOFF_DEBUG_MSG(("STOFFPropertyHandlerDecoder::readInsertElement find empty tag\n"));
197
0
      return false;
198
0
    }
199
0
    if (m_handler) m_handler->insertElement(s.cstr());
200
0
    return true;
201
0
  }
202
203
  //! reads an element with a property list
204
  bool readInsertElementWithList(librevenge::RVNGInputStream &input)
205
0
  {
206
0
    librevenge::RVNGString s;
207
0
    if (!readString(input, s)) return false;
208
209
0
    if (s.empty()) {
210
0
      STOFF_DEBUG_MSG(("STOFFPropertyHandlerDecoder::readInsertElementWithProperty: find empty tag\n"));
211
0
      return false;
212
0
    }
213
0
    librevenge::RVNGPropertyList lists;
214
0
    if (!readPropertyList(input, lists)) {
215
0
      STOFF_DEBUG_MSG(("STOFFPropertyHandlerDecoder::readInsertElementWithProperty: can not read propertyList for tag %s\n",
216
0
                       s.cstr()));
217
0
      return false;
218
0
    }
219
220
0
    if (m_handler) m_handler->insertElement(s.cstr(), lists);
221
0
    return true;
222
0
  }
223
224
  //! reads a set of characters
225
  bool readCharacters(librevenge::RVNGInputStream &input)
226
0
  {
227
0
    librevenge::RVNGString s;
228
0
    if (!readString(input, s)) return false;
229
0
    if (!s.size()) return true;
230
0
    if (m_handler) m_handler->characters(s);
231
0
    return true;
232
0
  }
233
234
  //
235
  // low level
236
  //
237
238
  //! low level: reads a property vector: number of properties list followed by list of properties list
239
  bool readPropertyListVector(librevenge::RVNGInputStream &input, librevenge::RVNGPropertyListVector &vect)
240
0
  {
241
0
    long numElt;
242
0
    if (!readLong(input, numElt)) return false;
243
244
0
    if (numElt < 0) {
245
0
      STOFF_DEBUG_MSG(("STOFFPropertyHandlerDecoder::readPropertyListVector: can not read numElt=%ld\n",
246
0
                       numElt));
247
0
      return false;
248
0
    }
249
0
    for (long i = 0; i < numElt; i++) {
250
0
      librevenge::RVNGPropertyList lists;
251
0
      if (readPropertyList(input, lists)) {
252
0
        vect.append(lists);
253
0
        continue;
254
0
      }
255
0
      STOFF_DEBUG_MSG(("STOFFPropertyHandlerDecoder::readPropertyListVector: can not read property list %ld\n", i));
256
0
      return false;
257
0
    }
258
0
    return true;
259
0
  }
260
261
  //! low level: reads a property list: number of properties followed by list of properties
262
  bool readPropertyList(librevenge::RVNGInputStream &input, librevenge::RVNGPropertyList &lists)
263
0
  {
264
0
    long numElt;
265
0
    if (!readLong(input, numElt)) return false;
266
267
0
    if (numElt < 0) {
268
0
      STOFF_DEBUG_MSG(("STOFFPropertyHandlerDecoder::readPropertyList: can not read numElt=%ld\n",
269
0
                       numElt));
270
0
      return false;
271
0
    }
272
0
    for (long i = 0; i < numElt; i++) {
273
0
      unsigned const char *c;
274
0
      unsigned long numRead;
275
0
      c = input.read(1,numRead);
276
0
      if (!c || numRead != 1) {
277
0
        STOFF_DEBUG_MSG(("STOFFPropertyHandlerDecoder:readPropertyList can not read data type for child %ld\n", i));
278
0
        return false;
279
0
      }
280
0
      switch (*c) {
281
0
      case 'p':
282
0
        if (readProperty(input, lists)) break;
283
0
        STOFF_DEBUG_MSG(("STOFFPropertyHandlerDecoder::readPropertyList: can not read property %ld\n", i));
284
0
        return false;
285
0
      case 'v': {
286
0
        librevenge::RVNGString key;
287
0
        librevenge::RVNGPropertyListVector vect;
288
0
        if (!readString(input, key) || key.empty() || !readPropertyListVector(input, vect)) {
289
0
          STOFF_DEBUG_MSG(("STOFFPropertyHandlerDecoder::readPropertyList: can not read propertyVector for child %ld\n", i));
290
0
          return false;
291
0
        }
292
0
        lists.insert(key.cstr(),vect);
293
0
        break;
294
0
      }
295
0
      default:
296
0
        STOFF_DEBUG_MSG(("STOFFPropertyHandlerDecoder:readPropertyList find unknown type %c for child %ld\n", char(*c), i));
297
0
        return false;
298
0
      }
299
0
    }
300
0
    return true;
301
0
  }
302
303
  //! low level: reads a property and its value, adds it to \a list
304
  bool readProperty(librevenge::RVNGInputStream &input, librevenge::RVNGPropertyList &list)
305
0
  {
306
0
    librevenge::RVNGString key, val;
307
0
    if (!readString(input, key)) return false;
308
0
    if (!readString(input, val)) return false;
309
310
0
    list.insert(key.cstr(), val);
311
0
    return true;
312
0
  }
313
314
  //! low level: reads a string : size and string
315
  bool readString(librevenge::RVNGInputStream &input, librevenge::RVNGString &s)
316
0
  {
317
0
    long numC = 0;
318
0
    if (!readLong(input, numC)) return false;
319
0
    if (numC==0) {
320
0
      s = librevenge::RVNGString("");
321
0
      return true;
322
0
    }
323
0
    unsigned long numRead;
324
0
    const unsigned char *dt = input.read(static_cast<unsigned long>(numC), numRead);
325
0
    if (dt == nullptr || numRead != static_cast<unsigned long>(numC)) {
326
0
      STOFF_DEBUG_MSG(("STOFFPropertyHandlerDecoder::readString: can not read a string\n"));
327
0
      return false;
328
0
    }
329
0
    s = librevenge::RVNGString(reinterpret_cast<const char *>(dt));
330
0
    return true;
331
0
  }
332
333
  //! low level: reads an long value
334
  static bool readLong(librevenge::RVNGInputStream &input, long &val)
335
0
  {
336
0
    unsigned long numRead = 0;
337
0
    auto const *dt = input.read(4, numRead);
338
0
    if (dt == nullptr || numRead != 4) {
339
0
      STOFF_DEBUG_MSG(("STOFFPropertyHandlerDecoder::readLong: can not read long\n"));
340
0
      return false;
341
0
    }
342
0
    val = long((dt[3]<<24)|(dt[2]<<16)|(dt[1]<<8)|dt[0]);
343
0
    return true;
344
0
  }
345
private:
346
  STOFFPropertyHandlerDecoder(STOFFPropertyHandlerDecoder const &orig);
347
  STOFFPropertyHandlerDecoder &operator=(STOFFPropertyHandlerDecoder const &);
348
349
protected:
350
  //! the streamfile
351
  STOFFPropertyHandler *m_handler;
352
};
353
354
////////////////////////////////////////////////////
355
//
356
// STOFFPropertyHandler
357
//
358
////////////////////////////////////////////////////
359
STOFFPropertyHandler::~STOFFPropertyHandler()
360
0
{
361
0
}
362
363
bool STOFFPropertyHandler::checkData(librevenge::RVNGBinaryData const &encoded)
364
0
{
365
0
  STOFFPropertyHandlerDecoder decod;
366
0
  return decod.readData(encoded);
367
0
}
368
369
bool STOFFPropertyHandler::readData(librevenge::RVNGBinaryData const &encoded)
370
0
{
371
0
  STOFFPropertyHandlerDecoder decod(this);
372
0
  return decod.readData(encoded);
373
0
}
374
375
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: