Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/include/oox/helper/containerhelper.hxx
Line
Count
Source
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
20
#ifndef INCLUDED_OOX_HELPER_CONTAINERHELPER_HXX
21
#define INCLUDED_OOX_HELPER_CONTAINERHELPER_HXX
22
23
#include <cstddef>
24
#include <vector>
25
26
#include <com/sun/star/uno/Reference.hxx>
27
#include <com/sun/star/uno/Sequence.hxx>
28
#include <oox/dllapi.h>
29
#include <rtl/ustring.hxx>
30
#include <sal/types.h>
31
32
namespace com::sun::star {
33
    namespace container { class XNameAccess; }
34
    namespace container { class XNameContainer; }
35
    namespace uno { class Any; }
36
}
37
38
namespace oox {
39
40
41
/** A range of signed 32-bit integer values. */
42
struct ValueRange
43
{
44
    sal_Int32           mnFirst;
45
    sal_Int32           mnLast;
46
47
100k
    explicit     ValueRange( sal_Int32 nValue ) : mnFirst( nValue ), mnLast( nValue ) {}
48
58.5k
    explicit     ValueRange( sal_Int32 nFirst, sal_Int32 nLast ) : mnFirst( nFirst ), mnLast( nLast ) {}
49
50
0
    bool         operator==( const ValueRange& rRange ) const { return (mnFirst == rRange.mnFirst) && (mnLast == rRange.mnLast); }
51
0
    bool         operator!=( const ValueRange& rRange ) const { return !(*this == rRange); }
52
0
    bool         contains( const ValueRange& rRange ) const { return (mnFirst <= rRange.mnFirst) && (rRange.mnLast <= mnLast); }
53
0
    bool         intersects( const ValueRange& rRange ) const { return (mnFirst <= rRange.mnLast) && (rRange.mnFirst <= mnLast); }
54
};
55
56
57
typedef ::std::vector< ValueRange > ValueRangeVector;
58
59
60
/** An ordered list of value ranges. The insertion operation will merge
61
    consecutive value ranges.
62
 */
63
class OOX_DLLPUBLIC ValueRangeSet
64
{
65
public:
66
180
                        ValueRangeSet() {}
67
68
    /** Inserts the passed value range into the range list. */
69
    void                insert( const ValueRange& rRange );
70
71
    /** Returns the ordered list of all value ranges. */
72
0
    const ValueRangeVector& getRanges() const { return maRanges; }
73
74
private:
75
    ValueRangeVector    maRanges;
76
};
77
78
79
/** Template for a 2-dimensional array of objects.
80
81
    This class template provides a similar interface to the ::std::vector
82
    template.
83
 */
84
template< typename Type >
85
class Matrix
86
{
87
public:
88
    typedef ::std::vector< Type >                       container_type;
89
    typedef typename container_type::value_type         value_type;
90
    typedef typename container_type::pointer            pointer;
91
    typedef typename container_type::reference          reference;
92
    typedef typename container_type::const_reference    const_reference;
93
    typedef typename container_type::size_type          size_type;
94
    typedef typename container_type::iterator           iterator;
95
    typedef typename container_type::const_iterator     const_iterator;
96
97
5
                 Matrix() : mnWidth( 0 ) {}
98
0
    explicit     Matrix( size_type nWidth, size_type nHeight ) { resize( nWidth, nHeight ); }
99
    explicit     Matrix( size_type nWidth, size_type nHeight, const_reference rData ) { resize( nWidth, nHeight, rData ); }
100
101
0
    bool         empty() const { return maData.empty(); }
102
0
    size_type    size() const { return maData.size(); }
103
0
    size_type    width() const { return mnWidth; }
104
0
    size_type    height() const { return empty() ? 0 : (size() / width()); }
105
106
0
    void         clear() { resize( 0, 0 ); }
107
0
    void         resize( size_type nWidth, size_type nHeight ) { mnWidth = nWidth; maData.resize( nWidth * nHeight ); }
108
0
    void         resize( size_type nWidth, size_type nHeight, const_reference rData ) { mnWidth = nWidth; maData.resize( nWidth * nHeight, rData ); }
109
110
    iterator     at( size_type nX, size_type nY ) { return maData.begin() + mnWidth * nY + nX; }
111
0
    const_iterator at( size_type nX, size_type nY ) const { return maData.begin() + mnWidth * nY + nX; }
112
113
    reference    operator()( size_type nX, size_type nY ) { return *at( nX, nY ); }
114
0
    const_reference operator()( size_type nX, size_type nY ) const { return *at( nX, nY ); }
115
116
0
    iterator     begin() { return maData.begin(); }
117
    const_iterator begin() const { return maData.begin(); }
118
0
    iterator     end() { return maData.end(); }
119
    const_iterator end() const { return maData.end(); }
120
121
    iterator     row_begin( size_type nY ) { return at( 0, nY ); }
122
0
    const_iterator row_begin( size_type nY ) const { return at( 0, nY ); }
123
    iterator     row_end( size_type nY ) { return at( mnWidth, nY ); }
124
0
    const_iterator row_end( size_type nY ) const { return at( mnWidth, nY ); }
125
126
    reference    row_front( size_type nY ) { return (*this)( 0, nY ); }
127
0
    const_reference row_front( size_type nY ) const { return (*this)( 0, nY ); }
128
129
private:
130
    container_type      maData;
131
    size_type           mnWidth;
132
};
133
134
135
/** Static helper functions for improved API container handling. */
136
class OOX_DLLPUBLIC ContainerHelper
137
{
138
public:
139
140
    /** Returns a name that is not used in the passed name container.
141
142
        @param rxNameAccess  com.sun.star.container.XNameAccess interface of
143
            the name container.
144
145
        @param rSuggestedName  Suggested name for the object.
146
147
        @return  An unused name. Will be equal to the suggested name, if not
148
            contained, otherwise a numerical index will be appended.
149
     */
150
    static OUString getUnusedName(
151
                            const css::uno::Reference< css::container::XNameAccess >& rxNameAccess,
152
                            const OUString& rSuggestedName,
153
                            sal_Unicode cSeparator );
154
155
    /** Inserts an object into a name container.
156
157
        @param rxNameContainer  com.sun.star.container.XNameContainer interface
158
            of the name container.
159
160
        @param rName  Exact name for the object.
161
162
        @param rObject  The object to be inserted.
163
164
        @return  True = object successfully inserted.
165
     */
166
    static bool         insertByName(
167
                            const css::uno::Reference< css::container::XNameContainer >& rxNameContainer,
168
                            const OUString& rName,
169
                            const css::uno::Any& rObject );
170
171
    /** Inserts an object into a name container.
172
173
        The function will use an unused name to insert the object, based on the
174
        suggested object name. It is possible to specify whether the existing
175
        object or the new inserted object will be renamed, if the container
176
        already has an object with the name suggested for the new object.
177
178
        @param rxNameContainer  com.sun.star.container.XNameContainer interface
179
            of the name container.
180
181
        @param rSuggestedName  Suggested name for the object.
182
183
        @param rObject  The object to be inserted.
184
185
        The new object
186
        will be inserted with a name not yet extant in the container (this
187
        is done by appending a numerical index to the suggested name).
188
189
        @return  The final name the object is inserted with. Will always be
190
            equal to the suggested name, if parameter bRenameOldExisting is
191
            true.
192
     */
193
    static OUString insertByUnusedName(
194
                            const css::uno::Reference< css::container::XNameContainer >& rxNameContainer,
195
                            const OUString& rSuggestedName,
196
                            sal_Unicode cSeparator,
197
                            const css::uno::Any& rObject );
198
199
    // std::vector and std::map element access --------------------------------
200
201
    /** Returns the pointer to an existing element of the passed vector, or a
202
        null pointer, if the passed index is out of bounds. */
203
    template< typename VectorType >
204
    static const typename VectorType::value_type*
205
                        getVectorElement( const VectorType& rVector, sal_Int32 nIndex );
206
207
    /** Returns the pointer to an existing element of the passed vector, or a
208
        null pointer, if the passed index is out of bounds. */
209
    template< typename VectorType >
210
    static typename VectorType::value_type*
211
                        getVectorElementAccess( VectorType& rVector, sal_Int32 nIndex );
212
213
    /** Returns the reference to an existing element of the passed vector, or
214
        the passed default value, if the passed index is out of bounds. */
215
    template< typename VectorType >
216
    static const typename VectorType::value_type&
217
                        getVectorElement( const VectorType& rVector, sal_Int32 nIndex, const typename VectorType::value_type& rDefault );
218
219
    /** Returns the pointer to an existing element of the passed map, or a null
220
        pointer, if an element with the passed key does not exist. */
221
    template< typename MapType >
222
    static const typename MapType::mapped_type*
223
                        getMapElement( const MapType& rMap, const typename MapType::key_type& rKey );
224
225
    /** Returns the reference to an existing element of the passed map, or the
226
        passed default value, if an element with the passed key does not exist. */
227
    template< typename MapType >
228
    static const typename MapType::mapped_type&
229
                        getMapElement( const MapType& rMap, const typename MapType::key_type& rKey, const typename MapType::mapped_type& rDefault );
230
231
    /** Creates a UNO sequence of sequences from a matrix with copies of all elements.
232
233
        @param rMatrix  The matrix to be converted to a sequence of sequences.
234
235
        @return  A com.sun.star.uno.Sequence object containing
236
            com.sun.star.uno.Sequence objects with copies of all objects
237
            contained in the passed matrix.
238
     */
239
    template< typename MatrixType >
240
    static css::uno::Sequence< css::uno::Sequence< typename MatrixType::value_type > >
241
                            matrixToSequenceSequence( const MatrixType& rMatrix );
242
};
243
244
245
template< typename VectorType >
246
/*static*/ const typename VectorType::value_type* ContainerHelper::getVectorElement( const VectorType& rVector, sal_Int32 nIndex )
247
2.25M
{
248
2.25M
    return ((0 <= nIndex) && (static_cast< size_t >( nIndex ) < rVector.size())) ? &rVector[ static_cast< size_t >( nIndex ) ] : nullptr;
249
2.25M
}
std::__1::vector<oox::xls::PivotCacheItem, std::__1::allocator<oox::xls::PivotCacheItem> >::value_type const* oox::ContainerHelper::getVectorElement<std::__1::vector<oox::xls::PivotCacheItem, std::__1::allocator<oox::xls::PivotCacheItem> > >(std::__1::vector<oox::xls::PivotCacheItem, std::__1::allocator<oox::xls::PivotCacheItem> > const&, int)
Line
Count
Source
247
2.27k
{
248
2.27k
    return ((0 <= nIndex) && (static_cast< size_t >( nIndex ) < rVector.size())) ? &rVector[ static_cast< size_t >( nIndex ) ] : nullptr;
249
2.27k
}
std::__1::vector<oox::xls::PivotCacheGroupItem, std::__1::allocator<oox::xls::PivotCacheGroupItem> >::value_type const* oox::ContainerHelper::getVectorElement<std::__1::vector<oox::xls::PivotCacheGroupItem, std::__1::allocator<oox::xls::PivotCacheGroupItem> > >(std::__1::vector<oox::xls::PivotCacheGroupItem, std::__1::allocator<oox::xls::PivotCacheGroupItem> > const&, int)
Line
Count
Source
247
51
{
248
51
    return ((0 <= nIndex) && (static_cast< size_t >( nIndex ) < rVector.size())) ? &rVector[ static_cast< size_t >( nIndex ) ] : nullptr;
249
51
}
std::__1::vector<oox::xls::PTDataFieldModel, std::__1::allocator<oox::xls::PTDataFieldModel> >::value_type const* oox::ContainerHelper::getVectorElement<std::__1::vector<oox::xls::PTDataFieldModel, std::__1::allocator<oox::xls::PTDataFieldModel> > >(std::__1::vector<oox::xls::PTDataFieldModel, std::__1::allocator<oox::xls::PTDataFieldModel> > const&, int)
Line
Count
Source
247
2
{
248
2
    return ((0 <= nIndex) && (static_cast< size_t >( nIndex ) < rVector.size())) ? &rVector[ static_cast< size_t >( nIndex ) ] : nullptr;
249
2
}
std::__1::vector<Color, std::__1::allocator<Color> >::value_type const* oox::ContainerHelper::getVectorElement<std::__1::vector<Color, std::__1::allocator<Color> > >(std::__1::vector<Color, std::__1::allocator<Color> > const&, int)
Line
Count
Source
247
2.25M
{
248
2.25M
    return ((0 <= nIndex) && (static_cast< size_t >( nIndex ) < rVector.size())) ? &rVector[ static_cast< size_t >( nIndex ) ] : nullptr;
249
2.25M
}
Unexecuted instantiation: std::__1::vector<rtl::OUString, std::__1::allocator<rtl::OUString> >::value_type const* oox::ContainerHelper::getVectorElement<std::__1::vector<rtl::OUString, std::__1::allocator<rtl::OUString> > >(std::__1::vector<rtl::OUString, std::__1::allocator<rtl::OUString> > const&, int)
250
251
template< typename VectorType >
252
/*static*/ typename VectorType::value_type* ContainerHelper::getVectorElementAccess( VectorType& rVector, sal_Int32 nIndex )
253
120
{
254
120
    return ((0 <= nIndex) && (static_cast< size_t >( nIndex ) < rVector.size())) ? &rVector[ static_cast< size_t >( nIndex ) ] : nullptr;
255
120
}
std::__1::vector<std::__1::vector<int, std::__1::allocator<int> >, std::__1::allocator<std::__1::vector<int, std::__1::allocator<int> > > >::value_type* oox::ContainerHelper::getVectorElementAccess<std::__1::vector<std::__1::vector<int, std::__1::allocator<int> >, std::__1::allocator<std::__1::vector<int, std::__1::allocator<int> > > > >(std::__1::vector<std::__1::vector<int, std::__1::allocator<int> >, std::__1::allocator<std::__1::vector<int, std::__1::allocator<int> > > >&, int)
Line
Count
Source
253
98
{
254
98
    return ((0 <= nIndex) && (static_cast< size_t >( nIndex ) < rVector.size())) ? &rVector[ static_cast< size_t >( nIndex ) ] : nullptr;
255
98
}
std::__1::vector<oox::xls::PivotCacheGroupItem, std::__1::allocator<oox::xls::PivotCacheGroupItem> >::value_type* oox::ContainerHelper::getVectorElementAccess<std::__1::vector<oox::xls::PivotCacheGroupItem, std::__1::allocator<oox::xls::PivotCacheGroupItem> > >(std::__1::vector<oox::xls::PivotCacheGroupItem, std::__1::allocator<oox::xls::PivotCacheGroupItem> >&, int)
Line
Count
Source
253
22
{
254
22
    return ((0 <= nIndex) && (static_cast< size_t >( nIndex ) < rVector.size())) ? &rVector[ static_cast< size_t >( nIndex ) ] : nullptr;
255
22
}
256
257
template< typename VectorType >
258
/*static*/ const typename VectorType::value_type& ContainerHelper::getVectorElement( const VectorType& rVector, sal_Int32 nIndex, const typename VectorType::value_type& rDefault )
259
1.42k
{
260
1.42k
    return ((0 <= nIndex) && (static_cast< size_t >( nIndex ) < rVector.size())) ? rVector[ static_cast< size_t >( nIndex ) ] : rDefault;
261
1.42k
}
262
263
template< typename MapType >
264
/*static*/ const typename MapType::mapped_type* ContainerHelper::getMapElement( const MapType& rMap, const typename MapType::key_type& rKey )
265
10.4M
{
266
10.4M
    typename MapType::const_iterator aIt = rMap.find( rKey );
267
10.4M
    return (aIt == rMap.end()) ? nullptr : &aIt->second;
268
10.4M
}
std::__1::map<short, ScRange, std::__1::less<short>, std::__1::allocator<std::__1::pair<short const, ScRange> > >::mapped_type const* oox::ContainerHelper::getMapElement<std::__1::map<short, ScRange, std::__1::less<short>, std::__1::allocator<std::__1::pair<short const, ScRange> > > >(std::__1::map<short, ScRange, std::__1::less<short>, std::__1::allocator<std::__1::pair<short const, ScRange> > > const&, std::__1::map<short, ScRange, std::__1::less<short>, std::__1::allocator<std::__1::pair<short const, ScRange> > >::key_type const&)
Line
Count
Source
265
3.85k
{
266
3.85k
    typename MapType::const_iterator aIt = rMap.find( rKey );
267
3.85k
    return (aIt == rMap.end()) ? nullptr : &aIt->second;
268
3.85k
}
std::__1::map<int, rtl::OUString, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, rtl::OUString> > >::mapped_type const* oox::ContainerHelper::getMapElement<std::__1::map<int, rtl::OUString, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, rtl::OUString> > > >(std::__1::map<int, rtl::OUString, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, rtl::OUString> > > const&, std::__1::map<int, rtl::OUString, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, rtl::OUString> > >::key_type const&)
Line
Count
Source
265
10.4M
{
266
10.4M
    typename MapType::const_iterator aIt = rMap.find( rKey );
267
10.4M
    return (aIt == rMap.end()) ? nullptr : &aIt->second;
268
10.4M
}
std::__1::map<rtl::OUString, oox::vml::OleObjectInfo, std::__1::less<rtl::OUString>, std::__1::allocator<std::__1::pair<rtl::OUString const, oox::vml::OleObjectInfo> > >::mapped_type const* oox::ContainerHelper::getMapElement<std::__1::map<rtl::OUString, oox::vml::OleObjectInfo, std::__1::less<rtl::OUString>, std::__1::allocator<std::__1::pair<rtl::OUString const, oox::vml::OleObjectInfo> > > >(std::__1::map<rtl::OUString, oox::vml::OleObjectInfo, std::__1::less<rtl::OUString>, std::__1::allocator<std::__1::pair<rtl::OUString const, oox::vml::OleObjectInfo> > > const&, std::__1::map<rtl::OUString, oox::vml::OleObjectInfo, std::__1::less<rtl::OUString>, std::__1::allocator<std::__1::pair<rtl::OUString const, oox::vml::OleObjectInfo> > >::key_type const&)
Line
Count
Source
265
912
{
266
912
    typename MapType::const_iterator aIt = rMap.find( rKey );
267
912
    return (aIt == rMap.end()) ? nullptr : &aIt->second;
268
912
}
std::__1::map<rtl::OUString, oox::vml::ControlInfo, std::__1::less<rtl::OUString>, std::__1::allocator<std::__1::pair<rtl::OUString const, oox::vml::ControlInfo> > >::mapped_type const* oox::ContainerHelper::getMapElement<std::__1::map<rtl::OUString, oox::vml::ControlInfo, std::__1::less<rtl::OUString>, std::__1::allocator<std::__1::pair<rtl::OUString const, oox::vml::ControlInfo> > > >(std::__1::map<rtl::OUString, oox::vml::ControlInfo, std::__1::less<rtl::OUString>, std::__1::allocator<std::__1::pair<rtl::OUString const, oox::vml::ControlInfo> > > const&, std::__1::map<rtl::OUString, oox::vml::ControlInfo, std::__1::less<rtl::OUString>, std::__1::allocator<std::__1::pair<rtl::OUString const, oox::vml::ControlInfo> > >::key_type const&)
Line
Count
Source
265
879
{
266
879
    typename MapType::const_iterator aIt = rMap.find( rKey );
267
879
    return (aIt == rMap.end()) ? nullptr : &aIt->second;
268
879
}
269
270
template< typename MapType >
271
/*static*/ const typename MapType::mapped_type& ContainerHelper::getMapElement( const MapType& rMap, const typename MapType::key_type& rKey, const typename MapType::mapped_type& rDefault )
272
2.97M
{
273
2.97M
    typename MapType::const_iterator aIt = rMap.find( rKey );
274
2.97M
    return (aIt == rMap.end()) ? rDefault : aIt->second;
275
2.97M
}
Unexecuted instantiation: std::__1::map<oox::xls::BinAddress, com::sun::star::uno::Sequence<com::sun::star::sheet::FormulaToken>, std::__1::less<oox::xls::BinAddress>, std::__1::allocator<std::__1::pair<oox::xls::BinAddress const, com::sun::star::uno::Sequence<com::sun::star::sheet::FormulaToken> > > >::mapped_type const& oox::ContainerHelper::getMapElement<std::__1::map<oox::xls::BinAddress, com::sun::star::uno::Sequence<com::sun::star::sheet::FormulaToken>, std::__1::less<oox::xls::BinAddress>, std::__1::allocator<std::__1::pair<oox::xls::BinAddress const, com::sun::star::uno::Sequence<com::sun::star::sheet::FormulaToken> > > > >(std::__1::map<oox::xls::BinAddress, com::sun::star::uno::Sequence<com::sun::star::sheet::FormulaToken>, std::__1::less<oox::xls::BinAddress>, std::__1::allocator<std::__1::pair<oox::xls::BinAddress const, com::sun::star::uno::Sequence<com::sun::star::sheet::FormulaToken> > > > const&, std::__1::map<oox::xls::BinAddress, com::sun::star::uno::Sequence<com::sun::star::sheet::FormulaToken>, std::__1::less<oox::xls::BinAddress>, std::__1::allocator<std::__1::pair<oox::xls::BinAddress const, com::sun::star::uno::Sequence<com::sun::star::sheet::FormulaToken> > > >::key_type const&, std::__1::map<oox::xls::BinAddress, com::sun::star::uno::Sequence<com::sun::star::sheet::FormulaToken>, std::__1::less<oox::xls::BinAddress>, std::__1::allocator<std::__1::pair<oox::xls::BinAddress const, com::sun::star::uno::Sequence<com::sun::star::sheet::FormulaToken> > > >::mapped_type const&)
std::__1::map<int, Color, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, Color> > >::mapped_type const& oox::ContainerHelper::getMapElement<std::__1::map<int, Color, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, Color> > > >(std::__1::map<int, Color, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, Color> > > const&, std::__1::map<int, Color, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, Color> > >::key_type const&, std::__1::map<int, Color, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, Color> > >::mapped_type const&)
Line
Count
Source
272
2.97M
{
273
2.97M
    typename MapType::const_iterator aIt = rMap.find( rKey );
274
2.97M
    return (aIt == rMap.end()) ? rDefault : aIt->second;
275
2.97M
}
276
277
template< typename MatrixType >
278
/*static*/ css::uno::Sequence< css::uno::Sequence< typename MatrixType::value_type > > ContainerHelper::matrixToSequenceSequence( const MatrixType& rMatrix )
279
0
{
280
0
    typedef typename MatrixType::value_type ValueType;
281
0
    css::uno::Sequence< css::uno::Sequence< ValueType > > aSeq;
282
0
    if( !rMatrix.empty() )
283
0
    {
284
0
        aSeq.realloc( static_cast< sal_Int32 >( rMatrix.height() ) );
285
0
        auto pSeq = aSeq.getArray();
286
0
        for( size_t nRow = 0, nHeight = rMatrix.height(); nRow < nHeight; ++nRow )
287
0
            pSeq[ static_cast< sal_Int32 >( nRow ) ] =
288
0
                css::uno::Sequence< ValueType >( &rMatrix.row_front( nRow ), static_cast< sal_Int32 >( rMatrix.width() ) );
289
0
    }
290
0
    return aSeq;
291
0
}
292
293
294
} // namespace oox
295
296
#endif
297
298
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */