From f36d829ef02c54b18734dd027a1c0d9b55a6171f Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Mon, 5 Jul 2010 07:22:42 -0700 Subject: Spectrum build: fixed DLL rpath Rather than explicitly modifying LD_LIBRARY_PATH using a shell script when the application is launched, the relative path from the application binary to the FFT library is encoded in the application using an --rpath flag. Task-number: QTBUG-11756 Reviewed-by: Andy Shaw --- demos/spectrum/app/app.pro | 13 +++-------- demos/spectrum/app/spectrum.sh | 50 ------------------------------------------ 2 files changed, 3 insertions(+), 60 deletions(-) delete mode 100644 demos/spectrum/app/spectrum.sh diff --git a/demos/spectrum/app/app.pro b/demos/spectrum/app/app.pro index ebeef87..28fdab0 100644 --- a/demos/spectrum/app/app.pro +++ b/demos/spectrum/app/app.pro @@ -3,7 +3,6 @@ include(../spectrum.pri) TEMPLATE = app TARGET = spectrum -unix: !macx: !symbian: TARGET = spectrum.bin QT += multimedia @@ -113,15 +112,9 @@ symbian { # Specify directory in which to create spectrum application DESTDIR = ../bin - unix: !symbian { - # On unices other than Mac OSX, we copy a shell script into the bin directory. - # This script takes care of correctly setting the LD_LIBRARY_PATH so that - # the dynamic library can be located. - copy_launch_script.target = copy_launch_script - copy_launch_script.commands = \ - install -m 0555 $$QT_SOURCE_TREE/demos/spectrum/app/spectrum.sh ../bin/spectrum - QMAKE_EXTRA_TARGETS += copy_launch_script - POST_TARGETDEPS += copy_launch_script + unix: { + # Provide relative path from application to fftreal library + QMAKE_LFLAGS += -Wl,--rpath=\\\$\$ORIGIN } } } diff --git a/demos/spectrum/app/spectrum.sh b/demos/spectrum/app/spectrum.sh deleted file mode 100644 index 2a230ed..0000000 --- a/demos/spectrum/app/spectrum.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/sh -############################################################################# -## -## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -## All rights reserved. -## Contact: Nokia Corporation (qt-info@nokia.com) -## -## This file is part of the examples of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:LGPL$ -## No Commercial Usage -## This file contains pre-release code and may not be distributed. -## You may use this file in accordance with the terms and conditions -## contained in the Technology Preview License Agreement accompanying -## this package. -## -## GNU Lesser General Public License Usage -## Alternatively, this file may be used under the terms of the GNU Lesser -## General Public License version 2.1 as published by the Free Software -## Foundation and appearing in the file LICENSE.LGPL included in the -## packaging of this file. Please review the following information to -## ensure the GNU Lesser General Public License version 2.1 requirements -## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -## -## In addition, as a special exception, Nokia gives you certain additional -## rights. These rights are described in the Nokia Qt LGPL Exception -## version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -## -## If you have questions regarding the use of this file, please contact -## Nokia at qt-info@nokia.com. -## -## -## -## -## -## -## -## -## $QT_END_LICENSE$ -## -############################################################################# - - -# Shell script for launching spectrum application on Unix systems other than Mac OSX - -bindir=`dirname "$0"` -LD_LIBRARY_PATH="${bindir}:${LD_LIBRARY_PATH}" -export LD_LIBRARY_PATH -exec "${bindir}/spectrum.bin" ${1+"$@"} - -- cgit v0.12 From 78f48dc47dd7ea52f2ad979a7fd5289da9f22e66 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Mon, 5 Jul 2010 11:39:37 +0100 Subject: Spectrum demo: fixed installation All binaries must be written into $$QT_BUILD_DIR/demos/spectrum in order for them to be correctly installed. Task-number: QTBUG-11572 Task-number: QTBUG-11756 Reviewed-by: Andy Shaw --- demos/spectrum/3rdparty/fftreal/fftreal.pro | 14 ++++++++------ demos/spectrum/app/app.pro | 7 +++---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/demos/spectrum/3rdparty/fftreal/fftreal.pro b/demos/spectrum/3rdparty/fftreal/fftreal.pro index 6801b42..c9da205 100644 --- a/demos/spectrum/3rdparty/fftreal/fftreal.pro +++ b/demos/spectrum/3rdparty/fftreal/fftreal.pro @@ -1,3 +1,5 @@ +include(../../spectrum.pri) + TEMPLATE = lib TARGET = fftreal @@ -31,13 +33,13 @@ symbian { # Provide unique ID for the generated binary, required by Symbian OS TARGET.UID3 = 0xA000E403 TARGET.CAPABILITY = UserEnvironment +} + +macx { + CONFIG += lib_bundle } else { - macx { - CONFIG += lib_bundle - } else { - DESTDIR = ../../bin - } -} + !symbian: DESTDIR = ../.. +} # Install diff --git a/demos/spectrum/app/app.pro b/demos/spectrum/app/app.pro index 28fdab0..1b419db 100644 --- a/demos/spectrum/app/app.pro +++ b/demos/spectrum/app/app.pro @@ -63,8 +63,7 @@ symbian { LIBS += -F$${fftreal_dir} LIBS += -framework fftreal } else { - # Link to dynamic library which is written to ../bin - LIBS += -L../bin + LIBS += -L.. LIBS += -lfftreal } } @@ -85,7 +84,7 @@ symbian { !contains(DEFINES, DISABLE_FFT) { # Include FFTReal DLL in the SIS file - fftreal.sources = ../3rdparty/fftreal/fftreal.dll + fftreal.sources = ../fftreal.dll fftreal.path = !:/sys/bin DEPLOYMENT += fftreal } @@ -110,7 +109,7 @@ symbian { } } else { # Specify directory in which to create spectrum application - DESTDIR = ../bin + DESTDIR = .. unix: { # Provide relative path from application to fftreal library -- cgit v0.12 From 4a1d231cd5e0b756a919642b9faf35146a190b95 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 6 Jul 2010 13:33:47 +0200 Subject: Support QSslSocket::systemCaCertificates() on Symbian Implemented access to the unified certificate store on Symbian with Shane and Peter's help. Task-number: QTBUG-11399 Reviewed-by: Shane Kearns Reviewed-by: Peter Hartmann --- src/network/network.pro | 2 +- src/network/ssl/qsslsocket_openssl.cpp | 134 +++++++++++++++++++++++++++++++++ src/network/ssl/qsslsocket_openssl_p.h | 64 ++++++++++++++++ 3 files changed, 199 insertions(+), 1 deletion(-) diff --git a/src/network/network.pro b/src/network/network.pro index 8582d8a..7ed7d3a 100644 --- a/src/network/network.pro +++ b/src/network/network.pro @@ -27,5 +27,5 @@ QMAKE_LIBS += $$QMAKE_LIBS_NETWORK symbian { TARGET.UID3=0x2001B2DE - LIBS += -lesock -linsock + LIBS += -lesock -linsock -lcertstore -lefsrv -lctframework } diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index cad8ca7..d7088ee 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -68,6 +68,8 @@ PtrCertOpenSystemStoreW QSslSocketPrivate::ptrCertOpenSystemStoreW = 0; PtrCertFindCertificateInStore QSslSocketPrivate::ptrCertFindCertificateInStore = 0; PtrCertCloseStore QSslSocketPrivate::ptrCertCloseStore = 0; +#elif defined(Q_OS_SYMBIAN) +#include #endif QT_BEGIN_NAMESPACE @@ -565,6 +567,119 @@ void QSslSocketPrivate::resetDefaultCiphers() setDefaultCiphers(ciphers); } +#if defined(Q_OS_SYMBIAN) + +QCertificateRetriever::QCertificateRetriever(QCertificateConsumer* parent) + : CActive(EPriorityStandard) + , certStore(0) + , certFilter(0) + , consumer(parent) + , currentCertificateIndex(0) + , certDescriptor(0, 0) +{ + CActiveScheduler::Add(this); + QT_TRAP_THROWING(certStore = CUnifiedCertStore::NewL(qt_s60GetRFs(), EFalse)); + QT_TRAP_THROWING(certFilter = CCertAttributeFilter::NewL()); + certFilter->SetFormat(EX509Certificate); +} + +QCertificateRetriever::~QCertificateRetriever() +{ + delete certFilter; + delete certStore; + Cancel(); +} + +void QCertificateRetriever::fetch() +{ + certStore->Initialize(iStatus); + state = Initializing; + SetActive(); +} + +void QCertificateRetriever::list() +{ + certStore->List(certs, *certFilter, iStatus); + state = Listing; + SetActive(); +} + +void QCertificateRetriever::retrieveNextCertificate() +{ + CCTCertInfo* cert = certs[currentCertificateIndex]; + currentCertificate.resize(cert->Size()); + certDescriptor.Set((TUint8*)currentCertificate.data(), 0, currentCertificate.size()); + certStore->Retrieve(*cert, certDescriptor, iStatus); + state = RetrievingCertificates; + SetActive(); +} + +void QCertificateRetriever::RunL() +{ + switch (state) { + case Initializing: + list(); + break; + case Listing: + currentCertificateIndex = 0; + retrieveNextCertificate(); + break; + case RetrievingCertificates: + consumer->addEncodedCertificate(currentCertificate); + currentCertificate = QByteArray(); + + currentCertificateIndex++; + + if (currentCertificateIndex < certs.Count()) + retrieveNextCertificate(); + else + consumer->finish(); + break; + } +} + +void QCertificateRetriever::DoCancel() +{ + switch (state) { + case Initializing: + certStore->CancelInitialize(); + break; + case Listing: + certStore->CancelList(); + break; + case RetrievingCertificates: + certStore->CancelRetrieve(); + break; + } +} + +QCertificateConsumer::QCertificateConsumer(QObject* parent) + : QObject(parent) + , retriever(0) +{ +} + +QCertificateConsumer::~QCertificateConsumer() +{ + delete retriever; +} + +void QCertificateConsumer::finish() +{ + delete retriever; + retriever = 0; + emit finished(); +} + +void QCertificateConsumer::start() +{ + retriever = new QCertificateRetriever(this); + Q_CHECK_PTR(retriever); + retriever->fetch(); +} + +#endif // defined(Q_OS_SYMBIAN) + QList QSslSocketPrivate::systemCaCertificates() { ensureInitialized(); @@ -638,7 +753,26 @@ QList QSslSocketPrivate::systemCaCertificates() systemCerts.append(QSslCertificate::fromPath(QLatin1String("/usr/lib/ssl/certs/*.pem"), QSsl::Pem, QRegExp::Wildcard)); // Gentoo, Mandrake systemCerts.append(QSslCertificate::fromPath(QLatin1String("/usr/share/ssl/*.pem"), QSsl::Pem, QRegExp::Wildcard)); // Centos, Redhat, SuSE systemCerts.append(QSslCertificate::fromPath(QLatin1String("/usr/local/ssl/*.pem"), QSsl::Pem, QRegExp::Wildcard)); // Normal OpenSSL Tarball +#elif defined(Q_OS_SYMBIAN) + QThread* certThread = new QThread; + + QCertificateConsumer *consumer = new QCertificateConsumer(); + consumer->moveToThread(certThread); + QObject::connect(certThread, SIGNAL(started()), consumer, SLOT(start())); + QObject::connect(consumer, SIGNAL(finished()), certThread, SLOT(quit()), Qt::DirectConnection); + + certThread->start(); + certThread->wait(); + foreach (const QByteArray &encodedCert, consumer->encodedCertificates()) { + QSslCertificate cert(encodedCert, QSsl::Der); + if (!cert.isNull()) + systemCerts.append(cert); + } + + delete consumer; + delete certThread; #endif + return systemCerts; } diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h index 3c08757..e41320d 100644 --- a/src/network/ssl/qsslsocket_openssl_p.h +++ b/src/network/ssl/qsslsocket_openssl_p.h @@ -118,6 +118,70 @@ public: static QList STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509); }; +#if defined(Q_OS_SYMBIAN) +#include // link against certstore.lib +#include // link against ctframework.lib + +class QCertificateRetriever; + +class QCertificateConsumer : public QObject +{ + Q_OBJECT +public: + QCertificateConsumer(QObject* parent = 0); + ~QCertificateConsumer(); + + void finish(); + + void addEncodedCertificate(const QByteArray& certificate) + { certificates.append(certificate); } + QList encodedCertificates() const { return certificates; } + +public slots: + void start(); + +signals: + void finished(); + +private: + QList certificates; + QCertificateRetriever *retriever; +}; + + +class QCertificateRetriever : public CActive +{ +public: + QCertificateRetriever(QCertificateConsumer* consumer); + ~QCertificateRetriever(); + + void fetch(); + +private: + virtual void RunL(); + virtual void DoCancel(); + + void list(); + void retrieveNextCertificate(); + + enum { + Initializing, + Listing, + RetrievingCertificates + } state; + + CUnifiedCertStore* certStore; + RMPointerArray certs; + CCertAttributeFilter* certFilter; + QCertificateConsumer* consumer; + int currentCertificateIndex; + QByteArray currentCertificate; + TPtr8 certDescriptor; +}; + +#endif + + QT_END_NAMESPACE #endif -- cgit v0.12 From 92b6ca830f279cfa9d37946f1fd72843b24e704b Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 2 Jul 2010 17:38:10 +0200 Subject: fix bogus return value from qprocess::execute() Task-number: QTBUG-230, QTBUG-5866 Reviewed-by: joerg --- src/corelib/io/qprocess.cpp | 14 ++++++++++---- tests/auto/qprocess/tst_qprocess.cpp | 9 +++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 8eba2b0..4c21a40 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -2082,14 +2082,19 @@ QProcess::ExitStatus QProcess::exitStatus() const process. On Windows, arguments that contain spaces are wrapped in quotes. + + If the process cannot be started, -2 is returned. If the process + crashes, -1 is returned. Otherwise, the process' exit code is + returned. */ int QProcess::execute(const QString &program, const QStringList &arguments) { QProcess process; process.setReadChannelMode(ForwardedChannels); process.start(program, arguments); - process.waitForFinished(-1); - return process.exitCode(); + if (!process.waitForFinished(-1)) + return -2; + return process.exitStatus() == QProcess::NormalExit ? process.exitCode() : -1; } /*! @@ -2104,8 +2109,9 @@ int QProcess::execute(const QString &program) QProcess process; process.setReadChannelMode(ForwardedChannels); process.start(program); - process.waitForFinished(-1); - return process.exitCode(); + if (!process.waitForFinished(-1)) + return -2; + return process.exitStatus() == QProcess::NormalExit ? process.exitCode() : -1; } /*! diff --git a/tests/auto/qprocess/tst_qprocess.cpp b/tests/auto/qprocess/tst_qprocess.cpp index 8dae9a0..8242d30 100644 --- a/tests/auto/qprocess/tst_qprocess.cpp +++ b/tests/auto/qprocess/tst_qprocess.cpp @@ -93,6 +93,7 @@ private slots: void getSetCheck(); void constructing(); void simpleStart(); + void execute(); void startDetached(); void crashTest(); void crashTest2(); @@ -284,6 +285,14 @@ void tst_QProcess::simpleStart() QCOMPARE(qVariantValue(spy.at(2).at(0)), QProcess::NotRunning); } //----------------------------------------------------------------------------- +void tst_QProcess::execute() +{ + QCOMPARE(QProcess::execute("testProcessNormal/testProcessNormal", + QStringList() << "arg1" << "arg2"), 0); + QCOMPARE(QProcess::execute("nonexistingexe"), -2); +} + +//----------------------------------------------------------------------------- void tst_QProcess::startDetached() { QProcess proc; -- cgit v0.12 From 4fe7291edcac2688f042a11ff5c23374c6c0375d Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 6 Jul 2010 13:56:38 +0200 Subject: add setNativeArguments() and nativeArguments() this function enables starting subprocesses which need command lines which cannot be constructed via the portable list-based api. such cases would be programs which need quoting rules which diverge from the msvc runtime. Reviewed-by: joerg Task-number: QTBUG-7620 (and various others which boil down to that) --- src/corelib/io/qprocess.cpp | 44 ++++++++++++++++++ src/corelib/io/qprocess.h | 5 +++ src/corelib/io/qprocess_p.h | 3 ++ src/corelib/io/qprocess_symbian.cpp | 17 ++++--- src/corelib/io/qprocess_win.cpp | 5 +++ src/s60installs/bwins/QtCoreu.def | 2 + src/s60installs/eabi/QtCoreu.def | 2 + tests/auto/qprocess/testProcessSpacesArgs/main.cpp | 7 ++- tests/auto/qprocess/tst_qprocess.cpp | 52 ++++++++++++++++++++++ 9 files changed, 129 insertions(+), 8 deletions(-) diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 4c21a40..9bc4063 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -1377,6 +1377,50 @@ void QProcess::setStandardOutputProcess(QProcess *destination) dto->stdinChannel.pipeFrom(dfrom); } +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + +/*! + \since 4.7 + + Returns the additional native command line arguments for the program. + + \note This function is available only on the Windows and Symbian + platforms. + + \sa setNativeArguments() +*/ +QString QProcess::nativeArguments() const +{ + Q_D(const QProcess); + return d->nativeArguments; +} + +/*! + \since 4.7 + \overload + + Sets additional native command line arguments for the program. + + On operating systems where the system API for passing command line + arguments to a subprocess natively uses a single string, one can + conceive command lines which cannot be passed via QProcess's portable + list-based API. In such cases this function must be used to set a + string which is \e appended to the string composed from the usual + argument list, with a delimiting space. + + \note This function is available only on the Windows and Symbian + platforms. + + \sa nativeArguments() +*/ +void QProcess::setNativeArguments(const QString &arguments) +{ + Q_D(QProcess); + d->nativeArguments = arguments; +} + +#endif + /*! If QProcess has been assigned a working directory, this function returns the working directory that the QProcess will enter before the program has diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h index f84b855..b07d742 100644 --- a/src/corelib/io/qprocess.h +++ b/src/corelib/io/qprocess.h @@ -148,6 +148,11 @@ public: void setStandardErrorFile(const QString &fileName, OpenMode mode = Truncate); void setStandardOutputProcess(QProcess *destination); +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + QString nativeArguments() const; + void setNativeArguments(const QString &arguments); +#endif + QString workingDirectory() const; void setWorkingDirectory(const QString &dir); diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h index 60b7b5a..8b7e3ff 100644 --- a/src/corelib/io/qprocess_p.h +++ b/src/corelib/io/qprocess_p.h @@ -181,6 +181,9 @@ public: QString program; QStringList arguments; +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + QString nativeArguments; +#endif QProcessEnvironment environment; QRingBuffer outputReadBuffer; diff --git a/src/corelib/io/qprocess_symbian.cpp b/src/corelib/io/qprocess_symbian.cpp index 92212fe..af657b2 100644 --- a/src/corelib/io/qprocess_symbian.cpp +++ b/src/corelib/io/qprocess_symbian.cpp @@ -219,7 +219,8 @@ static bool qt_rprocess_running(RProcess *proc) return false; } -static void qt_create_symbian_commandline(const QStringList &arguments, QString &commandLine) +static void qt_create_symbian_commandline( + const QStringList &arguments, const QString &nativeArguments, QString &commandLine) { for (int i = 0; i < arguments.size(); ++i) { QString tmp = arguments.at(i); @@ -243,12 +244,14 @@ static void qt_create_symbian_commandline(const QStringList &arguments, QString } } - // Chop the extra trailing space if any arguments were appended - if (arguments.size()) + if (!nativeArguments.isEmpty()) + commandLine += nativeArguments; + else if (!commandLine.isEmpty()) // Chop the extra trailing space if any arguments were appended commandLine.chop(1); } -static TInt qt_create_symbian_process(RProcess **proc, const QString &programName, const QStringList &arguments) +static TInt qt_create_symbian_process(RProcess **proc, + const QString &programName, const QStringList &arguments, const QString &nativeArguments) { RProcess *newProc = NULL; newProc = new RProcess(); @@ -257,7 +260,7 @@ static TInt qt_create_symbian_process(RProcess **proc, const QString &programNam return KErrNoMemory; QString commandLine; - qt_create_symbian_commandline(arguments, commandLine); + qt_create_symbian_commandline(arguments, nativeArguments, commandLine); TPtrC program_ptr(reinterpret_cast(programName.constData())); TPtrC cmdline_ptr(reinterpret_cast(commandLine.constData())); @@ -794,7 +797,7 @@ void QProcessPrivate::startProcess() q, SLOT(_q_processDied())); } - TInt err = qt_create_symbian_process(&symbianProcess, program, arguments); + TInt err = qt_create_symbian_process(&symbianProcess, program, arguments, nativeArguments); if (err == KErrNone) { pid = symbianProcess->Id().Id(); @@ -1030,7 +1033,7 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a RProcess *newProc = NULL; - TInt err = qt_create_symbian_process(&newProc, program, arguments); + TInt err = qt_create_symbian_process(&newProc, program, arguments, QString()); if (err == KErrNone) { if (pid) diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index cb25a58..702349f 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -366,6 +366,11 @@ void QProcessPrivate::startProcess() if (environment.d.constData()) envlist = qt_create_environment(environment.d.constData()->hash); #endif + if (!nativeArguments.isEmpty()) { + if (!args.isEmpty()) + args += QLatin1Char(' '); + args += nativeArguments; + } #if defined QPROCESS_DEBUG qDebug("Creating process"); diff --git a/src/s60installs/bwins/QtCoreu.def b/src/s60installs/bwins/QtCoreu.def index 101c6a8..94be1bb 100644 --- a/src/s60installs/bwins/QtCoreu.def +++ b/src/s60installs/bwins/QtCoreu.def @@ -4482,4 +4482,6 @@ EXPORTS ?textDirection@QLocale@@QBE?AW4LayoutDirection@Qt@@XZ @ 4481 NONAME ; enum Qt::LayoutDirection QLocale::textDirection(void) const ?peek@QIODevicePrivate@@UAE_JPAD_J@Z @ 4482 NONAME ; long long QIODevicePrivate::peek(char *, long long) ?peek@QIODevicePrivate@@UAE?AVQByteArray@@_J@Z @ 4483 NONAME ; class QByteArray QIODevicePrivate::peek(long long) + ?nativeArguments@QProcess@@QBE?AVQString@@XZ @ 4484 NONAME ; class QString QProcess::nativeArguments(void) const + ?setNativeArguments@QProcess@@QAEXABVQString@@@Z @ 4485 NONAME ; void QProcess::setNativeArguments(class QString const &) diff --git a/src/s60installs/eabi/QtCoreu.def b/src/s60installs/eabi/QtCoreu.def index 7b9e777..46c4885 100644 --- a/src/s60installs/eabi/QtCoreu.def +++ b/src/s60installs/eabi/QtCoreu.def @@ -3709,4 +3709,6 @@ EXPORTS _ZNK7QString13isRightToLeftEv @ 3708 NONAME _ZN16QIODevicePrivate4peekEPcx @ 3709 NONAME _ZN16QIODevicePrivate4peekEx @ 3710 NONAME + _ZN8QProcess18setNativeArgumentsERK7QString @ 3711 NONAME + _ZNK8QProcess15nativeArgumentsEv @ 3712 NONAME diff --git a/tests/auto/qprocess/testProcessSpacesArgs/main.cpp b/tests/auto/qprocess/testProcessSpacesArgs/main.cpp index d842934..ae5d3ae 100644 --- a/tests/auto/qprocess/testProcessSpacesArgs/main.cpp +++ b/tests/auto/qprocess/testProcessSpacesArgs/main.cpp @@ -44,9 +44,14 @@ int main(int argc, char ** argv) { -#if defined(__SYMBIAN32__) +#if defined(__SYMBIAN32__) || defined(WINCE) || defined(_WIN32_WCE) +# if defined(__SYMBIAN32__) // Printing to stdout messes up the out.txt, so open a file and print there. FILE* file = fopen("c:\\logs\\qprocess_args_test.txt","w+"); +# else + // No pipes on this "OS" + FILE* file = fopen("\\temp\\qprocess_args_test.txt","w+"); +# endif for (int i = 0; i < argc; ++i) { if (i) fprintf(file, "|"); diff --git a/tests/auto/qprocess/tst_qprocess.cpp b/tests/auto/qprocess/tst_qprocess.cpp index 8242d30..fd310f4 100644 --- a/tests/auto/qprocess/tst_qprocess.cpp +++ b/tests/auto/qprocess/tst_qprocess.cpp @@ -132,6 +132,9 @@ private slots: void waitForBytesWrittenInABytesWrittenSlot(); void spaceArgsTest_data(); void spaceArgsTest(); +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + void nativeArguments(); +#endif void exitCodeTest(); void setEnvironment_data(); void setEnvironment(); @@ -1630,6 +1633,55 @@ void tst_QProcess::spaceArgsTest() process = 0; } +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + +//----------------------------------------------------------------------------- +void tst_QProcess::nativeArguments() +{ + QProcess proc; + + // This doesn't actually need special quoting, so it is pointless to use + // native arguments here, but that's not the point of this test. + proc.setNativeArguments("hello kitty, \"*\"!"); + + proc.start(QString::fromLatin1("testProcessSpacesArgs/nospace"), QStringList()); + +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + QVERIFY(proc.waitForStarted(5000)); + QVERIFY(proc.waitForFinished(5000)); +#else + QVERIFY(proc.waitForStarted(10000)); + QVERIFY(proc.waitForFinished(10000)); +#endif + +#if defined(Q_OS_SYMBIAN) || defined(Q_OS_WINCE) + // Symbian test outputs to a file, so check that +# ifdef Q_OS_SYMBIAN + FILE* file = fopen("c:\\logs\\qprocess_args_test.txt","r"); +# else + FILE* file = fopen("\\temp\\qprocess_args_test.txt","r"); +# endif + char buf[256]; + fgets(buf, 256, file); + fclose(file); + QStringList actual = QString::fromLatin1(buf).split("|"); +#else + QStringList actual = QString::fromLatin1(proc.readAll()).split("|"); +#endif + QVERIFY(!actual.isEmpty()); + // not interested in the program name, it might be different. + actual.removeFirst(); + QStringList expected; +#if defined(Q_OS_WINCE) + expected << "hello" << "kitty," << "\"*\"!"; // Weird, weird ... +#else + expected << "hello" << "kitty," << "*!"; +#endif + QCOMPARE(actual, expected); +} + +#endif + //----------------------------------------------------------------------------- void tst_QProcess::exitCodeTest() { -- cgit v0.12 From fa9c62460791c9b9add365fc9543ec0392f50cee Mon Sep 17 00:00:00 2001 From: Thomas Zander Date: Mon, 5 Jul 2010 17:05:04 +0200 Subject: Adapt the TapAndHold recognizer to non-touch too The QTapAndHoldGestureRecognizer now can trigger also on mouse and GraphicsSceneMouse events and all of them will cause the gesture start event to be sent after the touch interval timed out. Reviewed-by: Denis --- src/gui/kernel/qstandardgestures.cpp | 63 +++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/src/gui/kernel/qstandardgestures.cpp b/src/gui/kernel/qstandardgestures.cpp index 8a3e89e..62d8a53 100644 --- a/src/gui/kernel/qstandardgestures.cpp +++ b/src/gui/kernel/qstandardgestures.cpp @@ -45,6 +45,7 @@ #include "qevent.h" #include "qwidget.h" #include "qabstractscrollarea.h" +#include #include "qdebug.h" #ifndef QT_NO_GESTURES @@ -509,49 +510,65 @@ QTapAndHoldGestureRecognizer::recognize(QGesture *state, QObject *object, if (object == state && event->type() == QEvent::Timer) { q->killTimer(d->timerId); d->timerId = 0; - return QGestureRecognizer::Ignore | QGestureRecognizer::ConsumeEventHint; + return QGestureRecognizer::FinishGesture | QGestureRecognizer::ConsumeEventHint; } const QTouchEvent *ev = static_cast(event); - - QGestureRecognizer::Result result = QGestureRecognizer::CancelGesture; + const QMouseEvent *me = static_cast(event); + const QGraphicsSceneMouseEvent *gsme = static_cast(event); enum { TimerInterval = 2000 }; enum { TapRadius = 40 }; switch (event->type()) { + case QEvent::GraphicsSceneMousePress: + d->position = gsme->screenPos(); + q->setHotSpot(d->position); + if (d->timerId) + q->killTimer(d->timerId); + d->timerId = q->startTimer(TimerInterval); + return QGestureRecognizer::MayBeGesture; // we don't show a sign of life until the timeout + case QEvent::MouseButtonPress: + d->position = me->globalPos(); + q->setHotSpot(d->position); + if (d->timerId) + q->killTimer(d->timerId); + d->timerId = q->startTimer(TimerInterval); + return QGestureRecognizer::MayBeGesture; // we don't show a sign of life until the timeout case QEvent::TouchBegin: - d->position = ev->touchPoints().at(0).pos(); + d->position = ev->touchPoints().at(0).startScreenPos(); + q->setHotSpot(d->position); if (d->timerId) q->killTimer(d->timerId); d->timerId = q->startTimer(TimerInterval); - q->setHotSpot(ev->touchPoints().at(0).startScreenPos()); - result = QGestureRecognizer::TriggerGesture; - break; + return QGestureRecognizer::MayBeGesture; // we don't show a sign of life until the timeout + case QEvent::GraphicsSceneMouseRelease: + case QEvent::MouseButtonRelease: case QEvent::TouchEnd: - if (d->timerId) - result = QGestureRecognizer::CancelGesture; - else - result = QGestureRecognizer::FinishGesture; - break; + return QGestureRecognizer::CancelGesture; // get out of the MayBeGesture state case QEvent::TouchUpdate: - if (q->state() != Qt::NoGesture && ev->touchPoints().size() == 1) { + if (d->timerId && ev->touchPoints().size() == 1) { QTouchEvent::TouchPoint p = ev->touchPoints().at(0); QPoint delta = p.pos().toPoint() - p.startPos().toPoint(); if (delta.manhattanLength() <= TapRadius) - result = QGestureRecognizer::TriggerGesture; + return QGestureRecognizer::MayBeGesture; } - break; - case QEvent::MouseButtonPress: - case QEvent::MouseMove: - case QEvent::MouseButtonRelease: - result = QGestureRecognizer::Ignore; - break; + return QGestureRecognizer::CancelGesture; + case QEvent::MouseMove: { + QPoint delta = me->globalPos() - d->position.toPoint(); + if (d->timerId && delta.manhattanLength() <= TapRadius) + return QGestureRecognizer::MayBeGesture; + return QGestureRecognizer::CancelGesture; + } + case QEvent::GraphicsSceneMouseMove: { + QPoint delta = gsme->screenPos() - d->position.toPoint(); + if (d->timerId && delta.manhattanLength() <= TapRadius) + return QGestureRecognizer::MayBeGesture; + return QGestureRecognizer::CancelGesture; + } default: - result = QGestureRecognizer::Ignore; - break; + return QGestureRecognizer::Ignore; } - return result; } void QTapAndHoldGestureRecognizer::reset(QGesture *state) -- cgit v0.12 From 2fa8b39c8a687550934e9668384f0bbe9f56f550 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 6 Jul 2010 19:08:45 +0200 Subject: fix autotest fixing QProcess::execute() revealed that this test has always been broken on windows. --- tests/auto/linguist/lrelease/tst_lrelease.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/auto/linguist/lrelease/tst_lrelease.cpp b/tests/auto/linguist/lrelease/tst_lrelease.cpp index fdb384e..3b2c2d2 100644 --- a/tests/auto/linguist/lrelease/tst_lrelease.cpp +++ b/tests/auto/linguist/lrelease/tst_lrelease.cpp @@ -171,7 +171,12 @@ void tst_lrelease::mixedcodecs() { QVERIFY(!QProcess::execute(binDir + "/lrelease testdata/mixedcodecs-ts11.ts")); QVERIFY(!QProcess::execute(binDir + "/lrelease testdata/mixedcodecs-ts20.ts")); +#ifdef Q_OS_WIN + QVERIFY(!QProcess::execute("fc /b testdata\\mixedcodecs-ts11.qm testdata\\mixedcodecs-ts20.qm")); +#else QVERIFY(!QProcess::execute("cmp testdata/mixedcodecs-ts11.qm testdata/mixedcodecs-ts20.qm")); +#endif + QTranslator translator; QVERIFY(translator.load("testdata/mixedcodecs-ts11.qm")); qApp->installTranslator(&translator); -- cgit v0.12 753' href='#n753'>753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * Copyright by the Board of Trustees of the University of Illinois.         *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
 * terms governing use, modification, and redistribution, is contained in    *
 * the COPYING file, which can be found at the root of the source code       *
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/****************/
/* Module Setup */
/****************/

#include "H5Dmodule.h" /* This source code file is part of the H5D module */

/***********/
/* Headers */
/***********/
#include "H5private.h"   /* Generic Functions                        */
#include "H5CXprivate.h" /* API Contexts                             */
#include "H5Dpkg.h"      /* Dataset functions                        */
#include "H5Eprivate.h"  /* Error handling                           */
#include "H5FLprivate.h" /* Free Lists                               */
#include "H5Iprivate.h"  /* IDs                                      */
#include "H5MMprivate.h" /* Memory management                        */
#include "H5Sprivate.h"  /* Dataspace                                */

#include "H5VLnative_private.h" /* Native VOL connector                     */

/****************/
/* Local Macros */
/****************/

/******************/
/* Local Typedefs */
/******************/

/********************/
/* Local Prototypes */
/********************/

/* Setup/teardown routines */
static herr_t H5D__ioinfo_init(size_t count, H5D_dset_io_info_t *dset_info, H5D_io_info_t *io_info);
static herr_t H5D__dset_ioinfo_init(H5D_t *dset, H5D_dset_io_info_t *dset_info, H5D_storage_t *store);
static herr_t H5D__typeinfo_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, hid_t mem_type_id);
static herr_t H5D__typeinfo_init_phase2(H5D_io_info_t *io_info);
#ifdef H5_HAVE_PARALLEL
static herr_t H5D__ioinfo_adjust(H5D_io_info_t *io_info);
#endif /* H5_HAVE_PARALLEL */
static herr_t H5D__typeinfo_term(H5D_io_info_t *io_info, size_t type_info_init);

/*********************/
/* Package Variables */
/*********************/

/*******************/
/* Local Variables */
/*******************/

/* Declare a free list to manage blocks of type conversion data */
H5FL_BLK_DEFINE(type_conv);

/*-------------------------------------------------------------------------
 * Function:	H5D__read
 *
 * Purpose:	Reads multiple (parts of) DATASETs into application memory BUFs.
 *              See H5Dread_multi() for complete details.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5D__read(size_t count, H5D_dset_io_info_t *dset_info)
{
    H5D_io_info_t io_info;                    /* Dataset I/O info  for multi dsets */
    size_t        type_info_init = 0;         /* Number of datatype info structs that have been initialized */
    H5S_t        *orig_mem_space_local;       /* Local buffer for orig_mem_space */
    H5S_t       **orig_mem_space = NULL;      /* If not NULL, ptr to an array of dataspaces       */
                                              /* containing the original memory spaces contained  */
                                              /* in dset_info.  This is needed in order to        */
                                              /* restore the original state of  dset_info if we   */
                                              /* replaced any mem spaces with equivalents         */
                                              /* projected to a rank equal to that of file_space. */
                                              /*                                                  */
                                              /* This field is only used if                       */
                                              /* H5S_select_shape_same() returns TRUE when        */
                                              /* comparing at least one mem_space and data_space, */
                                              /* and the mem_space has a different rank.          */
                                              /*                                                  */
                                              /* Note that this is a temporary variable - the     */
                                              /* projected memory space is stored in dset_info,   */
                                              /* and will be freed when that structure is         */
                                              /* freed. */
    H5D_storage_t  store_local;               /* Local buffer for store */
    H5D_storage_t *store      = &store_local; /* Union of EFL and chunk pointer in file space */
    size_t         io_op_init = 0;            /* Number I/O ops that have been initialized */
    size_t         io_skipped =
        0;            /* Number I/O ops that have been skipped (due to the dataset not being allocated) */
    size_t i;         /* Local index variable */
    char   fake_char; /* Temporary variable for NULL buffer pointers */
    herr_t ret_value = SUCCEED; /* Return value	*/

    FUNC_ENTER_NOAPI(FAIL)

    /* Init io_info */
    if (H5D__ioinfo_init(count, dset_info, &io_info) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info")
    io_info.op_type = H5D_IO_OP_READ;

    /* Allocate store buffer if necessary */
    if (count > 1)
        if (NULL == (store = (H5D_storage_t *)H5MM_malloc(count * sizeof(H5D_storage_t))))
            HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate dset storage info array buffer")

#ifdef H5_HAVE_PARALLEL
    /* Check for non-MPI-based VFD.  Only need to check first dataset since all
     * share the same file. */
    if (!(H5F_HAS_FEATURE(dset_info[0].dset->oloc.file, H5FD_FEAT_HAS_MPI))) {
        H5FD_mpio_xfer_t io_xfer_mode; /* MPI I/O transfer mode */

        /* Get I/O transfer mode */
        if (H5CX_get_io_xfer_mode(&io_xfer_mode) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get MPI-I/O transfer mode")

        /* Collective access is not permissible without a MPI based VFD */
        if (io_xfer_mode == H5FD_MPIO_COLLECTIVE)
            HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "collective access for MPI-based drivers only")
    }  /* end if */
#endif /*H5_HAVE_PARALLEL*/

    /* iterate over all dsets and construct I/O information necessary to do I/O */
    for (i = 0; i < count; i++) {
        haddr_t prev_tag = HADDR_UNDEF;

        /* check args */
        if (NULL == dset_info[i].dset)
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
        if (NULL == dset_info[i].dset->oloc.file)
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")

        /* set metadata tagging with dset oheader addr */
        H5AC_tag(dset_info[i].dset->oloc.addr, &prev_tag);

        /* Set up datatype info for operation */
        if (H5D__typeinfo_init(&io_info, &(dset_info[i]), dset_info[i].mem_type_id) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info")
        type_info_init++;

        /* Make certain that the number of elements in each selection is the same, and cache nelmts in
         * dset_info */
        dset_info[i].nelmts = H5S_GET_SELECT_NPOINTS(dset_info[i].mem_space);
        if (dset_info[i].nelmts != H5S_GET_SELECT_NPOINTS(dset_info[i].file_space))
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,
                        "src and dest dataspaces have different number of elements selected")

        /* Check for a NULL buffer */
        if (NULL == dset_info[i].buf.vp) {
            /* Check for any elements selected (which is invalid) */
            if (dset_info[i].nelmts > 0)
                HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer")

            /* If the buffer is nil, and 0 element is selected, make a fake buffer.
             * This is for some MPI package like ChaMPIon on NCSA's tungsten which
             * doesn't support this feature.
             */
            dset_info[i].buf.vp = &fake_char;
        } /* end if */

        /* Make sure that both selections have their extents set */
        if (!(H5S_has_extent(dset_info[i].file_space)))
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file dataspace does not have extent set")
        if (!(H5S_has_extent(dset_info[i].mem_space)))
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "memory dataspace does not have extent set")

        /* H5S_select_shape_same() has been modified to accept topologically identical
         * selections with different rank as having the same shape (if the most
         * rapidly changing coordinates match up), but the I/O code still has
         * difficulties with the notion.
         *
         * To solve this, we check to see if H5S_select_shape_same() returns true,
         * and if the ranks of the mem and file spaces are different.  If they are,
         * construct a new mem space that is equivalent to the old mem space, and
         * use that instead.
         *
         * Note that in general, this requires us to touch up the memory buffer as
         * well.
         */
        if (dset_info[i].nelmts > 0 &&
            TRUE == H5S_SELECT_SHAPE_SAME(dset_info[i].mem_space, dset_info[i].file_space) &&
            H5S_GET_EXTENT_NDIMS(dset_info[i].mem_space) != H5S_GET_EXTENT_NDIMS(dset_info[i].file_space)) {
            ptrdiff_t buf_adj = 0;

            /* Allocate original memory space buffer if necessary */
            if (!orig_mem_space) {
                if (count > 1) {
                    /* Allocate buffer */
                    if (NULL == (orig_mem_space = (H5S_t **)H5MM_calloc(count * sizeof(H5S_t *))))
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL,
                                    "couldn't allocate original memory space array buffer")
                }
                else
                    /* Use local buffer */
                    orig_mem_space = &orig_mem_space_local;
            }

            /* Save original memory space */
            orig_mem_space[i]      = dset_info[i].mem_space;
            dset_info[i].mem_space = NULL;

            /* Attempt to construct projected dataspace for memory dataspace */
            if (H5S_select_construct_projection(orig_mem_space[i], &dset_info[i].mem_space,
                                                (unsigned)H5S_GET_EXTENT_NDIMS(dset_info[i].file_space),
                                                (hsize_t)dset_info[i].type_info.dst_type_size, &buf_adj) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to construct projected memory dataspace")
            HDassert(dset_info[i].mem_space);

            /* Adjust the buffer by the given amount */
            dset_info[i].buf.vp = (void *)(((uint8_t *)dset_info[i].buf.vp) + buf_adj);
        } /* end if */

        /* If space hasn't been allocated and not using external storage,
         * return fill value to buffer if fill time is upon allocation, or
         * do nothing if fill time is never.  If the dataset is compact and
         * fill time is NEVER, there is no way to tell whether part of data
         * has been overwritten.  So just proceed in reading.
         */
        if (dset_info[i].nelmts > 0 && dset_info[i].dset->shared->dcpl_cache.efl.nused == 0 &&
            !(*dset_info[i].dset->shared->layout.ops->is_space_alloc)(
                &dset_info[i].dset->shared->layout.storage) &&
            !(dset_info[i].dset->shared->layout.ops->is_data_cached &&
              (*dset_info[i].dset->shared->layout.ops->is_data_cached)(dset_info[i].dset->shared))) {
            H5D_fill_value_t fill_status; /* Whether/How the fill value is defined */

            /* Retrieve dataset's fill-value properties */
            if (H5P_is_fill_value_defined(&dset_info[i].dset->shared->dcpl_cache.fill, &fill_status) < 0)
                HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined")

            /* Should be impossible, but check anyway... */
            if (fill_status == H5D_FILL_VALUE_UNDEFINED &&
                (dset_info[i].dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_ALLOC ||
                 dset_info[i].dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_IFSET))
                HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL,
                            "read failed: dataset doesn't exist, no data can be read")

            /* If we're never going to fill this dataset, just leave the junk in the user's buffer */
            if (dset_info[i].dset->shared->dcpl_cache.fill.fill_time != H5D_FILL_TIME_NEVER)
                /* Go fill the user's selection with the dataset's fill value */
                if (H5D__fill(dset_info[i].dset->shared->dcpl_cache.fill.buf, dset_info[i].dset->shared->type,
                              dset_info[i].buf.vp, dset_info[i].type_info.mem_type,
                              dset_info[i].mem_space) < 0)
                    HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "filling buf failed")

            /* No need to perform any more I/O for this dataset */
            dset_info[i].skip_io = TRUE;
            io_skipped++;
        } /* end if */
        else {
            /* Set up I/O operation */
            if (H5D__dset_ioinfo_init(dset_info[i].dset, &(dset_info[i]), &(store[i])) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to set up I/O operation")

            /* Sanity check that space is allocated, if there are elements */
            if (dset_info[i].nelmts > 0)
                HDassert(
                    (*dset_info[i].dset->shared->layout.ops->is_space_alloc)(
                        &dset_info[i].dset->shared->layout.storage) ||
                    (dset_info[i].dset->shared->layout.ops->is_data_cached &&
                     (*dset_info[i].dset->shared->layout.ops->is_data_cached)(dset_info[i].dset->shared)) ||
                    dset_info[i].dset->shared->dcpl_cache.efl.nused > 0 ||
                    dset_info[i].dset->shared->layout.type == H5D_COMPACT);

            /* Call storage method's I/O initialization routine */
            if (dset_info[i].layout_ops.io_init &&
                (dset_info[i].layout_ops.io_init)(&io_info, &(dset_info[i])) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info")
            dset_info[i].skip_io = FALSE;
            io_op_init++;

            /* Reset metadata tagging */
            H5AC_tag(prev_tag, NULL);
        }
    } /* end of for loop */

    HDassert(type_info_init == count);
    HDassert(io_op_init + io_skipped == count);

    /* If no datasets have I/O, we're done */
    if (io_op_init == 0)
        HGOTO_DONE(SUCCEED)

    /* Perform second phase of type info initialization */
    if (H5D__typeinfo_init_phase2(&io_info) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info (second phase)")

#ifdef H5_HAVE_PARALLEL
    /* Adjust I/O info for any parallel I/O */
    if (H5D__ioinfo_adjust(&io_info) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to adjust I/O info for parallel I/O")
#endif /*H5_HAVE_PARALLEL*/

    /* If multi dataset I/O callback is not provided, perform read IO via
     * single-dset path with looping */
    if (io_info.md_io_ops.multi_read_md) {
        /* Create sel_pieces array if any pieces are selected */
        if (io_info.piece_count > 0) {
            HDassert(!io_info.sel_pieces);
            HDassert(io_info.pieces_added == 0);

            /* Allocate sel_pieces array */
            if (NULL ==
                (io_info.sel_pieces = H5MM_malloc(io_info.piece_count * sizeof(io_info.sel_pieces[0]))))
                HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "unable to allocate array of selected pieces")
        }

        /* MDIO-specific second phase initialization */
        for (i = 0; i < count; i++)
            if (dset_info[i].layout_ops.mdio_init) {
                haddr_t prev_tag = HADDR_UNDEF;

                /* set metadata tagging with dset oheader addr */
                H5AC_tag(dset_info[i].dset->oloc.addr, &prev_tag);

                /* Make second phase IO init call */
                if ((dset_info[i].layout_ops.mdio_init)(&io_info, &(dset_info[i])) < 0)
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't populate array of selected pieces")

                /* Reset metadata tagging */
                H5AC_tag(prev_tag, NULL);
            }

        /* Invoke correct "high level" I/O routine */
        if ((*io_info.md_io_ops.multi_read_md)(&io_info) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data")
    } /* end if */
    else {
        haddr_t prev_tag = HADDR_UNDEF;

        if (!H5D_LAYOUT_CB_PERFORM_IO(&io_info) && io_info.piece_count > 0) {
            if (NULL == (io_info.mem_spaces = H5MM_malloc(io_info.piece_count * sizeof(H5S_t *))))
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                            "memory allocation failed for memory space list")
            if (NULL == (io_info.file_spaces = H5MM_malloc(io_info.piece_count * sizeof(H5S_t *))))
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for file space list")
            if (NULL == (io_info.addrs = H5MM_malloc(io_info.piece_count * sizeof(haddr_t))))
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                            "memory allocation failed for piece address list")
            if (NULL == (io_info.element_sizes = H5MM_malloc(io_info.piece_count * sizeof(size_t))))
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                            "memory allocation failed for element size list")
            if (NULL == (io_info.rbufs = H5MM_malloc(io_info.piece_count * sizeof(void *))))
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                            "memory allocation failed for read buffer list")
        }

        /* Loop with serial & single-dset read IO path */
        for (i = 0; i < count; i++) {
            /* Check for skipped I/O */
            if (dset_info[i].skip_io)
                continue;

            /* set metadata tagging with dset oheader addr */
            H5AC_tag(dset_info[i].dset->oloc.addr, &prev_tag);

            /* Invoke correct "high level" I/O routine */
            if ((*dset_info[i].io_ops.multi_read)(&io_info, &dset_info[i]) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data")

            /* Reset metadata tagging */
            H5AC_tag(prev_tag, NULL);
        }

        /* Make final multi dataset selection I/O call if we are using both
         * features - in this case the multi_read callbacks did not perform the
         * actual I/O */
        H5_CHECK_OVERFLOW(io_info.pieces_added, size_t, uint32_t)
        if (!H5D_LAYOUT_CB_PERFORM_IO(&io_info))
            if (H5F_shared_select_read(io_info.f_sh, H5FD_MEM_DRAW, (uint32_t)io_info.pieces_added,
                                       io_info.mem_spaces, io_info.file_spaces, io_info.addrs,
                                       io_info.element_sizes, io_info.rbufs) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "selection read failed")
    }

