<commit_before>/*
* Copyright(c) Sophist Solutions, Inc. 1990-2018.  All rights reserved
*/
#include "../../StroikaPreComp.h"

#include "../../Characters/Format.h"
#include "../../Characters/ToString.h"
#include "../../IO/FileAccessException.h"

#include "Socket-Private_.h"

#include "Socket.h"

// Comment this in to turn on aggressive noisy DbgTrace in this module
//#define   USE_NOISY_TRACE_IN_THIS_MODULE_       1

using namespace Stroika::Foundation;
using namespace Stroika::Foundation::Characters;
using namespace Stroika::Foundation::Execution;
using namespace Stroika::Foundation::Memory;
using namespace Stroika::Foundation::IO;
using namespace Stroika::Foundation::IO::Network;

using namespace Stroika::Foundation::IO::Network::PRIVATE_;

/*
* Notes:
*      http://stackoverflow.com/questions/2693709/what-was-the-motivation-for-adding-the-ipv6-v6only-flag
*  Windows:
*      https://msdn.microsoft.com/en-us/library/windows/desktop/bb513665(v=vs.85).aspx
*      Windows Vista and later only
*
*  not sure how to handle this best cuz not every OS will support dual-stack (or will it?)
*
*  So assume no duel sockets. That seems best --LGP 2017-04-24
*/
namespace {
    constexpr bool kUseDualStackSockets_ = false; // opposite of IPV6_V6ONLY
}

/*
 ********************************************************************************
 ******************************** Network::Socket *******************************
 ********************************************************************************
 */
Socket::PlatformNativeHandle Socket::mkLowLevelSocket_ (SocketAddress::FamilyType family, Socket::Type socketKind, const Optional<IPPROTO>& protocol)
{
#if qPlatform_Windows
    IO::Network::Platform::Windows::WinSock::AssureStarted ();
#endif
    Socket::PlatformNativeHandle sfd;
#if qPlatform_POSIX
    ThrowErrNoIfNegative (sfd = Handle_ErrNoResultInterruption ([=]() -> int { return socket (static_cast<int> (family), static_cast<int> (socketKind), static_cast<int> (protocol.Value ())); }));
#elif qPlatform_Windows
    DISABLE_COMPILER_MSC_WARNING_START (28193) // dump warning about examining sfd
    ThrowErrNoIfNegative<Socket::PlatformNativeHandle> (sfd = ::socket (static_cast<int> (family), static_cast<int> (socketKind), static_cast<int> (protocol.Value ())));
    DISABLE_COMPILER_MSC_WARNING_END (28193)
#else
    AssertNotImplemented ();
#endif
    if (family == SocketAddress::FamilyType::INET6) {
        int useIPV6Only = not kUseDualStackSockets_;
#if qPlatform_Linux
        // Linux follows the RFC, and uses dual-stack mode by default
        constexpr bool kOSDefaultIPV6Only_{false};
        bool           mustSet = useIPV6Only != kOSDefaultIPV6Only_;
#elif qPlatfom_Windows
        // Windows defaults to NOT dual sockets, so nothing todo for windows
        constexpr bool kOSDefaultIPV6Only_{true};
        bool           mustSet = useIPV6Only != kOSDefaultIPV6Only_;
#else
        bool mustSet = true;
#endif
        if (mustSet) {
            if (::setsockopt (sfd, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<const char*> (&useIPV6Only), sizeof (useIPV6Only)) < 0) {
                AssertNotReached ();
            }
        }
    }
    return sfd;
}

/*
 ********************************************************************************
 ***************************** Network::Socket::Ptr *****************************
 ********************************************************************************
 */
Socket::PlatformNativeHandle Socket::Ptr::Detach ()
{
    lock_guard<const AssertExternallySynchronizedLock> critSec{*this};
    PlatformNativeHandle                               h = kINVALID_NATIVE_HANDLE_;
    if (fRep_ != nullptr) {
        h = fRep_->Detach ();
    }
    fRep_.reset ();
    return h;
}

Socket::Type Socket::Ptr::GetType () const
{
    shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
    return getsockopt<Type> (SOL_SOCKET, SO_TYPE);
}

void Socket::Ptr::Bind (const SocketAddress& sockAddr, BindFlags bindFlags)
{
    Debug::TraceContextBumper                          ctx{Stroika_Foundation_Debug_OptionalizeTraceArgs (L"IO::Network::Socket::Bind", L"sockAddr=%s bindFlags.fReUseAddr=%s", Characters::ToString (sockAddr).c_str (), Characters::ToString (bindFlags.fReUseAddr).c_str ())};
    lock_guard<const AssertExternallySynchronizedLock> critSec{*this};
    RequireNotNull (fRep_); // Construct with Socket::Kind::SOCKET_STREAM?

    // Indicates that the rules used in validating addresses supplied in a bind(2) call should allow
    // reuse of local addresses. For AF_INET sockets this means that a socket may bind, except when
    // there is an active listening socket bound to the address. When the listening socket is bound
    // to INADDR_ANY with a specific port then it is not possible to bind to this port for any local address.
    setsockopt<int> (SOL_SOCKET, SO_REUSEADDR, bindFlags.fReUseAddr ? 1 : 0);

    sockaddr_storage     useSockAddr = sockAddr.As<sockaddr_storage> ();
    PlatformNativeHandle sfd         = fRep_->GetNativeSocket ();
#if qPlatform_Windows
    try {
        ThrowErrNoIfNegative<Socket::PlatformNativeHandle> (::bind (sfd, (sockaddr*)&useSockAddr, sizeof (useSockAddr)));
    }
    catch (const Execution::Platform::Windows::Exception& e) {
        if (e == WSAEACCES) {
            Throw (StringException (Characters::Format (L"Cannot Bind to port %d: WSAEACCES (probably already bound with SO_EXCLUSIVEADDRUSE)", (int)sockAddr.GetPort ())));
        }
    }
#else
    // EACCESS reproted as FileAccessException - which is crazy confusing.
    // @todo - find a better way, but for now remap this...
    try {
        ThrowErrNoIfNegative (Handle_ErrNoResultInterruption ([&sfd, &useSockAddr]() -> int { return ::bind (sfd, (sockaddr*)&useSockAddr, sizeof (useSockAddr)); }));
    }
    catch (const IO::FileAccessException&) {
        Throw (StringException (Characters::Format (L"Cannot Bind to port %d: EACCESS (probably already bound with SO_EXCLUSIVEADDRUSE)", (int)sockAddr.GetPort ())));
    }
#endif
    catch (...) {
        Throw (StringException (Characters::Format (L"Cannot Bind to port %d: %s", (int)sockAddr.GetPort (), Characters::ToString (current_exception ()).c_str ())));
    }
}

bool Socket::Ptr::IsOpen () const
{
    shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
    if (fRep_ != nullptr) {
        return fRep_->GetNativeSocket () != kINVALID_NATIVE_HANDLE_;
    }
    return false;
}

String Socket::Ptr::ToString () const
{
    shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
    StringBuilder                                       sb;
    if (fRep_ == nullptr) {
        sb += L"nullptr";
    }
    else {
        sb += L"{";
        sb += L"Native-Socket: " + ((fRep_->GetNativeSocket () == kINVALID_NATIVE_HANDLE_) ? L"CLOSED" : Characters::ToString (fRep_->GetNativeSocket ())) + L", ";
        if (auto ola = GetLocalAddress ()) {
            sb += L"Local-Address: " + Characters::ToString (*ola);
        }
        sb += L"}";
    }
    return sb.str ();
}

/*
 ********************************************************************************
 ******************** Execution::ThrowErrNoIfNegative ***************************
 ********************************************************************************
 */
#if qPlatform_Windows
namespace Stroika {
    namespace Foundation {
        namespace Execution {
            // this specialization needed because the winsock type for SOCKET is UNSIGNED so < 0 test doesn't work
            template <>
            IO::Network::Socket::PlatformNativeHandle ThrowErrNoIfNegative (IO::Network::Socket::PlatformNativeHandle returnCode)
            {
                if (returnCode == kINVALID_NATIVE_HANDLE_) {
                    Execution::Platform::Windows::Exception::Throw (::WSAGetLastError ());
                }
                return returnCode;
            }
        }
    }
}
#endif
<commit_msg>cosmetic<commit_after>/*
* Copyright(c) Sophist Solutions, Inc. 1990-2018.  All rights reserved
*/
#include "../../StroikaPreComp.h"

#include "../../Characters/Format.h"
#include "../../Characters/ToString.h"
#include "../../IO/FileAccessException.h"

#include "Socket-Private_.h"

#include "Socket.h"

// Comment this in to turn on aggressive noisy DbgTrace in this module
//#define   USE_NOISY_TRACE_IN_THIS_MODULE_       1

using namespace Stroika::Foundation;
using namespace Stroika::Foundation::Characters;
using namespace Stroika::Foundation::Execution;
using namespace Stroika::Foundation::Memory;
using namespace Stroika::Foundation::IO;
using namespace Stroika::Foundation::IO::Network;

using namespace Stroika::Foundation::IO::Network::PRIVATE_;

/*
 * Notes:
 *      http://stackoverflow.com/questions/2693709/what-was-the-motivation-for-adding-the-ipv6-v6only-flag
 *  Windows:
 *      https://msdn.microsoft.com/en-us/library/windows/desktop/bb513665(v=vs.85).aspx
 *      Windows Vista and later only
 *
 *  not sure how to handle this best cuz not every OS will support dual-stack (or will it?)
 *
 *  So assume no dual-stack sockets. That seems best --LGP 2017-04-24
 */
namespace {
    constexpr bool kUseDualStackSockets_ = false; // opposite of IPV6_V6ONLY
}

/*
 ********************************************************************************
 ******************************** Network::Socket *******************************
 ********************************************************************************
 */
Socket::PlatformNativeHandle Socket::mkLowLevelSocket_ (SocketAddress::FamilyType family, Socket::Type socketKind, const Optional<IPPROTO>& protocol)
{
#if qPlatform_Windows
    IO::Network::Platform::Windows::WinSock::AssureStarted ();
#endif
    Socket::PlatformNativeHandle sfd;
#if qPlatform_POSIX
    ThrowErrNoIfNegative (sfd = Handle_ErrNoResultInterruption ([=]() -> int { return socket (static_cast<int> (family), static_cast<int> (socketKind), static_cast<int> (protocol.Value ())); }));
#elif qPlatform_Windows
    DISABLE_COMPILER_MSC_WARNING_START (28193) // dump warning about examining sfd
    ThrowErrNoIfNegative<Socket::PlatformNativeHandle> (sfd = ::socket (static_cast<int> (family), static_cast<int> (socketKind), static_cast<int> (protocol.Value ())));
    DISABLE_COMPILER_MSC_WARNING_END (28193)
#else
    AssertNotImplemented ();
#endif
    if (family == SocketAddress::FamilyType::INET6) {
        int useIPV6Only = not kUseDualStackSockets_;
#if qPlatform_Linux
        // Linux follows the RFC, and uses dual-stack mode by default
        constexpr bool kOSDefaultIPV6Only_{false};
        bool           mustSet = useIPV6Only != kOSDefaultIPV6Only_;
#elif qPlatfom_Windows
        // Windows defaults to NOT dual sockets, so nothing todo for windows
        constexpr bool kOSDefaultIPV6Only_{true};
        bool           mustSet = useIPV6Only != kOSDefaultIPV6Only_;
#else
        bool mustSet = true;
#endif
        if (mustSet) {
            if (::setsockopt (sfd, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<const char*> (&useIPV6Only), sizeof (useIPV6Only)) < 0) {
                AssertNotReached ();
            }
        }
    }
    return sfd;
}

/*
 ********************************************************************************
 ***************************** Network::Socket::Ptr *****************************
 ********************************************************************************
 */
Socket::PlatformNativeHandle Socket::Ptr::Detach ()
{
    lock_guard<const AssertExternallySynchronizedLock> critSec{*this};
    PlatformNativeHandle                               h = kINVALID_NATIVE_HANDLE_;
    if (fRep_ != nullptr) {
        h = fRep_->Detach ();
    }
    fRep_.reset ();
    return h;
}

Socket::Type Socket::Ptr::GetType () const
{
    shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
    return getsockopt<Type> (SOL_SOCKET, SO_TYPE);
}

void Socket::Ptr::Bind (const SocketAddress& sockAddr, BindFlags bindFlags)
{
    Debug::TraceContextBumper                          ctx{Stroika_Foundation_Debug_OptionalizeTraceArgs (L"IO::Network::Socket::Bind", L"sockAddr=%s bindFlags.fReUseAddr=%s", Characters::ToString (sockAddr).c_str (), Characters::ToString (bindFlags.fReUseAddr).c_str ())};
    lock_guard<const AssertExternallySynchronizedLock> critSec{*this};
    RequireNotNull (fRep_); // Construct with Socket::Kind::SOCKET_STREAM?

    // Indicates that the rules used in validating addresses supplied in a bind(2) call should allow
    // reuse of local addresses. For AF_INET sockets this means that a socket may bind, except when
    // there is an active listening socket bound to the address. When the listening socket is bound
    // to INADDR_ANY with a specific port then it is not possible to bind to this port for any local address.
    setsockopt<int> (SOL_SOCKET, SO_REUSEADDR, bindFlags.fReUseAddr ? 1 : 0);

    sockaddr_storage     useSockAddr = sockAddr.As<sockaddr_storage> ();
    PlatformNativeHandle sfd         = fRep_->GetNativeSocket ();
#if qPlatform_Windows
    try {
        ThrowErrNoIfNegative<Socket::PlatformNativeHandle> (::bind (sfd, (sockaddr*)&useSockAddr, sizeof (useSockAddr)));
    }
    catch (const Execution::Platform::Windows::Exception& e) {
        if (e == WSAEACCES) {
            Throw (StringException (Characters::Format (L"Cannot Bind to port %d: WSAEACCES (probably already bound with SO_EXCLUSIVEADDRUSE)", (int)sockAddr.GetPort ())));
        }
    }
#else
    // EACCESS reproted as FileAccessException - which is crazy confusing.
    // @todo - find a better way, but for now remap this...
    try {
        ThrowErrNoIfNegative (Handle_ErrNoResultInterruption ([&sfd, &useSockAddr]() -> int { return ::bind (sfd, (sockaddr*)&useSockAddr, sizeof (useSockAddr)); }));
    }
    catch (const IO::FileAccessException&) {
        Throw (StringException (Characters::Format (L"Cannot Bind to port %d: EACCESS (probably already bound with SO_EXCLUSIVEADDRUSE)", (int)sockAddr.GetPort ())));
    }
#endif
    catch (...) {
        Throw (StringException (Characters::Format (L"Cannot Bind to port %d: %s", (int)sockAddr.GetPort (), Characters::ToString (current_exception ()).c_str ())));
    }
}

bool Socket::Ptr::IsOpen () const
{
    shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
    if (fRep_ != nullptr) {
        return fRep_->GetNativeSocket () != kINVALID_NATIVE_HANDLE_;
    }
    return false;
}

String Socket::Ptr::ToString () const
{
    shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
    StringBuilder                                       sb;
    if (fRep_ == nullptr) {
        sb += L"nullptr";
    }
    else {
        sb += L"{";
        sb += L"Native-Socket: " + ((fRep_->GetNativeSocket () == kINVALID_NATIVE_HANDLE_) ? L"CLOSED" : Characters::ToString (fRep_->GetNativeSocket ())) + L", ";
        if (auto ola = GetLocalAddress ()) {
            sb += L"Local-Address: " + Characters::ToString (*ola);
        }
        sb += L"}";
    }
    return sb.str ();
}

/*
 ********************************************************************************
 ******************** Execution::ThrowErrNoIfNegative ***************************
 ********************************************************************************
 */
#if qPlatform_Windows
namespace Stroika {
    namespace Foundation {
        namespace Execution {
            // this specialization needed because the winsock type for SOCKET is UNSIGNED so < 0 test doesn't work
            template <>
            IO::Network::Socket::PlatformNativeHandle ThrowErrNoIfNegative (IO::Network::Socket::PlatformNativeHandle returnCode)
            {
                if (returnCode == kINVALID_NATIVE_HANDLE_) {
                    Execution::Platform::Windows::Exception::Throw (::WSAGetLastError ());
                }
                return returnCode;
            }
        }
    }
}
#endif
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include <iostream>
#include <fstream>
#include "itkHDF5TransformIOFactory.h"
#include "itkTransformFileWriter.h"
#include "itkTransformFileReader.h"
#include "itkAffineTransform.h"
#include "itkTransformFactory.h"
#include "itkSimilarity2DTransform.h"
#include "itkBSplineTransform.h"
#include "itksys/SystemTools.hxx"

//Transforms from Filtering/DisplacementField/include
#include "itkBSplineExponentialDiffeomorphicTransform.h"
#include "itkBSplineSmoothingOnUpdateDisplacementFieldTransform.h"
#include "itkConstantVelocityFieldTransform.h"
#include "itkDisplacementFieldTransform.h"
#include "itkGaussianExponentialDiffeomorphicTransform.h"
#include "itkGaussianSmoothingOnUpdateDisplacementFieldTransform.h"

template < typename ScalarType, typename DisplacementTransformType >
static int ReadWriteTest(const char * const fileName)
{
  // Now test reading/writing many different transform types.
  typename itk::TransformFileReaderTemplate<ScalarType>::Pointer
    reader = itk::TransformFileReaderTemplate<ScalarType>::New();

  typename itk::TransformFileWriterTemplate<ScalarType>::Pointer
    writer = itk::TransformFileWriterTemplate<ScalarType>::New();

  writer->SetFileName( fileName );
  reader->SetFileName( fileName );

  typename DisplacementTransformType::Pointer displacementTransform = DisplacementTransformType::New();
    {
    typedef typename DisplacementTransformType::DisplacementFieldType FieldType;
    typename FieldType::Pointer field = FieldType::New(); //This is based on itk::Image

    const int dimLength = 20;
    typename FieldType::SizeType size;
    size.Fill( dimLength );
    typename FieldType::IndexType start;
    start.Fill( 0 );
    typename FieldType::RegionType region;
    region.SetSize( size );
    region.SetIndex( start );
    field->SetRegions( region );
    typename FieldType::SpacingType spacing;
    spacing.Fill( 1.2 );
    field->SetSpacing( spacing );
    field->Allocate();

    typename DisplacementTransformType::OutputVectorType zeroVector;
    zeroVector.Fill( 0 );
    field->FillBuffer( zeroVector );

    displacementTransform->SetDisplacementField( field );
    }

  try
    {
    writer->AddTransform( displacementTransform );
    writer->Update();
    //std::cout << std::endl;
    //std::cout << "Testing read : " << std::endl;
    reader->Update();
    }
  catch( itk::ExceptionObject & excp )
    {
    std::cerr << "Error while saving the transforms" << std::endl;
    std::cerr << excp << std::endl;
    std::cout << "[FAILED]" << std::endl;
    return EXIT_FAILURE;
    }
  return EXIT_SUCCESS;
}

