LibreOffice Module connectivity (master) 1
MacabHeader.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 * 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
21#include "MacabHeader.hxx"
22#include "MacabRecord.hxx"
23#include "macabutilities.hxx"
24
25#include <math.h>
26#include <com/sun/star/sdbc/DataType.hpp>
28
29using namespace connectivity::macab;
30using namespace com::sun::star::sdbc;
31using namespace com::sun::star::util;
32using namespace ::dbtools;
33
34
35MacabHeader::MacabHeader(const sal_Int32 _size, macabfield **_fields)
36{
37 sal_Int32 i;
38 size = _size;
39 fields = std::make_unique<macabfield *[]>(size);
40 for(i = 0; i < size; i++)
41 {
42 if(_fields[i] == nullptr)
43 {
44 fields[i] = nullptr;
45 }
46 else
47 {
48 /* The constructor duplicates the macabfields it gets because they
49 * are either deleted later or used for other purposes.
50 */
51 fields[i] = new macabfield;
52 fields[i]->type = _fields[i]->type;
53 fields[i]->value = _fields[i]->value;
54 if (fields[i]->value)
55 CFRetain(fields[i]->value);
56 }
57 }
58
59}
60
61
63{
64 size = 0;
65 fields = nullptr;
66}
67
68
70{
71}
72
73
75{
76 /* Add one MacabHeader to another. Anything not already in the header is
77 * added to the end of it.
78 */
79 sal_Int32 rSize = r->getSize();
80 if(rSize != 0) // If the new header does actually have fields
81 {
82 /* If our header is currently empty, just copy all of the fields from
83 * the new header to this one.
84 */
85 if(size == 0)
86 {
87 sal_Int32 i;
88 size = rSize;
89 fields = std::make_unique<macabfield *[]>(size);
90 for(i = 0; i < size; i++)
91 {
92 fields[i] = r->copy(i);
93 }
94 }
95
96 /* Otherwise, only add the duplicates. We do this with a two-pass
97 * approach. First, find out how many fields to add, then reallocate
98 * the size of the fields array and add the old ones at the end.
99 * (More precisely, we create a _new_ fields array with the new length
100 * allocated to it, then get all of the fields from the current
101 * fields array to it, then copy the non-duplicates from the new
102 * header to the end.)
103 */
104 else
105 {
106 sal_Int32 i;
107 sal_Int32 numToAdd = 0, numAdded = 0;
108 macabfield **newFields;
109 for( i = 0; i < rSize; i++)
110 {
111 if(!contains(r->get(i)))
112 {
113 numToAdd++;
114 }
115 }
116
117 newFields = new macabfield *[size+numToAdd];
118 for(i = 0; i < size; i++)
119 {
120 newFields[i] = copy(i);
121 }
122
123 for( i = 0; i < rSize; i++)
124 {
125 if(!contains(r->get(i)))
126 {
127 newFields[size+numAdded] = r->copy(i);
128 numAdded++;
129 if(numAdded == numToAdd)
130 break;
131 }
132 }
133
135 size += numAdded;
136 fields.reset(newFields);
137 }
138 }
139}
140
141
142OUString MacabHeader::getString(const sal_Int32 i) const
143{
144 OUString nRet;
145
146 if(i < size)
147 {
148 if(fields[i] == nullptr || fields[i]->value == nullptr || CFGetTypeID(fields[i]->value) != CFStringGetTypeID())
149 return OUString();
150 try
151 {
152 nRet = CFStringToOUString(static_cast<CFStringRef>(fields[i]->value));
153 }
154 catch(...){ }
155 }
156
157 return nRet;
158}
159
160
162{
163 sortRecord(0,size);
164}
165
166
167macabfield **MacabHeader::sortRecord(const sal_Int32 _start, const sal_Int32 _length)
168{
169 /* Sort using mergesort. Because it uses mergesort, it is recursive and
170 * not in place (so it creates a new array at every step of the
171 * recursion), so if you prefer to use a different sort, please feel
172 * free to implement it.
173 */
174 macabfield** sorted = new macabfield *[_length];
175 if(_length <= 2)
176 {
177 if(_length == 2)
178 {
179 if(compareFields(fields[_start], fields[_start+1]) > 0)
180 {
181 sorted[0] = get(_start+1);
182 sorted[1] = get(_start);
183 }
184 else
185 {
186 sorted[0] = get(_start);
187 sorted[1] = get(_start+1);
188 }
189 }
190 else if(_length == 1)
191 {
192 sorted[0] = get(_start);
193 }
194 }
195 else
196 {
197 sal_Int32 halfLength = floor(_length/2);
198 sal_Int32 fp = 0, lp = 0;
199 sal_Int32 i;
200 macabfield **firstHalf = sortRecord(_start, halfLength);
201 macabfield **lastHalf = sortRecord(_start+halfLength, _length-halfLength);
202
203 for(i = 0; i < _length; i++)
204 {
205 if(compareFields(firstHalf[fp],lastHalf[lp]) < 0)
206 {
207 sorted[i] = firstHalf[fp++];
208 if(fp == halfLength)
209 {
210 for( i++; i < _length; i++)
211 {
212 sorted[i] = lastHalf[lp++];
213 }
214 break;
215 }
216 }
217 else
218 {
219 sorted[i] = lastHalf[lp++];
220 if(lp == _length - halfLength)
221 {
222 for( i++; i < _length; i++)
223 {
224 sorted[i] = firstHalf[fp++];
225 }
226 break;
227 }
228 }
229 }
230 if(_length == size)
231 {
232 fields.reset(sorted);
233 }
234 delete firstHalf;
235 delete lastHalf;
236 }
237 return sorted;
238}
239
240sal_Int32 MacabHeader::compareFields(const macabfield *_field1, const macabfield *_field2)
241{
242 /* Comparing two fields in a MacabHeader is different than comparing two
243 * fields in a MacabRecord. It starts in the same way (if one of the two
244 * fields is NULL, it belongs after the other, so it is considered
245 * "greater"). But, then, all headers are CFStrings, no matter what
246 * type they claim to be (since they actually hold the expected type for
247 * the records with that header). That being said, all we have to do is
248 * the built-in CFStringCompare.
249 */
250 if(_field1 == _field2)
251 return 0;
252 if(_field1 == nullptr)
253 return 1;
254 if(_field2 == nullptr)
255 return -1;
256
257 CFComparisonResult result = CFStringCompare(
258 static_cast<CFStringRef>(_field1->value),
259 static_cast<CFStringRef>(_field2->value),
260 0); // 0 = no options (like ignore case)
261
262 return static_cast<sal_Int32>(result);
263}
264
265
266sal_Int32 MacabHeader::getColumnNumber(std::u16string_view s) const
267{
268 sal_Int32 i;
269 for(i = 0; i < size; i++)
270 {
271 if(getString(i) == s)
272 break;
273 }
274
275 if(i == size)
276 i = -1;
277
278 return i;
279}
280
281
283{
284 return this;
285}
286
287
289{
290}
291
292
294{
295 id = 0;
296 record = _record;
297 return *this;
298}
299
300
302{
303 id++;
304}
305
306
307bool MacabHeader::iterator::operator!= (const sal_Int32 i) const
308{
309 return(id != i);
310}
311
312
313bool MacabHeader::iterator::operator== (const sal_Int32 i) const
314{
315 return(id == i);
316}
317
318
320{
321 return record->get(id);
322}
323
324
325sal_Int32 MacabHeader::end() const
326{
327 return size;
328}
329
330/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool operator==(const sal_Int32 i) const
bool operator!=(const sal_Int32 i) const
iterator & operator=(MacabHeader *_record)
virtual ~MacabHeader() override
Definition: MacabHeader.cxx:69
sal_Int32 getColumnNumber(std::u16string_view s) const
OUString getString(const sal_Int32 i) const
static sal_Int32 compareFields(const macabfield *_field1, const macabfield *_field2)
void operator+=(const MacabHeader *r)
Definition: MacabHeader.cxx:74
std::unique_ptr< macabfield *[]> fields
Definition: MacabRecord.hxx:50
macabfield * get(const sal_Int32 i) const
macabfield * copy(const sal_Int32 i) const
bool contains(const macabfield *_field) const
Definition: MacabRecord.cxx:81
Any value
OUString CFStringToOUString(const CFStringRef sOrig)
int i
Any result