done:
    /* Shut down the I/O op information */
    for (i = 0; i < io_op_init; i++)
        if (!dset_info[i].skip_io && dset_info[i].layout_ops.io_term &&
            (*dset_info[i].layout_ops.io_term)(&io_info, &(dset_info[i])) < 0)
            HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down I/O op info")

    /* Shut down datatype info for operation */
    if (H5D__typeinfo_term(&io_info, type_info_init) < 0)
        HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down type info")

    /* Discard projected mem spaces and restore originals */
    if (orig_mem_space) {
        for (i = 0; i < count; i++)
            if (orig_mem_space[i]) {
                if (H5S_close(dset_info[i].mem_space) < 0)
                    HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL,
                                "unable to shut down projected memory dataspace")
                dset_info[i].mem_space = orig_mem_space[i];
            }

        /* Free orig_mem_space array if it was allocated */
        if (orig_mem_space != &orig_mem_space_local)
            H5MM_free(orig_mem_space);
    }

    /* Free global piece array */
    H5MM_xfree(io_info.sel_pieces);

    /* Free selection I/O arrays */
    H5MM_xfree(io_info.mem_spaces);
    H5MM_xfree(io_info.file_spaces);
    H5MM_xfree(io_info.addrs);
    H5MM_xfree(io_info.element_sizes);
    H5MM_xfree(io_info.rbufs);

    /* Free store array if it was allocated */
    if (store != &store_local)
        H5MM_free(store);

    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5D__read() */