template<typename ScalarType>
static int oneTest(const char *const goodname,const char *const badname)
{
  typedef typename itk::AffineTransform<ScalarType,4>  AffineTransformType;
  typedef typename itk::AffineTransform<ScalarType,10> AffineTransformTypeNotRegistered;
  typename AffineTransformType::Pointer        affine = AffineTransformType::New();

  itk::ObjectFactoryBase::RegisterFactory(itk::HDF5TransformIOFactory::New() );

  // Set it's parameters
  typename AffineTransformType::ParametersType p = affine->GetParameters();
  for ( unsigned int i = 0; i < p.GetSize(); i++ )
    {
    p[i] = i;
    }
  affine->SetParameters ( p );
  p = affine->GetFixedParameters ();
  for ( unsigned int i = 0; i < p.GetSize(); i++ )
    {
    p[i] = i;
    }
  affine->SetFixedParameters ( p );
  typename itk::TransformFileWriterTemplate<ScalarType>::Pointer
    writer = itk::TransformFileWriterTemplate<ScalarType>::New();
  typename itk::TransformFileReaderTemplate<ScalarType>::Pointer
    reader = itk::TransformFileReaderTemplate<ScalarType>::New();

  writer->AddTransform(affine);

  writer->SetFileName( goodname );
  reader->SetFileName( goodname );

  // Testing writing std::cout << "Testing write : ";
  affine->Print ( std::cout );
  try
    {
    writer->Update();
    std::cout << std::endl;
    std::cout << "Testing read : " << std::endl;
    reader->Update();
    }
  catch( itk::ExceptionObject & excp )
    {
    std::cerr << "Error while saving the transforms" << std::endl;
    std::cerr << excp << std::endl;
    std::cout << "[FAILED]" << std::endl;
    return EXIT_FAILURE;
    }

  try
    {
    typename itk::TransformFileReaderTemplate<ScalarType>::TransformListType * list = reader->GetTransformList();
    typename itk::TransformFileReaderTemplate<ScalarType>::TransformListType::iterator lit = list->begin();
    while ( lit != list->end() )
      {
      (*lit)->Print ( std::cout );
      ++lit;
      }
    }
  catch( itk::ExceptionObject & excp )
    {
    std::cerr << "Error while saving the transforms" << std::endl;
    std::cerr << excp << std::endl;
    std::cout << "[FAILED]" << std::endl;
    return EXIT_FAILURE;
    }

  std::cout << "Creating bad writer" << std::endl;
  typename AffineTransformTypeNotRegistered::Pointer Bogus = AffineTransformTypeNotRegistered::New();

  // Set it's parameters
  p = Bogus->GetParameters();
  for ( unsigned int i = 0; i < p.GetSize(); i++ )
    {
    p[i] = i;
    }
  Bogus->SetParameters ( p );
  p = Bogus->GetFixedParameters ();
  for ( unsigned int i = 0; i < p.GetSize(); i++ )
    {
    p[i] = i;
    }
  Bogus->SetFixedParameters ( p );

  typename itk::TransformFileWriterTemplate<ScalarType>::Pointer
    badwriter = itk::TransformFileWriterTemplate<ScalarType>::New();
  typename itk::TransformFileReaderTemplate<ScalarType>::Pointer
    badreader = itk::TransformFileReaderTemplate<ScalarType>::New();
  badwriter->AddTransform(Bogus);
  badwriter->SetFileName(badname);
  badreader->SetFileName(badname);

  // Testing writing
  std::cout << "Testing write of non register transform : " << std::endl;
  std::cout << std::flush;
  try
    {
    badwriter->Update();
    }
  catch( itk::ExceptionObject & excp )
    {
    std::cerr << "Error while saving the transforms" << std::endl;
    std::cerr << excp << std::endl;
    std::cout << "[FAILED]" << std::endl;
    return EXIT_FAILURE;
    }

  // Testing writing
  std::cout << "Testing read of non register transform : " << std::endl;
  std::cout << std::flush;
  bool caught = false;
  try
    {
    badreader->Update();
    }
  catch( itk::ExceptionObject & excp )
    {
    caught = true;
    std::cout << "Caught exception as expected" << std::endl;
    std::cout << excp << std::endl;
    }
  if ( !caught )
    {
    std::cerr << "Did not catch non registered transform" << std::endl;
    std::cout << "[FAILED]" << std::endl;
    return EXIT_FAILURE;
    }

  int error_sum = 0;
  error_sum += ReadWriteTest< float, itk::BSplineSmoothingOnUpdateDisplacementFieldTransform<float,2> >(goodname);
  error_sum += ReadWriteTest< float, itk::BSplineSmoothingOnUpdateDisplacementFieldTransform<float,3> >(goodname);
  error_sum += ReadWriteTest< double, itk::BSplineSmoothingOnUpdateDisplacementFieldTransform<double,2> >(goodname);
  error_sum += ReadWriteTest< double, itk::BSplineSmoothingOnUpdateDisplacementFieldTransform<double,3> >(goodname);

  error_sum += ReadWriteTest< float, itk::ConstantVelocityFieldTransform<float,2> >(goodname);
  error_sum += ReadWriteTest< float, itk::ConstantVelocityFieldTransform<float,3> >(goodname);
  error_sum += ReadWriteTest< double, itk::ConstantVelocityFieldTransform<double,2> >(goodname);
  error_sum += ReadWriteTest< double, itk::ConstantVelocityFieldTransform<double,3> >(goodname);

  error_sum += ReadWriteTest< float, itk::DisplacementFieldTransform<float, 2> >(goodname);
  error_sum += ReadWriteTest< float, itk::DisplacementFieldTransform<float, 3> >(goodname);
  error_sum += ReadWriteTest< double, itk::DisplacementFieldTransform<double, 2> >(goodname);
  error_sum += ReadWriteTest< double, itk::DisplacementFieldTransform<double, 3> >(goodname);

  error_sum += ReadWriteTest< float, itk::BSplineSmoothingOnUpdateDisplacementFieldTransform<float,2> >(goodname);
  error_sum += ReadWriteTest< float, itk::BSplineSmoothingOnUpdateDisplacementFieldTransform<float,3> >(goodname);
  error_sum += ReadWriteTest< double, itk::BSplineSmoothingOnUpdateDisplacementFieldTransform<double,2> >(goodname);
  error_sum += ReadWriteTest< double, itk::BSplineSmoothingOnUpdateDisplacementFieldTransform<double,3> >(goodname);

  error_sum += ReadWriteTest< float, itk::GaussianExponentialDiffeomorphicTransform<float,2> >(goodname);
  error_sum += ReadWriteTest< float, itk::GaussianExponentialDiffeomorphicTransform<float,3> >(goodname);
  error_sum += ReadWriteTest< double, itk::GaussianExponentialDiffeomorphicTransform<double,2> >(goodname);
  error_sum += ReadWriteTest< double, itk::GaussianExponentialDiffeomorphicTransform<double,3> >(goodname);

  error_sum += ReadWriteTest< float, itk::GaussianSmoothingOnUpdateDisplacementFieldTransform<float,2> >(goodname);
  error_sum += ReadWriteTest< float, itk::GaussianSmoothingOnUpdateDisplacementFieldTransform<float,3> >(goodname);
  error_sum += ReadWriteTest< double, itk::GaussianSmoothingOnUpdateDisplacementFieldTransform<double,2> >(goodname);
  error_sum += ReadWriteTest< double, itk::GaussianSmoothingOnUpdateDisplacementFieldTransform<double,3> >(goodname);

  if( error_sum > 0 )
    {
    std::cerr << "Atleast 1 transform type could not be read/written " << error_sum << std::endl;
    std::cout << "[FAILED]" << std::endl;
    return EXIT_FAILURE;
    }

  std::cout << "[PASSED]" << std::endl;

  return EXIT_SUCCESS;
}

//
// test endless loop bug in transform reader, triggered by no
// EOL at end of file.
// This test will exercise this reported bug:
// http://public.kitware.com/Bug/view.php?id=7028
template<typename ScalarType>
int
secondTest()
{
  std::filebuf fb;
  fb.open("IllegalTransform.txt",std::ios::out);
  std::ostream os(&fb);
  os << "#Insight Transform File V1.0"
     << std::endl
     << "#Transform 0"
     << std::endl
     << "Transform: AffineTransform_double_10_10"
     << std::endl
     << "Parameters: "
     << "  0 1 2 3 4 5 6 7 8 9 10 11 12"
     << " 13 14 15 16 17 18 19 20 21 22"
     << std::endl
     << "FixedParameters: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18";
  fb.close();
  typename itk::TransformFileReaderTemplate<ScalarType>::Pointer reader;
  reader = itk::TransformFileReaderTemplate<ScalarType>::New();
  reader->SetFileName("IllegalTransform.txt");
  try
    {
    reader->Update();
    std::cerr << "FAILED to throw expected exception" << std::endl;
    typename itk::TransformFileReaderTemplate<ScalarType>::TransformListType *list;
    list = reader->GetTransformList();
    typename itk::TransformFileReaderTemplate<ScalarType>::TransformListType::iterator lit =
      list->begin();
    while ( lit != list->end() )
      {
      (*lit)->Print ( std::cout );
      ++lit;
      }
    }
  catch( itk::ExceptionObject & excp )
    {
    std::cerr << "EXPECTED Error while reading the transforms" << std::endl;
    std::cerr << excp << std::endl;
    std::cout << "[SUCCESS]" << std::endl;
    return EXIT_SUCCESS;
    }
  return EXIT_FAILURE;
}

int itkIOTransformHDF5Test(int argc, char* argv[])
{
  if (argc > 1)
    {
    itksys::SystemTools::ChangeDirectory(argv[1]);
    }
  const int result1 =  oneTest<float>("Transforms_float.h5", "TransformsBad_float.h5" );
  const int result2 =  secondTest<float>();

  const int result3 =  oneTest<double>("Transforms_double.hdf5", "TransformsBad_double.hdf5" );
  const int result4 =  secondTest<double>();

  return (
          ( !( result1 == EXIT_SUCCESS && result2 == EXIT_SUCCESS) ) &&
          ( !( result3 == EXIT_SUCCESS && result4 == EXIT_SUCCESS) )
          );
}
<commit_msg>BUG: Remove InsightLegacy test code from TransformHDF5Test.<commit_after>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include <iostream>
#include <fstream>
#include "itkHDF5TransformIOFactory.h"
#include "itkTransformFileWriter.h"
#include "itkTransformFileReader.h"
#include "itkAffineTransform.h"
#include "itkTransformFactory.h"
#include "itkSimilarity2DTransform.h"
#include "itkBSplineTransform.h"
#include "itksys/SystemTools.hxx"

//Transforms from Filtering/DisplacementField/include
#include "itkBSplineExponentialDiffeomorphicTransform.h"
#include "itkBSplineSmoothingOnUpdateDisplacementFieldTransform.h"
#include "itkConstantVelocityFieldTransform.h"
#include "itkDisplacementFieldTransform.h"
#include "itkGaussianExponentialDiffeomorphicTransform.h"
#include "itkGaussianSmoothingOnUpdateDisplacementFieldTransform.h"

template < typename ScalarType, typename DisplacementTransformType >
static int ReadWriteTest(const char * const fileName)
{
  // Now test reading/writing many different transform types.
  typename itk::TransformFileReaderTemplate<ScalarType>::Pointer
    reader = itk::TransformFileReaderTemplate<ScalarType>::New();

  typename itk::TransformFileWriterTemplate<ScalarType>::Pointer
    writer = itk::TransformFileWriterTemplate<ScalarType>::New();

  writer->SetFileName( fileName );
  reader->SetFileName( fileName );

  typename DisplacementTransformType::Pointer displacementTransform = DisplacementTransformType::New();
    {
    typedef typename DisplacementTransformType::DisplacementFieldType FieldType;
    typename FieldType::Pointer field = FieldType::New(); //This is based on itk::Image

    const int dimLength = 20;
    typename FieldType::SizeType size;
    size.Fill( dimLength );
    typename FieldType::IndexType start;
    start.Fill( 0 );
    typename FieldType::RegionType region;
    region.SetSize( size );
    region.SetIndex( start );
    field->SetRegions( region );
    typename FieldType::SpacingType spacing;
    spacing.Fill( 1.2 );
    field->SetSpacing( spacing );
    field->Allocate();

    typename DisplacementTransformType::OutputVectorType zeroVector;
    zeroVector.Fill( 0 );
    field->FillBuffer( zeroVector );

    displacementTransform->SetDisplacementField( field );
    }

  try
    {
    writer->AddTransform( displacementTransform );
    writer->Update();
    //std::cout << std::endl;
    //std::cout << "Testing read : " << std::endl;
    reader->Update();
    }
  catch( itk::ExceptionObject & excp )
    {
    std::cerr << "Error while saving the transforms" << std::endl;
    std::cerr << excp << std::endl;
    std::cout << "[FAILED]" << std::endl;
    return EXIT_FAILURE;
    }
  return EXIT_SUCCESS;
}

template<typename ScalarType>
static int oneTest(const char *const goodname,const char *const badname)
{
  typedef typename itk::AffineTransform<ScalarType,4>  AffineTransformType;
  typedef typename itk::AffineTransform<ScalarType,10> AffineTransformTypeNotRegistered;
  typename AffineTransformType::Pointer        affine = AffineTransformType::New();

  itk::ObjectFactoryBase::RegisterFactory(itk::HDF5TransformIOFactory::New() );

  // Set it's parameters
  typename AffineTransformType::ParametersType p = affine->GetParameters();
  for ( unsigned int i = 0; i < p.GetSize(); i++ )
    {
    p[i] = i;
    }
  affine->SetParameters ( p );
  p = affine->GetFixedParameters ();
  for ( unsigned int i = 0; i < p.GetSize(); i++ )
    {
    p[i] = i;
    }
  affine->SetFixedParameters ( p );
  typename itk::TransformFileWriterTemplate<ScalarType>::Pointer
    writer = itk::TransformFileWriterTemplate<ScalarType>::New();
  typename itk::TransformFileReaderTemplate<ScalarType>::Pointer
    reader = itk::TransformFileReaderTemplate<ScalarType>::New();

  writer->AddTransform(affine);

  writer->SetFileName( goodname );
  reader->SetFileName( goodname );

  // Testing writing std::cout << "Testing write : ";
  affine->Print ( std::cout );
  try
    {
    writer->Update();
    std::cout << std::endl;
    std::cout << "Testing read : " << std::endl;
    reader->Update();
    }
  catch( itk::ExceptionObject & excp )
    {
    std::cerr << "Error while saving the transforms" << std::endl;
    std::cerr << excp << std::endl;
    std::cout << "[FAILED]" << std::endl;
    return EXIT_FAILURE;
    }

  try
    {
    typename itk::TransformFileReaderTemplate<ScalarType>::TransformListType * list = reader->GetTransformList();
    typename itk::TransformFileReaderTemplate<ScalarType>::TransformListType::iterator lit = list->begin();
    while ( lit != list->end() )
      {
      (*lit)->Print ( std::cout );
      ++lit;
      }
    }
  catch( itk::ExceptionObject & excp )
    {
    std::cerr << "Error while saving the transforms" << std::endl;
    std::cerr << excp << std::endl;
    std::cout << "[FAILED]" << std::endl;
    return EXIT_FAILURE;
    }

  std::cout << "Creating bad writer" << std::endl;
  typename AffineTransformTypeNotRegistered::Pointer Bogus = AffineTransformTypeNotRegistered::New();

  // Set it's parameters
  p = Bogus->GetParameters();
  for ( unsigned int i = 0; i < p.GetSize(); i++ )
    {
    p[i] = i;
    }
  Bogus->SetParameters ( p );
  p = Bogus->GetFixedParameters ();
  for ( unsigned int i = 0; i < p.GetSize(); i++ )
    {
    p[i] = i;
    }
  Bogus->SetFixedParameters ( p );

  typename itk::TransformFileWriterTemplate<ScalarType>::Pointer
    badwriter = itk::TransformFileWriterTemplate<ScalarType>::New();
  typename itk::TransformFileReaderTemplate<ScalarType>::Pointer
    badreader = itk::TransformFileReaderTemplate<ScalarType>::New();
  badwriter->AddTransform(Bogus);
  badwriter->SetFileName(badname);
  badreader->SetFileName(badname);

  // Testing writing
  std::cout << "Testing write of non register transform : " << std::endl;
  std::cout << std::flush;
  try
    {
    badwriter->Update();
    }
  catch( itk::ExceptionObject & excp )
    {
    std::cerr << "Error while saving the transforms" << std::endl;
    std::cerr << excp << std::endl;
    std::cout << "[FAILED]" << std::endl;
    return EXIT_FAILURE;
    }

  // Testing writing
  std::cout << "Testing read of non register transform : " << std::endl;
  std::cout << std::flush;
  bool caught = false;
  try
    {
    badreader->Update();
    }
  catch( itk::ExceptionObject & excp )
    {
    caught = true;
    std::cout << "Caught exception as expected" << std::endl;
    std::cout << excp << std::endl;
    }
  if ( !caught )
    {
    std::cerr << "Did not catch non registered transform" << std::endl;
    std::cout << "[FAILED]" << std::endl;
    return EXIT_FAILURE;
    }

  int error_sum = 0;
  error_sum += ReadWriteTest< float, itk::BSplineSmoothingOnUpdateDisplacementFieldTransform<float,2> >(goodname);
  error_sum += ReadWriteTest< float, itk::BSplineSmoothingOnUpdateDisplacementFieldTransform<float,3> >(goodname);
  error_sum += ReadWriteTest< double, itk::BSplineSmoothingOnUpdateDisplacementFieldTransform<double,2> >(goodname);
  error_sum += ReadWriteTest< double, itk::BSplineSmoothingOnUpdateDisplacementFieldTransform<double,3> >(goodname);

  error_sum += ReadWriteTest< float, itk::ConstantVelocityFieldTransform<float,2> >(goodname);
  error_sum += ReadWriteTest< float, itk::ConstantVelocityFieldTransform<float,3> >(goodname);
  error_sum += ReadWriteTest< double, itk::ConstantVelocityFieldTransform<double,2> >(goodname);
  error_sum += ReadWriteTest< double, itk::ConstantVelocityFieldTransform<double,3> >(goodname);

  error_sum += ReadWriteTest< float, itk::DisplacementFieldTransform<float, 2> >(goodname);
  error_sum += ReadWriteTest< float, itk::DisplacementFieldTransform<float, 3> >(goodname);
  error_sum += ReadWriteTest< double, itk::DisplacementFieldTransform<double, 2> >(goodname);
  error_sum += ReadWriteTest< double, itk::DisplacementFieldTransform<double, 3> >(goodname);

  error_sum += ReadWriteTest< float, itk::BSplineSmoothingOnUpdateDisplacementFieldTransform<float,2> >(goodname);
  error_sum += ReadWriteTest< float, itk::BSplineSmoothingOnUpdateDisplacementFieldTransform<float,3> >(goodname);
  error_sum += ReadWriteTest< double, itk::BSplineSmoothingOnUpdateDisplacementFieldTransform<double,2> >(goodname);
  error_sum += ReadWriteTest< double, itk::BSplineSmoothingOnUpdateDisplacementFieldTransform<double,3> >(goodname);

  error_sum += ReadWriteTest< float, itk::GaussianExponentialDiffeomorphicTransform<float,2> >(goodname);
  error_sum += ReadWriteTest< float, itk::GaussianExponentialDiffeomorphicTransform<float,3> >(goodname);
  error_sum += ReadWriteTest< double, itk::GaussianExponentialDiffeomorphicTransform<double,2> >(goodname);
  error_sum += ReadWriteTest< double, itk::GaussianExponentialDiffeomorphicTransform<double,3> >(goodname);

  error_sum += ReadWriteTest< float, itk::GaussianSmoothingOnUpdateDisplacementFieldTransform<float,2> >(goodname);
  error_sum += ReadWriteTest< float, itk::GaussianSmoothingOnUpdateDisplacementFieldTransform<float,3> >(goodname);
  error_sum += ReadWriteTest< double, itk::GaussianSmoothingOnUpdateDisplacementFieldTransform<double,2> >(goodname);
  error_sum += ReadWriteTest< double, itk::GaussianSmoothingOnUpdateDisplacementFieldTransform<double,3> >(goodname);

  if( error_sum > 0 )
    {
    std::cerr << "Atleast 1 transform type could not be read/written " << error_sum << std::endl;
    std::cout << "[FAILED]" << std::endl;
    return EXIT_FAILURE;
    }

  std::cout << "[PASSED]" << std::endl;

  return EXIT_SUCCESS;
}

int itkIOTransformHDF5Test(int argc, char* argv[])
{
  if (argc > 1)
    {
    itksys::SystemTools::ChangeDirectory(argv[1]);
    }
  const int result1 =  oneTest<float>("Transforms_float.h5", "TransformsBad_float.h5" );
  const int result2 =  oneTest<double>("Transforms_double.hdf5", "TransformsBad_double.hdf5" );

  return ( !( result1 == EXIT_SUCCESS && result2 == EXIT_SUCCESS) );
}
<|endoftext|>


<commit_before>#include <windows.h>
#include <winternl.h>
#include <tlhelp32.h>
#include <vector>
#include <algorithm>

#include "NativeCore.hpp"

static DWORD GetRemotePeb(HANDLE process, PPEB* ppeb)
{
	const auto ntdll = GetModuleHandle(TEXT("ntdll"));
	if (!ntdll)
		return ERROR_MOD_NOT_FOUND;

	using tRtlNtStatusToDosError = ULONG (NTAPI *)(
			_In_ NTSTATUS Status
		);
	const auto pRtlNtStatusToDosError = tRtlNtStatusToDosError(GetProcAddress(ntdll, "RtlNtStatusToDosError"));
	if (!pRtlNtStatusToDosError)
		return ERROR_NOT_FOUND;

	using tNtQueryInformationProcess = NTSTATUS (NTAPI *)(
			_In_ HANDLE ProcessHandle,
			_In_ PROCESSINFOCLASS ProcessInformationClass,
			_Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation,
			_In_ ULONG ProcessInformationLength,
			_Out_opt_ PULONG ReturnLength
		);

	const auto pNtQueryInformationProcess = tNtQueryInformationProcess(GetProcAddress(ntdll, "NtQueryInformationProcess"));
	if (!pNtQueryInformationProcess)
		return ERROR_NOT_FOUND;

	PROCESS_BASIC_INFORMATION pbi;
	const auto status = pNtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), nullptr);
	if (!NT_SUCCESS(status))
		return pRtlNtStatusToDosError(status);

	*ppeb = pbi.PebBaseAddress;

	return ERROR_SUCCESS;
}

template <typename Proc>
static DWORD EnumerateRemoteModulesNative(HANDLE process, Proc proc)
{
	PPEB ppeb;
	const auto error = GetRemotePeb(process, &ppeb);
	if (error != ERROR_SUCCESS)
		return error;

	PPEB_LDR_DATA ldr;
	auto success = ReadRemoteMemory(process, ppeb->Ldr, &ldr, 0, sizeof(ldr));
	if (!success)
		return ERROR_READ_FAULT; // we seem to swallow the error anyways, might aswell give a distinctive one back

	const auto list_head = &ldr->InMemoryOrderModuleList; // remote address
	PLIST_ENTRY list_current; // remote address
	success = ReadRemoteMemory(process, &list_head->Flink, &list_current, 0, sizeof(list_current));
	if (!success)
		return ERROR_READ_FAULT;

	while (list_current != list_head)
	{
		// TODO: error handling - what do we do if module list changed? We can't un-call the callback

		LDR_DATA_TABLE_ENTRY mod;
		success = ReadRemoteMemory(process, CONTAINING_RECORD(list_current, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks), &mod, 0, sizeof(mod));
		if (!success)
			return ERROR_SUCCESS; // return success here to prevent running the other one

		EnumerateRemoteModuleData data = {};
		data.BaseAddress = mod.DllBase;
		data.Size = *(ULONG*)&mod.Reserved2[1]; // instead of undocced member could read ImageSize from headers
		const auto path_len = std::min(sizeof(RC_UnicodeChar) * (PATH_MAXIMUM_LENGTH - 1), size_t(mod.FullDllName.Length));
		success = ReadRemoteMemory(process, mod.FullDllName.Buffer, data.Path, 0, int(path_len));
		if (!success)
			return ERROR_SUCCESS; // return success here to prevent running the other one

		// UNICODE_STRING is not guaranteed to be null terminated
		data.Path[path_len / 2] = 0;

		proc(&data);

		list_current = mod.InMemoryOrderLinks.Flink;
	}

	return ERROR_SUCCESS;
}

template <typename Proc>
static DWORD EnumerateRemoteModulesWinapi(HANDLE process, Proc proc)
{
	const auto handle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetProcessId(process));
	if (handle == INVALID_HANDLE_VALUE)
		return GetLastError();

	MODULEENTRY32W me32 = {};
	me32.dwSize = sizeof(MODULEENTRY32W);
	if (Module32FirstW(handle, &me32))
	{
		do
		{
			EnumerateRemoteModuleData data = {};
			data.BaseAddress = me32.modBaseAddr;
			data.Size = me32.modBaseSize;
			std::memcpy(data.Path, me32.szExePath, std::min(MAX_PATH, PATH_MAXIMUM_LENGTH));

			proc(&data);
		} while (Module32NextW(handle, &me32));
	}

	CloseHandle(handle);

	return ERROR_SUCCESS;
}

void RC_CallConv EnumerateRemoteSectionsAndModules(RC_Pointer process, EnumerateRemoteSectionsCallback callbackSection, EnumerateRemoteModulesCallback callbackModule)
{
	if (callbackSection == nullptr && callbackModule == nullptr)
	{
		return;
	}

	std::vector<EnumerateRemoteSectionData> sections;

	MEMORY_BASIC_INFORMATION memInfo = { };
	memInfo.RegionSize = 0x1000;
	size_t address = 0;
	while (VirtualQueryEx(process, reinterpret_cast<LPCVOID>(address), &memInfo, sizeof(MEMORY_BASIC_INFORMATION)) != 0 && address + memInfo.RegionSize > address)
	{
		if (memInfo.State == MEM_COMMIT)
		{
			EnumerateRemoteSectionData section = {};
			section.BaseAddress = memInfo.BaseAddress;
			section.Size = memInfo.RegionSize;

			section.Protection = SectionProtection::NoAccess;
			if ((memInfo.Protect & PAGE_EXECUTE) == PAGE_EXECUTE) section.Protection |= SectionProtection::Execute;
			if ((memInfo.Protect & PAGE_EXECUTE_READ) == PAGE_EXECUTE_READ) section.Protection |= SectionProtection::Execute | SectionProtection::Read;
			if ((memInfo.Protect & PAGE_EXECUTE_READWRITE) == PAGE_EXECUTE_READWRITE) section.Protection |= SectionProtection::Execute | SectionProtection::Read | SectionProtection::Write;
			if ((memInfo.Protect & PAGE_EXECUTE_WRITECOPY) == PAGE_EXECUTE_WRITECOPY) section.Protection |= SectionProtection::Execute | SectionProtection::Read | SectionProtection::CopyOnWrite;
			if ((memInfo.Protect & PAGE_READONLY) == PAGE_READONLY) section.Protection |= SectionProtection::Read;
			if ((memInfo.Protect & PAGE_READWRITE) == PAGE_READWRITE) section.Protection |= SectionProtection::Read | SectionProtection::Write;
			if ((memInfo.Protect & PAGE_WRITECOPY) == PAGE_WRITECOPY) section.Protection |= SectionProtection::Read | SectionProtection::CopyOnWrite;
			if ((memInfo.Protect & PAGE_GUARD) == PAGE_GUARD) section.Protection |= SectionProtection::Guard;

			switch (memInfo.Type)
			{
			case MEM_IMAGE:
				section.Type = SectionType::Image;
				break;
			case MEM_MAPPED:
				section.Type = SectionType::Mapped;
				break;
			case MEM_PRIVATE:
				section.Type = SectionType::Private;
				break;
			}

			section.Category = section.Type == SectionType::Private ? SectionCategory::HEAP : SectionCategory::Unknown;

			sections.push_back(std::move(section));
		}
		address = reinterpret_cast<size_t>(memInfo.BaseAddress) + memInfo.RegionSize;
	}

	const auto moduleEnumerator = [&](EnumerateRemoteModuleData* data)
	{
		if (callbackModule != nullptr)
			callbackModule(data);

		if (callbackSection != nullptr)
		{
			auto it = std::lower_bound(std::begin(sections), std::end(sections), static_cast<LPVOID>(data->BaseAddress), [&sections](const auto& lhs, const LPVOID& rhs)
				{
					return lhs.BaseAddress < rhs;
				});

			IMAGE_DOS_HEADER DosHdr = {};
			IMAGE_NT_HEADERS NtHdr = {};

			ReadRemoteMemory(process, data->BaseAddress, &DosHdr, 0, sizeof(IMAGE_DOS_HEADER));
			ReadRemoteMemory(process, PUCHAR(data->BaseAddress) + DosHdr.e_lfanew, &NtHdr, 0, sizeof(IMAGE_NT_HEADERS));

			std::vector<IMAGE_SECTION_HEADER> sectionHeaders(NtHdr.FileHeader.NumberOfSections);
			ReadRemoteMemory(process, PUCHAR(data->BaseAddress) + DosHdr.e_lfanew + sizeof(IMAGE_NT_HEADERS), sectionHeaders.data(), 0, NtHdr.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
			for (auto i = 0; i < NtHdr.FileHeader.NumberOfSections; ++i)
			{
				auto&& sectionHeader = sectionHeaders[i];

				const auto sectionAddress = reinterpret_cast<size_t>(data->BaseAddress) + sectionHeader.VirtualAddress;
				for (auto j = it; j != std::end(sections); ++j)
				{
					if (sectionAddress >= reinterpret_cast<size_t>(j->BaseAddress) && sectionAddress < reinterpret_cast<size_t>(j->BaseAddress) + static_cast<size_t>(j->Size))
					{
						// Copy the name because it is not null padded.
						char buffer[IMAGE_SIZEOF_SHORT_NAME + 1] = { 0 };
						std::memcpy(buffer, sectionHeader.Name, IMAGE_SIZEOF_SHORT_NAME);

						if (std::strcmp(buffer, ".text") == 0 || std::strcmp(buffer, "code") == 0)
						{
							j->Category = SectionCategory::CODE;
						}
						else if (std::strcmp(buffer, ".data") == 0 || std::strcmp(buffer, "data") == 0 || std::strcmp(buffer, ".rdata") == 0 || std::strcmp(buffer, ".idata") == 0)
						{
							j->Category = SectionCategory::DATA;
						}

						MultiByteToUnicode(buffer, j->Name, IMAGE_SIZEOF_SHORT_NAME);
						std::memcpy(j->ModulePath, data->Path, std::min(MAX_PATH, PATH_MAXIMUM_LENGTH));

						break;
					}
				}

			}
		}
	};

	if(EnumerateRemoteModulesNative(process, moduleEnumerator) != ERROR_SUCCESS)
		EnumerateRemoteModulesWinapi(process, moduleEnumerator);

	if (callbackSection != nullptr)
	{
		for (auto&& section : sections)
		{
			callbackSection(&section);
		}
	}
}
<commit_msg>fix broken code - how did this work<commit_after>#include <windows.h>
#include <winternl.h>
#include <tlhelp32.h>
#include <vector>
#include <algorithm>

#include "NativeCore.hpp"

static DWORD GetRemotePeb(HANDLE process, PPEB* ppeb)
{
	const auto ntdll = GetModuleHandle(TEXT("ntdll"));
	if (!ntdll)
		return ERROR_MOD_NOT_FOUND;

	using tRtlNtStatusToDosError = ULONG (NTAPI *)(
			_In_ NTSTATUS Status
		);
	const auto pRtlNtStatusToDosError = tRtlNtStatusToDosError(GetProcAddress(ntdll, "RtlNtStatusToDosError"));
	if (!pRtlNtStatusToDosError)
		return ERROR_NOT_FOUND;

	using tNtQueryInformationProcess = NTSTATUS (NTAPI *)(
			_In_ HANDLE ProcessHandle,
			_In_ PROCESSINFOCLASS ProcessInformationClass,
			_Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation,
			_In_ ULONG ProcessInformationLength,
			_Out_opt_ PULONG ReturnLength
		);

	const auto pNtQueryInformationProcess = tNtQueryInformationProcess(GetProcAddress(ntdll, "NtQueryInformationProcess"));
	if (!pNtQueryInformationProcess)
		return ERROR_NOT_FOUND;

	PROCESS_BASIC_INFORMATION pbi;
	const auto status = pNtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), nullptr);
	if (!NT_SUCCESS(status))
		return pRtlNtStatusToDosError(status);

	*ppeb = pbi.PebBaseAddress;

	return ERROR_SUCCESS;
}

template <typename Proc>
static DWORD EnumerateRemoteModulesNative(HANDLE process, Proc proc)
{
	PPEB ppeb;
	const auto error = GetRemotePeb(process, &ppeb);
	if (error != ERROR_SUCCESS)
		return error;

	PPEB_LDR_DATA ldr;
	auto success = ReadRemoteMemory(process, &ppeb->Ldr, &ldr, 0, sizeof(ldr));
	if (!success)
		return ERROR_READ_FAULT; // we seem to swallow the error anyways, might aswell give a distinctive one back

	const auto list_head = &ldr->InMemoryOrderModuleList; // remote address
	PLIST_ENTRY list_current; // remote address
	success = ReadRemoteMemory(process, &list_head->Flink, &list_current, 0, sizeof(list_current));
	if (!success)
		return ERROR_READ_FAULT;

	while (list_current != list_head)
	{
		// TODO: error handling - what do we do if module list changed? We can't un-call the callback

		LDR_DATA_TABLE_ENTRY mod;
		success = ReadRemoteMemory(process, CONTAINING_RECORD(list_current, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks), &mod, 0, sizeof(mod));
		if (!success)
			return ERROR_SUCCESS; // return success here to prevent running the other one

		EnumerateRemoteModuleData data = {};
		data.BaseAddress = mod.DllBase;
		data.Size = *(ULONG*)&mod.Reserved2[1]; // instead of undocced member could read ImageSize from headers
		const auto path_len = std::min(sizeof(RC_UnicodeChar) * (PATH_MAXIMUM_LENGTH - 1), size_t(mod.FullDllName.Length));
		success = ReadRemoteMemory(process, mod.FullDllName.Buffer, data.Path, 0, int(path_len));
		if (!success)
			return ERROR_SUCCESS; // return success here to prevent running the other one

		// UNICODE_STRING is not guaranteed to be null terminated
		data.Path[path_len / 2] = 0;

		proc(&data);

		list_current = mod.InMemoryOrderLinks.Flink;
	}

	return ERROR_SUCCESS;
}

template <typename Proc>
static DWORD EnumerateRemoteModulesWinapi(HANDLE process, Proc proc)
{
	const auto handle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetProcessId(process));
	if (handle == INVALID_HANDLE_VALUE)
		return GetLastError();

	MODULEENTRY32W me32 = {};
	me32.dwSize = sizeof(MODULEENTRY32W);
	if (Module32FirstW(handle, &me32))
	{
		do
		{
			EnumerateRemoteModuleData data = {};
			data.BaseAddress = me32.modBaseAddr;
			data.Size = me32.modBaseSize;
			std::memcpy(data.Path, me32.szExePath, std::min(MAX_PATH, PATH_MAXIMUM_LENGTH));

			proc(&data);
		} while (Module32NextW(handle, &me32));
	}

	CloseHandle(handle);

	return ERROR_SUCCESS;
}

