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