/*-------------------------------------------------------------------------
 * Function:	H5D__write
 *
 * Purpose:	Writes multiple (part of) DATASETs to a file from application
 *          memory BUFs. See H5Dwrite_multi() for complete details.
 *
 *          This was referred from H5D__write for multi-dset work.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5D__write(size_t count, H5D_dset_io_info_t *dset_info)
{
    H5D_io_info_t io_info;                    /* Dataset I/O info for multi dsets */
    size_t        type_info_init = 0;         /* Number of datatype info structs that have been initialized */
    H5S_t        *orig_mem_space_local;       /* Local buffer for orig_mem_space */
    H5S_t       **orig_mem_space = NULL;      /* If not NULL, ptr to an array of dataspaces       */
                                              /* containing the original memory spaces contained  */
                                              /* in dset_info.  This is needed in order to        */
                                              /* restore the original state of  dset_info if we   */
                                              /* replaced any mem spaces with equivalents         */
                                              /* projected to a rank equal to that of file_space. */
                                              /*                                                  */
                                              /* This field is only used if                       */
                                              /* H5S_select_shape_same() returns TRUE when        */
                                              /* comparing at least one mem_space and data_space, */
                                              /* and the mem_space has a different rank.          */
                                              /*                                                  */
                                              /* Note that this is a temporary variable - the     */
                                              /* projected memory space is stored in dset_info,   */
                                              /* and will be freed when that structure is         */
                                              /* freed. */
    H5D_storage_t  store_local;               /* Local buffer for store */
    H5D_storage_t *store      = &store_local; /* Union of EFL and chunk pointer in file space */
    size_t         io_op_init = 0;            /* Number I/O ops that have been initialized */
    size_t         i;                         /* Local index variable */
    char           fake_char;                 /* Temporary variable for NULL buffer pointers */
    herr_t         ret_value = SUCCEED;       /* Return value	*/

    FUNC_ENTER_NOAPI(FAIL)

    /* Init io_info */
    if (H5D__ioinfo_init(count, dset_info, &io_info) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info")
    io_info.op_type = H5D_IO_OP_WRITE;

    /* Allocate store buffer if necessary */
    if (count > 1)
        if (NULL == (store = (H5D_storage_t *)H5MM_malloc(count * sizeof(H5D_storage_t))))
            HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate dset storage info array buffer")

    /* iterate over all dsets and construct I/O information */
    for (i = 0; i < count; i++) {
        hbool_t should_alloc_space = FALSE; /* Whether or not to initialize dataset's storage */
        haddr_t prev_tag           = HADDR_UNDEF;

        /* check args */
        if (NULL == dset_info[i].dset)
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
        if (NULL == dset_info[i].dset->oloc.file)
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")

        /* set metadata tagging with dset oheader addr */
        H5AC_tag(dset_info[i].dset->oloc.addr, &prev_tag);

        /* All filters in the DCPL must have encoding enabled. */
        if (!dset_info[i].dset->shared->checked_filters) {
            if (H5Z_can_apply(dset_info[i].dset->shared->dcpl_id, dset_info[i].dset->shared->type_id) < 0)
                HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "can't apply filters")

            dset_info[i].dset->shared->checked_filters = TRUE;
        } /* end if */

        /* Check if we are allowed to write to this file */
        if (0 == (H5F_INTENT(dset_info[i].dset->oloc.file) & H5F_ACC_RDWR))
            HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "no write intent on file")

        /* Set up datatype info for operation */
        if (H5D__typeinfo_init(&io_info, &(dset_info[i]), dset_info[i].mem_type_id) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info")
        type_info_init++;

        /* Various MPI based checks */
#ifdef H5_HAVE_PARALLEL
        if (H5F_HAS_FEATURE(dset_info[i].dset->oloc.file, H5FD_FEAT_HAS_MPI)) {
            /* If MPI based VFD is used, no VL or region reference datatype support yet. */
            /* This is because they use the global heap in the file and we don't */
            /* support parallel access of that yet */
            if (H5T_is_vl_storage(dset_info[i].type_info.mem_type) > 0)
                HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL,
                            "Parallel IO does not support writing VL or region reference datatypes yet")
        } /* end if */
        else {
            H5FD_mpio_xfer_t io_xfer_mode; /* MPI I/O transfer mode */

            /* Get I/O transfer mode */
            if (H5CX_get_io_xfer_mode(&io_xfer_mode) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get MPI-I/O transfer mode")

            /* Collective access is not permissible without a MPI based VFD */
            if (io_xfer_mode == H5FD_MPIO_COLLECTIVE)
                HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "collective access for MPI-based driver only")
        } /* end else */
#endif    /*H5_HAVE_PARALLEL*/

        /* Make certain that the number of elements in each selection is the same, and cache nelmts in
         * dset_info */
        dset_info[i].nelmts = H5S_GET_SELECT_NPOINTS(dset_info[i].mem_space);
        if (dset_info[i].nelmts != H5S_GET_SELECT_NPOINTS(dset_info[i].file_space))
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,
                        "src and dest dataspaces have different number of elements selected")

        /* Check for a NULL buffer */
        if (NULL == dset_info[i].buf.cvp) {
            /* Check for any elements selected (which is invalid) */
            if (dset_info[i].nelmts > 0)
                HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer")

            /* If the buffer is nil, and 0 element is selected, make a fake buffer.
             * This is for some MPI package like ChaMPIon on NCSA's tungsten which
             * doesn't support this feature.
             */
            dset_info[i].buf.cvp = &fake_char;
        } /* end if */

        /* Make sure that both selections have their extents set */
        if (!(H5S_has_extent(dset_info[i].file_space)))
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file dataspace does not have extent set")
        if (!(H5S_has_extent(dset_info[i].mem_space)))
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "memory dataspace does not have extent set")

        /* H5S_select_shape_same() has been modified to accept topologically
         * identical selections with different rank as having the same shape
         * (if the most rapidly changing coordinates match up), but the I/O
         * code still has difficulties with the notion.
         *
         * To solve this, we check to see if H5S_select_shape_same() returns
         * true, and if the ranks of the mem and file spaces are different.
         * If they are, construct a new mem space that is equivalent to the
         * old mem space, and use that instead.
         *
         * Note that in general, this requires us to touch up the memory buffer
         * as well.
         */
        if (dset_info[i].nelmts > 0 &&
            TRUE == H5S_SELECT_SHAPE_SAME(dset_info[i].mem_space, dset_info[i].file_space) &&
            H5S_GET_EXTENT_NDIMS(dset_info[i].mem_space) != H5S_GET_EXTENT_NDIMS(dset_info[i].file_space)) {
            ptrdiff_t buf_adj = 0;

            /* Allocate original memory space buffer if necessary */
            if (!orig_mem_space) {
                if (count > 1) {
                    /* Allocate buffer */
                    if (NULL == (orig_mem_space = (H5S_t **)H5MM_calloc(count * sizeof(H5S_t *))))
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL,
                                    "couldn't allocate original memory space array buffer")
                }
                else
                    /* Use local buffer */
                    orig_mem_space = &orig_mem_space_local;
            }

            /* Save original memory space */
            orig_mem_space[i]      = dset_info[i].mem_space;
            dset_info[i].mem_space = NULL;

            /* Attempt to construct projected dataspace for memory dataspace */
            if (H5S_select_construct_projection(orig_mem_space[i], &dset_info[i].mem_space,
                                                (unsigned)H5S_GET_EXTENT_NDIMS(dset_info[i].file_space),
                                                dset_info[i].type_info.src_type_size, &buf_adj) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to construct projected memory dataspace")
            HDassert(dset_info[i].mem_space);

            /* Adjust the buffer by the given amount */
            dset_info[i].buf.cvp = (const void *)(((const uint8_t *)dset_info[i].buf.cvp) + buf_adj);
        } /* end if */

        /* Retrieve dataset properties */
        /* <none needed currently> */

        /* Set up I/O operation */
        if (H5D__dset_ioinfo_init(dset_info[i].dset, &(dset_info[i]), &(store[i])) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up I/O operation")

        /* Allocate dataspace and initialize it if it hasn't been. */
        should_alloc_space = dset_info[i].dset->shared->dcpl_cache.efl.nused == 0 &&
                             !(*dset_info[i].dset->shared->layout.ops->is_space_alloc)(
                                 &dset_info[i].dset->shared->layout.storage);

        /*
         * If not using an MPI-based VFD, we only need to allocate
         * and initialize storage if there's a selection in the
         * dataset's dataspace. Otherwise, we always need to participate
         * in the storage allocation since this may use collective
         * operations and we will hang if we don't participate.
         */
        if (!H5F_HAS_FEATURE(dset_info[i].dset->oloc.file, H5FD_FEAT_HAS_MPI))
            should_alloc_space = should_alloc_space && (dset_info[i].nelmts > 0);

        if (should_alloc_space) {
            hssize_t file_nelmts;    /* Number of elements in file dataset's dataspace */
            hbool_t  full_overwrite; /* Whether we are over-writing all the elements */

            /* Get the number of elements in file dataset's dataspace */
            if ((file_nelmts = H5S_GET_EXTENT_NPOINTS(dset_info[i].file_space)) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL,
                            "can't retrieve number of elements in file dataset")

            /* Always allow fill values to be written if the dataset has a VL datatype */
            if (H5T_detect_class(dset_info[i].dset->shared->type, H5T_VLEN, FALSE))
                full_overwrite = FALSE;
            else
                full_overwrite = (hbool_t)((hsize_t)file_nelmts == dset_info[i].nelmts ? TRUE : FALSE);

            /* Allocate storage */
            if (H5D__alloc_storage(dset_info[i].dset, H5D_ALLOC_WRITE, full_overwrite, NULL) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize storage")
        } /* end if */

        /* Call storage method's I/O initialization routine */
        /* Init io_info.dset_info[] and generate piece_info in skip list */
        if (dset_info[i].layout_ops.io_init &&
            (*dset_info[i].layout_ops.io_init)(&io_info, &(dset_info[i])) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info")
        dset_info[i].skip_io = FALSE;
        io_op_init++;

        /* Reset metadata tagging */
        H5AC_tag(prev_tag, NULL);
    } /* end of for loop */

    HDassert(type_info_init == count);
    HDassert(io_op_init == count);

    /* Perform second phase of type info initialization */
    if (H5D__typeinfo_init_phase2(&io_info) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info (second phase)")

#ifdef H5_HAVE_PARALLEL
    /* Adjust I/O info for any parallel I/O */
    if (H5D__ioinfo_adjust(&io_info) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to adjust I/O info for parallel I/O")
#endif /*H5_HAVE_PARALLEL*/

    /* If multi dataset I/O callback is not provided, perform write IO via
     * single-dset path with looping */
    if (io_info.md_io_ops.multi_write_md) {
        /* Create sel_pieces array if any pieces are selected */
        if (io_info.piece_count > 0) {
            HDassert(!io_info.sel_pieces);
            HDassert(io_info.pieces_added == 0);

            /* Allocate sel_pieces array */
            if (NULL ==
                (io_info.sel_pieces = H5MM_malloc(io_info.piece_count * sizeof(io_info.sel_pieces[0]))))
                HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "unable to allocate array of selected pieces")
        }

        /* MDIO-specific second phase initialization */
        for (i = 0; i < count; i++)
            if (dset_info[i].layout_ops.mdio_init) {
                haddr_t prev_tag = HADDR_UNDEF;

                /* set metadata tagging with dset oheader addr */
                H5AC_tag(dset_info[i].dset->oloc.addr, &prev_tag);

                /* Make second phase IO init call */
                if ((dset_info[i].layout_ops.mdio_init)(&io_info, &(dset_info[i])) < 0)
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't populate array of selected pieces")

                /* Reset metadata tagging */
                H5AC_tag(prev_tag, NULL);
            }

        /* Invoke correct "high level" I/O routine */
        if ((*io_info.md_io_ops.multi_write_md)(&io_info) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data")
    } /* end if */
    else {
        haddr_t prev_tag = HADDR_UNDEF;

        if (!H5D_LAYOUT_CB_PERFORM_IO(&io_info) && io_info.piece_count > 0) {
            if (NULL == (io_info.mem_spaces = H5MM_malloc(io_info.piece_count * sizeof(H5S_t *))))
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                            "memory allocation failed for memory space list")
            if (NULL == (io_info.file_spaces = H5MM_malloc(io_info.piece_count * sizeof(H5S_t *))))
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for file space list")
            if (NULL == (io_info.addrs = H5MM_malloc(io_info.piece_count * sizeof(haddr_t))))
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                            "memory allocation failed for piece address list")
            if (NULL == (io_info.element_sizes = H5MM_malloc(io_info.piece_count * sizeof(size_t))))
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                            "memory allocation failed for element size list")
            if (NULL == (io_info.wbufs = H5MM_malloc(io_info.piece_count * sizeof(const void *))))
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
                            "memory allocation failed for read buffer list")
        }

        /* loop with serial & single-dset write IO path */
        for (i = 0; i < count; i++) {
            HDassert(!dset_info[i].skip_io);

            /* set metadata tagging with dset oheader addr */
            H5AC_tag(dset_info->dset->oloc.addr, &prev_tag);

            /* Invoke correct "high level" I/O routine */
            if ((*dset_info[i].io_ops.multi_write)(&io_info, &dset_info[i]) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data")

            /* Reset metadata tagging */
            H5AC_tag(prev_tag, NULL);
        }

        /* Make final multi dataset selection I/O call if we are using both
         * features - in this case the multi_write callbacks did not perform the
         * actual I/O */
        H5_CHECK_OVERFLOW(io_info.pieces_added, size_t, uint32_t)
        if (!H5D_LAYOUT_CB_PERFORM_IO(&io_info))
            if (H5F_shared_select_write(io_info.f_sh, H5FD_MEM_DRAW, (uint32_t)io_info.pieces_added,
                                        io_info.mem_spaces, io_info.file_spaces, io_info.addrs,
                                        io_info.element_sizes, io_info.wbufs) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "selection write failed")
    }

#ifdef OLD_WAY
    /*
     * This was taken out because it can be called in a parallel program with
     * independent access, causing the metadata cache to get corrupted. Its been
     * disabled for all types of access (serial as well as parallel) to make the
     * modification time consistent for all programs. -QAK
     *
     * We should set a value in the dataset's shared information instead and flush
     * it to the file when the dataset is being closed. -QAK
     */
    /*
     * Update modification time.  We have to do this explicitly because
     * writing to a dataset doesn't necessarily change the object header.
     */
    if (H5O_touch(&(dataset->oloc), FALSE) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to update modification time")
#endif /* OLD_WAY */

done:
    /* Shut down the I/O op information */
    for (i = 0; i < io_op_init; i++) {
        HDassert(!dset_info[i].skip_io);
        if (dset_info[i].layout_ops.io_term &&
            (*dset_info[i].layout_ops.io_term)(&io_info, &(dset_info[i])) < 0)
            HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down I/O op info")
    }

    /* Shut down datatype info for operation */
    if (H5D__typeinfo_term(&io_info, type_info_init) < 0)
        HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down type info")

    /* Discard projected mem spaces and restore originals */
    if (orig_mem_space) {
        for (i = 0; i < count; i++)
            if (orig_mem_space[i]) {
                if (H5S_close(dset_info[i].mem_space) < 0)
                    HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL,
                                "unable to shut down projected memory dataspace")
                dset_info[i].mem_space = orig_mem_space[i];
            }

        /* Free orig_mem_space array if it was allocated */
        if (orig_mem_space != &orig_mem_space_local)
            H5MM_free(orig_mem_space);
    }

    /* Free global piece array */
    H5MM_xfree(io_info.sel_pieces);

    /* Free store array if it was allocated */
    if (store != &store_local)
        H5MM_free(store);

    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5D__write */

/*-------------------------------------------------------------------------
 * Function:	H5D__ioinfo_init
 *
 * Purpose:	General setup for H5D_io_info_t struct
 *
 * Return:	Non-negative on success/Negative on failure
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__ioinfo_init(size_t count, H5D_dset_io_info_t *dset_info, H5D_io_info_t *io_info)
{
    FUNC_ENTER_PACKAGE_NOERR

    /* check args */
    HDassert(count > 0);
    HDassert(dset_info);
    HDassert(dset_info[0].dset->oloc.file);
    HDassert(io_info);

    /* Zero out struct */
    HDmemset(io_info, 0, sizeof(*io_info));

    /* Set up simple fields */
    io_info->f_sh  = count > 0 ? H5F_SHARED(dset_info[0].dset->oloc.file) : NULL;
    io_info->count = count;

    /* Start without multi-dataset I/O ops. If we're not using the collective
     * I/O path then we will call the single dataset callbacks in a loop. */

    /* Use provided dset_info */
    io_info->dsets_info = dset_info;

    /* Start with selection I/O on if the global is on, layout callback will
     * turn it off if appropriate */
    io_info->use_select_io = H5_use_selection_io_g;

#ifdef H5_HAVE_PARALLEL
    /* Determine if the file was opened with an MPI VFD */
    if (count > 0)
        io_info->using_mpi_vfd = H5F_HAS_FEATURE(dset_info[0].dset->oloc.file, H5FD_FEAT_HAS_MPI);
#endif /* H5_HAVE_PARALLEL */

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5D__ioinfo_init() */

/*-------------------------------------------------------------------------
 * Function:	H5D__dset_ioinfo_init
 *
 * Purpose:	Routine for determining correct I/O operations for each I/O action.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__dset_ioinfo_init(H5D_t *dset, H5D_dset_io_info_t *dset_info, H5D_storage_t *store)
{
    FUNC_ENTER_PACKAGE_NOERR

    /* check args */
    HDassert(dset);
    HDassert(dset->oloc.file);
    HDassert(dset_info->type_info.tpath);

    /* Set up "normal" I/O fields */
    dset_info->dset  = dset;
    dset_info->store = store;

    /* Set I/O operations to initial values */
    dset_info->layout_ops = *dset->shared->layout.ops;

    /* Set the "high-level" I/O operations for the dataset */
    dset_info->io_ops.multi_read  = dset->shared->layout.ops->ser_read;
    dset_info->io_ops.multi_write = dset->shared->layout.ops->ser_write;

    /* Set the I/O operations for reading/writing single blocks on disk */
    if (dset_info->type_info.is_xform_noop && dset_info->type_info.is_conv_noop) {
        /*
         * If there is no data transform or type conversion then read directly
         * into the application's buffer.
         * This saves at least one mem-to-mem copy.
         */
        dset_info->io_ops.single_read  = H5D__select_read;
        dset_info->io_ops.single_write = H5D__select_write;
    } /* end if */
    else {
        /*
         * This is the general case (type conversion, usually).
         */
        dset_info->io_ops.single_read  = H5D__scatgath_read;
        dset_info->io_ops.single_write = H5D__scatgath_write;
    } /* end else */

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5D__dset_ioinfo_init() */

/*-------------------------------------------------------------------------
 * Function:	H5D__typeinfo_init
 *
 * Purpose:	Routine for determining correct datatype information for
 *              each I/O action.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Quincey Koziol
 *		Tuesday, March  4, 2008
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__typeinfo_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, hid_t mem_type_id)
{
    H5D_type_info_t  *type_info;
    const H5D_t      *dset;
    const H5T_t      *src_type;            /* Source datatype */
    const H5T_t      *dst_type;            /* Destination datatype */
    H5Z_data_xform_t *data_transform;      /* Data transform info */
    herr_t            ret_value = SUCCEED; /* Return value	*/

    FUNC_ENTER_PACKAGE

    /* check args */
    HDassert(io_info);
    HDassert(dset_info);

    /* Set convenience pointers */
    type_info = &dset_info->type_info;
    dset      = dset_info->dset;
    HDassert(dset);

    /* Patch the top level file pointer for dt->shared->u.vlen.f if needed */
    if (H5T_patch_vlen_file(dset->shared->type, H5F_VOL_OBJ(dset->oloc.file)) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch VL datatype file pointer")

    /* Initialize type info safely */
    HDmemset(type_info, 0, sizeof(*type_info));

    /* Get the memory & dataset datatypes */
    if (NULL == (type_info->mem_type = (const H5T_t *)H5I_object_verify(mem_type_id, H5I_DATATYPE)))
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
    type_info->dset_type = dset->shared->type;

    if (io_info->op_type == H5D_IO_OP_WRITE) {
        src_type               = type_info->mem_type;
        dst_type               = dset->shared->type;
        type_info->src_type_id = mem_type_id;
        type_info->dst_type_id = dset->shared->type_id;
    } /* end if */
    else {
        src_type               = dset->shared->type;
        dst_type               = type_info->mem_type;
        type_info->src_type_id = dset->shared->type_id;
        type_info->dst_type_id = mem_type_id;
    } /* end else */

    /* Locate the type conversion function and dataspace conversion
     * functions, and set up the element numbering information. If a data
     * type conversion is necessary then register datatype IDs. Data type
     * conversion is necessary if the user has set the `need_bkg' to a high
     * enough value in xfer_parms since turning off datatype conversion also
     * turns off background preservation.
     */
    if (NULL == (type_info->tpath = H5T_path_find(src_type, dst_type)))
        HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to convert between src and dest datatype")

    /* Retrieve info from API context */
    if (H5CX_get_data_transform(&data_transform) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get data transform info")

    /* Precompute some useful information */
    type_info->src_type_size = H5T_get_size(src_type);
    type_info->dst_type_size = H5T_get_size(dst_type);
    type_info->is_conv_noop  = H5T_path_noop(type_info->tpath);
    type_info->is_xform_noop = H5Z_xform_noop(data_transform);
    if (type_info->is_xform_noop && type_info->is_conv_noop) {
        type_info->cmpd_subset = NULL;
        type_info->need_bkg    = H5T_BKG_NO;
    } /* end if */
    else {
        H5T_bkg_t bkgr_buf_type; /* Background buffer type */

        /* Get info from API context */
        if (H5CX_get_bkgr_buf_type(&bkgr_buf_type) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve background buffer type")

        /* Check if the datatypes are compound subsets of one another */
        type_info->cmpd_subset = H5T_path_compound_subset(type_info->tpath);

        /* Update io_info->max_type_size */
        io_info->max_type_size =
            MAX3(io_info->max_type_size, type_info->src_type_size, type_info->dst_type_size);

        /* Check if we need a background buffer */
        if ((io_info->op_type == H5D_IO_OP_WRITE) && H5T_detect_class(dset->shared->type, H5T_VLEN, FALSE))
            type_info->need_bkg = H5T_BKG_YES;
        else {
            H5T_bkg_t path_bkg; /* Type conversion's background info */

            if ((path_bkg = H5T_path_bkg(type_info->tpath))) {
                /* Retrieve the bkgr buffer property */
                type_info->need_bkg = bkgr_buf_type;
                type_info->need_bkg = MAX(path_bkg, type_info->need_bkg);
            } /* end if */
            else
                type_info->need_bkg = H5T_BKG_NO; /*never needed even if app says yes*/
        }                                         /* end else */
    }                                             /* end else */

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5D__typeinfo_init() */

/*-------------------------------------------------------------------------
 * Function:    H5D__typeinfo_init_phase2
 *
 * Purpose:     Finish initializing type info for all datasets after
 *              calculating the max type size across all datasets.
 *
 * Return:      Non-negative on success/Negative on failure
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__typeinfo_init_phase2(H5D_io_info_t *io_info)
{
    herr_t ret_value = SUCCEED; /* Return value */

    FUNC_ENTER_PACKAGE

    /* check args */
    HDassert(io_info);

    /* Check if we need to allocate a shared type conversion buffer */
    if (io_info->max_type_size) {
        void  *tconv_buf;    /* Temporary conversion buffer pointer */
        void  *bkgr_buf;     /* Background conversion buffer pointer */
        size_t max_temp_buf; /* Maximum temporary buffer size */
        size_t target_size;  /* Desired buffer size	*/
        size_t i;            /* Local index variable */

        /* Get info from API context */
        if (H5CX_get_max_temp_buf(&max_temp_buf) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve max. temp. buf size")
        if (H5CX_get_tconv_buf(&tconv_buf) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve temp. conversion buffer pointer")
        if (H5CX_get_bkgr_buf(&bkgr_buf) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve background conversion buffer pointer")

        /* Set up datatype conversion/background buffers */
        target_size = max_temp_buf;

        /* If the buffer is too small to hold even one element (in the dataset with the largest , try to make
         * it bigger */
        if (target_size < io_info->max_type_size) {
            hbool_t default_buffer_info; /* Whether the buffer information are the defaults */

            /* Detect if we have all default settings for buffers */
            default_buffer_info =
                (hbool_t)((H5D_TEMP_BUF_SIZE == max_temp_buf) && (NULL == tconv_buf) && (NULL == bkgr_buf));

            /* Check if we are using the default buffer info */
            if (default_buffer_info)
                /* OK to get bigger for library default settings */
                target_size = io_info->max_type_size;
            else
                /* Don't get bigger than the application has requested */
                HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "temporary buffer max size is too small")
        } /* end if */

        /* Get a temporary buffer for type conversion unless the app has already
         * supplied one through the xfer properties. Instead of allocating a
         * buffer which is the exact size, we allocate the target size. This
         * buffer is shared among all datasets in the operation, unlike for the
         * background buffer, where each dataset gets its own. */
        if (NULL == (io_info->tconv_buf = (uint8_t *)tconv_buf)) {
            /* Allocate temporary buffer */
            if (NULL == (io_info->tconv_buf = H5FL_BLK_MALLOC(type_conv, target_size)))
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion")
            io_info->tconv_buf_allocated = TRUE;
        } /* end if */

        /* Don't use API provided background buffer if there's more than one dataset, since each
         * dataset needs its own */
        if (io_info->count > 1)
            bkgr_buf = NULL;

        /* Iterate over datasets */
        for (i = 0; i < io_info->count; i++) {
            H5D_type_info_t *type_info = &io_info->dsets_info[i].type_info;

            /* Compute the number of elements that will fit into buffer */
            type_info->request_nelmts = target_size / MAX(type_info->src_type_size, type_info->dst_type_size);
            ;

            /* Sanity check elements in temporary buffer */
            if (type_info->request_nelmts == 0)
                HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "temporary buffer max size is too small")

            /* Allocate background buffer if necessary */
            if (type_info->need_bkg && NULL == (type_info->bkg_buf = (uint8_t *)bkgr_buf)) {
                size_t bkg_size; /* Desired background buffer size	*/

                /* Compute the background buffer size */
                /* (don't try to use buffers smaller than the default size) */
                bkg_size = type_info->request_nelmts * type_info->dst_type_size;
                if (bkg_size < max_temp_buf)
                    bkg_size = max_temp_buf;

                /* Allocate background buffer */
                /* (Need calloc()-like call since memory needs to be initialized) */
                if (NULL == (type_info->bkg_buf = H5FL_BLK_CALLOC(type_conv, bkg_size)))
                    HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
                                "memory allocation failed for background conversion")
                type_info->bkg_buf_allocated = TRUE;
            } /* end if */
        }
    }

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5D__typeinfo_init_phase2() */

#ifdef H5_HAVE_PARALLEL

/*-------------------------------------------------------------------------
 * Function:	H5D__ioinfo_adjust
 *
 * Purpose:	Adjust operation's I/O info for any parallel I/O
 *
 *          This was derived from H5D__ioinfo_adjust for multi-dset work.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__ioinfo_adjust(H5D_io_info_t *io_info)
{
    H5D_t *dset0;               /* only the first dset , also for single dsets case */
    herr_t ret_value = SUCCEED; /* Return value	*/

    FUNC_ENTER_PACKAGE

    /* check args */
    HDassert(io_info);

    /* check the first dset, should exist either single or multi dset cases */
    HDassert(io_info->dsets_info[0].dset);
    dset0 = io_info->dsets_info[0].dset;
    HDassert(dset0->oloc.file);

    /* Reset the actual io mode properties to the default values in case
     * the DXPL (if it's non-default) was previously used in a collective
     * I/O operation.
     */
    if (!H5CX_is_def_dxpl()) {
        H5CX_set_mpio_actual_chunk_opt(H5D_MPIO_NO_CHUNK_OPTIMIZATION);
        H5CX_set_mpio_actual_io_mode(H5D_MPIO_NO_COLLECTIVE);
    } /* end if */

    /* Make any parallel I/O adjustments */
    if (io_info->using_mpi_vfd) {
        H5FD_mpio_xfer_t xfer_mode; /* Parallel transfer for this request */
        htri_t           opt;       /* Flag whether a selection is optimizable */

        /* Get the original state of parallel I/O transfer mode */
        if (H5CX_get_io_xfer_mode(&xfer_mode) < 0)
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get MPI-I/O transfer mode")

        /* Get MPI communicator */
        if (MPI_COMM_NULL == (io_info->comm = H5F_mpi_get_comm(dset0->oloc.file)))
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't retrieve MPI communicator")

        /* Check if we can set direct MPI-IO read/write functions */
        if ((opt = H5D__mpio_opt_possible(io_info)) < 0)
            HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "invalid check for direct IO dataspace ")

        /* Check if we can use the optimized parallel I/O routines */
        if (opt == TRUE) {
            /* Override the I/O op pointers to the MPI-specific routines, unless
             * selection I/O is to be used - in this case the file driver will
             * handle collective I/O */
            /* Check for selection/vector support in file driver? -NAF */
            if (!io_info->use_select_io) {
                io_info->md_io_ops.multi_read_md   = H5D__collective_read;
                io_info->md_io_ops.multi_write_md  = H5D__collective_write;
                io_info->md_io_ops.single_read_md  = H5D__mpio_select_read;
                io_info->md_io_ops.single_write_md = H5D__mpio_select_write;
            } /* end if */
        }     /* end if */
        else {
            /* Fail when file sync is required, since it requires collective write */
            if (io_info->op_type == H5D_IO_OP_WRITE) {
                hbool_t mpi_file_sync_required = FALSE;
                if (H5F_shared_get_mpi_file_sync_required(io_info->f_sh, &mpi_file_sync_required) < 0)
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get MPI file_sync_required flag")

                if (mpi_file_sync_required)
                    HGOTO_ERROR(
                        H5E_DATASET, H5E_NO_INDEPENDENT, FAIL,
                        "Can't perform independent write when MPI_File_sync is required by ROMIO driver.")
            }

            /* Check if there are any filters in the pipeline. If there are,
             * we cannot break to independent I/O if this is a write operation
             * with multiple ranks involved; otherwise, there will be metadata
             * inconsistencies in the file.
             */
            if (io_info->op_type == H5D_IO_OP_WRITE) {
                size_t i;

                /* Check all datasets for filters */
                for (i = 0; i < io_info->count; i++)
                    if (io_info->dsets_info[i].dset->shared->dcpl_cache.pline.nused > 0)
                        break;

                /* If the above loop didn't complete at least one dataset has a filter */
                if (i < io_info->count) {
                    int comm_size = 0;

                    /* Retrieve size of MPI communicator used for file */
                    if ((comm_size = H5F_shared_mpi_get_size(io_info->f_sh)) < 0)
                        HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get MPI communicator size")

                    if (comm_size > 1) {
                        char local_no_coll_cause_string[512];
                        char global_no_coll_cause_string[512];

                        if (H5D__mpio_get_no_coll_cause_strings(local_no_coll_cause_string, 512,
                                                                global_no_coll_cause_string, 512) < 0)
                            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL,
                                        "can't get reasons for breaking collective I/O")

                        HGOTO_ERROR(H5E_IO, H5E_NO_INDEPENDENT, FAIL,
                                    "Can't perform independent write with filters in pipeline.\n"
                                    "    The following caused a break from collective I/O:\n"
                                    "        Local causes: %s\n"
                                    "        Global causes: %s",
                                    local_no_coll_cause_string, global_no_coll_cause_string);
                    }
                }
            }

            /* If we won't be doing collective I/O, but the user asked for
             * collective I/O, change the request to use independent I/O
             */
            if (xfer_mode == H5FD_MPIO_COLLECTIVE) {
                /* Change the xfer_mode to independent for handling the I/O */
                if (H5CX_set_io_xfer_mode(H5FD_MPIO_INDEPENDENT) < 0)
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set MPI-I/O transfer mode")
            } /* end if */
        }     /* end else */
    }         /* end if */

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5D__ioinfo_adjust() */
#endif /* H5_HAVE_PARALLEL */

/*-------------------------------------------------------------------------
 * Function:    H5D__typeinfo_term
 *
 * Purpose:     Common logic for terminating a type info object
 *
 * Return:      Non-negative on success/Negative on failure
 *
 * Programmer:  Quincey Koziol
 *              Thursday, March  6, 2008
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__typeinfo_term(H5D_io_info_t *io_info, size_t type_info_init)
{
    size_t i;

    FUNC_ENTER_PACKAGE_NOERR

    /* Check for releasing datatype conversion & background buffers */
    if (io_info->tconv_buf_allocated) {
        HDassert(io_info->tconv_buf);
        (void)H5FL_BLK_FREE(type_conv, io_info->tconv_buf);
    } /* end if */
    for (i = 0; i < type_info_init; i++)
        if (io_info->dsets_info[i].type_info.bkg_buf_allocated) {
            HDassert(io_info->dsets_info[i].type_info.bkg_buf);
            (void)H5FL_BLK_FREE(type_conv, io_info->dsets_info[i].type_info.bkg_buf);
        } /* end if */

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5D__typeinfo_term() */