diff --git a/externals/coda-oss/modules/c++/config/include/config/coda_oss_config.h.in b/externals/coda-oss/modules/c++/config/include/config/coda_oss_config.h.in
index 14fca616b..24d164881 100644
--- a/externals/coda-oss/modules/c++/config/include/config/coda_oss_config.h.in
+++ b/externals/coda-oss/modules/c++/config/include/config/coda_oss_config.h.in
@@ -3,6 +3,7 @@
#ifndef _CODA_OSS_CONFIG_H_
#define _CODA_OSS_CONFIG_H_
+/* these should no longer be needed */
#cmakedefine HAVE_PTHREAD_H @HAVE_PTHREAD_H@
#cmakedefine HAVE_EXECINFO_H @HAVE_EXECINFO_H@
#cmakedefine HAVE_CLOCK_GETTIME @HAVE_CLOCK_GETTIME@
@@ -11,12 +12,14 @@
#cmakedefine HAVE_LOCALTIME_R @HAVE_LOCALTIME_R@
#cmakedefine HAVE_GMTIME_R @HAVE_GMTIME_R@
#cmakedefine HAVE_SETENV @HAVE_SETENV@
-#cmakedefine HAVE_POSIX_MEMALIGN @HAVE_POSIX_MEMALIGN@
-#cmakedefine HAVE_MEMALIGN @HAVE_MEMALIGN@
#cmakedefine01 BIGENDIAN
#cmakedefine SIZEOF_SIZE_T @SIZEOF_SIZE_T@
-#cmakedefine HAVE_ATTRIBUTE_NOINLINE @HAVE_ATTRIBUTE_NOINLINE@
+#cmakedefine HAVE_POSIX_MEMALIGN @HAVE_POSIX_MEMALIGN@
+#cmakedefine HAVE_MEMALIGN @HAVE_MEMALIGN@
#cmakedefine HAVE_ATTRIBUTE_ALIGNED @HAVE_ATTRIBUTE_ALIGNED@
+#cmakedefine HAVE_ATTRIBUTE_NOINLINE @HAVE_ATTRIBUTE_NOINLINE@
+
+/* still might need these ... for now */
#cmakedefine CODA_EXPORT @CODA_EXPORT@
#endif /* _CODA_OSS_CONFIG_H_ */
diff --git a/externals/coda-oss/modules/c++/config/include/config/compiler_extensions.h b/externals/coda-oss/modules/c++/config/include/config/compiler_extensions.h
index d6f295b0b..93c445d82 100644
--- a/externals/coda-oss/modules/c++/config/include/config/compiler_extensions.h
+++ b/externals/coda-oss/modules/c++/config/include/config/compiler_extensions.h
@@ -19,21 +19,34 @@
* see .
*
*/
-#ifndef CONFIG_COMPILER_EXTENSIONS
-#define CONFIG_COMPILER_EXTENSIONS
+#ifndef CODA_OSS_config_compiler_extentions_h_INCLUDED_
+#define CODA_OSS_config_compiler_extentions_h_INCLUDED_
+#pragma once
#include
-#ifdef HAVE_ATTRIBUTE_NOINLINE
-#define ATTRIBUTE_NOINLINE __attribute__((noinline))
-#else
-#define ATTRIBUTE_NOINLINE
-#endif
+#ifndef CODA_OSS_attribute_noinline_DEFINED_
+ #define CODA_OSS_attribute_noinline_DEFINED_ 1
-#ifdef HAVE_ATTRIBUTE_ALIGNED
-#define ATTRIBUTE_ALIGNED(x) __attribute__((aligned (x)))
-#else
-#define ATTRIBUTE_ALIGNED(X)
-#endif
+ // https://stackoverflow.com/a/49468469/8877
+ #if defined(__GNUC__)
+ #define ATTRIBUTE_NOINLINE __attribute__((noinline))
+ #elif defined(_MSC_VER)
+ #define ATTRIBUTE_NOINLINE __declspec(noinline)
+ #else
+ #define ATTRIBUTE_NOINLINE
+ #endif
+#endif // CODA_OSS_attribute_noinline_DEFINED_
-#endif
+#ifndef CODA_OSS_attribute_aligned_DEFINED_
+ #define CODA_OSS_attribute_aligned_DEFINED_ 1
+
+ #if defined(__GNUC__)
+ // https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Variable-Attributes.html
+ #define ATTRIBUTE_ALIGNED(x) __attribute__((aligned(x)))
+ #else
+ #define ATTRIBUTE_ALIGNED(X)
+ #endif
+#endif // CODA_OSS_attribute_aligned_DEFINED_
+
+#endif // CODA_OSS_config_compiler_extentions_h_INCLUDED_
diff --git a/externals/coda-oss/modules/c++/io/include/io/PipeStream.h b/externals/coda-oss/modules/c++/io/include/io/PipeStream.h
index 5795a79b0..1f2299b27 100644
--- a/externals/coda-oss/modules/c++/io/include/io/PipeStream.h
+++ b/externals/coda-oss/modules/c++/io/include/io/PipeStream.h
@@ -39,11 +39,8 @@ namespace io
* \brief captures the standard output from a pipe
* and streams it to the specified location
*/
-class PipeStream : InputStream
+struct PipeStream : InputStream
{
-
-public:
-
/*!
* Constructor --
* Streams data from a pipe when available
@@ -95,6 +92,9 @@ class PipeStream : InputStream
virtual sys::SSize_T streamTo(OutputStream& soi,
sys::SSize_T numBytes = IS_END);
+ PipeStream(const PipeStream&) = delete;
+ PipeStream& operator=(const PipeStream&) = delete;
+
protected:
/*!
* \brief returns the requested size in bytes from the stream
@@ -104,13 +104,7 @@ class PipeStream : InputStream
sys::ExecPipe mExecPipe;
mem::ScopedArray mCharString;
- size_t mBufferSize;
-
-private:
-
- //! Noncopyable
- PipeStream(const PipeStream& );
- const PipeStream& operator=(const PipeStream& );
+ size_t mBufferSize = DEFAULT_CHUNK_SIZE;
};
}
diff --git a/externals/coda-oss/modules/c++/io/include/io/TempFile.h b/externals/coda-oss/modules/c++/io/include/io/TempFile.h
index 7f1d9dde0..b08c0a1ac 100644
--- a/externals/coda-oss/modules/c++/io/include/io/TempFile.h
+++ b/externals/coda-oss/modules/c++/io/include/io/TempFile.h
@@ -32,9 +32,8 @@ namespace io
* RAII object for a temporary file that gets deleted
* upon object destruction
*/
-class TempFile
+struct TempFile
{
-public:
/*!
* Constructor for TempFile object. Provided a directory,
* this will find a random, unused filename, and create a file
@@ -53,10 +52,11 @@ class TempFile
{
return mPathname;
}
+
+ TempFile(const TempFile&) = delete;
+ TempFile& operator=(const TempFile&) = delete;
+
private:
- // Noncopyable
- TempFile(const TempFile& );
- const TempFile& operator=(const TempFile& );
const sys::OS mOS;
const std::string mPathname;
};
diff --git a/externals/coda-oss/modules/c++/logging/include/logging/Logger.h b/externals/coda-oss/modules/c++/logging/include/logging/Logger.h
index f1e2ca9ed..c946af30e 100644
--- a/externals/coda-oss/modules/c++/logging/include/logging/Logger.h
+++ b/externals/coda-oss/modules/c++/logging/include/logging/Logger.h
@@ -43,10 +43,8 @@ namespace logging
* Instances of the Logger class represent a single logging channel.
* A Logger instance can log to several Handlers.
*/
-class Logger : public Filterer
+struct Logger : public Filterer
{
-
-public:
/*!
* Constructs a Logger with an optional name
* \param name (optional) Name of the logger
@@ -130,15 +128,13 @@ class Logger : public Filterer
//! Removes all handlers
void reset();
-private:
- // Noncopyable
// NOTE: It isn't currently safe to copy a logger because mHandlers isn't
// a deep copy and you end up with a double delete (it's not using
// smart pointers :o( ). If we really wanted to support a copy,
// would need to decide if mHandlers should be deeply or shallowly
// copied.
- Logger(const Logger& );
- Logger& operator=(const Logger& );
+ Logger(const Logger&) = delete;
+ Logger& operator=(const Logger&) = delete;
protected:
void handle(const LogRecord* record);
diff --git a/externals/coda-oss/modules/c++/mem/include/mem/ScopedAlignedArray.h b/externals/coda-oss/modules/c++/mem/include/mem/ScopedAlignedArray.h
index c0e55e5ad..429cc50c8 100644
--- a/externals/coda-oss/modules/c++/mem/include/mem/ScopedAlignedArray.h
+++ b/externals/coda-oss/modules/c++/mem/include/mem/ScopedAlignedArray.h
@@ -34,9 +34,8 @@ namespace mem
* \brief This class provides RAII for alignedAlloc() and alignedFree()
*/
template
- class ScopedAlignedArray
+ struct ScopedAlignedArray
{
- public:
typedef T ElementType;
explicit ScopedAlignedArray(
@@ -91,11 +90,10 @@ namespace mem
return array;
}
- private:
- // Noncopyable
- ScopedAlignedArray(const ScopedAlignedArray& );
- const ScopedAlignedArray& operator=(const ScopedAlignedArray& );
+ ScopedAlignedArray(const ScopedAlignedArray&) = delete;
+ ScopedAlignedArray& operator=(const ScopedAlignedArray&) = delete;
+ private:
static
T* allocate(size_t numElements, size_t alignment)
{
diff --git a/externals/coda-oss/modules/c++/mem/include/mem/ScopedArray.h b/externals/coda-oss/modules/c++/mem/include/mem/ScopedArray.h
index 4fa6b8c05..55d710add 100644
--- a/externals/coda-oss/modules/c++/mem/include/mem/ScopedArray.h
+++ b/externals/coda-oss/modules/c++/mem/include/mem/ScopedArray.h
@@ -33,9 +33,8 @@ namespace mem
* It is based on boost::scoped_array.
*/
template
- class ScopedArray
- {
- public:
+ struct ScopedArray
+ {
typedef T ElementType;
explicit ScopedArray(T* array = NULL) :
@@ -71,10 +70,8 @@ namespace mem
return array;
}
- private:
- // Noncopyable
- ScopedArray(const ScopedArray& );
- const ScopedArray& operator=(const ScopedArray& );
+ ScopedArray(const ScopedArray&) = delete;
+ ScopedArray& operator=(const ScopedArray&) = delete;
private:
T* mArray;
diff --git a/externals/coda-oss/modules/c++/mem/include/mem/ScratchMemory.h b/externals/coda-oss/modules/c++/mem/include/mem/ScratchMemory.h
index 77c66a40f..2eb5c9113 100644
--- a/externals/coda-oss/modules/c++/mem/include/mem/ScratchMemory.h
+++ b/externals/coda-oss/modules/c++/mem/include/mem/ScratchMemory.h
@@ -157,10 +157,10 @@ class ScratchMemory
return mNumBytesNeeded;
}
-private:
- ScratchMemory(const ScratchMemory&);
- ScratchMemory& operator=(const ScratchMemory&);
+ ScratchMemory(const ScratchMemory&) = delete;
+ ScratchMemory& operator=(const ScratchMemory&) = delete;
+private:
struct Segment
{
Segment(size_t numBytes, size_t numBuffers, size_t alignment, size_t offset);
diff --git a/externals/coda-oss/modules/c++/mem/include/mem/VectorOfPointers.h b/externals/coda-oss/modules/c++/mem/include/mem/VectorOfPointers.h
index e26a58c37..acded251c 100644
--- a/externals/coda-oss/modules/c++/mem/include/mem/VectorOfPointers.h
+++ b/externals/coda-oss/modules/c++/mem/include/mem/VectorOfPointers.h
@@ -37,9 +37,8 @@ namespace mem
* \brief This class provides safe cleanup for vectors of pointers
*/
template
-class VectorOfPointers
+struct VectorOfPointers
{
-public:
VectorOfPointers()
{
}
@@ -149,19 +148,16 @@ class VectorOfPointers
return mValues.erase(first, last);
}
-private:
- // Noncopyable
- VectorOfPointers(const VectorOfPointers& );
- const VectorOfPointers& operator=(const VectorOfPointers& );
+ VectorOfPointers(const VectorOfPointers&) = delete;
+ VectorOfPointers& operator=(const VectorOfPointers&) = delete;
private:
std::vector mValues;
};
template
- class VectorOfSharedPointers
+ struct VectorOfSharedPointers
{
-public:
VectorOfSharedPointers()
{
}
diff --git a/externals/coda-oss/modules/c++/mem/unittests/test_scoped_copyable_ptr.cpp b/externals/coda-oss/modules/c++/mem/unittests/test_scoped_copyable_ptr.cpp
index bf3fa2594..ff0747f92 100644
--- a/externals/coda-oss/modules/c++/mem/unittests/test_scoped_copyable_ptr.cpp
+++ b/externals/coda-oss/modules/c++/mem/unittests/test_scoped_copyable_ptr.cpp
@@ -20,38 +20,34 @@
*
*/
+#include
+
#include
#include "TestCase.h"
namespace
{
-struct Foo
+struct Foo final
{
- Foo()
- : val1(0),
- val2(0)
- {
- }
-
- size_t val1;
- size_t val2;
+ size_t val1 = 0;
+ size_t val2 = 0;
};
-struct Bar
+struct Bar final
{
- Bar()
- : val3(0)
- {
- }
-
mem::ScopedCopyablePtr foo;
- size_t val3;
+ size_t val3 = 0;
+};
+
+struct Baz final
+{
+ std::shared_ptr pFoo;
+ size_t val3 = 0;
};
-class AssignOnDestruct
+struct AssignOnDestruct final
{
-public:
AssignOnDestruct(size_t &ref, size_t finalVal) :
mRef(ref),
mFinalVal(finalVal)
@@ -92,6 +88,25 @@ TEST_CASE(testCopyConstructor)
TEST_ASSERT_EQ(bar1.val3, 30);
}
+TEST_CASE(testSharedCopyConstructor)
+{
+ // Initialize the values
+ Baz b1;
+ b1.pFoo.reset(new Foo());
+ b1.pFoo->val1 = 10;
+ b1.pFoo->val2 = 20;
+ b1.val3 = 30;
+
+ // Show that memory is shared, not copied as with mem::ScopedCopyablePtr
+ auto b2 = b1;
+ b2.pFoo->val1 = 40;
+ b2.pFoo->val2 = 50;
+ b2.val3 = 60;
+ TEST_ASSERT_EQ(b1.pFoo->val1, 40);
+ TEST_ASSERT_EQ(b1.pFoo->val2, 50);
+ TEST_ASSERT_EQ(b1.val3, 30);
+}
+
TEST_CASE(testAssignmentOperator)
{
// Initialize the values
@@ -117,6 +132,27 @@ TEST_CASE(testAssignmentOperator)
TEST_ASSERT_EQ(bar1.val3, 30);
}
+TEST_CASE(testSharedAssignmentOperator)
+{
+ // Initialize the values
+ Baz b1;
+ b1.pFoo.reset(new Foo());
+ b1.pFoo->val1 = 10;
+ b1.pFoo->val2 = 20;
+ b1.val3 = 30;
+
+ Baz b2;
+ b2 = b1;
+
+ // Show that memory is shared, not copied as with mem::ScopedCopyablePtr
+ b2.pFoo->val1 = 40;
+ b2.pFoo->val2 = 50;
+ b2.val3 = 60;
+ TEST_ASSERT_EQ(b1.pFoo->val1, 40);
+ TEST_ASSERT_EQ(b1.pFoo->val2, 50);
+ TEST_ASSERT_EQ(b1.val3, 30);
+}
+
TEST_CASE(testDestructor)
{
// When the ScopedCopyablePtr goes out of scope, it should delete the
@@ -167,7 +203,9 @@ TEST_CASE(testEqualityOperator)
int main(int, char**)
{
TEST_CHECK(testCopyConstructor);
+ TEST_CHECK(testSharedCopyConstructor);
TEST_CHECK(testAssignmentOperator);
+ TEST_CHECK(testSharedAssignmentOperator);
TEST_CHECK(testDestructor);
TEST_CHECK(testSyntax);
TEST_CHECK(testEqualityOperator);
diff --git a/externals/coda-oss/modules/c++/mt/include/mt/CriticalSection.h b/externals/coda-oss/modules/c++/mt/include/mt/CriticalSection.h
index 69ce39b12..b4aeb42c0 100644
--- a/externals/coda-oss/modules/c++/mt/include/mt/CriticalSection.h
+++ b/externals/coda-oss/modules/c++/mt/include/mt/CriticalSection.h
@@ -51,9 +51,8 @@ namespace mt
* }
* \endcode
*/
-template class CriticalSection
+template struct CriticalSection
{
-public:
//! Constructor. Lock the mutex.
CriticalSection(T* mutex) :
mMutex(mutex),
@@ -92,10 +91,8 @@ template class CriticalSection
mIsLocked = true;
}
-private:
- // Noncopyable
- CriticalSection(const CriticalSection& );
- const CriticalSection& operator=(const CriticalSection& );
+ CriticalSection(const CriticalSection&) = delete;
+ CriticalSection& operator=(const CriticalSection&) = delete;
private:
T* const mMutex;
diff --git a/externals/coda-oss/modules/c++/mt/include/mt/RequestQueue.h b/externals/coda-oss/modules/c++/mt/include/mt/RequestQueue.h
index 313ee2104..cb0d8201c 100644
--- a/externals/coda-oss/modules/c++/mt/include/mt/RequestQueue.h
+++ b/externals/coda-oss/modules/c++/mt/include/mt/RequestQueue.h
@@ -49,10 +49,8 @@ namespace mt
*/
template
-class RequestQueue
+struct RequestQueue
{
-public:
-
//! Default constructor
RequestQueue() :
mAvailableSpace(&mQueueLock),
@@ -128,10 +126,8 @@ class RequestQueue
mAvailableSpace.signal();
}
-private:
- // Noncopyable
- RequestQueue(const RequestQueue& );
- const RequestQueue& operator=(const RequestQueue& );
+ RequestQueue(const RequestQueue&) = delete;
+ RequestQueue& operator=(const RequestQueue&) = delete;
private:
//! The internal data structure
diff --git a/externals/coda-oss/modules/c++/re/source/RegexPCRE.cpp b/externals/coda-oss/modules/c++/re/source/RegexPCRE.cpp
index 44e72bb8f..e641e2d57 100644
--- a/externals/coda-oss/modules/c++/re/source/RegexPCRE.cpp
+++ b/externals/coda-oss/modules/c++/re/source/RegexPCRE.cpp
@@ -139,10 +139,8 @@ class ScopedMatchData
return str.substr(index, subStringLength);
}
-private:
- // Noncopyable
- ScopedMatchData(const ScopedMatchData& );
- ScopedMatchData& operator=(const ScopedMatchData& );
+ ScopedMatchData(const ScopedMatchData&) = delete;
+ ScopedMatchData& operator=(const ScopedMatchData&) = delete;
private:
const pcre2_code* const mCode;
diff --git a/externals/coda-oss/modules/c++/str/include/str/Manip.h b/externals/coda-oss/modules/c++/str/include/str/Manip.h
index 9d404e97c..c7dda96f6 100644
--- a/externals/coda-oss/modules/c++/str/include/str/Manip.h
+++ b/externals/coda-oss/modules/c++/str/include/str/Manip.h
@@ -23,9 +23,11 @@
#ifndef __STR_MANIP_H__
#define __STR_MANIP_H__
-#include
#include
+
+#include
#include
+
#include "str/Convert.h"
namespace str
diff --git a/externals/coda-oss/modules/c++/str/source/Manip.cpp b/externals/coda-oss/modules/c++/str/source/Manip.cpp
index 7b2140256..65f6a2d94 100644
--- a/externals/coda-oss/modules/c++/str/source/Manip.cpp
+++ b/externals/coda-oss/modules/c++/str/source/Manip.cpp
@@ -19,15 +19,16 @@
* see .
*
*/
+#include
+
+#include
+#include
+#include
#include
#include
#include
-#include
-#include
-#include
-
-#include
+#include
namespace
{
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounter.h b/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounter.h
index 569d8454f..b193339d7 100644
--- a/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounter.h
+++ b/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounter.h
@@ -22,14 +22,16 @@
#ifndef __SYS_ATOMIC_COUNTER_H__
#define __SYS_ATOMIC_COUNTER_H__
+#pragma once
-#include
+#include
+#include
#if defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) )
#include
#elif (defined(WIN32) || defined(_WIN32))
#include
-#elif defined(__sun) && defined(HAVE_ATOMIC_H)
+#elif defined(__sun) //&& defined(HAVE_ATOMIC_H)
// atomic.h is available in Solaris 10+
// TODO: For Solaris 9 and older, we currently use the mutex implementation
// http://blogs.oracle.com/d/entry/atomic_operations
@@ -58,13 +60,13 @@ namespace sys
*
* TODO: Provide other operations such as getThenSet() and compareThenSet().
*/
-class AtomicCounter
+template
+struct AtomicCounterT final
{
-public:
- typedef AtomicCounterImpl::ValueType ValueType;
+ using ValueType = typename TAtomicCounterImpl::ValueType ;
//! Constructor
- AtomicCounter(ValueType initialValue = 0) :
+ AtomicCounterT(ValueType initialValue = 0) :
mImpl(initialValue)
{
}
@@ -146,14 +148,24 @@ class AtomicCounter
return mImpl.get();
}
-private:
- // Noncopyable
- AtomicCounter(const AtomicCounter& );
- const AtomicCounter& operator=(const AtomicCounter& );
+ AtomicCounterT(const AtomicCounterT&) = delete;
+ AtomicCounterT& operator=(const AtomicCounterT&) = delete;
private:
- AtomicCounterImpl mImpl;
+ TAtomicCounterImpl mImpl;
};
+
+// platform-specific
+using AtomicCounterOS = AtomicCounterT;
+// built on
+using AtomicCounterCpp11 = AtomicCounterT;
+
+#if !CODA_OSS_cpp17
+using AtomicCounter = AtomicCounterOS; // TODO: AtomicCounterCpp11
+#else
+using AtomicCounter = AtomicCounterCpp11;
+#endif
+
}
#endif
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounterCpp11.h b/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounterCpp11.h
new file mode 100644
index 000000000..bf949f948
--- /dev/null
+++ b/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounterCpp11.h
@@ -0,0 +1,68 @@
+/* =========================================================================
+ * This file is part of sys-c++
+ * =========================================================================
+ *
+ * (C) Copyright 2021, Maxar Technologies, Inc.
+ *
+ * sys-c++ is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; If not,
+ * see .
+ *
+ */
+
+#ifndef CODA_OSS_sys_AtomicCounterCpp11_h_INCLUDED_
+#define CODA_OSS_sys_AtomicCounterCpp11_h_INCLUDED_
+#pragma once
+
+#include
+
+#include // C++11: https://en.cppreference.com/w/cpp/atomic/atomic
+
+namespace sys
+{
+struct AtomicCounterImplCpp11 final
+{
+ using ValueType = size_t ;
+
+ explicit AtomicCounterImplCpp11(ValueType initialValue) :
+ mValue(initialValue)
+ {
+ }
+
+ ValueType getThenIncrement()
+ {
+ // https://en.cppreference.com/w/cpp/atomic/atomic/fetch_add
+ return mValue.fetch_add(1);
+ }
+
+ ValueType getThenDecrement()
+ {
+ // https://en.cppreference.com/w/cpp/atomic/atomic/fetch_sub
+ return mValue.fetch_sub(1);
+ }
+
+ ValueType get() const
+ {
+ // https://en.cppreference.com/w/cpp/atomic/atomic/load
+ return mValue.load();
+ }
+
+ AtomicCounterImplCpp11(const AtomicCounterImplCpp11&) = delete;
+ AtomicCounterImplCpp11& operator=(const AtomicCounterImplCpp11&) = delete;
+
+private:
+ std::atomic mValue;
+};
+}
+
+#endif // CODA_OSS_sys_AtomicCounterCpp11_h_INCLUDED_
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounterMutex.h b/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounterMutex.h
index c8ae0ad10..c56a8f0a4 100644
--- a/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounterMutex.h
+++ b/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounterMutex.h
@@ -27,9 +27,8 @@
namespace sys
{
-class AtomicCounterImpl
+struct AtomicCounterImpl
{
-public:
typedef size_t ValueType;
explicit
@@ -73,10 +72,8 @@ class AtomicCounterImpl
return value;
}
-private:
- // Noncopyable
- AtomicCounterImpl(const AtomicCounterImpl& );
- const AtomicCounterImpl& operator=(const AtomicCounterImpl& );
+ AtomicCounterImpl(const AtomicCounterImpl&) = delete;
+ AtomicCounterImpl& operator=(const AtomicCounterImpl&) = delete;
private:
ValueType mValue;
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounterSolaris.h b/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounterSolaris.h
index dbaafcb6e..eb406ddad 100644
--- a/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounterSolaris.h
+++ b/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounterSolaris.h
@@ -30,9 +30,8 @@
namespace sys
{
// Implemented from boost/smart_ptr/detail/atomic_count_solaris.hpp
-class AtomicCounterImpl
+struct AtomicCounterImpl
{
-public:
typedef Uint32_T ValueType;
explicit
@@ -56,10 +55,8 @@ class AtomicCounterImpl
return static_cast(mValue);
}
-private:
- // Noncopyable
- AtomicCounterImpl(const AtomicCounterImpl& );
- const AtomicCounterImpl& operator=(const AtomicCounterImpl& );
+ AtomicCounterImpl(const AtomicCounterImpl&) = delete;
+ AtomicCounterImpl& operator=(const AtomicCounterImpl&) = delete;
private:
ValueType mValue;
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounterWin32.h b/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounterWin32.h
index ce1998d52..d78a17dd6 100644
--- a/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounterWin32.h
+++ b/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounterWin32.h
@@ -29,9 +29,8 @@
namespace sys
{
// Implemented from boost/smart_ptr/detail/atomic_count_win32.hpp
-class AtomicCounterImpl
+struct AtomicCounterImpl
{
-public:
typedef long ValueType;
explicit
@@ -55,10 +54,8 @@ class AtomicCounterImpl
return static_cast(mValue);
}
-private:
- // Noncopyable
- AtomicCounterImpl(const AtomicCounterImpl& );
- const AtomicCounterImpl& operator=(const AtomicCounterImpl& );
+ AtomicCounterImpl(const AtomicCounterImpl&) = delete;
+ AtomicCounterImpl& operator=(const AtomicCounterImpl&) = delete;
private:
ValueType mValue;
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounterX86.h b/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounterX86.h
index aa2805a7b..5231e587b 100644
--- a/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounterX86.h
+++ b/externals/coda-oss/modules/c++/sys/include/sys/AtomicCounterX86.h
@@ -26,9 +26,8 @@
namespace sys
{
// Implemented from boost/smart_ptr/detail/atomic_count_gcc_x86.hpp
-class AtomicCounterImpl
+struct AtomicCounterImpl
{
-public:
typedef int ValueType;
explicit
@@ -52,6 +51,9 @@ class AtomicCounterImpl
return atomicExchangeAndAdd(&mValue, 0);
}
+ AtomicCounterImpl(const AtomicCounterImpl&) = delete;
+ AtomicCounterImpl& operator=(const AtomicCounterImpl&) = delete;
+
private:
static
ValueType atomicExchangeAndAdd(ValueType* pw, ValueType dv)
@@ -74,11 +76,6 @@ class AtomicCounterImpl
return r;
}
-private:
- // Noncopyable
- AtomicCounterImpl(const AtomicCounterImpl& );
- const AtomicCounterImpl& operator=(const AtomicCounterImpl& );
-
private:
mutable ValueType mValue;
};
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/Backtrace.h b/externals/coda-oss/modules/c++/sys/include/sys/Backtrace.h
index d0d285895..ebfb9d2e8 100644
--- a/externals/coda-oss/modules/c++/sys/include/sys/Backtrace.h
+++ b/externals/coda-oss/modules/c++/sys/include/sys/Backtrace.h
@@ -3,6 +3,7 @@
* =========================================================================
*
* (C) Copyright 2004 - 2014, MDA Information Systems LLC
+ * (C) Copyright 2021, Maxar Technologies, Inc.
*
* sys-c++ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -20,10 +21,27 @@
*
*/
-#ifndef __SYS_BACKTRACE_H__
-#define __SYS_BACKTRACE_H__
+#ifndef CODA_OSS_sys_Backtrace_h_INCLUDED_
+#define CODA_OSS_sys_Backtrace_h_INCLUDED_
+#pragma once
#include
+#include
+
+// We know at compile-time whether sys::getBacktrace() is supported.
+#if defined(__GNUC__)
+// https://man7.org/linux/man-pages/man3/backtrace.3.html
+// "These functions are GNU extensions."
+#define CODA_OSS_sys_Backtrace 20210216L
+#elif _WIN32
+#define CODA_OSS_sys_Backtrace 20210216L
+#else
+#define CODA_OSS_sys_Backtrace 0
+#endif
+
+namespace version { namespace sys {
+constexpr auto backtrace = CODA_OSS_sys_Backtrace;
+} }
namespace sys
{
@@ -32,12 +50,12 @@ namespace sys
* function calls. Usefulness and format may vary depending on
* your platform and what kind of symbols are compiled in.
*
- * Currently only supported on *nix with glibc. This function will
+ * Currently only supported on *nix with glibc and Windows. This function will
* return with an error message instead of a backtrace if the current
* configuration is unsupported.
*/
-std::string getBacktrace();
+std::string getBacktrace(bool* pSupported = nullptr);
+std::string getBacktrace(bool& supported, std::vector& frames);
}
-#endif
-
+#endif // CODA_OSS_sys_Backtrace_h_INCLUDED_
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/ConditionVarPosix.h b/externals/coda-oss/modules/c++/sys/include/sys/ConditionVarPosix.h
index 889902741..b1f7c692b 100644
--- a/externals/coda-oss/modules/c++/sys/include/sys/ConditionVarPosix.h
+++ b/externals/coda-oss/modules/c++/sys/include/sys/ConditionVarPosix.h
@@ -24,9 +24,9 @@
#ifndef __SYS_THREAD_PTHREAD_CONDITION_VARIABLE_H__
#define __SYS_THREAD_PTHREAD_CONDITION_VARIABLE_H__
-#include
+#include
-#if defined(HAVE_PTHREAD_H)
+#if CODA_OSS_POSIX_SOURCE
#include "sys/MutexPosix.h"
#include "sys/ConditionVarInterface.h"
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/Conf.h b/externals/coda-oss/modules/c++/sys/include/sys/Conf.h
index a957da98e..16d405ff6 100644
--- a/externals/coda-oss/modules/c++/sys/include/sys/Conf.h
+++ b/externals/coda-oss/modules/c++/sys/include/sys/Conf.h
@@ -24,6 +24,15 @@
#define __SYS_CONF_H__
#pragma once
+// POSIX is more-or-less "Unix"
+// https://linux.die.net/man/7/feature_test_macros
+// "If no feature test macros are explicitly defined, then the following feature test macros
+// are defined by default: ... _POSIX_SOURCE, and _POSIX_C_SOURCE=200809L. [...]
+// _POSIX_SOURCE Defining this obsolete macro ... is equivalent to defining _POSIX_C_SOURCE ..."
+#define CODA_OSS_POSIX_SOURCE (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 1))
+#define CODA_OSS_POSIX2001_SOURCE CODA_OSS_POSIX_SOURCE && (_POSIX_C_SOURCE >= 200112L)
+#define CODA_OSS_POSIX2008_SOURCE CODA_OSS_POSIX2001_SOURCE && (_POSIX_C_SOURCE >= 200809L)
+
#include
#include
#include
@@ -106,13 +115,14 @@ namespace sys
typedef HANDLE Handle_T;
typedef Int64_T Off_T;
typedef DWORD Pid_T;
-# if SIZEOF_SIZE_T == 8
+# if _WIN64 // SIZEOF_SIZE_T == 8
+ static_assert(sizeof(size_t) == 8, "wrong sizeof(size_t)");
typedef Int64_T SSize_T;
-# elif SIZEOF_SIZE_T == 4
+# else // SIZEOF_SIZE_T == 4
+ static_assert(sizeof(size_t) == 4, "wrong sizeof(size_t)");
typedef Int32_T SSize_T;
-# else
- #error SIZEOF_SIZE_T must be set at configure time
# endif
+ static_assert(sizeof(size_t) == sizeof(SSize_T), "size_t and SSize_T should be the same size");
}
#else // !windows
# include
@@ -314,19 +324,23 @@ namespace sys
inline void* alignedAlloc(size_t size,
size_t alignment = SSE_INSTRUCTION_ALIGNMENT)
{
-#if defined(WIN32) || defined(_WIN32)
- void* p = _aligned_malloc(size, alignment);
-#elif defined(HAVE_POSIX_MEMALIGN)
void* p = nullptr;
+#if defined(WIN32) || defined(_WIN32)
+ p = _aligned_malloc(size, alignment);
+#elif CODA_OSS_POSIX2001_SOURCE
+ // https://linux.die.net/man/3/posix_memalign
if (posix_memalign(&p, alignment, size) != 0)
{
p = nullptr;
}
-#elif defined(HAVE_MEMALIGN)
- void* const p = memalign(alignment, size);
+#elif CODA_OSS_POSIX_SOURCE
+ // https://linux.die.net/man/3/posix_memalign
+ // "The functions memalign(), ... have been available in all Linux libc libraries."
+ p = memalign(alignment, size);
#else
//! this is a basic unaligned allocation
- void* p = malloc(size);
+ p = malloc(size);
+ #error "Don't know how to implement alignedAlloc()."
#endif
if (!p)
throw except::Exception(Ctxt(
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/DateTime.h b/externals/coda-oss/modules/c++/sys/include/sys/DateTime.h
index 1a78190c1..28232dbbf 100644
--- a/externals/coda-oss/modules/c++/sys/include/sys/DateTime.h
+++ b/externals/coda-oss/modules/c++/sys/include/sys/DateTime.h
@@ -23,10 +23,12 @@
#ifndef __SYS_DATE_TIME_H__
#define __SYS_DATE_TIME_H__
+#pragma once
-#include
#include
+#include
+
namespace sys
{
@@ -36,15 +38,15 @@ namespace sys
class DateTime
{
protected:
- int mYear;
- int mMonth;
- int mDayOfMonth;
- int mDayOfWeek;
- int mDayOfYear;
- int mHour;
- int mMinute;
- double mSecond;
- double mTimeInMillis;
+ int mYear = 0;
+ int mMonth = 0;
+ int mDayOfMonth = 0;
+ int mDayOfWeek = 0;
+ int mDayOfYear = 0;
+ int mHour = 0;
+ int mMinute = 0;
+ double mSecond = 0.0;
+ double mTimeInMillis = 0.0;
// Turn a tm struct into a double
double toMillis(tm t) const;
@@ -71,9 +73,12 @@ class DateTime
//! @brief Given seconds since the epoch, provides the time
virtual void getTime(time_t numSecondsSinceEpoch, tm& t) const = 0;
+ static void localtime(time_t numSecondsSinceEpoch, tm& t);
+ static void gmtime(time_t numSecondsSinceEpoch, tm& t);
+
public:
- DateTime();
- virtual ~DateTime();
+ DateTime() = default;
+ virtual ~DateTime() {}
//! Return month {1,12}
int getMonth() const { return mMonth; }
@@ -175,6 +180,14 @@ class DateTime
//@}
};
+// Always make our own versions available for unit-testing. Clients should use
+// DateTme methods and implementers DateTime::localtime()/DateTime::gmtime().
+namespace details
+{
+extern int localtime_s(tm*, const time_t*);
+extern int gmtime_s(tm*, const time_t*);
+}
+
}
#endif//__SYS_DATE_TIME_H__
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/Dbg.h b/externals/coda-oss/modules/c++/sys/include/sys/Dbg.h
index 6e91ea55f..52126be87 100644
--- a/externals/coda-oss/modules/c++/sys/include/sys/Dbg.h
+++ b/externals/coda-oss/modules/c++/sys/include/sys/Dbg.h
@@ -3,6 +3,7 @@
* =========================================================================
*
* (C) Copyright 2004 - 2014, MDA Information Systems LLC
+ * (C) Copyright 2021, Maxar Technologies, Inc.
*
* sys-c++ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -21,8 +22,8 @@
*/
-#ifndef __DBG_H__
-#define __DBG_H__
+#ifndef CODA_OSS_sys_Dbg_h_INCLUDED_
+#define CODA_OSS_sys_Dbg_h_INCLUDED_
#include
#include
@@ -35,6 +36,52 @@
# include
#endif
+// A "debug" build has debugging symbols, detailed call stacks, minimal optimization, STL validation, etc.
+// A "release" build is likely to "run fast" and be "shipped;" it might lack much of what is in a "debug" build.
+#ifndef CODA_OSS_DEBUG
+#if defined(_MSC_VER)
+ // https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-160
+ #if _DEBUG // "Defined as 1 ... . Otherwise, undefined."
+ #ifdef NDEBUG
+ #error "NDEBUG #define'd with _DEBUG"
+ #endif
+ #define CODA_OSS_DEBUG 1
+ #endif // _DEBUG
+#elif defined(__GNUC__)
+ // https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html#Common-Predefined-Macros
+ #if __OPTIMIZE__ // "... is defined ... . If they are defined, their value is 1."
+ #ifndef NDEBUG
+ //#error "NDEBUG should be #define'd with __OPTIMIZE__"
+ #endif
+ #define CODA_OSS_DEBUG 0
+ #endif // __OPTIMIZE__
+#else
+ #error "Can't #define CODA_OSS_DEBUG for this compiler."
+#endif
+#endif // CODA_OSS_DEBUG
+#ifndef CODA_OSS_DEBUG // not set above, check NDEBUG
+ #ifdef NDEBUG // https://en.cppreference.com/w/c/error/assert
+ #define CODA_OSS_DEBUG 0 // NDEBUG = "No DEBUG"
+ #else
+ #define CODA_OSS_DEBUG 1
+ #endif // NDEBUG
+#endif
+#ifndef CODA_OSS_DEBUG
+ #error "Unable to #define CODA_OSS_DEBUG"
+#endif
+
+// Be sure NDEBUG and CODA_OSS_DEBUG are in-sync
+// GCC doesn't set NDEBUG w/__OPTIMIZE__ (see above), so we can't be too rigorous
+#if CODA_OSS_DEBUG && defined(NDEBUG)
+ #error "Both CODA_OSS_DEBUG and NDEBUG are set."
+#endif
+
+namespace sys
+{
+constexpr auto debug_build = CODA_OSS_DEBUG ? true : false;
+constexpr auto release_build = !debug_build;
+}
+
#ifndef DEBUG_STREAM
#define DEBUG_STREAM stderr
#endif
@@ -79,6 +126,23 @@
* open emacs, for instance, with the file in question at the line number
* in question.
*/
+// Keep __DEBUG for existing code/scripts; but shouldn't be used.
+#ifndef CODA_OSS_debugging
+ #ifdef __DEBUG
+ #define CODA_OSS_debugging 1
+ // or ... use the value of CODA_OSS_DEBUG ?
+ //#define CODA_OSS_debugging CODA_OSS_DEBUG
+ #else
+ // or here ... ?
+ //#define CODA_OSS_debugging CODA_OSS_DEBUG
+ #define CODA_OSS_debugging 0
+ #endif
+#endif // CODA_OSS_debugging
+
+namespace sys
+{
+constexpr bool debugging = CODA_OSS_debugging ? true : false;
+}
namespace sys
{
@@ -101,7 +165,7 @@ void diePrintf(const char *format, ...);
#define die_printf sys::diePrintf
#define dbg_ln(STR) dbg_printf("[%s, %d]: '%s'\n", __FILE__, __LINE__, STR)
-#ifdef __DEBUG
+#if CODA_OSS_debugging
#ifndef __DEBUG_SHORTEN_EVAL
#define EVAL(X) std::cout << '(' << __FILE__ << ',' <<__LINE__ << ") "#X"=" << X << std::endl
@@ -121,4 +185,4 @@ void diePrintf(const char *format, ...);
#define ASSERT_OR(A, E) 1
#endif
-#endif // __DBG_H__
+#endif // CODA_OSS_sys_Dbg_h_INCLUDED_
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/Exec.h b/externals/coda-oss/modules/c++/sys/include/sys/Exec.h
index 710f95086..9b8d56d56 100644
--- a/externals/coda-oss/modules/c++/sys/include/sys/Exec.h
+++ b/externals/coda-oss/modules/c++/sys/include/sys/Exec.h
@@ -82,11 +82,8 @@ class Exec : public sys::Runnable
* \brief opens a child process and connects a pipe
* to read back the std::cout
*/
-class ExecPipe : Exec
+struct ExecPipe : Exec
{
-
-public:
-
/*!
* Constructor --
* Kicks off child process and connects a pipe to the std::cout
@@ -136,6 +133,9 @@ class ExecPipe : Exec
// this is a blocking call until the process is complete
int closePipe();
+ ExecPipe(const ExecPipe&) = delete;
+ ExecPipe& operator=(const ExecPipe&) = delete;
+
protected:
#ifdef _WIN32
@@ -153,12 +153,6 @@ class ExecPipe : Exec
//! forcefully kill the process and call closePipe
int killProcess();
-
-private:
-
- //! Noncopyable
- ExecPipe(const ExecPipe& );
- const ExecPipe& operator=(const ExecPipe& );
};
}
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/MutexPosix.h b/externals/coda-oss/modules/c++/sys/include/sys/MutexPosix.h
index 39e623847..e954c3312 100644
--- a/externals/coda-oss/modules/c++/sys/include/sys/MutexPosix.h
+++ b/externals/coda-oss/modules/c++/sys/include/sys/MutexPosix.h
@@ -24,9 +24,9 @@
#ifndef __SYS_MUTEX_POSIX_H__
#define __SYS_MUTEX_POSIX_H__
-#include
+#include
-#if defined(HAVE_PTHREAD_H)
+#if CODA_OSS_POSIX_SOURCE
#include "sys/MutexInterface.h"
#include
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/SemaphorePosix.h b/externals/coda-oss/modules/c++/sys/include/sys/SemaphorePosix.h
index 49078abc3..fc1731d8f 100644
--- a/externals/coda-oss/modules/c++/sys/include/sys/SemaphorePosix.h
+++ b/externals/coda-oss/modules/c++/sys/include/sys/SemaphorePosix.h
@@ -24,9 +24,9 @@
#ifndef __SYS_SEMAPHORE_POSIX_H__
#define __SYS_SEMAPHORE_POSIX_H__
-#include
+#include
-#if defined(HAVE_PTHREAD_H) && !defined(__APPLE_CC__)
+#if CODA_OSS_POSIX_SOURCE &&!defined(__APPLE_CC__)
#include "sys/SemaphoreInterface.h"
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/ThreadInterface.h b/externals/coda-oss/modules/c++/sys/include/sys/ThreadInterface.h
index 36f7ec0fa..9ea31adb4 100644
--- a/externals/coda-oss/modules/c++/sys/include/sys/ThreadInterface.h
+++ b/externals/coda-oss/modules/c++/sys/include/sys/ThreadInterface.h
@@ -68,9 +68,8 @@ namespace sys
*
*/
-class ThreadInterface : public Runnable
+struct ThreadInterface : public Runnable
{
-public:
enum { DEFAULT_LEVEL, KERNEL_LEVEL, USER_LEVEL };
enum { MINIMUM_PRIORITY, NORMAL_PRIORITY, MAXIMUM_PRIORITY };
@@ -242,6 +241,10 @@ class ThreadInterface : public Runnable
mIsRunning = isRunning;
}
+
+ ThreadInterface(const ThreadInterface&) = delete;
+ ThreadInterface& operator=(const ThreadInterface&) = delete;
+
private:
bool mIsSelf;
@@ -272,10 +275,6 @@ class ThreadInterface : public Runnable
//! The level at which this thread runs
int mLevel;
bool mIsRunning;
-
- // Noncopyable
- ThreadInterface(const ThreadInterface& );
- const ThreadInterface& operator=(const ThreadInterface& );
};
}
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/ThreadPosix.h b/externals/coda-oss/modules/c++/sys/include/sys/ThreadPosix.h
index 51e6d5316..bbb18ae7a 100644
--- a/externals/coda-oss/modules/c++/sys/include/sys/ThreadPosix.h
+++ b/externals/coda-oss/modules/c++/sys/include/sys/ThreadPosix.h
@@ -24,9 +24,9 @@
#ifndef __SYS_THREAD_PTHREAD_THREAD_H__
#define __SYS_THREAD_PTHREAD_THREAD_H__
-#include
+#include
-#if defined(HAVE_PTHREAD_H)
+#if CODA_OSS_POSIX_SOURCE
#include
#include
diff --git a/externals/coda-oss/modules/c++/sys/source/Backtrace.cpp b/externals/coda-oss/modules/c++/sys/source/Backtrace.cpp
index 212c988f9..48a9970c4 100644
--- a/externals/coda-oss/modules/c++/sys/source/Backtrace.cpp
+++ b/externals/coda-oss/modules/c++/sys/source/Backtrace.cpp
@@ -22,23 +22,38 @@
#include
-#include
+#include
#include
-static const size_t MAX_STACK_ENTRIES = 62;
+#include
+
+#if !CODA_OSS_sys_Backtrace
+
+static std::string getBacktrace(bool* pSupported, std::vector*)
+{
+ if (pSupported != nullptr)
+ {
+ *pSupported = false;
+ }
+ return "sys::getBacktrace() is not supported "
+ "on the current platform and/or libc";
+}
+
+#else
-#ifdef HAVE_EXECINFO_H
+#if defined(__GNUC__)
+// https://man7.org/linux/man-pages/man3/backtrace.3.html
+// "These functions are GNU extensions."
#include
-#include
+
+constexpr size_t MAX_STACK_ENTRIES = 62;
namespace
{
-
//! RAII wrapper for stack symbols
-class BacktraceHelper
+struct BacktraceHelper final
{
-public:
BacktraceHelper(char** stackSymbols)
: mStackSymbols(stackSymbols)
{}
@@ -48,18 +63,22 @@ class BacktraceHelper
std::free(mStackSymbols);
}
- std::string operator[](size_t idx)
+ std::string operator[](size_t idx) const
{
return mStackSymbols[idx];
}
private:
char** mStackSymbols;
};
-
}
-std::string sys::getBacktrace()
+static std::string getBacktrace(bool* pSupported, std::vector* pFrames)
{
+ if (pSupported != nullptr)
+ {
+ *pSupported = true;
+ }
+
void* stackBuffer[MAX_STACK_ENTRIES];
int currentStackSize = backtrace(stackBuffer, MAX_STACK_ENTRIES);
BacktraceHelper stackSymbols(backtrace_symbols(stackBuffer,
@@ -68,18 +87,83 @@ std::string sys::getBacktrace()
std::stringstream ss;
for (int ii = 0; ii < currentStackSize; ++ii)
{
- ss << stackSymbols[ii] << std::endl;
+ auto stackSymbol = stackSymbols[ii] + "\n";
+ ss << stackSymbol;
+ if (pFrames != nullptr)
+ {
+ pFrames->push_back(std::move(stackSymbol));
+ }
}
return ss.str();
}
-#else
+#elif _WIN32
+#include
+#include
+#pragma comment(lib, "dbghelp")
-std::string sys::getBacktrace()
+static std::string getBacktrace(bool* pSupported, std::vector* pFrames)
{
- return "sys::getBacktrace() is not supported "
- "on the current platform and/or libc";
+ if (pSupported != nullptr)
+ {
+ *pSupported = true;
+ }
+
+ // https://stackoverflow.com/a/5699483/8877
+ HANDLE process = GetCurrentProcess();
+ auto result = SymInitialize(process, NULL, TRUE) == TRUE ? true : false; // https://docs.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-syminitialize
+ if (!result)
+ {
+ return "sys::getBacktrace(): SymInitialize() failed";
+ }
+
+ PVOID stack[100];
+ auto frames = CaptureStackBackTrace(0, 100, stack, NULL);
+ auto symbol = reinterpret_cast(calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1));
+ if (symbol == nullptr)
+ {
+ return "sys::getBacktrace(): calloc() failed";
+ }
+ symbol->MaxNameLen = 255;
+ symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+
+ std::string retval;
+ for (unsigned int i = 0; i < frames; i++)
+ {
+ const auto address = reinterpret_cast(stack[i]);
+ result = SymFromAddr(process, address, 0, symbol) == TRUE ? true : false;
+ if (!result)
+ {
+ continue;
+ }
+ auto frame = str::format("%i: %s - 0x%0X\n",
+ frames - i - 1,
+ symbol->Name,
+ symbol->Address);
+ retval += frame;
+ if (pFrames != nullptr)
+ {
+ pFrames->push_back(std::move(frame));
+ }
+ }
+
+ free(symbol);
+ return retval;
}
+#else
+
+#error "CODA_OSS_sys_Backtrace inconsistency."
+
#endif
+#endif // CODA_OSS_sys_Backtrace
+
+std::string sys::getBacktrace(bool* pSupported)
+{
+ return ::getBacktrace(pSupported, nullptr /*frames*/);
+}
+std::string sys::getBacktrace(bool& supported, std::vector& frames)
+{
+ return ::getBacktrace(&supported, &frames);
+}
diff --git a/externals/coda-oss/modules/c++/sys/source/ConditionVarPosix.cpp b/externals/coda-oss/modules/c++/sys/source/ConditionVarPosix.cpp
index 77a62b7b2..144c25bee 100644
--- a/externals/coda-oss/modules/c++/sys/source/ConditionVarPosix.cpp
+++ b/externals/coda-oss/modules/c++/sys/source/ConditionVarPosix.cpp
@@ -22,7 +22,7 @@
#include
-#if defined(HAVE_PTHREAD_H)
+#if CODA_OSS_POSIX_SOURCE
#include
diff --git a/externals/coda-oss/modules/c++/sys/source/DateTime.cpp b/externals/coda-oss/modules/c++/sys/source/DateTime.cpp
index 2346b2091..eb3059dca 100644
--- a/externals/coda-oss/modules/c++/sys/source/DateTime.cpp
+++ b/externals/coda-oss/modules/c++/sys/source/DateTime.cpp
@@ -19,20 +19,23 @@
* see .
*
*/
+#include "sys/DateTime.h"
-#include
+#include
+#include
+#include
+#include
+
+#include
#include "except/Exception.h"
-#include "sys/DateTime.h"
#include "sys/Conf.h"
#include "str/Convert.h"
#include "str/Manip.h"
-#include
-#include
-#if defined(HAVE_SYS_TIME_H)
+#if CODA_OSS_POSIX_SOURCE
#include
-#elif defined(_WIN32)
+#elif _WIN32
#include
#endif
@@ -379,17 +382,20 @@ double sys::DateTime::toMillis(tm t) const
return (timeInSeconds + timediff) * 1000;
}
-void sys::DateTime::setNow()
+static double getNowInMillis()
{
-#ifdef HAVE_CLOCK_GETTIME
+ // https://linux.die.net/man/2/gettimeofday
+ // "SVr4, 4.3BSD. POSIX.1-2001 describes gettimeofday() ... POSIX.1-2008 marks
+ // gettimeofday() as obsolete, recommending the use of clock_gettime(2) instead."
+#if CODA_OSS_POSIX2008_SOURCE
struct timespec now;
clock_gettime(CLOCK_REALTIME,&now);
- mTimeInMillis = (now.tv_sec + 1.0e-9 * now.tv_nsec) * 1000;
-#elif defined(HAVE_SYS_TIME_H)
+ return (now.tv_sec + 1.0e-9 * now.tv_nsec) * 1000;
+#elif CODA_OSS_POSIX_SOURCE
struct timeval now;
gettimeofday(&now,NULL);
- mTimeInMillis = (now.tv_sec + 1.0e-6 * now.tv_usec) * 1000;
-#elif defined(_WIN32)
+ return (now.tv_sec + 1.0e-6 * now.tv_usec) * 1000;
+#elif _WIN32
// Getting time twice may be inefficient but is quicker
// than converting the SYSTEMTIME structure into
// milliseconds
@@ -397,10 +403,14 @@ void sys::DateTime::setNow()
// does not need millisecond accuracy
SYSTEMTIME now;
GetLocalTime(&now);
- mTimeInMillis = (double)time(NULL) * 1000 + now.wMilliseconds;
+ return (double)time(NULL) * 1000 + now.wMilliseconds;
#else
- mTimeInMillis = (double)time(NULL) * 1000;
+ return (double)time(NULL) * 1000;
#endif
+}
+void sys::DateTime::setNow()
+{
+ mTimeInMillis = getNowInMillis();
fromMillis();
}
@@ -409,21 +419,6 @@ void sys::DateTime::getTime(tm& t) const
getTime(static_cast(mTimeInMillis / 1000), t);
}
-sys::DateTime::DateTime() :
- mYear(0),
- mMonth(0),
- mDayOfMonth(0),
- mDayOfWeek(0),
- mDayOfYear(0),
- mHour(0),
- mMinute(0),
- mSecond(0.0),
- mTimeInMillis(0.0)
-{ }
-
-sys::DateTime::~DateTime()
-{}
-
std::string sys::DateTime::monthToString(int month)
{
switch (month)
@@ -601,3 +596,89 @@ std::string sys::DateTime::format(const std::string& formatStr) const
return std::string(str);
}
+
+// https://en.cppreference.com/w/c/chrono/localtime
+// "The structure may be shared between gmtime, localtime, and ctime ... ."
+static std::mutex g_dateTimeMutex;
+template
+static inline int time_s(F f, tm* t, const time_t* numSecondsSinceEpoch)
+{
+ tm* result = nullptr;
+ {
+ std::lock_guard guard(g_dateTimeMutex);
+ result = f(numSecondsSinceEpoch);
+ }
+ if (result == nullptr)
+ {
+ return errno;
+ }
+
+ *t = *result;
+ return 0; // no error
+}
+int sys::details::localtime_s(tm* t, const time_t* numSecondsSinceEpoch)
+{
+ return time_s(localtime, t, numSecondsSinceEpoch);
+}
+int sys::details::gmtime_s(tm* t, const time_t* numSecondsSinceEpoch)
+{
+ return time_s(gmtime, t, numSecondsSinceEpoch);
+}
+
+void sys::DateTime::localtime(time_t numSecondsSinceEpoch, tm& t)
+{
+ // Would like to use the reentrant version. If we don't have one, cross
+ // our fingers and hope the regular function actually is reentrant
+ // (supposedly this is the case on Windows).
+#if CODA_OSS_POSIX_SOURCE
+ if (::localtime_r(&numSecondsSinceEpoch, &t) == NULL)
+ {
+ int const errnum = errno;
+ throw except::Exception(Ctxt("localtime_r() failed (" +
+ std::string(::strerror(errnum)) + ")"));
+ }
+#elif _WIN32
+ const auto errnum = ::localtime_s(&t, &numSecondsSinceEpoch);
+ if (errnum != 0)
+ {
+ throw except::Exception(Ctxt("localtime_s() failed (" +
+ std::string(::strerror(errnum)) + ")"));
+ }
+#else
+ const auto errnum = sys::details::localtime_s(&t, &numSecondsSinceEpoch);
+ if (errnum != 0)
+ {
+ throw except::Exception(Ctxt("localtime failed (" +
+ std::string(::strerror(errnum)) + ")"));
+ }
+#endif
+}
+
+void sys::DateTime::gmtime(time_t numSecondsSinceEpoch, tm& t)
+{
+ // Would like to use the reentrant version. If we don't have one, cross
+ // our fingers and hope the regular function actually is reentrant
+ // (supposedly this is the case on Windows).
+#if CODA_OSS_POSIX_SOURCE
+ if (::gmtime_r(&numSecondsSinceEpoch, &t) == NULL)
+ {
+ int const errnum = errno;
+ throw except::Exception(Ctxt("gmtime_r() failed (" +
+ std::string(::strerror(errnum)) + ")"));
+ }
+#elif _WIN32
+ const auto errnum = ::gmtime_s(&t, &numSecondsSinceEpoch);
+ if (errnum != 0)
+ {
+ throw except::Exception(Ctxt("gmtime_s() failed (" +
+ std::string(::strerror(errnum)) + ")"));
+ }
+#else
+ const auto errnum = sys::details::gmtime_s(&t, &numSecondsSinceEpoch);
+ if (errnum != 0)
+ {
+ throw except::Exception(Ctxt("gmtime failed (" +
+ std::string(::strerror(errnum)) + ")"));
+ }
+#endif
+}
\ No newline at end of file
diff --git a/externals/coda-oss/modules/c++/sys/source/Dbg.cpp b/externals/coda-oss/modules/c++/sys/source/Dbg.cpp
index bdd2bb24a..e2d573eb3 100644
--- a/externals/coda-oss/modules/c++/sys/source/Dbg.cpp
+++ b/externals/coda-oss/modules/c++/sys/source/Dbg.cpp
@@ -3,6 +3,7 @@
* =========================================================================
*
* (C) Copyright 2004 - 2014, MDA Information Systems LLC
+ * (C) Copyright 2021, Maxar Technologies, Inc.
*
* sys-c++ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -25,15 +26,14 @@
void sys::dbgPrintf(const char *format, ...)
{
-#ifdef __DEBUG
- va_list args;
- va_start(args, format);
- fprintf(DEBUG_STREAM, " ");
- vfprintf(DEBUG_STREAM, format, args);
- va_end(args);
-#else
- (void)format; //suppress unreferenced formal parameter warning when __DEBUG not defined
-#endif
+ if (sys::debugging)
+ {
+ va_list args;
+ va_start(args, format);
+ fprintf(DEBUG_STREAM, " ");
+ vfprintf(DEBUG_STREAM, format, args);
+ va_end(args);
+ }
}
void sys::diePrintf(const char *format, ...)
diff --git a/externals/coda-oss/modules/c++/sys/source/LocalDateTime.cpp b/externals/coda-oss/modules/c++/sys/source/LocalDateTime.cpp
index c3fca4b63..22bde3d57 100755
--- a/externals/coda-oss/modules/c++/sys/source/LocalDateTime.cpp
+++ b/externals/coda-oss/modules/c++/sys/source/LocalDateTime.cpp
@@ -19,11 +19,6 @@
* see .
*
*/
-
-#include
-
-#include
-
#include
#include
@@ -59,33 +54,7 @@ void LocalDateTime::toMillis()
void LocalDateTime::getTime(time_t numSecondsSinceEpoch, tm& t) const
{
- // Would like to use the reentrant version. If we don't have one, cross
- // our fingers and hope the regular function actually is reentrant
- // (supposedly this is the case on Windows).
-#ifdef _WIN32
- const auto errnum = ::localtime_s(&t, &numSecondsSinceEpoch);
- if (errnum != 0)
- {
- throw except::Exception(Ctxt("localtime_s() failed (" +
- std::string(::strerror(errnum)) + ")"));
- }
-#elif defined(HAVE_LOCALTIME_R)
- if (::localtime_r(&numSecondsSinceEpoch, &t) == NULL)
- {
- int const errnum = errno;
- throw except::Exception(Ctxt("localtime_r() failed (" +
- std::string(::strerror(errnum)) + ")"));
- }
-#else
- tm const * const localTimePtr = ::localtime(&numSecondsSinceEpoch);
- if (localTimePtr == NULL)
- {
- int const errnum = errno;
- throw except::Exception(Ctxt("localtime failed (" +
- std::string(::strerror(errnum)) + ")"));
- }
- t = *localTimePtr;
-#endif
+ DateTime::localtime(numSecondsSinceEpoch, t);
}
LocalDateTime::LocalDateTime() :
diff --git a/externals/coda-oss/modules/c++/sys/source/MutexPosix.cpp b/externals/coda-oss/modules/c++/sys/source/MutexPosix.cpp
index 04b9882e9..f28ce93be 100644
--- a/externals/coda-oss/modules/c++/sys/source/MutexPosix.cpp
+++ b/externals/coda-oss/modules/c++/sys/source/MutexPosix.cpp
@@ -22,7 +22,7 @@
#include
-#if defined(HAVE_PTHREAD_H)
+#if CODA_OSS_POSIX_SOURCE
diff --git a/externals/coda-oss/modules/c++/sys/source/OSUnix.cpp b/externals/coda-oss/modules/c++/sys/source/OSUnix.cpp
index 992f86010..e91b7a88d 100644
--- a/externals/coda-oss/modules/c++/sys/source/OSUnix.cpp
+++ b/externals/coda-oss/modules/c++/sys/source/OSUnix.cpp
@@ -20,19 +20,21 @@
*
*/
-#include "config/coda_oss_config.h"
-
-#if !(defined(WIN32) || defined(_WIN32))
-
#include
#include
-#include
-#include
#include
+#include
+
+#include
#include
#include
#include
-#include
+
+#include "sys/Conf.h"
+
+#if !(defined(WIN32) || defined(_WIN32))
+
+#include
#if defined(__APPLE__)
@@ -314,7 +316,8 @@ void sys::OSUnix::setEnv(const std::string& var,
{
int ret;
-#ifdef HAVE_SETENV
+#if CODA_OSS_POSIX2001_SOURCE
+ // https://man7.org/linux/man-pages/man3/setenv.3.html
ret = setenv(var.c_str(), val.c_str(), overwrite);
#else
// putenv() will overwrite the value if it already exists, so if we don't
diff --git a/externals/coda-oss/modules/c++/sys/source/SemaphorePosix.cpp b/externals/coda-oss/modules/c++/sys/source/SemaphorePosix.cpp
index 605326cf5..0d6d09cee 100644
--- a/externals/coda-oss/modules/c++/sys/source/SemaphorePosix.cpp
+++ b/externals/coda-oss/modules/c++/sys/source/SemaphorePosix.cpp
@@ -22,7 +22,7 @@
#include
-#if defined(HAVE_PTHREAD_H) && !defined(__APPLE_CC__)
+#if CODA_OSS_POSIX_SOURCE && !defined(__APPLE_CC__)
#include
diff --git a/externals/coda-oss/modules/c++/sys/source/ThreadPosix.cpp b/externals/coda-oss/modules/c++/sys/source/ThreadPosix.cpp
index d7601a555..07f7f9867 100644
--- a/externals/coda-oss/modules/c++/sys/source/ThreadPosix.cpp
+++ b/externals/coda-oss/modules/c++/sys/source/ThreadPosix.cpp
@@ -22,7 +22,7 @@
#include
-#if defined(HAVE_PTHREAD_H)
+#if CODA_OSS_POSIX_SOURCE
#if defined(WIN32) || defined(_WIN32)
# define SIGKILL 0
diff --git a/externals/coda-oss/modules/c++/sys/source/UTCDateTime.cpp b/externals/coda-oss/modules/c++/sys/source/UTCDateTime.cpp
index 45b532b4b..0a6e8fd08 100755
--- a/externals/coda-oss/modules/c++/sys/source/UTCDateTime.cpp
+++ b/externals/coda-oss/modules/c++/sys/source/UTCDateTime.cpp
@@ -19,11 +19,8 @@
* see .
*
*/
-
-#include
-
-#include
#include
+
#include
#include
#include
@@ -133,33 +130,7 @@ void UTCDateTime::toMillis()
void UTCDateTime::getTime(time_t numSecondsSinceEpoch, tm& t) const
{
- // Would like to use the reentrant version. If we don't have one, cross
- // our fingers and hope the regular function actually is reentrant
- // (supposedly this is the case on Windows).
-#if _WIN32
- const auto errnum = ::gmtime_s(&t, &numSecondsSinceEpoch);
- if (errnum != 0)
- {
- throw except::Exception(Ctxt("gmtime_s() failed (" +
- std::string(::strerror(errnum)) + ")"));
- }
-#elif defined(HAVE_GMTIME_R)
- if (::gmtime_r(&numSecondsSinceEpoch, &t) == NULL)
- {
- int const errnum = errno;
- throw except::Exception(Ctxt("gmtime_r() failed (" +
- std::string(::strerror(errnum)) + ")"));
- }
-#else
- tm const * const gmTimePtr = ::gmtime(&numSecondsSinceEpoch);
- if (gmTimePtr == NULL)
- {
- int const errnum = errno;
- throw except::Exception(Ctxt("gmtime failed (" +
- std::string(::strerror(errnum)) + ")"));
- }
- t = *gmTimePtr;
-#endif
+ DateTime::gmtime(numSecondsSinceEpoch, t);
}
UTCDateTime::UTCDateTime()
diff --git a/externals/coda-oss/modules/c++/sys/unittests/test_atomic_counter.cpp b/externals/coda-oss/modules/c++/sys/unittests/test_atomic_counter.cpp
index d329d65e1..f3ebafea1 100644
--- a/externals/coda-oss/modules/c++/sys/unittests/test_atomic_counter.cpp
+++ b/externals/coda-oss/modules/c++/sys/unittests/test_atomic_counter.cpp
@@ -32,21 +32,31 @@
namespace
{
-typedef sys::AtomicCounter::ValueType ValueType;
-
-TEST_CASE(testConstructor)
+template
+static void testConstructor_(const std::string& testName)
{
- TEST_ASSERT_EQ(sys::AtomicCounter().get(), 0);
- TEST_ASSERT_EQ(sys::AtomicCounter(12345).get(), 12345);
+ using ValueType = typename TAtomicCounter::ValueType;
+
+ TEST_ASSERT_EQ(TAtomicCounter().get(), 0);
+ TEST_ASSERT_EQ(TAtomicCounter(12345).get(), 12345);
TEST_ASSERT_EQ(
- sys::AtomicCounter(std::numeric_limits::max()).get(),
+ TAtomicCounter(std::numeric_limits::max()).get(),
std::numeric_limits::max());
}
+TEST_CASE(testConstructor)
+{
+ testConstructor_(testName);
+ testConstructor_(testName);
+ testConstructor_(testName);
+}
-TEST_CASE(testIncrement)
+template
+static void testIncrement_(const std::string& testName)
{
- sys::AtomicCounter ctr(100);
+ using ValueType = typename TAtomicCounter::ValueType;
+
+ TAtomicCounter ctr(100);
TEST_ASSERT_EQ(ctr.getThenIncrement(), 100);
TEST_ASSERT_EQ(ctr.get(), 101);
@@ -65,10 +75,19 @@ TEST_CASE(testIncrement)
TEST_ASSERT_EQ(value, 105);
TEST_ASSERT_EQ(ctr.get(), 105);
}
+TEST_CASE(testIncrement)
+{
+ testIncrement_(testName);
+ testIncrement_(testName);
+ testIncrement_(testName);
+}
-TEST_CASE(testDecrement)
+template
+static void testDecrement_(const std::string& testName)
{
- sys::AtomicCounter ctr(100);
+ using ValueType = typename TAtomicCounter::ValueType;
+
+ TAtomicCounter ctr(100);
TEST_ASSERT_EQ(ctr.getThenDecrement(), 100);
TEST_ASSERT_EQ(ctr.get(), 99);
@@ -87,12 +106,18 @@ TEST_CASE(testDecrement)
TEST_ASSERT_EQ(value, 95);
TEST_ASSERT_EQ(ctr.get(), 95);
}
+TEST_CASE(testDecrement)
+{
+ testDecrement_(testName);
+ testDecrement_(testName);
+ testDecrement_(testName);
+}
-class IncrementAtomicCounter : public sys::Runnable
+template
+struct IncrementAtomicCounterT final : public sys::Runnable
{
-public:
- IncrementAtomicCounter(size_t numIncrements,
- sys::AtomicCounter& ctr,
+ IncrementAtomicCounterT(size_t numIncrements,
+ TAtomicCounter& ctr,
ValueType* values) :
mNumIncrements(numIncrements),
mCtr(ctr),
@@ -110,19 +135,23 @@ class IncrementAtomicCounter : public sys::Runnable
private:
const size_t mNumIncrements;
- sys::AtomicCounter& mCtr;
+ TAtomicCounter& mCtr;
ValueType* const mValues;
};
-TEST_CASE(testThreadedIncrement)
+template
+static void testThreadedIncrement_(const std::string& testName)
{
+ using ValueType = typename TAtomicCounter::ValueType;
+ using IncrementAtomicCounter = IncrementAtomicCounterT;
+
const size_t numThreads = 13;
const size_t numIncrements = 1000;
std::vector values(numThreads * numIncrements);
std::vector valuesPtr(numThreads);
std::vector threads(numThreads);
- sys::AtomicCounter ctr(0);
+ TAtomicCounter ctr(0);
// Create all the threads
ValueType* ptr(&values[0]);
@@ -161,15 +190,21 @@ TEST_CASE(testThreadedIncrement)
std::sort(values.begin(), values.end());
for (size_t ii = 0; ii < values.size(); ++ii)
{
- TEST_ASSERT_EQ(values[ii], (sys::SSize_T)ii);
+ TEST_ASSERT_EQ(static_cast(values[ii]), static_cast(ii));
}
}
+TEST_CASE(testThreadedIncrement)
+{
+ testThreadedIncrement_(testName);
+ testThreadedIncrement_(testName);
+ testThreadedIncrement_(testName);
+}
-class DecrementAtomicCounter : public sys::Runnable
+template
+struct DecrementAtomicCounterT final : public sys::Runnable
{
-public:
- DecrementAtomicCounter(size_t numDecrements,
- sys::AtomicCounter& ctr,
+ DecrementAtomicCounterT(size_t numDecrements,
+ TAtomicCounter& ctr,
ValueType* values) :
mNumDecrements(numDecrements),
mCtr(ctr),
@@ -187,19 +222,23 @@ class DecrementAtomicCounter : public sys::Runnable
private:
const size_t mNumDecrements;
- sys::AtomicCounter& mCtr;
+ TAtomicCounter& mCtr;
ValueType* const mValues;
};
-TEST_CASE(testThreadedDecrement)
+template
+static void testThreadedDecrement_(const std::string& testName)
{
+ using ValueType = typename TAtomicCounter::ValueType;
+ using DecrementAtomicCounter = DecrementAtomicCounterT;
+
const size_t numThreads = 13;
const size_t numDecrements = 1000;
std::vector values(numThreads * numDecrements);
std::vector valuesPtr(numThreads);
std::vector threads(numThreads);
- sys::AtomicCounter ctr(numThreads * numDecrements - 1);
+ TAtomicCounter ctr(numThreads * numDecrements - 1);
// Create all the threads
ValueType* ptr(&values[0]);
@@ -238,9 +277,15 @@ TEST_CASE(testThreadedDecrement)
std::sort(values.begin(), values.end());
for (size_t ii = 0; ii < values.size(); ++ii)
{
- TEST_ASSERT_EQ(values[ii], (sys::SSize_T)ii);
+ TEST_ASSERT_EQ(static_cast(values[ii]), static_cast(ii));
}
}
+TEST_CASE(testThreadedDecrement)
+{
+ testThreadedDecrement_(testName);
+ testThreadedDecrement_(testName);
+ testThreadedDecrement_(testName);
+}
}
int main(int, char**)
diff --git a/externals/coda-oss/modules/c++/sys/unittests/test_datetime.cpp b/externals/coda-oss/modules/c++/sys/unittests/test_datetime.cpp
index 8d2cdad54..c6c5e9443 100755
--- a/externals/coda-oss/modules/c++/sys/unittests/test_datetime.cpp
+++ b/externals/coda-oss/modules/c++/sys/unittests/test_datetime.cpp
@@ -157,12 +157,58 @@ TEST_CASE(testParameterizedConstructor)
TEST_ASSERT_EQ(u5.getSecond(), u4.getSecond());
}
+static void testDateTimeDetails_(const std::string& testName, const tm& result, const sys::DateTime& dt)
+{
+ const auto ad = result.tm_year + 1900; // "years since 1900"
+ // this might break in 2038: https://en.wikipedia.org/wiki/Year_2038_problem
+ TEST_ASSERT_GREATER_EQ(ad, 1900);
+ TEST_ASSERT_GREATER_EQ(ad, 1970);
+ TEST_ASSERT_GREATER_EQ(ad, 2021);
+ TEST_ASSERT_LESSER_EQ(result.tm_yday, 365); // "days since January 1"
+
+ TEST_ASSERT_EQ(ad, dt.getYear());
+ TEST_ASSERT_EQ(result.tm_yday + 1, dt.getDayOfYear());
+}
+TEST_CASE(testDateTimeDetails)
+{
+ const time_t now = time(nullptr);
+ {
+ tm local;
+ const auto result = sys::details::localtime_s(&local, &now);
+ TEST_ASSERT_EQ(0, result);
+ testDateTimeDetails_(testName, local, sys::LocalDateTime());
+ }
+ {
+ tm global;
+ const auto result = sys::details::gmtime_s(&global, &now);
+ TEST_ASSERT_EQ(0, result);
+ testDateTimeDetails_(testName, global, sys::UTCDateTime());
+ }
+}
+
+TEST_CASE(testGetTimeInMillis)
+{
+ const sys::LocalDateTime lt;
+ const auto result = lt.getTimeInMillis();
+ TEST_ASSERT_GREATER_EQ(result, 0.0);
+ constexpr auto February_02_2021 = 1612928129.0 * 1000.0; // in milliseconds
+ TEST_ASSERT_GREATER_EQ(result, February_02_2021);
+
+ constexpr auto recent_past = February_02_2021 * 0.999;
+ TEST_ASSERT_GREATER_EQ(result, recent_past);
+
+ constexpr auto far_into_the_future = February_02_2021 * 100.0;
+ TEST_ASSERT_LESSER_EQ(result, far_into_the_future);
+}
+
}
int main(int, char**)
{
TEST_CHECK(testDefaultConstructor);
TEST_CHECK(testParameterizedConstructor);
+ TEST_CHECK(testDateTimeDetails);
+ TEST_CHECK(testGetTimeInMillis);
return 0;
}
diff --git a/externals/coda-oss/modules/c++/sys/unittests/test_os.cpp b/externals/coda-oss/modules/c++/sys/unittests/test_os.cpp
index eac17d158..1583250ef 100644
--- a/externals/coda-oss/modules/c++/sys/unittests/test_os.cpp
+++ b/externals/coda-oss/modules/c++/sys/unittests/test_os.cpp
@@ -20,12 +20,17 @@
*
*/
+#include
+
#include
#include
+#include // std::accumulate
#include
#include
#include
+#include
+#include
#include "TestCase.h"
namespace
@@ -219,6 +224,59 @@ TEST_CASE(testFsOutput)
#endif
}
+static std::string f(bool& supported, std::vector& frames)
+{
+ return sys::getBacktrace(supported, frames);
+}
+static std::string g(bool& supported, std::vector& frames)
+{
+ return f(supported, frames);
+}
+static std::string h(bool& supported, std::vector& frames)
+{
+ return g(supported, frames);
+}
+TEST_CASE(testBacktrace)
+{
+ bool supported;
+ std::vector frames;
+ const auto result = h(supported, frames);
+ TEST_ASSERT_TRUE(!result.empty());
+
+ size_t frames_size = 0;
+ auto version_sys_backtrace_ = version::sys::backtrace; // "Conditional expression is constant"
+ if (version_sys_backtrace_ >= 20210216L)
+ {
+ TEST_ASSERT_TRUE(supported);
+
+ #if _WIN32
+ constexpr auto frames_size_RELEASE = 2;
+ constexpr auto frames_size_DEBUG = 13;
+ #elif defined(__GNUC__)
+ constexpr auto frames_size_RELEASE = 5;
+ constexpr auto frames_size_DEBUG = 9;
+ #else
+ #error "CODA_OSS_sys_Backtrace inconsistency."
+ #endif
+ frames_size = sys::debug_build ? frames_size_DEBUG : frames_size_RELEASE;
+ }
+ else
+ {
+ TEST_ASSERT_FALSE(supported);
+ }
+ TEST_ASSERT_EQ(frames.size(), frames_size);
+
+ const auto msg = std::accumulate(frames.begin(), frames.end(), std::string());
+ if (supported)
+ {
+ TEST_ASSERT_EQ(result, msg);
+ }
+ else
+ {
+ TEST_ASSERT_TRUE(msg.empty());
+ }
+}
+
}
int main(int, char**)
@@ -228,6 +286,7 @@ int main(int, char**)
TEST_CHECK(testEnvVariables);
TEST_CHECK(testFsExtension);
TEST_CHECK(testFsOutput);
+ TEST_CHECK(testBacktrace);
return 0;
}
diff --git a/externals/coda-oss/modules/c++/tiff/include/tiff/FileWriter.h b/externals/coda-oss/modules/c++/tiff/include/tiff/FileWriter.h
index 6276d81b7..fb495a676 100644
--- a/externals/coda-oss/modules/c++/tiff/include/tiff/FileWriter.h
+++ b/externals/coda-oss/modules/c++/tiff/include/tiff/FileWriter.h
@@ -41,10 +41,8 @@ namespace tiff
* to the same file. Contains function for manipulating each
* sub-image and for writing data.
*********************************************************************/
-class FileWriter
+struct FileWriter
{
-public:
-
//! Constructor
FileWriter() :
mIFDOffset(0)
@@ -116,11 +114,8 @@ class FileWriter
*****************************************************************/
void writeHeader();
-
-private:
- // Noncopyable
- FileWriter(const FileWriter& );
- const FileWriter& operator=(const FileWriter& );
+ FileWriter(const FileWriter&) = delete;
+ FileWriter& operator=(const FileWriter&) = delete;
private:
//! The position to write the offset to the first IFD to
diff --git a/externals/coda-oss/modules/c++/xml.lite/include/xml/lite/ContentHandler.h b/externals/coda-oss/modules/c++/xml.lite/include/xml/lite/ContentHandler.h
index ff72f6725..e086bc847 100644
--- a/externals/coda-oss/modules/c++/xml.lite/include/xml/lite/ContentHandler.h
+++ b/externals/coda-oss/modules/c++/xml.lite/include/xml/lite/ContentHandler.h
@@ -25,8 +25,13 @@
#pragma once
#include
+#include
#include
+#include
+
+#include "sys/CPlusPlus.h"
+
#include "xml/lite/Attributes.h"
/*!
@@ -39,6 +44,29 @@
* suit your needs.
*/
+// If `wchar_t` is built-in (as it should be), then `f(wchar_t)` can be overloaded
+// with `f(uint16_t)` and/or `f(uint32_t)`. If it is **not** (old "C++11" compilers)
+// then one of those overload attempts will fail.
+#ifndef CODA_OSS_wchar_t_is_type_
+ #if defined(_MSC_VER)
+ // https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-160
+ // "Defined as 1 when the /Zc:wchar_t compiler option is set. Otherwise, undefined."
+ #define CODA_OSS_wchar_t_is_type_ (_NATIVE_WCHAR_T_DEFINED == 1)
+ #else
+ #if CODA_OSS_cpp14
+ #define CODA_OSS_wchar_t_is_type_ 1
+ #else
+ // If your "wchar_t" isn't a distinct type, set this to 0.
+ // On old systems, it might be a typedef for uint16_t or uint32_t
+ //#define CODA_OSS_wchar_t_is_type_ 0
+ #define CODA_OSS_wchar_t_is_type_ 1
+ #endif // CODA_OSS_cpp14
+ #endif
+#endif
+// https://docs.microsoft.com/en-us/cpp/build/reference/zc-wchar-t-wchar-t-is-native-type?view=msvc-160
+// "... the C++ standard requires that wchar_t be a built-in type. "
+static_assert(CODA_OSS_wchar_t_is_type_, "wchar_t should be a built-in type.");
+
namespace xml
{
namespace lite
@@ -93,7 +121,13 @@ class ContentHandler
* \param length The length of the new data
*/
virtual void characters(const char *data, int length) = 0;
- virtual bool characters(const wchar_t* const /*data*/, const size_t /*length*/)
+ #if CODA_OSS_wchar_t_is_type_
+ virtual bool characters(const wchar_t* /*data*/, size_t /*length*/)
+ { return false; /* continue on to existing characters()*/ } /* =0 would break existing code */
+ #endif
+ virtual bool characters(const uint16_t* /*data*/, size_t /*length*/)
+ { return false; /* continue on to existing characters()*/ } /* =0 would break existing code */
+ virtual bool characters(const uint32_t* /*data*/, size_t /*length*/)
{ return false; /* continue on to existing characters()*/ } /* =0 would break existing code */
virtual bool use_wchar_t() const // =0 would break existing code
diff --git a/externals/coda-oss/modules/c++/xml.lite/include/xml/lite/MinidomHandler.h b/externals/coda-oss/modules/c++/xml.lite/include/xml/lite/MinidomHandler.h
index 2d8ffffd0..c1613e056 100644
--- a/externals/coda-oss/modules/c++/xml.lite/include/xml/lite/MinidomHandler.h
+++ b/externals/coda-oss/modules/c++/xml.lite/include/xml/lite/MinidomHandler.h
@@ -108,7 +108,11 @@ class MinidomHandler : public ContentHandler
* \param length The length of the char data
*/
virtual void characters(const char* value, int length) override;
- bool characters(const wchar_t* const value, const size_t length) override;
+ #if CODA_OSS_wchar_t_is_type_
+ bool characters(const wchar_t* value, size_t length) override;
+ #endif
+ bool characters(const uint16_t* /*data*/, size_t /*length*/) override;
+ bool characters(const uint32_t* /*data*/, size_t /*length*/) override;
// Which characters() routine should be called?
bool use_wchar_t() const override;
@@ -188,6 +192,11 @@ class MinidomHandler : public ContentHandler
bool mOwnDocument;
bool mPreserveCharData;
bool mStoreEncoding = false;
+
+ private:
+ template
+ bool characters_(const T* value, size_t length);
+ bool call_characters(const std::string& utf8Value);
};
}
}
diff --git a/externals/coda-oss/modules/c++/xml.lite/source/MinidomHandler.cpp b/externals/coda-oss/modules/c++/xml.lite/source/MinidomHandler.cpp
index 3d4b2d3a2..78478438b 100644
--- a/externals/coda-oss/modules/c++/xml.lite/source/MinidomHandler.cpp
+++ b/externals/coda-oss/modules/c++/xml.lite/source/MinidomHandler.cpp
@@ -21,6 +21,7 @@
*/
#include
+#include
#include "str/Manip.h"
#include "str/Convert.h"
@@ -87,22 +88,55 @@ void xml::lite::MinidomHandler::characters(const char *value, int length)
#endif
characters(value, length, pEncoding);
}
-bool xml::lite::MinidomHandler::characters(const wchar_t* const value_, const size_t length_)
+
+template
+inline std::string toUtf8_(const CharT* value, size_t length)
{
- #ifndef _WIN32
- // As on Windows, this comes to us already encoded ... but UTF-32
- const auto value = reinterpret_cast(value_);
- const std::u32string strValue(value, length_);
+ const std::basic_string strValue(value, length);
std::string utf8Value;
str::toUtf8(strValue, utf8Value);
+ return utf8Value;
+}
+inline std::string toUtf8(const uint16_t* value_, size_t length)
+{
+ const auto value = reinterpret_cast(value_);
+ return toUtf8_(value, length);
+}
+inline std::string toUtf8(const uint32_t* value_, size_t length)
+{
+ const auto value = reinterpret_cast(value_);
+ return toUtf8_(value, length);
+}
+#if CODA_OSS_wchar_t_is_type_
+inline std::string toUtf8(const wchar_t* value_, size_t length)
+{
+ using wchar_t_type = std::conditional::type;
+#ifdef _WIN32
+ // if we somehow get here on Windows (shouldn't, see below), wchar_t is UTF-16 not UTF-32
+ static_assert(sizeof(wchar_t) == sizeof(wchar_t_type), "wchar_t should be 16-bits on Windows.");
+#endif
+ const auto value = reinterpret_cast(value_);
+ return toUtf8(value, length);
+}
+#endif
+bool xml::lite::MinidomHandler::call_characters(const std::string& utf8Value)
+{
const auto length = static_cast(utf8Value.length());
- static const auto encoding = string_encoding::utf_8;
+ static const auto encoding = xml::lite::string_encoding::utf_8;
characters(utf8Value.c_str(), length, &encoding);
- return true; // all done, characters(char*) already called, above
+ return true; // all done, characters(char*) already called, above
+}
+
+template
+bool xml::lite::MinidomHandler::characters_(const T* value, size_t length)
+{
+ #ifndef _WIN32
+ const auto utf8Value = toUtf8(value, length);
+ return call_characters(utf8Value); // all done, characters(char*) already called, above
#else
- UNREFERENCED_PARAMETER(value_);
- UNREFERENCED_PARAMETER(length_);
+ UNREFERENCED_PARAMETER(value);
+ UNREFERENCED_PARAMETER(length);
// On Windows, we want std::string encoded as Windows-1252 (ISO8859-1)
// so that western European characters will be displayed. We can't convert
// to UTF-8 (as above on Linux), because Windows doesn't have good support
@@ -111,6 +145,20 @@ bool xml::lite::MinidomHandler::characters(const wchar_t* const value_, const si
return false; // call characters(char*) to get a Windows-1252 string
#endif
}
+#if CODA_OSS_wchar_t_is_type_
+bool xml::lite::MinidomHandler::characters(const wchar_t* value, size_t length)
+{
+ return characters_(value, length);
+}
+#endif
+bool xml::lite::MinidomHandler::characters(const uint32_t* value, size_t length)
+{
+ return characters_(value, length);
+}
+bool xml::lite::MinidomHandler::characters(const uint16_t* value, size_t length)
+{
+ return characters_(value, length);
+}
bool xml::lite::MinidomHandler::use_wchar_t() const
{
diff --git a/externals/coda-oss/modules/c++/zip/source/ZipFile.cpp b/externals/coda-oss/modules/c++/zip/source/ZipFile.cpp
index 50ca5fe24..1256d5cf4 100644
--- a/externals/coda-oss/modules/c++/zip/source/ZipFile.cpp
+++ b/externals/coda-oss/modules/c++/zip/source/ZipFile.cpp
@@ -121,10 +121,10 @@ void ZipFile::readCentralDir()
readCentralDirValues(eocd, (mCompressed + mCompressedLength) - eocd);
p = mCompressed + mCentralDirOffset;
- sys::SSize_T len = (mCompressed + mCompressedLength) - p;
- for (size_t i = 0; i < mEntries.size(); ++i)
+ const sys::SSize_T len = (mCompressed + mCompressedLength) - p;
+ for (auto& entry : mEntries)
{
- mEntries[i] = newCentralDirEntry(&p, len);
+ entry = newCentralDirEntry(&p, len);
}
}
diff --git a/externals/nitro/modules/c++/nitf/include/nitf/TRE.hpp b/externals/nitro/modules/c++/nitf/include/nitf/TRE.hpp
index 4f3fedd76..48d4dfaff 100644
--- a/externals/nitro/modules/c++/nitf/include/nitf/TRE.hpp
+++ b/externals/nitro/modules/c++/nitf/include/nitf/TRE.hpp
@@ -40,7 +40,7 @@ namespace nitf
* \class FieldIterator
* \brief The C++ wrapper for the nitf_TREEnumerator
*/
- struct TREFieldIterator /*final*/ : public nitf::Object // no "final", SWIG doesn't like it
+struct TREFieldIterator : public nitf::Object // no "final", SWIG doesn't like it
{
TREFieldIterator() noexcept(false)
{
diff --git a/externals/nitro/modules/c++/nitf/source/CompressionInterface.cpp b/externals/nitro/modules/c++/nitf/source/CompressionInterface.cpp
index 77a7bf056..18ef6b8ef 100644
--- a/externals/nitro/modules/c++/nitf/source/CompressionInterface.cpp
+++ b/externals/nitro/modules/c++/nitf/source/CompressionInterface.cpp
@@ -63,7 +63,7 @@ NITF_BOOL CompressionInterface::adapterStart(
NITF_BOOL CompressionInterface::adapterWriteBlock(
nitf_CompressionControl* object,
nitf_IOInterface* io,
- const std::byte* data,
+ const uint8_t* data,
NITF_BOOL pad,
NITF_BOOL noData,
nitf_Error* error)
@@ -97,6 +97,17 @@ NITF_BOOL CompressionInterface::adapterWriteBlock(
return NRT_FAILURE;
}
}
+NITF_BOOL CompressionInterface::adapterWriteBlock(
+ nitf_CompressionControl* object,
+ nitf_IOInterface* io,
+ const std::byte* data_,
+ NITF_BOOL pad,
+ NITF_BOOL noData,
+ nitf_Error* error)
+{
+ const auto data = reinterpret_cast(data_);
+ return adapterWriteBlock(object, io, data, pad, noData, error);
+}
NITF_BOOL CompressionInterface::adapterEnd(
nitf_CompressionControl* object,
diff --git a/externals/nitro/modules/c++/nitf/unittests/test_tre_read.cpp b/externals/nitro/modules/c++/nitf/unittests/test_tre_read.cpp
index 3ebab0798..939488334 100644
--- a/externals/nitro/modules/c++/nitf/unittests/test_tre_read.cpp
+++ b/externals/nitro/modules/c++/nitf/unittests/test_tre_read.cpp
@@ -90,23 +90,35 @@ const std::string output_file = "test_writer_3++.nitf";
namespace fs = std::filesystem;
static std::string argv0;
+
+static bool is_vs_gtest()
+{
+ return argv0.empty(); // no argv[0] in VS w/GTest
+}
+
static fs::path findInputFile(const std::string& name)
{
- const fs::path inputFile = fs::path("modules") / "c++" / "nitf" / "unittests" / name;
+ const auto inputFile = fs::path("modules") / "c++" / "nitf" / "unittests" / name;
- fs::path root;
- if (argv0.empty())
+ if (is_vs_gtest()) // running Google Test in Visual Studio
{
- // running in Visual Studio
- root = fs::current_path().parent_path().parent_path();
- }
- else
- {
- root = fs::absolute(argv0).parent_path().parent_path().parent_path().parent_path();
- root = root.parent_path().parent_path();
+ const auto root= fs::current_path().parent_path().parent_path();
+ return root / inputFile;
}
- return root / inputFile;
+ const auto exe = fs::absolute(argv0);
+ fs::path root = exe.parent_path();
+ do
+ {
+ auto retval = root / inputFile;
+ if (fs::exists(retval))
+ {
+ return retval;
+ }
+ root = root.parent_path();
+ } while (!root.empty());
+
+ return inputFile;
}
TEST_CASE(test_nitf_Record_unmergeTREs_crash)
diff --git a/externals/nitro/modules/c/CMakeLists.txt b/externals/nitro/modules/c/CMakeLists.txt
index b953c3431..15dc3dbbe 100644
--- a/externals/nitro/modules/c/CMakeLists.txt
+++ b/externals/nitro/modules/c/CMakeLists.txt
@@ -4,5 +4,9 @@ set(TARGET_LANGUAGE c)
add_subdirectory(nrt)
add_subdirectory(nitf)
add_subdirectory(cgm)
-add_subdirectory(j2k)
+
+if (ENABLE_J2K)
+ add_subdirectory(j2k)
+endif()
+
add_subdirectory(jpeg)
diff --git a/externals/nitro/modules/c/cgm/CMakeLists.txt b/externals/nitro/modules/c/cgm/CMakeLists.txt
index 2675a0dee..3a8e9674a 100644
--- a/externals/nitro/modules/c/cgm/CMakeLists.txt
+++ b/externals/nitro/modules/c/cgm/CMakeLists.txt
@@ -1,5 +1,12 @@
set(MODULE_NAME cgm)
+if (BUILD_SHARED)
+ set(BUILD_SHARED_LIBS ON)
+ add_definitions(
+ -DNITF_MODULE_EXPORTS
+ )
+endif()
+
coda_add_module(
${MODULE_NAME}
DEPS nitf-c
diff --git a/externals/nitro/modules/c/j2k/CMakeLists.txt b/externals/nitro/modules/c/j2k/CMakeLists.txt
index a0ab1bdf2..41d18abb7 100644
--- a/externals/nitro/modules/c/j2k/CMakeLists.txt
+++ b/externals/nitro/modules/c/j2k/CMakeLists.txt
@@ -4,6 +4,13 @@ if (TARGET openjpeg)
set(HAVE_OPENJPEG_H 1)
endif()
+if (BUILD_SHARED)
+ set(BUILD_SHARED_LIBS ON)
+ add_definitions(
+ -DJ2K_MODULE_EXPORTS
+ )
+endif()
+
coda_generate_module_config_header(${MODULE_NAME})
coda_add_module(
diff --git a/externals/nitro/modules/c/jpeg/CMakeLists.txt b/externals/nitro/modules/c/jpeg/CMakeLists.txt
index 830d184fc..cc493c80f 100644
--- a/externals/nitro/modules/c/jpeg/CMakeLists.txt
+++ b/externals/nitro/modules/c/jpeg/CMakeLists.txt
@@ -1,3 +1,11 @@
+
+if (BUILD_SHARED)
+ set(BUILD_SHARED_LIBS ON)
+ add_definitions(
+ -DNITF_MODULE_EXPORTS
+ )
+endif()
+
if (TARGET jpeg) # refers to libjpeg (external dependency)
coda_add_module(
jpeg # becomes jpeg-c (nitro module)
diff --git a/externals/nitro/modules/c/nitf/CMakeLists.txt b/externals/nitro/modules/c/nitf/CMakeLists.txt
index 8e8e1506a..ec5f6956c 100644
--- a/externals/nitro/modules/c/nitf/CMakeLists.txt
+++ b/externals/nitro/modules/c/nitf/CMakeLists.txt
@@ -2,6 +2,13 @@ set(MODULE_NAME nitf)
coda_generate_module_config_header(${MODULE_NAME})
+if (BUILD_SHARED)
+ set(BUILD_SHARED_LIBS ON)
+ add_definitions(
+ -DNITF_MODULE_EXPORTS
+ )
+endif()
+
coda_add_module(
${MODULE_NAME}
DEPS nrt-c
@@ -72,7 +79,8 @@ coda_add_tests(
test_image_io.c
test_mem_source.c
test_tre_mods.c
- test_zero_field.c)
+ test_zero_field.c
+ test_moveTREs.c)
# Build all the TRE
diff --git a/externals/nitro/modules/c/nitf/source/NitfWriter.c b/externals/nitro/modules/c/nitf/source/NitfWriter.c
index 5dc5d5ba2..b33e682a4 100644
--- a/externals/nitro/modules/c/nitf/source/NitfWriter.c
+++ b/externals/nitro/modules/c/nitf/source/NitfWriter.c
@@ -834,6 +834,13 @@ NITFAPI(NITF_BOOL) nitf_Writer_prepareIO(nitf_Writer* writer,
NITF_ERR_MEMORY);
return NITF_FAILURE;
}
+
+ /* first, set the writer to NULL */
+ for (i = 0; i < numImages; i++)
+ {
+ writer->imageWriters[i] = NULL;
+ }
+
writer->numImageWriters = numImages;
for (i = 0; i < numImages; i++)
{
@@ -842,9 +849,6 @@ NITFAPI(NITF_BOOL) nitf_Writer_prepareIO(nitf_Writer* writer,
uint32_t nbpp, nbands, xbands, nrows, ncols;
uint64_t length;
- /* first, set the writer to NULL */
- writer->imageWriters[i] = NULL;
-
/* guard against an overflowing data length */
iter = nitf_List_at(record->images, i);
segment = (nitf_ImageSegment*) nitf_ListIterator_get(&iter);
diff --git a/externals/nitro/modules/c/nitf/source/Record.c b/externals/nitro/modules/c/nitf/source/Record.c
index cce8ffa82..04967aa5b 100644
--- a/externals/nitro/modules/c/nitf/source/Record.c
+++ b/externals/nitro/modules/c/nitf/source/Record.c
@@ -20,6 +20,8 @@
*
*/
+#include
+
#include "nitf/Record.h"
/*
@@ -271,6 +273,7 @@ moveTREs(nitf_Extensions* source,
{
tre = nitf_ExtensionsIterator_get(&srcIter);
treLength = (uint32_t)tre->handler->getCurrentSize(tre, error);
+ treLength += NITF_ETAG_SZ + NITF_EL_SZ;
skipLeft -= treLength;
if (skipLeft < 1)
break;
@@ -2033,139 +2036,152 @@ nitf_Record_moveReservedExtensionSegment(nitf_Record* record,
* securityCls - security class field (i.e., imageSecurityClass)
* securityGrp - Security group object (i.e., securityGroup)
* idx - Index field (DE index in original segment) (i.e.,UDOFL)
- * typeStr - Type string (i.e.,UDID)
+ * segmentType - Type string (i.e.,UDID)
*/
-
-#define UNMERGE_SEGMENT(section, securityCls, securityGrp, idx, typeStr) \
- length = nitf_Extensions_computeLength(section, version, error); \
- if (length > maxLength) \
- { \
- if (!nitf_Field_get( \
- idx, &overflowIndex, NITF_CONV_INT, NITF_INT32_SZ, error)) \
- { \
- nitf_Error_init(error, \
- "Could not retrieve overflow segment index", \
- NITF_CTXT, \
- NITF_ERR_INVALID_OBJECT); \
- return NITF_FAILURE; \
- } \
- if (overflowIndex == 0) \
- { \
- overflowIndex = addOverflowSegment(record, \
- segIndex, \
- #typeStr, \
- securityCls, \
- securityGrp, \
- &overflow, \
- error); \
- if (overflowIndex == 0) \
- { \
- nitf_Error_init(error, \
- "Could not add overflow segment", \
- NITF_CTXT, \
- NITF_ERR_INVALID_OBJECT); \
- return NITF_FAILURE; \
- } \
- } \
- if ((overflow == NULL) || !moveTREs(section, \
- overflow->subheader->userDefinedSection, \
- maxLength, \
- error)) \
- { \
- nitf_Error_init(error, \
- "Could not transfer TREs to overflow segment", \
- NITF_CTXT, \
- NITF_ERR_INVALID_OBJECT); \
- return NITF_FAILURE; \
- } \
- if (!nitf_Field_setUint32(idx, overflowIndex, error)) \
- { \
- nitf_Error_init(error, \
- "Could not set overflow segment index", \
- NITF_CTXT, \
- NITF_ERR_INVALID_OBJECT); \
- return NITF_FAILURE; \
- } \
- }
-
-NITFAPI(NITF_BOOL)
-nitf_Record_unmergeTREs(nitf_Record* record, nitf_Error* error)
+NITFPRIV(NITF_BOOL) unmergeSegment(nitf_Version version, nitf_Record* record,
+ nitf_Extensions* section, nitf_Field* securityCls, nitf_FileSecurity* securityGrp, nitf_Field* idx, char* segmentType,
+ uint32_t maxLength, uint32_t segIndex, nitf_Error* error)
{
- /* NITF version */
- nitf_Version version;
+ assert(record != NULL);
+ assert(section != NULL);
- /* File header */
- nitf_FileHeader* header;
+ /* Overflow segment */
+ nitf_DESegment* overflow = NULL;
- /* Current segment list */
- nitf_ListIterator segIter;
+ /* Length of TREs in current section */
+ const uint32_t length = nitf_Extensions_computeLength(section,version,error);
+ if (length > maxLength)
+ {
+ /* Overflow index of current extension */
+ uint32_t overflowIndex;
+ if (!nitf_Field_get(idx, &overflowIndex,
+ NITF_CONV_INT,NITF_INT32_SZ, error))
+ {
+ nitf_Error_init(error, "Could not retrieve overflow segment index",
+ NITF_CTXT, NITF_ERR_INVALID_OBJECT);
+ return NITF_FAILURE;
+ }
+ if (overflowIndex == 0)
+ {
+ overflowIndex = addOverflowSegment(record, segIndex, segmentType,
+ securityCls, securityGrp, &overflow, error);
+ if (overflowIndex == 0)
+ {
+ nitf_Error_init(error, "Could not add overflow segment",
+ NITF_CTXT, NITF_ERR_INVALID_OBJECT);
+ return NITF_FAILURE;
+ }
- /* Current segment list end */
- nitf_ListIterator segEnd;
+ if (!nitf_Field_setUint32(idx, overflowIndex, error))
+ {
+ nitf_Error_init(error, "Could not set overflow segment index",
+ NITF_CTXT, NITF_ERR_INVALID_OBJECT);
+ return NITF_FAILURE;
+ }
+ }
+ else /* already tested for 0 above, wrap-around from -1 (below) isn't possible */
+ {
+ assert(overflowIndex > 0);
+ nitf_ListIterator iter = nitf_List_at(record->dataExtensions, overflowIndex - 1);
+ const nitf_ListIterator end = nitf_List_end(record->dataExtensions);
+ if (nitf_ListIterator_notEqualTo(&iter, &end))
+ {
+ overflow = (nitf_DESegment*)nitf_ListIterator_get(&iter);
+ }
+ }
- /* Current segment index */
- uint32_t segIndex;
+ if (overflow == NULL)
+ {
+ nitf_Error_init(error, "Invalid dataExtension segment number",
+ NITF_CTXT, NITF_ERR_INVALID_OBJECT);
+ return NITF_FAILURE;
+ }
- /* Length of TREs in current section */
- uint32_t length;
+ nitf_DESubheader* subheader = overflow->subheader;
+ if (subheader == NULL)
+ {
+ nitf_Error_init(error, "Invalid dataExtension segment number (overflow->subheader)",
+ NITF_CTXT, NITF_ERR_INVALID_OBJECT);
+ return NITF_FAILURE;
+ }
+ nitf_Extensions* userDefinedSection = subheader->userDefinedSection;
+ if (userDefinedSection == NULL)
+ {
+ nitf_Error_init(error, "Invalid dataExtension segment number (subheader->userDefinedSection)",
+ NITF_CTXT, NITF_ERR_INVALID_OBJECT);
+ return NITF_FAILURE;
+ }
+ if(!moveTREs(section, userDefinedSection, maxLength, error))
+ {
+ nitf_Error_init(error, "Could not transfer TREs to overflow segment",
+ NITF_CTXT, NITF_ERR_INVALID_OBJECT);
+ return NITF_FAILURE;
+ }
+ }
+ return NITF_SUCCESS;
+}
- /* Max length for this type of section */
- uint32_t maxLength;
+NITFAPI(NITF_BOOL)
+nitf_Record_unmergeTREs(nitf_Record* record, nitf_Error* error)
+{
+ /* check for NULL data */
+ if (record == NULL)
+ {
+ nitf_Error_init(error, "NULL data",
+ NITF_CTXT, NITF_ERR_INVALID_PARAMETER);
+ return NITF_FAILURE;
+ }
- /* Overflow index of current extension */
- uint32_t overflowIndex;
+ /* NITF version */
+ const nitf_Version version = nitf_Record_getVersion(record);
- /* Overflow segment */
- nitf_DESegment* overflow = NULL;
+ /* Max length for this type of section */
+ uint32_t maxLength = 99999;
- version = nitf_Record_getVersion(record);
+ /* Current segment index */
+ uint32_t segIndex = 1; /* ??? I moved this up so this would be initialized!! */
/* File header */
+ const nitf_FileHeader* header = record->header;
+ if (header != NULL)
+ {
+ unmergeSegment(version, record, header->userDefinedSection,
+ header->classification, header->securityGroup,
+ header->NITF_UDHOFL, "UDHD",
+ maxLength, segIndex, error);
- maxLength = 99999;
- segIndex = 1; /* ??? I moved this up so this would be initialized!! */
-
- header = record->header;
- UNMERGE_SEGMENT(header->userDefinedSection,
- header->classification,
- header->securityGroup,
- header->NITF_UDHOFL,
- UDHD);
-
- UNMERGE_SEGMENT(header->extendedSection,
- header->classification,
- header->securityGroup,
- header->NITF_XHDLOFL,
- XHD);
+ unmergeSegment(version, record, header->extendedSection,
+ header->classification, header->securityGroup,
+ header->NITF_XHDLOFL, "XHD",
+ maxLength, segIndex, error);
+ }
/* Image segments */
- segIter = nitf_List_begin(record->images);
- segEnd = nitf_List_end(record->images);
+ nitf_ListIterator segIter = nitf_List_begin(record->images);
+ nitf_ListIterator segEnd = nitf_List_end(record->images);
while (nitf_ListIterator_notEqualTo(&segIter, &segEnd))
{
- /* Current subheader */
- nitf_ImageSubheader* subheader;
-
maxLength = 99999;
-
- subheader =
+
+ /* Current subheader */
+ nitf_ImageSubheader* subheader =
(nitf_ImageSubheader*)((nitf_ImageSegment*)
nitf_ListIterator_get(&segIter))
->subheader;
-
- /* User defined section */
- UNMERGE_SEGMENT(subheader->userDefinedSection,
- subheader->imageSecurityClass,
- subheader->securityGroup,
- subheader->NITF_UDOFL,
- UDID);
-
- /* Extension section */
- UNMERGE_SEGMENT(subheader->extendedSection,
- subheader->imageSecurityClass,
- subheader->securityGroup,
- subheader->NITF_IXSOFL,
- IXSHD);
+ if (subheader != NULL)
+ {
+ /* User defined section */
+ unmergeSegment(version, record, subheader->userDefinedSection,
+ subheader->imageSecurityClass, subheader->securityGroup,
+ subheader->NITF_UDOFL, "UDID",
+ maxLength, segIndex, error);
+
+ /* Extension section */
+ unmergeSegment(version, record, subheader->extendedSection,
+ subheader->imageSecurityClass, subheader->securityGroup,
+ subheader->NITF_IXSOFL, "IXSHD",
+ maxLength, segIndex, error);
+ }
segIndex += 1;
nitf_ListIterator_increment(&segIter);
@@ -2178,23 +2194,22 @@ nitf_Record_unmergeTREs(nitf_Record* record, nitf_Error* error)
while (nitf_ListIterator_notEqualTo(&segIter, &segEnd))
{
- /* Current subheader */
- nitf_GraphicSubheader* subheader;
-
/* Hello, really? Somebody needs to fix hardcode DP */
maxLength = 9741;
- subheader = (nitf_GraphicSubheader*)((nitf_GraphicSegment*)
+ /* Current subheader */
+ nitf_GraphicSubheader* subheader = (nitf_GraphicSubheader*)((nitf_GraphicSegment*)
nitf_ListIterator_get(
&segIter))
->subheader;
-
- /* Extension section */
- UNMERGE_SEGMENT(subheader->extendedSection,
- subheader->securityClass,
- subheader->securityGroup,
- subheader->NITF_SXSOFL,
- SXSHD);
+ if (subheader != NULL)
+ {
+ /* Extension section */
+ unmergeSegment(version, record, subheader->extendedSection,
+ subheader->securityClass, subheader->securityGroup,
+ subheader->NITF_SXSOFL, "SXSHD",
+ maxLength, segIndex, error);
+ }
segIndex += 1;
nitf_ListIterator_increment(&segIter);
@@ -2207,24 +2222,22 @@ nitf_Record_unmergeTREs(nitf_Record* record, nitf_Error* error)
while (nitf_ListIterator_notEqualTo(&segIter, &segEnd))
{
- /* Current subheader */
- nitf_LabelSubheader* subheader;
-
/* Fix hardcode! */
maxLength = 9747;
- subheader =
+ /* Current subheader */
+ nitf_LabelSubheader* subheader =
(nitf_LabelSubheader*)((nitf_LabelSegment*)
nitf_ListIterator_get(&segIter))
->subheader;
-
- /* Extension section */
-
- UNMERGE_SEGMENT(subheader->extendedSection,
- subheader->securityClass,
- subheader->securityGroup,
- subheader->NITF_LXSOFL,
- LXSHD);
+ if (subheader != NULL)
+ {
+ /* Extension section */
+ unmergeSegment(version, record, subheader->extendedSection,
+ subheader->securityClass, subheader->securityGroup,
+ subheader->NITF_LXSOFL, "LXSHD",
+ maxLength, segIndex, error);
+ }
segIndex += 1;
nitf_ListIterator_increment(&segIter);
@@ -2237,23 +2250,22 @@ nitf_Record_unmergeTREs(nitf_Record* record, nitf_Error* error)
while (nitf_ListIterator_notEqualTo(&segIter, &segEnd))
{
- /* Current subheader */
- nitf_TextSubheader* subheader;
-
/* Fix hardcode! */
maxLength = 9717;
- subheader =
+ /* Current subheader */
+ nitf_TextSubheader* subheader =
(nitf_TextSubheader*)((nitf_TextSegment*)nitf_ListIterator_get(
&segIter))
->subheader;
-
- /* Extension section */
- UNMERGE_SEGMENT(subheader->extendedSection,
- subheader->securityClass,
- subheader->securityGroup,
- subheader->NITF_TXSOFL,
- TXSHD);
+ if (subheader != NULL)
+ {
+ /* Extension section */
+ unmergeSegment(version, record, subheader->extendedSection,
+ subheader->securityClass, subheader->securityGroup,
+ subheader->NITF_TXSOFL, "TXSHD",
+ maxLength, segIndex, error);
+ }
segIndex += 1;
nitf_ListIterator_increment(&segIter);
@@ -2306,8 +2318,7 @@ NITFAPI(NITF_BOOL) nitf_Record_mergeTREs(nitf_Record* record, nitf_Error* error)
NITF_DESTAG_SZ + 1,
error))
{
- nitf_Error_init(error,
- "Could not retrieve DE segment id",
+ nitf_Error_init(error, "Could not retrieve DE segment id",
NITF_CTXT,
NITF_ERR_INVALID_OBJECT);
return NITF_FAILURE;
@@ -2334,9 +2345,7 @@ NITFAPI(NITF_BOOL) nitf_Record_mergeTREs(nitf_Record* record, nitf_Error* error)
error);
if (eflag)
{
- nitf_Error_init(
- error,
- "Could not retrieve DE segment header overflow value",
+ nitf_Error_init(error, "Could not retrieve DE segment header overflow value",
NITF_CTXT,
NITF_ERR_INVALID_OBJECT);
return NITF_FAILURE;
diff --git a/externals/nitro/modules/c/nitf/unittests/test_moveTREs.c b/externals/nitro/modules/c/nitf/unittests/test_moveTREs.c
new file mode 100644
index 000000000..3df64f2ac
--- /dev/null
+++ b/externals/nitro/modules/c/nitf/unittests/test_moveTREs.c
@@ -0,0 +1,129 @@
+/* =========================================================================
+ * This file is part of NITRO
+ * =========================================================================
+ *
+ * (C) Copyright 2004 - 2014, MDA Information Systems LLC
+ *
+ * NITRO is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, If not,
+ * see .
+ *
+ */
+
+
+/**
+ * This test serves as an example to show how one can construct and write
+ * a NITF from scratch.
+ */
+
+
+#include
+#include "Test.h"
+
+static const char* const DATE_TIME = "20120126000000";
+
+static
+NITF_BOOL insertTRE(nitf_Extensions* ext, nitf_Error* error)
+{
+ char buffer[1024];
+
+ memset(buffer, 0, 1024);
+ nitf_TRE* tre = nitf_TRE_construct("MTXFIL", "MTXFIL", error);
+
+ nitf_TRE_setField(tre, "raw_data", (NITF_DATA*)buffer, 1024, error);
+ if (!nitf_Extensions_appendTRE(ext, tre, error))
+ return NITF_FAILURE;
+
+ return NITF_SUCCESS;
+}
+
+static
+NITF_BOOL initializeTREs(nitf_FileHeader* header, nitf_Error* error)
+{
+ int i = 0;
+ char buffer[1024];
+
+ memset(buffer, 0, 1024);
+
+ /* Create a large number of TREs that will force a TRE_OVERFLOW DES */
+ for (i = 0; i < 100; ++i)
+ {
+ insertTRE(header->extendedSection, error);
+ }
+
+ return NITF_SUCCESS;
+}
+
+static
+NITF_BOOL initializeHeader(nitf_FileHeader* header, nitf_Error* error)
+{
+ return (nitf_Field_setString(header->fileHeader, "NITF", error) &&
+ nitf_Field_setString(header->fileVersion, "02.10", error) &&
+ nitf_Field_setUint32(header->complianceLevel, 3, error) &&
+ nitf_Field_setString(header->systemType, "BF01", error) &&
+ nitf_Field_setString(header->originStationID, "mdaus", error) &&
+ nitf_Field_setString(header->fileDateTime, DATE_TIME, error) &&
+ nitf_Field_setString(header->fileTitle, "TRE Overflow Test", error) &&
+ nitf_Field_setString(header->classification, "U", error) &&
+ nitf_Field_setUint32(header->encrypted, 0, error) &&
+ initializeTREs(header, error));
+}
+
+
+NITF_BOOL unmergeTREs(nitf_Record *record, nitf_Error *error)
+{
+ if (!nitf_Record_unmergeTREs(record, error))
+ goto CATCH_ERROR;
+
+ return NITF_SUCCESS;
+
+ CATCH_ERROR:
+ return NITF_FAILURE;
+}
+
+
+TEST_CASE_ARGS(testUnmerge)
+{
+ nitf_Version version = NITF_VER_21;
+ nitf_Record *record = NULL;
+ nitf_Error error;
+ nitf_Uint32 treSize;
+
+ TEST_ASSERT((record = nitf_Record_construct(version, &error)));
+ TEST_ASSERT(initializeHeader(record->header, &error));
+
+ TEST_ASSERT(unmergeTREs(record, &error));
+
+ /* Extension Segment should be less then 99999 now after the unmerge */
+ treSize = nitf_Extensions_computeLength(record->header->extendedSection, version, &error);
+ TEST_ASSERT(treSize < 99999);
+
+ /* Add another TRE */
+ TEST_ASSERT(insertTRE(record->header->extendedSection, &error));
+
+ /* Unmerge again, this should move the new TRE to the existing TRE_OVERFLOW */
+ TEST_ASSERT(unmergeTREs(record, &error));
+
+ treSize = nitf_Extensions_computeLength(record->header->extendedSection, version, &error);
+ TEST_ASSERT(treSize < 99999);
+
+
+ nitf_Record_destruct(&record);
+}
+
+int main(int argc, char **argv)
+{
+ CHECK_ARGS(testUnmerge);
+ return 0;
+}
+
diff --git a/externals/nitro/modules/c/nrt/CMakeLists.txt b/externals/nitro/modules/c/nrt/CMakeLists.txt
index 6470aedca..9f6598342 100644
--- a/externals/nitro/modules/c/nrt/CMakeLists.txt
+++ b/externals/nitro/modules/c/nrt/CMakeLists.txt
@@ -2,6 +2,13 @@ set(MODULE_NAME nrt)
coda_generate_module_config_header(${MODULE_NAME})
+if (BUILD_SHARED)
+ set(BUILD_SHARED_LIBS ON)
+ add_definitions(
+ -DNRT_MODULE_EXPORTS
+ )
+endif()
+
coda_add_module(
${MODULE_NAME}
DEPS ${CMAKE_DL_LIBS} config-c++