void RC_CallConv EnumerateRemoteSectionsAndModules(RC_Pointer process, EnumerateRemoteSectionsCallback callbackSection, EnumerateRemoteModulesCallback callbackModule)
{
	if (callbackSection == nullptr && callbackModule == nullptr)
	{
		return;
	}

	std::vector<EnumerateRemoteSectionData> sections;

	MEMORY_BASIC_INFORMATION memInfo = { };
	memInfo.RegionSize = 0x1000;
	size_t address = 0;
	while (VirtualQueryEx(process, reinterpret_cast<LPCVOID>(address), &memInfo, sizeof(MEMORY_BASIC_INFORMATION)) != 0 && address + memInfo.RegionSize > address)
	{
		if (memInfo.State == MEM_COMMIT)
		{
			EnumerateRemoteSectionData section = {};
			section.BaseAddress = memInfo.BaseAddress;
			section.Size = memInfo.RegionSize;

			section.Protection = SectionProtection::NoAccess;
			if ((memInfo.Protect & PAGE_EXECUTE) == PAGE_EXECUTE) section.Protection |= SectionProtection::Execute;
			if ((memInfo.Protect & PAGE_EXECUTE_READ) == PAGE_EXECUTE_READ) section.Protection |= SectionProtection::Execute | SectionProtection::Read;
			if ((memInfo.Protect & PAGE_EXECUTE_READWRITE) == PAGE_EXECUTE_READWRITE) section.Protection |= SectionProtection::Execute | SectionProtection::Read | SectionProtection::Write;
			if ((memInfo.Protect & PAGE_EXECUTE_WRITECOPY) == PAGE_EXECUTE_WRITECOPY) section.Protection |= SectionProtection::Execute | SectionProtection::Read | SectionProtection::CopyOnWrite;
			if ((memInfo.Protect & PAGE_READONLY) == PAGE_READONLY) section.Protection |= SectionProtection::Read;
			if ((memInfo.Protect & PAGE_READWRITE) == PAGE_READWRITE) section.Protection |= SectionProtection::Read | SectionProtection::Write;
			if ((memInfo.Protect & PAGE_WRITECOPY) == PAGE_WRITECOPY) section.Protection |= SectionProtection::Read | SectionProtection::CopyOnWrite;
			if ((memInfo.Protect & PAGE_GUARD) == PAGE_GUARD) section.Protection |= SectionProtection::Guard;

			switch (memInfo.Type)
			{
			case MEM_IMAGE:
				section.Type = SectionType::Image;
				break;
			case MEM_MAPPED:
				section.Type = SectionType::Mapped;
				break;
			case MEM_PRIVATE:
				section.Type = SectionType::Private;
				break;
			}

			section.Category = section.Type == SectionType::Private ? SectionCategory::HEAP : SectionCategory::Unknown;

			sections.push_back(std::move(section));
		}
		address = reinterpret_cast<size_t>(memInfo.BaseAddress) + memInfo.RegionSize;
	}

	const auto moduleEnumerator = [&](EnumerateRemoteModuleData* data)
	{
		if (callbackModule != nullptr)
			callbackModule(data);

		if (callbackSection != nullptr)
		{
			auto it = std::lower_bound(std::begin(sections), std::end(sections), static_cast<LPVOID>(data->BaseAddress), [&sections](const auto& lhs, const LPVOID& rhs)
				{
					return lhs.BaseAddress < rhs;
				});

			IMAGE_DOS_HEADER DosHdr = {};
			IMAGE_NT_HEADERS NtHdr = {};

			ReadRemoteMemory(process, data->BaseAddress, &DosHdr, 0, sizeof(IMAGE_DOS_HEADER));
			ReadRemoteMemory(process, PUCHAR(data->BaseAddress) + DosHdr.e_lfanew, &NtHdr, 0, sizeof(IMAGE_NT_HEADERS));

			std::vector<IMAGE_SECTION_HEADER> sectionHeaders(NtHdr.FileHeader.NumberOfSections);
			ReadRemoteMemory(process, PUCHAR(data->BaseAddress) + DosHdr.e_lfanew + sizeof(IMAGE_NT_HEADERS), sectionHeaders.data(), 0, NtHdr.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
			for (auto i = 0; i < NtHdr.FileHeader.NumberOfSections; ++i)
			{
				auto&& sectionHeader = sectionHeaders[i];

				const auto sectionAddress = reinterpret_cast<size_t>(data->BaseAddress) + sectionHeader.VirtualAddress;
				for (auto j = it; j != std::end(sections); ++j)
				{
					if (sectionAddress >= reinterpret_cast<size_t>(j->BaseAddress) && sectionAddress < reinterpret_cast<size_t>(j->BaseAddress) + static_cast<size_t>(j->Size))
					{
						// Copy the name because it is not null padded.
						char buffer[IMAGE_SIZEOF_SHORT_NAME + 1] = { 0 };
						std::memcpy(buffer, sectionHeader.Name, IMAGE_SIZEOF_SHORT_NAME);

						if (std::strcmp(buffer, ".text") == 0 || std::strcmp(buffer, "code") == 0)
						{
							j->Category = SectionCategory::CODE;
						}
						else if (std::strcmp(buffer, ".data") == 0 || std::strcmp(buffer, "data") == 0 || std::strcmp(buffer, ".rdata") == 0 || std::strcmp(buffer, ".idata") == 0)
						{
							j->Category = SectionCategory::DATA;
						}

						MultiByteToUnicode(buffer, j->Name, IMAGE_SIZEOF_SHORT_NAME);
						std::memcpy(j->ModulePath, data->Path, std::min(MAX_PATH, PATH_MAXIMUM_LENGTH));

						break;
					}
				}

			}
		}
	};

	if(EnumerateRemoteModulesNative(process, moduleEnumerator) != ERROR_SUCCESS)
		EnumerateRemoteModulesWinapi(process, moduleEnumerator);

	if (callbackSection != nullptr)
	{
		for (auto&& section : sections)
		{
			callbackSection(&section);
		}
	}
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef SW_NDARR_HXX
#define SW_NDARR_HXX

#include <vector>

#include <com/sun/star/embed/XEmbeddedObject.hpp>

#include <svl/svarray.hxx>
#include <svtools/embedhlp.hxx>

#include <bparr.hxx>
#include <ndtyp.hxx>

class Graphic;
class GraphicObject;
class String;
class SwAttrSet;
class SfxItemSet;
class SwCntntNode;
class SwDoc;
class SwGrfFmtColl;
class SwGrfNode;
class SwHistory;
class SwNode;
class SwNodeIndex;
class SwNodeRange;
class SwOLENode;
class SwOutlineNodes;
class SwPaM;
class SwSectionData;
class SwSectionFmt;
class SwTOXBase;
class SwSectionNode;
class SwStartNode;
class SwTableBoxFmt;
class SwTableFmt;
class SwTableLine;
class SwTableLineFmt;
class SwTableNode;
class SwTblToTxtSaves;
class SwTxtFmtColl;
class SwTxtNode;
class SwUndoTblToTxt;
class SwUndoTxtToTbl;
struct SwPosition;

// --------------------
// class SwNodes
// --------------------

typedef SwNode * SwNodePtr;
typedef BOOL (*FnForEach_SwNodes)( const SwNodePtr&, void* pArgs );

SV_DECL_PTRARR_SORT( SwOutlineNodes, SwNodePtr, 0, 10 )

class SW_DLLPUBLIC SwNodes: private BigPtrArray
{
    friend class SwDoc;
    friend class SwNode;
    friend class SwNodeIndex;

    SwNodeIndex* pRoot;                 // Liste aller Indizies auf Nodes

    // --> OD 2008-05-14 #refactorlists# - removed <bSyncNumberAndNumRule>
    void InsertNode( const SwNodePtr pNode,
                     const SwNodeIndex& rPos );
    void InsertNode( const SwNodePtr pNode,
                     ULONG nPos );
    // <--

    SwDoc* pMyDoc;                      // in diesem Doc ist das Nodes-Array

    SwNode *pEndOfPostIts, *pEndOfInserts,  // das sind die festen Bereiche
           *pEndOfAutotext, *pEndOfRedlines,
           *pEndOfContent;

    mutable SwOutlineNodes* pOutlineNds;        // Array aller GliederiungsNodes

    BOOL bInNodesDel : 1;               // falls rekursiv aufgerufen wird
                                        // Num/Outline nicht aktualisierem
    BOOL bInDelUpdOutl : 1;             // Flags fuers aktualisieren von Outl.
    BOOL bInDelUpdNum : 1;              // Flags fuers aktualisieren von Outl.

    // fuer dier Verwaltung der Indizies
    void RegisterIndex( SwNodeIndex& rIdx );
    void DeRegisterIndex( SwNodeIndex& rIdx );
    void RemoveNode( ULONG nDelPos, ULONG nLen, BOOL bDel );

    // Aktionen auf die Nodes
    void SectionUpDown( const SwNodeIndex & aStart, const SwNodeIndex & aEnd );
    void DelNodes( const SwNodeIndex& rStart, ULONG nCnt = 1 );

    void ChgNode( SwNodeIndex& rDelPos, ULONG nSize,
                  SwNodeIndex& rInsPos, BOOL bNewFrms );

    void UpdtOutlineIdx( const SwNode& );   // Update ab Node alle OutlineNodes

    void _CopyNodes( const SwNodeRange&, const SwNodeIndex&,
                    BOOL bNewFrms = TRUE, BOOL bTblInsDummyNode = FALSE ) const;
    void _DelDummyNodes( const SwNodeRange& rRg );

public:
    SwNodes( SwDoc* pDoc );

public:
    ~SwNodes();

    typedef ::std::vector<SwNodeRange> NodeRanges_t;
    typedef ::std::vector<NodeRanges_t> TableRanges_t;

    SwNodePtr operator[]( ULONG n ) const
        { return (SwNodePtr)BigPtrArray::operator[] ( n ); }

//JP 29.09.97: impl. steht im ndindex.hxx - sollte moeglichst bald auf die
//              neue Schnittstelle angepasst werden
    inline SwNodePtr operator[]( const SwNodeIndex& rIdx ) const;

    ULONG Count() const { return BigPtrArray::Count(); }
    void ForEach( FnForEach_SwNodes fnForEach, void* pArgs = 0 )
    {
        BigPtrArray::ForEach( 0, BigPtrArray::Count(),
                                (FnForEach) fnForEach, pArgs );
    }
    void ForEach( ULONG nStt, ULONG nEnd, FnForEach_SwNodes fnForEach, void* pArgs = 0 )
    {
        BigPtrArray::ForEach( nStt, nEnd, (FnForEach) fnForEach, pArgs );
    }
    void ForEach( const SwNodeIndex& rStart, const SwNodeIndex& rEnd,
                    FnForEach_SwNodes fnForEach, void* pArgs = 0 );

    // eine noch leere Section
    SwNode& GetEndOfPostIts() const     { return *pEndOfPostIts; }
    // Section fuer alle Fussnoten
    SwNode& GetEndOfInserts() const     { return *pEndOfInserts; }
    // Section fuer alle Flys/Header/Footers
    SwNode& GetEndOfAutotext() const    { return *pEndOfAutotext; }
    // Section fuer alle Redlines
    SwNode& GetEndOfRedlines() const    { return *pEndOfRedlines; }
    // das ist der letzte EndNode einer SonderSection. Hier nach kommt nur
    // noch die normale ContentSection (also der BodyText)
    SwNode& GetEndOfExtras() const      { return *pEndOfRedlines; }
    // die normale ContentSection (also der BodyText)
    SwNode& GetEndOfContent() const     { return *pEndOfContent; }

    // ist das NodesArray das normale vom Doc? (nicht das UndoNds, .. )
    // Implementierung steht im doc.hxx (weil man dazu Doc kennen muss) !
    BOOL IsDocNodes() const;

    USHORT GetSectionLevel(const SwNodeIndex &rIndex) const;
    void Delete(const SwNodeIndex &rPos, ULONG nNodes = 1);

    BOOL _MoveNodes( const SwNodeRange&, SwNodes& rNodes, const SwNodeIndex&,
                BOOL bNewFrms = TRUE );
    void MoveRange( SwPaM&, SwPosition&, SwNodes& rNodes );

    void _Copy( const SwNodeRange& rRg, const SwNodeIndex& rInsPos,
                BOOL bNewFrms = TRUE ) const
        {   _CopyNodes( rRg, rInsPos, bNewFrms ); }

    void SectionUp( SwNodeRange *);
    void SectionDown( SwNodeRange *pRange, SwStartNodeType = SwNormalStartNode );

    BOOL CheckNodesRange( const SwNodeIndex& rStt, const SwNodeIndex& rEnd ) const;

    void GoStartOfSection(SwNodeIndex *) const;
    void GoEndOfSection(SwNodeIndex *) const;

    SwCntntNode* GoNext(SwNodeIndex *) const;
    SwCntntNode* GoPrevious(SwNodeIndex *) const;

    //Gehe zum naechsten/vorherigen Cntnt/Tabellennode, fuer den
    //es LayoutFrames gibt, dabei Kopf-/Fusszeilen/Rahmen etc. nicht verlassen
    SwNode* GoNextWithFrm(SwNodeIndex *) const;
    SwNode* GoPreviousWithFrm(SwNodeIndex *) const;

    // zum naechsten Content-Node, der nicht geschuetzt oder versteckt ist
    // (beides auf FALSE ==> GoNext/GoPrevious!!!)
    SwCntntNode* GoNextSection( SwNodeIndex *, int bSkipHidden  = TRUE,
                                           int bSkipProtect = TRUE ) const;
    SwCntntNode* GoPrevSection( SwNodeIndex *, int bSkipHidden  = TRUE,
                                           int bSkipProtect = TRUE ) const;

    // erzeuge ein leere Section von Start und EndNode. Darf nur gerufen
    // werden, wenn eine neue Section mit Inhalt erzeugt werden soll.
    // Zum Beispiel bei den Filtern/Undo/...
    SwStartNode* MakeEmptySection( const SwNodeIndex& rIdx,
                                    SwStartNodeType = SwNormalStartNode );

    // die Impl. von "Make...Node" stehen in den angegebenen .ccx-Files
    SwTxtNode *MakeTxtNode( const SwNodeIndex & rWhere,
                            SwTxtFmtColl *pColl,
                            SwAttrSet* pAutoAttr = 0 ); // in ndtxt.cxx
    SwStartNode* MakeTextSection( const SwNodeIndex & rWhere,
                            SwStartNodeType eSttNdTyp,
                            SwTxtFmtColl *pColl,
                            SwAttrSet* pAutoAttr = 0 );

    SwGrfNode *MakeGrfNode( const SwNodeIndex & rWhere,
                            const String& rGrfName,
                            const String& rFltName,
                            const Graphic* pGraphic,
                            SwGrfFmtColl *pColl,
                            SwAttrSet* pAutoAttr = 0,
                            BOOL bDelayed = FALSE );    // in ndgrf.cxx

    SwGrfNode *MakeGrfNode( const SwNodeIndex & rWhere,
                            const GraphicObject& rGrfObj,
                            SwGrfFmtColl *pColl,
                            SwAttrSet* pAutoAttr = 0 ); // in ndgrf.cxx

    SwOLENode *MakeOLENode( const SwNodeIndex & rWhere,
                            const svt::EmbeddedObjectRef&,
                            SwGrfFmtColl *pColl,
                            SwAttrSet* pAutoAttr = 0 ); // in ndole.cxx
    SwOLENode *MakeOLENode( const SwNodeIndex & rWhere,
                            const String &rName,
                            sal_Int64 nAspect,
                            SwGrfFmtColl *pColl,
                            SwAttrSet* pAutoAttr ); // in ndole.cxx

        // Array aller GliederiungsNodes;
    const SwOutlineNodes& GetOutLineNds() const;

    //void UpdateOutlineNode( const SwNode&, BYTE nOldLevel, BYTE nNewLevel );//#outline level,removed by zhaojianwei
        // alle Nodes Updaten - Rule/Format-Aenderung
    void UpdateOutlineNode(SwNode & rNd);

        // fuege die Nodes fuer die Tabelle ein
        // wenn Lines angegeben, erzeuge die Matrix aus Lines & Boxen
        // ansonsten nur die Anzahl von Boxen.
    /* #109161#

       New parameter pAttrSet: If pAttrSet is non-null and contains an
       adjust item it is propagated to the table cells. If there is an
       adjust in pCntntTxtColl or pHeadlineTxtColl this adjust item
       overrides the item in pAttrSet.

     */
    SwTableNode* InsertTable( const SwNodeIndex& rNdIdx,
                        USHORT nBoxes, SwTxtFmtColl* pCntntTxtColl,
                        USHORT nLines = 0, USHORT nRepeat = 0,
                        SwTxtFmtColl* pHeadlineTxtColl = 0,
                        const SwAttrSet * pAttrSet = 0);

        // erzeuge aus dem makierten Bereich eine ausgeglichene Tabelle
    SwTableNode* TextToTable( const SwNodeRange& rRange, sal_Unicode cCh,
                                SwTableFmt* pTblFmt,
                                SwTableLineFmt* pLineFmt,
                                SwTableBoxFmt* pBoxFmt,
                                SwTxtFmtColl* pTxtColl,
                                SwUndoTxtToTbl* pUndo = 0 );

    SwNodeRange * ExpandRangeForTableBox(const SwNodeRange & rRange);

    //create a table from a vector of NodeRanges - API support
    SwTableNode* TextToTable( const TableRanges_t& rTableNodes,
                                SwTableFmt* pTblFmt,
                                SwTableLineFmt* pLineFmt,
                                SwTableBoxFmt* pBoxFmt,
                                SwTxtFmtColl* pTxtColl
                                /*, SwUndo... pUndo*/ );

        // erzeuge aus der Tabelle wieder normalen Text
    BOOL TableToText( const SwNodeRange& rRange, sal_Unicode cCh,
                        SwUndoTblToTxt* = 0 );
        // steht im untbl.cxx und darf nur vom Undoobject gerufen werden
    SwTableNode* UndoTableToText( ULONG nStt, ULONG nEnd,
                        const SwTblToTxtSaves& rSavedData );

        // fuege in der Line, vor der InsPos eine neue Box ein. Das Format
        // wird von der nachfolgenden (vorhergenden;wenn an Ende) genommen
        // in der Line muss schon eine Box vorhanden sein !
    BOOL InsBoxen( SwTableNode*, SwTableLine*, SwTableBoxFmt*,
                        // Formate fuer den TextNode der Box
                        SwTxtFmtColl*, const SfxItemSet* pAutoAttr,
                        USHORT nInsPos, USHORT nCnt = 1 );
        // Splittet eine Tabelle in der Grund-Zeile, in der der Index steht.
        // Alle GrundZeilen dahinter wandern in eine neue Tabelle/-Node.
        // Ist das Flag bCalcNewSize auf TRUE, wird fuer beide neuen Tabellen
        // die neue SSize aus dem Max der Boxen errechnet; vorrausgesetzt,
        // die SSize ist "absolut" gesetzt (LONG_MAX)
        // (Wird zur Zeit nur fuer den RTF-Parser benoetigt)
    SwTableNode* SplitTable( const SwNodeIndex& rPos, BOOL bAfter = TRUE,
                                BOOL bCalcNewSize = FALSE );
        // fuegt 2 Tabellen, die hintereinander stehen, wieder zusammen
    BOOL MergeTable( const SwNodeIndex& rPos, BOOL bWithPrev = TRUE,
                    USHORT nMode = 0, SwHistory* pHistory = 0 );

        // fuege eine neue SwSection ein
    SwSectionNode* InsertTextSection(SwNodeIndex const& rNdIdx,
                                SwSectionFmt& rSectionFmt,
                                SwSectionData const&,
                                SwTOXBase const*const pTOXBase,
                                SwNodeIndex const*const pEnde,
                                bool const bInsAtStart = true,
                                bool const bCreateFrms = true);

        // in welchem Doc steht das Nodes-Array ?
            SwDoc* GetDoc()         { return pMyDoc; }
    const   SwDoc* GetDoc() const   { return pMyDoc; }

        // suche den vorhergehenden [/nachfolgenden ] ContentNode oder
        // TabellenNode mit Frames. Wird kein Ende angeben, dann wird mit
        // dem FrameIndex begonnen; ansonsten, wird mit dem vor rFrmIdx und
        // dem hintern pEnd die Suche gestartet. Sollte kein gueltiger Node
        // gefunden werden, wird 0 returnt. rFrmIdx zeigt auf dem Node mit
        // Frames
    SwNode* FindPrvNxtFrmNode( SwNodeIndex& rFrmIdx,
                                const SwNode* pEnd = 0 ) const;

    //-> #112139#
    SwNode * DocumentSectionStartNode(SwNode * pNode) const;
    SwNode * DocumentSectionEndNode(SwNode * pNode) const;
    //<- #112139#
private:
    // privater Constructor, weil nie kopiert werden darf !!
    SwNodes( const SwNodes & rNodes );
};

#endif
<commit_msg>undoapi: #i115383#: rollback change: make SwNodes ctor protected again<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef SW_NDARR_HXX
#define SW_NDARR_HXX

#include <vector>

#include <boost/utility.hpp>

#include <com/sun/star/embed/XEmbeddedObject.hpp>

#include <svl/svarray.hxx>
#include <svtools/embedhlp.hxx>

#include <bparr.hxx>
#include <ndtyp.hxx>

class Graphic;
class GraphicObject;
class String;
class SwAttrSet;
class SfxItemSet;
class SwCntntNode;
class SwDoc;
class SwGrfFmtColl;
class SwGrfNode;
class SwHistory;
class SwNode;
class SwNodeIndex;
class SwNodeRange;
class SwOLENode;
class SwOutlineNodes;
class SwPaM;
class SwSectionData;
class SwSectionFmt;
class SwTOXBase;
class SwSectionNode;
class SwStartNode;
class SwTableBoxFmt;
class SwTableFmt;
class SwTableLine;
class SwTableLineFmt;
class SwTableNode;
class SwTblToTxtSaves;
class SwTxtFmtColl;
class SwTxtNode;
class SwUndoTblToTxt;
class SwUndoTxtToTbl;
struct SwPosition;

// --------------------
// class SwNodes
// --------------------

typedef SwNode * SwNodePtr;
typedef BOOL (*FnForEach_SwNodes)( const SwNodePtr&, void* pArgs );

SV_DECL_PTRARR_SORT( SwOutlineNodes, SwNodePtr, 0, 10 )

class SW_DLLPUBLIC SwNodes
    : private BigPtrArray
    , private ::boost::noncopyable
{
    friend class SwDoc;
    friend class SwNode;
    friend class SwNodeIndex;

    SwNodeIndex* pRoot;                 // Liste aller Indizies auf Nodes

    // --> OD 2008-05-14 #refactorlists# - removed <bSyncNumberAndNumRule>
    void InsertNode( const SwNodePtr pNode,
                     const SwNodeIndex& rPos );
    void InsertNode( const SwNodePtr pNode,
                     ULONG nPos );
    // <--

    SwDoc* pMyDoc;                      // in diesem Doc ist das Nodes-Array

    SwNode *pEndOfPostIts, *pEndOfInserts,  // das sind die festen Bereiche
           *pEndOfAutotext, *pEndOfRedlines,
           *pEndOfContent;

    mutable SwOutlineNodes* pOutlineNds;        // Array aller GliederiungsNodes

    BOOL bInNodesDel : 1;               // falls rekursiv aufgerufen wird
                                        // Num/Outline nicht aktualisierem
    BOOL bInDelUpdOutl : 1;             // Flags fuers aktualisieren von Outl.
    BOOL bInDelUpdNum : 1;              // Flags fuers aktualisieren von Outl.

    // fuer dier Verwaltung der Indizies
    void RegisterIndex( SwNodeIndex& rIdx );
    void DeRegisterIndex( SwNodeIndex& rIdx );
    void RemoveNode( ULONG nDelPos, ULONG nLen, BOOL bDel );

    // Aktionen auf die Nodes
    void SectionUpDown( const SwNodeIndex & aStart, const SwNodeIndex & aEnd );
    void DelNodes( const SwNodeIndex& rStart, ULONG nCnt = 1 );

    void ChgNode( SwNodeIndex& rDelPos, ULONG nSize,
                  SwNodeIndex& rInsPos, BOOL bNewFrms );

    void UpdtOutlineIdx( const SwNode& );   // Update ab Node alle OutlineNodes

    void _CopyNodes( const SwNodeRange&, const SwNodeIndex&,
                    BOOL bNewFrms = TRUE, BOOL bTblInsDummyNode = FALSE ) const;
    void _DelDummyNodes( const SwNodeRange& rRg );

protected:
    SwNodes( SwDoc* pDoc );

public:
    ~SwNodes();

    typedef ::std::vector<SwNodeRange> NodeRanges_t;
    typedef ::std::vector<NodeRanges_t> TableRanges_t;

    SwNodePtr operator[]( ULONG n ) const
        { return (SwNodePtr)BigPtrArray::operator[] ( n ); }

//JP 29.09.97: impl. steht im ndindex.hxx - sollte moeglichst bald auf die
//              neue Schnittstelle angepasst werden
    inline SwNodePtr operator[]( const SwNodeIndex& rIdx ) const;

    ULONG Count() const { return BigPtrArray::Count(); }
    void ForEach( FnForEach_SwNodes fnForEach, void* pArgs = 0 )
    {
        BigPtrArray::ForEach( 0, BigPtrArray::Count(),
                                (FnForEach) fnForEach, pArgs );
    }
    void ForEach( ULONG nStt, ULONG nEnd, FnForEach_SwNodes fnForEach, void* pArgs = 0 )
    {
        BigPtrArray::ForEach( nStt, nEnd, (FnForEach) fnForEach, pArgs );
    }
    void ForEach( const SwNodeIndex& rStart, const SwNodeIndex& rEnd,
                    FnForEach_SwNodes fnForEach, void* pArgs = 0 );

    // eine noch leere Section
    SwNode& GetEndOfPostIts() const     { return *pEndOfPostIts; }
    // Section fuer alle Fussnoten
    SwNode& GetEndOfInserts() const     { return *pEndOfInserts; }
    // Section fuer alle Flys/Header/Footers
    SwNode& GetEndOfAutotext() const    { return *pEndOfAutotext; }
    // Section fuer alle Redlines
    SwNode& GetEndOfRedlines() const    { return *pEndOfRedlines; }
    // das ist der letzte EndNode einer SonderSection. Hier nach kommt nur
    // noch die normale ContentSection (also der BodyText)
    SwNode& GetEndOfExtras() const      { return *pEndOfRedlines; }
    // die normale ContentSection (also der BodyText)
    SwNode& GetEndOfContent() const     { return *pEndOfContent; }

    // ist das NodesArray das normale vom Doc? (nicht das UndoNds, .. )
    // Implementierung steht im doc.hxx (weil man dazu Doc kennen muss) !
    BOOL IsDocNodes() const;

    USHORT GetSectionLevel(const SwNodeIndex &rIndex) const;
    void Delete(const SwNodeIndex &rPos, ULONG nNodes = 1);

    BOOL _MoveNodes( const SwNodeRange&, SwNodes& rNodes, const SwNodeIndex&,
                BOOL bNewFrms = TRUE );
    void MoveRange( SwPaM&, SwPosition&, SwNodes& rNodes );

    void _Copy( const SwNodeRange& rRg, const SwNodeIndex& rInsPos,
                BOOL bNewFrms = TRUE ) const
        {   _CopyNodes( rRg, rInsPos, bNewFrms ); }

    void SectionUp( SwNodeRange *);
    void SectionDown( SwNodeRange *pRange, SwStartNodeType = SwNormalStartNode );

    BOOL CheckNodesRange( const SwNodeIndex& rStt, const SwNodeIndex& rEnd ) const;

    void GoStartOfSection(SwNodeIndex *) const;
    void GoEndOfSection(SwNodeIndex *) const;

    SwCntntNode* GoNext(SwNodeIndex *) const;
    SwCntntNode* GoPrevious(SwNodeIndex *) const;

    //Gehe zum naechsten/vorherigen Cntnt/Tabellennode, fuer den
    //es LayoutFrames gibt, dabei Kopf-/Fusszeilen/Rahmen etc. nicht verlassen
    SwNode* GoNextWithFrm(SwNodeIndex *) const;
    SwNode* GoPreviousWithFrm(SwNodeIndex *) const;

    // zum naechsten Content-Node, der nicht geschuetzt oder versteckt ist
    // (beides auf FALSE ==> GoNext/GoPrevious!!!)
    SwCntntNode* GoNextSection( SwNodeIndex *, int bSkipHidden  = TRUE,
                                           int bSkipProtect = TRUE ) const;
    SwCntntNode* GoPrevSection( SwNodeIndex *, int bSkipHidden  = TRUE,
                                           int bSkipProtect = TRUE ) const;

    // erzeuge ein leere Section von Start und EndNode. Darf nur gerufen
    // werden, wenn eine neue Section mit Inhalt erzeugt werden soll.
    // Zum Beispiel bei den Filtern/Undo/...
    SwStartNode* MakeEmptySection( const SwNodeIndex& rIdx,
                                    SwStartNodeType = SwNormalStartNode );

    // die Impl. von "Make...Node" stehen in den angegebenen .ccx-Files
    SwTxtNode *MakeTxtNode( const SwNodeIndex & rWhere,
                            SwTxtFmtColl *pColl,
                            SwAttrSet* pAutoAttr = 0 ); // in ndtxt.cxx
    SwStartNode* MakeTextSection( const SwNodeIndex & rWhere,
                            SwStartNodeType eSttNdTyp,
                            SwTxtFmtColl *pColl,
                            SwAttrSet* pAutoAttr = 0 );

    SwGrfNode *MakeGrfNode( const SwNodeIndex & rWhere,
                            const String& rGrfName,
                            const String& rFltName,
                            const Graphic* pGraphic,
                            SwGrfFmtColl *pColl,
                            SwAttrSet* pAutoAttr = 0,
                            BOOL bDelayed = FALSE );    // in ndgrf.cxx

    SwGrfNode *MakeGrfNode( const SwNodeIndex & rWhere,
                            const GraphicObject& rGrfObj,
                            SwGrfFmtColl *pColl,
                            SwAttrSet* pAutoAttr = 0 ); // in ndgrf.cxx

    SwOLENode *MakeOLENode( const SwNodeIndex & rWhere,
                            const svt::EmbeddedObjectRef&,
                            SwGrfFmtColl *pColl,
                            SwAttrSet* pAutoAttr = 0 ); // in ndole.cxx
    SwOLENode *MakeOLENode( const SwNodeIndex & rWhere,
                            const String &rName,
                            sal_Int64 nAspect,
                            SwGrfFmtColl *pColl,
                            SwAttrSet* pAutoAttr ); // in ndole.cxx

        // Array aller GliederiungsNodes;
    const SwOutlineNodes& GetOutLineNds() const;

    //void UpdateOutlineNode( const SwNode&, BYTE nOldLevel, BYTE nNewLevel );//#outline level,removed by zhaojianwei
        // alle Nodes Updaten - Rule/Format-Aenderung
    void UpdateOutlineNode(SwNode & rNd);

        // fuege die Nodes fuer die Tabelle ein
        // wenn Lines angegeben, erzeuge die Matrix aus Lines & Boxen
        // ansonsten nur die Anzahl von Boxen.
    /* #109161#

       New parameter pAttrSet: If pAttrSet is non-null and contains an
       adjust item it is propagated to the table cells. If there is an
       adjust in pCntntTxtColl or pHeadlineTxtColl this adjust item
       overrides the item in pAttrSet.

     */
    SwTableNode* InsertTable( const SwNodeIndex& rNdIdx,
                        USHORT nBoxes, SwTxtFmtColl* pCntntTxtColl,
                        USHORT nLines = 0, USHORT nRepeat = 0,
                        SwTxtFmtColl* pHeadlineTxtColl = 0,
                        const SwAttrSet * pAttrSet = 0);

        // erzeuge aus dem makierten Bereich eine ausgeglichene Tabelle
    SwTableNode* TextToTable( const SwNodeRange& rRange, sal_Unicode cCh,
                                SwTableFmt* pTblFmt,
                                SwTableLineFmt* pLineFmt,
                                SwTableBoxFmt* pBoxFmt,
                                SwTxtFmtColl* pTxtColl,
                                SwUndoTxtToTbl* pUndo = 0 );

    SwNodeRange * ExpandRangeForTableBox(const SwNodeRange & rRange);

    //create a table from a vector of NodeRanges - API support
    SwTableNode* TextToTable( const TableRanges_t& rTableNodes,
                                SwTableFmt* pTblFmt,
                                SwTableLineFmt* pLineFmt,
                                SwTableBoxFmt* pBoxFmt,
                                SwTxtFmtColl* pTxtColl
                                /*, SwUndo... pUndo*/ );

        // erzeuge aus der Tabelle wieder normalen Text
    BOOL TableToText( const SwNodeRange& rRange, sal_Unicode cCh,
                        SwUndoTblToTxt* = 0 );
        // steht im untbl.cxx und darf nur vom Undoobject gerufen werden
    SwTableNode* UndoTableToText( ULONG nStt, ULONG nEnd,
                        const SwTblToTxtSaves& rSavedData );

        // fuege in der Line, vor der InsPos eine neue Box ein. Das Format
        // wird von der nachfolgenden (vorhergenden;wenn an Ende) genommen
        // in der Line muss schon eine Box vorhanden sein !
    BOOL InsBoxen( SwTableNode*, SwTableLine*, SwTableBoxFmt*,
                        // Formate fuer den TextNode der Box
                        SwTxtFmtColl*, const SfxItemSet* pAutoAttr,
                        USHORT nInsPos, USHORT nCnt = 1 );
        // Splittet eine Tabelle in der Grund-Zeile, in der der Index steht.
        // Alle GrundZeilen dahinter wandern in eine neue Tabelle/-Node.
        // Ist das Flag bCalcNewSize auf TRUE, wird fuer beide neuen Tabellen
        // die neue SSize aus dem Max der Boxen errechnet; vorrausgesetzt,
        // die SSize ist "absolut" gesetzt (LONG_MAX)
        // (Wird zur Zeit nur fuer den RTF-Parser benoetigt)
    SwTableNode* SplitTable( const SwNodeIndex& rPos, BOOL bAfter = TRUE,
                                BOOL bCalcNewSize = FALSE );
        // fuegt 2 Tabellen, die hintereinander stehen, wieder zusammen
    BOOL MergeTable( const SwNodeIndex& rPos, BOOL bWithPrev = TRUE,
                    USHORT nMode = 0, SwHistory* pHistory = 0 );

        // fuege eine neue SwSection ein
    SwSectionNode* InsertTextSection(SwNodeIndex const& rNdIdx,
                                SwSectionFmt& rSectionFmt,
                                SwSectionData const&,
                                SwTOXBase const*const pTOXBase,
                                SwNodeIndex const*const pEnde,
                                bool const bInsAtStart = true,
                                bool const bCreateFrms = true);

        // in welchem Doc steht das Nodes-Array ?
            SwDoc* GetDoc()         { return pMyDoc; }
    const   SwDoc* GetDoc() const   { return pMyDoc; }

        // suche den vorhergehenden [/nachfolgenden ] ContentNode oder
        // TabellenNode mit Frames. Wird kein Ende angeben, dann wird mit
        // dem FrameIndex begonnen; ansonsten, wird mit dem vor rFrmIdx und
        // dem hintern pEnd die Suche gestartet. Sollte kein gueltiger Node
        // gefunden werden, wird 0 returnt. rFrmIdx zeigt auf dem Node mit
        // Frames
    SwNode* FindPrvNxtFrmNode( SwNodeIndex& rFrmIdx,
                                const SwNode* pEnd = 0 ) const;

    //-> #112139#
    SwNode * DocumentSectionStartNode(SwNode * pNode) const;
    SwNode * DocumentSectionEndNode(SwNode * pNode) const;
    //<- #112139#
};

#endif
<|endoftext|>