summaryrefslogtreecommitdiffstats
path: root/connectivity/source/drivers/macab
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /connectivity/source/drivers/macab
parentInitial commit. (diff)
downloadlibreoffice-upstream/4%7.4.7.tar.xz
libreoffice-upstream/4%7.4.7.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'connectivity/source/drivers/macab')
-rw-r--r--connectivity/source/drivers/macab/MacabAddressBook.cxx249
-rw-r--r--connectivity/source/drivers/macab/MacabAddressBook.hxx60
-rw-r--r--connectivity/source/drivers/macab/MacabCatalog.cxx112
-rw-r--r--connectivity/source/drivers/macab/MacabCatalog.hxx51
-rw-r--r--connectivity/source/drivers/macab/MacabColumns.cxx94
-rw-r--r--connectivity/source/drivers/macab/MacabColumns.hxx42
-rw-r--r--connectivity/source/drivers/macab/MacabConnection.cxx316
-rw-r--r--connectivity/source/drivers/macab/MacabConnection.hxx110
-rw-r--r--connectivity/source/drivers/macab/MacabDatabaseMetaData.cxx1073
-rw-r--r--connectivity/source/drivers/macab/MacabDatabaseMetaData.hxx195
-rw-r--r--connectivity/source/drivers/macab/MacabDriver.cxx310
-rw-r--r--connectivity/source/drivers/macab/MacabDriver.hxx161
-rw-r--r--connectivity/source/drivers/macab/MacabGroup.cxx93
-rw-r--r--connectivity/source/drivers/macab/MacabGroup.hxx38
-rw-r--r--connectivity/source/drivers/macab/MacabHeader.cxx330
-rw-r--r--connectivity/source/drivers/macab/MacabHeader.hxx61
-rw-r--r--connectivity/source/drivers/macab/MacabPreparedStatement.cxx343
-rw-r--r--connectivity/source/drivers/macab/MacabPreparedStatement.hxx111
-rw-r--r--connectivity/source/drivers/macab/MacabRecord.cxx336
-rw-r--r--connectivity/source/drivers/macab/MacabRecord.hxx71
-rw-r--r--connectivity/source/drivers/macab/MacabRecords.cxx1160
-rw-r--r--connectivity/source/drivers/macab/MacabRecords.hxx125
-rw-r--r--connectivity/source/drivers/macab/MacabResultSet.cxx1094
-rw-r--r--connectivity/source/drivers/macab/MacabResultSet.hxx213
-rw-r--r--connectivity/source/drivers/macab/MacabResultSetMetaData.cxx216
-rw-r--r--connectivity/source/drivers/macab/MacabResultSetMetaData.hxx80
-rw-r--r--connectivity/source/drivers/macab/MacabStatement.cxx631
-rw-r--r--connectivity/source/drivers/macab/MacabStatement.hxx169
-rw-r--r--connectivity/source/drivers/macab/MacabTable.cxx86
-rw-r--r--connectivity/source/drivers/macab/MacabTable.hxx54
-rw-r--r--connectivity/source/drivers/macab/MacabTables.cxx80
-rw-r--r--connectivity/source/drivers/macab/MacabTables.hxx49
-rw-r--r--connectivity/source/drivers/macab/macab1.component26
-rw-r--r--connectivity/source/drivers/macab/macabcondition.cxx244
-rw-r--r--connectivity/source/drivers/macab/macabcondition.hxx165
-rw-r--r--connectivity/source/drivers/macab/macaborder.cxx75
-rw-r--r--connectivity/source/drivers/macab/macaborder.hxx64
-rw-r--r--connectivity/source/drivers/macab/macabutilities.hxx138
38 files changed, 8825 insertions, 0 deletions
diff --git a/connectivity/source/drivers/macab/MacabAddressBook.cxx b/connectivity/source/drivers/macab/MacabAddressBook.cxx
new file mode 100644
index 000000000..02d4faf74
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabAddressBook.cxx
@@ -0,0 +1,249 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabAddressBook.hxx"
+#include "MacabRecords.hxx"
+#include "MacabGroup.hxx"
+
+#include <vector>
+
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <AddressBook/ABAddressBookC.h>
+#include <postmac.h>
+#include <connectivity/CommonTools.hxx>
+
+using namespace connectivity::macab;
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+void manageDuplicateGroups(std::vector<MacabGroup *> _xGroups)
+{
+ /* If we have two cases of groups, say, family, this makes it:
+ * family
+ * family (2)
+ */
+ std::vector<MacabGroup *>::reverse_iterator iter1, iter2;
+ sal_Int32 count;
+
+ for(iter1 = _xGroups.rbegin(); iter1 != _xGroups.rend(); ++iter1)
+ {
+ /* If the name matches the default table name, there is already
+ * (obviously) a conflict. So, start the count of groups with this
+ * name at 2 instead of 1.
+ */
+ if( (*iter1)->getName() == MacabAddressBook::getDefaultTableName() )
+ count = 2;
+ else
+ count = 1;
+
+ iter2 = iter1;
+ for( ++iter2; iter2 != _xGroups.rend(); ++iter2)
+ {
+ if( (*iter1)->getName() == (*iter2)->getName() )
+ {
+ count++;
+ }
+ }
+
+ // duplicate!
+ if(count != 1)
+ {
+ OUString sName = (*iter1)->getName() + " (" +
+ OUString::number(count) +
+ ")";
+ (*iter1)->setName(sName);
+ }
+ }
+}
+
+}
+
+MacabAddressBook::MacabAddressBook( )
+ : m_aAddressBook(ABGetSharedAddressBook()),
+ m_xMacabRecords(nullptr),
+ m_bRetrievedGroups(false)
+{
+ if(m_aAddressBook == nullptr)
+ {
+ // TODO: tell the user to reset the permission via "tccutil reset AddressBook"
+ // or the system preferences and try again, this time granting the access
+ throw RuntimeException(
+ "failed to access the macOS address book - permission not granted?" );
+ }
+}
+
+
+MacabAddressBook::~MacabAddressBook()
+{
+ if(m_xMacabRecords != nullptr)
+ {
+ delete m_xMacabRecords;
+ m_xMacabRecords = nullptr;
+ }
+
+ for(MacabGroup* pMacabGroup : m_xMacabGroups)
+ delete pMacabGroup;
+
+ m_bRetrievedGroups = false;
+}
+
+
+/* Get the address book's default table name. This is the table name that
+ * refers to the table containing _all_ records in the address book.
+ */
+const OUString & MacabAddressBook::getDefaultTableName()
+{
+ /* This string probably needs to be localized. */
+ static const OUString aDefaultTableName
+ (OUString("Address Book"));
+
+ return aDefaultTableName;
+}
+
+
+MacabRecords *MacabAddressBook::getMacabRecords()
+{
+ /* If the MacabRecords don't exist, create them. */
+ if(m_xMacabRecords == nullptr)
+ {
+ m_xMacabRecords = new MacabRecords(m_aAddressBook);
+ m_xMacabRecords->setName(getDefaultTableName());
+ m_xMacabRecords->initialize();
+ }
+
+ return m_xMacabRecords;
+}
+
+
+/* Get the MacabRecords for a given name: either a group name or the
+ * default table name.
+ */
+MacabRecords *MacabAddressBook::getMacabRecords(std::u16string_view _tableName)
+{
+ if(_tableName == getDefaultTableName())
+ {
+ return getMacabRecords();
+ }
+ else
+ {
+ return getMacabGroup(_tableName);
+ }
+}
+
+
+MacabRecords *MacabAddressBook::getMacabRecordsMatch(const OUString& _tableName)
+{
+ if(match(_tableName, getDefaultTableName(), '\0'))
+ {
+ return getMacabRecords();
+ }
+
+ return getMacabGroupMatch(_tableName);
+}
+
+
+std::vector<MacabGroup *> MacabAddressBook::getMacabGroups()
+{
+ /* If the MacabGroups haven't been created yet, create them. */
+ if(!m_bRetrievedGroups)
+ {
+ /* If the MacabRecords haven't been created yet, create them. */
+ if(m_xMacabRecords == nullptr)
+ {
+ m_xMacabRecords = new MacabRecords(m_aAddressBook);
+ m_xMacabRecords->setName(getDefaultTableName());
+ m_xMacabRecords->initialize();
+ }
+
+ CFArrayRef allGroups = ABCopyArrayOfAllGroups(m_aAddressBook);
+ sal_Int32 nGroups = CFArrayGetCount(allGroups);
+ m_xMacabGroups = std::vector<MacabGroup *>(nGroups);
+
+ sal_Int32 i;
+ ABGroupRef xGroup;
+
+ /* Go through each group and create a MacabGroup out of it. */
+ for(i = 0; i < nGroups; i++)
+ {
+ xGroup = static_cast<ABGroupRef>(const_cast<void *>(CFArrayGetValueAtIndex(allGroups, i)));
+ m_xMacabGroups[i] = new MacabGroup(m_aAddressBook, m_xMacabRecords, xGroup);
+ }
+
+ CFRelease(allGroups);
+
+ /* Manage duplicates. */
+ manageDuplicateGroups(m_xMacabGroups);
+ m_bRetrievedGroups = true;
+ }
+
+ return m_xMacabGroups;
+}
+
+
+MacabGroup *MacabAddressBook::getMacabGroup(std::u16string_view _groupName)
+{
+ // initialize groups if not already initialized
+ if(!m_bRetrievedGroups)
+ getMacabGroups();
+
+ sal_Int32 nGroups = m_xMacabGroups.size();
+ sal_Int32 i;
+
+ for(i = 0; i < nGroups; i++)
+ {
+ if(m_xMacabGroups[i] != nullptr)
+ {
+ if(m_xMacabGroups[i]->getName() == _groupName)
+ {
+ return m_xMacabGroups[i];
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+
+MacabGroup *MacabAddressBook::getMacabGroupMatch(OUString const & _groupName)
+{
+ // initialize groups if not already initialized
+ if(!m_bRetrievedGroups)
+ getMacabGroups();
+
+ sal_Int32 nGroups = m_xMacabGroups.size();
+ sal_Int32 i;
+
+ for(i = 0; i < nGroups; i++)
+ {
+ if(m_xMacabGroups[i] != nullptr)
+ {
+ if(match(m_xMacabGroups[i]->getName(), _groupName, '\0'))
+ {
+ return m_xMacabGroups[i];
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabAddressBook.hxx b/connectivity/source/drivers/macab/MacabAddressBook.hxx
new file mode 100644
index 000000000..a23e0c1eb
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabAddressBook.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MacabRecords.hxx"
+#include "MacabGroup.hxx"
+
+#include <string_view>
+#include <vector>
+
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <AddressBook/ABAddressBookC.h>
+#include <postmac.h>
+
+namespace connectivity::macab
+{
+ class MacabAddressBook
+ {
+ protected:
+ ABAddressBookRef m_aAddressBook;
+ MacabRecords *m_xMacabRecords;
+ std::vector<MacabGroup *> m_xMacabGroups;
+ bool m_bRetrievedGroups;
+
+ public:
+ MacabAddressBook();
+ ~MacabAddressBook();
+ static const OUString & getDefaultTableName();
+
+ MacabRecords *getMacabRecords();
+ std::vector<MacabGroup *> getMacabGroups();
+
+ MacabGroup *getMacabGroup(std::u16string_view _groupName);
+ MacabRecords *getMacabRecords(std::u16string_view _tableName);
+
+ MacabGroup *getMacabGroupMatch(const OUString& _groupName);
+ MacabRecords *getMacabRecordsMatch(const OUString& _tableName);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabCatalog.cxx b/connectivity/source/drivers/macab/MacabCatalog.cxx
new file mode 100644
index 000000000..96ff62fd5
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabCatalog.cxx
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabCatalog.hxx"
+#include "MacabConnection.hxx"
+#include "MacabTables.hxx"
+#include <com/sun/star/sdbc/XRow.hpp>
+
+using namespace connectivity::macab;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::cppu;
+
+
+MacabCatalog::MacabCatalog(MacabConnection* _pCon)
+ : connectivity::sdbcx::OCatalog(_pCon),
+ m_pConnection(_pCon)
+{
+}
+
+void MacabCatalog::refreshTables()
+{
+ ::std::vector< OUString> aVector;
+ Sequence< OUString > aTypes { "%" };
+ Reference< XResultSet > xResult = m_xMetaData->getTables(
+ Any(), "%", "%", aTypes);
+
+ if (xResult.is())
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ OUString aName;
+ // const OUString& sDot = MacabCatalog::getDot();
+
+ while (xResult->next())
+ {
+ // aName = xRow->getString(2);
+ // aName += sDot;
+ aName = xRow->getString(3);
+ aVector.push_back(aName);
+ }
+ }
+ if (m_pTables)
+ m_pTables->reFill(aVector);
+ else
+ m_pTables.reset( new MacabTables(m_xMetaData,*this,m_aMutex,aVector) );
+}
+
+void MacabCatalog::refreshViews()
+{
+}
+
+void MacabCatalog::refreshGroups()
+{
+}
+
+void MacabCatalog::refreshUsers()
+{
+}
+
+const OUString& MacabCatalog::getDot()
+{
+ static const OUString sDot = ".";
+ return sDot;
+}
+
+
+// XTablesSupplier
+Reference< XNameAccess > SAL_CALL MacabCatalog::getTables( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ try
+ {
+ if (!m_pTables)
+ refreshTables();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_pTables.get();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabCatalog.hxx b/connectivity/source/drivers/macab/MacabCatalog.hxx
new file mode 100644
index 000000000..1757bb908
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabCatalog.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdbcx/VCatalog.hxx>
+
+namespace connectivity::macab
+{
+ class MacabConnection;
+
+ class MacabCatalog : public connectivity::sdbcx::OCatalog
+ {
+ MacabConnection* m_pConnection; // used to get the metadata
+
+ public:
+ explicit MacabCatalog(MacabConnection* _pCon);
+
+ MacabConnection* getConnection() const { return m_pConnection; }
+
+ static const OUString& getDot();
+
+ // implementation of the pure virtual methods
+ virtual void refreshTables() override;
+ virtual void refreshViews() override;
+ virtual void refreshGroups() override;
+ virtual void refreshUsers() override;
+
+ // XTablesSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTables(
+ ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabColumns.cxx b/connectivity/source/drivers/macab/MacabColumns.cxx
new file mode 100644
index 000000000..6a49ad1d0
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabColumns.cxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabColumns.hxx"
+#include "MacabTable.hxx"
+#include "MacabTables.hxx"
+#include "MacabCatalog.hxx"
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+
+using namespace connectivity::macab;
+using namespace connectivity::sdbcx;
+using namespace connectivity;
+using namespace ::comphelper;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+sdbcx::ObjectType MacabColumns::createObject(const OUString& _rName)
+{
+ const Any aCatalog;
+ const OUString sCatalogName;
+ const OUString sSchemaName(m_pTable->getSchema());
+ const OUString sTableName(m_pTable->getTableName());
+ Reference< XResultSet > xResult = m_pTable->getConnection()->getMetaData()->getColumns(
+ aCatalog, sSchemaName, sTableName, _rName);
+
+ sdbcx::ObjectType xRet;
+ if (xResult.is())
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+
+ while (xResult->next())
+ {
+ if (xRow->getString(4) == _rName)
+ {
+ xRet = new OColumn(
+ _rName,
+ xRow->getString(6),
+ xRow->getString(13),
+ xRow->getString(12),
+ xRow->getInt(11),
+ xRow->getInt(7),
+ xRow->getInt(9),
+ xRow->getInt(5),
+ false,
+ false,
+ false,
+ true,
+ sCatalogName,
+ sSchemaName,
+ sTableName);
+ break;
+ }
+ }
+ }
+
+ return xRet;
+}
+
+void MacabColumns::impl_refresh()
+{
+ m_pTable->refreshColumns();
+}
+
+MacabColumns::MacabColumns( MacabTable* _pTable,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector)
+ : sdbcx::OCollection(*_pTable, true, _rMutex, _rVector),
+ m_pTable(_pTable)
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabColumns.hxx b/connectivity/source/drivers/macab/MacabColumns.hxx
new file mode 100644
index 000000000..7123af89d
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabColumns.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MacabTable.hxx"
+#include <connectivity/sdbcx/VCollection.hxx>
+
+namespace connectivity::macab
+{
+ class MacabColumns : public sdbcx::OCollection
+ {
+ protected:
+ MacabTable* m_pTable;
+
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+
+ public:
+ MacabColumns( MacabTable* _pTable,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabConnection.cxx b/connectivity/source/drivers/macab/MacabConnection.cxx
new file mode 100644
index 000000000..eaa6cf523
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabConnection.cxx
@@ -0,0 +1,316 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabConnection.hxx"
+#include "MacabAddressBook.hxx"
+#include "MacabDatabaseMetaData.hxx"
+#include "MacabStatement.hxx"
+#include "MacabPreparedStatement.hxx"
+#include "MacabDriver.hxx"
+#include "MacabCatalog.hxx"
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/TransactionIsolation.hpp>
+#include <cppuhelper/weak.hxx>
+
+using namespace connectivity::macab;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+
+IMPLEMENT_SERVICE_INFO(MacabConnection, "com.sun.star.sdbc.drivers.MacabConnection", "com.sun.star.sdbc.Connection")
+
+MacabConnection::MacabConnection(MacabDriver* _pDriver)
+ : m_pAddressBook(nullptr),
+ m_pDriver(_pDriver)
+{
+ m_pDriver->acquire();
+}
+
+MacabConnection::~MacabConnection()
+{
+ if (!doIsClosed())
+ doClose();
+
+ m_pDriver->release();
+ m_pDriver = nullptr;
+}
+
+void MacabConnection::construct(const OUString&, const Sequence< PropertyValue >&)
+{
+ osl_atomic_increment( &m_refCount );
+
+ // get the macOS shared address book
+ m_pAddressBook = new MacabAddressBook();
+
+ osl_atomic_decrement( &m_refCount );
+}
+// XServiceInfo
+
+Reference< XStatement > SAL_CALL MacabConnection::createStatement( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // create a statement
+ // the statement can only be executed once
+ Reference< XStatement > xReturn = new MacabStatement(this);
+ m_aStatements.push_back(WeakReferenceHelper(xReturn));
+ return xReturn;
+}
+
+Reference< XPreparedStatement > SAL_CALL MacabConnection::prepareStatement( const OUString& _sSql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // create a statement
+ // the statement can only be executed more than once
+ Reference< XPreparedStatement > xReturn = new MacabPreparedStatement(this, _sSql);
+ m_aStatements.push_back(WeakReferenceHelper(xReturn));
+ return xReturn;
+}
+
+Reference< XPreparedStatement > SAL_CALL MacabConnection::prepareCall( const OUString& )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // not implemented yet :-) a task to do
+ return nullptr;
+}
+
+OUString SAL_CALL MacabConnection::nativeSQL( const OUString& _sSql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ // when you need to transform SQL92 to you driver specific you can do it here
+
+ return _sSql;
+}
+
+void SAL_CALL MacabConnection::setAutoCommit( sal_Bool )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+ // here you have to set your commit mode please have a look at the jdbc documentation to get a clear explanation
+}
+
+sal_Bool SAL_CALL MacabConnection::getAutoCommit( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+ // you have to distinguish which if you are in autocommit mode or not
+ // at normal case true should be fine here
+
+ return true;
+}
+
+void SAL_CALL MacabConnection::commit( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // when you database does support transactions you should commit here
+}
+
+void SAL_CALL MacabConnection::rollback( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // same as commit but for the other case
+}
+
+sal_Bool SAL_CALL MacabConnection::isClosed( )
+{
+ return doIsClosed();
+}
+
+bool MacabConnection::doIsClosed()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // just simple -> we are closed when we are disposed, that means someone called dispose(); (XComponent)
+ return MacabConnection_BASE::rBHelper.bDisposed;
+}
+
+Reference< XDatabaseMetaData > SAL_CALL MacabConnection::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // here we have to create the class with biggest interface
+ // The answer is 42 :-)
+ Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
+ if (!xMetaData.is())
+ {
+ xMetaData = new MacabDatabaseMetaData(this); // need the connection because it can return it
+ m_xMetaData = xMetaData;
+ }
+
+ return xMetaData;
+}
+
+void SAL_CALL MacabConnection::setReadOnly( sal_Bool )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // set you connection to readonly
+}
+
+sal_Bool SAL_CALL MacabConnection::isReadOnly( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // return if your connection to readonly
+ return false;
+}
+
+void SAL_CALL MacabConnection::setCatalog( const OUString& )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // if your database doesn't work with catalogs you go to next method otherwise you know what to do
+}
+
+OUString SAL_CALL MacabConnection::getCatalog( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+
+ // return your current catalog
+ return OUString();
+}
+
+void SAL_CALL MacabConnection::setTransactionIsolation( sal_Int32 )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // set your isolation level
+ // please have a look at @see com.sun.star.sdbc.TransactionIsolation
+}
+
+sal_Int32 SAL_CALL MacabConnection::getTransactionIsolation( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+
+ // please have a look at @see com.sun.star.sdbc.TransactionIsolation
+ return TransactionIsolation::NONE;
+}
+
+Reference< css::container::XNameAccess > SAL_CALL MacabConnection::getTypeMap( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+
+ // if your driver has special database types you can return it here
+
+ return nullptr;
+}
+
+void SAL_CALL MacabConnection::setTypeMap( const Reference< css::container::XNameAccess >& )
+{
+ // the other way around
+}
+
+// XCloseable
+void SAL_CALL MacabConnection::close( )
+{
+ doClose();
+}
+
+void MacabConnection::doClose()
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabConnection_BASE::rBHelper.bDisposed);
+ }
+ dispose();
+}
+
+// XWarningsSupplier
+Any SAL_CALL MacabConnection::getWarnings( )
+{
+ // when you collected some warnings -> return it
+ return Any();
+}
+
+void SAL_CALL MacabConnection::clearWarnings( )
+{
+ // you should clear your collected warnings here
+}
+
+void MacabConnection::disposing()
+{
+ // we noticed that we should be destroyed in near future so we have to dispose our statements
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ for (auto& rxStatement : m_aStatements)
+ {
+ Reference< XComponent > xComp(rxStatement.get(), UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ }
+ m_aStatements.clear();
+
+ if (m_pAddressBook != nullptr)
+ {
+ delete m_pAddressBook;
+ m_pAddressBook = nullptr;
+ }
+
+ m_xMetaData.clear();
+
+ MacabConnection_BASE::disposing();
+}
+
+Reference< XTablesSupplier > MacabConnection::createCatalog()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ Reference< XTablesSupplier > xTab = m_xCatalog;
+ if (!m_xCatalog.is())
+ {
+ xTab = new MacabCatalog(this);
+ m_xCatalog = xTab;
+ }
+ return xTab;
+}
+
+MacabAddressBook* MacabConnection::getAddressBook() const
+{
+ return m_pAddressBook;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT void* createMacabConnection( void* _pDriver )
+{
+ // by definition, the pointer crossing library boundaries as void ptr is acquired once
+ return cppu::acquire(new MacabConnection( static_cast< MacabDriver* >( _pDriver ) ));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabConnection.hxx b/connectivity/source/drivers/macab/MacabConnection.hxx
new file mode 100644
index 000000000..dc2bfa34f
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabConnection.hxx
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/CommonTools.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <TConnection.hxx>
+
+namespace connectivity::macab
+{
+
+ typedef ::cppu::WeakComponentImplHelper<css::sdbc::XConnection,
+ css::sdbc::XWarningsSupplier,
+ css::lang::XServiceInfo
+ > OMetaConnection_BASE;
+
+ class MacabDriver;
+ class MacabAddressBook;
+
+ typedef std::vector< css::uno::WeakReferenceHelper > OWeakRefArray;
+
+ typedef connectivity::OMetaConnection MacabConnection_BASE;
+
+ class MacabConnection : public MacabConnection_BASE
+ {
+ protected:
+
+ // Data attributes
+
+ MacabAddressBook* m_pAddressBook; // the address book
+ MacabDriver* m_pDriver; // pointer to the owning driver object
+ css::uno::Reference< css::sdbcx::XTablesSupplier>
+ m_xCatalog; // needed for the SQL interpreter
+
+ private:
+ bool doIsClosed();
+
+ void doClose();
+
+ public:
+ /// @throws css::sdbc::SQLException
+ virtual void construct( const OUString& url,const css::uno::Sequence< css::beans::PropertyValue >& info);
+
+ explicit MacabConnection(MacabDriver* _pDriver);
+ virtual ~MacabConnection() override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override;
+ virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override;
+ virtual sal_Bool SAL_CALL getAutoCommit( ) override;
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL rollback( ) override;
+ virtual sal_Bool SAL_CALL isClosed( ) override;
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual void SAL_CALL setCatalog( const OUString& catalog ) override;
+ virtual OUString SAL_CALL getCatalog( ) override;
+ virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override;
+ virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override;
+ virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+ // needed for the SQL interpreter
+ css::uno::Reference< css::sdbcx::XTablesSupplier > createCatalog();
+
+ // accessors
+ MacabDriver* getDriver() const { return m_pDriver;}
+ MacabAddressBook* getAddressBook() const;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabDatabaseMetaData.cxx b/connectivity/source/drivers/macab/MacabDatabaseMetaData.cxx
new file mode 100644
index 000000000..b54b844c9
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabDatabaseMetaData.cxx
@@ -0,0 +1,1073 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabDatabaseMetaData.hxx"
+#include "MacabAddressBook.hxx"
+#include "MacabHeader.hxx"
+#include "MacabGroup.hxx"
+#include "macabutilities.hxx"
+
+#include "MacabDriver.hxx"
+#include <FDatabaseMetaDataResultSet.hxx>
+#include <OTypeInfo.hxx>
+#include <com/sun/star/sdbc/ColumnSearch.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/TransactionIsolation.hpp>
+#include <rtl/ref.hxx>
+
+#include <vector>
+
+using namespace connectivity::macab;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+
+MacabDatabaseMetaData::MacabDatabaseMetaData(MacabConnection* _pCon)
+ : m_xConnection(_pCon),
+ m_bUseCatalog(true)
+{
+ OSL_ENSURE(_pCon,"MacabDatabaseMetaData::MacabDatabaseMetaData: No connection set!");
+
+ osl_atomic_increment( &m_refCount );
+ m_bUseCatalog = !(usesLocalFiles() || usesLocalFilePerTable());
+ osl_atomic_decrement( &m_refCount );
+}
+
+MacabDatabaseMetaData::~MacabDatabaseMetaData()
+{
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getCatalogSeparator( )
+{
+ if (m_bUseCatalog)
+ { // do some special here for you database
+ }
+
+ return OUString();
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxBinaryLiteralLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxRowSize( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxCatalogNameLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxCharLiteralLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxColumnNameLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxColumnsInIndex( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxCursorNameLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxConnections( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxColumnsInTable( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxStatementLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxTableNameLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxTablesInSelect( )
+{
+ // MaxTablesInSelect describes how many tables can participate in the FROM part of a given SELECT statement,
+ // currently, the resultset/statement implementations can cope with one table only
+ return 1;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::doesMaxRowSizeIncludeBlobs( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::storesLowerCaseQuotedIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::storesLowerCaseIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::storesMixedCaseQuotedIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::storesMixedCaseIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::storesUpperCaseQuotedIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::storesUpperCaseIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsAlterTableWithAddColumn( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsAlterTableWithDropColumn( )
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxIndexLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsNonNullableColumns( )
+{
+ return false;
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getCatalogTerm( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getIdentifierQuoteString( )
+{
+ // normally this is "
+ return "\"";
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getExtraNameCharacters( )
+{
+ return OUString();
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsDifferentTableCorrelationNames( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::isCatalogAtStart( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::dataDefinitionIgnoredInTransactions( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::dataDefinitionCausesTransactionCommit( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsDataManipulationTransactionsOnly( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsPositionedDelete( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsPositionedUpdate( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsOpenStatementsAcrossRollback( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsOpenStatementsAcrossCommit( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsOpenCursorsAcrossCommit( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsOpenCursorsAcrossRollback( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSchemasInDataManipulation( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsANSI92FullSQL( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsANSI92EntryLevelSQL( )
+{
+ return true; // should be supported at least
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsIntegrityEnhancementFacility( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSchemasInIndexDefinitions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSchemasInTableDefinitions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCatalogsInTableDefinitions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCatalogsInIndexDefinitions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCatalogsInDataManipulation( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsOuterJoins( )
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxStatements( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxProcedureNameLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxSchemaNameLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsTransactions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::allProceduresAreCallable( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsStoredProcedures( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSelectForUpdate( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::allTablesAreSelectable( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::isReadOnly( )
+{
+ // for the moment, we have read-only addresses, but this might change in the future
+ return true;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::usesLocalFiles( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::usesLocalFilePerTable( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsTypeConversion( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::nullPlusNonNullIsNull( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsColumnAliasing( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsTableCorrelationNames( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsConvert( sal_Int32, sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsExpressionsInOrderBy( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsGroupBy( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsGroupByBeyondSelect( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsGroupByUnrelated( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsMultipleTransactions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsMultipleResultSets( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsLikeEscapeClause( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsOrderByUnrelated( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsUnion( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsUnionAll( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsMixedCaseIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsMixedCaseQuotedIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::nullsAreSortedAtEnd( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::nullsAreSortedAtStart( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::nullsAreSortedHigh( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::nullsAreSortedLow( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSchemasInProcedureCalls( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSchemasInPrivilegeDefinitions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCatalogsInProcedureCalls( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCorrelatedSubqueries( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSubqueriesInComparisons( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSubqueriesInExists( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSubqueriesInIns( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSubqueriesInQuantifieds( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsANSI92IntermediateSQL( )
+{
+ return false;
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getURL( )
+{
+ // if someday we support more than the default address book,
+ // this method should return the URL which was used to create it
+ return "sdbc:address:macab:";
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getUserName( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getDriverName( )
+{
+ return "macab";
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getDriverVersion()
+{
+ return MACAB_DRIVER_VERSION;
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getDatabaseProductVersion( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getDatabaseProductName( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getProcedureTerm( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getSchemaTerm( )
+{
+ return OUString();
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getDriverMajorVersion( )
+{
+ return MACAB_DRIVER_VERSION_MAJOR;
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getDefaultTransactionIsolation( )
+{
+ return TransactionIsolation::NONE;
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getDriverMinorVersion( )
+{
+ return MACAB_DRIVER_VERSION_MINOR;
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getSQLKeywords( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getSearchStringEscape( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getStringFunctions( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getTimeDateFunctions( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getSystemFunctions( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabDatabaseMetaData::getNumericFunctions( )
+{
+ return OUString();
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsExtendedSQLGrammar( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCoreSQLGrammar( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsMinimumSQLGrammar( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsFullOuterJoins( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsLimitedOuterJoins( )
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxColumnsInGroupBy( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxColumnsInOrderBy( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxColumnsInSelect( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxUserNameLength( )
+{
+ return 0; // 0 means no limit
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsResultSetType( sal_Int32 setType )
+{
+ switch (setType)
+ {
+ case ResultSetType::FORWARD_ONLY:
+ case ResultSetType::SCROLL_INSENSITIVE:
+ return true;
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 )
+{
+ switch (setType)
+ {
+ case ResultSetType::FORWARD_ONLY:
+ case ResultSetType::SCROLL_INSENSITIVE:
+ return true;
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::ownUpdatesAreVisible( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::ownDeletesAreVisible( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::ownInsertsAreVisible( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::othersUpdatesAreVisible( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::othersDeletesAreVisible( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::othersInsertsAreVisible( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::updatesAreDetected( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::deletesAreDetected( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::insertsAreDetected( sal_Int32 )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabDatabaseMetaData::supportsBatchUpdates( )
+{
+ return false;
+}
+
+Reference< XConnection > SAL_CALL MacabDatabaseMetaData::getConnection( )
+{
+ return m_xConnection;
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getTableTypes( )
+{
+ rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTableTypes);
+
+ static ODatabaseMetaDataResultSet::ORows aRows = []
+ {
+ static constexpr OUStringLiteral aTable = u"TABLE";
+ ODatabaseMetaDataResultSet::ORows tmp;
+ ODatabaseMetaDataResultSet::ORow aRow(2);
+ aRow[0] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[1] = new ORowSetValueDecorator(OUString(aTable));
+ tmp.push_back(aRow);
+ return tmp;
+ }();
+ pResult->setRows(std::vector(aRows));
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getTypeInfo( )
+{
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTypeInfo);
+
+ static ODatabaseMetaDataResultSet::ORows aRows = []()
+ {
+ ODatabaseMetaDataResultSet::ORows tmp;
+ ODatabaseMetaDataResultSet::ORow aRow(19);
+
+ // We support four types: char, timestamp, integer, float
+ aRow[0] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[1] = new ORowSetValueDecorator(OUString("CHAR"));
+ aRow[2] = new ORowSetValueDecorator(DataType::CHAR);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(254));
+ aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue();
+ aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue();
+ aRow[6] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[7] = new ORowSetValueDecorator(sal_Int32(ColumnValue::NULLABLE));
+ aRow[8] = ODatabaseMetaDataResultSet::get1Value();
+ aRow[9] = new ORowSetValueDecorator(sal_Int32(ColumnSearch::CHAR));
+ aRow[10] = ODatabaseMetaDataResultSet::get1Value();
+ aRow[11] = ODatabaseMetaDataResultSet::get0Value();
+ aRow[12] = ODatabaseMetaDataResultSet::get0Value();
+ aRow[13] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[14] = ODatabaseMetaDataResultSet::get0Value();
+ aRow[15] = ODatabaseMetaDataResultSet::get0Value();
+ aRow[16] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[17] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[18] = new ORowSetValueDecorator(sal_Int32(10));
+
+ tmp.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("TIMESTAMP"));
+ aRow[2] = new ORowSetValueDecorator(DataType::TIMESTAMP);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(19));
+ aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue();
+ aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue();
+ tmp.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("INTEGER"));
+ aRow[2] = new ORowSetValueDecorator(DataType::INTEGER);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(20));
+ aRow[15] = new ORowSetValueDecorator(sal_Int32(20));
+ tmp.push_back(aRow);
+
+ aRow[1] = new ORowSetValueDecorator(OUString("FLOAT"));
+ aRow[2] = new ORowSetValueDecorator(DataType::FLOAT);
+ aRow[3] = new ORowSetValueDecorator(sal_Int32(20));
+ aRow[15] = new ORowSetValueDecorator(sal_Int32(15));
+ tmp.push_back(aRow);
+
+ return tmp;
+ }();
+ pResult->setRows(std::vector(aRows));
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getCatalogs( )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eCatalogs );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getSchemas( )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eSchemas );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getColumnPrivileges(
+ const Any&, const OUString&, const OUString&,
+ const OUString& )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eColumnPrivileges );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getColumns(
+ const Any&,
+ const OUString&,
+ const OUString& tableNamePattern,
+ const OUString& columnNamePattern)
+{
+ rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eColumns);
+ MacabRecords *aRecords;
+ OUString sTableName;
+
+ aRecords = m_xConnection->getAddressBook()->getMacabRecordsMatch(tableNamePattern);
+
+ ODatabaseMetaDataResultSet::ORows aRows;
+ if(aRecords != nullptr)
+ {
+ MacabHeader *aHeader = aRecords->getHeader();
+ sTableName = aRecords->getName();
+
+ ODatabaseMetaDataResultSet::ORow aRow(19);
+
+ aRow[0] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[1] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[2] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[3] = new ORowSetValueDecorator(sTableName);
+ aRow[8] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[9] = ODatabaseMetaDataResultSet::get0Value();
+ aRow[10] = new ORowSetValueDecorator(sal_Int32(10));
+ aRow[11] = ODatabaseMetaDataResultSet::get1Value();
+ aRow[12] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[13] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[14] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[15] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[16] = new ORowSetValueDecorator(sal_Int32(254));
+ aRow[18] = new ORowSetValueDecorator(OUString("YES"));
+
+ sal_Int32 nPosition = 1;
+ OUString sName;
+
+ MacabHeader::iterator aField;
+
+ for ( aField = aHeader->begin();
+ aField != aHeader->end();
+ ++aField, ++nPosition)
+ {
+
+ sName = CFStringToOUString(static_cast<CFStringRef>((*aField)->value));
+ if (match(columnNamePattern, sName, '\0'))
+ {
+ aRow[4] = new ORowSetValueDecorator(sName);
+ aRow[17] = new ORowSetValueDecorator(nPosition);
+ switch((*aField)->type)
+ {
+ case kABStringProperty:
+ aRow[5] = new ORowSetValueDecorator(DataType::CHAR);
+ aRow[6] = new ORowSetValueDecorator(OUString("CHAR"));
+ aRow[7] = new ORowSetValueDecorator(sal_Int32(256));
+ aRows.push_back(aRow);
+ break;
+ case kABDateProperty:
+ aRow[5] = new ORowSetValueDecorator(DataType::TIMESTAMP);
+ aRow[6] = new ORowSetValueDecorator(OUString("TIMESTAMP"));
+ aRows.push_back(aRow);
+ break;
+ case kABIntegerProperty:
+ aRow[5] = new ORowSetValueDecorator(DataType::INTEGER);
+ aRow[6] = new ORowSetValueDecorator(OUString("INTEGER"));
+ aRow[7] = new ORowSetValueDecorator(sal_Int32(20));
+ aRows.push_back(aRow);
+ break;
+ case kABRealProperty:
+ aRow[5] = new ORowSetValueDecorator(DataType::FLOAT);
+ aRow[6] = new ORowSetValueDecorator(OUString("FLOAT"));
+ aRow[7] = new ORowSetValueDecorator(sal_Int32(15));
+ aRows.push_back(aRow);
+ break;
+ default:
+ ;
+ // shouldn't happen -- throw an error...?
+ }
+ }
+ }
+ }
+ pResult->setRows(std::move(aRows));
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getTables(
+ const Any&,
+ const OUString&,
+ const OUString&,
+ const Sequence< OUString >& types)
+{
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTables);
+
+ // check whether we have tables in the requested types
+ // for the moment, we answer only the "TABLE" table type
+ // when no types are given at all, we return all the tables
+ static constexpr OUStringLiteral aTable = u"TABLE";
+ bool bTableFound = false;
+ const OUString* p = types.getConstArray(),
+ * pEnd = p + types.getLength();
+
+ if (p == pEnd)
+ {
+ bTableFound = true;
+ }
+ else while (p < pEnd)
+ {
+ if (match(*p, aTable, '\0'))
+ {
+ bTableFound = true;
+ break;
+ }
+ p++;
+ }
+ if (!bTableFound)
+ return pResult;
+
+ static ODatabaseMetaDataResultSet::ORows aRows = [&]()
+ {
+ ODatabaseMetaDataResultSet::ORows tmp;
+ ODatabaseMetaDataResultSet::ORow aRow(6);
+
+ MacabRecords *xRecords = m_xConnection->getAddressBook()->getMacabRecords();
+ std::vector<MacabGroup *> xGroups = m_xConnection->getAddressBook()->getMacabGroups();
+ sal_Int32 i, nGroups;
+ nGroups = xGroups.size();
+
+ aRow[0] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[1] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[2] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[3] = new ORowSetValueDecorator(xRecords->getName());
+ aRow[4] = new ORowSetValueDecorator(OUString(aTable));
+ aRow[5] = ODatabaseMetaDataResultSet::getEmptyValue();
+ tmp.push_back(aRow);
+
+ for(i = 0; i < nGroups; i++)
+ {
+ aRow[3] = new ORowSetValueDecorator(xGroups[i]->getName());
+ tmp.push_back(aRow);
+ }
+ return tmp;
+ }();
+ pResult->setRows(std::vector(aRows));
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getProcedureColumns(
+ const Any&, const OUString&,
+ const OUString&, const OUString& )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eProcedureColumns );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getProcedures(
+ const Any&, const OUString&,
+ const OUString& )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eProcedures );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getVersionColumns(
+ const Any&, const OUString&, const OUString& table )
+{
+ rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eVersionColumns);
+
+ ODatabaseMetaDataResultSet::ORows aRows;
+
+ if (m_xConnection->getAddressBook()->getMacabRecords(table) != nullptr)
+ {
+ ODatabaseMetaDataResultSet::ORow aRow( 9 );
+
+ OUString sName = CFStringToOUString(kABModificationDateProperty);
+
+ aRow[0] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[1] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[2] = new ORowSetValueDecorator(sName);
+ aRow[3] = new ORowSetValueDecorator(DataType::TIMESTAMP);
+ aRow[4] = new ORowSetValueDecorator(OUString("TIMESTAMP"));
+
+ aRow[5] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[6] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[7] = ODatabaseMetaDataResultSet::getEmptyValue();
+ aRow[8] = ODatabaseMetaDataResultSet::getEmptyValue();
+
+ aRows.push_back(aRow);
+ }
+ pResult->setRows(std::move(aRows));
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getExportedKeys(
+ const Any&, const OUString&, const OUString& )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eExportedKeys );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getImportedKeys(
+ const Any&, const OUString&, const OUString& )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eImportedKeys );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getPrimaryKeys(
+ const Any&, const OUString&, const OUString& )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::ePrimaryKeys );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getIndexInfo(
+ const Any&, const OUString&, const OUString&,
+ sal_Bool, sal_Bool )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eIndexInfo );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getBestRowIdentifier(
+ const Any&, const OUString&, const OUString&, sal_Int32,
+ sal_Bool )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eBestRowIdentifier );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getTablePrivileges(
+ const Any&, const OUString&, const OUString& )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTablePrivileges );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getCrossReference(
+ const Any&, const OUString&,
+ const OUString&, const Any&,
+ const OUString&, const OUString& )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eCrossReference );
+}
+
+Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getUDTs( const Any&, const OUString&, const OUString&, const Sequence< sal_Int32 >& )
+{
+ OSL_FAIL("Not implemented yet!");
+ throw SQLException();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabDatabaseMetaData.hxx b/connectivity/source/drivers/macab/MacabDatabaseMetaData.hxx
new file mode 100644
index 000000000..662be1c01
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabDatabaseMetaData.hxx
@@ -0,0 +1,195 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MacabConnection.hxx"
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace connectivity::macab
+{
+
+ class MacabDatabaseMetaData : public ::cppu::WeakImplHelper< css::sdbc::XDatabaseMetaData>
+ {
+ rtl::Reference< MacabConnection > m_xConnection;
+ bool m_bUseCatalog;
+
+ public:
+
+ MacabConnection* getOwnConnection() const { return m_xConnection.get(); }
+
+ explicit MacabDatabaseMetaData(MacabConnection* _pCon);
+ virtual ~MacabDatabaseMetaData() override;
+
+ // this interface is really BIG
+ // XDatabaseMetaData
+ virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override;
+ virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override;
+ virtual OUString SAL_CALL getURL( ) override;
+ virtual OUString SAL_CALL getUserName( ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override;
+ virtual OUString SAL_CALL getDatabaseProductName( ) override;
+ virtual OUString SAL_CALL getDatabaseProductVersion( ) override;
+ virtual OUString SAL_CALL getDriverName( ) override;
+ virtual OUString SAL_CALL getDriverVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFiles( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override;
+ virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL supportsMixedCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesMixedCaseQuotedIdentifiers( ) override;
+ virtual OUString SAL_CALL getIdentifierQuoteString( ) override;
+ virtual OUString SAL_CALL getSQLKeywords( ) override;
+ virtual OUString SAL_CALL getNumericFunctions( ) override;
+ virtual OUString SAL_CALL getStringFunctions( ) override;
+ virtual OUString SAL_CALL getSystemFunctions( ) override;
+ virtual OUString SAL_CALL getTimeDateFunctions( ) override;
+ virtual OUString SAL_CALL getSearchStringEscape( ) override;
+ virtual OUString SAL_CALL getExtraNameCharacters( ) override;
+ virtual sal_Bool SAL_CALL supportsAlterTableWithAddColumn( ) override;
+ virtual sal_Bool SAL_CALL supportsAlterTableWithDropColumn( ) override;
+ virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override;
+ virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override;
+ virtual sal_Bool SAL_CALL supportsTypeConversion( ) override;
+ virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override;
+ virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override;
+ virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupBy( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override;
+ virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override;
+ virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override;
+ virtual sal_Bool SAL_CALL supportsOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override;
+ virtual OUString SAL_CALL getSchemaTerm( ) override;
+ virtual OUString SAL_CALL getProcedureTerm( ) override;
+ virtual OUString SAL_CALL getCatalogTerm( ) override;
+ virtual sal_Bool SAL_CALL isCatalogAtStart( ) override;
+ virtual OUString SAL_CALL getCatalogSeparator( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInDataManipulation( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInTableDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInDataManipulation( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInTableDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override;
+ virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override;
+ virtual sal_Bool SAL_CALL supportsUnion( ) override;
+ virtual sal_Bool SAL_CALL supportsUnionAll( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override;
+ virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override;
+ virtual sal_Int32 SAL_CALL getMaxConnections( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxRowSize( ) override;
+ virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override;
+ virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxStatements( ) override;
+ virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxTablesInSelect( ) override;
+ virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override;
+ virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getSchemas( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCatalogs( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getBestRowIdentifier( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope, sal_Bool nullable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getVersionColumns( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCrossReference( const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTypeInfo( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override;
+ virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabDriver.cxx b/connectivity/source/drivers/macab/MacabDriver.cxx
new file mode 100644
index 000000000..4667c690a
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabDriver.cxx
@@ -0,0 +1,310 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabDriver.hxx"
+#include "MacabConnection.hxx"
+
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+#include <strings.hrc>
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdb;
+using namespace com::sun::star::frame;
+using namespace connectivity::macab;
+
+namespace {
+
+/** throws a generic SQL exception with SQLState S1000 and error code 0
+ */
+void throwGenericSQLException( const OUString& _rMessage )
+{
+ SQLException aError;
+ aError.Message = _rMessage;
+ aError.SQLState = "S1000";
+ aError.ErrorCode = 0;
+ throw aError;
+}
+
+/** throws an SQLException saying that no Mac OS installation was found
+ */
+void throwNoMacOSException()
+{
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(
+ STR_NO_MAC_OS_FOUND
+ ) );
+ throwGenericSQLException( sError );
+}
+
+
+}
+
+// = MacabImplModule
+
+
+MacabImplModule::MacabImplModule()
+ :m_bAttemptedLoadModule(false)
+ ,m_hConnectorModule(nullptr)
+ ,m_pConnectionFactoryFunc(nullptr)
+{
+}
+
+
+bool MacabImplModule::isMacOSPresent()
+{
+ return impl_loadModule();
+}
+
+
+namespace
+{
+ template< typename FUNCTION >
+ void lcl_getFunctionFromModuleOrUnload( oslModule& _rModule, const char* _pAsciiSymbolName, FUNCTION& _rFunction )
+ {
+ _rFunction = nullptr;
+ if ( _rModule )
+ {
+
+ const OUString sSymbolName = OUString::createFromAscii( _pAsciiSymbolName );
+ _rFunction = reinterpret_cast<FUNCTION>( osl_getSymbol( _rModule, sSymbolName.pData ) );
+
+ if ( !_rFunction )
+ { // did not find the symbol
+ SAL_WARN( "connectivity.macab", "lcl_getFunctionFromModuleOrUnload: could not find the symbol " << _pAsciiSymbolName );
+ osl_unloadModule( _rModule );
+ _rModule = nullptr;
+ }
+ }
+ }
+}
+
+
+extern "C" { static void thisModule() {} }
+
+bool MacabImplModule::impl_loadModule()
+{
+ if ( m_bAttemptedLoadModule )
+ return ( m_hConnectorModule != nullptr );
+ m_bAttemptedLoadModule = true;
+
+ OSL_ENSURE( !m_hConnectorModule && !m_pConnectionFactoryFunc,
+ "MacabImplModule::impl_loadModule: inconsistence: inconsistency (never attempted load before, but some values already set)!");
+
+ const OUString sModuleName( SAL_MODULENAME( "macabdrv1" ) );
+ m_hConnectorModule = osl_loadModuleRelative( &thisModule, sModuleName.pData, SAL_LOADMODULE_NOW ); // LAZY! #i61335#
+ OSL_ENSURE( m_hConnectorModule, "MacabImplModule::impl_loadModule: could not load the implementation library!" );
+ if ( !m_hConnectorModule )
+ return false;
+
+ lcl_getFunctionFromModuleOrUnload( m_hConnectorModule, "createMacabConnection", m_pConnectionFactoryFunc );
+
+ if ( !m_hConnectorModule )
+ // one of the symbols did not exist
+ throw RuntimeException();
+
+ return true;
+}
+
+
+void MacabImplModule::impl_unloadModule()
+{
+ OSL_PRECOND( m_hConnectorModule != nullptr, "MacabImplModule::impl_unloadModule: no module!" );
+
+ osl_unloadModule( m_hConnectorModule );
+ m_hConnectorModule = nullptr;
+
+ m_pConnectionFactoryFunc = nullptr;
+
+ m_bAttemptedLoadModule = false;
+}
+
+
+void MacabImplModule::init()
+{
+ if ( !impl_loadModule() )
+ throwNoMacOSException();
+
+}
+
+
+MacabConnection* MacabImplModule::createConnection( MacabDriver* _pDriver ) const
+{
+ OSL_PRECOND( m_hConnectorModule, "MacabImplModule::createConnection: not initialized!" );
+
+ void* pUntypedConnection = (*m_pConnectionFactoryFunc)( _pDriver );
+ if ( !pUntypedConnection )
+ throw RuntimeException();
+
+ return static_cast< MacabConnection* >( pUntypedConnection );
+}
+
+
+void MacabImplModule::shutdown()
+{
+ if ( !m_hConnectorModule )
+ return;
+
+ impl_unloadModule();
+}
+
+
+// = MacabDriver
+
+MacabDriver::MacabDriver(
+ const Reference< css::uno::XComponentContext >& _rxContext)
+ : MacabDriver_BASE(m_aMutex),
+ m_xContext(_rxContext),
+ m_aImplModule()
+{
+ if ( !m_xContext.is() )
+ throw NullPointerException();
+
+ osl_atomic_increment( &m_refCount );
+ try
+ {
+ Reference< XDesktop2 > xDesktop = Desktop::create( m_xContext );
+ xDesktop->addTerminateListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.macab");
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+void MacabDriver::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ // when driver will be destroyed so all our connections have to be destroyed as well
+ for (auto& rxConnection : m_xConnections)
+ {
+ Reference< XComponent > xComp(rxConnection.get(), UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ }
+ m_xConnections.clear();
+
+ WeakComponentImplHelperBase::disposing();
+}
+
+OUString SAL_CALL MacabDriver::getImplementationName( )
+{
+ return "com.sun.star.comp.sdbc.macab.Driver";
+}
+
+sal_Bool SAL_CALL MacabDriver::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > SAL_CALL MacabDriver::getSupportedServiceNames( )
+{
+ // which service is supported
+ // for more information @see com.sun.star.sdbc.Driver
+ return { "com.sun.star.sdbc.Driver" };
+}
+
+Reference< XConnection > SAL_CALL MacabDriver::connect( const OUString& url, const Sequence< PropertyValue >& info )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ m_aImplModule.init();
+
+ // create a new connection with the given properties and append it to our vector
+ MacabConnection* pConnection = m_aImplModule.createConnection( this );
+ SAL_WARN_IF( !pConnection, "connectivity.macab", "MacabDriver::connect: no connection has been created by the factory!" );
+
+ // by definition, the factory function returned an object which was acquired once
+ Reference< XConnection > xConnection = pConnection;
+ pConnection->release();
+
+ // late constructor call which can throw exception and allows a correct dtor call when so
+ pConnection->construct( url, info );
+
+ // remember it
+ m_xConnections.push_back( WeakReferenceHelper( *pConnection ) );
+
+ return xConnection;
+}
+
+sal_Bool SAL_CALL MacabDriver::acceptsURL( const OUString& url )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if ( !m_aImplModule.isMacOSPresent() )
+ return false;
+
+ // here we have to look whether we support this URL format
+ return url == "sdbc:address:macab";
+}
+
+Sequence< DriverPropertyInfo > SAL_CALL MacabDriver::getPropertyInfo( const OUString&, const Sequence< PropertyValue >& )
+{
+ // if you have something special to say, return it here :-)
+ return Sequence< DriverPropertyInfo >();
+}
+
+sal_Int32 SAL_CALL MacabDriver::getMajorVersion( )
+{
+ return MACAB_DRIVER_VERSION_MAJOR;
+}
+
+sal_Int32 SAL_CALL MacabDriver::getMinorVersion( )
+{
+ return MACAB_DRIVER_VERSION_MINOR;
+}
+
+void SAL_CALL MacabDriver::queryTermination( const EventObject& )
+{
+ // nothing to do, nothing to veto
+}
+
+void SAL_CALL MacabDriver::notifyTermination( const EventObject& )
+{
+ m_aImplModule.shutdown();
+}
+
+void SAL_CALL MacabDriver::disposing( const EventObject& )
+{
+ // not interested in (this is the disposing of the desktop, if any)
+}
+
+OUString MacabDriver::impl_getConfigurationSettingsPath()
+{
+ return "/org.openoffice.Office.DataAccess/DriverSettings/com.sun.star.comp.sdbc.macab.Driver";
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_MacabDriver_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new MacabDriver(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabDriver.hxx b/connectivity/source/drivers/macab/MacabDriver.hxx
new file mode 100644
index 000000000..d18f5e982
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabDriver.hxx
@@ -0,0 +1,161 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/frame/XTerminateListener.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <osl/module.h>
+
+// the address book driver's version
+#define MACAB_DRIVER_VERSION "0.1"
+#define MACAB_DRIVER_VERSION_MAJOR 0
+#define MACAB_DRIVER_VERSION_MINOR 1
+
+namespace connectivity::macab
+{
+ class MacabConnection;
+ class MacabDriver;
+
+ typedef void* (SAL_CALL * ConnectionFactoryFunction)( void* _pDriver );
+
+ typedef std::vector< css::uno::WeakReferenceHelper > OWeakRefArray;
+
+
+ // = MacabImplModule
+
+ class MacabImplModule
+ {
+ private:
+ /// Did we already attempt to load the module and to retrieve the symbols?
+ bool m_bAttemptedLoadModule;
+ oslModule m_hConnectorModule;
+ ConnectionFactoryFunction m_pConnectionFactoryFunc;
+
+ public:
+ MacabImplModule();
+
+ /** determines whether there is a mac OS present in the environment
+ */
+ bool isMacOSPresent();
+
+ /** initializes the implementation module.
+
+ @throws css::uno::RuntimeException
+ if the module could be loaded, but required symbols are missing
+ @throws css::sdbc::SQLException
+ if no Mac OS was found at all
+ */
+ void init();
+
+ /** shuts down the impl module
+ */
+ void shutdown();
+
+ /** creates a new connection
+ @precond
+ <member>init</member> has been called before
+ @throws css::uno::RuntimeException
+ if no connection object could be created (which is a severe error, normally impossible)
+ */
+ MacabConnection* createConnection( MacabDriver* _pDriver ) const;
+
+ private:
+ /** loads the implementation module and retrieves the needed symbols
+
+ Save against being called multiple times.
+
+ @return <TRUE/> if the module could be loaded successfully.
+
+ @throws css::uno::RuntimeException
+ if the module could be loaded, but required symbols are missing
+ */
+ bool impl_loadModule();
+
+ /** unloads the implementation module, and resets all function pointers to <NULL/>
+ @precond m_hConnectorModule is not <NULL/>
+ */
+ void impl_unloadModule();
+ };
+
+
+ // = MacabDriver
+
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver,
+ css::lang::XServiceInfo,
+ css::frame::XTerminateListener > MacabDriver_BASE;
+ class MacabDriver : public MacabDriver_BASE
+ {
+ protected:
+ ::osl::Mutex m_aMutex; // mutex is need to control member access
+ OWeakRefArray m_xConnections; // vector containing a list of all the
+ // MacabConnection objects for this Driver
+ css::uno::Reference< css::uno::XComponentContext >
+ m_xContext; // the multi-service factory
+ MacabImplModule m_aImplModule;
+
+ public:
+ css::uno::Reference< css::uno::XComponentContext > const &
+ getComponentContext() const { return m_xContext; }
+
+ /** returns the path of our configuration settings
+ */
+ static OUString impl_getConfigurationSettingsPath();
+
+ explicit MacabDriver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext);
+ protected:
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Int32 SAL_CALL getMajorVersion() override;
+ virtual sal_Int32 SAL_CALL getMinorVersion() override;
+
+ // XTerminateListener
+ virtual void SAL_CALL queryTermination( const css::lang::EventObject& Event ) override;
+ virtual void SAL_CALL notifyTermination( const css::lang::EventObject& Event ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ private:
+ /** shuts down the library which contains the real implementations
+
+ This method is safe against being called multiple times
+
+ @precond our mutex is locked
+ */
+ void impl_shutdownImplementationModule();
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabGroup.cxx b/connectivity/source/drivers/macab/MacabGroup.cxx
new file mode 100644
index 000000000..a57f1729f
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabGroup.cxx
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabGroup.hxx"
+#include "MacabRecords.hxx"
+#include "macabutilities.hxx"
+
+using namespace connectivity::macab;
+
+
+/* A MacabGroup is basically a MacabRecords with a different constructor.
+ * It only exists as a different entity for clarification purposes (a group
+ * is its own entity in the macOS Address Book) and because its
+ * construction is so unique (it is based on an already existent
+ * MacabRecords of the entire address book).
+ */
+MacabGroup::MacabGroup(const ABAddressBookRef _addressBook, const MacabRecords *_allRecords, const ABGroupRef _xGroup)
+ : MacabRecords(_addressBook)
+{
+ sal_Int32 i, j, nAllRecordsSize;
+ CFArrayRef xGroupMembers = ABGroupCopyArrayOfAllMembers(_xGroup);
+ ABPersonRef xPerson;
+ CFStringRef sGroupMemberUID;
+ bool bFound;
+ macabfield *xRecordField;
+
+ // Set the group's name (stored in MacabRecords as m_sName)
+ CFStringRef sGroupName;
+ sGroupName = static_cast<CFStringRef>(ABRecordCopyValue(_xGroup, kABGroupNameProperty));
+ m_sName = CFStringToOUString(sGroupName);
+ CFRelease(sGroupName);
+
+ // The _group's_ records (remember MacabGroup inherits from MacabRecords)
+ recordsSize = static_cast<sal_Int32>(CFArrayGetCount(xGroupMembers));
+ records = new MacabRecord *[recordsSize];
+ setHeader(_allRecords->getHeader());
+
+ /* Go through each record in the group and try to find that record's UID
+ * in the MacabRecords that was passed in. If it is found, add that
+ * record to the group. Otherwise, report an error. (All records should
+ * exist in the MacabRecords that was passed in.)
+ */
+ nAllRecordsSize = _allRecords->size();
+ for(i = 0; i < recordsSize; i++)
+ {
+ xPerson = static_cast<ABPersonRef>(const_cast<void *>(CFArrayGetValueAtIndex(xGroupMembers,i)));
+ if(xPerson != nullptr)
+ {
+ sGroupMemberUID = static_cast<CFStringRef>(ABRecordCopyValue(xPerson, kABUIDProperty));
+ if(sGroupMemberUID != nullptr)
+ {
+ bFound = false;
+ for(j = 0; j < nAllRecordsSize; j++)
+ {
+ xRecordField = _allRecords->getField(j,CFStringToOUString(kABUIDProperty));
+ if(xRecordField != nullptr && xRecordField->value != nullptr)
+ {
+ if(CFEqual(xRecordField->value, sGroupMemberUID))
+ {
+ /* Found the matching UID! Insert into the group... */
+ insertRecord(_allRecords->getRecord(j));
+ bFound = true;
+ break;
+ }
+ }
+ }
+ OSL_ENSURE(bFound, "MacabGroup::MacabGroup : Could not find group member based on UID!");
+ CFRelease(sGroupMemberUID);
+ }
+ }
+ }
+
+ CFRelease(xGroupMembers);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabGroup.hxx b/connectivity/source/drivers/macab/MacabGroup.hxx
new file mode 100644
index 000000000..ddcd47b46
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabGroup.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MacabRecords.hxx"
+
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <AddressBook/ABAddressBookC.h>
+#include <postmac.h>
+
+
+namespace connectivity::macab
+{
+ class MacabGroup: public MacabRecords {
+ public:
+ MacabGroup(const ABAddressBookRef _addressBook, const MacabRecords *_allRecords, const ABGroupRef _xGroup);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabHeader.cxx b/connectivity/source/drivers/macab/MacabHeader.cxx
new file mode 100644
index 000000000..da270dd05
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabHeader.cxx
@@ -0,0 +1,330 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabHeader.hxx"
+#include "MacabRecord.hxx"
+#include "macabutilities.hxx"
+
+#include <math.h>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <connectivity/dbconversion.hxx>
+
+using namespace connectivity::macab;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::util;
+using namespace ::dbtools;
+
+
+MacabHeader::MacabHeader(const sal_Int32 _size, macabfield **_fields)
+{
+ sal_Int32 i;
+ size = _size;
+ fields = std::make_unique<macabfield *[]>(size);
+ for(i = 0; i < size; i++)
+ {
+ if(_fields[i] == nullptr)
+ {
+ fields[i] = nullptr;
+ }
+ else
+ {
+ /* The constructor duplicates the macabfields it gets because they
+ * are either deleted later or used for other purposes.
+ */
+ fields[i] = new macabfield;
+ fields[i]->type = _fields[i]->type;
+ fields[i]->value = _fields[i]->value;
+ if (fields[i]->value)
+ CFRetain(fields[i]->value);
+ }
+ }
+
+}
+
+
+MacabHeader::MacabHeader()
+{
+ size = 0;
+ fields = nullptr;
+}
+
+
+MacabHeader::~MacabHeader()
+{
+}
+
+
+void MacabHeader::operator+= (const MacabHeader *r)
+{
+ /* Add one MacabHeader to another. Anything not already in the header is
+ * added to the end of it.
+ */
+ sal_Int32 rSize = r->getSize();
+ if(rSize != 0) // If the new header does actually have fields
+ {
+ /* If our header is currently empty, just copy all of the fields from
+ * the new header to this one.
+ */
+ if(size == 0)
+ {
+ sal_Int32 i;
+ size = rSize;
+ fields = std::make_unique<macabfield *[]>(size);
+ for(i = 0; i < size; i++)
+ {
+ fields[i] = r->copy(i);
+ }
+ }
+
+ /* Otherwise, only add the duplicates. We do this with a two-pass
+ * approach. First, find out how many fields to add, then reallocate
+ * the size of the fields array and add the old ones at the end.
+ * (More precisely, we create a _new_ fields array with the new length
+ * allocated to it, then get all of the fields from the current
+ * fields array to it, then copy the non-duplicates from the new
+ * header to the end.)
+ */
+ else
+ {
+ sal_Int32 i;
+ sal_Int32 numToAdd = 0, numAdded = 0;
+ macabfield **newFields;
+ for( i = 0; i < rSize; i++)
+ {
+ if(!contains(r->get(i)))
+ {
+ numToAdd++;
+ }
+ }
+
+ newFields = new macabfield *[size+numToAdd];
+ for(i = 0; i < size; i++)
+ {
+ newFields[i] = copy(i);
+ }
+
+ for( i = 0; i < rSize; i++)
+ {
+ if(!contains(r->get(i)))
+ {
+ newFields[size+numAdded] = r->copy(i);
+ numAdded++;
+ if(numAdded == numToAdd)
+ break;
+ }
+ }
+
+ releaseFields();
+ size += numAdded;
+ fields.reset(newFields);
+ }
+ }
+}
+
+
+OUString MacabHeader::getString(const sal_Int32 i) const
+{
+ OUString nRet;
+
+ if(i < size)
+ {
+ if(fields[i] == nullptr || fields[i]->value == nullptr || CFGetTypeID(fields[i]->value) != CFStringGetTypeID())
+ return OUString();
+ try
+ {
+ nRet = CFStringToOUString(static_cast<CFStringRef>(fields[i]->value));
+ }
+ catch(...){ }
+ }
+
+ return nRet;
+}
+
+
+void MacabHeader::sortRecord()
+{
+ sortRecord(0,size);
+}
+
+
+macabfield **MacabHeader::sortRecord(const sal_Int32 _start, const sal_Int32 _length)
+{
+ /* Sort using mergesort. Because it uses mergesort, it is recursive and
+ * not in place (so it creates a new array at every step of the
+ * recursion), so if you prefer to use a different sort, please feel
+ * free to implement it.
+ */
+ macabfield** sorted = new macabfield *[_length];
+ if(_length <= 2)
+ {
+ if(_length == 2)
+ {
+ if(compareFields(fields[_start], fields[_start+1]) > 0)
+ {
+ sorted[0] = get(_start+1);
+ sorted[1] = get(_start);
+ }
+ else
+ {
+ sorted[0] = get(_start);
+ sorted[1] = get(_start+1);
+ }
+ }
+ else if(_length == 1)
+ {
+ sorted[0] = get(_start);
+ }
+ }
+ else
+ {
+ sal_Int32 halfLength = floor(_length/2);
+ sal_Int32 fp = 0, lp = 0;
+ sal_Int32 i;
+ macabfield **firstHalf = sortRecord(_start, halfLength);
+ macabfield **lastHalf = sortRecord(_start+halfLength, _length-halfLength);
+
+ for(i = 0; i < _length; i++)
+ {
+ if(compareFields(firstHalf[fp],lastHalf[lp]) < 0)
+ {
+ sorted[i] = firstHalf[fp++];
+ if(fp == halfLength)
+ {
+ for( i++; i < _length; i++)
+ {
+ sorted[i] = lastHalf[lp++];
+ }
+ break;
+ }
+ }
+ else
+ {
+ sorted[i] = lastHalf[lp++];
+ if(lp == _length - halfLength)
+ {
+ for( i++; i < _length; i++)
+ {
+ sorted[i] = firstHalf[fp++];
+ }
+ break;
+ }
+ }
+ }
+ if(_length == size)
+ {
+ fields.reset(sorted);
+ }
+ delete firstHalf;
+ delete lastHalf;
+ }
+ return sorted;
+}
+
+sal_Int32 MacabHeader::compareFields(const macabfield *_field1, const macabfield *_field2)
+{
+ /* Comparing two fields in a MacabHeader is different than comparing two
+ * fields in a MacabRecord. It starts in the same way (if one of the two
+ * fields is NULL, it belongs after the other, so it is considered
+ * "greater"). But, then, all headers are CFStrings, no matter what
+ * type they claim to be (since they actually hold the expected type for
+ * the records with that header). That being said, all we have to do is
+ * the built-in CFStringCompare.
+ */
+ if(_field1 == _field2)
+ return 0;
+ if(_field1 == nullptr)
+ return 1;
+ if(_field2 == nullptr)
+ return -1;
+
+ CFComparisonResult result = CFStringCompare(
+ static_cast<CFStringRef>(_field1->value),
+ static_cast<CFStringRef>(_field2->value),
+ 0); // 0 = no options (like ignore case)
+
+ return static_cast<sal_Int32>(result);
+}
+
+
+sal_Int32 MacabHeader::getColumnNumber(std::u16string_view s) const
+{
+ sal_Int32 i;
+ for(i = 0; i < size; i++)
+ {
+ if(getString(i) == s)
+ break;
+ }
+
+ if(i == size)
+ i = -1;
+
+ return i;
+}
+
+
+MacabHeader *MacabHeader::begin()
+{
+ return this;
+}
+
+
+MacabHeader::iterator::iterator ()
+{
+}
+
+
+MacabHeader::iterator& MacabHeader::iterator::operator= (MacabHeader *_record)
+{
+ id = 0;
+ record = _record;
+ return *this;
+}
+
+
+void MacabHeader::iterator::operator++ ()
+{
+ id++;
+}
+
+
+bool MacabHeader::iterator::operator!= (const sal_Int32 i) const
+{
+ return(id != i);
+}
+
+
+bool MacabHeader::iterator::operator== (const sal_Int32 i) const
+{
+ return(id == i);
+}
+
+
+macabfield *MacabHeader::iterator::operator* () const
+{
+ return record->get(id);
+}
+
+
+sal_Int32 MacabHeader::end() const
+{
+ return size;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabHeader.hxx b/connectivity/source/drivers/macab/MacabHeader.hxx
new file mode 100644
index 000000000..24b3fc7b0
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabHeader.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "MacabRecord.hxx"
+
+namespace connectivity::macab
+{
+ class MacabHeader: public MacabRecord{
+ protected:
+ macabfield **sortRecord(sal_Int32 _start, sal_Int32 _length);
+ public:
+ MacabHeader();
+ MacabHeader(const sal_Int32 _size, macabfield **_fields);
+ virtual ~MacabHeader() override;
+ void operator+= (const MacabHeader *r);
+ OUString getString(const sal_Int32 i) const;
+ void sortRecord();
+ sal_Int32 getColumnNumber(std::u16string_view s) const;
+
+ static sal_Int32 compareFields(const macabfield *_field1, const macabfield *_field2);
+
+ MacabHeader *begin();
+ sal_Int32 end() const;
+ class iterator{
+ protected:
+ sal_Int32 id;
+ MacabHeader *record;
+ public:
+ iterator& operator= (MacabHeader *_record);
+ iterator();
+ void operator++ ();
+ bool operator!= (const sal_Int32 i) const;
+ bool operator== (const sal_Int32 i) const;
+ macabfield *operator* () const;
+ };
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabPreparedStatement.cxx b/connectivity/source/drivers/macab/MacabPreparedStatement.cxx
new file mode 100644
index 000000000..6d72345b6
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabPreparedStatement.cxx
@@ -0,0 +1,343 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabPreparedStatement.hxx"
+#include "MacabAddressBook.hxx"
+#include <propertyids.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+
+using namespace connectivity::macab;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::util;
+
+IMPLEMENT_SERVICE_INFO(MacabPreparedStatement, "com.sun.star.sdbc.drivers.MacabPreparedStatement", "com.sun.star.sdbc.PreparedStatement");
+
+void MacabPreparedStatement::checkAndResizeParameters(sal_Int32 nParams)
+{
+ if ( !m_aParameterRow.is() )
+ m_aParameterRow = new OValueVector();
+
+ if (nParams < 1)
+ ::dbtools::throwInvalidIndexException(*this);
+
+ if (nParams >= static_cast<sal_Int32>(m_aParameterRow->size()))
+ m_aParameterRow->resize(nParams);
+}
+
+void MacabPreparedStatement::setMacabFields() const
+{
+ ::rtl::Reference<connectivity::OSQLColumns> xColumns; // selected columns
+
+ xColumns = m_aSQLIterator.getSelectColumns();
+ if (!xColumns.is())
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(
+ STR_INVALID_COLUMN_SELECTION
+ ) );
+ ::dbtools::throwGenericSQLException(sError,nullptr);
+ }
+ m_xMetaData->setMacabFields(xColumns);
+}
+
+void MacabPreparedStatement::resetParameters() const
+{
+ m_nParameterIndex = 0;
+}
+
+void MacabPreparedStatement::getNextParameter(OUString &rParameter) const
+{
+ if (m_nParameterIndex >= static_cast<sal_Int32>(m_aParameterRow->size()))
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(
+ STR_INVALID_PARA_COUNT
+ ) );
+ ::dbtools::throwGenericSQLException(sError,*const_cast<MacabPreparedStatement *>(this));
+ }
+
+ rParameter = (*m_aParameterRow)[m_nParameterIndex].getString();
+
+ m_nParameterIndex++;
+}
+
+MacabPreparedStatement::MacabPreparedStatement(
+ MacabConnection* _pConnection,
+ const OUString& sql)
+ : MacabPreparedStatement_BASE(_pConnection),
+ m_sSqlStatement(sql),
+ m_bPrepared(false),
+ m_nParameterIndex(0),
+ m_aParameterRow()
+{
+
+}
+
+MacabPreparedStatement::~MacabPreparedStatement()
+{
+}
+
+void MacabPreparedStatement::disposing()
+{
+ MacabPreparedStatement_BASE::disposing();
+
+ if (m_aParameterRow.is())
+ {
+ m_aParameterRow->clear();
+ m_aParameterRow = nullptr;
+ }
+}
+
+Reference< XResultSetMetaData > SAL_CALL MacabPreparedStatement::getMetaData()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
+
+ if (!m_xMetaData.is())
+ {
+ const OSQLTables& xTabs = m_aSQLIterator.getTables();
+ OUString sTableName = MacabAddressBook::getDefaultTableName();
+
+ if(! xTabs.empty() )
+ {
+
+ // can only deal with one table at a time
+ if(xTabs.size() == 1 && !m_aSQLIterator.hasErrors() )
+ sTableName = xTabs.begin()->first;
+
+ }
+ m_xMetaData = new MacabResultSetMetaData(getOwnConnection(),sTableName);
+ setMacabFields();
+ }
+ Reference< XResultSetMetaData > xMetaData = m_xMetaData;
+ return xMetaData;
+}
+
+void SAL_CALL MacabPreparedStatement::close()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
+
+ // Reset last warning message
+ try {
+ clearWarnings ();
+ MacabCommonStatement::close();
+ }
+ catch (SQLException &) {
+ // If we get an error, ignore
+ }
+
+ // Remove this Statement object from the Connection object's
+ // list
+}
+
+sal_Bool SAL_CALL MacabPreparedStatement::execute()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
+
+ Reference< XResultSet> xRS = MacabCommonStatement::executeQuery(m_sSqlStatement);
+
+ return xRS.is();
+}
+
+sal_Int32 SAL_CALL MacabPreparedStatement::executeUpdate()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
+
+ // same as in statement with the difference that this statement also can contain parameter
+ return 0;
+}
+
+Reference< XConnection > SAL_CALL MacabPreparedStatement::getConnection()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
+
+ return m_pConnection;
+}
+
+Reference< XResultSet > SAL_CALL MacabPreparedStatement::executeQuery()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
+
+ Reference< XResultSet > rs = MacabCommonStatement::executeQuery(m_sSqlStatement);
+
+ return rs;
+}
+
+void SAL_CALL MacabPreparedStatement::setNull(sal_Int32 parameterIndex, sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
+
+ checkAndResizeParameters(parameterIndex);
+
+ (*m_aParameterRow)[parameterIndex - 1].setNull();
+}
+
+void SAL_CALL MacabPreparedStatement::setObjectNull(sal_Int32, sal_Int32, const OUString&)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setObjectNull", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setBoolean(sal_Int32, sal_Bool)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setBoolean", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setByte(sal_Int32, sal_Int8)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setByte", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setShort(sal_Int32, sal_Int16)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setShort", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setInt(sal_Int32, sal_Int32)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setInt", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setLong(sal_Int32, sal_Int64)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setLong", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setFloat(sal_Int32, float)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setFloat", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setDouble(sal_Int32, double)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setDouble", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setString(sal_Int32 parameterIndex, const OUString &x)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
+
+ checkAndResizeParameters(parameterIndex);
+
+ (*m_aParameterRow)[parameterIndex - 1] = x;
+}
+
+void SAL_CALL MacabPreparedStatement::setBytes(sal_Int32, const Sequence< sal_Int8 >&)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setBytes", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setDate(sal_Int32, const Date&)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setDate", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setTime(sal_Int32, const css::util::Time&)
+{
+
+ ::dbtools::throwFunctionNotSupportedSQLException("setTime", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setTimestamp(sal_Int32, const DateTime&)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setTimestamp", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setBinaryStream(sal_Int32, const Reference< css::io::XInputStream >&, sal_Int32)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setBinaryStream", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setCharacterStream(sal_Int32, const Reference< css::io::XInputStream >&, sal_Int32)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setCharacterStream", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setObject(sal_Int32 parameterIndex, const Any& x)
+{
+ if(!::dbtools::implSetObject(this,parameterIndex,x))
+ {
+ const OUString sError( m_pConnection->getResources().getResourceStringWithSubstitution(
+ STR_UNKNOWN_PARA_TYPE,
+ "$position$", OUString::number(parameterIndex)
+ ) );
+ ::dbtools::throwGenericSQLException(sError,*this);
+ }
+}
+
+void SAL_CALL MacabPreparedStatement::setObjectWithInfo(sal_Int32, const Any&, sal_Int32, sal_Int32)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setObjectWithInfo", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setRef(sal_Int32, const Reference< XRef >&)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setRef", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setBlob(sal_Int32, const Reference< XBlob >&)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setBlob", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setClob(sal_Int32, const Reference< XClob >&)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setClob", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::setArray(sal_Int32, const Reference< XArray >&)
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("setArray", nullptr);
+}
+
+void SAL_CALL MacabPreparedStatement::clearParameters()
+{
+ ::dbtools::throwFunctionNotSupportedSQLException("clearParameters", nullptr);
+}
+
+void MacabPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ break;
+ case PROPERTY_ID_RESULTSETTYPE:
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ break;
+ case PROPERTY_ID_USEBOOKMARKS:
+ break;
+ default:
+ MacabCommonStatement::setFastPropertyValue_NoBroadcast(nHandle,rValue);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabPreparedStatement.hxx b/connectivity/source/drivers/macab/MacabPreparedStatement.hxx
new file mode 100644
index 000000000..6e649bf64
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabPreparedStatement.hxx
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MacabStatement.hxx"
+#include "MacabResultSetMetaData.hxx"
+#include <connectivity/FValue.hxx>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace connectivity::macab
+{
+ typedef ::cppu::ImplInheritanceHelper< MacabCommonStatement,
+ css::sdbc::XPreparedStatement,
+ css::sdbc::XParameters,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::lang::XServiceInfo> MacabPreparedStatement_BASE;
+
+ class MacabPreparedStatement : public MacabPreparedStatement_BASE
+ {
+ protected:
+ OUString m_sSqlStatement;
+ ::rtl::Reference< MacabResultSetMetaData >
+ m_xMetaData;
+ bool m_bPrepared;
+ mutable sal_Int32 m_nParameterIndex;
+ OValueRow m_aParameterRow;
+
+ /// @throws css::sdbc::SQLException
+ void checkAndResizeParameters(sal_Int32 nParams);
+ /// @throws css::sdbc::SQLException
+ void setMacabFields() const;
+
+ protected:
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue) override;
+
+ virtual void resetParameters() const override;
+ virtual void getNextParameter(OUString &rParameter) const override;
+ virtual ~MacabPreparedStatement() override;
+
+ public:
+ DECLARE_SERVICE_INFO();
+ MacabPreparedStatement(MacabConnection* _pConnection, const OUString& sql);
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XPreparedStatement
+ using MacabCommonStatement::executeQuery;
+ using MacabCommonStatement::executeUpdate;
+ using MacabCommonStatement::execute;
+
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( ) override;
+ virtual sal_Int32 SAL_CALL executeUpdate( ) override;
+ virtual sal_Bool SAL_CALL execute( ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+
+ // XParameters
+ virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override;
+ virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override;
+ virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override;
+ virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override;
+ virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override;
+ virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override;
+ virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override;
+ virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override;
+ virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override;
+ virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override;
+ virtual void SAL_CALL clearParameters( ) override;
+
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabRecord.cxx b/connectivity/source/drivers/macab/MacabRecord.cxx
new file mode 100644
index 000000000..3072e1eaa
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabRecord.cxx
@@ -0,0 +1,336 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabRecord.hxx"
+#include "macabutilities.hxx"
+#include <com/sun/star/util/DateTime.hpp>
+
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <AddressBook/ABAddressBookC.h>
+#include <postmac.h>
+#include <connectivity/dbconversion.hxx>
+
+using namespace connectivity::macab;
+using namespace com::sun::star::util;
+using namespace ::dbtools;
+
+
+MacabRecord::MacabRecord() : size(0)
+{
+}
+
+
+MacabRecord::MacabRecord(const sal_Int32 _size)
+ : size(_size),
+ fields(std::make_unique<macabfield *[]>(size))
+{
+ sal_Int32 i;
+ for(i = 0; i < size; i++)
+ fields[i] = nullptr;
+}
+
+
+MacabRecord::~MacabRecord()
+{
+ if(size > 0)
+ {
+ releaseFields();
+ int i;
+ for(i = 0; i < size; i++)
+ {
+ delete fields[i];
+ fields[i] = nullptr;
+ }
+ }
+}
+
+
+void MacabRecord::insertAtColumn (CFTypeRef _value, ABPropertyType _type, const sal_Int32 _column)
+{
+ if(_column < size)
+ {
+ if(fields[_column] == nullptr)
+ fields[_column] = new macabfield;
+
+ fields[_column]->value = _value;
+ if (fields[_column]->value)
+ CFRetain(fields[_column]->value);
+ fields[_column]->type = _type;
+ }
+}
+
+
+bool MacabRecord::contains (const macabfield *_field) const
+{
+ if(_field == nullptr)
+ return false;
+ else
+ return contains(_field->value);
+}
+
+
+bool MacabRecord::contains (const CFTypeRef _value) const
+{
+ sal_Int32 i;
+ for(i = 0; i < size; i++)
+ {
+ if(fields[i] != nullptr)
+ {
+ if(CFEqual(fields[i]->value, _value))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+sal_Int32 MacabRecord::getSize() const
+{
+ return size;
+}
+
+
+macabfield *MacabRecord::copy(const sal_Int32 i) const
+{
+ /* Note: copy(i) creates a new macabfield identical to that at
+ * location i, whereas get(i) returns a pointer to the macabfield
+ * at location i.
+ */
+ if(i < size)
+ {
+ macabfield *_copy = new macabfield;
+ _copy->type = fields[i]->type;
+ _copy->value = fields[i]->value;
+ if (_copy->value)
+ CFRetain(_copy->value);
+ return _copy;
+ }
+
+ return nullptr;
+}
+
+
+macabfield *MacabRecord::get(const sal_Int32 i) const
+{
+ /* Note: copy(i) creates a new macabfield identical to that at
+ * location i, whereas get(i) returns a pointer to the macabfield
+ * at location i.
+ */
+ if(i < size)
+ {
+ return fields[i];
+ }
+
+ return nullptr;
+}
+
+
+void MacabRecord::releaseFields()
+{
+ /* This method is, at the moment, only used in MacabHeader.cxx, but
+ * the idea is simple: if you are not destroying this object but want
+ * to clear it of its macabfields, you should release each field's
+ * value.
+ */
+ sal_Int32 i;
+ for(i = 0; i < size; i++)
+ CFRelease(fields[i]->value);
+}
+
+
+sal_Int32 MacabRecord::compareFields(const macabfield *_field1, const macabfield *_field2)
+{
+
+ /* When comparing records, if either field is NULL (and the other is
+ * not), that field is considered "greater than" the other, so that it
+ * shows up later in the list when fields are ordered.
+ */
+ if(_field1 == _field2)
+ return 0;
+ if(_field1 == nullptr)
+ return 1;
+ if(_field2 == nullptr)
+ return -1;
+
+ /* If they aren't the same type, for now, return the one with
+ * the smaller type ID... I don't know of a better way to compare
+ * two different data types.
+ */
+ if(_field1->type != _field2->type)
+ return(_field1->type - _field2->type);
+
+ CFComparisonResult result;
+
+ /* Carbon has a unique compare function for each data type: */
+ switch(_field1->type)
+ {
+ case kABStringProperty:
+ result = CFStringCompare(
+ static_cast<CFStringRef>(_field1->value),
+ static_cast<CFStringRef>(_field2->value),
+ kCFCompareLocalized); // Specifies that the comparison should take into account differences related to locale, such as the thousands separator character.
+ break;
+
+ case kABDateProperty:
+ result = CFDateCompare(
+ static_cast<CFDateRef>(_field1->value),
+ static_cast<CFDateRef>(_field2->value),
+ nullptr); // NULL = unused variable
+ break;
+
+ case kABIntegerProperty:
+ case kABRealProperty:
+ result = CFNumberCompare(
+ static_cast<CFNumberRef>(_field1->value),
+ static_cast<CFNumberRef>(_field2->value),
+ nullptr); // NULL = unused variable
+ break;
+
+ default:
+ result = kCFCompareEqualTo; // can't compare
+ }
+
+ return static_cast<sal_Int32>(result);
+}
+
+
+/* Create a macabfield out of an OUString and type. Together with the
+ * method fieldToString() (below), it is possible to switch conveniently
+ * between an OUString and a macabfield (for use when creating and handling
+ * SQL statement).
+ */
+macabfield *MacabRecord::createMacabField(const OUString& _newFieldString, const ABPropertyType _abType)
+{
+ macabfield *newField = nullptr;
+ switch(_abType)
+ {
+ case kABStringProperty:
+ newField = new macabfield;
+ newField->value = OUStringToCFString(_newFieldString);
+ newField->type = _abType;
+ break;
+ case kABDateProperty:
+ {
+ DateTime aDateTime = DBTypeConversion::toDateTime(_newFieldString);
+
+ // bad format...
+ if(aDateTime.Year == 0 && aDateTime.Month == 0 && aDateTime.Day == 0)
+ {
+ }
+ else
+ {
+ double nTime = DBTypeConversion::toDouble(aDateTime, DBTypeConversion::getStandardDate());
+ nTime -= kCFAbsoluteTimeIntervalSince1970;
+ newField = new macabfield;
+ newField->value = CFDateCreate(nullptr, static_cast<CFAbsoluteTime>(nTime));
+ newField->type = _abType;
+ }
+ }
+ break;
+ case kABIntegerProperty:
+ try
+ {
+ sal_Int64 nVal = _newFieldString.toInt64();
+
+ newField = new macabfield;
+ newField->value = CFNumberCreate(nullptr,kCFNumberLongType, &nVal);
+ newField->type = _abType;
+ }
+ // bad format...
+ catch(...)
+ {
+ }
+ break;
+ case kABRealProperty:
+ try
+ {
+ double nVal = _newFieldString.toDouble();
+
+ newField = new macabfield;
+ newField->value = CFNumberCreate(nullptr,kCFNumberDoubleType, &nVal);
+ newField->type = _abType;
+ }
+ // bad format...
+ catch(...)
+ {
+ }
+ break;
+ default:
+ ;
+ }
+ return newField;
+}
+
+
+/* Create an OUString out of a macabfield. Together with the method
+ * createMacabField() (above), it is possible to switch conveniently
+ * between an OUString and a macabfield (for use when creating and handling
+ * SQL statement).
+ */
+OUString MacabRecord::fieldToString(const macabfield *_aField)
+{
+ if(_aField == nullptr)
+ return OUString();
+
+ OUString fieldString;
+
+ switch(_aField->type)
+ {
+ case kABStringProperty:
+ fieldString = CFStringToOUString(static_cast<CFStringRef>(_aField->value));
+ break;
+ case kABDateProperty:
+ {
+ DateTime aTime = CFDateToDateTime(static_cast<CFDateRef>(_aField->value));
+ fieldString = DBTypeConversion::toDateTimeString(aTime);
+ }
+ break;
+ case kABIntegerProperty:
+ {
+ CFNumberType numberType = CFNumberGetType( static_cast<CFNumberRef>(_aField->value) );
+ sal_Int64 nVal;
+ // Should we check for the wrong type here, e.g., a float?
+ bool m_bSuccess = !CFNumberGetValue(static_cast<CFNumberRef>(_aField->value), numberType, &nVal);
+ if(m_bSuccess)
+ fieldString = OUString::number(nVal);
+ }
+ break;
+ case kABRealProperty:
+ {
+ CFNumberType numberType = CFNumberGetType( static_cast<CFNumberRef>(_aField->value) );
+ double nVal;
+ // Should we check for the wrong type here, e.g., an int?
+ bool m_bSuccess = !CFNumberGetValue(static_cast<CFNumberRef>(_aField->value), numberType, &nVal);
+ if(m_bSuccess)
+ fieldString = OUString::number(nVal);
+ }
+ break;
+ default:
+ ;
+ }
+ return fieldString;
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabRecord.hxx b/connectivity/source/drivers/macab/MacabRecord.hxx
new file mode 100644
index 000000000..5184eefc8
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabRecord.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <sal/types.h>
+#include <osl/diagnose.h>
+#include <rtl/ustring.hxx>
+
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <AddressBook/ABAddressBookC.h>
+#include <postmac.h>
+
+namespace connectivity::macab
+{
+ /* a MacabRecord is at root a list of macabfields (which is just
+ * something to hold both a CFTypeRef (a CoreFoundation object) and
+ * its Address Book type.
+ */
+ struct macabfield
+ {
+ CFTypeRef value;
+ ABPropertyType type;
+ };
+
+ class MacabRecord{
+ protected:
+ sal_Int32 size;
+ std::unique_ptr<macabfield *[]> fields;
+ protected:
+ void releaseFields();
+ public:
+ MacabRecord();
+ explicit MacabRecord(const sal_Int32 _size);
+ virtual ~MacabRecord();
+ void insertAtColumn (CFTypeRef _value, ABPropertyType _type, const sal_Int32 _column);
+ bool contains(const macabfield *_field) const;
+ bool contains(const CFTypeRef _value) const;
+ sal_Int32 getSize() const;
+ macabfield *copy(const sal_Int32 i) const;
+ macabfield *get(const sal_Int32 i) const;
+
+ static sal_Int32 compareFields(const macabfield *_field1, const macabfield *_field2);
+ static macabfield *createMacabField(const OUString& _newFieldString, const ABPropertyType _abtype);
+ static OUString fieldToString(const macabfield *_aField);
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabRecords.cxx b/connectivity/source/drivers/macab/MacabRecords.cxx
new file mode 100644
index 000000000..17ee6585d
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabRecords.cxx
@@ -0,0 +1,1160 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "MacabRecords.hxx"
+#include "MacabRecord.hxx"
+#include "MacabHeader.hxx"
+#include "macabutilities.hxx"
+
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <AddressBook/ABAddressBookC.h>
+#include <postmac.h>
+#include <com/sun/star/util/DateTime.hpp>
+
+using namespace connectivity::macab;
+using namespace com::sun::star::util;
+
+namespace {
+
+void manageDuplicateHeaders(macabfield **_headerNames, const sal_Int32 _length)
+{
+ /* If we have two cases of, say, phone: home, this makes it:
+ * phone: home (1)
+ * phone: home (2)
+ */
+ sal_Int32 i, j;
+ sal_Int32 count;
+ for(i = _length-1; i >= 0; i--)
+ {
+ count = 1;
+ for( j = i-1; j >= 0; j--)
+ {
+ if(CFEqual(_headerNames[i]->value, _headerNames[j]->value))
+ {
+ count++;
+ }
+ }
+
+ // duplicate!
+ if(count != 1)
+ {
+ // There is probably a better way to do this...
+ OUString newName = CFStringToOUString(static_cast<CFStringRef>(_headerNames[i]->value));
+ CFRelease(_headerNames[i]->value);
+ newName += " (" + OUString::number(count) + ")";
+ _headerNames[i]->value = OUStringToCFString(newName);
+ }
+ }
+}
+
+}
+
+MacabRecords::MacabRecords(const ABAddressBookRef _addressBook, MacabHeader *_header, MacabRecord **_records, sal_Int32 _numRecords)
+ : recordsSize(_numRecords), currentRecord(_numRecords), recordType(kABPersonRecordType),
+ header(_header), records(_records), addressBook(_addressBook)
+{
+ /* Variables constructed... */
+ bootstrap_CF_types();
+ bootstrap_requiredProperties();
+}
+
+
+/* Creates a MacabRecords from another: copies the length, name, and
+ * address book of the original, but the header or the records themselves.
+ * The idea is that the only reason to copy a MacabRecords is to create
+ * a filtered version of it, which can have the same length (to avoid
+ * resizing) and will work from the same base addressbook, but might have
+ * entirely different values and even (possibly in the future) a different
+ * header.
+ */
+MacabRecords::MacabRecords(const MacabRecords *_copy)
+ : recordsSize(_copy->recordsSize), currentRecord(0), recordType(kABPersonRecordType),
+ header(nullptr), records(new MacabRecord *[recordsSize]), addressBook(_copy->addressBook),
+ m_sName(_copy->m_sName)
+{
+ /* Variables constructed... */
+ bootstrap_CF_types();
+ bootstrap_requiredProperties();
+}
+
+
+MacabRecords::MacabRecords(const ABAddressBookRef _addressBook)
+ : recordsSize(0), currentRecord(0), recordType(kABPersonRecordType),
+ header(nullptr), records(nullptr), addressBook(_addressBook)
+{
+ /* Variables constructed... */
+ bootstrap_CF_types();
+ bootstrap_requiredProperties();
+}
+
+
+void MacabRecords::initialize()
+{
+
+ /* Make sure everything is NULL before initializing. (We usually just
+ * initialize after we use the constructor that takes only a
+ * MacabAddressBook, so these variables will most likely already be
+ * NULL.
+ */
+ if(records != nullptr)
+ {
+ sal_Int32 i;
+
+ for(i = 0; i < recordsSize; i++)
+ delete records[i];
+
+ delete [] records;
+ }
+
+ if(header != nullptr)
+ delete header;
+
+ /* We can handle both default record Address Book record types in
+ * this method, though only kABPersonRecordType is ever used.
+ */
+ CFArrayRef allRecords;
+ if(CFStringCompare(recordType, kABPersonRecordType, 0) == kCFCompareEqualTo)
+ allRecords = ABCopyArrayOfAllPeople(addressBook);
+ else
+ allRecords = ABCopyArrayOfAllGroups(addressBook);
+
+ ABRecordRef record;
+ sal_Int32 i;
+ recordsSize = static_cast<sal_Int32>(CFArrayGetCount(allRecords));
+ records = new MacabRecord *[recordsSize];
+
+ /* First, we create the header... */
+ header = createHeaderForRecordType(allRecords, recordType);
+
+ /* Then, we create each of the records... */
+ for(i = 0; i < recordsSize; i++)
+ {
+ record = const_cast<ABRecordRef>(CFArrayGetValueAtIndex(allRecords, i));
+ records[i] = createMacabRecord(record, header, recordType);
+ }
+ currentRecord = recordsSize;
+
+ CFRelease(allRecords);
+}
+
+
+MacabRecords::~MacabRecords()
+{
+}
+
+
+void MacabRecords::setHeader(MacabHeader *_header)
+{
+ if(header != nullptr)
+ delete header;
+ header = _header;
+}
+
+
+MacabHeader *MacabRecords::getHeader() const
+{
+ return header;
+}
+
+
+/* Inserts a MacabRecord at a given location. If there is already a
+ * MacabRecord at that location, return it.
+ */
+MacabRecord *MacabRecords::insertRecord(MacabRecord *_newRecord, const sal_Int32 _location)
+{
+ MacabRecord *oldRecord;
+
+ /* If the location is greater than the current allocated size of this
+ * MacabRecords, allocate more space.
+ */
+ if(_location >= recordsSize)
+ {
+ sal_Int32 i;
+ MacabRecord **newRecordsArray = new MacabRecord *[_location+1];
+ for(i = 0; i < recordsSize; i++)
+ {
+ newRecordsArray[i] = records[i];
+ }
+ delete [] records;
+ records = newRecordsArray;
+ }
+
+ /* Remember: currentRecord refers to one above the highest existing
+ * record (i.e., it refers to where to place the next record if a
+ * location is not given).
+ */
+ if(_location >= currentRecord)
+ currentRecord = _location+1;
+
+ oldRecord = records[_location];
+ records[_location] = _newRecord;
+ return oldRecord;
+}
+
+
+/* Insert a record at the next available place. */
+void MacabRecords::insertRecord(MacabRecord *_newRecord)
+{
+ insertRecord(_newRecord, currentRecord);
+}
+
+
+MacabRecord *MacabRecords::getRecord(const sal_Int32 _location) const
+{
+ if(_location >= recordsSize)
+ return nullptr;
+ return records[_location];
+}
+
+
+macabfield *MacabRecords::getField(const sal_Int32 _recordNumber, const sal_Int32 _columnNumber) const
+{
+ if(_recordNumber >= recordsSize)
+ return nullptr;
+
+ MacabRecord *record = records[_recordNumber];
+
+ if(_columnNumber < 0 || _columnNumber >= record->getSize())
+ return nullptr;
+
+ return record->get(_columnNumber);
+}
+
+
+macabfield *MacabRecords::getField(const sal_Int32 _recordNumber, std::u16string_view _columnName)
+ const
+{
+ if(header != nullptr)
+ {
+ sal_Int32 columnNumber = header->getColumnNumber(_columnName);
+ if(columnNumber == -1)
+ return nullptr;
+
+ return getField(_recordNumber, columnNumber);
+ }
+ else
+ {
+ // error: shouldn't access field with null header!
+ return nullptr;
+ }
+}
+
+
+sal_Int32 MacabRecords::getFieldNumber(std::u16string_view _columnName) const
+{
+ if(header != nullptr)
+ return header->getColumnNumber(_columnName);
+ else
+ // error: shouldn't access field with null header!
+ return -1;
+}
+
+
+/* Create the lcl_CFTypes array -- we need this because there is no
+ * way to get the ABType of an object from the object itself, and the
+ * function ABTypeOfProperty can't handle multiple levels of data
+ * (e.g., it can tell us that "address" is of type
+ * kABDictionaryProperty, but it cannot tell us that all of the keys
+ * and values in the dictionary have type kABStringProperty. On the
+ * other hand, we _can_ get the CFType out of any object.
+ * Unfortunately, all information about CFTypeIDs comes with the
+ * warning that they change between releases, so we build them
+ * ourselves here. (The one that we can't build is for multivalues,
+ * e.g., kABMultiStringProperty. All of these appear to have the
+ * same type: 1, but there is no function that I've found to give
+ * us that dynamically in case that number ever changes.
+ */
+void MacabRecords::bootstrap_CF_types()
+{
+ lcl_CFTypes = {
+ {CFNumberGetTypeID(), kABIntegerProperty},
+ {CFStringGetTypeID(), kABStringProperty},
+ {CFDateGetTypeID(), kABDateProperty},
+ {CFArrayGetTypeID(), kABArrayProperty},
+ {CFDictionaryGetTypeID(), kABDictionaryProperty},
+ {CFDataGetTypeID(), kABDataProperty}};
+}
+
+
+/* This is based on the possible fields required in the mail merge template
+ * in sw. If the fields possible there change, it would be optimal to
+ * change these fields as well.
+ */
+void MacabRecords::bootstrap_requiredProperties()
+{
+ requiredProperties = {
+ kABTitleProperty, kABFirstNameProperty, kABLastNameProperty, kABOrganizationProperty,
+ kABAddressProperty, kABPhoneProperty, kABEmailProperty};
+}
+
+
+/* Create the header for a given record type and a given array of records.
+ * Because the array of records and the record type are given, if you want
+ * to, you can run this method on the members of a group, or on any other
+ * filtered list of people and get a header relevant to them (e.g., if
+ * they only have home addresses, the work address fields won't show up).
+ */
+MacabHeader *MacabRecords::createHeaderForRecordType(const CFArrayRef _records, const CFStringRef _recordType) const
+{
+ /* We have two types of properties for a given record type, nonrequired
+ * and required. Required properties are ones that will show up whether
+ * or not they are empty. Nonrequired properties will only show up if
+ * at least one record in the set has that property filled. The reason
+ * is that some properties, like the kABTitleProperty are required by
+ * the mail merge wizard (in module sw) but are by default not shown in
+ * the macOS address book, so they would be weeded out at this stage
+ * and not shown if they were not required.
+ *
+ * Note: with the addition of required properties, I am not sure that
+ * this method still works for kABGroupRecordType (since the required
+ * properties are all for kABPersonRecordType).
+ *
+ * Note: required properties are constructed in the method
+ * bootstrap_requiredProperties() (above).
+ */
+ CFArrayRef allProperties = ABCopyArrayOfPropertiesForRecordType(addressBook, _recordType);
+ CFStringRef *nonRequiredProperties;
+ sal_Int32 numRecords = static_cast<sal_Int32>(CFArrayGetCount(_records));
+ sal_Int32 numProperties = static_cast<sal_Int32>(CFArrayGetCount(allProperties));
+ sal_Int32 numNonRequiredProperties = numProperties - requiredProperties.size();
+
+ /* While searching through the properties for required properties, these
+ * sal_Bools will keep track of what we have found.
+ */
+ bool bFoundRequiredProperties[requiredProperties.size()];
+
+
+ /* We have three MacabHeaders: headerDataForProperty is where we
+ * store the result of createHeaderForProperty(), which return a
+ * MacabHeader for a single property. lcl_header is where we store
+ * the MacabHeader that we are constructing. And, nonRequiredHeader
+ * is where we construct the MacabHeader for non-required properties,
+ * so that we can sort them before adding them to lcl_header.
+ */
+ MacabHeader *headerDataForProperty;
+ MacabHeader *lcl_header = new MacabHeader();
+ MacabHeader *nonRequiredHeader = new MacabHeader();
+
+ /* Other variables... */
+ sal_Int32 k;
+ ABRecordRef record;
+ CFStringRef property;
+
+
+ /* Allocate and initialize... */
+ nonRequiredProperties = new CFStringRef[numNonRequiredProperties];
+ k = 0;
+ for(std::vector<CFStringRef>::size_type i = 0; i < requiredProperties.size(); i++)
+ bFoundRequiredProperties[i] = false;
+
+ /* Determine the non-required properties... */
+ for(sal_Int32 i = 0; i < numProperties; i++)
+ {
+ bool bFoundProperty = false;
+ property = static_cast<CFStringRef>(CFArrayGetValueAtIndex(allProperties, i));
+ for(std::vector<CFStringRef>::size_type j = 0; j < requiredProperties.size(); j++)
+ {
+ if(CFEqual(property, requiredProperties[j]))
+ {
+ bFoundProperty = true;
+ bFoundRequiredProperties[j] = true;
+ break;
+ }
+ }
+
+ if(!bFoundProperty)
+ {
+ /* If we have found too many non-required properties */
+ if(k == numNonRequiredProperties)
+ {
+ k++; // so that the OSL_ENSURE below fails
+ break;
+ }
+ nonRequiredProperties[k] = property;
+ k++;
+ }
+ }
+
+ // Somehow, we got too many or too few non-required properties...
+ // Most likely, one of the required properties no longer exists, which
+ // we also test later.
+ OSL_ENSURE(k == numNonRequiredProperties, "MacabRecords::createHeaderForRecordType: Found an unexpected number of non-required properties");
+
+ /* Fill the header with required properties first... */
+ for(std::vector<CFStringRef>::size_type i = 0; i < requiredProperties.size(); i++)
+ {
+ if(bFoundRequiredProperties[i])
+ {
+ /* The order of these matters (we want all address properties
+ * before any phone properties, or else things will look weird),
+ * so we get all possibilities for each property, going through
+ * each record, and then go onto the next property.
+ * (Note: the reason that we have to go through all records
+ * in the first place is that properties like address, phone, and
+ * e-mail are multi-value properties with an unknown number of
+ * values. A user could specify thirteen different kinds of
+ * e-mail addresses for one of her or his contacts, and we need to
+ * get all of them.
+ */
+ for(sal_Int32 j = 0; j < numRecords; j++)
+ {
+ record = const_cast<ABRecordRef>(CFArrayGetValueAtIndex(_records, j));
+ headerDataForProperty = createHeaderForProperty(record,requiredProperties[i],_recordType,true);
+ if(headerDataForProperty != nullptr)
+ {
+ (*lcl_header) += headerDataForProperty;
+ delete headerDataForProperty;
+ }
+ }
+ }
+ else
+ {
+ // Couldn't find a required property...
+ OSL_FAIL(OString("MacabRecords::createHeaderForRecordType: could not find required property: " +
+ OUStringToOString(CFStringToOUString(requiredProperties[i]), RTL_TEXTENCODING_ASCII_US)).getStr());
+ }
+ }
+
+ /* And now, non-required properties... */
+ for(sal_Int32 i = 0; i < numRecords; i++)
+ {
+ record = const_cast<ABRecordRef>(CFArrayGetValueAtIndex(_records, i));
+
+ for(sal_Int32 j = 0; j < numNonRequiredProperties; j++)
+ {
+ property = nonRequiredProperties[j];
+ headerDataForProperty = createHeaderForProperty(record,property,_recordType,false);
+ if(headerDataForProperty != nullptr)
+ {
+ (*nonRequiredHeader) += headerDataForProperty;
+ delete headerDataForProperty;
+ }
+ }
+
+ }
+ nonRequiredHeader->sortRecord();
+
+ (*lcl_header) += nonRequiredHeader;
+ delete nonRequiredHeader;
+
+ CFRelease(allProperties);
+ delete [] nonRequiredProperties;
+
+ return lcl_header;
+}
+
+
+/* Create a header for a single property. Basically, this method gets
+ * the property's value and type and then calls another method of
+ * the same name to do the dirty work.
+ */
+MacabHeader *MacabRecords::createHeaderForProperty(const ABRecordRef _record, const CFStringRef _propertyName, const CFStringRef _recordType, const bool _isPropertyRequired) const
+{
+ // local variables
+ CFStringRef localizedPropertyName;
+ CFTypeRef propertyValue;
+ ABPropertyType propertyType;
+ MacabHeader *result;
+
+ /* Get the property's value */
+ propertyValue = ABRecordCopyValue(_record,_propertyName);
+ if(propertyValue == nullptr && !_isPropertyRequired)
+ return nullptr;
+
+ propertyType = ABTypeOfProperty(addressBook, _recordType, _propertyName);
+ localizedPropertyName = ABCopyLocalizedPropertyOrLabel(_propertyName);
+
+ result = createHeaderForProperty(propertyType, propertyValue, localizedPropertyName);
+
+ if(propertyValue != nullptr)
+ CFRelease(propertyValue);
+
+ return result;
+}
+
+
+/* Create a header for a single property. This method is recursive
+ * because a single property might contain several sub-properties that
+ * we also want to treat singly.
+ */
+MacabHeader *MacabRecords::createHeaderForProperty(const ABPropertyType _propertyType, const CFTypeRef _propertyValue, const CFStringRef _propertyName) const
+{
+ macabfield **headerNames = nullptr;
+ sal_Int32 length = 0;
+
+ switch(_propertyType)
+ {
+ /* Scalars */
+ case kABStringProperty:
+ case kABRealProperty:
+ case kABIntegerProperty:
+ case kABDateProperty:
+ length = 1;
+ headerNames = new macabfield *[1];
+ headerNames[0] = new macabfield;
+ headerNames[0]->value = _propertyName;
+ headerNames[0]->type = _propertyType;
+ break;
+
+ /* Multi-scalars */
+ case kABMultiIntegerProperty:
+ case kABMultiDateProperty:
+ case kABMultiStringProperty:
+ case kABMultiRealProperty:
+ case kABMultiDataProperty:
+ /* For non-scalars, we can only get more information if the property
+ * actually exists.
+ */
+ if(_propertyValue != nullptr)
+ {
+ sal_Int32 i;
+
+ sal_Int32 multiLength = ABMultiValueCount(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)));
+ CFStringRef multiLabel, localizedMultiLabel;
+ OUString multiLabelString;
+ OUString multiPropertyString;
+ OUString headerNameString;
+ ABPropertyType multiType = static_cast<ABPropertyType>(ABMultiValuePropertyType(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue))) - 0x100);
+
+ length = multiLength;
+ headerNames = new macabfield *[multiLength];
+ multiPropertyString = CFStringToOUString(_propertyName);
+
+ /* Go through each element, and - since each element is a scalar -
+ * just create a new macabfield for it.
+ */
+ for(i = 0; i < multiLength; i++)
+ {
+ multiLabel = ABMultiValueCopyLabelAtIndex(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)), i);
+ localizedMultiLabel = ABCopyLocalizedPropertyOrLabel(multiLabel);
+ multiLabelString = CFStringToOUString(localizedMultiLabel);
+ CFRelease(multiLabel);
+ CFRelease(localizedMultiLabel);
+ headerNameString = multiPropertyString + ": " + fixLabel(multiLabelString);
+ headerNames[i] = new macabfield;
+ headerNames[i]->value = OUStringToCFString(headerNameString);
+ headerNames[i]->type = multiType;
+ }
+ }
+ break;
+
+ /* Multi-array or dictionary */
+ case kABMultiArrayProperty:
+ case kABMultiDictionaryProperty:
+ /* For non-scalars, we can only get more information if the property
+ * actually exists.
+ */
+ if(_propertyValue != nullptr)
+ {
+ sal_Int32 i,j,k;
+
+ // Total number of multi-array or multi-dictionary elements.
+ sal_Int32 multiLengthFirstLevel = ABMultiValueCount(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)));
+
+ /* Total length, including the length of each element (e.g., if
+ * this multi-dictionary contains three dictionaries, and each
+ * dictionary has four elements, this variable will be twelve,
+ * whereas multiLengthFirstLevel will be three.
+ */
+ sal_Int32 multiLengthSecondLevel = 0;
+
+ CFStringRef multiLabel, localizedMultiLabel;
+ CFTypeRef multiValue;
+ OUString multiLabelString;
+ OUString multiPropertyString;
+ std::vector<std::unique_ptr<MacabHeader>> multiHeaders;
+ ABPropertyType multiType = static_cast<ABPropertyType>(ABMultiValuePropertyType(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue))) - 0x100);
+
+ multiPropertyString = CFStringToOUString(_propertyName);
+
+ /* Go through each element - since each element can really
+ * contain anything, we run this method again on each element
+ * and store the resulting MacabHeader (in the multiHeaders
+ * array). Then, all we'll have to do is combine the MacabHeaders
+ * into a single one.
+ */
+ for(i = 0; i < multiLengthFirstLevel; i++)
+ {
+ /* label */
+ multiLabel = ABMultiValueCopyLabelAtIndex(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)), i);
+ multiValue = ABMultiValueCopyValueAtIndex(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)), i);
+ std::unique_ptr<MacabHeader> hdr;
+ if(multiValue && multiLabel)
+ {
+ localizedMultiLabel = ABCopyLocalizedPropertyOrLabel(multiLabel);
+ multiLabelString = multiPropertyString + ": " + fixLabel(CFStringToOUString(localizedMultiLabel));
+ CFRelease(multiLabel);
+ CFRelease(localizedMultiLabel);
+ multiLabel = OUStringToCFString(multiLabelString);
+ hdr.reset(createHeaderForProperty(multiType, multiValue, multiLabel));
+ if (!hdr)
+ hdr = std::make_unique<MacabHeader>();
+ multiLengthSecondLevel += hdr->getSize();
+ }
+ else
+ {
+ hdr = std::make_unique<MacabHeader>();
+ }
+ if(multiValue)
+ CFRelease(multiValue);
+ if(multiLabel)
+ CFRelease(multiLabel);
+ multiHeaders.push_back(std::move(hdr));
+ }
+
+ /* We now have enough information to create our final MacabHeader.
+ * We go through each field of each header and add it to the
+ * headerNames array (which is what is used below to construct
+ * the MacabHeader we return).
+ */
+ length = multiLengthSecondLevel;
+ headerNames = new macabfield *[multiLengthSecondLevel];
+
+ for(i = 0, j = 0, k = 0; i < multiLengthSecondLevel; i++,k++)
+ {
+ while(multiHeaders[j]->getSize() == k)
+ {
+ j++;
+ k = 0;
+ }
+
+ headerNames[i] = multiHeaders[j]->copy(k);
+ }
+ }
+ break;
+
+ /* Dictionary */
+ case kABDictionaryProperty:
+ /* For non-scalars, we can only get more information if the property
+ * actually exists.
+ */
+ if(_propertyValue != nullptr)
+ {
+ /* Assume all keys are strings */
+ sal_Int32 numRecords = static_cast<sal_Int32>(CFDictionaryGetCount(static_cast<CFDictionaryRef>(_propertyValue)));
+
+ /* The only method for getting info out of a CFDictionary, of both
+ * keys and values, is to all of them all at once, so these
+ * variables will hold them.
+ */
+ CFStringRef *dictKeys;
+ CFTypeRef *dictValues;
+
+ sal_Int32 i,j,k;
+ OUString dictKeyString, propertyNameString;
+ ABPropertyType dictType;
+ MacabHeader **dictHeaders = new MacabHeader *[numRecords];
+ OUString dictLabelString;
+ CFStringRef dictLabel, localizedDictKey;
+
+ /* Get the keys and values */
+ dictKeys = static_cast<CFStringRef *>(malloc(sizeof(CFStringRef)*numRecords));
+ dictValues = static_cast<CFTypeRef *>(malloc(sizeof(CFTypeRef)*numRecords));
+ CFDictionaryGetKeysAndValues(static_cast<CFDictionaryRef>(_propertyValue), reinterpret_cast<const void **>(dictKeys), dictValues);
+
+ propertyNameString = CFStringToOUString(_propertyName);
+
+ length = 0;
+ /* Go through each element - assuming that the key is a string but
+ * that the value could be anything. Since the value could be
+ * anything, we can't assume that it is scalar (it could even be
+ * another dictionary), so we attempt to get its type using
+ * the method getABTypeFromCFType and then run this method
+ * recursively on that element, storing the MacabHeader that
+ * results. Then, we just combine all of the MacabHeaders into
+ * one.
+ */
+ for(i = 0; i < numRecords; i++)
+ {
+ dictType = getABTypeFromCFType( CFGetTypeID(dictValues[i]) );
+ localizedDictKey = ABCopyLocalizedPropertyOrLabel(dictKeys[i]);
+ dictKeyString = CFStringToOUString(localizedDictKey);
+ dictLabelString = propertyNameString + ": " + fixLabel(dictKeyString);
+ dictLabel = OUStringToCFString(dictLabelString);
+ dictHeaders[i] = createHeaderForProperty(dictType, dictValues[i], dictLabel);
+ if (!dictHeaders[i])
+ dictHeaders[i] = new MacabHeader();
+ length += dictHeaders[i]->getSize();
+ CFRelease(dictLabel);
+ CFRelease(localizedDictKey);
+ }
+
+ /* Combine all of the macabfields in each MacabHeader into the
+ * headerNames array, which (at the end of this method) is used
+ * to create the MacabHeader that is returned.
+ */
+ headerNames = new macabfield *[length];
+ for(i = 0, j = 0, k = 0; i < length; i++,k++)
+ {
+ while(dictHeaders[j]->getSize() == k)
+ {
+ j++;
+ k = 0;
+ }
+
+ headerNames[i] = dictHeaders[j]->copy(k);
+ }
+
+ for(i = 0; i < numRecords; i++)
+ delete dictHeaders[i];
+
+ delete [] dictHeaders;
+ free(dictKeys);
+ free(dictValues);
+ }
+ break;
+
+ /* Array */
+ case kABArrayProperty:
+ /* For non-scalars, we can only get more information if the property
+ * actually exists.
+ */
+ if(_propertyValue != nullptr)
+ {
+ sal_Int32 arrLength = static_cast<sal_Int32>(CFArrayGetCount(static_cast<CFArrayRef>(_propertyValue)));
+ sal_Int32 i,j,k;
+ CFTypeRef arrValue;
+ ABPropertyType arrType;
+ std::vector<std::unique_ptr<MacabHeader>> arrHeaders;
+ OUString propertyNameString = CFStringToOUString(_propertyName);
+ OUString arrLabelString;
+ CFStringRef arrLabel;
+
+ length = 0;
+ /* Go through each element - since the elements here do not have
+ * unique keys like the ones in dictionaries, we create a unique
+ * key out of the id of the element in the array (the first
+ * element gets a 0 plopped onto the end of it, the second a 1...
+ * As with dictionaries, the elements could be anything, including
+ * another array, so we have to run this method recursively on
+ * each element, storing the resulting MacabHeader into an array,
+ * which we then combine into one MacabHeader that is returned.
+ */
+ for(i = 0; i < arrLength; i++)
+ {
+ arrValue = CFArrayGetValueAtIndex(static_cast<CFArrayRef>(_propertyValue), i);
+ arrType = getABTypeFromCFType( CFGetTypeID(arrValue) );
+ arrLabelString = propertyNameString + OUString::number(i);
+ arrLabel = OUStringToCFString(arrLabelString);
+ auto hdr = std::unique_ptr<MacabHeader>(createHeaderForProperty(arrType, arrValue, arrLabel));
+ if (!hdr)
+ hdr = std::make_unique<MacabHeader>();
+ length += hdr->getSize();
+ CFRelease(arrLabel);
+ arrHeaders.push_back(std::move(hdr));
+ }
+
+ headerNames = new macabfield *[length];
+ for(i = 0, j = 0, k = 0; i < length; i++,k++)
+ {
+ while(arrHeaders[j]->getSize() == k)
+ {
+ j++;
+ k = 0;
+ }
+
+ headerNames[i] = arrHeaders[j]->copy(k);
+ }
+ }
+ break;
+
+ default:
+ break;
+
+ }
+
+ /* If we succeeded at adding elements to the headerNames array, then
+ * length will no longer be 0. If it is, create a new MacabHeader
+ * out of the headerNames (after weeding out duplicate headers), and
+ * then return the result. If the length is still 0, return NULL: we
+ * failed to create a MacabHeader out of this property.
+ */
+ if(length != 0)
+ {
+ manageDuplicateHeaders(headerNames, length);
+ MacabHeader *headerResult = new MacabHeader(length, headerNames);
+ for(sal_Int32 i = 0; i < length; ++i)
+ delete headerNames[i];
+ delete [] headerNames;
+ return headerResult;
+ }
+ else
+ return nullptr;
+}
+
+
+/* Create a MacabRecord out of an ABRecord, using a given MacabHeader and
+ * the record's type. We go through each property for this record type
+ * then process it much like we processed the header (above), with two
+ * exceptions: if we come upon something not in the header, we ignore it
+ * (it's something we don't want to add), and once we find a corresponding
+ * location in the header, we store the property and the property type in
+ * a macabfield. (For the header, we stored the property type and the name
+ * of the property as a CFString.)
+ */
+MacabRecord *MacabRecords::createMacabRecord(const ABRecordRef _abrecord, const MacabHeader *_header, const CFStringRef _recordType) const
+{
+ /* The new record that we will create... */
+ MacabRecord *macabRecord = new MacabRecord(_header->getSize());
+
+ CFArrayRef recordProperties = ABCopyArrayOfPropertiesForRecordType(addressBook, _recordType);
+ sal_Int32 numProperties = static_cast<sal_Int32>(CFArrayGetCount(recordProperties));
+
+ sal_Int32 i;
+
+ CFTypeRef propertyValue;
+ ABPropertyType propertyType;
+
+ CFStringRef propertyName, localizedPropertyName;
+ OUString propertyNameString;
+ for(i = 0; i < numProperties; i++)
+ {
+ propertyName = static_cast<CFStringRef>(CFArrayGetValueAtIndex(recordProperties, i));
+ localizedPropertyName = ABCopyLocalizedPropertyOrLabel(propertyName);
+ propertyNameString = CFStringToOUString(localizedPropertyName);
+ CFRelease(localizedPropertyName);
+
+ /* Get the property's value */
+ propertyValue = ABRecordCopyValue(_abrecord,propertyName);
+ if(propertyValue != nullptr)
+ {
+ propertyType = ABTypeOfProperty(addressBook, _recordType, propertyName);
+ if(propertyType != kABErrorInProperty)
+ insertPropertyIntoMacabRecord(propertyType, macabRecord, _header, propertyNameString, propertyValue);
+
+ CFRelease(propertyValue);
+ }
+ }
+ CFRelease(recordProperties);
+ return macabRecord;
+}
+
+
+/* Inserts a given property into a MacabRecord. This method calls another
+ * method by the same name after getting the property type (it only
+ * receives the property value). It is called when we aren't given the
+ * property's type already.
+ */
+void MacabRecords::insertPropertyIntoMacabRecord(MacabRecord *_abrecord, const MacabHeader *_header, const OUString& _propertyName, const CFTypeRef _propertyValue) const
+{
+ CFTypeID cf_type = CFGetTypeID(_propertyValue);
+ ABPropertyType ab_type = getABTypeFromCFType( cf_type );
+
+ if(ab_type != kABErrorInProperty)
+ insertPropertyIntoMacabRecord(ab_type, _abrecord, _header, _propertyName, _propertyValue);
+}
+
+
+/* Inserts a given property into a MacabRecord. This method is recursive
+ * because properties can contain many sub-properties.
+ */
+void MacabRecords::insertPropertyIntoMacabRecord(const ABPropertyType _propertyType, MacabRecord *_abrecord, const MacabHeader *_header, const OUString& _propertyName, const CFTypeRef _propertyValue) const
+{
+ /* If there is no value, return */
+ if(_propertyValue == nullptr)
+ return;
+
+ /* The main switch statement */
+ switch(_propertyType)
+ {
+ /* Scalars */
+ case kABStringProperty:
+ case kABRealProperty:
+ case kABIntegerProperty:
+ case kABDateProperty:
+ {
+ /* Only scalars actually insert a property into the MacabRecord.
+ * In all other cases, this method is called recursively until a
+ * scalar type, an error, or an unknown type are found.
+ * Because of that, the following checks only occur for this type.
+ * We store whether we have successfully placed this property
+ * into the MacabRecord (or whether an unrecoverable error occurred).
+ * Then, we try over and over again to place the property into the
+ * record. There are three possible results:
+ * 1) Success!
+ * 2) There is already a property stored at the column of this name,
+ * in which case we have a duplicate header (see the method
+ * manageDuplicateHeaders()). If that is the case, we add an ID
+ * to the end of the column name in the same format as we do in
+ * manageDuplicateHeaders() and try again.
+ * 3) No column of this name exists in the header. In this case,
+ * there is nothing we can do: we have failed to place this
+ * property into the record.
+ */
+ bool bPlaced = false;
+ OUString columnName = _propertyName;
+ sal_Int32 i = 1;
+
+ // A big safeguard to prevent two fields from having the same name.
+ while(!bPlaced)
+ {
+ sal_Int32 columnNumber = _header->getColumnNumber(columnName);
+ bPlaced = true;
+ if(columnNumber != -1)
+ {
+ // collision! A property already exists here!
+ if(_abrecord->get(columnNumber) != nullptr)
+ {
+ bPlaced = false;
+ i++;
+ columnName = _propertyName + " (" + OUString::number(i) + ")";
+ }
+
+ // success!
+ else
+ {
+ _abrecord->insertAtColumn(_propertyValue, _propertyType, columnNumber);
+ }
+ }
+ }
+ }
+ break;
+
+ /* Array */
+ case kABArrayProperty:
+ {
+ /* An array is basically just a list of anything, so all we do
+ * is go through the array, and rerun this method recursively
+ * on each element.
+ */
+ sal_Int32 arrLength = static_cast<sal_Int32>(CFArrayGetCount(static_cast<CFArrayRef>(_propertyValue)));
+ sal_Int32 i;
+ OUString newPropertyName;
+
+ /* Going through each element... */
+ for(i = 0; i < arrLength; i++)
+ {
+ const void *arrValue = CFArrayGetValueAtIndex(static_cast<CFArrayRef>(_propertyValue), i);
+ newPropertyName = _propertyName + OUString::number(i);
+ insertPropertyIntoMacabRecord(_abrecord, _header, newPropertyName, arrValue);
+ CFRelease(arrValue);
+ }
+
+ }
+ break;
+
+ /* Dictionary */
+ case kABDictionaryProperty:
+ {
+ /* A dictionary is basically a hashmap. Technically, it can
+ * hold any object as a key and any object as a value.
+ * For our case, we assume that the key is a string (so that
+ * we can use the key to get the column name and match it against
+ * the header), but we don't assume anything about the value, so
+ * we run this method recursively (or, rather, we run the version
+ * of this method for when we don't know the object's type) until
+ * we hit a scalar value.
+ */
+
+ sal_Int32 numRecords = static_cast<sal_Int32>(CFDictionaryGetCount(static_cast<CFDictionaryRef>(_propertyValue)));
+ OUString dictKeyString;
+ sal_Int32 i;
+ OUString newPropertyName;
+
+ /* Unfortunately, the only way to get both keys and values out
+ * of a dictionary in Carbon is to get them all at once, so we
+ * do that.
+ */
+ CFStringRef *dictKeys;
+ CFStringRef localizedDictKey;
+ CFTypeRef *dictValues;
+ dictKeys = static_cast<CFStringRef *>(malloc(sizeof(CFStringRef)*numRecords));
+ dictValues = static_cast<CFTypeRef *>(malloc(sizeof(CFTypeRef)*numRecords));
+ CFDictionaryGetKeysAndValues(static_cast<CFDictionaryRef>(_propertyValue), reinterpret_cast<const void **>(dictKeys), dictValues);
+
+ /* Going through each element... */
+ for(i = 0; i < numRecords; i++)
+ {
+ localizedDictKey = ABCopyLocalizedPropertyOrLabel(dictKeys[i]);
+ dictKeyString = CFStringToOUString(localizedDictKey);
+ CFRelease(localizedDictKey);
+ newPropertyName = _propertyName + ": " + fixLabel(dictKeyString);
+ insertPropertyIntoMacabRecord(_abrecord, _header, newPropertyName, dictValues[i]);
+ }
+
+ free(dictKeys);
+ free(dictValues);
+ }
+ break;
+
+ /* Multivalue */
+ case kABMultiIntegerProperty:
+ case kABMultiDateProperty:
+ case kABMultiStringProperty:
+ case kABMultiRealProperty:
+ case kABMultiDataProperty:
+ case kABMultiDictionaryProperty:
+ case kABMultiArrayProperty:
+ {
+ /* All scalar multivalues are handled in the same way. Each element
+ * is a label and a value. All labels are strings
+ * (kABStringProperty), and all values have the same type
+ * (which is the type of the multivalue minus 255, or as
+ * Carbon's list of property types has it, minus 0x100.
+ * We just get the correct type, then go through each element
+ * and get the label and value and print them in a list.
+ */
+
+ sal_Int32 i;
+ sal_Int32 multiLength = ABMultiValueCount(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)));
+ CFStringRef multiLabel, localizedMultiLabel;
+ CFTypeRef multiValue;
+ OUString multiLabelString, newPropertyName;
+ ABPropertyType multiType = static_cast<ABPropertyType>(ABMultiValuePropertyType(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue))) - 0x100);
+
+ /* Go through each element... */
+ for(i = 0; i < multiLength; i++)
+ {
+ /* Label and value */
+ multiLabel = ABMultiValueCopyLabelAtIndex(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)), i);
+ multiValue = ABMultiValueCopyValueAtIndex(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)), i);
+
+ localizedMultiLabel = ABCopyLocalizedPropertyOrLabel(multiLabel);
+ multiLabelString = CFStringToOUString(localizedMultiLabel);
+ newPropertyName = _propertyName + ": " + fixLabel(multiLabelString);
+ insertPropertyIntoMacabRecord(multiType, _abrecord, _header, newPropertyName, multiValue);
+
+ /* free our variables */
+ CFRelease(multiLabel);
+ CFRelease(localizedMultiLabel);
+ CFRelease(multiValue);
+ }
+ }
+ break;
+
+ /* Unhandled types */
+ case kABErrorInProperty:
+ case kABDataProperty:
+ default:
+ /* An error, as far as I have seen, only shows up as a type
+ * returned by a function for dictionaries when the dictionary
+ * holds many types of values. Since we do not use that function,
+ * it shouldn't come up. I have yet to see the kABDataProperty,
+ * and I am not sure how to represent it as a string anyway,
+ * since it appears to just be a bunch of bytes. Assumably, if
+ * these bytes made up a string, the type would be
+ * kABStringProperty. I think that this is used when we are not
+ * sure what the type is (e.g., it could be a string or a number).
+ * That being the case, I still don't know how to represent it.
+ * And, default should never come up, since we've exhausted all
+ * of the possible types for ABPropertyType, but... just in case.
+ */
+ break;
+ }
+
+}
+
+
+ABPropertyType MacabRecords::getABTypeFromCFType(const CFTypeID cf_type ) const
+{
+ for(auto const & i: lcl_CFTypes)
+ {
+ /* A match! */
+ if(i.cf == cf_type)
+ {
+ return static_cast<ABPropertyType>(i.ab);
+ }
+ }
+ return kABErrorInProperty;
+}
+
+
+sal_Int32 MacabRecords::size() const
+{
+ return currentRecord;
+}
+
+
+MacabRecords *MacabRecords::begin()
+{
+ return this;
+}
+
+
+MacabRecords::iterator::iterator ()
+{
+}
+
+
+MacabRecords::iterator& MacabRecords::iterator::operator= (MacabRecords *_records)
+{
+ id = 0;
+ records = _records;
+ return *this;
+}
+
+
+void MacabRecords::iterator::operator++ ()
+{
+ id++;
+}
+
+
+bool MacabRecords::iterator::operator!= (const sal_Int32 i) const
+{
+ return(id != i);
+}
+
+
+bool MacabRecords::iterator::operator== (const sal_Int32 i) const
+{
+ return(id == i);
+}
+
+
+MacabRecord *MacabRecords::iterator::operator* () const
+{
+ return records->getRecord(id);
+}
+
+
+sal_Int32 MacabRecords::end() const
+{
+ return currentRecord;
+}
+
+
+void MacabRecords::swap(const sal_Int32 _id1, const sal_Int32 _id2)
+{
+ MacabRecord *swapRecord = records[_id1];
+
+ records[_id1] = records[_id2];
+ records[_id2] = swapRecord;
+}
+
+
+void MacabRecords::setName(const OUString& _sName)
+{
+ m_sName = _sName;
+}
+
+
+OUString const & MacabRecords::getName() const
+{
+ return m_sName;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabRecords.hxx b/connectivity/source/drivers/macab/MacabRecords.hxx
new file mode 100644
index 000000000..8d0d5cf6f
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabRecords.hxx
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+#include <vector>
+
+#include "MacabRecord.hxx"
+#include "MacabHeader.hxx"
+
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <AddressBook/ABAddressBookC.h>
+#include <postmac.h>
+#include <com/sun/star/util/DateTime.hpp>
+
+namespace connectivity::macab
+{
+ /* This struct is for converting CF types to AB types (Core Foundation
+ * types to Address Book types).
+ */
+ struct lcl_CFType {
+ CFTypeID cf;
+ sal_Int32 ab;
+ };
+
+ class MacabRecords{
+ protected:
+ /* MacabRecords is, at its core, a table of macabfields, in the
+ * form of a header and a list of objects of type MacabRecord.
+ * It also has a unique name that refers to the name of the table.
+ */
+ sal_Int32 recordsSize;
+ sal_Int32 currentRecord;
+ CFStringRef recordType;
+ MacabHeader *header;
+ MacabRecord **records;
+ ABAddressBookRef addressBook;
+ OUString m_sName;
+
+ /* For converting CF types to AB types */
+ std::vector<lcl_CFType> lcl_CFTypes;
+
+ /* For required properties */
+ std::vector<CFStringRef> requiredProperties;
+
+ private:
+ /* All of the private methods are for creating a MacabHeader or a
+ * MacabRecord. They are used by the initialize method that goes
+ * about filling a MacabRecords using all of the records in the
+ * macOS Address Book.
+ */
+ void bootstrap_CF_types();
+ void bootstrap_requiredProperties();
+ MacabHeader *createHeaderForProperty(const ABRecordRef _record, const CFStringRef _propertyName, const CFStringRef _recordType, const bool _isPropertyRequired) const;
+ MacabHeader *createHeaderForProperty(const ABPropertyType _propertyType, const CFTypeRef _propertyValue, const CFStringRef _propertyName) const;
+ ABPropertyType getABTypeFromCFType(const CFTypeID cf_type ) const;
+ void insertPropertyIntoMacabRecord(MacabRecord *_abrecord, const MacabHeader *_header, const OUString& _propertyName, const CFTypeRef _propertyValue) const;
+ void insertPropertyIntoMacabRecord(const ABPropertyType _propertyType, MacabRecord *_abrecord, const MacabHeader *_header, const OUString& _propertyName, const CFTypeRef _propertyValue) const;
+ public:
+ MacabRecords(const ABAddressBookRef _addressBook, MacabHeader *_header, MacabRecord **_records, sal_Int32 _numRecords);
+ explicit MacabRecords(const MacabRecords *_copy);
+ explicit MacabRecords(const ABAddressBookRef _addressBook);
+ ~MacabRecords();
+
+ void initialize();
+
+ void setHeader(MacabHeader *_header);
+ MacabHeader *getHeader() const;
+
+ void setName(const OUString& _sName);
+ OUString const & getName() const;
+
+ MacabRecord *insertRecord(MacabRecord *_newRecord, const sal_Int32 _location);
+ void insertRecord(MacabRecord *_newRecord);
+ MacabRecord *getRecord(const sal_Int32 _location) const;
+ void swap(const sal_Int32 _id1, const sal_Int32 _id2);
+
+ macabfield *getField(const sal_Int32 _recordNumber, const sal_Int32 _columnNumber) const;
+ macabfield *getField(const sal_Int32 _recordNumber, std::u16string_view _columnName) const;
+ sal_Int32 getFieldNumber(std::u16string_view _columnName) const;
+
+ sal_Int32 size() const;
+
+ MacabHeader *createHeaderForRecordType(const CFArrayRef _records, const CFStringRef _recordType) const;
+ MacabRecord *createMacabRecord(const ABRecordRef _abrecord, const MacabHeader *_header, const CFStringRef _recordType) const;
+
+ MacabRecords *begin();
+ sal_Int32 end() const;
+ class iterator{
+ protected:
+ MacabRecords *records;
+ public:
+ sal_Int32 id;
+ iterator& operator= (MacabRecords *_records);
+ iterator();
+ void operator++ ();
+ bool operator!= (const sal_Int32 i) const;
+ bool operator== (const sal_Int32 i) const;
+ MacabRecord *operator* () const;
+ };
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabResultSet.cxx b/connectivity/source/drivers/macab/MacabResultSet.cxx
new file mode 100644
index 000000000..4142fcb6c
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabResultSet.cxx
@@ -0,0 +1,1094 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabResultSet.hxx"
+#include "MacabAddressBook.hxx"
+#include "MacabRecords.hxx"
+#include "macabutilities.hxx"
+#include "MacabResultSetMetaData.hxx"
+#include "MacabConnection.hxx"
+#include "macabcondition.hxx"
+#include "macaborder.hxx"
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbcx/CompareBookmark.hpp>
+#include <TConnection.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <resource/sharedresources.hxx>
+#include <rtl/ref.hxx>
+#include <strings.hrc>
+
+using namespace connectivity::macab;
+using namespace cppu;
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::beans;
+using namespace css::sdbc;
+using namespace css::sdbcx;
+using namespace css::io;
+using namespace css::util;
+
+IMPLEMENT_SERVICE_INFO(MacabResultSet, "com.sun.star.sdbc.drivers.MacabResultSet", "com.sun.star.sdbc.ResultSet");
+
+MacabResultSet::MacabResultSet(MacabCommonStatement* pStmt)
+ : MacabResultSet_BASE(m_aMutex),
+ OPropertySetHelper(MacabResultSet_BASE::rBHelper),
+ m_xStatement(pStmt),
+ m_aMacabRecords(),
+ m_nRowPos(-1),
+ m_bWasNull(true),
+ m_sTableName(MacabAddressBook::getDefaultTableName())
+{
+}
+
+MacabResultSet::~MacabResultSet()
+{
+}
+
+void MacabResultSet::allMacabRecords()
+{
+ rtl::Reference<MacabConnection> pConnection = static_cast< MacabConnection *>(m_xStatement->getConnection().get());
+
+ m_aMacabRecords = pConnection->getAddressBook()->getMacabRecords(m_sTableName);
+}
+
+void MacabResultSet::someMacabRecords(const MacabCondition *pCondition)
+{
+ rtl::Reference<MacabConnection> pConnection = static_cast< MacabConnection *>(m_xStatement->getConnection().get());
+ MacabRecords* allRecords;
+
+ allRecords = pConnection->getAddressBook()->getMacabRecords(m_sTableName);
+
+ // Bad table!! Throw exception?
+ if(allRecords == nullptr)
+ return;
+
+ if(m_aMacabRecords != nullptr && m_aMacabRecords != allRecords)
+ delete m_aMacabRecords;
+
+ // The copy constructor copies everything but records (including the
+ // maximum allocated size, which means that we'll never have to resize)
+ m_aMacabRecords = new MacabRecords(allRecords);
+
+ if(pCondition->isAlwaysFalse())
+ {
+ return;
+ }
+
+ MacabRecords::iterator iterator;
+
+ for (iterator = allRecords->begin();
+ iterator != allRecords->end();
+ ++iterator)
+ {
+ if (pCondition->eval(*iterator))
+ m_aMacabRecords->insertRecord(*iterator);
+ }
+}
+
+void MacabResultSet::sortMacabRecords(const MacabOrder *pOrder)
+{
+ // I do this with ints rather than an iterator because the ids will
+ // be changing when we change the order and ints are easier to deal
+ // with (for me).
+ sal_Int32 i, j, size, smallest;
+ size = m_aMacabRecords->size();
+
+ for(i = 0; i < size; i++)
+ {
+ smallest = i;
+ for( j = i + 1; j < size; j++)
+ {
+ // if smallest > j
+ if(pOrder->compare(m_aMacabRecords->getRecord(smallest),
+ m_aMacabRecords->getRecord(j) ) > 0)
+ {
+ smallest = j;
+ }
+
+ }
+
+ if(smallest != i)
+ {
+ m_aMacabRecords->swap(i,smallest);
+ }
+ }
+
+}
+
+void MacabResultSet::setTableName(OUString const & _sTableName)
+{
+ m_sTableName = _sTableName;
+}
+
+void MacabResultSet::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ m_xStatement.clear();
+ m_xMetaData.clear();
+}
+
+Any SAL_CALL MacabResultSet::queryInterface(const Type & rType)
+{
+ Any aRet = OPropertySetHelper::queryInterface(rType);
+ if (!aRet.hasValue())
+ aRet = MacabResultSet_BASE::queryInterface(rType);
+ return aRet;
+}
+
+void SAL_CALL MacabResultSet::acquire() noexcept
+{
+ MacabResultSet_BASE::acquire();
+}
+
+void SAL_CALL MacabResultSet::release() noexcept
+{
+ MacabResultSet_BASE::release();
+}
+
+Sequence< Type > SAL_CALL MacabResultSet::getTypes()
+{
+ OTypeCollection aTypes(
+ cppu::UnoType<css::beans::XMultiPropertySet>::get(),
+ cppu::UnoType<css::beans::XFastPropertySet>::get(),
+ cppu::UnoType<css::beans::XPropertySet>::get());
+
+ return comphelper::concatSequences(aTypes.getTypes(), MacabResultSet_BASE::getTypes());
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL MacabResultSet::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+sal_Int32 SAL_CALL MacabResultSet::findColumn(const OUString& columnName)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ // find the first column with the name columnName
+ Reference< XResultSetMetaData > xMeta = getMetaData();
+ sal_Int32 nLen = xMeta->getColumnCount();
+
+ for (sal_Int32 i = 1; i <= nLen; ++i)
+ {
+ if (xMeta->isCaseSensitive(i) ?
+ columnName == xMeta->getColumnName(i) :
+ columnName.equalsIgnoreAsciiCase(xMeta->getColumnName(i)))
+ return i;
+ }
+
+ ::dbtools::throwInvalidColumnException( columnName, *this );
+ assert(false);
+ return 0; // Never reached
+}
+
+OUString SAL_CALL MacabResultSet::getString(sal_Int32 columnIndex)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ OUString aRet;
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ m_bWasNull = true;
+
+ if (m_nRowPos != -1 && m_nRowPos != nRecords && m_xMetaData.is())
+ {
+ sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(columnIndex);
+ macabfield *aField = m_aMacabRecords->getField(m_nRowPos,nFieldNumber);
+ if(aField != nullptr)
+ {
+ if(aField->type == kABStringProperty)
+ {
+ aRet = CFStringToOUString(static_cast<CFStringRef>(aField->value));
+ m_bWasNull = false;
+ }
+ }
+ }
+
+// Trigger an exception if m_bWasNull is true?
+ return aRet;
+}
+
+sal_Bool SAL_CALL MacabResultSet::getBoolean(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getBoolean", nullptr);
+
+ return false;
+}
+
+sal_Int8 SAL_CALL MacabResultSet::getByte(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getByte", nullptr);
+
+ return 0;
+}
+
+sal_Int16 SAL_CALL MacabResultSet::getShort(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getShort", nullptr);
+
+ return 0;
+}
+
+sal_Int32 SAL_CALL MacabResultSet::getInt(sal_Int32 columnIndex)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ sal_Int32 nRet = 0;
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ m_bWasNull = true;
+
+ if (m_nRowPos != -1 && m_nRowPos != nRecords && m_xMetaData.is())
+ {
+ sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(columnIndex);
+ macabfield *aField = m_aMacabRecords->getField(m_nRowPos,nFieldNumber);
+ if(aField != nullptr)
+ {
+ if(aField->type == kABIntegerProperty)
+ {
+ CFNumberType numberType = CFNumberGetType( static_cast<CFNumberRef>(aField->value) );
+ // m_bWasNull now becomes whether getting the value was successful
+ // Should we check for the wrong type here, e.g., a float or a 64 bit int?
+ m_bWasNull = !CFNumberGetValue(static_cast<CFNumberRef>(aField->value), numberType, &nRet);
+ }
+ }
+ }
+
+// Trigger an exception if m_bWasNull is true?
+ return nRet;
+}
+
+sal_Int64 SAL_CALL MacabResultSet::getLong(sal_Int32 columnIndex)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ sal_Int64 nRet = 0;
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ m_bWasNull = true;
+
+ if (m_nRowPos != -1 && m_nRowPos != nRecords && m_xMetaData.is())
+ {
+ sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(columnIndex);
+ macabfield *aField = m_aMacabRecords->getField(m_nRowPos,nFieldNumber);
+ if(aField != nullptr)
+ {
+ if(aField->type == kABIntegerProperty)
+ {
+ CFNumberType numberType = CFNumberGetType( static_cast<CFNumberRef>(aField->value) );
+ // m_bWasNull now becomes whether getting the value was successful
+ // Should we check for the wrong type here, e.g., a float or a 32 bit int?
+ m_bWasNull = !CFNumberGetValue(static_cast<CFNumberRef>(aField->value), numberType, &nRet);
+ }
+ }
+ }
+
+// Trigger an exception if m_bWasNull is true?
+ return nRet;
+}
+
+float SAL_CALL MacabResultSet::getFloat(sal_Int32 columnIndex)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ float nVal = 0;
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ m_bWasNull = true;
+
+ if (m_nRowPos != -1 && m_nRowPos != nRecords && m_xMetaData.is())
+ {
+ sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(columnIndex);
+ macabfield *aField = m_aMacabRecords->getField(m_nRowPos,nFieldNumber);
+ if(aField != nullptr)
+ {
+ if(aField->type == kABRealProperty)
+ {
+ CFNumberType numberType = CFNumberGetType( static_cast<CFNumberRef>(aField->value) );
+ // m_bWasNull now becomes whether getting the value was successful
+ // Should we check for the wrong type here, e.g., an int or a double?
+ m_bWasNull = !CFNumberGetValue(static_cast<CFNumberRef>(aField->value), numberType, &nVal);
+ }
+ }
+ }
+
+// Trigger an exception if m_bWasNull is true?
+ return nVal;
+}
+
+double SAL_CALL MacabResultSet::getDouble(sal_Int32 columnIndex)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ double nVal = 0;
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ m_bWasNull = true;
+
+ if (m_nRowPos != -1 && m_nRowPos != nRecords && m_xMetaData.is())
+ {
+ sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(columnIndex);
+ macabfield *aField = m_aMacabRecords->getField(m_nRowPos,nFieldNumber);
+ if(aField != nullptr)
+ {
+ if(aField->type == kABRealProperty)
+ {
+ CFNumberType numberType = CFNumberGetType( static_cast<CFNumberRef>(aField->value) );
+ // m_bWasNull now becomes whether getting the value was successful
+ // Should we check for the wrong type here, e.g., an int or a float?
+ m_bWasNull = !CFNumberGetValue(static_cast<CFNumberRef>(aField->value), numberType, &nVal);
+ }
+ }
+ }
+
+// Trigger an exception if m_bWasNull is true?
+ return nVal;
+}
+
+Sequence< sal_Int8 > SAL_CALL MacabResultSet::getBytes(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getBytes", nullptr);
+
+ return Sequence< sal_Int8 >();
+}
+
+Date SAL_CALL MacabResultSet::getDate(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getDate", nullptr);
+
+ Date aRet;
+ return aRet;
+}
+
+Time SAL_CALL MacabResultSet::getTime(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getTime", nullptr);
+
+ css::util::Time nRet;
+ return nRet;
+}
+
+DateTime SAL_CALL MacabResultSet::getTimestamp(sal_Int32 columnIndex)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ DateTime nRet;
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ m_bWasNull = true;
+
+ if (m_nRowPos != -1 && m_nRowPos != nRecords && m_xMetaData.is())
+ {
+ sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(columnIndex);
+ macabfield *aField = m_aMacabRecords->getField(m_nRowPos,nFieldNumber);
+ if(aField != nullptr)
+ {
+ if(aField->type == kABDateProperty)
+ {
+ nRet = CFDateToDateTime(static_cast<CFDateRef>(aField->value));
+ m_bWasNull = false;
+ }
+ }
+ }
+
+// Trigger an exception if m_bWasNull is true?
+ return nRet;
+}
+
+Reference< XInputStream > SAL_CALL MacabResultSet::getBinaryStream(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getBinaryStream", nullptr);
+
+ return nullptr;
+}
+
+Reference< XInputStream > SAL_CALL MacabResultSet::getCharacterStream(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getCharacterStream", nullptr);
+
+ return nullptr;
+}
+
+Any SAL_CALL MacabResultSet::getObject(sal_Int32, const Reference< css::container::XNameAccess >&)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getObject", nullptr);
+
+ return Any();
+}
+
+Reference< XRef > SAL_CALL MacabResultSet::getRef(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getRef", nullptr);
+
+ return nullptr;
+}
+
+Reference< XBlob > SAL_CALL MacabResultSet::getBlob(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getBlob", nullptr);
+
+ return nullptr;
+}
+
+Reference< XClob > SAL_CALL MacabResultSet::getClob(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getClob", nullptr);
+
+ return nullptr;
+}
+
+Reference< XArray > SAL_CALL MacabResultSet::getArray(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFunctionNotSupportedSQLException("getArray", nullptr);
+
+ return nullptr;
+}
+
+Reference< XResultSetMetaData > SAL_CALL MacabResultSet::getMetaData()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ if (!m_xMetaData.is())
+ m_xMetaData = new MacabResultSetMetaData(m_xStatement->getOwnConnection(), m_sTableName);
+
+ Reference< XResultSetMetaData > xMetaData = m_xMetaData;
+ return xMetaData;
+}
+
+sal_Bool SAL_CALL MacabResultSet::isBeforeFirst()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ if (m_nRowPos == -1)
+ return true;
+
+ return false;
+}
+
+sal_Bool SAL_CALL MacabResultSet::isAfterLast()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ if (m_nRowPos == nRecords)
+ return true;
+
+ return false;
+}
+
+sal_Bool SAL_CALL MacabResultSet::isFirst()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ if (m_nRowPos == 0)
+ return true;
+
+ return false;
+}
+
+sal_Bool SAL_CALL MacabResultSet::isLast()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ if (m_nRowPos == nRecords - 1)
+ return true;
+
+ return false;
+}
+
+void SAL_CALL MacabResultSet::beforeFirst()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ // move before the first row
+ m_nRowPos = -1;
+}
+
+void SAL_CALL MacabResultSet::afterLast()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ // move after the last row
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ m_nRowPos = nRecords;
+}
+
+void SAL_CALL MacabResultSet::close()
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+ }
+ dispose();
+}
+
+sal_Bool SAL_CALL MacabResultSet::first()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ if (nRecords == 0)
+ return false;
+
+ m_nRowPos = 0;
+ return true;
+}
+
+sal_Bool SAL_CALL MacabResultSet::last()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ if (nRecords == 0)
+ return false;
+
+ m_nRowPos = nRecords - 1;
+ return true;
+}
+
+sal_Int32 SAL_CALL MacabResultSet::getRow()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ return m_nRowPos;
+}
+
+sal_Bool SAL_CALL MacabResultSet::absolute(sal_Int32 row)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ sal_Int32 nRecords = m_aMacabRecords->size();
+ if (row <= -1 ||
+ row >= nRecords)
+ return false;
+
+ m_nRowPos = row;
+ return true;
+}
+
+sal_Bool SAL_CALL MacabResultSet::relative(sal_Int32 row)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ return absolute(m_nRowPos + row);
+}
+
+sal_Bool SAL_CALL MacabResultSet::next()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ return absolute(m_nRowPos + 1);
+}
+
+sal_Bool SAL_CALL MacabResultSet::previous()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ return absolute(m_nRowPos - 1);
+}
+
+Reference< XInterface > SAL_CALL MacabResultSet::getStatement()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ Reference< XStatement > xStatement = m_xStatement;
+ return xStatement;
+}
+
+sal_Bool SAL_CALL MacabResultSet::rowDeleted()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ return false;
+}
+
+sal_Bool SAL_CALL MacabResultSet::rowInserted()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ return false;
+}
+
+sal_Bool SAL_CALL MacabResultSet::rowUpdated()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ return false;
+}
+
+sal_Bool SAL_CALL MacabResultSet::wasNull()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ return m_bWasNull;
+}
+
+void SAL_CALL MacabResultSet::cancel()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::clearWarnings()
+{
+}
+
+Any SAL_CALL MacabResultSet::getWarnings()
+{
+ return Any();
+}
+
+void SAL_CALL MacabResultSet::insertRow()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ // you only have to implement this if you want to insert new rows
+}
+
+void SAL_CALL MacabResultSet::updateRow()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ // only when you allow updates
+}
+
+void SAL_CALL MacabResultSet::deleteRow()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::cancelRowUpdates()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::moveToInsertRow()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ // only when you allow inserts
+}
+
+void SAL_CALL MacabResultSet::moveToCurrentRow()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateNull(sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateBoolean(sal_Int32, sal_Bool)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateByte(sal_Int32, sal_Int8)
+{
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+}
+
+void SAL_CALL MacabResultSet::updateShort(sal_Int32, sal_Int16)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateInt(sal_Int32, sal_Int32)
+{
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+}
+
+void SAL_CALL MacabResultSet::updateLong(sal_Int32, sal_Int64)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateFloat(sal_Int32, float)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateDouble(sal_Int32, double)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateString(sal_Int32, const OUString&)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateBytes(sal_Int32, const Sequence< sal_Int8 >&)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateDate(sal_Int32, const Date&)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateTime(sal_Int32, const css::util::Time&)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateTimestamp(sal_Int32, const DateTime&)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateBinaryStream(sal_Int32, const Reference< XInputStream >&, sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateCharacterStream(sal_Int32, const Reference< XInputStream >&, sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::refreshRow()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateObject(sal_Int32, const Any&)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL MacabResultSet::updateNumericObject(sal_Int32, const Any&, sal_Int32)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+}
+
+// XRowLocate
+Any SAL_CALL MacabResultSet::getBookmark()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ sal_Int32 nRecords = m_aMacabRecords->size();
+
+ if (m_nRowPos != -1 && m_nRowPos != nRecords)
+ {
+ macabfield *uidField = m_aMacabRecords->getField(m_nRowPos,u"UID");
+ if(uidField != nullptr)
+ {
+ if(uidField->type == kABStringProperty)
+ {
+ return Any(CFStringToOUString( static_cast<CFStringRef>(uidField->value) ));
+ }
+ }
+ }
+ return Any();
+}
+
+sal_Bool SAL_CALL MacabResultSet::moveToBookmark(const Any& bookmark)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ OUString sBookmark = comphelper::getString(bookmark);
+ sal_Int32 nRecords = m_aMacabRecords->size();
+
+ for (sal_Int32 nRow = 0; nRow < nRecords; nRow++)
+ {
+ macabfield *uidField = m_aMacabRecords->getField(m_nRowPos,u"UID");
+ if(uidField != nullptr)
+ {
+ if(uidField->type == kABStringProperty)
+ {
+ OUString sUniqueIdentifier = CFStringToOUString( static_cast<CFStringRef>(uidField->value) );
+ if (sUniqueIdentifier == sBookmark)
+ {
+ m_nRowPos = nRow;
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL MacabResultSet::moveRelativeToBookmark(const Any& bookmark, sal_Int32 rows)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ sal_Int32 nRowSave = m_nRowPos;
+
+ if (moveToBookmark(bookmark))
+ {
+ sal_Int32 nRecords = m_aMacabRecords->size();
+
+ m_nRowPos += rows;
+
+ if (-1 < m_nRowPos && m_nRowPos < nRecords)
+ return true;
+ }
+
+ m_nRowPos = nRowSave;
+ return false;
+}
+
+sal_Int32 SAL_CALL MacabResultSet::compareBookmarks(const Any& firstItem, const Any& secondItem)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ OUString sFirst = comphelper::getString(firstItem);
+ OUString sSecond = comphelper::getString(secondItem);
+
+ if (sFirst < sSecond)
+ return CompareBookmark::LESS;
+ if (sFirst > sSecond)
+ return CompareBookmark::GREATER;
+ return CompareBookmark::EQUAL;
+}
+
+sal_Bool SAL_CALL MacabResultSet::hasOrderedBookmarks()
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL MacabResultSet::hashBookmark(const Any& bookmark)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ OUString sBookmark = comphelper::getString(bookmark);
+
+ return sBookmark.hashCode();
+}
+
+// XDeleteRows
+Sequence< sal_Int32 > SAL_CALL MacabResultSet::deleteRows(const Sequence< Any >&)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed);
+
+ return Sequence< sal_Int32 >();
+}
+
+IPropertyArrayHelper* MacabResultSet::createArrayHelper() const
+{
+ return new OPropertyArrayHelper
+ {
+ {
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
+ PROPERTY_ID_CURSORNAME,
+ cppu::UnoType<OUString>::get(),
+ PropertyAttribute::READONLY
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
+ PROPERTY_ID_FETCHDIRECTION,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
+ PROPERTY_ID_FETCHSIZE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE),
+ PROPERTY_ID_ISBOOKMARKABLE,
+ cppu::UnoType<bool>::get(),
+ PropertyAttribute::READONLY
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
+ PROPERTY_ID_RESULTSETCONCURRENCY,
+ cppu::UnoType<sal_Int32>::get(),
+ PropertyAttribute::READONLY
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
+ PROPERTY_ID_RESULTSETTYPE,
+ cppu::UnoType<sal_Int32>::get(),
+ PropertyAttribute::READONLY
+ }
+ }
+ };
+}
+
+IPropertyArrayHelper & MacabResultSet::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+sal_Bool MacabResultSet::convertFastPropertyValue(
+ Any &,
+ Any &,
+ sal_Int32 nHandle,
+ const Any& )
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ throw css::lang::IllegalArgumentException();
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ case PROPERTY_ID_FETCHSIZE:
+ default:
+ ;
+ }
+ return false;
+}
+
+void MacabResultSet::setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const Any& )
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ throw Exception("cannot set prop " + OUString::number(nHandle), nullptr);
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ break;
+ default:
+ ;
+ }
+}
+
+void MacabResultSet::getFastPropertyValue(
+ Any& _rValue,
+ sal_Int32 nHandle) const
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ _rValue <<= false;
+ break;
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ case PROPERTY_ID_FETCHDIRECTION:
+ case PROPERTY_ID_FETCHSIZE:
+ ;
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabResultSet.hxx b/connectivity/source/drivers/macab/MacabResultSet.hxx
new file mode 100644
index 000000000..306ef562d
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabResultSet.hxx
@@ -0,0 +1,213 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MacabStatement.hxx"
+#include "MacabResultSetMetaData.hxx"
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbcx/XDeleteRows.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+
+namespace connectivity::macab
+{
+ /*
+ ** MacabResultSet
+ */
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet,
+ css::sdbc::XRow,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::util::XCancellable,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XResultSetUpdate,
+ css::sdbc::XRowUpdate,
+ css::sdbcx::XRowLocate,
+ css::sdbcx::XDeleteRows,
+ css::sdbc::XCloseable,
+ css::sdbc::XColumnLocate,
+ css::lang::XServiceInfo> MacabResultSet_BASE;
+ class MacabRecords;
+
+ class MacabResultSet : public cppu::BaseMutex,
+ public MacabResultSet_BASE,
+ public ::cppu::OPropertySetHelper,
+ public comphelper::OPropertyArrayUsageHelper<MacabResultSet>
+ {
+ protected:
+ ::rtl::Reference< MacabCommonStatement > m_xStatement; // the statement that has created this result set
+ ::rtl::Reference< MacabResultSetMetaData > m_xMetaData; // the description of the columns in this result set
+ MacabRecords * m_aMacabRecords; // address book entries matching the query
+ sal_Int32 m_nRowPos; // the current row within the result set
+ bool m_bWasNull; // last entry retrieved from this result set was NULL
+ OUString m_sTableName;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue) override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle) const override;
+
+ // you can't delete objects of this type
+ virtual ~MacabResultSet() override;
+
+ public:
+ DECLARE_SERVICE_INFO();
+
+ explicit MacabResultSet(MacabCommonStatement *pStmt);
+
+ css::uno::Reference< css::uno::XInterface > operator *()
+ {
+ return css::uno::Reference< css::uno::XInterface >(*static_cast<MacabResultSet_BASE*>(this));
+ }
+
+ void allMacabRecords();
+ void someMacabRecords(const class MacabCondition *pCondition);
+ void sortMacabRecords(const class MacabOrder *pOrder);
+ void setTableName(const OUString& _sTableName);
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // XResultSet
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+ // XResultSetUpdate
+ virtual void SAL_CALL insertRow( ) override;
+ virtual void SAL_CALL updateRow( ) override;
+ virtual void SAL_CALL deleteRow( ) override;
+ virtual void SAL_CALL cancelRowUpdates( ) override;
+ virtual void SAL_CALL moveToInsertRow( ) override;
+ virtual void SAL_CALL moveToCurrentRow( ) override;
+ // XRowUpdate
+ virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override;
+ virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override;
+ virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override;
+ virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override;
+ virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override;
+ virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override;
+
+ // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+
+ // XRowLocate
+ virtual css::uno::Any SAL_CALL getBookmark( ) override;
+ virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override;
+ virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& firstItem, const css::uno::Any& secondItem ) override;
+ virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override;
+ virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override;
+
+ // XDeleteRows
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const css::uno::Sequence< css::uno::Any >& rows ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabResultSetMetaData.cxx b/connectivity/source/drivers/macab/MacabResultSetMetaData.cxx
new file mode 100644
index 000000000..e08d92cfc
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabResultSetMetaData.cxx
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabResultSetMetaData.hxx"
+#include "MacabHeader.hxx"
+#include "MacabRecords.hxx"
+#include "MacabAddressBook.hxx"
+#include "macabutilities.hxx"
+#include <connectivity/dbexception.hxx>
+#include <strings.hrc>
+
+using namespace connectivity::macab;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::sdbc;
+
+MacabResultSetMetaData::MacabResultSetMetaData(MacabConnection* _pConnection, OUString const & _sTableName)
+ : m_pConnection(_pConnection),
+ m_sTableName(_sTableName),
+ m_aMacabFields()
+{
+}
+
+MacabResultSetMetaData::~MacabResultSetMetaData()
+{
+}
+
+void MacabResultSetMetaData::setMacabFields(const ::rtl::Reference<connectivity::OSQLColumns> &xColumns)
+{
+ static constexpr OUStringLiteral aName = u"Name";
+ MacabRecords *aRecords;
+ MacabHeader *aHeader;
+
+ aRecords = m_pConnection->getAddressBook()->getMacabRecords(m_sTableName);
+
+ // In case, somehow, we don't have anything with the name m_sTableName
+ if(aRecords == nullptr)
+ {
+ impl_throwError(STR_NO_TABLE);
+ }
+
+ aHeader = aRecords->getHeader();
+
+ for (const auto& rxColumn : *xColumns)
+ {
+ OUString aFieldName;
+ sal_uInt32 nFieldNumber;
+
+ rxColumn->getPropertyValue(aName) >>= aFieldName;
+ nFieldNumber = aHeader->getColumnNumber(aFieldName);
+ m_aMacabFields.push_back(nFieldNumber);
+ }
+
+}
+
+sal_Int32 SAL_CALL MacabResultSetMetaData::getColumnDisplaySize(sal_Int32 /* column */)
+{
+ // For now, all columns are the same size.
+ return 50;
+}
+
+sal_Int32 SAL_CALL MacabResultSetMetaData::getColumnType(sal_Int32 column)
+{
+ MacabRecords *aRecords;
+ MacabHeader *aHeader;
+ macabfield *aField;
+
+ aRecords = m_pConnection->getAddressBook()->getMacabRecords(m_sTableName);
+
+ // In case, somehow, we don't have anything with the name m_sTableName
+ if(aRecords == nullptr)
+ {
+ impl_throwError(STR_NO_TABLE);
+ }
+
+ aHeader = aRecords->getHeader();
+ aField = aHeader->get(column-1);
+
+ if(aField == nullptr)
+ {
+ ::dbtools::throwInvalidIndexException(*this);
+ return -1;
+ }
+
+ return ABTypeToDataType(aField->type);
+}
+
+sal_Int32 SAL_CALL MacabResultSetMetaData::getColumnCount()
+{
+ return m_aMacabFields.size();
+}
+
+sal_Bool SAL_CALL MacabResultSetMetaData::isCaseSensitive(sal_Int32)
+{
+ return true;
+}
+
+OUString SAL_CALL MacabResultSetMetaData::getSchemaName(sal_Int32)
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabResultSetMetaData::getColumnName(sal_Int32 column)
+{
+ sal_uInt32 nFieldNumber = m_aMacabFields[column - 1];
+ MacabRecords *aRecords;
+ MacabHeader *aHeader;
+
+ aRecords = m_pConnection->getAddressBook()->getMacabRecords(m_sTableName);
+
+ // In case, somehow, we don't have anything with the name m_sTableName
+ if(aRecords == nullptr)
+ {
+ impl_throwError(STR_NO_TABLE);
+ }
+
+ aHeader = aRecords->getHeader();
+ OUString aName = aHeader->getString(nFieldNumber);
+
+ return aName;
+}
+
+OUString SAL_CALL MacabResultSetMetaData::getTableName(sal_Int32)
+{
+ return m_sTableName;
+}
+
+OUString SAL_CALL MacabResultSetMetaData::getCatalogName(sal_Int32)
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabResultSetMetaData::getColumnTypeName(sal_Int32)
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabResultSetMetaData::getColumnLabel(sal_Int32)
+{
+ return OUString();
+}
+
+OUString SAL_CALL MacabResultSetMetaData::getColumnServiceName(sal_Int32)
+{
+ return OUString();
+}
+
+sal_Bool SAL_CALL MacabResultSetMetaData::isCurrency(sal_Int32)
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabResultSetMetaData::isAutoIncrement(sal_Int32)
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabResultSetMetaData::isSigned(sal_Int32)
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL MacabResultSetMetaData::getPrecision(sal_Int32)
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL MacabResultSetMetaData::getScale(sal_Int32)
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL MacabResultSetMetaData::isNullable(sal_Int32)
+{
+ return sal_Int32(true);
+}
+
+sal_Bool SAL_CALL MacabResultSetMetaData::isSearchable(sal_Int32)
+{
+ return true;
+}
+
+sal_Bool SAL_CALL MacabResultSetMetaData::isReadOnly(sal_Int32)
+{
+ return true;
+}
+
+sal_Bool SAL_CALL MacabResultSetMetaData::isDefinitelyWritable(sal_Int32)
+{
+ return false;
+}
+
+sal_Bool SAL_CALL MacabResultSetMetaData::isWritable(sal_Int32)
+{
+ return false;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabResultSetMetaData.hxx b/connectivity/source/drivers/macab/MacabResultSetMetaData.hxx
new file mode 100644
index 000000000..b82088154
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabResultSetMetaData.hxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MacabConnection.hxx"
+#include <connectivity/CommonTools.hxx>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <rtl/ref.hxx>
+
+namespace connectivity::macab
+{
+ /*
+ ** MacabResultSetMetaData
+ */
+ class MacabResultSetMetaData : public ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData>
+ {
+ MacabConnection* m_pConnection;
+ OUString m_sTableName;
+ std::vector<sal_Int32> m_aMacabFields; // for each selected column, contains the number
+ // of the corresponding AddressBook field
+
+ protected:
+ virtual ~MacabResultSetMetaData() override;
+
+ public:
+ MacabResultSetMetaData(MacabConnection* _pConnection, OUString const & _sTableName);
+
+ // avoid ambiguous cast error from the compiler
+ operator css::uno::Reference< css::sdbc::XResultSetMetaData > () noexcept
+ { return this; }
+
+ /// @throws css::sdbc::SQLException
+ void setMacabFields(
+ const ::rtl::Reference<connectivity::OSQLColumns> &xColumns);
+ sal_uInt32 fieldAtColumn(sal_Int32 columnIndex) const
+ { return m_aMacabFields[columnIndex - 1]; }
+
+ virtual sal_Int32 SAL_CALL getColumnCount( ) override;
+ virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getTableName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabStatement.cxx b/connectivity/source/drivers/macab/MacabStatement.cxx
new file mode 100644
index 000000000..95b922ce6
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabStatement.cxx
@@ -0,0 +1,631 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabStatement.hxx"
+#include <sqlbison.hxx>
+#include "MacabConnection.hxx"
+#include "MacabAddressBook.hxx"
+#include "MacabDriver.hxx"
+#include "MacabResultSet.hxx"
+#include "MacabResultSetMetaData.hxx"
+#include "macabcondition.hxx"
+#include "macaborder.hxx"
+#include "macabutilities.hxx"
+#include <TConnection.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <connectivity/dbexception.hxx>
+#include <resource/sharedresources.hxx>
+#include <rtl/ref.hxx>
+#include <strings.hrc>
+
+using namespace connectivity::macab;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+using namespace com::sun::star::io;
+using namespace com::sun::star::util;
+
+namespace connectivity::macab
+{
+ void impl_throwError(TranslateId pErrorId)
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(pErrorId) );
+ ::dbtools::throwGenericSQLException(sError,nullptr);
+ }
+}
+
+IMPLEMENT_SERVICE_INFO(MacabStatement, "com.sun.star.sdbc.drivers.MacabStatement", "com.sun.star.sdbc.Statement");
+
+MacabCommonStatement::MacabCommonStatement(MacabConnection* _pConnection )
+ : MacabCommonStatement_BASE(m_aMutex),
+ OPropertySetHelper(rBHelper),
+ m_aParser(_pConnection->getDriver()->getComponentContext()),
+ m_aSQLIterator(_pConnection, _pConnection->createCatalog()->getTables(), m_aParser ),
+ m_pParseTree(nullptr),
+ m_pConnection(_pConnection)
+{
+ m_pConnection->acquire();
+}
+
+MacabCommonStatement::~MacabCommonStatement()
+{
+}
+
+void MacabCommonStatement::resetParameters() const
+{
+}
+
+void MacabCommonStatement::getNextParameter(OUString &) const
+{
+ impl_throwError(STR_PARA_ONLY_PREPARED);
+}
+
+MacabCondition *MacabCommonStatement::analyseWhereClause(const OSQLParseNode *pParseNode) const
+{
+ if (pParseNode->count() == 3)
+ {
+ const OSQLParseNode *pLeft = pParseNode->getChild(0),
+ *pMiddle = pParseNode->getChild(1),
+ *pRight = pParseNode->getChild(2);
+
+ // WHERE ( ... ) ?
+ if (SQL_ISPUNCTUATION(pLeft, "(") && SQL_ISPUNCTUATION(pRight, ")"))
+ {
+ return analyseWhereClause(pMiddle);
+ }
+ else if (SQL_ISRULE(pParseNode, comparison_predicate))
+ {
+ if (pLeft->isToken() && pRight->isToken())
+ {
+ switch (pMiddle->getNodeType())
+ {
+ case SQLNodeType::Equal:
+ // WHERE 0 = 1
+ return new MacabConditionConstant(pLeft->getTokenValue() == pRight->getTokenValue());
+
+ case SQLNodeType::NotEqual:
+ // WHERE 0 <> 1
+ // (might not be correct SQL... don't care, handling anyway)
+ return new MacabConditionConstant(pLeft->getTokenValue() != pRight->getTokenValue());
+
+ default:
+ break;
+ }
+ }
+ else if (SQL_ISRULE(pLeft, column_ref))
+ {
+ OUString sColumnName,
+ sTableRange;
+
+ m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
+
+ if (pRight->isToken() || SQL_ISRULE(pRight, parameter))
+ {
+ OUString sMatchString;
+
+ if (pRight->isToken()) // WHERE Name = 'Doe'
+ sMatchString = pRight->getTokenValue();
+ else if (SQL_ISRULE(pRight, parameter)) // WHERE Name = ?
+ getNextParameter(sMatchString);
+
+ switch (pMiddle->getNodeType())
+ {
+ case SQLNodeType::Equal:
+ // WHERE Name = 'Smith'
+ return new MacabConditionEqual(m_pHeader, sColumnName, sMatchString);
+
+ case SQLNodeType::NotEqual:
+ // WHERE Name <> 'Jones'
+ return new MacabConditionDifferent(m_pHeader, sColumnName, sMatchString);
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+ else if (SQL_ISRULE(pParseNode, search_condition))
+ {
+ if (SQL_ISTOKEN(pMiddle, OR))
+ {
+ // WHERE Name = 'Smith' OR Name = 'Jones'
+ return new MacabConditionOr(
+ analyseWhereClause(pLeft),
+ analyseWhereClause(pRight));
+ }
+ }
+ else if (SQL_ISRULE(pParseNode, boolean_term))
+ {
+ if (SQL_ISTOKEN(pMiddle, AND))
+ {
+ // WHERE Name = 'Smith' AND "Given Name" = 'Peter'
+ return new MacabConditionAnd(
+ analyseWhereClause(pLeft),
+ analyseWhereClause(pRight));
+ }
+ }
+ }
+ else if (SQL_ISRULE(pParseNode, test_for_null) || SQL_ISRULE(pParseNode, like_predicate))
+ {
+ const OSQLParseNode *pLeft = pParseNode->getChild(0);
+ const OSQLParseNode* pPart2 = pParseNode->getChild(1);
+ const OSQLParseNode *pMiddleLeft = pPart2->getChild(0),
+ *pMiddleRight = pPart2->getChild(1),
+ *pRight = pPart2->getChild(2);
+
+ if (SQL_ISRULE(pParseNode, test_for_null))
+ {
+ if (SQL_ISRULE(pLeft, column_ref) &&
+ SQL_ISTOKEN(pMiddleLeft, IS) &&
+ SQL_ISTOKEN(pRight, NULL))
+ {
+ OUString sColumnName,
+ sTableRange;
+
+ m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
+
+ if (SQL_ISTOKEN(pMiddleRight, NOT))
+ {
+ // WHERE "Mobile Phone" IS NOT NULL
+ return new MacabConditionNotNull(m_pHeader, sColumnName);
+ }
+ else
+ {
+ // WHERE "Mobile Phone" IS NULL
+ return new MacabConditionNull(m_pHeader, sColumnName);
+ }
+ }
+ }
+ else if (SQL_ISRULE(pParseNode, like_predicate))
+ {
+ if (SQL_ISRULE(pLeft, column_ref))
+ {
+ OUString sColumnName,
+ sTableRange;
+
+ m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
+
+ if (pMiddleRight->isToken() || SQL_ISRULE(pMiddleRight, parameter))
+ {
+ OUString sMatchString;
+
+ if (pMiddleRight->isToken()) // WHERE Name LIKE 'Sm%'
+ sMatchString = pMiddleRight->getTokenValue();
+ else if (SQL_ISRULE(pMiddleRight, parameter)) // WHERE Name LIKE ?
+ getNextParameter(sMatchString);
+
+ return new MacabConditionSimilar(m_pHeader, sColumnName, sMatchString);
+ }
+ }
+ }
+ }
+ impl_throwError(STR_QUERY_TOO_COMPLEX);
+ // Unreachable:
+ OSL_ASSERT(false);
+ return nullptr;
+}
+
+MacabOrder *MacabCommonStatement::analyseOrderByClause(const OSQLParseNode *pParseNode) const
+{
+ if (SQL_ISRULE(pParseNode, ordering_spec_commalist))
+ {
+ MacabComplexOrder *list = new MacabComplexOrder();
+ sal_uInt32 n = pParseNode->count();
+
+ // Iterate through the ordering columns
+ for (sal_uInt32 i = 0; i < n; i++)
+ {
+ list->addOrder
+ (analyseOrderByClause(pParseNode->getChild(i)));
+ }
+
+ return list;
+ }
+ else if (SQL_ISRULE(pParseNode, ordering_spec))
+ {
+ if (pParseNode->count() == 2)
+ {
+ OSQLParseNode* pColumnRef = pParseNode->getChild(0);
+ OSQLParseNode* pAscendingDescending = pParseNode->getChild(1);
+
+ if (SQL_ISRULE(pColumnRef, column_ref))
+ {
+ if (pColumnRef->count() == 3)
+ pColumnRef = pColumnRef->getChild(2);
+
+ if (pColumnRef->count() == 1)
+ {
+ OUString sColumnName =
+ pColumnRef->getChild(0)->getTokenValue();
+ bool bAscending =
+ !SQL_ISTOKEN(pAscendingDescending, DESC);
+
+ return new MacabSimpleOrder(m_pHeader, sColumnName, bAscending);
+ }
+ }
+ }
+ }
+ impl_throwError(STR_QUERY_TOO_COMPLEX);
+ // Unreachable:
+ OSL_ASSERT(false);
+ return nullptr;
+}
+
+OUString MacabCommonStatement::getTableName() const
+{
+ const OSQLTables& xTabs = m_aSQLIterator.getTables();
+
+ if( xTabs.empty() )
+ return OUString();
+
+ // can only deal with one table at a time
+ if(xTabs.size() > 1 || m_aSQLIterator.hasErrors() )
+ return OUString();
+
+ return xTabs.begin()->first;
+}
+
+void MacabCommonStatement::setMacabFields(MacabResultSet *pResult) const
+{
+ ::rtl::Reference<connectivity::OSQLColumns> xColumns; // selected columns
+ rtl::Reference<MacabResultSetMetaData> pMeta; // meta information - holds the list of AddressBook fields
+
+ xColumns = m_aSQLIterator.getSelectColumns();
+ if (!xColumns.is())
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(
+ STR_INVALID_COLUMN_SELECTION
+ ) );
+ ::dbtools::throwGenericSQLException(sError,nullptr);
+ }
+ pMeta = static_cast<MacabResultSetMetaData *>(pResult->getMetaData().get());
+ pMeta->setMacabFields(xColumns);
+}
+
+void MacabCommonStatement::selectRecords(MacabResultSet *pResult) const
+{
+ const OSQLParseNode *pParseNode;
+
+ pParseNode = m_aSQLIterator.getWhereTree();
+ if (pParseNode != nullptr)
+ {
+ if (SQL_ISRULE(pParseNode, where_clause))
+ {
+ resetParameters();
+ pParseNode = pParseNode->getChild(1);
+ MacabCondition *pCondition = analyseWhereClause(pParseNode);
+ if (pCondition->isAlwaysTrue())
+ pResult->allMacabRecords();
+ else
+ pResult->someMacabRecords(pCondition);
+ delete pCondition;
+ return;
+ }
+ }
+
+ // no WHERE clause: get all rows
+ pResult->allMacabRecords();
+}
+
+void MacabCommonStatement::sortRecords(MacabResultSet *pResult) const
+{
+ const OSQLParseNode *pParseNode;
+
+ pParseNode = m_aSQLIterator.getOrderTree();
+ if (pParseNode != nullptr)
+ {
+ if (SQL_ISRULE(pParseNode, opt_order_by_clause))
+ {
+ pParseNode = pParseNode->getChild(2);
+ MacabOrder *pOrder = analyseOrderByClause(pParseNode);
+ pResult->sortMacabRecords(pOrder);
+ delete pOrder;
+ }
+ }
+}
+
+Any SAL_CALL MacabCommonStatement::queryInterface( const Type & rType )
+{
+ Any aRet = MacabCommonStatement_BASE::queryInterface(rType);
+ if (!aRet.hasValue())
+ aRet = OPropertySetHelper::queryInterface(rType);
+ return aRet;
+}
+
+Sequence< Type > SAL_CALL MacabCommonStatement::getTypes( )
+{
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<XMultiPropertySet>::get(),
+ cppu::UnoType<XFastPropertySet>::get(),
+ cppu::UnoType<XPropertySet>::get());
+
+ return comphelper::concatSequences(aTypes.getTypes(),MacabCommonStatement_BASE::getTypes());
+}
+
+void SAL_CALL MacabCommonStatement::cancel( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ checkDisposed(rBHelper.bDisposed);
+ // cancel the current sql statement
+}
+
+void SAL_CALL MacabCommonStatement::close( )
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(rBHelper.bDisposed);
+
+ }
+ dispose();
+}
+
+sal_Bool SAL_CALL MacabCommonStatement::execute(
+ const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(rBHelper.bDisposed);
+
+ Reference< XResultSet > xRS = executeQuery(sql);
+
+ return xRS.is();
+}
+
+Reference< XResultSet > SAL_CALL MacabCommonStatement::executeQuery(
+ const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(rBHelper.bDisposed);
+
+ rtl::Reference<MacabResultSet> pResult = new MacabResultSet(this);
+ OUString aErr;
+
+ m_pParseTree = m_aParser.parseTree(aErr, sql).release();
+ if (m_pParseTree == nullptr)
+ throw SQLException(aErr, *this, aErr, 0, Any());
+
+ m_aSQLIterator.setParseTree(m_pParseTree);
+ m_aSQLIterator.traverseAll();
+ switch (m_aSQLIterator.getStatementType())
+ {
+ case OSQLStatementType::Select:
+ {
+ OUString sTableName = getTableName(); // FROM which table ?
+ if (sTableName.getLength() != 0) // a match
+ {
+ MacabRecords *aRecords;
+ aRecords = m_pConnection->getAddressBook()->getMacabRecords(sTableName);
+
+ // In case, somehow, we don't have anything with the name m_sTableName
+ if(aRecords == nullptr)
+ {
+ impl_throwError(STR_NO_TABLE);
+ }
+ else
+ {
+ m_pHeader = aRecords->getHeader();
+
+ pResult->setTableName(sTableName);
+
+ setMacabFields(pResult.get()); // SELECT which columns ?
+ selectRecords(pResult.get()); // WHERE which condition ?
+ sortRecords(pResult.get()); // ORDER BY which columns ?
+ }
+// To be continued: DISTINCT
+// etc...
+ }
+ }
+ break;
+
+ default:
+// To be continued: UPDATE
+// DELETE
+// etc...
+ impl_throwError(STR_QUERY_TOO_COMPLEX);
+ }
+
+ m_xResultSet = Reference<XResultSet>(pResult);
+ return pResult;
+}
+
+Reference< XConnection > SAL_CALL MacabCommonStatement::getConnection( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(rBHelper.bDisposed);
+
+ // just return our connection here
+ return m_pConnection;
+}
+
+sal_Int32 SAL_CALL MacabCommonStatement::executeUpdate( const OUString& )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(rBHelper.bDisposed);
+
+ // the return values gives information about how many rows are affected by executing the sql statement
+ return 0;
+}
+
+Any SAL_CALL MacabCommonStatement::getWarnings( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(rBHelper.bDisposed);
+
+ return Any(m_aLastWarning);
+}
+
+void SAL_CALL MacabCommonStatement::clearWarnings( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(rBHelper.bDisposed);
+
+ m_aLastWarning = SQLWarning();
+}
+
+::cppu::IPropertyArrayHelper* MacabCommonStatement::createArrayHelper( ) const
+{
+ // this properties are defined by the service statement
+ // they must be in alphabetic order
+ return new ::cppu::OPropertyArrayHelper
+ {
+ {
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
+ PROPERTY_ID_CURSORNAME,
+ cppu::UnoType<OUString>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING),
+ PROPERTY_ID_ESCAPEPROCESSING,
+ cppu::UnoType<bool>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
+ PROPERTY_ID_FETCHDIRECTION,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
+ PROPERTY_ID_FETCHSIZE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE),
+ PROPERTY_ID_MAXFIELDSIZE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS),
+ PROPERTY_ID_MAXROWS,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT),
+ PROPERTY_ID_QUERYTIMEOUT,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
+ PROPERTY_ID_RESULTSETCONCURRENCY,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
+ PROPERTY_ID_RESULTSETTYPE,
+ cppu::UnoType<sal_Int32>::get(),
+ 0
+ },
+ {
+ ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS),
+ PROPERTY_ID_USEBOOKMARKS,
+ cppu::UnoType<bool>::get(),
+ 0
+ }
+ }
+ };
+}
+
+::cppu::IPropertyArrayHelper & MacabCommonStatement::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+sal_Bool MacabCommonStatement::convertFastPropertyValue(
+ Any &,
+ Any &,
+ sal_Int32,
+ const Any&)
+{
+ // here we have to try to convert
+ return false;
+}
+
+void MacabCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any&)
+{
+ // set the value to whatever is necessary
+ switch (nHandle)
+ {
+ case PROPERTY_ID_QUERYTIMEOUT:
+ case PROPERTY_ID_MAXFIELDSIZE:
+ case PROPERTY_ID_MAXROWS:
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ case PROPERTY_ID_FETCHDIRECTION:
+ case PROPERTY_ID_FETCHSIZE:
+ case PROPERTY_ID_ESCAPEPROCESSING:
+ case PROPERTY_ID_USEBOOKMARKS:
+ default:
+ ;
+ }
+}
+
+void MacabCommonStatement::getFastPropertyValue(Any&,sal_Int32 nHandle) const
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_QUERYTIMEOUT:
+ case PROPERTY_ID_MAXFIELDSIZE:
+ case PROPERTY_ID_MAXROWS:
+ case PROPERTY_ID_CURSORNAME:
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ case PROPERTY_ID_RESULTSETTYPE:
+ case PROPERTY_ID_FETCHDIRECTION:
+ case PROPERTY_ID_FETCHSIZE:
+ case PROPERTY_ID_ESCAPEPROCESSING:
+ case PROPERTY_ID_USEBOOKMARKS:
+ default:
+ ;
+ }
+}
+
+void SAL_CALL MacabCommonStatement::acquire() noexcept
+{
+ MacabCommonStatement_BASE::acquire();
+}
+
+void SAL_CALL MacabCommonStatement::release() noexcept
+{
+ MacabCommonStatement_BASE::release();
+}
+
+Reference< css::beans::XPropertySetInfo > SAL_CALL MacabCommonStatement::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+MacabStatement::MacabStatement(MacabConnection* _pConnection)
+ : MacabStatement_BASE(_pConnection)
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabStatement.hxx b/connectivity/source/drivers/macab/MacabStatement.hxx
new file mode 100644
index 000000000..700a895c0
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabStatement.hxx
@@ -0,0 +1,169 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MacabConnection.hxx"
+#include "MacabHeader.hxx"
+#include <connectivity/sqliterator.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <com/sun/star/sdbc/XStatement.hpp>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/proparrhlp.hxx>
+
+namespace connectivity::macab
+{
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XStatement,
+ css::sdbc::XWarningsSupplier,
+ css::util::XCancellable,
+ css::sdbc::XCloseable> MacabCommonStatement_BASE;
+
+
+ // Class MacabCommonStatement
+ // is a base class for the normal statement and for the prepared statement
+
+ class MacabCommonStatement : public cppu::BaseMutex,
+ public MacabCommonStatement_BASE,
+ public ::cppu::OPropertySetHelper,
+ public comphelper::OPropertyArrayUsageHelper<MacabCommonStatement>
+
+ {
+ css::sdbc::SQLWarning m_aLastWarning;
+
+ protected:
+ connectivity::OSQLParser m_aParser;
+ connectivity::OSQLParseTreeIterator m_aSQLIterator;
+ connectivity::OSQLParseNode* m_pParseTree;
+ MacabConnection* m_pConnection; // The owning Connection object
+ MacabHeader* m_pHeader; // The header of the address book on which to run queries (provided by m_pConnection)
+ css::uno::WeakReference< css::sdbc::XResultSet> m_xResultSet; // The last ResultSet created
+
+
+ protected:
+ /// @throws css::sdbc::SQLException
+ class MacabCondition *analyseWhereClause(
+ const OSQLParseNode *pParseNode) const;
+ /// @throws css::sdbc::SQLException
+ class MacabOrder *analyseOrderByClause(
+ const OSQLParseNode *pParseNode) const;
+ OUString getTableName( ) const;
+ /// @throws css::sdbc::SQLException
+ void setMacabFields(class MacabResultSet *pResult) const;
+ /// @throws css::sdbc::SQLException
+ void selectRecords(MacabResultSet *pResult) const;
+ /// @throws css::sdbc::SQLException
+ void sortRecords(MacabResultSet *pResult) const;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue) override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle) const override;
+
+ /// @throws css::sdbc::SQLException
+ virtual void resetParameters() const;
+ /// @throws css::sdbc::SQLException
+ virtual void getNextParameter(OUString &rParameter) const;
+ virtual ~MacabCommonStatement() override;
+
+ public:
+ using MacabCommonStatement_BASE::rBHelper;
+
+ explicit MacabCommonStatement(MacabConnection *_pConnection);
+ using MacabCommonStatement_BASE::operator css::uno::Reference< css::uno::XInterface >;
+
+ // OComponentHelper
+ using MacabCommonStatement_BASE::disposing;
+
+ // XInterface
+ virtual void SAL_CALL release() noexcept override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual css::uno::Any SAL_CALL queryInterface(
+ const css::uno::Type & rType
+ ) override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes(
+ ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo(
+ ) override;
+
+ // XStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery(
+ const OUString& sql ) override;
+ virtual sal_Int32 SAL_CALL executeUpdate(
+ const OUString& sql ) override;
+ virtual sal_Bool SAL_CALL execute(
+ const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection(
+ ) override;
+
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings(
+ ) override;
+ virtual void SAL_CALL clearWarnings(
+ ) override;
+
+ // XCancellable
+ virtual void SAL_CALL cancel(
+ ) override;
+
+ // XCloseable
+ virtual void SAL_CALL close(
+ ) override;
+
+ // other methods
+ MacabConnection* getOwnConnection() const { return m_pConnection; }
+ };
+
+
+ // Class MacabStatement
+
+ typedef ::cppu::ImplInheritanceHelper<
+ MacabCommonStatement, css::lang::XServiceInfo > MacabStatement_BASE;
+
+ class MacabStatement : public MacabStatement_BASE
+ {
+ protected:
+ virtual ~MacabStatement() override { }
+
+ public:
+ explicit MacabStatement(MacabConnection* _pConnection);
+ DECLARE_SERVICE_INFO();
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabTable.cxx b/connectivity/source/drivers/macab/MacabTable.cxx
new file mode 100644
index 000000000..1628cd297
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabTable.cxx
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabTable.hxx"
+#include "MacabTables.hxx"
+#include "MacabColumns.hxx"
+#include "MacabCatalog.hxx"
+#include <com/sun/star/sdbc/XRow.hpp>
+
+using namespace connectivity::macab;
+using namespace connectivity;
+using namespace ::comphelper;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+MacabTable::MacabTable( sdbcx::OCollection* _pTables, MacabConnection* _pConnection)
+ : MacabTable_TYPEDEF(_pTables, true),
+ m_pConnection(_pConnection)
+{
+ construct();
+}
+
+MacabTable::MacabTable( sdbcx::OCollection* _pTables,
+ MacabConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description ,
+ const OUString& SchemaName,
+ const OUString& CatalogName
+ ) : MacabTable_TYPEDEF(_pTables,true,
+ Name,
+ Type,
+ Description,
+ SchemaName,
+ CatalogName),
+ m_pConnection(_pConnection)
+{
+ construct();
+}
+
+void MacabTable::refreshColumns()
+{
+ ::std::vector< OUString> aVector;
+
+ if (!isNew())
+ {
+ Reference< XResultSet > xResult = m_pConnection->getMetaData()->getColumns(
+ Any(), m_SchemaName, m_Name, "%");
+
+ if (xResult.is())
+ {
+ Reference< XRow > xRow(xResult, UNO_QUERY);
+ while (xResult->next())
+ aVector.push_back(xRow->getString(4));
+ }
+ }
+
+ if (m_xColumns)
+ m_xColumns->reFill(aVector);
+ else
+ m_xColumns.reset(new MacabColumns(this, m_aMutex, aVector));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabTable.hxx b/connectivity/source/drivers/macab/MacabTable.hxx
new file mode 100644
index 000000000..897d589cc
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabTable.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "MacabConnection.hxx"
+#include <connectivity/sdbcx/VTable.hxx>
+
+namespace connectivity::macab
+{
+ typedef connectivity::sdbcx::OTable MacabTable_TYPEDEF;
+
+ class MacabTable : public MacabTable_TYPEDEF
+ {
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+ MacabConnection* m_pConnection;
+
+ public:
+ MacabTable( sdbcx::OCollection* _pTables, MacabConnection* _pConnection);
+ MacabTable( sdbcx::OCollection* _pTables,
+ MacabConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description = OUString(),
+ const OUString& SchemaName = OUString(),
+ const OUString& CatalogName = OUString()
+ );
+
+ MacabConnection* getConnection() { return m_pConnection;}
+
+ virtual void refreshColumns() override;
+
+ OUString const & getTableName() const { return m_Name; }
+ OUString const & getSchema() const { return m_SchemaName; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabTables.cxx b/connectivity/source/drivers/macab/MacabTables.cxx
new file mode 100644
index 000000000..e7149d264
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabTables.cxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "MacabTables.hxx"
+#include "MacabTable.hxx"
+#include "MacabCatalog.hxx"
+#include "MacabConnection.hxx"
+#include <comphelper/types.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+
+using namespace connectivity::macab;
+using namespace connectivity;
+using namespace ::comphelper;
+using namespace ::cppu;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+sdbcx::ObjectType MacabTables::createObject(const OUString& _rName)
+{
+ OUString aName,aSchema;
+ aSchema = "%";
+ aName = _rName;
+
+ Sequence< OUString > aTypes { "%" };
+
+ Reference< XResultSet > xResult = m_xMetaData->getTables(Any(), aSchema, aName, aTypes);
+
+ sdbcx::ObjectType xRet;
+ if (xResult.is())
+ {
+ Reference< XRow > xRow(xResult, UNO_QUERY);
+ if (xResult->next()) // there can be only one table with this name
+ {
+ xRet = new MacabTable(
+ this,
+ static_cast<MacabCatalog&>(m_rParent).getConnection(),
+ aName,
+ xRow->getString(4),
+ xRow->getString(5),
+ "");
+ }
+ }
+ ::comphelper::disposeComponent(xResult);
+
+ return xRet;
+}
+
+void MacabTables::impl_refresh( )
+{
+ static_cast<MacabCatalog&>(m_rParent).refreshTables();
+}
+
+void MacabTables::disposing()
+{
+ m_xMetaData.clear();
+ OCollection::disposing();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/MacabTables.hxx b/connectivity/source/drivers/macab/MacabTables.hxx
new file mode 100644
index 000000000..0b0d841b7
--- /dev/null
+++ b/connectivity/source/drivers/macab/MacabTables.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+
+namespace connectivity::macab
+{
+ class MacabTables : public sdbcx::OCollection
+ {
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+
+ public:
+ MacabTables(
+ const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rMetaData,
+ ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector)
+ : sdbcx::OCollection(_rParent,true,_rMutex,_rVector),
+ m_xMetaData(_rMetaData)
+ { }
+
+ virtual void disposing() override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/macab1.component b/connectivity/source/drivers/macab/macab1.component
new file mode 100644
index 000000000..7cbc0d9c8
--- /dev/null
+++ b/connectivity/source/drivers/macab/macab1.component
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.sdbc.macab.Driver"
+ constructor="connectivity_MacabDriver_get_implementation">
+ <service name="com.sun.star.sdbc.Driver"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/drivers/macab/macabcondition.cxx b/connectivity/source/drivers/macab/macabcondition.cxx
new file mode 100644
index 000000000..41e087b2c
--- /dev/null
+++ b/connectivity/source/drivers/macab/macabcondition.cxx
@@ -0,0 +1,244 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "macabcondition.hxx"
+#include "MacabHeader.hxx"
+#include "MacabRecord.hxx"
+#include <connectivity/CommonTools.hxx>
+
+using namespace ::connectivity::macab;
+using namespace ::com::sun::star::sdbc;
+
+MacabCondition::~MacabCondition()
+{
+}
+
+MacabConditionConstant::MacabConditionConstant(const bool bValue)
+ : MacabCondition(),
+ m_bValue(bValue)
+{
+}
+
+bool MacabConditionConstant::isAlwaysTrue() const
+{
+ return m_bValue;
+}
+
+bool MacabConditionConstant::isAlwaysFalse() const
+{
+ return !m_bValue;
+}
+
+bool MacabConditionConstant::eval(const MacabRecord *) const
+{
+ return m_bValue;
+}
+
+MacabConditionColumn::MacabConditionColumn(
+ const MacabHeader *header, std::u16string_view sColumnName)
+ : MacabCondition(),
+ m_nFieldNumber(header->getColumnNumber(sColumnName))
+{
+}
+
+bool MacabConditionColumn::isAlwaysTrue() const
+{
+ // Sometimes true, sometimes false
+ return false;
+}
+
+bool MacabConditionColumn::isAlwaysFalse() const
+{
+ // Sometimes true, sometimes false
+ return false;
+}
+
+MacabConditionNull::MacabConditionNull(const MacabHeader *header, std::u16string_view sColumnName)
+ : MacabConditionColumn(header, sColumnName)
+{
+}
+
+bool MacabConditionNull::eval(const MacabRecord *aRecord) const
+{
+ macabfield *aValue = aRecord->get(m_nFieldNumber);
+
+ if(aValue == nullptr)
+ return true;
+ else if(aValue->value == nullptr)
+ return true;
+ else
+ return false;
+}
+
+MacabConditionNotNull::MacabConditionNotNull(
+ const MacabHeader *header, std::u16string_view sColumnName)
+ : MacabConditionColumn(header, sColumnName)
+{
+}
+
+bool MacabConditionNotNull::eval(const MacabRecord *aRecord) const
+{
+ macabfield *aValue = aRecord->get(m_nFieldNumber);
+
+ if(aValue == nullptr)
+ return false;
+ else if(aValue->value == nullptr)
+ return false;
+ else
+ return true;
+}
+
+MacabConditionCompare::MacabConditionCompare(const MacabHeader *header, std::u16string_view sColumnName, const OUString &sMatchString)
+ : MacabConditionColumn(header, sColumnName),
+ m_sMatchString(sMatchString)
+{
+}
+
+MacabConditionEqual::MacabConditionEqual(const MacabHeader *header, std::u16string_view sColumnName, const OUString &sMatchString)
+ : MacabConditionCompare(header, sColumnName, sMatchString)
+{
+}
+
+bool MacabConditionEqual::eval(const MacabRecord *aRecord) const
+{
+ macabfield *aValue = aRecord->get(m_nFieldNumber);
+
+ if(aValue == nullptr)
+ return false;
+
+ macabfield *aValue2 = MacabRecord::createMacabField(m_sMatchString,aValue->type);
+
+ if(aValue2 == nullptr)
+ return false;
+
+ sal_Int32 nReturn = MacabRecord::compareFields(aValue, aValue2);
+
+ delete aValue2;
+ return nReturn == 0;
+}
+
+MacabConditionDifferent::MacabConditionDifferent(const MacabHeader *header, std::u16string_view sColumnName, const OUString &sMatchString)
+ : MacabConditionCompare(header, sColumnName, sMatchString)
+{
+}
+
+bool MacabConditionDifferent::eval(const MacabRecord *aRecord) const
+{
+ macabfield *aValue = aRecord->get(m_nFieldNumber);
+
+ if(aValue == nullptr)
+ return false;
+
+ macabfield *aValue2 = MacabRecord::createMacabField(m_sMatchString,aValue->type);
+
+ if(aValue2 == nullptr)
+ return false;
+
+ sal_Int32 nReturn = MacabRecord::compareFields(aValue, aValue2);
+
+ delete aValue2;
+ return nReturn != 0;
+}
+
+MacabConditionSimilar::MacabConditionSimilar(const MacabHeader *header, std::u16string_view sColumnName, const OUString &sMatchString)
+ : MacabConditionCompare(header, sColumnName, sMatchString)
+{
+}
+
+bool MacabConditionSimilar::eval(const MacabRecord *aRecord) const
+{
+ macabfield *aValue = aRecord->get(m_nFieldNumber);
+
+ if(aValue == nullptr)
+ return false;
+
+ OUString sName = MacabRecord::fieldToString(aValue);
+
+ return match(m_sMatchString, sName, '\0');
+}
+
+MacabConditionBoolean::MacabConditionBoolean(MacabCondition *pLeft, MacabCondition *pRight)
+ : MacabCondition(),
+ m_pLeft(pLeft),
+ m_pRight(pRight)
+{
+}
+
+MacabConditionBoolean::~MacabConditionBoolean()
+{
+ delete m_pLeft;
+ delete m_pRight;
+}
+
+MacabConditionOr::MacabConditionOr(MacabCondition *pLeft, MacabCondition *pRight)
+ : MacabConditionBoolean(pLeft, pRight)
+{
+}
+
+bool MacabConditionOr::isAlwaysTrue() const
+{
+ return m_pLeft->isAlwaysTrue() || m_pRight->isAlwaysTrue();
+}
+
+bool MacabConditionOr::isAlwaysFalse() const
+{
+ return m_pLeft->isAlwaysFalse() && m_pRight->isAlwaysFalse();
+}
+
+bool MacabConditionOr::eval(const MacabRecord *aRecord) const
+{
+ // We avoid evaluating terms as much as we can
+ if (m_pLeft->isAlwaysTrue() || m_pRight->isAlwaysTrue()) return true;
+ if (m_pLeft->isAlwaysFalse() && m_pRight->isAlwaysFalse()) return false;
+
+ if (m_pLeft->eval(aRecord)) return true;
+ if (m_pRight->eval(aRecord)) return true;
+
+ return false;
+}
+
+MacabConditionAnd::MacabConditionAnd(MacabCondition *pLeft, MacabCondition *pRight)
+ : MacabConditionBoolean(pLeft, pRight)
+{
+}
+
+bool MacabConditionAnd::isAlwaysTrue() const
+{
+ return m_pLeft->isAlwaysTrue() && m_pRight->isAlwaysTrue();
+}
+
+bool MacabConditionAnd::isAlwaysFalse() const
+{
+ return m_pLeft->isAlwaysFalse() || m_pRight->isAlwaysFalse();
+}
+
+bool MacabConditionAnd::eval(const MacabRecord *aRecord) const
+{
+ // We avoid evaluating terms as much as we can
+ if (m_pLeft->isAlwaysFalse() || m_pRight->isAlwaysFalse()) return false;
+ if (m_pLeft->isAlwaysTrue() && m_pRight->isAlwaysTrue()) return true;
+
+ if (!m_pLeft->eval(aRecord)) return false;
+ if (!m_pRight->eval(aRecord)) return false;
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/macabcondition.hxx b/connectivity/source/drivers/macab/macabcondition.hxx
new file mode 100644
index 000000000..32e7b7071
--- /dev/null
+++ b/connectivity/source/drivers/macab/macabcondition.hxx
@@ -0,0 +1,165 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "MacabHeader.hxx"
+#include "MacabRecord.hxx"
+
+#include <connectivity/dbexception.hxx>
+
+namespace connectivity::macab
+{
+
+class MacabCondition
+{
+ public:
+ virtual ~MacabCondition();
+ virtual bool isAlwaysTrue() const = 0;
+ virtual bool isAlwaysFalse() const = 0;
+ virtual bool eval(const MacabRecord *aRecord) const = 0;
+};
+
+class MacabConditionConstant : public MacabCondition
+{
+ protected:
+ bool m_bValue;
+
+ public:
+ explicit MacabConditionConstant(const bool bValue);
+ virtual bool isAlwaysTrue() const override;
+ virtual bool isAlwaysFalse() const override;
+ virtual bool eval(const MacabRecord *aRecord) const override;
+};
+
+class MacabConditionColumn : public MacabCondition
+{
+ protected:
+ sal_Int32 m_nFieldNumber;
+
+ public:
+ /// @throws css::sdbc::SQLException
+ MacabConditionColumn(
+ const MacabHeader *header,
+ std::u16string_view sColumnName);
+ virtual bool isAlwaysTrue() const override;
+ virtual bool isAlwaysFalse() const override;
+};
+
+class MacabConditionNull : public MacabConditionColumn
+{
+ public:
+ /// @throws css::sdbc::SQLException
+ MacabConditionNull(
+ const MacabHeader *header,
+ std::u16string_view sColumnName);
+ virtual bool eval(const MacabRecord *aRecord) const override;
+};
+
+class MacabConditionNotNull : public MacabConditionColumn
+{
+ public:
+ /// @throws css::sdbc::SQLException
+ MacabConditionNotNull(
+ const MacabHeader *header,
+ std::u16string_view sColumnName);
+ virtual bool eval(const MacabRecord *aRecord) const override;
+};
+
+class MacabConditionCompare : public MacabConditionColumn
+{
+ protected:
+ const OUString m_sMatchString;
+
+ public:
+ /// @throws css::sdbc::SQLException
+ MacabConditionCompare(
+ const MacabHeader *header,
+ std::u16string_view sColumnName,
+ const OUString &sMatchString);
+};
+
+class MacabConditionEqual : public MacabConditionCompare
+{
+ public:
+ /// @throws css::sdbc::SQLException
+ MacabConditionEqual(
+ const MacabHeader *header,
+ std::u16string_view sColumnName,
+ const OUString &sMatchString);
+ virtual bool eval(const MacabRecord *aRecord) const override;
+};
+
+class MacabConditionDifferent : public MacabConditionCompare
+{
+ public:
+ /// @throws css::sdbc::SQLException
+ MacabConditionDifferent(
+ const MacabHeader *header,
+ std::u16string_view sColumnName,
+ const OUString &sMatchString);
+ virtual bool eval(const MacabRecord *aRecord) const override;
+};
+
+class MacabConditionSimilar : public MacabConditionCompare
+{
+ public:
+ /// @throws css::sdbc::SQLException
+ MacabConditionSimilar(
+ const MacabHeader *header,
+ std::u16string_view sColumnName,
+ const OUString &sMatchString);
+ virtual bool eval(const MacabRecord *aRecord) const override;
+};
+
+class MacabConditionBoolean : public MacabCondition
+{
+ protected:
+ MacabCondition *m_pLeft, *m_pRight;
+
+ public:
+ MacabConditionBoolean(MacabCondition *pLeft, MacabCondition *pRight);
+ virtual ~MacabConditionBoolean() override;
+};
+
+class MacabConditionOr : public MacabConditionBoolean
+{
+ public:
+ MacabConditionOr(MacabCondition *pLeft, MacabCondition *pRight);
+ virtual bool isAlwaysTrue() const override;
+ virtual bool isAlwaysFalse() const override;
+ virtual bool eval(const MacabRecord *aRecord) const override;
+};
+
+class MacabConditionAnd : public MacabConditionBoolean
+{
+ public:
+ MacabConditionAnd(MacabCondition *pLeft, MacabCondition *pRight);
+ virtual bool isAlwaysTrue() const override;
+ virtual bool isAlwaysFalse() const override;
+ virtual bool eval(const MacabRecord *aRecord) const override;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/macaborder.cxx b/connectivity/source/drivers/macab/macaborder.cxx
new file mode 100644
index 000000000..133e5d599
--- /dev/null
+++ b/connectivity/source/drivers/macab/macaborder.cxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "macaborder.hxx"
+#include "MacabHeader.hxx"
+#include "MacabRecord.hxx"
+
+using namespace ::connectivity::macab;
+
+MacabOrder::~MacabOrder()
+{
+}
+
+MacabSimpleOrder::MacabSimpleOrder(MacabHeader const *header, std::u16string_view sColumnName, bool bAscending)
+ : MacabOrder(),
+ m_nFieldNumber(header->getColumnNumber(sColumnName)),
+ m_bAscending(bAscending)
+{
+}
+
+sal_Int32 MacabSimpleOrder::compare(const MacabRecord *record1, const MacabRecord *record2) const
+{
+ sal_Int32 result;
+
+ result = MacabRecord::compareFields(record1->get(m_nFieldNumber), record2->get(m_nFieldNumber));
+
+ if (!m_bAscending) result = -result;
+
+ return result;
+}
+
+MacabComplexOrder::MacabComplexOrder()
+ : MacabOrder(),
+ m_aOrders()
+{
+}
+
+MacabComplexOrder::~MacabComplexOrder()
+{
+}
+
+void MacabComplexOrder::addOrder(MacabOrder *pOrder)
+{
+ m_aOrders.emplace_back(pOrder);
+}
+
+sal_Int32 MacabComplexOrder::compare(const MacabRecord *record1, const MacabRecord *record2) const
+{
+ for (auto const & p: m_aOrders)
+ {
+ sal_Int32 result = p->compare(record1, record2);
+
+ if (result) return result;
+ }
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/macaborder.hxx b/connectivity/source/drivers/macab/macaborder.hxx
new file mode 100644
index 000000000..e5eb6c987
--- /dev/null
+++ b/connectivity/source/drivers/macab/macaborder.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include "MacabHeader.hxx"
+#include "MacabRecord.hxx"
+
+#include <memory>
+#include <string_view>
+#include <vector>
+
+namespace connectivity::macab
+{
+ class MacabOrder
+ {
+ public:
+ virtual ~MacabOrder();
+
+ virtual sal_Int32 compare(const MacabRecord *record1, const MacabRecord *record2) const = 0;
+ };
+
+ class MacabSimpleOrder : public MacabOrder
+ {
+ sal_Int32 m_nFieldNumber;
+ bool m_bAscending;
+
+ public:
+ MacabSimpleOrder(MacabHeader const *header, std::u16string_view sColumnName, bool bAscending);
+
+ virtual sal_Int32 compare(const MacabRecord *record1, const MacabRecord *record2) const override;
+ };
+
+ class MacabComplexOrder : public MacabOrder
+ {
+ std::vector<std::unique_ptr<MacabOrder>> m_aOrders;
+
+ public:
+ MacabComplexOrder();
+ virtual ~MacabComplexOrder() override;
+
+ void addOrder(MacabOrder *pOrder);
+ virtual sal_Int32 compare(const MacabRecord *record1, const MacabRecord *record2) const override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/macab/macabutilities.hxx b/connectivity/source/drivers/macab/macabutilities.hxx
new file mode 100644
index 000000000..cfe46f37f
--- /dev/null
+++ b/connectivity/source/drivers/macab/macabutilities.hxx
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <unotools/resmgr.hxx>
+
+#include <time.h>
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <AddressBook/ABAddressBookC.h>
+#include <postmac.h>
+
+namespace connectivity::macab
+{
+
+ inline OUString CFStringToOUString(const CFStringRef sOrig)
+ {
+ /* Copied all-but directly from code by Florian Heckl in
+ * cws_src680_aquafilepicker01
+ * File was: fpicker/source/aqua/CFStringUtilities
+ * I only removed commented debugging lines and changed variable
+ * names.
+ */
+ if (nullptr == sOrig) {
+ return OUString();
+ }
+
+ CFRetain(sOrig);
+ CFIndex nStringLength = CFStringGetLength(sOrig);
+
+ UniChar unichars[nStringLength+1];
+
+ //'close' the string buffer correctly
+ unichars[nStringLength] = '\0';
+
+ CFStringGetCharacters (sOrig, CFRangeMake(0,nStringLength), unichars);
+ CFRelease(sOrig);
+
+ return OUString(reinterpret_cast<sal_Unicode *>(unichars));
+ }
+
+
+ inline CFStringRef OUStringToCFString(const OUString& aString)
+ {
+ /* Copied directly from code by Florian Heckl in
+ * cws_src680_aquafilepicker01
+ * File was: fpicker/source/aqua/CFStringUtilities
+ */
+
+ CFStringRef ref = CFStringCreateWithCharacters(kCFAllocatorDefault, reinterpret_cast<UniChar const *>(aString.getStr()), aString.getLength());
+
+ return ref;
+ }
+
+
+ inline css::util::DateTime CFDateToDateTime(const CFDateRef _cfDate)
+ {
+ /* Carbon can give us the time since 2001 of any CFDateRef,
+ * and it also stores the time since 1970 as a constant,
+ * basically allowing us to get the unixtime of any
+ * CFDateRef. From there, it is just a matter of choosing what
+ * we want to do with it.
+ */
+ css::util::DateTime nRet;
+ double timeSince2001 = CFDateGetAbsoluteTime(_cfDate);
+ time_t unixtime = timeSince2001+kCFAbsoluteTimeIntervalSince1970;
+ struct tm *ptm = localtime(&unixtime);
+ nRet.Year = ptm->tm_year+1900;
+ nRet.Month = ptm->tm_mon+1;
+ nRet.Day = ptm->tm_mday;
+ nRet.Hours = ptm->tm_hour;
+ nRet.Minutes = ptm->tm_min;
+ nRet.Seconds = ptm->tm_sec;
+ nRet.NanoSeconds = 0;
+ return nRet;
+ }
+
+
+ inline OUString fixLabel(const OUString& _originalLabel)
+ {
+ /* Get the length, and make sure that there is actually a string
+ * here.
+ */
+ if(_originalLabel.startsWith("_$!<"))
+ {
+ return _originalLabel.copy(4,_originalLabel.getLength()-8);
+ }
+
+ return _originalLabel;
+ }
+
+
+ inline sal_Int32 ABTypeToDataType(const ABPropertyType _abType)
+ {
+ sal_Int32 dataType;
+ switch(_abType)
+ {
+ case kABStringProperty:
+ dataType = css::sdbc::DataType::CHAR;
+ break;
+ case kABDateProperty:
+ dataType = css::sdbc::DataType::TIMESTAMP;
+ break;
+ case kABIntegerProperty:
+ dataType = css::sdbc::DataType::INTEGER;
+ break;
+ case kABRealProperty:
+ dataType = css::sdbc::DataType::FLOAT;
+ break;
+ default:
+ dataType = -1;
+ }
+ return dataType;
+ }
+
+ void impl_throwError(TranslateId pErrorId);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */