LibreOffice Module oox (master)  1
customshapepresetdata.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
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 
10 #include <config_folders.h>
11 #include <rtl/bootstrap.hxx>
12 #include <sal/log.hxx>
13 #include <tools/stream.hxx>
14 #include <comphelper/sequence.hxx>
15 
17 #include <oox/token/properties.hxx>
18 #include <oox/token/tokenmap.hxx>
19 #include <com/sun/star/awt/Rectangle.hpp>
20 #include <com/sun/star/beans/PropertyValue.hpp>
21 #include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
22 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
23 
24 using namespace ::com::sun::star;
25 
26 namespace
27 {
28 // Parses a string like: Value = (any) { (long) 19098 }, State = (com.sun.star.beans.PropertyState) DIRECT_VALUE, Name = "adj"
29 void lcl_parseAdjustmentValue(
30  std::vector<drawing::EnhancedCustomShapeAdjustmentValue>& rAdjustmentValues,
31  const OString& rValue)
32 {
33  sal_Int32 nIndex = 0;
34  drawing::EnhancedCustomShapeAdjustmentValue aAdjustmentValue;
35  do
36  {
37  OString aToken = rValue.getToken(0, ',', nIndex).trim();
38  static const char aNamePrefix[] = "Name = \"";
39  static const char aValuePrefix[] = "Value = (any) { (long) ";
40  if (aToken.startsWith(aNamePrefix))
41  {
42  OString aName = aToken.copy(strlen(aNamePrefix),
43  aToken.getLength() - strlen(aNamePrefix) - strlen("\""));
44  aAdjustmentValue.Name = OUString::fromUtf8(aName);
45  }
46  else if (aToken.startsWith(aValuePrefix))
47  {
48  OString aValue = aToken.copy(strlen(aValuePrefix),
49  aToken.getLength() - strlen(aValuePrefix) - strlen(" }"));
50  aAdjustmentValue.Value <<= aValue.toInt32();
51  }
52  else if (!aToken.startsWith("State = "))
53  SAL_WARN("oox", "lcl_parseAdjustmentValue: unexpected prefix: " << aToken);
54  } while (nIndex >= 0);
55  rAdjustmentValues.push_back(aAdjustmentValue);
56 }
57 
58 // Parses a string like: { Value = (any) { (long) 19098 }, State = (com.sun.star.beans.PropertyState) DIRECT_VALUE, Name = "adj" }, { Value = ..., State = ..., Name = ... }
59 void lcl_parseAdjustmentValues(
60  std::vector<drawing::EnhancedCustomShapeAdjustmentValue>& rAdjustmentValues,
61  const OString& rValue)
62 {
63  sal_Int32 nLevel = 0;
64  sal_Int32 nStart = 0;
65  for (sal_Int32 i = 0; i < rValue.getLength(); ++i)
66  {
67  if (rValue[i] == '{')
68  {
69  if (!nLevel)
70  nStart = i;
71  nLevel++;
72  }
73  else if (rValue[i] == '}')
74  {
75  nLevel--;
76  if (!nLevel)
77  {
78  lcl_parseAdjustmentValue(
79  rAdjustmentValues,
80  rValue.copy(nStart + strlen("{ "), i - nStart - strlen(" },")));
81  }
82  }
83  }
84 }
85 
86 drawing::EnhancedCustomShapeParameterPair
87 lcl_parseEnhancedCustomShapeParameterPair(const OString& rValue)
88 {
89  drawing::EnhancedCustomShapeParameterPair aPair;
90  // We expect the following here: First.Value, First.Type, Second.Value, Second.Type
91  static const char aExpectedFVPrefix[]
92  = "First = (com.sun.star.drawing.EnhancedCustomShapeParameter) { Value = (any) { (long) ";
93  assert(rValue.startsWith(aExpectedFVPrefix));
94  sal_Int32 nIndex = strlen(aExpectedFVPrefix);
95  aPair.First.Value <<= static_cast<sal_uInt32>(rValue.getToken(0, '}', nIndex).toInt32());
96 
97  static const char aExpectedFTPrefix[] = ", Type = (short) ";
98  assert(nIndex >= 0 && rValue.match(aExpectedFTPrefix, nIndex));
99  nIndex += strlen(aExpectedFTPrefix);
100  aPair.First.Type = static_cast<sal_uInt16>(rValue.getToken(0, '}', nIndex).toInt32());
101 
102  static const char aExpectedSVPrefix[] = ", Second = "
103  "(com.sun.star.drawing.EnhancedCustomShapeParameter) { "
104  "Value = (any) { (long) ";
105  assert(nIndex >= 0 && rValue.match(aExpectedSVPrefix, nIndex));
106  nIndex += strlen(aExpectedSVPrefix);
107  aPair.Second.Value <<= static_cast<sal_uInt32>(rValue.getToken(0, '}', nIndex).toInt32());
108 
109  static const char aExpectedSTPrefix[] = ", Type = (short) ";
110  assert(nIndex >= 0 && rValue.match(aExpectedSTPrefix, nIndex));
111  nIndex += strlen(aExpectedSTPrefix);
112  aPair.Second.Type = static_cast<sal_uInt16>(rValue.getToken(0, '}', nIndex).toInt32());
113  return aPair;
114 }
115 
116 drawing::EnhancedCustomShapeSegment lcl_parseEnhancedCustomShapeSegment(const OString& rValue)
117 {
118  drawing::EnhancedCustomShapeSegment aSegment;
119  // We expect the following here: Command, Count
120  static const char aExpectedCommandPrefix[] = "Command = (short) ";
121  assert(rValue.startsWith(aExpectedCommandPrefix));
122  sal_Int32 nIndex = strlen(aExpectedCommandPrefix);
123  aSegment.Command = static_cast<sal_Int16>(rValue.getToken(0, ',', nIndex).toInt32());
124 
125  static const char aExpectedCountPrefix[] = " Count = (short) ";
126  assert(nIndex >= 0 && rValue.match(aExpectedCountPrefix, nIndex));
127  nIndex += strlen(aExpectedCountPrefix);
128  aSegment.Count = static_cast<sal_Int16>(rValue.getToken(0, '}', nIndex).toInt32());
129  return aSegment;
130 }
131 
132 awt::Rectangle lcl_parseRectangle(const OString& rValue)
133 {
134  awt::Rectangle aRectangle;
135  // We expect the following here: X, Y, Width, Height
136  static const char aExpectedXPrefix[] = "X = (long) ";
137  assert(rValue.startsWith(aExpectedXPrefix));
138  sal_Int32 nIndex = strlen(aExpectedXPrefix);
139  aRectangle.X = rValue.getToken(0, ',', nIndex).toInt32();
140 
141  static const char aExpectedYPrefix[] = " Y = (long) ";
142  assert(nIndex >= 0 && rValue.match(aExpectedYPrefix, nIndex));
143  nIndex += strlen(aExpectedYPrefix);
144  aRectangle.Y = rValue.getToken(0, ',', nIndex).toInt32();
145 
146  static const char aExpectedWidthPrefix[] = " Width = (long) ";
147  assert(nIndex >= 0 && rValue.match(aExpectedWidthPrefix, nIndex));
148  nIndex += strlen(aExpectedWidthPrefix);
149  aRectangle.Width = rValue.getToken(0, ',', nIndex).toInt32();
150 
151  static const char aExpectedHeightPrefix[] = " Height = (long) ";
152  assert(nIndex >= 0 && rValue.match(aExpectedHeightPrefix, nIndex));
153  nIndex += strlen(aExpectedHeightPrefix);
154  aRectangle.Height = rValue.copy(nIndex).toInt32();
155 
156  return aRectangle;
157 }
158 
159 awt::Size lcl_parseSize(const OString& rValue)
160 {
161  awt::Size aSize;
162  // We expect the following here: Width, Height
163  static const char aExpectedWidthPrefix[] = "Width = (long) ";
164  assert(rValue.startsWith(aExpectedWidthPrefix));
165  sal_Int32 nIndex = strlen(aExpectedWidthPrefix);
166  aSize.Width = rValue.getToken(0, ',', nIndex).toInt32();
167 
168  static const char aExpectedHeightPrefix[] = " Height = (long) ";
169  assert(nIndex >= 0 && rValue.match(aExpectedHeightPrefix, nIndex));
170  nIndex += strlen(aExpectedHeightPrefix);
171  aSize.Height = rValue.copy(nIndex).toInt32();
172 
173  return aSize;
174 }
175 
176 drawing::EnhancedCustomShapeTextFrame lcl_parseEnhancedCustomShapeTextFrame(const OString& rValue)
177 {
178  drawing::EnhancedCustomShapeTextFrame aTextFrame;
179  sal_Int32 nLevel = 0;
180  bool bIgnore = false;
181  sal_Int32 nStart = 0;
182  for (sal_Int32 i = 0; i < rValue.getLength(); ++i)
183  {
184  if (rValue[i] == '{')
185  {
186  if (!nLevel)
187  bIgnore = true;
188  nLevel++;
189  }
190  else if (rValue[i] == '}')
191  {
192  nLevel--;
193  if (!nLevel)
194  bIgnore = false;
195  }
196  else if (rValue[i] == ',' && !bIgnore)
197  {
198  OString aToken = rValue.copy(nStart, i - nStart);
199  static const char aExpectedPrefix[]
200  = "TopLeft = (com.sun.star.drawing.EnhancedCustomShapeParameterPair) { ";
201  if (aToken.startsWith(aExpectedPrefix))
202  {
203  aToken = aToken.copy(strlen(aExpectedPrefix),
204  aToken.getLength() - strlen(aExpectedPrefix) - strlen(" }"));
205  aTextFrame.TopLeft = lcl_parseEnhancedCustomShapeParameterPair(aToken);
206  }
207  else
208  SAL_WARN("oox",
209  "lcl_parseEnhancedCustomShapeTextFrame: unexpected token: " << aToken);
210  nStart = i + strlen(", ");
211  }
212  }
213 
214  OString aToken = rValue.copy(nStart);
215  static const char aExpectedPrefix[]
216  = "BottomRight = (com.sun.star.drawing.EnhancedCustomShapeParameterPair) { ";
217  if (aToken.startsWith(aExpectedPrefix))
218  {
219  aToken = aToken.copy(strlen(aExpectedPrefix),
220  aToken.getLength() - strlen(aExpectedPrefix) - strlen(" }"));
221  aTextFrame.BottomRight = lcl_parseEnhancedCustomShapeParameterPair(aToken);
222  }
223  else
224  SAL_WARN("oox",
225  "lcl_parseEnhancedCustomShapeTextFrame: unexpected token at the end: " << aToken);
226 
227  return aTextFrame;
228 }
229 
230 // Parses a string like: Name = "Position", Handle = (long) 0, Value = (any) { ... }, State = (com.sun.star.beans.PropertyState) DIRECT_VALUE
231 // where "{ ... }" may contain "," as well.
232 void lcl_parseHandlePosition(std::vector<beans::PropertyValue>& rHandle, const OString& rValue)
233 {
234  sal_Int32 nLevel = 0;
235  bool bIgnore = false;
236  sal_Int32 nStart = 0;
237  for (sal_Int32 i = 0; i < rValue.getLength(); ++i)
238  {
239  if (rValue[i] == '{')
240  {
241  if (!nLevel)
242  bIgnore = true;
243  nLevel++;
244  }
245  else if (rValue[i] == '}')
246  {
247  nLevel--;
248  if (!nLevel)
249  bIgnore = false;
250  }
251  else if (rValue[i] == ',' && !bIgnore)
252  {
253  OString aToken = rValue.copy(nStart, i - nStart);
254  static const char aExpectedPrefix[]
255  = "Value = (any) { (com.sun.star.drawing.EnhancedCustomShapeParameterPair) { ";
256  if (aToken.startsWith(aExpectedPrefix))
257  {
258  aToken = aToken.copy(strlen(aExpectedPrefix),
259  aToken.getLength() - strlen(aExpectedPrefix) - strlen(" } }"));
260 
261  beans::PropertyValue aPropertyValue;
262  aPropertyValue.Name = "Position";
263  aPropertyValue.Value <<= lcl_parseEnhancedCustomShapeParameterPair(aToken);
264  rHandle.push_back(aPropertyValue);
265  }
266  else if (!aToken.startsWith("Name =") && !aToken.startsWith("Handle ="))
267  SAL_WARN("oox", "lcl_parseHandlePosition: unexpected token: " << aToken);
268  nStart = i + strlen(", ");
269  }
270  }
271 }
272 
273 // Parses a string like: Name = "RangeYMaximum", Handle = (long) 0, Value = (any) { ... }, State = (com.sun.star.beans.PropertyState) DIRECT_VALUE
274 // where "{ ... }" may contain "," as well.
275 void lcl_parseHandleRange(std::vector<beans::PropertyValue>& rHandle, const OString& rValue,
276  const OUString& rName)
277 {
278  sal_Int32 nLevel = 0;
279  bool bIgnore = false;
280  sal_Int32 nStart = 0;
281  for (sal_Int32 i = 0; i < rValue.getLength(); ++i)
282  {
283  if (rValue[i] == '{')
284  {
285  if (!nLevel)
286  bIgnore = true;
287  nLevel++;
288  }
289  else if (rValue[i] == '}')
290  {
291  nLevel--;
292  if (!nLevel)
293  bIgnore = false;
294  }
295  else if (rValue[i] == ',' && !bIgnore)
296  {
297  static const char aExpectedPrefix[]
298  = "Value = (any) { (com.sun.star.drawing.EnhancedCustomShapeParameter) { ";
299  if (rValue.match(aExpectedPrefix, nStart))
300  {
301  drawing::EnhancedCustomShapeParameter aParameter;
302  sal_Int32 nIndex{ nStart + static_cast<sal_Int32>(strlen(aExpectedPrefix)) };
303  // We expect the following here: Value and Type
304  static const char aExpectedVPrefix[] = "Value = (any) { (long) ";
305  assert(rValue.match(aExpectedVPrefix, nIndex));
306  nIndex += strlen(aExpectedVPrefix);
307  aParameter.Value <<= rValue.getToken(0, '}', nIndex).toInt32();
308 
309  static const char aExpectedTPrefix[] = ", Type = (short) ";
310  assert(nIndex >= 0 && rValue.match(aExpectedTPrefix, nIndex));
311  nIndex += strlen(aExpectedTPrefix);
312  aParameter.Type = static_cast<sal_Int16>(rValue.getToken(0, '}', nIndex).toInt32());
313 
314  beans::PropertyValue aPropertyValue;
315  aPropertyValue.Name = rName;
316  aPropertyValue.Value <<= aParameter;
317  rHandle.push_back(aPropertyValue);
318  }
319  else if (!rValue.match("Name =", nStart) && !rValue.match("Handle =", nStart))
320  SAL_WARN("oox", "lcl_parseHandleRange: unexpected token: "
321  << rValue.copy(nStart, i - nStart));
322  nStart = i + strlen(", ");
323  }
324  }
325 }
326 
327 // Parses a string like: Name = "RefY", Handle = (long) 0, Value = (any) { (long) 0 }, State = (com.sun.star.beans.PropertyState) DIRECT_VALUE
328 void lcl_parseHandleRef(std::vector<beans::PropertyValue>& rHandle, const OString& rValue,
329  const OUString& rName)
330 {
331  static const char aPrefix[] = "\", Handle = (long) 0, Value = (any) { (long) ";
332  const sal_Int32 nCheck = SAL_N_ELEMENTS(aPrefix) - 1;
333  const sal_Int32 nStart = SAL_N_ELEMENTS("Name = \"") - 1 + rName.getLength();
334 
335  if (rValue.copy(nStart, nCheck).equalsL(aPrefix, nCheck))
336  {
337  sal_Int32 nIndex = nStart + nCheck;
338  beans::PropertyValue aPropertyValue;
339  aPropertyValue.Name = rName;
340  // We only expect a Value here
341  aPropertyValue.Value <<= rValue.getToken(0, '}', nIndex).toInt32();
342  rHandle.push_back(aPropertyValue);
343  }
344  else
345  SAL_WARN("oox", "lcl_parseHandleRef: unexpected value: " << rValue);
346 }
347 
348 uno::Sequence<beans::PropertyValue> lcl_parseHandle(const OString& rValue)
349 {
350  std::vector<beans::PropertyValue> aRet;
351  sal_Int32 nLevel = 0;
352  sal_Int32 nStart = 0;
353  for (sal_Int32 i = 0; i < rValue.getLength(); ++i)
354  {
355  if (rValue[i] == '{')
356  {
357  if (!nLevel)
358  nStart = i;
359  nLevel++;
360  }
361  else if (rValue[i] == '}')
362  {
363  nLevel--;
364  if (!nLevel)
365  {
366  OString aToken = rValue.copy(nStart + strlen("{ "), i - nStart - strlen(" },"));
367  if (aToken.startsWith("Name = \"Position\""))
368  lcl_parseHandlePosition(aRet, aToken);
369  else if (aToken.startsWith("Name = \"RangeXMaximum\""))
370  lcl_parseHandleRange(aRet, aToken, "RangeXMaximum");
371  else if (aToken.startsWith("Name = \"RangeXMinimum\""))
372  lcl_parseHandleRange(aRet, aToken, "RangeXMinimum");
373  else if (aToken.startsWith("Name = \"RangeYMaximum\""))
374  lcl_parseHandleRange(aRet, aToken, "RangeYMaximum");
375  else if (aToken.startsWith("Name = \"RangeYMinimum\""))
376  lcl_parseHandleRange(aRet, aToken, "RangeYMinimum");
377  else if (aToken.startsWith("Name = \"RadiusRangeMaximum\""))
378  lcl_parseHandleRange(aRet, aToken, "RadiusRangeMaximum");
379  else if (aToken.startsWith("Name = \"RadiusRangeMinimum\""))
380  lcl_parseHandleRange(aRet, aToken, "RadiusRangeMinimum");
381  else if (aToken.startsWith("Name = \"RefX\""))
382  lcl_parseHandleRef(aRet, aToken, "RefX");
383  else if (aToken.startsWith("Name = \"RefY\""))
384  lcl_parseHandleRef(aRet, aToken, "RefY");
385  else if (aToken.startsWith("Name = \"RefR\""))
386  lcl_parseHandleRef(aRet, aToken, "RefR");
387  else if (aToken.startsWith("Name = \"RefAngle\""))
388  lcl_parseHandleRef(aRet, aToken, "RefAngle");
389  else
390  SAL_WARN("oox", "lcl_parseHandle: unexpected token: " << aToken);
391  }
392  }
393  }
394  return comphelper::containerToSequence(aRet);
395 }
396 
397 void lcl_parseHandles(std::vector<uno::Sequence<beans::PropertyValue>>& rHandles,
398  const OString& rValue)
399 {
400  sal_Int32 nLevel = 0;
401  sal_Int32 nStart = 0;
402  for (sal_Int32 i = 0; i < rValue.getLength(); ++i)
403  {
404  if (rValue[i] == '{')
405  {
406  if (!nLevel)
407  nStart = i;
408  nLevel++;
409  }
410  else if (rValue[i] == '}')
411  {
412  nLevel--;
413  if (!nLevel)
414  {
415  uno::Sequence<beans::PropertyValue> aHandle = lcl_parseHandle(
416  rValue.copy(nStart + strlen("{ "), i - nStart - strlen(" },")));
417  rHandles.push_back(aHandle);
418  }
419  }
420  }
421 }
422 
423 void lcl_parseEquations(std::vector<OUString>& rEquations, const OString& rValue)
424 {
425  bool bInString = false;
426  sal_Int32 nStart = 0;
427  for (sal_Int32 i = 0; i < rValue.getLength(); ++i)
428  {
429  if (rValue[i] == '"' && !bInString)
430  {
431  nStart = i;
432  bInString = true;
433  }
434  else if (rValue[i] == '"' && bInString)
435  {
436  bInString = false;
437  rEquations.push_back(OUString::fromUtf8(
438  rValue.subView(nStart + strlen("\""), i - nStart - strlen("\""))));
439  }
440  }
441 }
442 
443 void lcl_parsePathCoordinateValues(std::vector<beans::PropertyValue>& rPath, const OString& rValue)
444 {
445  std::vector<drawing::EnhancedCustomShapeParameterPair> aPairs;
446  sal_Int32 nLevel = 0;
447  sal_Int32 nStart = 0;
448  for (sal_Int32 i = 0; i < rValue.getLength(); ++i)
449  {
450  if (rValue[i] == '{')
451  {
452  if (!nLevel)
453  nStart = i;
454  nLevel++;
455  }
456  else if (rValue[i] == '}')
457  {
458  nLevel--;
459  if (!nLevel)
460  aPairs.push_back(lcl_parseEnhancedCustomShapeParameterPair(
461  rValue.copy(nStart + strlen("{ "), i - nStart - strlen(" },"))));
462  }
463  }
464 
465  beans::PropertyValue aPropertyValue;
466  aPropertyValue.Name = "Coordinates";
467  aPropertyValue.Value <<= comphelper::containerToSequence(aPairs);
468  rPath.push_back(aPropertyValue);
469 }
470 
471 // Parses a string like: Name = "Coordinates", Handle = (long) 0, Value = (any) { ... }, State = (com.sun.star.beans.PropertyState) DIRECT_VALUE
472 // where "{ ... }" may contain "," as well.
473 void lcl_parsePathCoordinates(std::vector<beans::PropertyValue>& rPath, const OString& rValue)
474 {
475  sal_Int32 nLevel = 0;
476  bool bIgnore = false;
477  sal_Int32 nStart = 0;
478  for (sal_Int32 i = 0; i < rValue.getLength(); ++i)
479  {
480  if (rValue[i] == '{')
481  {
482  if (!nLevel)
483  bIgnore = true;
484  nLevel++;
485  }
486  else if (rValue[i] == '}')
487  {
488  nLevel--;
489  if (!nLevel)
490  bIgnore = false;
491  }
492  else if (rValue[i] == ',' && !bIgnore)
493  {
494  OString aToken = rValue.copy(nStart, i - nStart);
495  static const char aExpectedPrefix[]
496  = "Value = (any) { ([]com.sun.star.drawing.EnhancedCustomShapeParameterPair) { ";
497  if (aToken.startsWith(aExpectedPrefix))
498  {
499  aToken = aToken.copy(strlen(aExpectedPrefix),
500  aToken.getLength() - strlen(aExpectedPrefix) - strlen(" } }"));
501  lcl_parsePathCoordinateValues(rPath, aToken);
502  }
503  else if (!aToken.startsWith("Name =") && !aToken.startsWith("Handle ="))
504  SAL_WARN("oox", "lcl_parsePathCoordinates: unexpected token: " << aToken);
505  nStart = i + strlen(", ");
506  }
507  }
508 }
509 
510 void lcl_parsePathSegmentValues(std::vector<beans::PropertyValue>& rPath, const OString& rValue)
511 {
512  std::vector<drawing::EnhancedCustomShapeSegment> aSegments;
513  sal_Int32 nLevel = 0;
514  sal_Int32 nStart = 0;
515  for (sal_Int32 i = 0; i < rValue.getLength(); ++i)
516  {
517  if (rValue[i] == '{')
518  {
519  if (!nLevel)
520  nStart = i;
521  nLevel++;
522  }
523  else if (rValue[i] == '}')
524  {
525  nLevel--;
526  if (!nLevel)
527  aSegments.push_back(lcl_parseEnhancedCustomShapeSegment(
528  rValue.copy(nStart + strlen("{ "), i - nStart - strlen(" },"))));
529  }
530  }
531 
532  beans::PropertyValue aPropertyValue;
533  aPropertyValue.Name = "Segments";
534  aPropertyValue.Value <<= comphelper::containerToSequence(aSegments);
535  rPath.push_back(aPropertyValue);
536 }
537 
538 // Parses a string like: Name = "Segments", Handle = (long) 0, Value = (any) { ... }, State = (com.sun.star.beans.PropertyState) DIRECT_VALUE
539 // where "{ ... }" may contain "," as well.
540 void lcl_parsePathSegments(std::vector<beans::PropertyValue>& rPath, const OString& rValue)
541 {
542  sal_Int32 nLevel = 0;
543  bool bIgnore = false;
544  sal_Int32 nStart = 0;
545  for (sal_Int32 i = 0; i < rValue.getLength(); ++i)
546  {
547  if (rValue[i] == '{')
548  {
549  if (!nLevel)
550  bIgnore = true;
551  nLevel++;
552  }
553  else if (rValue[i] == '}')
554  {
555  nLevel--;
556  if (!nLevel)
557  bIgnore = false;
558  }
559  else if (rValue[i] == ',' && !bIgnore)
560  {
561  OString aToken = rValue.copy(nStart, i - nStart);
562  static const char aExpectedPrefix[]
563  = "Value = (any) { ([]com.sun.star.drawing.EnhancedCustomShapeSegment) { ";
564  if (aToken.startsWith(aExpectedPrefix))
565  {
566  aToken = aToken.copy(strlen(aExpectedPrefix),
567  aToken.getLength() - strlen(aExpectedPrefix) - strlen(" } }"));
568  lcl_parsePathSegmentValues(rPath, aToken);
569  }
570  else if (!aToken.startsWith("Name =") && !aToken.startsWith("Handle ="))
571  SAL_WARN("oox", "lcl_parsePathSegments: unexpected token: " << aToken);
572  nStart = i + strlen(", ");
573  }
574  }
575 }
576 
577 void lcl_parsePathTextFrameValues(std::vector<beans::PropertyValue>& rPath, const OString& rValue)
578 {
579  std::vector<drawing::EnhancedCustomShapeTextFrame> aTextFrames;
580  sal_Int32 nLevel = 0;
581  sal_Int32 nStart = 0;
582  for (sal_Int32 i = 0; i < rValue.getLength(); ++i)
583  {
584  if (rValue[i] == '{')
585  {
586  if (!nLevel)
587  nStart = i;
588  nLevel++;
589  }
590  else if (rValue[i] == '}')
591  {
592  nLevel--;
593  if (!nLevel)
594  aTextFrames.push_back(lcl_parseEnhancedCustomShapeTextFrame(
595  rValue.copy(nStart + strlen("{ "), i - nStart - strlen(" },"))));
596  }
597  }
598 
599  beans::PropertyValue aPropertyValue;
600  aPropertyValue.Name = "TextFrames";
601  aPropertyValue.Value <<= comphelper::containerToSequence(aTextFrames);
602  rPath.push_back(aPropertyValue);
603 }
604 
605 // Parses a string like: Name = "TextFrames", Handle = (long) 0, Value = (any) { ... }, State = (com.sun.star.beans.PropertyState) DIRECT_VALUE
606 // where "{ ... }" may contain "," as well.
607 void lcl_parsePathTextFrames(std::vector<beans::PropertyValue>& rPath, const OString& rValue)
608 {
609  sal_Int32 nLevel = 0;
610  bool bIgnore = false;
611  sal_Int32 nStart = 0;
612  for (sal_Int32 i = 0; i < rValue.getLength(); ++i)
613  {
614  if (rValue[i] == '{')
615  {
616  if (!nLevel)
617  bIgnore = true;
618  nLevel++;
619  }
620  else if (rValue[i] == '}')
621  {
622  nLevel--;
623  if (!nLevel)
624  bIgnore = false;
625  }
626  else if (rValue[i] == ',' && !bIgnore)
627  {
628  OString aToken = rValue.copy(nStart, i - nStart);
629  static const char aExpectedPrefix[]
630  = "Value = (any) { ([]com.sun.star.drawing.EnhancedCustomShapeTextFrame) { ";
631  if (aToken.startsWith(aExpectedPrefix))
632  {
633  aToken = aToken.copy(strlen(aExpectedPrefix),
634  aToken.getLength() - strlen(aExpectedPrefix) - strlen(" } }"));
635  lcl_parsePathTextFrameValues(rPath, aToken);
636  }
637  else if (!aToken.startsWith("Name =") && !aToken.startsWith("Handle ="))
638  SAL_WARN("oox", "lcl_parsePathTextFrames: unexpected token: " << aToken);
639  nStart = i + strlen(", ");
640  }
641  }
642 }
643 
644 void lcl_parsePathSubViewSizeValues(std::vector<beans::PropertyValue>& rPath, const OString& rValue)
645 {
646  std::vector<awt::Size> aSizes;
647  sal_Int32 nLevel = 0;
648  sal_Int32 nStart = 0;
649  for (sal_Int32 i = 0; i < rValue.getLength(); ++i)
650  {
651  if (rValue[i] == '{')
652  {
653  if (!nLevel)
654  nStart = i;
655  nLevel++;
656  }
657  else if (rValue[i] == '}')
658  {
659  nLevel--;
660  if (!nLevel)
661  aSizes.push_back(
662  lcl_parseSize(rValue.copy(nStart + strlen("{ "), i - nStart - strlen(" },"))));
663  }
664  }
665 
666  beans::PropertyValue aPropertyValue;
667  aPropertyValue.Name = "SubViewSize";
668  aPropertyValue.Value <<= comphelper::containerToSequence(aSizes);
669  rPath.push_back(aPropertyValue);
670 }
671 
672 void lcl_parsePathSubViewSize(std::vector<beans::PropertyValue>& rPath, const OString& rValue)
673 {
674  sal_Int32 nLevel = 0;
675  bool bIgnore = false;
676  sal_Int32 nStart = 0;
677  for (sal_Int32 i = 0; i < rValue.getLength(); ++i)
678  {
679  if (rValue[i] == '{')
680  {
681  if (!nLevel)
682  bIgnore = true;
683  nLevel++;
684  }
685  else if (rValue[i] == '}')
686  {
687  nLevel--;
688  if (!nLevel)
689  bIgnore = false;
690  }
691  else if (rValue[i] == ',' && !bIgnore)
692  {
693  OString aToken = rValue.copy(nStart, i - nStart);
694  static const char aExpectedPrefix[] = "Value = (any) { ([]com.sun.star.awt.Size) { ";
695  if (aToken.startsWith(aExpectedPrefix))
696  {
697  aToken = aToken.copy(strlen(aExpectedPrefix),
698  aToken.getLength() - strlen(aExpectedPrefix) - strlen(" } }"));
699  lcl_parsePathSubViewSizeValues(rPath, aToken);
700  }
701  else if (!aToken.startsWith("Name =") && !aToken.startsWith("Handle ="))
702  SAL_WARN("oox", "lcl_parsePathSubViewSize: unexpected token: " << aToken);
703  nStart = i + strlen(", ");
704  }
705  }
706 }
707 
708 void lcl_parsePath(std::vector<beans::PropertyValue>& rPath, const OString& rValue)
709 {
710  sal_Int32 nLevel = 0;
711  sal_Int32 nStart = 0;
712  for (sal_Int32 i = 0; i < rValue.getLength(); ++i)
713  {
714  if (rValue[i] == '{')
715  {
716  if (!nLevel)
717  nStart = i;
718  nLevel++;
719  }
720  else if (rValue[i] == '}')
721  {
722  nLevel--;
723  if (!nLevel)
724  {
725  OString aToken = rValue.copy(nStart + strlen("{ "), i - nStart - strlen(" },"));
726  if (aToken.startsWith("Name = \"Coordinates\""))
727  lcl_parsePathCoordinates(rPath, aToken);
728  else if (aToken.startsWith("Name = \"Segments\""))
729  lcl_parsePathSegments(rPath, aToken);
730  else if (aToken.startsWith("Name = \"TextFrames\""))
731  lcl_parsePathTextFrames(rPath, aToken);
732  else if (aToken.startsWith("Name = \"SubViewSize\""))
733  lcl_parsePathSubViewSize(rPath, aToken);
734  else
735  SAL_WARN("oox", "lcl_parsePath: unexpected token: " << aToken);
736  }
737  }
738  }
739 }
740 }
741 
742 namespace oox::drawingml
743 {
745 {
746  OUString aPath("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/filter/oox-drawingml-cs-presets");
747  rtl::Bootstrap::expandMacros(aPath);
748  SvFileStream aStream(aPath, StreamMode::READ);
749  if (aStream.GetError() != ERRCODE_NONE)
750  SAL_WARN("oox", "failed to open oox-drawingml-cs-presets");
751  OString aLine;
752  OUString aName;
753  bool bNotDone = aStream.ReadLine(aLine);
754  PropertyMap aPropertyMap;
755  bool bFirst = true;
756  while (bNotDone)
757  {
758  static const char aCommentPrefix[] = "/* ";
759  if (aLine.startsWith(aCommentPrefix))
760  {
761  if (bFirst)
762  bFirst = false;
763  else
764  maPresetDataMap[TokenMap::getTokenFromUnicode(aName)] = aPropertyMap;
765  aName = OUString::fromUtf8(
766  aLine.subView(strlen(aCommentPrefix),
767  aLine.getLength() - strlen(aCommentPrefix) - strlen(" */")));
768  }
769  else
770  {
771  if (aLine == "AdjustmentValues")
772  {
773  aStream.ReadLine(aLine);
774  if (aLine != "([]com.sun.star.drawing.EnhancedCustomShapeAdjustmentValue) {}")
775  {
776  std::vector<drawing::EnhancedCustomShapeAdjustmentValue> aAdjustmentValues;
777  OString aExpectedPrefix(
778  "([]com.sun.star.drawing.EnhancedCustomShapeAdjustmentValue) { ");
779  assert(aLine.startsWith(aExpectedPrefix));
780 
781  OString aValue = aLine.copy(aExpectedPrefix.getLength(),
782  aLine.getLength() - aExpectedPrefix.getLength()
783  - strlen(" }"));
784  lcl_parseAdjustmentValues(aAdjustmentValues, aValue);
785  aPropertyMap.setProperty(PROP_AdjustmentValues,
786  comphelper::containerToSequence(aAdjustmentValues));
787  }
788  else
789  aPropertyMap.setProperty(PROP_AdjustmentValues, uno::Sequence<OUString>(0));
790  }
791  else if (aLine == "Equations")
792  {
793  aStream.ReadLine(aLine);
794  if (aLine != "([]string) {}")
795  {
796  std::vector<OUString> aEquations;
797  OString aExpectedPrefix("([]string) { ");
798  assert(aLine.startsWith(aExpectedPrefix));
799 
800  OString aValue = aLine.copy(aExpectedPrefix.getLength(),
801  aLine.getLength() - aExpectedPrefix.getLength()
802  - strlen(" }"));
803  lcl_parseEquations(aEquations, aValue);
804  aPropertyMap.setProperty(PROP_Equations,
805  comphelper::containerToSequence(aEquations));
806  }
807  else
808  aPropertyMap.setProperty(PROP_Equations, uno::Sequence<OUString>(0));
809  }
810  else if (aLine == "Handles")
811  {
812  aStream.ReadLine(aLine);
813  if (aLine != "([][]com.sun.star.beans.PropertyValue) {}")
814  {
815  std::vector<uno::Sequence<beans::PropertyValue>> aHandles;
816  OString aExpectedPrefix("([][]com.sun.star.beans.PropertyValue) { ");
817  assert(aLine.startsWith(aExpectedPrefix));
818 
819  OString aValue = aLine.copy(aExpectedPrefix.getLength(),
820  aLine.getLength() - aExpectedPrefix.getLength()
821  - strlen(" }"));
822  lcl_parseHandles(aHandles, aValue);
823  aPropertyMap.setProperty(PROP_Handles,
825  }
826  else
827  aPropertyMap.setProperty(PROP_Handles, uno::Sequence<OUString>(0));
828  }
829  else if (aLine == "MirroredX")
830  {
831  aStream.ReadLine(aLine);
832  if (aLine == "true" || aLine == "false")
833  {
834  aPropertyMap.setProperty(PROP_MirroredX, aLine == "true");
835  }
836  else
837  SAL_WARN("oox", "CustomShapeProperties::initializePresetDataMap: unexpected "
838  "MirroredX parameter");
839  }
840  else if (aLine == "MirroredY")
841  {
842  aStream.ReadLine(aLine);
843  if (aLine == "true" || aLine == "false")
844  {
845  aPropertyMap.setProperty(PROP_MirroredY, aLine == "true");
846  }
847  else
848  SAL_WARN("oox", "CustomShapeProperties::initializePresetDataMap: unexpected "
849  "MirroredY parameter");
850  }
851  else if (aLine == "Path")
852  {
853  aStream.ReadLine(aLine);
854  OString aExpectedPrefix("([]com.sun.star.beans.PropertyValue) { ");
855  assert(aLine.startsWith(aExpectedPrefix));
856 
857  std::vector<beans::PropertyValue> aPathValue;
858  OString aValue
859  = aLine.copy(aExpectedPrefix.getLength(),
860  aLine.getLength() - aExpectedPrefix.getLength() - strlen(" }"));
861  lcl_parsePath(aPathValue, aValue);
862  aPropertyMap.setProperty(PROP_Path, comphelper::containerToSequence(aPathValue));
863  }
864  else if (aLine == "Type")
865  {
866  // Just ignore the line here, we already know the correct type.
867  aStream.ReadLine(aLine);
868  aPropertyMap.setProperty(PROP_Type, "ooxml-" + aName);
869  }
870  else if (aLine == "ViewBox")
871  {
872  aStream.ReadLine(aLine);
873  OString aExpectedPrefix("(com.sun.star.awt.Rectangle) { ");
874  assert(aLine.startsWith(aExpectedPrefix));
875 
876  OString aValue
877  = aLine.copy(aExpectedPrefix.getLength(),
878  aLine.getLength() - aExpectedPrefix.getLength() - strlen(" }"));
879  aPropertyMap.setProperty(PROP_ViewBox, lcl_parseRectangle(aValue));
880  }
881  else
882  SAL_WARN("oox", "CustomShapeProperties::initializePresetDataMap: unhandled line: "
883  << aLine);
884  }
885  bNotDone = aStream.ReadLine(aLine);
886  }
887  maPresetDataMap[TokenMap::getTokenFromUnicode(aName)] = aPropertyMap;
888 }
889 }
890 
891 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 nIndex
A helper that maps property identifiers to property values.
Definition: propertymap.hxx:52
bool setProperty(sal_Int32 nPropId, Type &&rValue)
Sets the specified property to the passed value.
Definition: propertymap.hxx:70
ErrCode GetError() const
bool ReadLine(OString &rStr, sal_Int32 nMaxBytesToRead=0xFFFE)
static sal_Int32 getTokenFromUnicode(std::u16string_view rUnicodeName)
Returns the token identifier for the passed Unicode token name.
Definition: tokenmap.cxx:77
#define SAL_N_ELEMENTS(arr)
std::vector< ISegmentProgressBarRef > aSegments
#define ERRCODE_NONE
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
OUString aName
#define SAL_WARN(area, stream)