/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: |