File: | home/maarten/src/libreoffice/core/include/tools/ref.hxx |
Warning: | line 97, column 56 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 "rtfsprm.hxx" | |||
11 | #include <ooxml/resourceids.hxx> | |||
12 | #include <ooxml/QNameToString.hxx> | |||
13 | #include <rtl/strbuf.hxx> | |||
14 | #include "rtfdocumentimpl.hxx" | |||
15 | #include <algorithm> | |||
16 | ||||
17 | namespace writerfilter::rtftok | |||
18 | { | |||
19 | RTFSprm::RTFSprm(Id nKeyword, RTFValue::Pointer_t& pValue) | |||
20 | : m_nKeyword(nKeyword) | |||
21 | , m_pValue(pValue) | |||
22 | { | |||
23 | } | |||
24 | ||||
25 | sal_uInt32 RTFSprm::getId() const { return m_nKeyword; } | |||
26 | ||||
27 | Value::Pointer_t RTFSprm::getValue() { return Value::Pointer_t(m_pValue->Clone()); } | |||
28 | ||||
29 | writerfilter::Reference<Properties>::Pointer_t RTFSprm::getProps() | |||
30 | { | |||
31 | return m_pValue->getProperties(); | |||
32 | } | |||
33 | ||||
34 | #ifdef DBG_UTIL | |||
35 | std::string RTFSprm::getName() const { return "RTFSprm"; } | |||
36 | #endif | |||
37 | ||||
38 | #ifdef DBG_UTIL | |||
39 | std::string RTFSprm::toString() const | |||
40 | { | |||
41 | OStringBuffer aBuf("RTFSprm"); | |||
42 | ||||
43 | std::string sResult = QNameToString(m_nKeyword); | |||
44 | ||||
45 | aBuf.append(" ('"); | |||
46 | if (sResult.length() == 0) | |||
47 | aBuf.append(sal_Int32(m_nKeyword)); | |||
48 | else | |||
49 | aBuf.append(sResult.c_str()); | |||
50 | aBuf.append("', '"); | |||
51 | aBuf.append(m_pValue->toString().c_str()); | |||
52 | aBuf.append("')"); | |||
53 | ||||
54 | return aBuf.makeStringAndClear().getStr(); | |||
55 | } | |||
56 | #endif | |||
57 | ||||
58 | namespace | |||
59 | { | |||
60 | class RTFSprms_compare | |||
61 | { | |||
62 | Id keyword; | |||
63 | ||||
64 | public: | |||
65 | RTFSprms_compare(Id kw) | |||
66 | : keyword{ kw } | |||
67 | { | |||
68 | } | |||
69 | bool operator()(const std::pair<Id, RTFValue::Pointer_t>& raPair) const | |||
70 | { | |||
71 | return raPair.first == keyword; | |||
72 | } | |||
73 | }; | |||
74 | } | |||
75 | ||||
76 | RTFValue::Pointer_t RTFSprms::find(Id nKeyword, bool bFirst, bool bForWrite) | |||
77 | { | |||
78 | if (bForWrite) | |||
79 | ensureCopyBeforeWrite(); | |||
80 | ||||
81 | RTFSprms_compare cmp{ nKeyword }; | |||
82 | ||||
83 | if (bFirst) | |||
84 | { | |||
85 | auto it = std::find_if(m_pSprms->begin(), m_pSprms->end(), cmp); | |||
86 | if (it != m_pSprms->end()) | |||
87 | return it->second; | |||
88 | } | |||
89 | else | |||
90 | // find last | |||
91 | { | |||
92 | auto rit = std::find_if(m_pSprms->rbegin(), m_pSprms->rend(), cmp); | |||
93 | if (rit != m_pSprms->rend()) | |||
94 | return rit->second; | |||
95 | } | |||
96 | ||||
97 | return RTFValue::Pointer_t{}; | |||
98 | } | |||
99 | ||||
100 | void RTFSprms::set(Id nKeyword, const RTFValue::Pointer_t& pValue, RTFOverwrite eOverwrite) | |||
101 | { | |||
102 | ensureCopyBeforeWrite(); | |||
103 | ||||
104 | switch (eOverwrite) | |||
105 | { | |||
106 | case RTFOverwrite::YES_PREPEND: | |||
107 | { | |||
108 | m_pSprms->erase( | |||
109 | std::remove_if(m_pSprms->begin(), m_pSprms->end(), RTFSprms_compare{ nKeyword }), | |||
110 | m_pSprms->end()); | |||
111 | m_pSprms->emplace(m_pSprms->cbegin(), nKeyword, pValue); | |||
112 | break; | |||
113 | } | |||
114 | case RTFOverwrite::YES: | |||
115 | { | |||
116 | auto it | |||
117 | = std::find_if(m_pSprms->begin(), m_pSprms->end(), RTFSprms_compare{ nKeyword }); | |||
118 | if (it != m_pSprms->end()) | |||
119 | it->second = pValue; | |||
120 | else | |||
121 | m_pSprms->emplace_back(nKeyword, pValue); | |||
122 | break; | |||
123 | } | |||
124 | case RTFOverwrite::NO_IGNORE: | |||
125 | { | |||
126 | if (std::none_of(m_pSprms->cbegin(), m_pSprms->cend(), RTFSprms_compare{ nKeyword })) | |||
127 | m_pSprms->emplace_back(nKeyword, pValue); | |||
128 | break; | |||
129 | } | |||
130 | case RTFOverwrite::NO_APPEND: | |||
131 | { | |||
132 | m_pSprms->emplace_back(nKeyword, pValue); | |||
133 | break; | |||
134 | } | |||
135 | } | |||
136 | } | |||
137 | ||||
138 | bool RTFSprms::erase(Id nKeyword) | |||
139 | { | |||
140 | ensureCopyBeforeWrite(); | |||
141 | ||||
142 | auto i = std::find_if(m_pSprms->begin(), m_pSprms->end(), RTFSprms_compare{ nKeyword }); | |||
143 | if (i != m_pSprms->end()) | |||
144 | { | |||
145 | m_pSprms->erase(i); | |||
146 | return true; | |||
147 | } | |||
148 | return false; | |||
149 | } | |||
150 | ||||
151 | void RTFSprms::eraseLast(Id nKeyword) | |||
152 | { | |||
153 | ensureCopyBeforeWrite(); | |||
154 | ||||
155 | auto i = std::find_if(m_pSprms->rbegin(), m_pSprms->rend(), RTFSprms_compare{ nKeyword }); | |||
156 | if (i != m_pSprms->rend()) | |||
157 | m_pSprms->erase(std::next(i).base()); | |||
158 | } | |||
159 | ||||
160 | static RTFValue::Pointer_t getDefaultSPRM(Id const id, Id nStyleType) | |||
161 | { | |||
162 | if (!nStyleType || nStyleType == NS_ooxml::LN_Value_ST_StyleType_character) | |||
163 | { | |||
164 | switch (id) | |||
165 | { | |||
166 | case NS_ooxml::LN_EG_RPrBase_b: | |||
167 | return new RTFValue(0); | |||
168 | default: | |||
169 | break; | |||
170 | } | |||
171 | } | |||
172 | ||||
173 | if (!nStyleType || nStyleType == NS_ooxml::LN_Value_ST_StyleType_paragraph) | |||
174 | { | |||
175 | switch (id) | |||
176 | { | |||
177 | case NS_ooxml::LN_CT_Spacing_before: | |||
178 | case NS_ooxml::LN_CT_Spacing_after: | |||
179 | case NS_ooxml::LN_CT_Ind_left: | |||
180 | case NS_ooxml::LN_CT_Ind_right: | |||
181 | case NS_ooxml::LN_CT_Ind_firstLine: | |||
182 | return new RTFValue(0); | |||
183 | ||||
184 | case NS_ooxml::LN_CT_Spacing_lineRule: | |||
185 | return new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_auto); | |||
186 | case NS_ooxml::LN_CT_Spacing_line: | |||
187 | // presumably this means 100%, cf. static const int nSingleLineSpacing = 240; | |||
188 | return new RTFValue(240); | |||
189 | ||||
190 | default: | |||
191 | break; | |||
192 | } | |||
193 | } | |||
194 | ||||
195 | return RTFValue::Pointer_t(); | |||
196 | } | |||
197 | ||||
198 | /// Is it problematic to deduplicate this SPRM? | |||
199 | static bool isSPRMDeduplicateDenylist(Id nId) | |||
200 | { | |||
201 | switch (nId) | |||
202 | { | |||
203 | // See the NS_ooxml::LN_CT_PPrBase_tabs handler in DomainMapper, | |||
204 | // deduplication is explicitly not wanted for these tokens. | |||
205 | case NS_ooxml::LN_CT_TabStop_val: | |||
206 | case NS_ooxml::LN_CT_TabStop_leader: | |||
207 | case NS_ooxml::LN_CT_TabStop_pos: | |||
208 | // \htmautsp arrives after the style table, so only the non-style value is | |||
209 | // correct, keep these. | |||
210 | case NS_ooxml::LN_CT_Spacing_beforeAutospacing: | |||
211 | case NS_ooxml::LN_CT_Spacing_afterAutospacing: | |||
212 | // \chbrdr requires *all* of the border settings to be present, | |||
213 | // otherwise a default (NONE) border is created from the removed | |||
214 | // attributes which then overrides the style-defined border. | |||
215 | // See BorderHandler.cxx and NS_ooxml::LN_EG_RPrBase_bdr in DomainMapper. | |||
216 | // This also is needed for NS_ooxml::LN_CT_PBdr_top etc. | |||
217 | case NS_ooxml::LN_CT_Border_sz: | |||
218 | case NS_ooxml::LN_CT_Border_val: | |||
219 | case NS_ooxml::LN_CT_Border_color: | |||
220 | case NS_ooxml::LN_CT_Border_space: | |||
221 | case NS_ooxml::LN_CT_Border_shadow: | |||
222 | case NS_ooxml::LN_CT_Border_frame: | |||
223 | case NS_ooxml::LN_CT_Border_themeTint: | |||
224 | case NS_ooxml::LN_CT_Border_themeColor: | |||
225 | return true; | |||
226 | ||||
227 | default: | |||
228 | return false; | |||
229 | } | |||
230 | } | |||
231 | ||||
232 | /// Should this SPRM be removed if all its children are removed? | |||
233 | static bool isSPRMChildrenExpected(Id nId) | |||
234 | { | |||
235 | switch (nId) | |||
236 | { | |||
237 | case NS_ooxml::LN_CT_PBdr_top: | |||
238 | case NS_ooxml::LN_CT_PBdr_left: | |||
239 | case NS_ooxml::LN_CT_PBdr_bottom: | |||
240 | case NS_ooxml::LN_CT_PBdr_right: | |||
241 | // Expected children are NS_ooxml::LN_CT_Border_*. | |||
242 | case NS_ooxml::LN_CT_PrBase_shd: | |||
243 | // Expected children are NS_ooxml::LN_CT_Shd_*. | |||
244 | case NS_ooxml::LN_CT_PPrBase_ind: | |||
245 | // Expected children are NS_ooxml::LN_CT_Ind_*. | |||
246 | return true; | |||
247 | ||||
248 | default: | |||
249 | return false; | |||
250 | } | |||
251 | } | |||
252 | ||||
253 | /// Does the clone / deduplication of a single sprm. | |||
254 | static void cloneAndDeduplicateSprm(std::pair<Id, RTFValue::Pointer_t> const& rSprm, RTFSprms& ret, | |||
255 | Id nStyleType) | |||
256 | { | |||
257 | RTFValue::Pointer_t const pValue(ret.find(rSprm.first)); | |||
258 | if (pValue) | |||
| ||||
259 | { | |||
260 | if (rSprm.second->equals(*pValue)) | |||
261 | { | |||
262 | if (!isSPRMDeduplicateDenylist(rSprm.first)) | |||
263 | ret.erase(rSprm.first); // duplicate to style | |||
264 | } | |||
265 | else if (!rSprm.second->getSprms().empty() || !rSprm.second->getAttributes().empty()) | |||
266 | { | |||
267 | RTFSprms const sprms( | |||
268 | pValue->getSprms().cloneAndDeduplicate(rSprm.second->getSprms(), nStyleType)); | |||
269 | RTFSprms const attributes(pValue->getAttributes().cloneAndDeduplicate( | |||
270 | rSprm.second->getAttributes(), nStyleType)); | |||
271 | // Don't copy the sprm in case we expect it to have children but it doesn't have some. | |||
272 | if (!isSPRMChildrenExpected(rSprm.first) || !sprms.empty() || !attributes.empty()) | |||
273 | ret.set(rSprm.first, | |||
274 | RTFValue::Pointer_t(pValue->CloneWithSprms(attributes, sprms))); | |||
275 | } | |||
276 | } | |||
277 | else | |||
278 | { | |||
279 | // not found - try to override style with default | |||
280 | RTFValue::Pointer_t const pDefault(getDefaultSPRM(rSprm.first, nStyleType)); | |||
281 | if (pDefault) | |||
282 | { | |||
283 | ret.set(rSprm.first, pDefault); | |||
284 | } | |||
285 | else if (!rSprm.second->getSprms().empty() || !rSprm.second->getAttributes().empty()) | |||
286 | { | |||
287 | RTFSprms const sprms( | |||
288 | RTFSprms().cloneAndDeduplicate(rSprm.second->getSprms(), nStyleType)); | |||
289 | RTFSprms const attributes( | |||
290 | RTFSprms().cloneAndDeduplicate(rSprm.second->getAttributes(), nStyleType)); | |||
291 | if (!sprms.empty() || !attributes.empty()) | |||
292 | { | |||
293 | ret.set(rSprm.first, new RTFValue(attributes, sprms)); | |||
294 | } | |||
295 | } | |||
296 | } | |||
297 | } | |||
298 | ||||
299 | /// Extracts the list level matching nLevel from pAbstract. | |||
300 | static RTFValue::Pointer_t getListLevel(const RTFValue::Pointer_t& pAbstract, int nLevel) | |||
301 | { | |||
302 | for (const auto& rPair : pAbstract->getSprms()) | |||
303 | { | |||
304 | if (rPair.first != NS_ooxml::LN_CT_AbstractNum_lvl) | |||
305 | continue; | |||
306 | ||||
307 | RTFValue::Pointer_t pLevel = rPair.second->getAttributes().find(NS_ooxml::LN_CT_Lvl_ilvl); | |||
308 | if (!pLevel) | |||
309 | continue; | |||
310 | ||||
311 | if (pLevel->getInt() != nLevel) | |||
312 | continue; | |||
313 | ||||
314 | return rPair.second; | |||
315 | } | |||
316 | ||||
317 | return RTFValue::Pointer_t(); | |||
318 | } | |||
319 | ||||
320 | void RTFSprms::deduplicateList(const std::map<int, int>& rInvalidListLevelFirstIndents) | |||
321 | { | |||
322 | int nLevel = 0; | |||
323 | RTFValue::Pointer_t pLevelId | |||
324 | = getNestedSprm(*this, NS_ooxml::LN_CT_PPrBase_numPr, NS_ooxml::LN_CT_NumPr_ilvl); | |||
325 | if (pLevelId) | |||
326 | nLevel = pLevelId->getInt(); | |||
327 | ||||
328 | auto it = rInvalidListLevelFirstIndents.find(nLevel); | |||
329 | if (it == rInvalidListLevelFirstIndents.end()) | |||
330 | return; | |||
331 | ||||
332 | int nListValue = it->second; | |||
333 | ||||
334 | RTFValue::Pointer_t pParagraphValue | |||
335 | = getNestedAttribute(*this, NS_ooxml::LN_CT_PPrBase_ind, NS_ooxml::LN_CT_Ind_firstLine); | |||
336 | if (!pParagraphValue) | |||
337 | return; | |||
338 | ||||
339 | int nParagraphValue = pParagraphValue->getInt(); | |||
340 | ||||
341 | if (nParagraphValue == nListValue) | |||
342 | eraseNestedAttribute(*this, NS_ooxml::LN_CT_PPrBase_ind, NS_ooxml::LN_CT_Ind_firstLine); | |||
343 | } | |||
344 | ||||
345 | void RTFSprms::duplicateList(const RTFValue::Pointer_t& pAbstract) | |||
346 | { | |||
347 | int nLevel = 0; | |||
348 | RTFValue::Pointer_t pLevelId | |||
349 | = getNestedSprm(*this, NS_ooxml::LN_CT_PPrBase_numPr, NS_ooxml::LN_CT_NumPr_ilvl); | |||
350 | if (pLevelId) | |||
351 | nLevel = pLevelId->getInt(); | |||
352 | ||||
353 | RTFValue::Pointer_t pLevel = getListLevel(pAbstract, nLevel); | |||
354 | if (!pLevel) | |||
355 | return; | |||
356 | ||||
357 | RTFValue::Pointer_t pLevelInd = pLevel->getSprms().find(NS_ooxml::LN_CT_PPrBase_ind); | |||
358 | if (!pLevelInd) | |||
359 | return; | |||
360 | ||||
361 | for (const auto& rListLevelPair : pLevelInd->getAttributes()) | |||
362 | { | |||
363 | switch (rListLevelPair.first) | |||
364 | { | |||
365 | case NS_ooxml::LN_CT_Ind_left: | |||
366 | case NS_ooxml::LN_CT_Ind_right: | |||
367 | case NS_ooxml::LN_CT_Ind_firstLine: | |||
368 | RTFValue::Pointer_t pParagraphValue | |||
369 | = getNestedAttribute(*this, NS_ooxml::LN_CT_PPrBase_ind, rListLevelPair.first); | |||
370 | if (!pParagraphValue) | |||
371 | putNestedAttribute(*this, NS_ooxml::LN_CT_PPrBase_ind, rListLevelPair.first, | |||
372 | getDefaultSPRM(rListLevelPair.first, 0)); | |||
373 | ||||
374 | break; | |||
375 | } | |||
376 | } | |||
377 | } | |||
378 | ||||
379 | RTFSprms RTFSprms::cloneAndDeduplicate(RTFSprms& rReference, Id const nStyleType, | |||
380 | bool const bImplicitPPr) const | |||
381 | { | |||
382 | RTFSprms ret(*this); | |||
383 | ret.ensureCopyBeforeWrite(); | |||
384 | ||||
385 | // Note: apparently some attributes are set with OVERWRITE_NO_APPEND; | |||
386 | // it is probably a bad idea to mess with those in any way here? | |||
387 | for (auto& rSprm : rReference) | |||
388 | { | |||
389 | // Paragraph formatting sprms are directly contained in case of | |||
390 | // paragraphs, but they are below NS_ooxml::LN_CT_Style_pPr in case of | |||
391 | // styles. So handle those children directly, to avoid unexpected | |||
392 | // addition of direct formatting sprms at the paragraph level. | |||
393 | if (bImplicitPPr && rSprm.first == NS_ooxml::LN_CT_Style_pPr) | |||
394 | { | |||
395 | for (const auto& i : rSprm.second->getSprms()) | |||
396 | cloneAndDeduplicateSprm(i, ret, nStyleType); | |||
397 | } | |||
398 | else | |||
399 | cloneAndDeduplicateSprm(rSprm, ret, nStyleType); | |||
400 | } | |||
401 | return ret; | |||
402 | } | |||
403 | ||||
404 | bool RTFSprms::equals(const RTFValue& rOther) const | |||
405 | { | |||
406 | return std::all_of(m_pSprms->cbegin(), m_pSprms->cend(), | |||
407 | [&](const std::pair<Id, RTFValue::Pointer_t>& raPair) -> bool { | |||
408 | return raPair.second->equals(rOther); | |||
409 | }); | |||
410 | } | |||
411 | ||||
412 | void RTFSprms::ensureCopyBeforeWrite() | |||
413 | { | |||
414 | if (m_pSprms->GetRefCount() > 1) | |||
415 | { | |||
416 | tools::SvRef<RTFSprmsImpl> pClone(new RTFSprmsImpl); | |||
417 | for (auto& rSprm : *m_pSprms) | |||
418 | pClone->push_back( | |||
419 | std::make_pair(rSprm.first, RTFValue::Pointer_t(rSprm.second->Clone()))); | |||
420 | m_pSprms = pClone; | |||
421 | } | |||
422 | } | |||
423 | ||||
424 | RTFSprms::RTFSprms() | |||
425 | : m_pSprms(new RTFSprmsImpl) | |||
426 | { | |||
427 | } | |||
428 | ||||
429 | RTFSprms::~RTFSprms() = default; | |||
430 | ||||
431 | void RTFSprms::clear() | |||
432 | { | |||
433 | if (m_pSprms->GetRefCount() == 1) | |||
434 | return m_pSprms->clear(); | |||
435 | ||||
436 | m_pSprms = tools::SvRef<RTFSprmsImpl>(new RTFSprmsImpl); | |||
437 | } | |||
438 | ||||
439 | } // namespace writerfilter::rtftok | |||
440 | ||||
441 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
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 | * This file incorporates work covered by the following license notice: | |||
10 | * | |||
11 | * Licensed to the Apache Software Foundation (ASF) under one or more | |||
12 | * contributor license agreements. See the NOTICE file distributed | |||
13 | * with this work for additional information regarding copyright | |||
14 | * ownership. The ASF licenses this file to you under the Apache | |||
15 | * License, Version 2.0 (the "License"); you may not use this file | |||
16 | * except in compliance with the License. You may obtain a copy of | |||
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . | |||
18 | */ | |||
19 | #ifndef INCLUDED_TOOLS_REF_HXX | |||
20 | #define INCLUDED_TOOLS_REF_HXX | |||
21 | ||||
22 | #include <sal/config.h> | |||
23 | #include <cassert> | |||
24 | #include <tools/toolsdllapi.h> | |||
25 | #include <utility> | |||
26 | ||||
27 | /** | |||
28 | This implements similar functionality to boost::intrusive_ptr | |||
29 | */ | |||
30 | ||||
31 | namespace tools { | |||
32 | ||||
33 | /** T must be a class that extends SvRefBase */ | |||
34 | template<typename T> class SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) SvRef final { | |||
35 | public: | |||
36 | SvRef(): pObj(nullptr) {} | |||
37 | ||||
38 | SvRef(SvRef&& rObj) noexcept | |||
39 | { | |||
40 | pObj = rObj.pObj; | |||
41 | rObj.pObj = nullptr; | |||
42 | } | |||
43 | ||||
44 | SvRef(SvRef const & rObj): pObj(rObj.pObj) | |||
45 | { | |||
46 | if (pObj != nullptr) pObj->AddNextRef(); | |||
47 | } | |||
48 | ||||
49 | SvRef(T * pObjP): pObj(pObjP) | |||
50 | { | |||
51 | if (pObj != nullptr) pObj->AddFirstRef(); | |||
52 | } | |||
53 | ||||
54 | ~SvRef() | |||
55 | { | |||
56 | if (pObj != nullptr) pObj->ReleaseRef(); | |||
57 | } | |||
58 | ||||
59 | void clear() | |||
60 | { | |||
61 | if (pObj != nullptr) { | |||
62 | T * pRefObj = pObj; | |||
63 | pObj = nullptr; | |||
64 | pRefObj->ReleaseRef(); | |||
65 | } | |||
66 | } | |||
67 | ||||
68 | SvRef & operator =(SvRef const & rObj) | |||
69 | { | |||
70 | if (rObj.pObj != nullptr) { | |||
71 | rObj.pObj->AddNextRef(); | |||
72 | } | |||
73 | T * pRefObj = pObj; | |||
74 | pObj = rObj.pObj; | |||
75 | if (pRefObj != nullptr) { | |||
76 | pRefObj->ReleaseRef(); | |||
77 | } | |||
78 | return *this; | |||
79 | } | |||
80 | ||||
81 | SvRef & operator =(SvRef && rObj) | |||
82 | { | |||
83 | if (pObj != nullptr) { | |||
84 | pObj->ReleaseRef(); | |||
85 | } | |||
86 | pObj = rObj.pObj; | |||
87 | rObj.pObj = nullptr; | |||
88 | return *this; | |||
89 | } | |||
90 | ||||
91 | bool is() const { return pObj != nullptr; } | |||
92 | ||||
93 | explicit operator bool() const { return is(); } | |||
94 | ||||
95 | T * get() const { return pObj; } | |||
96 | ||||
97 | T * operator ->() const { assert(pObj != nullptr)(static_cast <bool> (pObj != nullptr) ? void (0) : __assert_fail ("pObj != nullptr", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx" , 97, __extension__ __PRETTY_FUNCTION__)); return pObj; } | |||
| ||||
98 | ||||
99 | T & operator *() const { assert(pObj != nullptr)(static_cast <bool> (pObj != nullptr) ? void (0) : __assert_fail ("pObj != nullptr", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx" , 99, __extension__ __PRETTY_FUNCTION__)); return *pObj; } | |||
100 | ||||
101 | bool operator ==(const SvRef<T> &rhs) const { return pObj == rhs.pObj; } | |||
102 | bool operator !=(const SvRef<T> &rhs) const { return !(*this == rhs); } | |||
103 | ||||
104 | private: | |||
105 | T * pObj; | |||
106 | }; | |||
107 | ||||
108 | /** | |||
109 | * This implements similar functionality to std::make_shared. | |||
110 | */ | |||
111 | template<typename T, typename... Args> | |||
112 | SvRef<T> make_ref(Args&& ... args) | |||
113 | { | |||
114 | return SvRef<T>(new T(std::forward<Args>(args)...)); | |||
115 | } | |||
116 | ||||
117 | } | |||
118 | ||||
119 | /** Classes that want to be referenced-counted via SvRef<T>, should extend this base class */ | |||
120 | class TOOLS_DLLPUBLIC__attribute__ ((visibility("default"))) SvRefBase | |||
121 | { | |||
122 | // work around a clang 3.5 optimization bug: if the bNoDelete is *first* | |||
123 | // it mis-compiles "if (--nRefCount == 0)" and never deletes any object | |||
124 | unsigned int nRefCount : 31; | |||
125 | // the only reason this is not bool is because MSVC cannot handle mixed type bitfields | |||
126 | unsigned int bNoDelete : 1; | |||
127 | ||||
128 | protected: | |||
129 | virtual ~SvRefBase() COVERITY_NOEXCEPT_FALSE; | |||
130 | ||||
131 | public: | |||
132 | SvRefBase() : nRefCount(0), bNoDelete(1) {} | |||
133 | SvRefBase(const SvRefBase &) : nRefCount(0), bNoDelete(1) {} | |||
134 | ||||
135 | SvRefBase & operator=(const SvRefBase &) { return *this; } | |||
136 | ||||
137 | void RestoreNoDelete() | |||
138 | { bNoDelete = 1; } | |||
139 | ||||
140 | void AddNextRef() | |||
141 | { | |||
142 | assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" )(static_cast <bool> (nRefCount < (1 << 30) && "Do not add refs to dead objects") ? void (0) : __assert_fail ("nRefCount < (1 << 30) && \"Do not add refs to dead objects\"" , "/home/maarten/src/libreoffice/core/include/tools/ref.hxx", 142, __extension__ __PRETTY_FUNCTION__)); | |||
143 | ++nRefCount; | |||
144 | } | |||
145 | ||||
146 | void AddFirstRef() | |||
147 | { | |||
148 | assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" )(static_cast <bool> (nRefCount < (1 << 30) && "Do not add refs to dead objects") ? void (0) : __assert_fail ("nRefCount < (1 << 30) && \"Do not add refs to dead objects\"" , "/home/maarten/src/libreoffice/core/include/tools/ref.hxx", 148, __extension__ __PRETTY_FUNCTION__)); | |||
149 | if( bNoDelete ) | |||
150 | bNoDelete = 0; | |||
151 | ++nRefCount; | |||
152 | } | |||
153 | ||||
154 | void ReleaseRef() | |||
155 | { | |||
156 | assert( nRefCount >= 1)(static_cast <bool> (nRefCount >= 1) ? void (0) : __assert_fail ("nRefCount >= 1", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx" , 156, __extension__ __PRETTY_FUNCTION__)); | |||
157 | if( --nRefCount == 0 && !bNoDelete) | |||
158 | { | |||
159 | // I'm not sure about the original purpose of this line, but right now | |||
160 | // it serves the purpose that anything that attempts to do an AddRef() | |||
161 | // after an object is deleted will trip an assert. | |||
162 | nRefCount = 1 << 30; | |||
163 | delete this; | |||
164 | } | |||
165 | } | |||
166 | ||||
167 | unsigned int GetRefCount() const | |||
168 | { return nRefCount; } | |||
169 | }; | |||
170 | ||||
171 | template<typename T> | |||
172 | class SvCompatWeakBase; | |||
173 | ||||
174 | /** SvCompatWeakHdl acts as an intermediary between SvCompatWeakRef<T> and T. | |||
175 | */ | |||
176 | template<typename T> | |||
177 | class SvCompatWeakHdl final : public SvRefBase | |||
178 | { | |||
179 | friend class SvCompatWeakBase<T>; | |||
180 | T* _pObj; | |||
181 | ||||
182 | SvCompatWeakHdl( T* pObj ) : _pObj( pObj ) {} | |||
183 | ||||
184 | public: | |||
185 | void ResetWeakBase( ) { _pObj = nullptr; } | |||
186 | T* GetObj() { return _pObj; } | |||
187 | }; | |||
188 | ||||
189 | /** We only have one place that extends this, in include/sfx2/frame.hxx, class SfxFrame. | |||
190 | Its function is to notify the SvCompatWeakHdl when an SfxFrame object is deleted. | |||
191 | */ | |||
192 | template<typename T> | |||
193 | class SvCompatWeakBase | |||
194 | { | |||
195 | tools::SvRef< SvCompatWeakHdl<T> > _xHdl; | |||
196 | ||||
197 | public: | |||
198 | /** Does not use initializer due to compiler warnings, | |||
199 | because the lifetime of the _xHdl object can exceed the lifetime of this class. | |||
200 | */ | |||
201 | SvCompatWeakBase( T* pObj ) { _xHdl = new SvCompatWeakHdl<T>( pObj ); } | |||
202 | ||||
203 | ~SvCompatWeakBase() { _xHdl->ResetWeakBase(); } | |||
204 | ||||
205 | SvCompatWeakHdl<T>* GetHdl() { return _xHdl.get(); } | |||
206 | }; | |||
207 | ||||
208 | /** We only have one weak reference in LO, in include/sfx2/frame.hxx, class SfxFrameWeak. | |||
209 | */ | |||
210 | template<typename T> | |||
211 | class SAL_WARN_UNUSED__attribute__((warn_unused)) SvCompatWeakRef | |||
212 | { | |||
213 | tools::SvRef< SvCompatWeakHdl<T> > _xHdl; | |||
214 | public: | |||
215 | SvCompatWeakRef( ) {} | |||
216 | SvCompatWeakRef( T* pObj ) | |||
217 | { if( pObj ) _xHdl = pObj->GetHdl(); } | |||
218 | #if defined(__COVERITY__) | |||
219 | ~SvCompatWeakRef() COVERITY_NOEXCEPT_FALSE {} | |||
220 | #endif | |||
221 | SvCompatWeakRef& operator = ( T * pObj ) | |||
222 | { _xHdl = pObj ? pObj->GetHdl() : nullptr; return *this; } | |||
223 | bool is() const | |||
224 | { return _xHdl.is() && _xHdl->GetObj(); } | |||
225 | explicit operator bool() const { return is(); } | |||
226 | T* operator -> () const | |||
227 | { return _xHdl.is() ? _xHdl->GetObj() : nullptr; } | |||
228 | operator T* () const | |||
229 | { return _xHdl.is() ? _xHdl->GetObj() : nullptr; } | |||
230 | }; | |||
231 | ||||
232 | #endif | |||
233 | ||||
234 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |