xref: /trunk/main/connectivity/source/drivers/macab/MacabRecords.cxx (revision 152e651ef53ab2fae14bf93407606b2c7fcbd35b)
19b5730f6SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
39b5730f6SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
49b5730f6SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
59b5730f6SAndrew Rist  * distributed with this work for additional information
69b5730f6SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
79b5730f6SAndrew Rist  * to you under the Apache License, Version 2.0 (the
89b5730f6SAndrew Rist  * "License"); you may not use this file except in compliance
99b5730f6SAndrew Rist  * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir  *
119b5730f6SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
139b5730f6SAndrew Rist  * Unless required by applicable law or agreed to in writing,
149b5730f6SAndrew Rist  * software distributed under the License is distributed on an
159b5730f6SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
169b5730f6SAndrew Rist  * KIND, either express or implied.  See the License for the
179b5730f6SAndrew Rist  * specific language governing permissions and limitations
189b5730f6SAndrew Rist  * under the License.
19cdf0e10cSrcweir  *
209b5730f6SAndrew Rist  *************************************************************/
219b5730f6SAndrew Rist 
229b5730f6SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_connectivity.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include "MacabRecords.hxx"
28cdf0e10cSrcweir #include "MacabRecord.hxx"
29cdf0e10cSrcweir #include "MacabHeader.hxx"
30cdf0e10cSrcweir #include "macabutilities.hxx"
31cdf0e10cSrcweir 
32cdf0e10cSrcweir #include <premac.h>
33cdf0e10cSrcweir #include <Carbon/Carbon.h>
34cdf0e10cSrcweir #include <AddressBook/ABAddressBookC.h>
35cdf0e10cSrcweir #include <postmac.h>
36cdf0e10cSrcweir #include <com/sun/star/util/DateTime.hpp>
37cdf0e10cSrcweir 
38cdf0e10cSrcweir using namespace connectivity::macab;
39cdf0e10cSrcweir using namespace com::sun::star::util;
40cdf0e10cSrcweir 
41cdf0e10cSrcweir // -------------------------------------------------------------------------
MacabRecords(const ABAddressBookRef _addressBook,MacabHeader * _header,MacabRecord ** _records,sal_Int32 _numRecords)42cdf0e10cSrcweir MacabRecords::MacabRecords(const ABAddressBookRef _addressBook, MacabHeader *_header, MacabRecord **_records, sal_Int32 _numRecords)
43cdf0e10cSrcweir {
44cdf0e10cSrcweir     /* Variables passed in... */
45cdf0e10cSrcweir     header = _header;
46cdf0e10cSrcweir     recordsSize = _numRecords;
47cdf0e10cSrcweir     currentRecord = _numRecords;
48cdf0e10cSrcweir     records = _records;
49cdf0e10cSrcweir     addressBook = _addressBook;
50cdf0e10cSrcweir 
51cdf0e10cSrcweir     /* Default variables... */
52cdf0e10cSrcweir     recordType = kABPersonRecordType;
53cdf0e10cSrcweir 
54cdf0e10cSrcweir     /* Variables constructed... */
55cdf0e10cSrcweir     bootstrap_CF_types();
56cdf0e10cSrcweir     bootstrap_requiredProperties();
57cdf0e10cSrcweir }
58cdf0e10cSrcweir 
59cdf0e10cSrcweir // -------------------------------------------------------------------------
60cdf0e10cSrcweir /* Creates a MacabRecords from another: copies the length, name, and
61cdf0e10cSrcweir  * address book of the original, but the header or the records themselves.
62cdf0e10cSrcweir  * The idea is that the only reason to copy a MacabRecords is to create
63cdf0e10cSrcweir  * a filtered version of it, which can have the same length (to avoid
64cdf0e10cSrcweir  * resizing) and will work from the same base addressbook, but might have
65cdf0e10cSrcweir  * entirey different values and even (possibly in the future) a different
66cdf0e10cSrcweir  * header.
67cdf0e10cSrcweir  */
MacabRecords(const MacabRecords * _copy)68cdf0e10cSrcweir MacabRecords::MacabRecords(const MacabRecords *_copy)
69cdf0e10cSrcweir {
70cdf0e10cSrcweir     /* Variables passed in... */
71cdf0e10cSrcweir     recordsSize = _copy->recordsSize;
72cdf0e10cSrcweir     addressBook = _copy->addressBook;
73cdf0e10cSrcweir     m_sName = _copy->m_sName;
74cdf0e10cSrcweir 
75cdf0e10cSrcweir     /* Default variables... */
76cdf0e10cSrcweir     currentRecord = 0;
77cdf0e10cSrcweir     header = NULL;
78cdf0e10cSrcweir     records = new MacabRecord *[recordsSize];
79cdf0e10cSrcweir     recordType = kABPersonRecordType;
80cdf0e10cSrcweir 
81cdf0e10cSrcweir     /* Variables constructed... */
82cdf0e10cSrcweir     bootstrap_CF_types();
83cdf0e10cSrcweir     bootstrap_requiredProperties();
84cdf0e10cSrcweir }
85cdf0e10cSrcweir 
86cdf0e10cSrcweir // -------------------------------------------------------------------------
MacabRecords(const ABAddressBookRef _addressBook)87cdf0e10cSrcweir MacabRecords::MacabRecords(const ABAddressBookRef _addressBook)
88cdf0e10cSrcweir {
89cdf0e10cSrcweir     /* Variables passed in... */
90cdf0e10cSrcweir     addressBook = _addressBook;
91cdf0e10cSrcweir 
92cdf0e10cSrcweir     /* Default variables... */
93cdf0e10cSrcweir     recordsSize = 0;
94cdf0e10cSrcweir     currentRecord = 0;
95cdf0e10cSrcweir     records = NULL;
96cdf0e10cSrcweir     header = NULL;
97cdf0e10cSrcweir     recordType = kABPersonRecordType;
98cdf0e10cSrcweir 
99cdf0e10cSrcweir     /* Variables constructed... */
100cdf0e10cSrcweir     bootstrap_CF_types();
101cdf0e10cSrcweir     bootstrap_requiredProperties();
102cdf0e10cSrcweir }
103cdf0e10cSrcweir 
104cdf0e10cSrcweir // -------------------------------------------------------------------------
initialize()105cdf0e10cSrcweir void MacabRecords::initialize()
106cdf0e10cSrcweir {
107cdf0e10cSrcweir 
108cdf0e10cSrcweir     /* Make sure everything is NULL before initializing. (We usually just
109cdf0e10cSrcweir      * initialize after we use the constructor that takes only a
110cdf0e10cSrcweir      * MacabAddressBook, so these variables will most likely already be
111cdf0e10cSrcweir      * NULL.
112cdf0e10cSrcweir      */
113cdf0e10cSrcweir     if(records != NULL)
114cdf0e10cSrcweir     {
115cdf0e10cSrcweir         sal_Int32 i;
116cdf0e10cSrcweir 
117cdf0e10cSrcweir         for(i = 0; i < recordsSize; i++)
118cdf0e10cSrcweir             delete records[i];
119cdf0e10cSrcweir 
120cdf0e10cSrcweir         delete [] records;
121cdf0e10cSrcweir     }
122cdf0e10cSrcweir 
123cdf0e10cSrcweir     if(header != NULL)
124cdf0e10cSrcweir         delete header;
125cdf0e10cSrcweir 
126cdf0e10cSrcweir     /* We can handle both default record Address Book record types in
127cdf0e10cSrcweir      * this method, though only kABPersonRecordType is ever used.
128cdf0e10cSrcweir      */
129cdf0e10cSrcweir     CFArrayRef allRecords;
130cdf0e10cSrcweir     if(CFStringCompare(recordType, kABPersonRecordType, 0) == kCFCompareEqualTo)
131cdf0e10cSrcweir         allRecords = ABCopyArrayOfAllPeople(addressBook);
132cdf0e10cSrcweir     else
133cdf0e10cSrcweir         allRecords = ABCopyArrayOfAllGroups(addressBook);
134cdf0e10cSrcweir 
135cdf0e10cSrcweir     ABRecordRef record;
136cdf0e10cSrcweir     sal_Int32 i;
137cdf0e10cSrcweir     recordsSize = (sal_Int32) CFArrayGetCount(allRecords);
138cdf0e10cSrcweir     records = new MacabRecord *[recordsSize];
139cdf0e10cSrcweir 
140cdf0e10cSrcweir     /* First, we create the header... */
141cdf0e10cSrcweir     header = createHeaderForRecordType(allRecords, recordType);
142cdf0e10cSrcweir 
143cdf0e10cSrcweir     /* Then, we create each of the records... */
144cdf0e10cSrcweir     for(i = 0; i < recordsSize; i++)
145cdf0e10cSrcweir     {
146cdf0e10cSrcweir         record = (ABRecordRef) CFArrayGetValueAtIndex(allRecords, i);
147cdf0e10cSrcweir         records[i] = createMacabRecord(record, header, recordType);
148cdf0e10cSrcweir     }
149cdf0e10cSrcweir     currentRecord = recordsSize;
150cdf0e10cSrcweir 
151cdf0e10cSrcweir     CFRelease(allRecords);
152cdf0e10cSrcweir }
153cdf0e10cSrcweir 
154cdf0e10cSrcweir // -------------------------------------------------------------------------
~MacabRecords()155cdf0e10cSrcweir MacabRecords::~MacabRecords()
156cdf0e10cSrcweir {
157cdf0e10cSrcweir }
158cdf0e10cSrcweir 
159cdf0e10cSrcweir // -------------------------------------------------------------------------
setHeader(MacabHeader * _header)160cdf0e10cSrcweir void MacabRecords::setHeader(MacabHeader *_header)
161cdf0e10cSrcweir {
162cdf0e10cSrcweir     if(header != NULL)
163cdf0e10cSrcweir         delete header;
164cdf0e10cSrcweir     header = _header;
165cdf0e10cSrcweir }
166cdf0e10cSrcweir 
167cdf0e10cSrcweir // -------------------------------------------------------------------------
getHeader() const168cdf0e10cSrcweir MacabHeader *MacabRecords::getHeader() const
169cdf0e10cSrcweir {
170cdf0e10cSrcweir     return header;
171cdf0e10cSrcweir }
172cdf0e10cSrcweir 
173cdf0e10cSrcweir // -------------------------------------------------------------------------
174cdf0e10cSrcweir /* Inserts a MacabRecord at a given location. If there is already a
175cdf0e10cSrcweir  * MacabRecord at that location, return it.
176cdf0e10cSrcweir  */
insertRecord(MacabRecord * _newRecord,const sal_Int32 _location)177cdf0e10cSrcweir MacabRecord *MacabRecords::insertRecord(MacabRecord *_newRecord, const sal_Int32 _location)
178cdf0e10cSrcweir {
179cdf0e10cSrcweir     MacabRecord *oldRecord;
180cdf0e10cSrcweir 
181cdf0e10cSrcweir     /* If the location is greater than the current allocated size of this
182cdf0e10cSrcweir      * MacabRecords, allocate more space.
183cdf0e10cSrcweir      */
184cdf0e10cSrcweir     if(_location >= recordsSize)
185cdf0e10cSrcweir     {
186cdf0e10cSrcweir         sal_Int32 i;
187cdf0e10cSrcweir         MacabRecord **newRecordsArray = new MacabRecord *[_location+1];
188cdf0e10cSrcweir         for(i = 0; i < recordsSize; i++)
189cdf0e10cSrcweir         {
190cdf0e10cSrcweir             newRecordsArray[i] = records[i];
191cdf0e10cSrcweir         }
192cdf0e10cSrcweir         delete [] records;
193cdf0e10cSrcweir         records = newRecordsArray;
194cdf0e10cSrcweir     }
195cdf0e10cSrcweir 
196cdf0e10cSrcweir     /* Remember: currentRecord refers to one above the highest existing
197cdf0e10cSrcweir      * record (i.e., it refers to where to place the next record if a
198cdf0e10cSrcweir      * location is not given).
199cdf0e10cSrcweir      */
200cdf0e10cSrcweir     if(_location >= currentRecord)
201cdf0e10cSrcweir         currentRecord = _location+1;
202cdf0e10cSrcweir 
203cdf0e10cSrcweir     oldRecord = records[_location];
204cdf0e10cSrcweir     records[_location] = _newRecord;
205cdf0e10cSrcweir     return oldRecord;
206cdf0e10cSrcweir }
207cdf0e10cSrcweir 
208cdf0e10cSrcweir // -------------------------------------------------------------------------
209cdf0e10cSrcweir /* Insert a record at the next available place. */
insertRecord(MacabRecord * _newRecord)210cdf0e10cSrcweir void MacabRecords::insertRecord(MacabRecord *_newRecord)
211cdf0e10cSrcweir {
212cdf0e10cSrcweir     insertRecord(_newRecord, currentRecord);
213cdf0e10cSrcweir }
214cdf0e10cSrcweir 
215cdf0e10cSrcweir // -------------------------------------------------------------------------
getRecord(const sal_Int32 _location) const216cdf0e10cSrcweir MacabRecord *MacabRecords::getRecord(const sal_Int32 _location) const
217cdf0e10cSrcweir {
218cdf0e10cSrcweir     if(_location >= recordsSize)
219cdf0e10cSrcweir         return NULL;
220cdf0e10cSrcweir     return records[_location];
221cdf0e10cSrcweir }
222cdf0e10cSrcweir 
223cdf0e10cSrcweir // -------------------------------------------------------------------------
getField(const sal_Int32 _recordNumber,const sal_Int32 _columnNumber) const224cdf0e10cSrcweir macabfield *MacabRecords::getField(const sal_Int32 _recordNumber, const sal_Int32 _columnNumber) const
225cdf0e10cSrcweir {
226cdf0e10cSrcweir     if(_recordNumber >= recordsSize)
227cdf0e10cSrcweir         return NULL;
228cdf0e10cSrcweir 
229cdf0e10cSrcweir     MacabRecord *record = records[_recordNumber];
230cdf0e10cSrcweir 
231cdf0e10cSrcweir     if(_columnNumber < 0 || _columnNumber >= record->getSize())
232cdf0e10cSrcweir         return NULL;
233cdf0e10cSrcweir 
234cdf0e10cSrcweir     return record->get(_columnNumber);
235cdf0e10cSrcweir }
236cdf0e10cSrcweir 
237cdf0e10cSrcweir // -------------------------------------------------------------------------
getField(const sal_Int32 _recordNumber,const::rtl::OUString _columnName) const238cdf0e10cSrcweir macabfield *MacabRecords::getField(const sal_Int32 _recordNumber, const ::rtl::OUString _columnName) const
239cdf0e10cSrcweir {
240cdf0e10cSrcweir     if(header != NULL)
241cdf0e10cSrcweir     {
242cdf0e10cSrcweir         sal_Int32 columnNumber = header->getColumnNumber(_columnName);
243cdf0e10cSrcweir         if(columnNumber == -1)
244cdf0e10cSrcweir             return NULL;
245cdf0e10cSrcweir 
246cdf0e10cSrcweir         return getField(_recordNumber, columnNumber);
247cdf0e10cSrcweir     }
248cdf0e10cSrcweir     else
249cdf0e10cSrcweir     {
250cdf0e10cSrcweir         // error: shouldn't access field with null header!
251cdf0e10cSrcweir         return NULL;
252cdf0e10cSrcweir     }
253cdf0e10cSrcweir }
254cdf0e10cSrcweir 
255cdf0e10cSrcweir // -------------------------------------------------------------------------
getFieldNumber(const::rtl::OUString _columnName) const256cdf0e10cSrcweir sal_Int32 MacabRecords::getFieldNumber(const ::rtl::OUString _columnName) const
257cdf0e10cSrcweir {
258cdf0e10cSrcweir     if(header != NULL)
259cdf0e10cSrcweir         return header->getColumnNumber(_columnName);
260cdf0e10cSrcweir     else
261cdf0e10cSrcweir         // error: shouldn't access field with null header!
262cdf0e10cSrcweir         return -1;
263cdf0e10cSrcweir }
264cdf0e10cSrcweir 
265cdf0e10cSrcweir // -------------------------------------------------------------------------
266cdf0e10cSrcweir /* Create the lcl_CFTypes array -- we need this because there is no
267cdf0e10cSrcweir  * way to get the ABType of an object from the object itself, and the
268cdf0e10cSrcweir  * function ABTypeOfProperty can't handle multiple levels of data
269cdf0e10cSrcweir  * (e.g., it can tell us that "address" is of type
270cdf0e10cSrcweir  * kABDictionaryProperty, but it cannot tell us that all of the keys
271cdf0e10cSrcweir  * and values in the dictionary have type kABStringProperty. On the
272cdf0e10cSrcweir  * other hand, we _can_ get the CFType out of any object.
273cdf0e10cSrcweir  * Unfortunately, all information about CFTypeIDs comes with the
274cdf0e10cSrcweir  * warning that they change between releases, so we build them
275cdf0e10cSrcweir  * ourselves here. (The one that we can't build is for multivalues,
276cdf0e10cSrcweir  * e.g., kABMultiStringProperty. All of these appear to have the
277cdf0e10cSrcweir  * same type: 1, but there is no function that I've found to give
278cdf0e10cSrcweir  * us that dynamically in case that number ever changes.
279cdf0e10cSrcweir  */
bootstrap_CF_types()280cdf0e10cSrcweir void MacabRecords::bootstrap_CF_types()
281cdf0e10cSrcweir {
282cdf0e10cSrcweir     lcl_CFTypesLength = 6;
283cdf0e10cSrcweir     lcl_CFTypes = new lcl_CFType[lcl_CFTypesLength];
284cdf0e10cSrcweir 
285cdf0e10cSrcweir     lcl_CFTypes[0].cf = CFNumberGetTypeID();
286cdf0e10cSrcweir     lcl_CFTypes[0].ab = kABIntegerProperty;
287cdf0e10cSrcweir 
288cdf0e10cSrcweir     lcl_CFTypes[1].cf = CFStringGetTypeID();
289cdf0e10cSrcweir     lcl_CFTypes[1].ab = kABStringProperty;
290cdf0e10cSrcweir 
291cdf0e10cSrcweir     lcl_CFTypes[2].cf = CFDateGetTypeID();
292cdf0e10cSrcweir     lcl_CFTypes[2].ab = kABDateProperty;
293cdf0e10cSrcweir 
294cdf0e10cSrcweir     lcl_CFTypes[3].cf = CFArrayGetTypeID();
295cdf0e10cSrcweir     lcl_CFTypes[3].ab = kABArrayProperty;
296cdf0e10cSrcweir 
297cdf0e10cSrcweir     lcl_CFTypes[4].cf = CFDictionaryGetTypeID();
298cdf0e10cSrcweir     lcl_CFTypes[4].ab = kABDictionaryProperty;
299cdf0e10cSrcweir 
300cdf0e10cSrcweir     lcl_CFTypes[5].cf = CFDataGetTypeID();
301cdf0e10cSrcweir     lcl_CFTypes[5].ab = kABDataProperty;
302cdf0e10cSrcweir }
303cdf0e10cSrcweir 
304cdf0e10cSrcweir // -------------------------------------------------------------------------
305cdf0e10cSrcweir /* This is based on the possible fields required in the mail merge template
306cdf0e10cSrcweir  * in sw. If the fields possible there change, it would be optimal to
307cdf0e10cSrcweir  * change these fields as well.
308cdf0e10cSrcweir  */
bootstrap_requiredProperties()309cdf0e10cSrcweir void MacabRecords::bootstrap_requiredProperties()
310cdf0e10cSrcweir {
311cdf0e10cSrcweir     numRequiredProperties = 7;
312cdf0e10cSrcweir     requiredProperties = new CFStringRef[numRequiredProperties];
313cdf0e10cSrcweir     requiredProperties[0] = kABTitleProperty;
314cdf0e10cSrcweir     requiredProperties[1] = kABFirstNameProperty;
315cdf0e10cSrcweir     requiredProperties[2] = kABLastNameProperty;
316cdf0e10cSrcweir     requiredProperties[3] = kABOrganizationProperty;
317cdf0e10cSrcweir     requiredProperties[4] = kABAddressProperty;
318cdf0e10cSrcweir     requiredProperties[5] = kABPhoneProperty;
319cdf0e10cSrcweir     requiredProperties[6] = kABEmailProperty;
320cdf0e10cSrcweir }
321cdf0e10cSrcweir 
322cdf0e10cSrcweir // -------------------------------------------------------------------------
323cdf0e10cSrcweir /* Create the header for a given record type and a given array of records.
324cdf0e10cSrcweir  * Because the array of records and the record type are given, if you want
325cdf0e10cSrcweir  * to, you can run this method on the members of a group, or on any other
326cdf0e10cSrcweir  * filtered list of people and get a header relevant to them (e.g., if
327cdf0e10cSrcweir  * they only have home addresses, the work address fields won't show up).
328cdf0e10cSrcweir  */
createHeaderForRecordType(const CFArrayRef _records,const CFStringRef _recordType) const329cdf0e10cSrcweir MacabHeader *MacabRecords::createHeaderForRecordType(const CFArrayRef _records, const CFStringRef _recordType) const
330cdf0e10cSrcweir {
331cdf0e10cSrcweir     /* We have two types of properties for a given record type, nonrequired
332cdf0e10cSrcweir      * and required. Required properties are ones that will show up whether
333cdf0e10cSrcweir      * or not they are empty. Nonrequired properties will only show up if
334cdf0e10cSrcweir      * at least one record in the set has that property filled. The reason
335cdf0e10cSrcweir      * is that some properties, like the kABTitleProperty are required by
336cdf0e10cSrcweir      * the mail merge wizard (in module sw) but are by default not shown in
337cdf0e10cSrcweir      * the Mac OS X address book, so they would be weeded out at this stage
338cdf0e10cSrcweir      * and not shown if they were not required.
339cdf0e10cSrcweir      *
340cdf0e10cSrcweir      * Note: with the addition of required properties, I am not sure that
341cdf0e10cSrcweir      * this method still works for kABGroupRecordType (since the required
342*152e651eSJohn Bampton      * properties are all for kABPersonRecordType).
343cdf0e10cSrcweir      *
344cdf0e10cSrcweir      * Note: required properties are constructed in the method
345cdf0e10cSrcweir      * bootstrap_requiredProperties() (above).
346cdf0e10cSrcweir      */
347cdf0e10cSrcweir     CFArrayRef allProperties = ABCopyArrayOfPropertiesForRecordType(addressBook, _recordType);
348cdf0e10cSrcweir     CFStringRef *nonRequiredProperties;
349cdf0e10cSrcweir     sal_Int32 numRecords = (sal_Int32) CFArrayGetCount(_records);
350cdf0e10cSrcweir     sal_Int32 numProperties = (sal_Int32) CFArrayGetCount(allProperties);
351cdf0e10cSrcweir     sal_Int32 numNonRequiredProperties = numProperties - numRequiredProperties;
352cdf0e10cSrcweir 
353cdf0e10cSrcweir     /* While searching through the properties for required properties, these
354cdf0e10cSrcweir      * sal_Bools will keep track of what we have found.
355cdf0e10cSrcweir      */
356cdf0e10cSrcweir     sal_Bool bFoundProperty;
357cdf0e10cSrcweir     sal_Bool bFoundRequiredProperties[numRequiredProperties];
358cdf0e10cSrcweir 
359cdf0e10cSrcweir 
360cdf0e10cSrcweir     /* We have three MacabHeaders: headerDataForProperty is where we
361cdf0e10cSrcweir      * store the result of createHeaderForProperty(), which return a
362cdf0e10cSrcweir      * MacabHeader for a single property. lcl_header is where we store
363cdf0e10cSrcweir      * the MacabHeader that we are constructing. And, nonRequiredHeader
364cdf0e10cSrcweir      * is where we construct the MacabHeader for non-required properties,
365cdf0e10cSrcweir      * so that we can sort them before adding them to lcl_header.
366cdf0e10cSrcweir      */
367cdf0e10cSrcweir     MacabHeader *headerDataForProperty;
368cdf0e10cSrcweir     MacabHeader *lcl_header = new MacabHeader();
369cdf0e10cSrcweir     MacabHeader *nonRequiredHeader = new MacabHeader();
370cdf0e10cSrcweir 
371cdf0e10cSrcweir     /* Other variables... */
372cdf0e10cSrcweir     sal_Int32 i, j, k;
373cdf0e10cSrcweir     ABRecordRef record;
374cdf0e10cSrcweir     CFStringRef property;
375cdf0e10cSrcweir 
376cdf0e10cSrcweir 
377cdf0e10cSrcweir     /* Allocate and initialize... */
378cdf0e10cSrcweir     nonRequiredProperties = new CFStringRef[numNonRequiredProperties];
379cdf0e10cSrcweir     k = 0;
380cdf0e10cSrcweir     for(i = 0; i < numRequiredProperties; i++)
381cdf0e10cSrcweir         bFoundRequiredProperties[i] = sal_False;
382cdf0e10cSrcweir 
383cdf0e10cSrcweir     /* Determine the non-required properties... */
384cdf0e10cSrcweir     for(i = 0; i < numProperties; i++)
385cdf0e10cSrcweir     {
386cdf0e10cSrcweir         property = (CFStringRef) CFArrayGetValueAtIndex(allProperties, i);
387cdf0e10cSrcweir         bFoundProperty = sal_False;
388cdf0e10cSrcweir         for(j = 0; j < numRequiredProperties; j++)
389cdf0e10cSrcweir         {
390cdf0e10cSrcweir             if(CFEqual(property, requiredProperties[j]))
391cdf0e10cSrcweir             {
392cdf0e10cSrcweir                 bFoundProperty = sal_True;
393cdf0e10cSrcweir                 bFoundRequiredProperties[j] = sal_True;
394cdf0e10cSrcweir                 break;
395cdf0e10cSrcweir             }
396cdf0e10cSrcweir         }
397cdf0e10cSrcweir 
398cdf0e10cSrcweir         if(bFoundProperty == sal_False)
399cdf0e10cSrcweir         {
400cdf0e10cSrcweir             /* If we have found too many non-required properties */
401cdf0e10cSrcweir             if(k == numNonRequiredProperties)
402cdf0e10cSrcweir             {
403cdf0e10cSrcweir                 k++; // so that the OSL_ENSURE below fails
404cdf0e10cSrcweir                 break;
405cdf0e10cSrcweir             }
406cdf0e10cSrcweir             nonRequiredProperties[k] = property;
407cdf0e10cSrcweir             k++;
408cdf0e10cSrcweir         }
409cdf0e10cSrcweir     }
410cdf0e10cSrcweir 
411cdf0e10cSrcweir     // Somehow, we got too many or too few non-requird properties...
412cdf0e10cSrcweir     // Most likely, one of the required properties no longer exists, which
413cdf0e10cSrcweir     // we also test later.
414cdf0e10cSrcweir     OSL_ENSURE(k == numNonRequiredProperties, "MacabRecords::createHeaderForRecordType: Found an unexpected number of non-required properties");
415cdf0e10cSrcweir 
416cdf0e10cSrcweir     /* Fill the header with required properties first... */
417cdf0e10cSrcweir     for(i = 0; i < numRequiredProperties; i++)
418cdf0e10cSrcweir     {
419cdf0e10cSrcweir         if(bFoundRequiredProperties[i] == sal_True)
420cdf0e10cSrcweir         {
421cdf0e10cSrcweir             /* The order of these matters (we want all address properties
422cdf0e10cSrcweir              * before any phone properties, or else things will look weird),
42351754c86SJohn Bampton              * so we get all possibilities for each property, going through
424cdf0e10cSrcweir              * each record, and then go onto the next property.
425cdf0e10cSrcweir              * (Note: the reason that we have to go through all records
426cdf0e10cSrcweir              * in the first place is that properties like address, phone, and
427cdf0e10cSrcweir              * e-mail are multi-value properties with an unknown number of
428cdf0e10cSrcweir              * values. A user could specify thirteen different kinds of
429cdf0e10cSrcweir              * e-mail addresses for one of her or his contacts, and we need to
430cdf0e10cSrcweir              * get all of them.
431cdf0e10cSrcweir              */
432cdf0e10cSrcweir             for(j = 0; j < numRecords; j++)
433cdf0e10cSrcweir             {
434cdf0e10cSrcweir                 record = (ABRecordRef) CFArrayGetValueAtIndex(_records, j);
435cdf0e10cSrcweir                 headerDataForProperty = createHeaderForProperty(record,requiredProperties[i],_recordType,sal_True);
436cdf0e10cSrcweir                 if(headerDataForProperty != NULL)
437cdf0e10cSrcweir                 {
438cdf0e10cSrcweir                     (*lcl_header) += headerDataForProperty;
439cdf0e10cSrcweir                     delete headerDataForProperty;
440cdf0e10cSrcweir                 }
441cdf0e10cSrcweir             }
442cdf0e10cSrcweir         }
443cdf0e10cSrcweir         else
444cdf0e10cSrcweir         {
445cdf0e10cSrcweir             // Couldn't find a required property...
446cdf0e10cSrcweir             OSL_ENSURE(false, ::rtl::OString("MacabRecords::createHeaderForRecordType: could not find required property: ") +
447cdf0e10cSrcweir                         ::rtl::OUStringToOString(CFStringToOUString(requiredProperties[i]), RTL_TEXTENCODING_ASCII_US));
448cdf0e10cSrcweir         }
449cdf0e10cSrcweir     }
450cdf0e10cSrcweir 
451cdf0e10cSrcweir     /* And now, non-required properties... */
452cdf0e10cSrcweir     for(i = 0; i < numRecords; i++)
453cdf0e10cSrcweir     {
454cdf0e10cSrcweir         record = (ABRecordRef) CFArrayGetValueAtIndex(_records, i);
455cdf0e10cSrcweir 
456cdf0e10cSrcweir         for(j = 0; j < numNonRequiredProperties; j++)
457cdf0e10cSrcweir         {
458cdf0e10cSrcweir             property = nonRequiredProperties[j];
459cdf0e10cSrcweir             headerDataForProperty = createHeaderForProperty(record,property,_recordType,sal_False);
460cdf0e10cSrcweir             if(headerDataForProperty != NULL)
461cdf0e10cSrcweir             {
462cdf0e10cSrcweir                 (*nonRequiredHeader) += headerDataForProperty;
463cdf0e10cSrcweir                 delete headerDataForProperty;
464cdf0e10cSrcweir             }
465cdf0e10cSrcweir         }
466cdf0e10cSrcweir 
467cdf0e10cSrcweir     }
468cdf0e10cSrcweir     nonRequiredHeader->sortRecord();
469cdf0e10cSrcweir 
470cdf0e10cSrcweir     (*lcl_header) += nonRequiredHeader;
471cdf0e10cSrcweir     delete nonRequiredHeader;
472cdf0e10cSrcweir 
473cdf0e10cSrcweir     CFRelease(allProperties);
474cdf0e10cSrcweir     delete [] nonRequiredProperties;
475cdf0e10cSrcweir 
476cdf0e10cSrcweir     return lcl_header;
477cdf0e10cSrcweir }
478cdf0e10cSrcweir 
479cdf0e10cSrcweir // -------------------------------------------------------------------------
480cdf0e10cSrcweir /* Create a header for a single property. Basically, this method gets
481cdf0e10cSrcweir  * the property's value and type and then calls another method of
482cdf0e10cSrcweir  * the same name to do the dirty work.
483cdf0e10cSrcweir  */
createHeaderForProperty(const ABRecordRef _record,const CFStringRef _propertyName,const CFStringRef _recordType,const sal_Bool _isPropertyRequired) const484cdf0e10cSrcweir MacabHeader *MacabRecords::createHeaderForProperty(const ABRecordRef _record, const CFStringRef _propertyName, const CFStringRef _recordType, const sal_Bool _isPropertyRequired) const
485cdf0e10cSrcweir {
486cdf0e10cSrcweir     // local variables
487cdf0e10cSrcweir     CFStringRef localizedPropertyName;
488cdf0e10cSrcweir     CFTypeRef propertyValue;
489cdf0e10cSrcweir     ABPropertyType propertyType;
490cdf0e10cSrcweir     MacabHeader *result;
491cdf0e10cSrcweir 
492cdf0e10cSrcweir     /* Get the property's value */
493cdf0e10cSrcweir     propertyValue = ABRecordCopyValue(_record,_propertyName);
494cdf0e10cSrcweir     if(propertyValue == NULL && _isPropertyRequired == sal_False)
495cdf0e10cSrcweir         return NULL;
496cdf0e10cSrcweir 
497cdf0e10cSrcweir     propertyType = ABTypeOfProperty(addressBook, _recordType, _propertyName);
498cdf0e10cSrcweir     localizedPropertyName = ABCopyLocalizedPropertyOrLabel(_propertyName);
499cdf0e10cSrcweir 
500cdf0e10cSrcweir     result = createHeaderForProperty(propertyType, propertyValue, localizedPropertyName);
501cdf0e10cSrcweir 
502cdf0e10cSrcweir     if(propertyValue != NULL)
503cdf0e10cSrcweir         CFRelease(propertyValue);
504cdf0e10cSrcweir 
505cdf0e10cSrcweir     return result;
506cdf0e10cSrcweir }
507cdf0e10cSrcweir 
508cdf0e10cSrcweir // -------------------------------------------------------------------------
509cdf0e10cSrcweir /* Create a header for a single property. This method is recursive
510cdf0e10cSrcweir  * because a single property might contain several sub-properties that
511cdf0e10cSrcweir  * we also want to treat singly.
512cdf0e10cSrcweir  */
createHeaderForProperty(const ABPropertyType _propertyType,const CFTypeRef _propertyValue,const CFStringRef _propertyName) const513cdf0e10cSrcweir MacabHeader *MacabRecords::createHeaderForProperty(const ABPropertyType _propertyType, const CFTypeRef _propertyValue, const CFStringRef _propertyName) const
514cdf0e10cSrcweir {
515cdf0e10cSrcweir     macabfield **headerNames = NULL;
516cdf0e10cSrcweir     sal_Int32 length = 0;
517cdf0e10cSrcweir 
518cdf0e10cSrcweir     switch(_propertyType)
519cdf0e10cSrcweir     {
520cdf0e10cSrcweir         /* Scalars */
521cdf0e10cSrcweir         case kABStringProperty:
522cdf0e10cSrcweir         case kABRealProperty:
523cdf0e10cSrcweir         case kABIntegerProperty:
524cdf0e10cSrcweir         case kABDateProperty:
525cdf0e10cSrcweir             length = 1;
526cdf0e10cSrcweir             headerNames = new macabfield *[1];
527cdf0e10cSrcweir             headerNames[0] = new macabfield;
528cdf0e10cSrcweir             headerNames[0]->value = _propertyName;
529cdf0e10cSrcweir             headerNames[0]->type = _propertyType;
530cdf0e10cSrcweir             break;
531cdf0e10cSrcweir 
532cdf0e10cSrcweir         /* Multi-scalars */
533cdf0e10cSrcweir         case kABMultiIntegerProperty:
534cdf0e10cSrcweir         case kABMultiDateProperty:
535cdf0e10cSrcweir         case kABMultiStringProperty:
536cdf0e10cSrcweir         case kABMultiRealProperty:
537cdf0e10cSrcweir         case kABMultiDataProperty:
538cdf0e10cSrcweir             /* For non-scalars, we can only get more information if the property
539cdf0e10cSrcweir              * actually exists.
540cdf0e10cSrcweir              */
541cdf0e10cSrcweir             if(_propertyValue != NULL)
542cdf0e10cSrcweir             {
543cdf0e10cSrcweir             sal_Int32 i;
544cdf0e10cSrcweir 
545cdf0e10cSrcweir             sal_Int32 multiLength = ABMultiValueCount((ABMutableMultiValueRef) _propertyValue);
546cdf0e10cSrcweir             CFStringRef multiLabel, localizedMultiLabel;
547cdf0e10cSrcweir             ::rtl::OUString multiLabelString;
548cdf0e10cSrcweir             ::rtl::OUString multiPropertyString;
549cdf0e10cSrcweir             ::rtl::OUString headerNameString;
550cdf0e10cSrcweir             ABPropertyType multiType = (ABPropertyType) (ABMultiValuePropertyType((ABMutableMultiValueRef) _propertyValue) - 0x100);
551cdf0e10cSrcweir 
552cdf0e10cSrcweir             length = multiLength;
553cdf0e10cSrcweir             headerNames = new macabfield *[multiLength];
554cdf0e10cSrcweir             multiPropertyString = CFStringToOUString(_propertyName);
555cdf0e10cSrcweir 
556cdf0e10cSrcweir             /* Go through each element, and - since each element is a scalar -
557cdf0e10cSrcweir              * just create a new macabfield for it.
558cdf0e10cSrcweir              */
559cdf0e10cSrcweir             for(i = 0; i < multiLength; i++)
560cdf0e10cSrcweir             {
561cdf0e10cSrcweir                 multiLabel = ABMultiValueCopyLabelAtIndex((ABMutableMultiValueRef) _propertyValue, i);
562cdf0e10cSrcweir                 localizedMultiLabel = ABCopyLocalizedPropertyOrLabel(multiLabel);
563cdf0e10cSrcweir                 multiLabelString = CFStringToOUString(localizedMultiLabel);
564cdf0e10cSrcweir                 CFRelease(multiLabel);
565cdf0e10cSrcweir                 CFRelease(localizedMultiLabel);
566cdf0e10cSrcweir                 headerNameString = multiPropertyString + ::rtl::OUString::createFromAscii(": ") + fixLabel(multiLabelString);
567cdf0e10cSrcweir                 headerNames[i] = new macabfield;
568cdf0e10cSrcweir                 headerNames[i]->value = OUStringToCFString(headerNameString);
569cdf0e10cSrcweir                 headerNames[i]->type = multiType;
570cdf0e10cSrcweir             }
571cdf0e10cSrcweir             }
572cdf0e10cSrcweir             break;
573cdf0e10cSrcweir 
574cdf0e10cSrcweir         /* Multi-array or dictionary */
575cdf0e10cSrcweir         case kABMultiArrayProperty:
576cdf0e10cSrcweir         case kABMultiDictionaryProperty:
577cdf0e10cSrcweir             /* For non-scalars, we can only get more information if the property
578cdf0e10cSrcweir              * actually exists.
579cdf0e10cSrcweir              */
580cdf0e10cSrcweir             if(_propertyValue != NULL)
581cdf0e10cSrcweir             {
582cdf0e10cSrcweir                 sal_Int32 i,j,k;
583cdf0e10cSrcweir 
584cdf0e10cSrcweir                 // Total number of multi-array or multi-dictionary elements.
585cdf0e10cSrcweir                 sal_Int32 multiLengthFirstLevel = ABMultiValueCount((ABMutableMultiValueRef) _propertyValue);
586cdf0e10cSrcweir 
587cdf0e10cSrcweir                 /* Total length, including the length of each element (e.g., if
588cdf0e10cSrcweir                  * this multi-dictionary contains three dictionaries, and each
589cdf0e10cSrcweir                  * dictionary has four elements, this variable will be twelve,
590cdf0e10cSrcweir                  * whereas multiLengthFirstLevel will be three.
591cdf0e10cSrcweir                  */
592cdf0e10cSrcweir                 sal_Int32 multiLengthSecondLevel = 0;
593cdf0e10cSrcweir 
594cdf0e10cSrcweir                 CFStringRef multiLabel, localizedMultiLabel;
595cdf0e10cSrcweir                 CFTypeRef multiValue;
596cdf0e10cSrcweir                 ::rtl::OUString multiLabelString;
597cdf0e10cSrcweir                 ::rtl::OUString multiPropertyString;
598cdf0e10cSrcweir                 MacabHeader **multiHeaders = new MacabHeader *[multiLengthFirstLevel];
599cdf0e10cSrcweir                 ABPropertyType multiType = (ABPropertyType) (ABMultiValuePropertyType((ABMutableMultiValueRef) _propertyValue) - 0x100);
600cdf0e10cSrcweir 
601cdf0e10cSrcweir                 multiPropertyString = CFStringToOUString(_propertyName);
602cdf0e10cSrcweir 
603cdf0e10cSrcweir                 /* Go through each element - since each element can really
604cdf0e10cSrcweir                  * contain anything, we run this method again on each element
605cdf0e10cSrcweir                  * and store the resulting MacabHeader (in the multiHeaders
606cdf0e10cSrcweir                  * array). Then, all we'll have to do is combine the MacabHeaders
607cdf0e10cSrcweir                  * into a single one.
608cdf0e10cSrcweir                  */
609cdf0e10cSrcweir                 for(i = 0; i < multiLengthFirstLevel; i++)
610cdf0e10cSrcweir                 {
611cdf0e10cSrcweir                     /* label */
612cdf0e10cSrcweir                     multiLabel = ABMultiValueCopyLabelAtIndex((ABMutableMultiValueRef) _propertyValue, i);
613cdf0e10cSrcweir                     multiValue = ABMultiValueCopyValueAtIndex((ABMutableMultiValueRef) _propertyValue, i);
614cdf0e10cSrcweir                     if(multiValue && multiLabel)
615cdf0e10cSrcweir                     {
616cdf0e10cSrcweir                         localizedMultiLabel = ABCopyLocalizedPropertyOrLabel(multiLabel);
617cdf0e10cSrcweir                         multiLabelString = multiPropertyString + ::rtl::OUString::createFromAscii(": ") + fixLabel(CFStringToOUString(localizedMultiLabel));
618cdf0e10cSrcweir                         CFRelease(multiLabel);
619cdf0e10cSrcweir                         CFRelease(localizedMultiLabel);
620cdf0e10cSrcweir                         multiLabel = OUStringToCFString(multiLabelString);
621cdf0e10cSrcweir                         multiHeaders[i] = createHeaderForProperty(multiType, multiValue, multiLabel);
622cdf0e10cSrcweir                         if (!multiHeaders[i])
623cdf0e10cSrcweir                             multiHeaders[i] = new MacabHeader();
624cdf0e10cSrcweir                         multiLengthSecondLevel += multiHeaders[i]->getSize();
625cdf0e10cSrcweir                     }
626cdf0e10cSrcweir                     else
627cdf0e10cSrcweir                     {
628cdf0e10cSrcweir                         multiHeaders[i] = new MacabHeader();
629cdf0e10cSrcweir                     }
630cdf0e10cSrcweir                     if(multiValue)
631cdf0e10cSrcweir                         CFRelease(multiValue);
632cdf0e10cSrcweir                 }
633cdf0e10cSrcweir 
634cdf0e10cSrcweir                 /* We now have enough information to create our final MacabHeader.
635cdf0e10cSrcweir                  * We go through each field of each header and add it to the
636cdf0e10cSrcweir                  * headerNames array (which is what is used below to construct
637cdf0e10cSrcweir                  * the MacabHeader we return).
638cdf0e10cSrcweir                  */
639cdf0e10cSrcweir                 length = multiLengthSecondLevel;
640cdf0e10cSrcweir                 headerNames = new macabfield *[multiLengthSecondLevel];
641cdf0e10cSrcweir 
642cdf0e10cSrcweir                 for(i = 0, j = 0, k = 0; i < multiLengthSecondLevel; i++,k++)
643cdf0e10cSrcweir                 {
644cdf0e10cSrcweir                     while(multiHeaders[j]->getSize() == k)
645cdf0e10cSrcweir                     {
646cdf0e10cSrcweir                         j++;
647cdf0e10cSrcweir                         k = 0;
648cdf0e10cSrcweir                     }
649cdf0e10cSrcweir 
650cdf0e10cSrcweir                     headerNames[i] = multiHeaders[j]->copy(k);
651cdf0e10cSrcweir                 }
652cdf0e10cSrcweir                 for(i = 0; i < multiLengthFirstLevel; i++)
653cdf0e10cSrcweir                     delete multiHeaders[i];
654cdf0e10cSrcweir 
655cdf0e10cSrcweir                 delete [] multiHeaders;
656cdf0e10cSrcweir             }
657cdf0e10cSrcweir             break;
658cdf0e10cSrcweir 
659cdf0e10cSrcweir         /* Dictionary */
660cdf0e10cSrcweir         case kABDictionaryProperty:
661cdf0e10cSrcweir             /* For non-scalars, we can only get more information if the property
662cdf0e10cSrcweir              * actually exists.
663cdf0e10cSrcweir              */
664cdf0e10cSrcweir             if(_propertyValue != NULL)
665cdf0e10cSrcweir             {
666cdf0e10cSrcweir             /* Assume all keys are strings */
667cdf0e10cSrcweir             sal_Int32 numRecords = (sal_Int32) CFDictionaryGetCount((CFDictionaryRef) _propertyValue);
668cdf0e10cSrcweir 
669cdf0e10cSrcweir             /* The only method for getting info out of a CFDictionary, of both
670cdf0e10cSrcweir              * keys and values, is to all of them all at once, so these
671cdf0e10cSrcweir              * variables will hold them.
672cdf0e10cSrcweir              */
673cdf0e10cSrcweir             CFStringRef *dictKeys;
674cdf0e10cSrcweir             CFTypeRef *dictValues;
675cdf0e10cSrcweir 
676cdf0e10cSrcweir             sal_Int32 i,j,k;
677cdf0e10cSrcweir             ::rtl::OUString dictKeyString, propertyNameString;
678cdf0e10cSrcweir             ABPropertyType dictType;
679cdf0e10cSrcweir             MacabHeader **dictHeaders = new MacabHeader *[numRecords];
680cdf0e10cSrcweir             ::rtl::OUString dictLabelString;
681cdf0e10cSrcweir             CFStringRef dictLabel, localizedDictKey;
682cdf0e10cSrcweir 
683cdf0e10cSrcweir             /* Get the keys and values */
684cdf0e10cSrcweir             dictKeys = (CFStringRef *) malloc(sizeof(CFStringRef)*numRecords);
685cdf0e10cSrcweir             dictValues = (CFTypeRef *) malloc(sizeof(CFTypeRef)*numRecords);
686cdf0e10cSrcweir             CFDictionaryGetKeysAndValues((CFDictionaryRef) _propertyValue, (const void **) dictKeys, (const void **) dictValues);
687cdf0e10cSrcweir 
688cdf0e10cSrcweir             propertyNameString = CFStringToOUString(_propertyName);
689cdf0e10cSrcweir 
690cdf0e10cSrcweir             length = 0;
691cdf0e10cSrcweir             /* Go through each element - assuming that the key is a string but
692cdf0e10cSrcweir              * that the value could be anything. Since the value could be
693cdf0e10cSrcweir              * anything, we can't assume that it is scalar (it could even be
694cdf0e10cSrcweir              * another dictionary), so we attempt to get its type using
695cdf0e10cSrcweir              * the method getABTypeFromCFType and then run this method
696cdf0e10cSrcweir              * recursively on that element, storing the MacabHeader that
697cdf0e10cSrcweir              * results. Then, we just combine all of the MacabHeaders into
698cdf0e10cSrcweir              * one.
699cdf0e10cSrcweir              */
700cdf0e10cSrcweir             for(i = 0; i < numRecords; i++)
701cdf0e10cSrcweir             {
702cdf0e10cSrcweir                 dictType = (ABPropertyType) getABTypeFromCFType( CFGetTypeID(dictValues[i]) );
703cdf0e10cSrcweir                 localizedDictKey = ABCopyLocalizedPropertyOrLabel(dictKeys[i]);
704cdf0e10cSrcweir                 dictKeyString = CFStringToOUString(localizedDictKey);
705cdf0e10cSrcweir                 dictLabelString = propertyNameString + ::rtl::OUString::createFromAscii(": ") + fixLabel(dictKeyString);
706cdf0e10cSrcweir                 dictLabel = OUStringToCFString(dictLabelString);
707cdf0e10cSrcweir                 dictHeaders[i] = createHeaderForProperty(dictType, dictValues[i], dictLabel);
708cdf0e10cSrcweir                 if (!dictHeaders[i])
709cdf0e10cSrcweir                     dictHeaders[i] = new MacabHeader();
710cdf0e10cSrcweir                 length += dictHeaders[i]->getSize();
711cdf0e10cSrcweir                 CFRelease(dictLabel);
712cdf0e10cSrcweir                 CFRelease(localizedDictKey);
713cdf0e10cSrcweir             }
714cdf0e10cSrcweir 
715cdf0e10cSrcweir             /* Combine all of the macabfields in each MacabHeader into the
716cdf0e10cSrcweir              * headerNames array, which (at the end of this method) is used
717cdf0e10cSrcweir              * to create the MacabHeader that is returned.
718cdf0e10cSrcweir              */
719cdf0e10cSrcweir             headerNames = new macabfield *[length];
720cdf0e10cSrcweir             for(i = 0, j = 0, k = 0; i < length; i++,k++)
721cdf0e10cSrcweir             {
722cdf0e10cSrcweir                 while(dictHeaders[j]->getSize() == k)
723cdf0e10cSrcweir                 {
724cdf0e10cSrcweir                     j++;
725cdf0e10cSrcweir                     k = 0;
726cdf0e10cSrcweir                 }
727cdf0e10cSrcweir 
728cdf0e10cSrcweir                 headerNames[i] = dictHeaders[j]->copy(k);
729cdf0e10cSrcweir             }
730cdf0e10cSrcweir 
731cdf0e10cSrcweir             for(i = 0; i < numRecords; i++)
732cdf0e10cSrcweir                 delete dictHeaders[i];
733cdf0e10cSrcweir 
734cdf0e10cSrcweir             delete [] dictHeaders;
735cdf0e10cSrcweir             free(dictKeys);
736cdf0e10cSrcweir             free(dictValues);
737cdf0e10cSrcweir             }
738cdf0e10cSrcweir             break;
739cdf0e10cSrcweir 
740cdf0e10cSrcweir         /* Array */
741cdf0e10cSrcweir         case kABArrayProperty:
742cdf0e10cSrcweir             /* For non-scalars, we can only get more information if the property
743cdf0e10cSrcweir              * actually exists.
744cdf0e10cSrcweir              */
745cdf0e10cSrcweir             if(_propertyValue != NULL)
746cdf0e10cSrcweir             {
747cdf0e10cSrcweir                 sal_Int32 arrLength = (sal_Int32) CFArrayGetCount( (CFArrayRef) _propertyValue);
748cdf0e10cSrcweir                 sal_Int32 i,j,k;
749cdf0e10cSrcweir                 CFTypeRef arrValue;
750cdf0e10cSrcweir                 ABPropertyType arrType;
751cdf0e10cSrcweir                 MacabHeader **arrHeaders = new MacabHeader *[arrLength];
752cdf0e10cSrcweir                 ::rtl::OUString propertyNameString = CFStringToOUString(_propertyName);
753cdf0e10cSrcweir                 ::rtl::OUString arrLabelString;
754cdf0e10cSrcweir                 CFStringRef arrLabel;
755cdf0e10cSrcweir 
756cdf0e10cSrcweir                 length = 0;
757cdf0e10cSrcweir                 /* Go through each element - since the elements here do not have
758cdf0e10cSrcweir                  * unique keys like the ones in dictionaries, we create a unique
759cdf0e10cSrcweir                  * key out of the id of the element in the array (the first
760cdf0e10cSrcweir                  * element gets a 0 plopped onto the end of it, the second a 1...
761cdf0e10cSrcweir                  * As with dictionaries, the elements could be anything, including
762cdf0e10cSrcweir                  * another array, so we have to run this method recursively on
763cdf0e10cSrcweir                  * each element, storing the resulting MacabHeader into an array,
764cdf0e10cSrcweir                  * which we then combine into one MacabHeader that is returned.
765cdf0e10cSrcweir                  */
766cdf0e10cSrcweir                 for(i = 0; i < arrLength; i++)
767cdf0e10cSrcweir                 {
768cdf0e10cSrcweir                     arrValue = (CFTypeRef) CFArrayGetValueAtIndex( (CFArrayRef) _propertyValue, i);
769cdf0e10cSrcweir                     arrType = (ABPropertyType) getABTypeFromCFType( CFGetTypeID(arrValue) );
770cdf0e10cSrcweir                     arrLabelString = propertyNameString + ::rtl::OUString::valueOf(i);
771cdf0e10cSrcweir                     arrLabel = OUStringToCFString(arrLabelString);
772cdf0e10cSrcweir                     arrHeaders[i] = createHeaderForProperty(arrType, arrValue, arrLabel);
773cdf0e10cSrcweir                     if (!arrHeaders[i])
774cdf0e10cSrcweir                         arrHeaders[i] = new MacabHeader();
775cdf0e10cSrcweir                     length += arrHeaders[i]->getSize();
776cdf0e10cSrcweir                     CFRelease(arrLabel);
777cdf0e10cSrcweir                 }
778cdf0e10cSrcweir 
779cdf0e10cSrcweir                 headerNames = new macabfield *[length];
780cdf0e10cSrcweir                 for(i = 0, j = 0, k = 0; i < length; i++,k++)
781cdf0e10cSrcweir                 {
782cdf0e10cSrcweir                     while(arrHeaders[j]->getSize() == k)
783cdf0e10cSrcweir                     {
784cdf0e10cSrcweir                         j++;
785cdf0e10cSrcweir                         k = 0;
786cdf0e10cSrcweir                     }
787cdf0e10cSrcweir 
788cdf0e10cSrcweir                     headerNames[i] = arrHeaders[j]->copy(k);
789cdf0e10cSrcweir                 }
790cdf0e10cSrcweir                 for(i = 0; i < arrLength; i++)
791cdf0e10cSrcweir                     delete arrHeaders[i];
792cdf0e10cSrcweir 
793cdf0e10cSrcweir                 delete [] arrHeaders;
794cdf0e10cSrcweir             }
795cdf0e10cSrcweir             break;
796cdf0e10cSrcweir 
797cdf0e10cSrcweir             default:
798cdf0e10cSrcweir                 break;
799cdf0e10cSrcweir 
800cdf0e10cSrcweir     }
801cdf0e10cSrcweir 
802cdf0e10cSrcweir     /* If we succeeded at adding elements to the headerNames array, then
803cdf0e10cSrcweir      * length will no longer be 0. If it is, create a new MacabHeader
804cdf0e10cSrcweir      * out of the headerNames (after weeding out duplicate headers), and
805cdf0e10cSrcweir      * then return the result. If the length is still 0, return NULL: we
806cdf0e10cSrcweir      * failed to create a MacabHeader out of this property.
807cdf0e10cSrcweir      */
808cdf0e10cSrcweir     if(length != 0)
809cdf0e10cSrcweir     {
810cdf0e10cSrcweir         manageDuplicateHeaders(headerNames, length);
811cdf0e10cSrcweir         MacabHeader *headerResult = new MacabHeader(length, headerNames);
812cdf0e10cSrcweir         delete [] headerNames;
813cdf0e10cSrcweir         return headerResult;
814cdf0e10cSrcweir     }
815cdf0e10cSrcweir     else
816cdf0e10cSrcweir         return NULL;
817cdf0e10cSrcweir }
818cdf0e10cSrcweir 
819cdf0e10cSrcweir // -------------------------------------------------------------------------
manageDuplicateHeaders(macabfield ** _headerNames,const sal_Int32 _length) const820cdf0e10cSrcweir void MacabRecords::manageDuplicateHeaders(macabfield **_headerNames, const sal_Int32 _length) const
821cdf0e10cSrcweir {
822cdf0e10cSrcweir     /* If we have two cases of, say, phone: home, this makes it:
823cdf0e10cSrcweir      * phone: home (1)
824cdf0e10cSrcweir      * phone: home (2)
825cdf0e10cSrcweir      */
826cdf0e10cSrcweir     sal_Int32 i, j;
827cdf0e10cSrcweir     sal_Int32 count;
828cdf0e10cSrcweir     for(i = _length-1; i >= 0; i--)
829cdf0e10cSrcweir     {
830cdf0e10cSrcweir         count = 1;
831cdf0e10cSrcweir         for( j = i-1; j >= 0; j--)
832cdf0e10cSrcweir         {
833cdf0e10cSrcweir             if(CFEqual(_headerNames[i]->value, _headerNames[j]->value))
834cdf0e10cSrcweir             {
835cdf0e10cSrcweir                 count++;
836cdf0e10cSrcweir             }
837cdf0e10cSrcweir         }
838cdf0e10cSrcweir 
839cdf0e10cSrcweir         // duplicate!
840cdf0e10cSrcweir         if(count != 1)
841cdf0e10cSrcweir         {
842cdf0e10cSrcweir             // There is probably a better way to do this...
843cdf0e10cSrcweir             ::rtl::OUString newName = CFStringToOUString((CFStringRef) _headerNames[i]->value);
844cdf0e10cSrcweir             CFRelease(_headerNames[i]->value);
845cdf0e10cSrcweir             newName += ::rtl::OUString::createFromAscii(" (") + ::rtl::OUString::valueOf(count) + ::rtl::OUString::createFromAscii(")");
846cdf0e10cSrcweir             _headerNames[i]->value = OUStringToCFString(newName);
847cdf0e10cSrcweir         }
848cdf0e10cSrcweir     }
849cdf0e10cSrcweir }
850cdf0e10cSrcweir 
851cdf0e10cSrcweir // -------------------------------------------------------------------------
852cdf0e10cSrcweir /* Create a MacabRecord out of an ABRecord, using a given MacabHeader and
853cdf0e10cSrcweir  * the record's type. We go through each property for this record type
854cdf0e10cSrcweir  * then process it much like we processed the header (above), with two
855cdf0e10cSrcweir  * exceptions: if we come upon something not in the header, we ignore it
856cdf0e10cSrcweir  * (it's something we don't want to add), and once we find a corresponding
857cdf0e10cSrcweir  * location in the header, we store the property and the property type in
858cdf0e10cSrcweir  * a macabfield. (For the header, we stored the property type and the name
859cdf0e10cSrcweir  * of the property as a CFString.)
860cdf0e10cSrcweir  */
createMacabRecord(const ABRecordRef _abrecord,const MacabHeader * _header,const CFStringRef _recordType) const861cdf0e10cSrcweir MacabRecord *MacabRecords::createMacabRecord(const ABRecordRef _abrecord, const MacabHeader *_header, const CFStringRef _recordType) const
862cdf0e10cSrcweir {
863cdf0e10cSrcweir     /* The new record that we will create... */
864cdf0e10cSrcweir     MacabRecord *macabRecord = new MacabRecord(_header->getSize());
865cdf0e10cSrcweir 
866cdf0e10cSrcweir     CFArrayRef recordProperties = ABCopyArrayOfPropertiesForRecordType(addressBook, _recordType);
867cdf0e10cSrcweir     sal_Int32 numProperties = (sal_Int32) CFArrayGetCount(recordProperties);
868cdf0e10cSrcweir 
869cdf0e10cSrcweir     sal_Int32 i;
870cdf0e10cSrcweir 
871cdf0e10cSrcweir     CFTypeRef propertyValue;
872cdf0e10cSrcweir     ABPropertyType propertyType;
873cdf0e10cSrcweir 
874cdf0e10cSrcweir     CFStringRef propertyName, localizedPropertyName;
875cdf0e10cSrcweir     ::rtl::OUString propertyNameString;
876cdf0e10cSrcweir     for(i = 0; i < numProperties; i++)
877cdf0e10cSrcweir     {
878cdf0e10cSrcweir         propertyName = (CFStringRef) CFArrayGetValueAtIndex(recordProperties, i);
879cdf0e10cSrcweir         localizedPropertyName = ABCopyLocalizedPropertyOrLabel(propertyName);
880cdf0e10cSrcweir         propertyNameString = CFStringToOUString(localizedPropertyName);
881cdf0e10cSrcweir         CFRelease(localizedPropertyName);
882cdf0e10cSrcweir 
883cdf0e10cSrcweir         /* Get the property's value */
884cdf0e10cSrcweir         propertyValue = ABRecordCopyValue(_abrecord,propertyName);
885cdf0e10cSrcweir         if(propertyValue != NULL)
886cdf0e10cSrcweir         {
887cdf0e10cSrcweir             propertyType = ABTypeOfProperty(addressBook, _recordType, propertyName);
888cdf0e10cSrcweir             if(propertyType != kABErrorInProperty)
889cdf0e10cSrcweir                 insertPropertyIntoMacabRecord(propertyType, macabRecord, _header, propertyNameString, propertyValue);
890cdf0e10cSrcweir 
891cdf0e10cSrcweir             CFRelease(propertyValue);
892cdf0e10cSrcweir         }
893cdf0e10cSrcweir     }
894cdf0e10cSrcweir     CFRelease(recordProperties);
895cdf0e10cSrcweir     return macabRecord;
896cdf0e10cSrcweir }
897cdf0e10cSrcweir 
898cdf0e10cSrcweir // -------------------------------------------------------------------------
899cdf0e10cSrcweir /* Inserts a given property into a MacabRecord. This method calls another
900cdf0e10cSrcweir  * method by the same name after getting the property type (it only
901cdf0e10cSrcweir  * receives the property value). It is called when we aren't given the
902cdf0e10cSrcweir  * property's type already.
903cdf0e10cSrcweir  */
insertPropertyIntoMacabRecord(MacabRecord * _abrecord,const MacabHeader * _header,const::rtl::OUString _propertyName,const CFTypeRef _propertyValue) const904cdf0e10cSrcweir void MacabRecords::insertPropertyIntoMacabRecord(MacabRecord *_abrecord, const MacabHeader *_header, const ::rtl::OUString _propertyName, const CFTypeRef _propertyValue) const
905cdf0e10cSrcweir {
906cdf0e10cSrcweir     CFTypeID cf_type = CFGetTypeID(_propertyValue);
907cdf0e10cSrcweir     ABPropertyType ab_type = getABTypeFromCFType( cf_type );
908cdf0e10cSrcweir 
909cdf0e10cSrcweir     if(ab_type != kABErrorInProperty)
910cdf0e10cSrcweir         insertPropertyIntoMacabRecord(ab_type, _abrecord, _header, _propertyName, _propertyValue);
911cdf0e10cSrcweir }
912cdf0e10cSrcweir 
913cdf0e10cSrcweir // -------------------------------------------------------------------------
914cdf0e10cSrcweir /* Inserts a given property into a MacabRecord. This method is recursive
915cdf0e10cSrcweir  * because properties can contain many sub-properties.
916cdf0e10cSrcweir  */
insertPropertyIntoMacabRecord(const ABPropertyType _propertyType,MacabRecord * _abrecord,const MacabHeader * _header,const::rtl::OUString _propertyName,const CFTypeRef _propertyValue) const917cdf0e10cSrcweir void MacabRecords::insertPropertyIntoMacabRecord(const ABPropertyType _propertyType, MacabRecord *_abrecord, const MacabHeader *_header, const ::rtl::OUString _propertyName, const CFTypeRef _propertyValue) const
918cdf0e10cSrcweir {
919cdf0e10cSrcweir     /* If there is no value, return */
920cdf0e10cSrcweir     if(_propertyValue == NULL)
921cdf0e10cSrcweir         return;
922cdf0e10cSrcweir 
923cdf0e10cSrcweir     /* The main switch statement */
924cdf0e10cSrcweir     switch(_propertyType)
925cdf0e10cSrcweir     {
926cdf0e10cSrcweir         /* Scalars */
927cdf0e10cSrcweir         case kABStringProperty:
928cdf0e10cSrcweir         case kABRealProperty:
929cdf0e10cSrcweir         case kABIntegerProperty:
930cdf0e10cSrcweir         case kABDateProperty:
931cdf0e10cSrcweir         {
932cdf0e10cSrcweir             /* Only scalars actually insert a property into the MacabRecord.
933cdf0e10cSrcweir              * In all other cases, this method is called recursively until a
934cdf0e10cSrcweir              * scalar type, an error, or an unknown type are found.
935cdf0e10cSrcweir              * Because of that, the following checks only occur for this type.
936cdf0e10cSrcweir              * We store whether we have successfully placed this property
93707a3d7f1SPedro Giffuni              * into the MacabRecord (or whether an unrecoverable error occurred).
938cdf0e10cSrcweir              * Then, we try over and over again to place the property into the
939cdf0e10cSrcweir              * record. There are three possible results:
940cdf0e10cSrcweir              * 1) Success!
941cdf0e10cSrcweir              * 2) There is already a property stored at the column of this name,
942cdf0e10cSrcweir              * in which case we have a duplicate header (see the method
943cdf0e10cSrcweir              * manageDuplicateHeaders()). If that is the case, we add an ID
944cdf0e10cSrcweir              * to the end of the column name in the same format as we do in
945cdf0e10cSrcweir              * manageDuplicateHeaders() and try again.
946cdf0e10cSrcweir              * 3) No column of this name exists in the header. In this case,
947cdf0e10cSrcweir              * there is nothing we can do: we have failed to place this
948cdf0e10cSrcweir              * property into the record.
949cdf0e10cSrcweir              */
950cdf0e10cSrcweir             sal_Bool bPlaced = sal_False;
951cdf0e10cSrcweir             ::rtl::OUString columnName = ::rtl::OUString(_propertyName);
952cdf0e10cSrcweir             sal_Int32 i = 1;
953cdf0e10cSrcweir 
954cdf0e10cSrcweir             // A big safeguard to prevent two fields from having the same name.
955cdf0e10cSrcweir             while(bPlaced != sal_True)
956cdf0e10cSrcweir             {
957cdf0e10cSrcweir                 sal_Int32 columnNumber = _header->getColumnNumber(columnName);
958cdf0e10cSrcweir                 bPlaced = sal_True;
959cdf0e10cSrcweir                 if(columnNumber != -1)
960cdf0e10cSrcweir                 {
961cdf0e10cSrcweir                     // collision! A property already exists here!
962cdf0e10cSrcweir                     if(_abrecord->get(columnNumber) != NULL)
963cdf0e10cSrcweir                     {
964cdf0e10cSrcweir                         bPlaced = sal_False;
965cdf0e10cSrcweir                         i++;
966cdf0e10cSrcweir                         columnName = ::rtl::OUString(_propertyName) + ::rtl::OUString::createFromAscii(" (") + ::rtl::OUString::valueOf(i) + ::rtl::OUString::createFromAscii(")");
967cdf0e10cSrcweir                     }
968cdf0e10cSrcweir 
969cdf0e10cSrcweir                     // success!
970cdf0e10cSrcweir                     else
971cdf0e10cSrcweir                     {
972cdf0e10cSrcweir                         _abrecord->insertAtColumn(_propertyValue, _propertyType, columnNumber);
973cdf0e10cSrcweir                     }
974cdf0e10cSrcweir                 }
975cdf0e10cSrcweir             }
976cdf0e10cSrcweir         }
977cdf0e10cSrcweir         break;
978cdf0e10cSrcweir 
979cdf0e10cSrcweir         /* Array */
980cdf0e10cSrcweir         case kABArrayProperty:
981cdf0e10cSrcweir             {
982cdf0e10cSrcweir                 /* An array is basically just a list of anything, so all we do
983cdf0e10cSrcweir                  * is go through the array, and rerun this method recursively
984cdf0e10cSrcweir                  * on each element.
985cdf0e10cSrcweir                  */
986cdf0e10cSrcweir                 sal_Int32 arrLength = (sal_Int32) CFArrayGetCount( (CFArrayRef) _propertyValue);
987cdf0e10cSrcweir                 sal_Int32 i;
988cdf0e10cSrcweir                 const void *arrValue;
989cdf0e10cSrcweir                 ::rtl::OUString newPropertyName;
990cdf0e10cSrcweir 
991cdf0e10cSrcweir                 /* Going through each element... */
992cdf0e10cSrcweir                 for(i = 0; i < arrLength; i++)
993cdf0e10cSrcweir                 {
994cdf0e10cSrcweir                     arrValue = CFArrayGetValueAtIndex( (CFArrayRef) _propertyValue, i);
995cdf0e10cSrcweir                     newPropertyName = _propertyName + ::rtl::OUString::valueOf(i);
996cdf0e10cSrcweir                     insertPropertyIntoMacabRecord(_abrecord, _header, newPropertyName, arrValue);
997cdf0e10cSrcweir                     CFRelease(arrValue);
998cdf0e10cSrcweir                 }
999cdf0e10cSrcweir 
1000cdf0e10cSrcweir             }
1001cdf0e10cSrcweir             break;
1002cdf0e10cSrcweir 
1003cdf0e10cSrcweir         /* Dictionary */
1004cdf0e10cSrcweir         case kABDictionaryProperty:
1005cdf0e10cSrcweir             {
1006cdf0e10cSrcweir                 /* A dictionary is basically a hashmap. Technically, it can
1007cdf0e10cSrcweir                  * hold any object as a key and any object as a value.
1008cdf0e10cSrcweir                  * For our case, we assume that the key is a string (so that
1009cdf0e10cSrcweir                  * we can use the key to get the column name and match it against
1010cdf0e10cSrcweir                  * the header), but we don't assume anything about the value, so
1011cdf0e10cSrcweir                  * we run this method recursively (or, rather, we run the version
1012cdf0e10cSrcweir                  * of this method for when we don't know the object's type) until
1013cdf0e10cSrcweir                  * we hit a scalar value.
1014cdf0e10cSrcweir                  */
1015cdf0e10cSrcweir 
1016cdf0e10cSrcweir                 sal_Int32 numRecords = (sal_Int32) CFDictionaryGetCount((CFDictionaryRef) _propertyValue);
1017cdf0e10cSrcweir                 ::rtl::OUString dictKeyString;
1018cdf0e10cSrcweir                 sal_Int32 i;
1019cdf0e10cSrcweir                 ::rtl::OUString newPropertyName;
1020cdf0e10cSrcweir 
1021cdf0e10cSrcweir                 /* Unfortunately, the only way to get both keys and values out
1022cdf0e10cSrcweir                  * of a dictionary in Carbon is to get them all at once, so we
1023cdf0e10cSrcweir                  * do that.
1024cdf0e10cSrcweir                  */
1025cdf0e10cSrcweir                 CFStringRef *dictKeys;
1026cdf0e10cSrcweir                 CFStringRef localizedDictKey;
1027cdf0e10cSrcweir                 CFTypeRef *dictValues;
1028cdf0e10cSrcweir                 dictKeys = (CFStringRef *) malloc(sizeof(CFStringRef)*numRecords);
1029cdf0e10cSrcweir                 dictValues = (CFTypeRef *) malloc(sizeof(CFTypeRef)*numRecords);
1030cdf0e10cSrcweir                 CFDictionaryGetKeysAndValues((CFDictionaryRef) _propertyValue, (const void **) dictKeys, (const void **) dictValues);
1031cdf0e10cSrcweir 
1032cdf0e10cSrcweir                 /* Going through each element... */
1033cdf0e10cSrcweir                 for(i = 0; i < numRecords; i++)
1034cdf0e10cSrcweir                 {
1035cdf0e10cSrcweir                     localizedDictKey = ABCopyLocalizedPropertyOrLabel(dictKeys[i]);
1036cdf0e10cSrcweir                     dictKeyString = CFStringToOUString(localizedDictKey);
1037cdf0e10cSrcweir                     CFRelease(localizedDictKey);
1038cdf0e10cSrcweir                     newPropertyName = _propertyName + ::rtl::OUString::createFromAscii(": ") + fixLabel(dictKeyString);
1039cdf0e10cSrcweir                     insertPropertyIntoMacabRecord(_abrecord, _header, newPropertyName, dictValues[i]);
1040cdf0e10cSrcweir                 }
1041cdf0e10cSrcweir 
1042cdf0e10cSrcweir                 free(dictKeys);
1043cdf0e10cSrcweir                 free(dictValues);
1044cdf0e10cSrcweir             }
1045cdf0e10cSrcweir             break;
1046cdf0e10cSrcweir 
1047cdf0e10cSrcweir         /* Multivalue */
1048cdf0e10cSrcweir         case kABMultiIntegerProperty:
1049cdf0e10cSrcweir         case kABMultiDateProperty:
1050cdf0e10cSrcweir         case kABMultiStringProperty:
1051cdf0e10cSrcweir         case kABMultiRealProperty:
1052cdf0e10cSrcweir         case kABMultiDataProperty:
1053cdf0e10cSrcweir         case kABMultiDictionaryProperty:
1054cdf0e10cSrcweir         case kABMultiArrayProperty:
1055cdf0e10cSrcweir             {
1056cdf0e10cSrcweir                 /* All scalar multivalues are handled in the same way. Each element
1057cdf0e10cSrcweir                  * is a label and a value. All labels are strings
1058cdf0e10cSrcweir                  * (kABStringProperty), and all values have the same type
1059cdf0e10cSrcweir                  * (which is the type of the multivalue minus 255, or as
1060cdf0e10cSrcweir                  * Carbon's list of property types has it, minus 0x100.
1061cdf0e10cSrcweir                  * We just get the correct type, then go through each element
1062cdf0e10cSrcweir                  * and get the label and value and print them in a list.
1063cdf0e10cSrcweir                  */
1064cdf0e10cSrcweir 
1065cdf0e10cSrcweir                 sal_Int32 i;
1066cdf0e10cSrcweir                 sal_Int32 multiLength = ABMultiValueCount((ABMutableMultiValueRef) _propertyValue);
1067cdf0e10cSrcweir                 CFStringRef multiLabel, localizedMultiLabel;
1068cdf0e10cSrcweir                 CFTypeRef multiValue;
1069cdf0e10cSrcweir                 ::rtl::OUString multiLabelString, newPropertyName;
1070cdf0e10cSrcweir                 ABPropertyType multiType = (ABPropertyType) (ABMultiValuePropertyType((ABMutableMultiValueRef) _propertyValue) - 0x100);
1071cdf0e10cSrcweir 
1072cdf0e10cSrcweir                 /* Go through each element... */
1073cdf0e10cSrcweir                 for(i = 0; i < multiLength; i++)
1074cdf0e10cSrcweir                 {
1075cdf0e10cSrcweir                     /* Label and value */
1076cdf0e10cSrcweir                     multiLabel = ABMultiValueCopyLabelAtIndex((ABMutableMultiValueRef) _propertyValue, i);
1077cdf0e10cSrcweir                     multiValue = ABMultiValueCopyValueAtIndex((ABMutableMultiValueRef) _propertyValue, i);
1078cdf0e10cSrcweir 
1079cdf0e10cSrcweir                     localizedMultiLabel = ABCopyLocalizedPropertyOrLabel(multiLabel);
1080cdf0e10cSrcweir                     multiLabelString = CFStringToOUString(localizedMultiLabel);
1081cdf0e10cSrcweir                     newPropertyName = _propertyName + ::rtl::OUString::createFromAscii(": ") + fixLabel(multiLabelString);
1082cdf0e10cSrcweir                     insertPropertyIntoMacabRecord(multiType, _abrecord, _header, newPropertyName, multiValue);
1083cdf0e10cSrcweir 
1084cdf0e10cSrcweir                     /* free our variables */
1085cdf0e10cSrcweir                     CFRelease(multiLabel);
1086cdf0e10cSrcweir                     CFRelease(localizedMultiLabel);
1087cdf0e10cSrcweir                     CFRelease(multiValue);
1088cdf0e10cSrcweir                 }
1089cdf0e10cSrcweir             }
1090cdf0e10cSrcweir             break;
1091cdf0e10cSrcweir 
1092cdf0e10cSrcweir         /* Unhandled types */
1093cdf0e10cSrcweir         case kABErrorInProperty:
1094cdf0e10cSrcweir         case kABDataProperty:
1095cdf0e10cSrcweir         default:
1096cdf0e10cSrcweir             /* An error, as far as I have seen, only shows up as a type
1097cdf0e10cSrcweir              * returned by a function for dictionaries when the dictionary
1098cdf0e10cSrcweir              * holds many types of values. Since we do not use that function,
1099cdf0e10cSrcweir              * it shouldn't come up. I have yet to see the kABDataProperty,
1100cdf0e10cSrcweir              * and I am not sure how to represent it as a string anyway,
1101cdf0e10cSrcweir              * since it appears to just be a bunch of bytes. Assumably, if
1102cdf0e10cSrcweir              * these bytes made up a string, the type would be
1103cdf0e10cSrcweir              * kABStringProperty. I think that this is used when we are not
1104cdf0e10cSrcweir              * sure what the type is (e.g., it could be a string or a number).
1105cdf0e10cSrcweir              * That being the case, I still don't know how to represent it.
1106cdf0e10cSrcweir              * And, default should never come up, since we've exhausted all
1107cdf0e10cSrcweir              * of the possible types for ABPropertyType, but... just in case.
1108cdf0e10cSrcweir              */
1109cdf0e10cSrcweir             break;
1110cdf0e10cSrcweir     }
1111cdf0e10cSrcweir 
1112cdf0e10cSrcweir }
1113cdf0e10cSrcweir 
1114cdf0e10cSrcweir // -------------------------------------------------------------------------
getABTypeFromCFType(const CFTypeID cf_type) const1115cdf0e10cSrcweir ABPropertyType MacabRecords::getABTypeFromCFType(const CFTypeID cf_type ) const
1116cdf0e10cSrcweir {
1117cdf0e10cSrcweir     sal_Int32 i;
1118cdf0e10cSrcweir     for(i = 0; i < lcl_CFTypesLength; i++)
1119cdf0e10cSrcweir     {
1120cdf0e10cSrcweir         /* A match! */
1121cdf0e10cSrcweir         if(lcl_CFTypes[i].cf == (sal_Int32) cf_type)
1122cdf0e10cSrcweir         {
1123cdf0e10cSrcweir             return (ABPropertyType) lcl_CFTypes[i].ab;
1124cdf0e10cSrcweir         }
1125cdf0e10cSrcweir     }
1126cdf0e10cSrcweir     return kABErrorInProperty;
1127cdf0e10cSrcweir }
1128cdf0e10cSrcweir 
1129cdf0e10cSrcweir // -------------------------------------------------------------------------
size() const1130cdf0e10cSrcweir sal_Int32 MacabRecords::size() const
1131cdf0e10cSrcweir {
1132cdf0e10cSrcweir     return currentRecord;
1133cdf0e10cSrcweir }
1134cdf0e10cSrcweir 
1135cdf0e10cSrcweir // -------------------------------------------------------------------------
begin()1136cdf0e10cSrcweir MacabRecords *MacabRecords::begin()
1137cdf0e10cSrcweir {
1138cdf0e10cSrcweir     return this;
1139cdf0e10cSrcweir }
1140cdf0e10cSrcweir 
1141cdf0e10cSrcweir // -------------------------------------------------------------------------
iterator()1142cdf0e10cSrcweir MacabRecords::iterator::iterator ()
1143cdf0e10cSrcweir {
1144cdf0e10cSrcweir }
1145cdf0e10cSrcweir 
1146cdf0e10cSrcweir // -------------------------------------------------------------------------
~iterator()1147cdf0e10cSrcweir MacabRecords::iterator::~iterator ()
1148cdf0e10cSrcweir {
1149cdf0e10cSrcweir }
1150cdf0e10cSrcweir 
1151cdf0e10cSrcweir // -------------------------------------------------------------------------
operator =(MacabRecords * _records)1152cdf0e10cSrcweir void MacabRecords::iterator::operator= (MacabRecords *_records)
1153cdf0e10cSrcweir {
1154cdf0e10cSrcweir     id = 0;
1155cdf0e10cSrcweir     records = _records;
1156cdf0e10cSrcweir }
1157cdf0e10cSrcweir 
1158cdf0e10cSrcweir // -------------------------------------------------------------------------
operator ++()1159cdf0e10cSrcweir void MacabRecords::iterator::operator++ ()
1160cdf0e10cSrcweir {
1161cdf0e10cSrcweir     id++;
1162cdf0e10cSrcweir }
1163cdf0e10cSrcweir 
1164cdf0e10cSrcweir // -------------------------------------------------------------------------
operator !=(const sal_Int32 i) const1165cdf0e10cSrcweir sal_Bool MacabRecords::iterator::operator!= (const sal_Int32 i) const
1166cdf0e10cSrcweir {
1167cdf0e10cSrcweir     return(id != i);
1168cdf0e10cSrcweir }
1169cdf0e10cSrcweir 
1170cdf0e10cSrcweir // -------------------------------------------------------------------------
operator ==(const sal_Int32 i) const1171cdf0e10cSrcweir sal_Bool MacabRecords::iterator::operator== (const sal_Int32 i) const
1172cdf0e10cSrcweir {
1173cdf0e10cSrcweir     return(id == i);
1174cdf0e10cSrcweir }
1175cdf0e10cSrcweir 
1176cdf0e10cSrcweir // -------------------------------------------------------------------------
operator *() const1177cdf0e10cSrcweir MacabRecord *MacabRecords::iterator::operator* () const
1178cdf0e10cSrcweir {
1179cdf0e10cSrcweir     return records->getRecord(id);
1180cdf0e10cSrcweir }
1181cdf0e10cSrcweir 
1182cdf0e10cSrcweir // -------------------------------------------------------------------------
end() const1183cdf0e10cSrcweir sal_Int32 MacabRecords::end() const
1184cdf0e10cSrcweir {
1185cdf0e10cSrcweir     return currentRecord;
1186cdf0e10cSrcweir }
1187cdf0e10cSrcweir 
1188cdf0e10cSrcweir // -------------------------------------------------------------------------
swap(const sal_Int32 _id1,const sal_Int32 _id2)1189cdf0e10cSrcweir void MacabRecords::swap(const sal_Int32 _id1, const sal_Int32 _id2)
1190cdf0e10cSrcweir {
1191cdf0e10cSrcweir     MacabRecord *swapRecord = records[_id1];
1192cdf0e10cSrcweir 
1193cdf0e10cSrcweir     records[_id1] = records[_id2];
1194cdf0e10cSrcweir     records[_id2] = swapRecord;
1195cdf0e10cSrcweir }
1196cdf0e10cSrcweir 
1197cdf0e10cSrcweir // -------------------------------------------------------------------------
setName(const::rtl::OUString _sName)1198cdf0e10cSrcweir void MacabRecords::setName(const ::rtl::OUString _sName)
1199cdf0e10cSrcweir {
1200cdf0e10cSrcweir     m_sName = _sName;
1201cdf0e10cSrcweir }
1202cdf0e10cSrcweir 
1203cdf0e10cSrcweir // -------------------------------------------------------------------------
getName() const1204cdf0e10cSrcweir ::rtl::OUString MacabRecords::getName() const
1205cdf0e10cSrcweir {
1206cdf0e10cSrcweir     return m_sName;
1207cdf0e10cSrcweir }
1208