1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_connectivity.hxx"
26
27 #include "MacabRecord.hxx"
28 #include "macabutilities.hxx"
29 #include <com/sun/star/util/DateTime.hpp>
30
31 #include <premac.h>
32 #include <Carbon/Carbon.h>
33 #include <AddressBook/ABAddressBookC.h>
34 #include <postmac.h>
35 #include <connectivity/dbconversion.hxx>
36
37 using namespace connectivity::macab;
38 using namespace com::sun::star::util;
39 using namespace ::dbtools;
40
41 // -------------------------------------------------------------------------
MacabRecord()42 MacabRecord::MacabRecord()
43 {
44 size = 0;
45 fields = NULL;
46 }
47
48 // -------------------------------------------------------------------------
MacabRecord(const sal_Int32 _size)49 MacabRecord::MacabRecord(const sal_Int32 _size)
50 {
51 size = _size;
52 fields = new macabfield *[size];
53 sal_Int32 i;
54 for(i = 0; i < size; i++)
55 fields[i] = NULL;
56 }
57
58 // -------------------------------------------------------------------------
~MacabRecord()59 MacabRecord::~MacabRecord()
60 {
61 if(size > 0)
62 {
63 int i;
64 for(i = 0; i < size; i++)
65 {
66 delete fields[i];
67 fields[i] = NULL;
68 }
69 }
70 delete [] fields;
71 fields = NULL;
72 }
73
74 // -------------------------------------------------------------------------
insertAtColumn(CFTypeRef _value,ABPropertyType _type,const sal_Int32 _column)75 void MacabRecord::insertAtColumn (CFTypeRef _value, ABPropertyType _type, const sal_Int32 _column)
76 {
77 if(_column < size)
78 {
79 if(fields[_column] == NULL)
80 fields[_column] = new macabfield;
81
82 fields[_column]->value = _value;
83 if (fields[_column]->value)
84 CFRetain(fields[_column]->value);
85 fields[_column]->type = _type;
86 }
87 }
88
89 // -------------------------------------------------------------------------
contains(const macabfield * _field) const90 sal_Bool MacabRecord::contains (const macabfield *_field) const
91 {
92 if(_field == NULL)
93 return sal_False;
94 else
95 return contains(_field->value);
96 }
97
98 // -------------------------------------------------------------------------
contains(const CFTypeRef _value) const99 sal_Bool MacabRecord::contains (const CFTypeRef _value) const
100 {
101 sal_Int32 i;
102 for(i = 0; i < size; i++)
103 {
104 if(fields[i] != NULL)
105 {
106 if(CFEqual(fields[i]->value, _value))
107 {
108 return sal_True;
109 }
110 }
111 }
112
113 return sal_False;
114 }
115
116 // -------------------------------------------------------------------------
getSize() const117 sal_Int32 MacabRecord::getSize() const
118 {
119 return size;
120 }
121
122 // -------------------------------------------------------------------------
copy(const sal_Int32 i) const123 macabfield *MacabRecord::copy(const sal_Int32 i) const
124 {
125 /* Note: copy(i) creates a new macabfield identical to that at
126 * location i, whereas get(i) returns a pointer to the macabfield
127 * at location i.
128 */
129 if(i < size)
130 {
131 macabfield *_copy = new macabfield;
132 _copy->type = fields[i]->type;
133 _copy->value = fields[i]->value;
134 if (_copy->value)
135 CFRetain(_copy->value);
136 return _copy;
137 }
138
139 return NULL;
140 }
141
142 // -------------------------------------------------------------------------
get(const sal_Int32 i) const143 macabfield *MacabRecord::get(const sal_Int32 i) const
144 {
145 /* Note: copy(i) creates a new macabfield identical to that at
146 * location i, whereas get(i) returns a pointer to the macabfield
147 * at location i.
148 */
149 if(i < size)
150 {
151 return fields[i];
152 }
153
154 return NULL;
155 }
156
157 // -------------------------------------------------------------------------
releaseFields()158 void MacabRecord::releaseFields()
159 {
160 /* This method is, at the moment, only used in MacabHeader.cxx, but
161 * the idea is simple: if you are not destroying this object but want
162 * to clear it of its macabfields, you should release each field's
163 * value.
164 */
165 sal_Int32 i;
166 for(i = 0; i < size; i++)
167 CFRelease(fields[i]->value);
168 }
169
170 // -------------------------------------------------------------------------
compareFields(const macabfield * _field1,const macabfield * _field2)171 sal_Int32 MacabRecord::compareFields(const macabfield *_field1, const macabfield *_field2)
172 {
173
174 /* When comparing records, if either field is NULL (and the other is
175 * not), that field is considered "greater than" the other, so that it
176 * shows up later in the list when fields are ordered.
177 */
178 if(_field1 == _field2)
179 return 0;
180 if(_field1 == NULL)
181 return 1;
182 if(_field2 == NULL)
183 return -1;
184
185 /* If they aren't the same type, for now, return the one with
186 * the smaller type ID... I don't know of a better way to compare
187 * two different data types.
188 */
189 if(_field1->type != _field2->type)
190 return(_field1->type - _field2->type);
191
192 CFComparisonResult result;
193
194 /* Carbon has a unique compare function for each data type: */
195 switch(_field1->type)
196 {
197 case kABStringProperty:
198 result = CFStringCompare(
199 (CFStringRef) _field1->value,
200 (CFStringRef) _field2->value,
201 kCFCompareLocalized); // Specifies that the comparison should take into account differences related to locale, such as the thousands separator character.
202 break;
203
204 case kABDateProperty:
205 result = CFDateCompare(
206 (CFDateRef) _field1->value,
207 (CFDateRef) _field2->value,
208 NULL); // NULL = unused variable
209 break;
210
211 case kABIntegerProperty:
212 case kABRealProperty:
213 result = CFNumberCompare(
214 (CFNumberRef) _field1->value,
215 (CFNumberRef) _field2->value,
216 NULL); // NULL = unused variable
217 break;
218
219 default:
220 result = kCFCompareEqualTo; // can't compare
221 }
222
223 return (sal_Int32) result;
224 }
225
226 // -------------------------------------------------------------------------
227 /* Create a macabfield out of an OUString and type. Together with the
228 * method fieldToString() (below), it is possible to switch conveniently
229 * between an OUString and a macabfield (for use when creating and handling
230 * SQL statement).
231 */
createMacabField(const::rtl::OUString _newFieldString,const ABPropertyType _abType)232 macabfield *MacabRecord::createMacabField(const ::rtl::OUString _newFieldString, const ABPropertyType _abType)
233 {
234 macabfield *newField = NULL;
235 switch(_abType)
236 {
237 case kABStringProperty:
238 newField = new macabfield;
239 newField->value = OUStringToCFString(_newFieldString);
240 newField->type = _abType;
241 break;
242 case kABDateProperty:
243 {
244 DateTime aDateTime = DBTypeConversion::toDateTime(_newFieldString);
245
246 // bad format...
247 if(aDateTime.Year == 0 && aDateTime.Month == 0 && aDateTime.Day == 0)
248 {
249 }
250 else
251 {
252 double nTime = DBTypeConversion::toDouble(aDateTime, DBTypeConversion::getStandardDate());
253 nTime -= kCFAbsoluteTimeIntervalSince1970;
254 newField = new macabfield;
255 newField->value = CFDateCreate(NULL, (CFAbsoluteTime) nTime);
256 newField->type = _abType;
257 }
258 }
259 break;
260 case kABIntegerProperty:
261 try
262 {
263 sal_Int64 nVal = _newFieldString.toInt64();
264
265 newField = new macabfield;
266 newField->value = CFNumberCreate(NULL,kCFNumberLongType, &nVal);
267 newField->type = _abType;
268 }
269 // bad format...
270 catch(...)
271 {
272 }
273 break;
274 case kABRealProperty:
275 try
276 {
277 double nVal = _newFieldString.toDouble();
278
279 newField = new macabfield;
280 newField->value = CFNumberCreate(NULL,kCFNumberDoubleType, &nVal);
281 newField->type = _abType;
282 }
283 // bad format...
284 catch(...)
285 {
286 }
287 break;
288 default:
289 ;
290 }
291 return newField;
292 }
293
294 // -------------------------------------------------------------------------
295 /* Create an OUString out of a macabfield. Together with the method
296 * createMacabField() (above), it is possible to switch conveniently
297 * between an OUString and a macabfield (for use when creating and handling
298 * SQL statement).
299 */
fieldToString(const macabfield * _aField)300 ::rtl::OUString MacabRecord::fieldToString(const macabfield *_aField)
301 {
302 if(_aField == NULL)
303 return ::rtl::OUString();
304
305 ::rtl::OUString fieldString;
306
307 switch(_aField->type)
308 {
309 case kABStringProperty:
310 fieldString = CFStringToOUString((CFStringRef) _aField->value);
311 break;
312 case kABDateProperty:
313 {
314 DateTime aTime = CFDateToDateTime((CFDateRef) _aField->value);
315 fieldString = DBTypeConversion::toDateTimeString(aTime);
316 }
317 break;
318 case kABIntegerProperty:
319 {
320 CFNumberType numberType = CFNumberGetType( (CFNumberRef) _aField->value );
321 sal_Int64 nVal;
322 // Should we check for the wrong type here, e.g., a float?
323 sal_Bool m_bSuccess = !CFNumberGetValue((CFNumberRef) _aField->value, numberType, &nVal);
324 if(m_bSuccess != sal_False)
325 fieldString = ::rtl::OUString::valueOf(nVal);
326 }
327 break;
328 case kABRealProperty:
329 {
330 CFNumberType numberType = CFNumberGetType( (CFNumberRef) _aField->value );
331 double nVal;
332 // Should we check for the wrong type here, e.g., an int?
333 sal_Bool m_bSuccess = !CFNumberGetValue((CFNumberRef) _aField->value, numberType, &nVal);
334 if(m_bSuccess != sal_False)
335 fieldString = ::rtl::OUString::valueOf(nVal);
336 }
337 break;
338 default:
339 ;
340 }
341 return fieldString;
342
343 }
344