<commit_before>// Copyright (c) Wiesław Šoltés. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include "StdAfx.h"
#include "..\BatchEncoder.h"
#include "..\utilities\Utilities.h"
#include "WorkThread.h"

DWORD WINAPI ReadThread(LPVOID lpParam)
{
    CPipeContext* pContext = (CPipeContext*)lpParam;
    HANDLE hFile = INVALID_HANDLE_VALUE;
    BYTE pReadBuff[4096];
    BOOL bRes = FALSE;
    DWORD dwReadBytes = 0;
    DWORD dwWriteBytes = 0;
    ULONGLONG nTotalBytesRead = 0;
    ULONGLONG nFileSize = 0;
    int nProgress = -1;
    int nPreviousProgress = -1;
    bool bRunning = true;

    pContext->bError = false;
    pContext->bFinished = false;

    // open existing source file with read-only flag
    hFile = ::CreateFile(pContext->szFileName,
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        0,
        NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        pContext->bError = true;
        pContext->bFinished = true;
        return FALSE;
    }

    nFileSize = ::GetFileSize64(hFile);
    if (nFileSize == 0)
    {
        pContext->bError = true;
        pContext->bFinished = true;
        ::CloseHandle(hFile);
        return FALSE;
    }

    // read/write loop
    do
    {
        // read data from source file
        bRes = ::ReadFile(hFile, pReadBuff, 4096, &dwReadBytes, 0);
        if ((bRes == FALSE) || (dwReadBytes == 0))
            break;

        // NOTE: Sleep(0) solves problem writing to pipe errors
        ::Sleep(0);

        // write data to write pipe
        bRes = ::WriteFile(pContext->hPipe, pReadBuff, dwReadBytes, &dwWriteBytes, 0);
        if ((bRes == FALSE) || (dwWriteBytes == 0) || (dwReadBytes != dwWriteBytes))
            break;

        // count read/write bytes
        nTotalBytesRead += dwReadBytes;
        nProgress = (int)((nTotalBytesRead * 100) / nFileSize);

        if (nProgress != nPreviousProgress)
        {
            bRunning = pContext->pWorkerContext->Callback(pContext->nIndex, nProgress, false);
            nPreviousProgress = nProgress;
        }

        if (bRunning == false)
            break;
    } while (bRes != FALSE);

    // clean up memory
    ::CloseHandle(hFile);

    // close write pipe to allow write thread terminate reading
    ::CloseHandle(pContext->hPipe);

    // check if all data was processed
    if (nTotalBytesRead != nFileSize)
    {
        pContext->bError = true;
        pContext->bFinished = true;
        return FALSE;
    }

    pContext->bError = false;
    pContext->bFinished = true;
    return TRUE;
}
<commit_msg>Delete ReadThread.cpp<commit_after><|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 2001, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 * $Log$
 * Revision 1.4  2002/12/18 14:17:55  gareth
 * Fix to bug #13438. When you eant a vector that calls delete[] on its members you should use RefArrayVectorOf.
 *
 * Revision 1.3  2002/11/04 14:53:28  tng
 * C++ Namespace Support.
 *
 * Revision 1.2  2002/02/14 15:17:31  peiyongz
 * getEnumString()
 *
 * Revision 1.1.1.1  2002/02/01 22:22:43  peiyongz
 * sane_include
 *
 * Revision 1.9  2001/12/13 16:48:29  peiyongz
 * Avoid dangling pointer
 *
 * Revision 1.8  2001/09/05 20:49:10  knoaman
 * Fix for complexTypes with mixed content model.
 *
 * Revision 1.7  2001/08/31 16:53:41  knoaman
 * Misc. fixes.
 *
 * Revision 1.6  2001/08/24 17:12:01  knoaman
 * Add support for anySimpleType.
 * Remove parameter 'baseValidator' from the virtual method 'newInstance'.
 *
 * Revision 1.5  2001/08/21 20:05:41  peiyongz
 * put back changes introduced in 1.3
 *
 * Revision 1.3  2001/08/16 14:41:38  knoaman
 * implementation of virtual methods.
 *
 * Revision 1.2  2001/07/24 21:23:40  tng
 * Schema: Use DatatypeValidator for ID/IDREF/ENTITY/ENTITIES/NOTATION.
 *
 * Revision 1.1  2001/07/13 14:10:40  peiyongz
 * UnionDTV
 *
 */

#if !defined(UNION_DATATYPEVALIDATOR_HPP)
#define UNION_DATATYPEVALIDATOR_HPP

#include <xercesc/validators/datatype/DatatypeValidator.hpp>
#include <xercesc/validators/schema/SchemaSymbols.hpp>

XERCES_CPP_NAMESPACE_BEGIN

class VALIDATORS_EXPORT UnionDatatypeValidator : public DatatypeValidator
{
public:

    // -----------------------------------------------------------------------
    //  Public ctor/dtor
    // -----------------------------------------------------------------------
	/** @name Constructor. */
    //@{

    UnionDatatypeValidator();

    //
    // constructor for native Union datatype validator
    // <simpleType name="nativeUnion">
    //      <union   memberTypes="member1 member2 ...">
    // </simpleType>
    //
    UnionDatatypeValidator(RefVectorOf<DatatypeValidator>* const memberTypeValidators
                         , const int                             finalSet);

    //
    // constructor for derived Union datatype validator
    // <simpleType name="derivedUnion">
    //      <restriction base="nativeUnion">
    //          <pattern     value="patter_value"/>
    //          <enumeartion value="enum_value"/>
    //      </restriction>
    // </simpleType>
    //
    UnionDatatypeValidator(DatatypeValidator*            const baseValidator
                         , RefHashTableOf<KVStringPair>* const facets
                         , RefArrayVectorOf<XMLCh>*           const enums
                         , const int                           finalSet);

    virtual ~UnionDatatypeValidator();

	//@}

	virtual const RefArrayVectorOf<XMLCh>* getEnumString() const;

    // -----------------------------------------------------------------------
    // Getter methods
    // -----------------------------------------------------------------------
    /** @name Getter Functions */
    //@{
    /**
      * Returns whether the type is atomic or not
      */
    virtual bool isAtomic() const;

    //@}

    // -----------------------------------------------------------------------
    // Validation methods
    // -----------------------------------------------------------------------
    /** @name Validation Function */
    //@{

    /**
     * validate that a string matches the boolean datatype
     * @param content A string containing the content to be validated
     *
     * @exception throws InvalidDatatypeException if the content is
     * is not valid.
     */

	void validate(const XMLCh* const content);

    /**
      * Checks whether a given type can be used as a substitute
      *
      * @param  toCheck    A datatype validator of the type to be used as a
      *                    substitute
      *
      * To be redefined in UnionDatatypeValidator
      */

    virtual bool isSubstitutableBy(const DatatypeValidator* const toCheck);

    //@}

    // -----------------------------------------------------------------------
    // Compare methods
    // -----------------------------------------------------------------------
    /** @name Compare Function */
    //@{

    /**
     * Compare two boolean data types
     *
     * @param content1
     * @param content2
     * @return
     */
    int compare(const XMLCh* const, const XMLCh* const);

    //@}

    /**
      * Returns an instance of the base datatype validator class
	  * Used by the DatatypeValidatorFactory.
      */
    DatatypeValidator* newInstance(RefHashTableOf<KVStringPair>* const facets
                                 , RefArrayVectorOf<XMLCh>*           const enums
                                 , const int                           finalSet);

    RefVectorOf<DatatypeValidator>* getMemberTypeValidators() const;

private:

    void checkContent(const XMLCh* const content, bool asBase);

    void init(DatatypeValidator*            const baseValidator
            , RefHashTableOf<KVStringPair>* const facets
            , RefArrayVectorOf<XMLCh>*           const enums);

    void cleanUp();

    RefArrayVectorOf<XMLCh>*  getEnumeration() const;

    void                 setEnumeration(RefArrayVectorOf<XMLCh>*, bool);

    // -----------------------------------------------------------------------
    //  Private data members
    //
    //  fEnumeration
    //      we own it.
    //
    //  fMemberTypeValidators
    //      we own it.
    //
    // -----------------------------------------------------------------------
     bool                 fEnumerationInherited;
     RefArrayVectorOf<XMLCh>*  fEnumeration;
     RefVectorOf<DatatypeValidator>*  fMemberTypeValidators;
};

inline DatatypeValidator* UnionDatatypeValidator::newInstance(
                                      RefHashTableOf<KVStringPair>* const facets
                                    , RefArrayVectorOf<XMLCh>*           const enums
                                    , const int                           finalSet)
{
    return (DatatypeValidator*) new UnionDatatypeValidator(this, facets, enums, finalSet);
}

inline void UnionDatatypeValidator::validate( const XMLCh* const content)
{
    checkContent(content, false);
}

inline void UnionDatatypeValidator::cleanUp()
{
    //~RefVectorOf will delete all adopted elements
    if ( !fEnumerationInherited && fEnumeration)
        delete fEnumeration;

    if (fMemberTypeValidators)
        delete fMemberTypeValidators;
}

inline RefArrayVectorOf<XMLCh>* UnionDatatypeValidator:: getEnumeration() const
{
    return fEnumeration;
}

inline void UnionDatatypeValidator::setEnumeration(RefArrayVectorOf<XMLCh>* enums
                                                 , bool                inherited)
{
    if (enums)
    {
        if (  !fEnumerationInherited && fEnumeration)
            delete fEnumeration;

        fEnumeration = enums;
        fEnumerationInherited = inherited;
        setFacetsDefined(DatatypeValidator::FACET_ENUMERATION);
    }
}

//
// get the native UnionDTV's fMemberTypeValidators
//
inline
RefVectorOf<DatatypeValidator>* UnionDatatypeValidator::getMemberTypeValidators() const
{
    UnionDatatypeValidator* thisdv = (UnionDatatypeValidator*)this; // cast away constness

    while (thisdv->getBaseValidator())
        thisdv = (UnionDatatypeValidator*) thisdv->getBaseValidator();

    return thisdv->fMemberTypeValidators;
}

inline bool UnionDatatypeValidator::isAtomic() const {

    RefVectorOf<DatatypeValidator>* memberDVs = getMemberTypeValidators();

    if (!memberDVs) {
        return false;
    }

    unsigned int memberSize = memberDVs->size();

    for (unsigned int i=0; i < memberSize; i++) {
        if (!memberDVs->elementAt(i)->isAtomic()) {
            return false;
        }
    }

    return true;
}

inline bool UnionDatatypeValidator::isSubstitutableBy(const DatatypeValidator* const toCheck) {

    if (toCheck == this) {
        return true;
    }

    unsigned int memberSize = fMemberTypeValidators->size();

    for (unsigned int i=0; i < memberSize; i++) {
        if (fMemberTypeValidators->elementAt(i)->isSubstitutableBy(toCheck)) {
            return true;
        }
    }

    return false;
}

XERCES_CPP_NAMESPACE_END

#endif

/**
  * End of file UnionDatatypeValidator.hpp
  */
<commit_msg>[Bug 14912] crashes inside UnionDatatypeValidator::isSubstitutableBy.   Patch from Alberto Massari.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 2001, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 * $Log$
 * Revision 1.5  2003/01/10 16:48:47  tng
 * [Bug 14912] crashes inside UnionDatatypeValidator::isSubstitutableBy.   Patch from Alberto Massari.
 *
 * Revision 1.4  2002/12/18 14:17:55  gareth
 * Fix to bug #13438. When you eant a vector that calls delete[] on its members you should use RefArrayVectorOf.
 *
 * Revision 1.3  2002/11/04 14:53:28  tng
 * C++ Namespace Support.
 *
 * Revision 1.2  2002/02/14 15:17:31  peiyongz
 * getEnumString()
 *
 * Revision 1.1.1.1  2002/02/01 22:22:43  peiyongz
 * sane_include
 *
 * Revision 1.9  2001/12/13 16:48:29  peiyongz
 * Avoid dangling pointer
 *
 * Revision 1.8  2001/09/05 20:49:10  knoaman
 * Fix for complexTypes with mixed content model.
 *
 * Revision 1.7  2001/08/31 16:53:41  knoaman
 * Misc. fixes.
 *
 * Revision 1.6  2001/08/24 17:12:01  knoaman
 * Add support for anySimpleType.
 * Remove parameter 'baseValidator' from the virtual method 'newInstance'.
 *
 * Revision 1.5  2001/08/21 20:05:41  peiyongz
 * put back changes introduced in 1.3
 *
 * Revision 1.3  2001/08/16 14:41:38  knoaman
 * implementation of virtual methods.
 *
 * Revision 1.2  2001/07/24 21:23:40  tng
 * Schema: Use DatatypeValidator for ID/IDREF/ENTITY/ENTITIES/NOTATION.
 *
 * Revision 1.1  2001/07/13 14:10:40  peiyongz
 * UnionDTV
 *
 */

#if !defined(UNION_DATATYPEVALIDATOR_HPP)
#define UNION_DATATYPEVALIDATOR_HPP

#include <xercesc/validators/datatype/DatatypeValidator.hpp>
#include <xercesc/validators/schema/SchemaSymbols.hpp>

XERCES_CPP_NAMESPACE_BEGIN

class VALIDATORS_EXPORT UnionDatatypeValidator : public DatatypeValidator
{
public:

    // -----------------------------------------------------------------------
    //  Public ctor/dtor
    // -----------------------------------------------------------------------
	/** @name Constructor. */
    //@{

    UnionDatatypeValidator();

    //
    // constructor for native Union datatype validator
    // <simpleType name="nativeUnion">
    //      <union   memberTypes="member1 member2 ...">
    // </simpleType>
    //
    UnionDatatypeValidator(RefVectorOf<DatatypeValidator>* const memberTypeValidators
                         , const int                             finalSet);

    //
    // constructor for derived Union datatype validator
    // <simpleType name="derivedUnion">
    //      <restriction base="nativeUnion">
    //          <pattern     value="patter_value"/>
    //          <enumeartion value="enum_value"/>
    //      </restriction>
    // </simpleType>
    //
    UnionDatatypeValidator(DatatypeValidator*            const baseValidator
                         , RefHashTableOf<KVStringPair>* const facets
                         , RefArrayVectorOf<XMLCh>*           const enums
                         , const int                           finalSet);

    virtual ~UnionDatatypeValidator();

	//@}

	virtual const RefArrayVectorOf<XMLCh>* getEnumString() const;

    // -----------------------------------------------------------------------
    // Getter methods
    // -----------------------------------------------------------------------
    /** @name Getter Functions */
    //@{
    /**
      * Returns whether the type is atomic or not
      */
    virtual bool isAtomic() const;

    //@}

    // -----------------------------------------------------------------------
    // Validation methods
    // -----------------------------------------------------------------------
    /** @name Validation Function */
    //@{

    /**
     * validate that a string matches the boolean datatype
     * @param content A string containing the content to be validated
     *
     * @exception throws InvalidDatatypeException if the content is
     * is not valid.
     */

	void validate(const XMLCh* const content);

    /**
      * Checks whether a given type can be used as a substitute
      *
      * @param  toCheck    A datatype validator of the type to be used as a
      *                    substitute
      *
      * To be redefined in UnionDatatypeValidator
      */

    virtual bool isSubstitutableBy(const DatatypeValidator* const toCheck);

    //@}

    // -----------------------------------------------------------------------
    // Compare methods
    // -----------------------------------------------------------------------
    /** @name Compare Function */
    //@{

    /**
     * Compare two boolean data types
     *
     * @param content1
     * @param content2
     * @return
     */
    int compare(const XMLCh* const, const XMLCh* const);

    //@}

    /**
      * Returns an instance of the base datatype validator class
	  * Used by the DatatypeValidatorFactory.
      */
    DatatypeValidator* newInstance(RefHashTableOf<KVStringPair>* const facets
                                 , RefArrayVectorOf<XMLCh>*           const enums
                                 , const int                           finalSet);

    RefVectorOf<DatatypeValidator>* getMemberTypeValidators() const;

private:

    void checkContent(const XMLCh* const content, bool asBase);

    void init(DatatypeValidator*            const baseValidator
            , RefHashTableOf<KVStringPair>* const facets
            , RefArrayVectorOf<XMLCh>*           const enums);

    void cleanUp();

    RefArrayVectorOf<XMLCh>*  getEnumeration() const;

    void                 setEnumeration(RefArrayVectorOf<XMLCh>*, bool);

    // -----------------------------------------------------------------------
    //  Private data members
    //
    //  fEnumeration
    //      we own it.
    //
    //  fMemberTypeValidators
    //      we own it.
    //
    // -----------------------------------------------------------------------
     bool                 fEnumerationInherited;
     RefArrayVectorOf<XMLCh>*  fEnumeration;
     RefVectorOf<DatatypeValidator>*  fMemberTypeValidators;
};

inline DatatypeValidator* UnionDatatypeValidator::newInstance(
                                      RefHashTableOf<KVStringPair>* const facets
                                    , RefArrayVectorOf<XMLCh>*           const enums
                                    , const int                           finalSet)
{
    return (DatatypeValidator*) new UnionDatatypeValidator(this, facets, enums, finalSet);
}

inline void UnionDatatypeValidator::validate( const XMLCh* const content)
{
    checkContent(content, false);
}

inline void UnionDatatypeValidator::cleanUp()
{
    //~RefVectorOf will delete all adopted elements
    if ( !fEnumerationInherited && fEnumeration)
        delete fEnumeration;

    if (fMemberTypeValidators)
        delete fMemberTypeValidators;
}

inline RefArrayVectorOf<XMLCh>* UnionDatatypeValidator:: getEnumeration() const
{
    return fEnumeration;
}

inline void UnionDatatypeValidator::setEnumeration(RefArrayVectorOf<XMLCh>* enums
                                                 , bool                inherited)
{
    if (enums)
    {
        if (  !fEnumerationInherited && fEnumeration)
            delete fEnumeration;

        fEnumeration = enums;
        fEnumerationInherited = inherited;
        setFacetsDefined(DatatypeValidator::FACET_ENUMERATION);
    }
}

//
// get the native UnionDTV's fMemberTypeValidators
//
inline
RefVectorOf<DatatypeValidator>* UnionDatatypeValidator::getMemberTypeValidators() const
{
    UnionDatatypeValidator* thisdv = (UnionDatatypeValidator*)this; // cast away constness

    while (thisdv->getBaseValidator())
        thisdv = (UnionDatatypeValidator*) thisdv->getBaseValidator();

    return thisdv->fMemberTypeValidators;
}

inline bool UnionDatatypeValidator::isAtomic() const {

    RefVectorOf<DatatypeValidator>* memberDVs = getMemberTypeValidators();

    if (!memberDVs) {
        return false;
    }

    unsigned int memberSize = memberDVs->size();

    for (unsigned int i=0; i < memberSize; i++) {
        if (!memberDVs->elementAt(i)->isAtomic()) {
            return false;
        }
    }

    return true;
}

inline bool UnionDatatypeValidator::isSubstitutableBy(const DatatypeValidator* const toCheck) {

    if (toCheck == this) {
        return true;
    }

    if (fMemberTypeValidators) {
        unsigned int memberSize = fMemberTypeValidators->size();

        for (unsigned int i=0; i < memberSize; i++) {
            if (fMemberTypeValidators->elementAt(i)->isSubstitutableBy(toCheck)) {
                return true;
            }
        }
    }
    return false;
}

XERCES_CPP_NAMESPACE_END

#endif

/**
  * End of file UnionDatatypeValidator.hpp
  */
<|endoftext|>


<commit_before>// __BEGIN_LICENSE__
//  Copyright (c) 2009-2012, United States Government as represented by the
//  Administrator of the National Aeronautics and Space Administration. All
//  rights reserved.
//
//  The NGT platform is 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
//
//  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.
// __END_LICENSE__

#include <vw/Core.h>
#include <vw/FileIO.h>
#include <vw/Image.h>
#include <vw/Cartography.h>
using namespace vw;

#include <asp/Core/Macros.h>
#include <asp/Core/Common.h>
#include <asp/Sessions/DG/StereoSessionDG.h>
#include <asp/Sessions/DG/XML.h>
#include <asp/Sessions/RPC/RPCMapTransform.h>
namespace po = boost::program_options;
namespace fs = boost::filesystem;

#include "ogr_spatialref.h"

struct Options : asp::BaseOptions {
  // Input
  std::string dem_file, image_file, camera_model_file, output_file;

  // Settings
  std::string target_srs_string;
  float target_resolution;
  BBox2 target_projwin;
  double nodata_value;
};

void handle_arguments( int argc, char *argv[], Options& opt ) {
  po::options_description general_options("");
  general_options.add_options()
    ("nodata-value", po::value(&opt.nodata_value), "Nodata value to use on output.")
    ("t_srs", po::value(&opt.target_srs_string), "Target spatial reference set. This mimicks the  gdal option.")
    ("tr", po::value(&opt.target_resolution)->default_value(0), "Set output file resolution (in target georeferenced units per pixel)")
    ("t_projwin", po::value(&opt.target_projwin),
     "Selects a subwindow from the source image for copying but with the corners given in georeferenced coordinates (xmin ymin xmax ymax). Max is exclusive.");

  general_options.add( asp::BaseOptionsDescription(opt) );

  po::options_description positional("");
  positional.add_options()
    ("dem", po::value(&opt.dem_file))
    ("camera-image", po::value(&opt.image_file))
    ("camera-model", po::value(&opt.camera_model_file))
    ("output-file", po::value(&opt.output_file));

  po::positional_options_description positional_desc;
  positional_desc.add("dem", 1);
  positional_desc.add("camera-image",1);
  positional_desc.add("camera-model",1);
  positional_desc.add("output-file",1);

  std::string usage("[options] <dem> <camera-image> <camera-model> <output>");
  po::variables_map vm =
    asp::check_command_line( argc, argv, opt, general_options,
                             positional, positional_desc, usage );

  if ( !vm.count("dem") || !vm.count("camera-image") ||
       !vm.count("camera-model") || !vm.count("t_srs") )
    vw_throw( ArgumentErr() << "Requires <dem> <camera-image> <camera-model> and <t_srs> input in order to proceed.\n\n"
              << usage << general_options );

  if ( opt.output_file.empty() )
    opt.output_file = fs::basename( opt.image_file ) + "_rpcmapped.tif";
}

int main( int argc, char* argv[] ) {

  Options opt;
  try {
    handle_arguments( argc, argv, opt );

    // Load DEM
    boost::shared_ptr<DiskImageResource>
      dem_rsrc( DiskImageResource::open( opt.dem_file ) );
    cartography::GeoReference dem_georef;
    read_georeference( dem_georef, opt.dem_file );

    // Read projection. Work out output bounding box in points using
    // original camera model.
    cartography::GeoReference target_georef;
    boost::replace_first(opt.target_srs_string,
                         "IAU2000:","DICT:IAU2000.wkt,");
    VW_OUT(DebugMessage,"asp") << "Asking GDAL to decipher: \""
                               << opt.target_srs_string << "\"\n";
    OGRSpatialReference gdal_spatial_ref;
    if (gdal_spatial_ref.SetFromUserInput( opt.target_srs_string.c_str() ))
      vw_throw( ArgumentErr() << "Failed to parse: \"" << opt.target_srs_string << "\"." );
    char *wkt = NULL;
    gdal_spatial_ref.exportToWkt( &wkt );
    std::string wkt_string(wkt);
    delete[] wkt;

    target_georef.set_wkt( wkt_string );

    // Work out target resolution and image size
    asp::StereoSessionDG session;
    boost::shared_ptr<camera::CameraModel>
      camera_model( session.camera_model( opt.image_file, opt.camera_model_file ) );
    Vector2i image_size = asp::file_image_size( opt.image_file );
    BBox2 point_bounds =
      opt.target_resolution <= 0 ?
      camera_bbox( target_georef, camera_model,
                   image_size.x(), image_size.y(),
                   opt.target_resolution ) :
      camera_bbox( target_georef, camera_model,
                   image_size.x(), image_size.y() );
    if ( opt.target_projwin != BBox2() ) {
      point_bounds = opt.target_projwin;
      if ( point_bounds.min().y() > point_bounds.max().y() )
        std::swap( point_bounds.min().y(),
                   point_bounds.max().y() );
      vw_out() << "Cropping to " << point_bounds << " pt. " << std::endl;
      point_bounds.max().x() -= opt.target_resolution;
      point_bounds.min().y() += opt.target_resolution;
    }

    {
      Matrix3x3 transform = math::identity_matrix<3>();
      transform(0,0) = opt.target_resolution;
      transform(1,1) = -opt.target_resolution;
      transform(0,2) = point_bounds.min().x();
      transform(1,2) = point_bounds.max().y();
      if ( target_georef.pixel_interpretation() ==
           cartography::GeoReference::PixelAsArea ) {
        transform(0,2) -= 0.5 * opt.target_resolution;
        transform(1,2) += 0.5 * opt.target_resolution;
      }
      target_georef.set_transform( transform );
    }
    vw_out() << "Output Georeference:\n" << target_georef << std::endl;

    BBox2i target_image_size =
      target_georef.point_to_pixel_bbox( point_bounds );
    vw_out() << "Creating output file that is " << target_image_size.size() << " px.\n";

    // Load RPC
    asp::RPCXML xml;
    xml.read_from_file( opt.camera_model_file );

    boost::shared_ptr<DiskImageResource>
      src_rsrc( DiskImageResource::open( opt.image_file ) );

    // Raster output image
    if ( src_rsrc->has_nodata_read() ) {
      asp::block_write_gdal_image( opt.output_file,
                                   apply_mask(transform( create_mask( DiskImageView<float>( src_rsrc), src_rsrc->nodata_read() ),
                                                         asp::RPCMapTransform( *xml.rpc_ptr(),
                                                                               target_georef,
                                                                               dem_georef,
                                                                               dem_rsrc ),
                                                         target_image_size.width(),
                                                         target_image_size.height(),
                                                         ValueEdgeExtension<PixelMask<float> >( PixelMask<float>() ),
                                                         BicubicInterpolation() ),
                                              src_rsrc->nodata_read() ),
                                   target_georef, opt,
                                   TerminalProgressCallback("","") );
    } else {
      asp::block_write_gdal_image(opt.output_file,
                                  transform( DiskImageView<float>( src_rsrc ),
                                             asp::RPCMapTransform( *xml.rpc_ptr(),
                                                                   target_georef,
                                                                   dem_georef,
                                                                   dem_rsrc ),
                                             target_image_size.width(),
                                             target_image_size.height(),
                                             ZeroEdgeExtension(),
                                             BicubicInterpolation() ),
                                  target_georef, opt,
                                  TerminalProgressCallback("","") );
    }

  } ASP_STANDARD_CATCHES;

  return 0;
}
<commit_msg>rpc_mapproject: Add a safety check for unprojected input<commit_after>// __BEGIN_LICENSE__
//  Copyright (c) 2009-2012, United States Government as represented by the
//  Administrator of the National Aeronautics and Space Administration. All
//  rights reserved.
//
//  The NGT platform is 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
//
//  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.
// __END_LICENSE__

#include <vw/Core.h>
#include <vw/FileIO.h>
#include <vw/Image.h>
#include <vw/Cartography.h>
using namespace vw;

#include <asp/Core/Macros.h>
#include <asp/Core/Common.h>
#include <asp/Sessions/DG/StereoSessionDG.h>
#include <asp/Sessions/DG/XML.h>
#include <asp/Sessions/RPC/RPCMapTransform.h>
namespace po = boost::program_options;
namespace fs = boost::filesystem;

#include "ogr_spatialref.h"

struct Options : asp::BaseOptions {
  // Input
  std::string dem_file, image_file, camera_model_file, output_file;

  // Settings
  std::string target_srs_string;
  float target_resolution;
  BBox2 target_projwin;
  double nodata_value;
};

void handle_arguments( int argc, char *argv[], Options& opt ) {
  po::options_description general_options("");
  general_options.add_options()
    ("nodata-value", po::value(&opt.nodata_value), "Nodata value to use on output.")
    ("t_srs", po::value(&opt.target_srs_string), "Target spatial reference set. This mimicks the  gdal option.")
    ("tr", po::value(&opt.target_resolution)->default_value(0), "Set output file resolution (in target georeferenced units per pixel)")
    ("t_projwin", po::value(&opt.target_projwin),
     "Selects a subwindow from the source image for copying but with the corners given in georeferenced coordinates (xmin ymin xmax ymax). Max is exclusive.");

  general_options.add( asp::BaseOptionsDescription(opt) );

  po::options_description positional("");
  positional.add_options()
    ("dem", po::value(&opt.dem_file))
    ("camera-image", po::value(&opt.image_file))
    ("camera-model", po::value(&opt.camera_model_file))
    ("output-file", po::value(&opt.output_file));

  po::positional_options_description positional_desc;
  positional_desc.add("dem", 1);
  positional_desc.add("camera-image",1);
  positional_desc.add("camera-model",1);
  positional_desc.add("output-file",1);

  std::string usage("[options] <dem> <camera-image> <camera-model> <output>");
  po::variables_map vm =
    asp::check_command_line( argc, argv, opt, general_options,
                             positional, positional_desc, usage );

  if ( !vm.count("dem") || !vm.count("camera-image") ||
       !vm.count("camera-model") || !vm.count("t_srs") )
    vw_throw( ArgumentErr() << "Requires <dem> <camera-image> <camera-model> and <t_srs> input in order to proceed.\n\n"
              << usage << general_options );

  if ( opt.output_file.empty() )
    opt.output_file = fs::basename( opt.image_file ) + "_rpcmapped.tif";
}

int main( int argc, char* argv[] ) {

  Options opt;
  try {
    handle_arguments( argc, argv, opt );

    // Safety check that the users are not trying to map project map
    // projected images.
    {
      cartography::GeoReference dummy_georef;
      VW_ASSERT( !read_georeference( dummy_georef, opt.image_file ),
                 ArgumentErr() << "Your input camera image is already map projected. The expected input is required to be unprojected or raw camera imagery." );
    }

    // Load DEM
    boost::shared_ptr<DiskImageResource>
      dem_rsrc( DiskImageResource::open( opt.dem_file ) );
    cartography::GeoReference dem_georef;
    read_georeference( dem_georef, opt.dem_file );

    // Read projection. Work out output bounding box in points using
    // original camera model.
    cartography::GeoReference target_georef;
    boost::replace_first(opt.target_srs_string,
                         "IAU2000:","DICT:IAU2000.wkt,");
    VW_OUT(DebugMessage,"asp") << "Asking GDAL to decipher: \""
                               << opt.target_srs_string << "\"\n";
    OGRSpatialReference gdal_spatial_ref;
    if (gdal_spatial_ref.SetFromUserInput( opt.target_srs_string.c_str() ))
      vw_throw( ArgumentErr() << "Failed to parse: \"" << opt.target_srs_string << "\"." );
    char *wkt = NULL;
    gdal_spatial_ref.exportToWkt( &wkt );
    std::string wkt_string(wkt);
    delete[] wkt;

    target_georef.set_wkt( wkt_string );

    // Work out target resolution and image size
    asp::StereoSessionDG session;
    boost::shared_ptr<camera::CameraModel>
      camera_model( session.camera_model( opt.image_file, opt.camera_model_file ) );
    Vector2i image_size = asp::file_image_size( opt.image_file );
    BBox2 point_bounds =
      opt.target_resolution <= 0 ?
      camera_bbox( target_georef, camera_model,
                   image_size.x(), image_size.y(),
                   opt.target_resolution ) :
      camera_bbox( target_georef, camera_model,
                   image_size.x(), image_size.y() );
    if ( opt.target_projwin != BBox2() ) {
      point_bounds = opt.target_projwin;
      if ( point_bounds.min().y() > point_bounds.max().y() )
        std::swap( point_bounds.min().y(),
                   point_bounds.max().y() );
      vw_out() << "Cropping to " << point_bounds << " pt. " << std::endl;
      point_bounds.max().x() -= opt.target_resolution;
      point_bounds.min().y() += opt.target_resolution;
    }

    {
      Matrix3x3 transform = math::identity_matrix<3>();
      transform(0,0) = opt.target_resolution;
      transform(1,1) = -opt.target_resolution;
      transform(0,2) = point_bounds.min().x();
      transform(1,2) = point_bounds.max().y();
      if ( target_georef.pixel_interpretation() ==
           cartography::GeoReference::PixelAsArea ) {
        transform(0,2) -= 0.5 * opt.target_resolution;
        transform(1,2) += 0.5 * opt.target_resolution;
      }
      target_georef.set_transform( transform );
    }
    vw_out() << "Output Georeference:\n" << target_georef << std::endl;

    BBox2i target_image_size =
      target_georef.point_to_pixel_bbox( point_bounds );
    vw_out() << "Creating output file that is " << target_image_size.size() << " px.\n";

    // Load RPC
    asp::RPCXML xml;
    xml.read_from_file( opt.camera_model_file );

    boost::shared_ptr<DiskImageResource>
      src_rsrc( DiskImageResource::open( opt.image_file ) );

    // Raster output image
    if ( src_rsrc->has_nodata_read() ) {
      asp::block_write_gdal_image( opt.output_file,
                                   apply_mask(transform( create_mask( DiskImageView<float>( src_rsrc), src_rsrc->nodata_read() ),
                                                         asp::RPCMapTransform( *xml.rpc_ptr(),
                                                                               target_georef,
                                                                               dem_georef,
                                                                               dem_rsrc ),
                                                         target_image_size.width(),
                                                         target_image_size.height(),
                                                         ValueEdgeExtension<PixelMask<float> >( PixelMask<float>() ),
                                                         BicubicInterpolation() ),
                                              src_rsrc->nodata_read() ),
                                   target_georef, opt,
                                   TerminalProgressCallback("","") );
    } else {
      asp::block_write_gdal_image(opt.output_file,
                                  transform( DiskImageView<float>( src_rsrc ),
                                             asp::RPCMapTransform( *xml.rpc_ptr(),
                                                                   target_georef,
                                                                   dem_georef,
                                                                   dem_rsrc ),
                                             target_image_size.width(),
                                             target_image_size.height(),
                                             ZeroEdgeExtension(),
                                             BicubicInterpolation() ),
                                  target_georef, opt,
                                  TerminalProgressCallback("","") );
    }

  } ASP_STANDARD_CATCHES;

  return 0;
}
<|endoftext|>


<commit_before>#ifndef sw_x0_io_null_filter_hpp
#define sw_x0_io_null_filter_hpp 1

#include <x0/io/filter.hpp>

namespace x0 {

/** simply passes incoming buffers through */
class null_filter :
	public filter
{
public:
	null_filter() {}

	virtual buffer process(const buffer& data)
	{
		return data;
	}
};

} // namespace x0

#endif
<commit_msg>buffer: compile fix (null_filter)<commit_after>#ifndef sw_x0_io_null_filter_hpp
#define sw_x0_io_null_filter_hpp 1

#include <x0/io/filter.hpp>

namespace x0 {

/** simply passes incoming buffers through */
class null_filter :
	public filter
{
public:
	null_filter() {}

	virtual buffer process(const buffer::view& data)
	{
		return buffer(data);
	}
};

} // namespace x0

#endif
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

/*
 * This file includes unit tests for NetEQ.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>  // memset

#include <string>
#include <vector>

#include "gtest/gtest.h"

#include "modules/audio_coding/neteq/test/NETEQTEST_CodecClass.h"
#include "modules/audio_coding/neteq/test/NETEQTEST_NetEQClass.h"
#include "modules/audio_coding/neteq/test/NETEQTEST_RTPpacket.h"
#include "typedefs.h"  // NOLINT(build/include)
#include "modules/audio_coding/neteq/interface/webrtc_neteq.h"
#include "modules/audio_coding/neteq/interface/webrtc_neteq_help_macros.h"
#include "testsupport/fileutils.h"

namespace webrtc {

class NetEqDecodingTest : public ::testing::Test {
 protected:
  NetEqDecodingTest();
  virtual void SetUp();
  virtual void TearDown();
  void SelectDecoders(WebRtcNetEQDecoder* used_codec);
  void LoadDecoders();
  void DecodeAndCompare(const std::string &rtp_file,
                        const std::string &ref_file);

  NETEQTEST_NetEQClass* neteq_inst_;
  std::vector<NETEQTEST_Decoder*> dec_;
};

NetEqDecodingTest::NetEqDecodingTest() : neteq_inst_(NULL) {}

void NetEqDecodingTest::SetUp() {
  WebRtcNetEQDecoder usedCodec[kDecoderReservedEnd - 1];

  SelectDecoders(usedCodec);
  neteq_inst_ = new NETEQTEST_NetEQClass(usedCodec, dec_.size(), 8000,
                                         kTCPLargeJitter);
  ASSERT_TRUE(neteq_inst_);
  LoadDecoders();
}

void NetEqDecodingTest::TearDown() {
  if (neteq_inst_)
    delete neteq_inst_;
  for (size_t i = 0; i < dec_.size(); ++i) {
    if (dec_[i])
      delete dec_[i];
  }
}

void NetEqDecodingTest::SelectDecoders(WebRtcNetEQDecoder* used_codec) {
  *used_codec++ = kDecoderPCMu;
  dec_.push_back(new decoder_PCMU(0));
  *used_codec++ = kDecoderPCMa;
  dec_.push_back(new decoder_PCMA(8));
  *used_codec++ = kDecoderILBC;
  dec_.push_back(new decoder_ILBC(102));
  *used_codec++ = kDecoderISAC;
  dec_.push_back(new decoder_iSAC(103));
  *used_codec++ = kDecoderISACswb;
  dec_.push_back(new decoder_iSACSWB(104));
  *used_codec++ = kDecoderPCM16B;
  dec_.push_back(new decoder_PCM16B_NB(93));
  *used_codec++ = kDecoderPCM16Bwb;
  dec_.push_back(new decoder_PCM16B_WB(94));
  *used_codec++ = kDecoderPCM16Bswb32kHz;
  dec_.push_back(new decoder_PCM16B_SWB32(95));
  *used_codec++ = kDecoderCNG;
  dec_.push_back(new decoder_CNG(13));
}

void NetEqDecodingTest::LoadDecoders() {
  for (size_t i = 0; i < dec_.size(); ++i) {
    ASSERT_EQ(0, dec_[i]->loadToNetEQ(*neteq_inst_));
  }
}

void NetEqDecodingTest::DecodeAndCompare(const std::string &rtp_file,
                                         const std::string &ref_file) {
  NETEQTEST_RTPpacket rtp;
  FILE* rtp_fp = fopen(rtp_file.c_str(), "rb");
  ASSERT_TRUE(rtp_fp != NULL);
  ASSERT_EQ(0, NETEQTEST_RTPpacket::skipFileHeader(rtp_fp));
  ASSERT_GT(rtp.readFromFile(rtp_fp), 0);

  FILE* ref_fp = NULL;
  FILE* out_fp = NULL;
  if (!ref_file.empty()) {
    ref_fp = fopen(ref_file.c_str(), "rb");
    ASSERT_TRUE(ref_fp != NULL);
  } else {
    std::string out_file = webrtc::test::OutputPath() + "neteq_out.pcm";
    out_fp = fopen(out_file.c_str(), "wb");
    ASSERT_TRUE(out_fp != NULL);
  }

  unsigned int sim_clock = 0;
  // NetEQ must be polled for data once every 10 ms. Thus, neither of the
  // constants below can be changed.
  const int kTimeStepMs = 10;
  const int kBlockSize8kHz = kTimeStepMs * 8;
  const int kBlockSize16kHz = kTimeStepMs * 16;
  const int kBlockSize32kHz = kTimeStepMs * 32;
  const int kMaxBlockSize = kBlockSize32kHz;
  while (rtp.dataLen() >= 0) {
    // Check if time to receive.
    while ((sim_clock >= rtp.time()) &&
           (rtp.dataLen() >= 0)) {
      if (rtp.dataLen() > 0) {
        ASSERT_EQ(0, neteq_inst_->recIn(rtp));
      }
      // Get next packet.
      ASSERT_NE(-1, rtp.readFromFile(rtp_fp));
    }

    // RecOut
    WebRtc_Word16 out_data[kMaxBlockSize];
    WebRtc_Word16 out_len = neteq_inst_->recOut(out_data);
    ASSERT_TRUE((out_len == kBlockSize8kHz) ||
                (out_len == kBlockSize16kHz) ||
                (out_len == kBlockSize32kHz));

    if (ref_fp) {
      // Read from ref file.
      WebRtc_Word16 ref_data[kMaxBlockSize];
      if (static_cast<size_t>(out_len) !=
          fread(ref_data, sizeof(WebRtc_Word16), out_len, ref_fp)) {
        break;
      }

      // Compare
      EXPECT_EQ(0, memcmp(out_data, ref_data, sizeof(WebRtc_Word16) * out_len));
    }

    if (out_fp) {
      // Write to output file (mainly for generating new output vectors).
      ASSERT_EQ(static_cast<size_t>(out_len),
                fwrite(out_data, sizeof(WebRtc_Word16), out_len, out_fp));
    }

    // Increase time.
    sim_clock += kTimeStepMs;
  }
  fclose(rtp_fp);
  if (ref_fp) {
    ASSERT_NE(0, feof(ref_fp));  // Make sure that we reached the end.
    fclose(ref_fp);
  }
  if (out_fp) fclose(out_fp);
}

#if defined(WEBRTC_LINUX) && defined(WEBRTC_ARCH_64_BITS)
TEST_F(NetEqDecodingTest, TestBitExactness) {
  const std::string kInputRtpFile = webrtc::test::ProjectRootPath() +
      "test/data/audio_coding/universal.rtp";
  const std::string kInputRefFile = webrtc::test::ProjectRootPath() +
      "test/data/audio_coding/universal_ref.pcm";
  DecodeAndCompare(kInputRtpFile, kInputRefFile);
}
#endif  // defined(WEBRTC_LINUX) && defined(WEBRTC_ARCH_64_BITS)

}  // namespace
<commit_msg>Testing NetEQ network statistics<commit_after>/*
 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

/*
 * This file includes unit tests for NetEQ.
 */

#include <stdlib.h>
#include <string.h>  // memset

#include <string>
#include <vector>

#include "gtest/gtest.h"

#include "modules/audio_coding/neteq/interface/webrtc_neteq.h"
#include "modules/audio_coding/neteq/interface/webrtc_neteq_help_macros.h"
#include "modules/audio_coding/neteq/test/NETEQTEST_CodecClass.h"
#include "modules/audio_coding/neteq/test/NETEQTEST_NetEQClass.h"
#include "modules/audio_coding/neteq/test/NETEQTEST_RTPpacket.h"
#include "testsupport/fileutils.h"
#include "typedefs.h"  // NOLINT(build/include)

namespace webrtc {

class RefFiles {
 public:
  RefFiles(const std::string& input_file, const std::string& output_file);
  ~RefFiles();
  template<class T> void ProcessReference(const T& test_results);
  template<typename T, size_t n> void ProcessReference(
      const T (&test_results)[n],
      size_t length);
  template<typename T, size_t n> void WriteToFile(
      const T (&test_results)[n],
      size_t length);
  template<typename T, size_t n> void ReadFromFileAndCompare(
      const T (&test_results)[n],
      size_t length);
  void WriteToFile(const WebRtcNetEQ_NetworkStatistics& stats);
  void ReadFromFileAndCompare(const WebRtcNetEQ_NetworkStatistics& stats);
  void WriteToFile(const WebRtcNetEQ_RTCPStat& stats);
  void ReadFromFileAndCompare(const WebRtcNetEQ_RTCPStat& stats);

  FILE* input_fp_;
  FILE* output_fp_;
};

RefFiles::RefFiles(const std::string &input_file,
                   const std::string &output_file)
    : input_fp_(NULL),
      output_fp_(NULL) {
  if (!input_file.empty()) {
    input_fp_ = fopen(input_file.c_str(), "rb");
    EXPECT_TRUE(input_fp_ != NULL);
  }
  if (!output_file.empty()) {
    output_fp_ = fopen(output_file.c_str(), "wb");
    EXPECT_TRUE(output_fp_ != NULL);
  }
}

RefFiles::~RefFiles() {
  if (input_fp_) {
    EXPECT_EQ(EOF, fgetc(input_fp_));  // Make sure that we reached the end.
    fclose(input_fp_);
  }
  if (output_fp_) fclose(output_fp_);
}

template<class T>
void RefFiles::ProcessReference(const T& test_results) {
  WriteToFile(test_results);
  ReadFromFileAndCompare(test_results);
}

template<typename T, size_t n>
void RefFiles::ProcessReference(const T (&test_results)[n], size_t length) {
  WriteToFile(test_results, length);
  ReadFromFileAndCompare(test_results, length);
}

template<typename T, size_t n>
void RefFiles::WriteToFile(const T (&test_results)[n], size_t length) {
  if (output_fp_) {
    ASSERT_EQ(length, fwrite(&test_results, sizeof(T), length, output_fp_));
  }
}

template<typename T, size_t n>
void RefFiles::ReadFromFileAndCompare(const T (&test_results)[n],
                                      size_t length) {
  if (input_fp_) {
    // Read from ref file.
    T* ref = new T[length];
    ASSERT_EQ(length, fread(ref, sizeof(T), length, input_fp_));
    // Compare
    EXPECT_EQ(0, memcmp(&test_results, ref, sizeof(T) * length));
    delete [] ref;
  }
}

void RefFiles::WriteToFile(const WebRtcNetEQ_NetworkStatistics& stats) {
  if (output_fp_) {
    ASSERT_EQ(1u, fwrite(&stats, sizeof(WebRtcNetEQ_NetworkStatistics), 1,
                         output_fp_));
  }
}

void RefFiles::ReadFromFileAndCompare(
    const WebRtcNetEQ_NetworkStatistics& stats) {
  if (input_fp_) {
    // Read from ref file.
    size_t stat_size = sizeof(WebRtcNetEQ_NetworkStatistics);
    WebRtcNetEQ_NetworkStatistics ref_stats;
    ASSERT_EQ(1u, fread(&ref_stats, stat_size, 1, input_fp_));
    // Compare
    EXPECT_EQ(0, memcmp(&stats, &ref_stats, stat_size));
  }
}

void RefFiles::WriteToFile(const WebRtcNetEQ_RTCPStat& stats) {
  if (output_fp_) {
    ASSERT_EQ(1u, fwrite(&(stats.fraction_lost), sizeof(stats.fraction_lost), 1,
                         output_fp_));
    ASSERT_EQ(1u, fwrite(&(stats.cum_lost), sizeof(stats.cum_lost), 1,
                         output_fp_));
    ASSERT_EQ(1u, fwrite(&(stats.ext_max), sizeof(stats.ext_max), 1,
                         output_fp_));
    ASSERT_EQ(1u, fwrite(&(stats.jitter), sizeof(stats.jitter), 1,
                         output_fp_));
  }
}

void RefFiles::ReadFromFileAndCompare(
    const WebRtcNetEQ_RTCPStat& stats) {
  if (input_fp_) {
    // Read from ref file.
    WebRtcNetEQ_RTCPStat ref_stats;
    ASSERT_EQ(1u, fread(&(ref_stats.fraction_lost),
                        sizeof(ref_stats.fraction_lost), 1, input_fp_));
    ASSERT_EQ(1u, fread(&(ref_stats.cum_lost), sizeof(ref_stats.cum_lost), 1,
                        input_fp_));
    ASSERT_EQ(1u, fread(&(ref_stats.ext_max), sizeof(ref_stats.ext_max), 1,
                        input_fp_));
    ASSERT_EQ(1u, fread(&(ref_stats.jitter), sizeof(ref_stats.jitter), 1,
                        input_fp_));
    // Compare
    EXPECT_EQ(ref_stats.fraction_lost, stats.fraction_lost);
    EXPECT_EQ(ref_stats.cum_lost, stats.cum_lost);
    EXPECT_EQ(ref_stats.ext_max, stats.ext_max);
    EXPECT_EQ(ref_stats.jitter, stats.jitter);
  }
}

class NetEqDecodingTest : public ::testing::Test {
 protected:
  // NetEQ must be polled for data once every 10 ms. Thus, neither of the
  // constants below can be changed.
  static const int kTimeStepMs = 10;
  static const int kBlockSize8kHz = kTimeStepMs * 8;
  static const int kBlockSize16kHz = kTimeStepMs * 16;
  static const int kBlockSize32kHz = kTimeStepMs * 32;
  static const int kMaxBlockSize = kBlockSize32kHz;

  NetEqDecodingTest();
  virtual void SetUp();
  virtual void TearDown();
  void SelectDecoders(WebRtcNetEQDecoder* used_codec);
  void LoadDecoders();
  void OpenInputFile(const std::string &rtp_file);
  void Process(NETEQTEST_RTPpacket* rtp_ptr, int16_t* out_len);
  void DecodeAndCompare(const std::string &rtp_file,
                        const std::string &ref_file);
  void DecodeAndCheckStats(const std::string &rtp_file,
                           const std::string &stat_ref_file,
                           const std::string &rtcp_ref_file);

  NETEQTEST_NetEQClass* neteq_inst_;
  std::vector<NETEQTEST_Decoder*> dec_;
  FILE* rtp_fp_;
  unsigned int sim_clock_;
  int16_t out_data_[kMaxBlockSize];
};

NetEqDecodingTest::NetEqDecodingTest()
    : neteq_inst_(NULL),
      rtp_fp_(NULL),
      sim_clock_(0) {
  memset(out_data_, 0, sizeof(out_data_));
}

void NetEqDecodingTest::SetUp() {
  WebRtcNetEQDecoder usedCodec[kDecoderReservedEnd - 1];

  SelectDecoders(usedCodec);
  neteq_inst_ = new NETEQTEST_NetEQClass(usedCodec, dec_.size(), 8000,
                                         kTCPLargeJitter);
  ASSERT_TRUE(neteq_inst_);
  LoadDecoders();
}

void NetEqDecodingTest::TearDown() {
  if (neteq_inst_)
    delete neteq_inst_;
  for (size_t i = 0; i < dec_.size(); ++i) {
    if (dec_[i])
      delete dec_[i];
  }
  if (rtp_fp_)
    fclose(rtp_fp_);
}

void NetEqDecodingTest::SelectDecoders(WebRtcNetEQDecoder* used_codec) {
  *used_codec++ = kDecoderPCMu;
  dec_.push_back(new decoder_PCMU(0));
  *used_codec++ = kDecoderPCMa;
  dec_.push_back(new decoder_PCMA(8));
  *used_codec++ = kDecoderILBC;
  dec_.push_back(new decoder_ILBC(102));
  *used_codec++ = kDecoderISAC;
  dec_.push_back(new decoder_iSAC(103));
  *used_codec++ = kDecoderISACswb;
  dec_.push_back(new decoder_iSACSWB(104));
  *used_codec++ = kDecoderPCM16B;
  dec_.push_back(new decoder_PCM16B_NB(93));
  *used_codec++ = kDecoderPCM16Bwb;
  dec_.push_back(new decoder_PCM16B_WB(94));
  *used_codec++ = kDecoderPCM16Bswb32kHz;
  dec_.push_back(new decoder_PCM16B_SWB32(95));
  *used_codec++ = kDecoderCNG;
  dec_.push_back(new decoder_CNG(13));
}

void NetEqDecodingTest::LoadDecoders() {
  for (size_t i = 0; i < dec_.size(); ++i) {
    ASSERT_EQ(0, dec_[i]->loadToNetEQ(*neteq_inst_));
  }
}

void NetEqDecodingTest::OpenInputFile(const std::string &rtp_file) {
  rtp_fp_ = fopen(rtp_file.c_str(), "rb");
  ASSERT_TRUE(rtp_fp_ != NULL);
  ASSERT_EQ(0, NETEQTEST_RTPpacket::skipFileHeader(rtp_fp_));
}

void NetEqDecodingTest::Process(NETEQTEST_RTPpacket* rtp, int16_t* out_len) {
  // Check if time to receive.
  while ((sim_clock_ >= rtp->time()) &&
         (rtp->dataLen() >= 0)) {
    if (rtp->dataLen() > 0) {
      ASSERT_EQ(0, neteq_inst_->recIn(*rtp));
    }
    // Get next packet.
    ASSERT_NE(-1, rtp->readFromFile(rtp_fp_));
  }

  // RecOut
  *out_len = neteq_inst_->recOut(out_data_);
  ASSERT_TRUE((*out_len == kBlockSize8kHz) ||
              (*out_len == kBlockSize16kHz) ||
              (*out_len == kBlockSize32kHz));

  // Increase time.
  sim_clock_ += kTimeStepMs;
}

void NetEqDecodingTest::DecodeAndCompare(const std::string &rtp_file,
                                         const std::string &ref_file) {
  OpenInputFile(rtp_file);

  std::string ref_out_file = "";
  if (ref_file.empty()) {
    ref_out_file = webrtc::test::OutputPath() + "neteq_out.pcm";
  }
  RefFiles ref_files(ref_file, ref_out_file);

  NETEQTEST_RTPpacket rtp;
  ASSERT_GT(rtp.readFromFile(rtp_fp_), 0);
  while (rtp.dataLen() >= 0) {
    int16_t out_len;
    Process(&rtp, &out_len);
    ref_files.ProcessReference(out_data_, out_len);
  }
}

void NetEqDecodingTest::DecodeAndCheckStats(const std::string &rtp_file,
                                            const std::string &stat_ref_file,
                                            const std::string &rtcp_ref_file) {
  OpenInputFile(rtp_file);
  std::string stat_out_file = "";
  if (stat_ref_file.empty()) {
    stat_out_file = webrtc::test::OutputPath() +
        "neteq_network_stats.dat";
  }
  RefFiles network_stat_files(stat_ref_file, stat_out_file);

  std::string rtcp_out_file = "";
  if (rtcp_ref_file.empty()) {
    rtcp_out_file = webrtc::test::OutputPath() +
        "neteq_rtcp_stats.dat";
  }
  RefFiles rtcp_stat_files(rtcp_ref_file, rtcp_out_file);

  NETEQTEST_RTPpacket rtp;
  ASSERT_GT(rtp.readFromFile(rtp_fp_), 0);
  while (rtp.dataLen() >= 0) {
    int16_t out_len;
    Process(&rtp, &out_len);

    // Query the network statistics API once per second
    if (sim_clock_ % 1000 == 0) {
      // Process NetworkStatistics.
      WebRtcNetEQ_NetworkStatistics network_stats;
      ASSERT_EQ(0, WebRtcNetEQ_GetNetworkStatistics(neteq_inst_->instance(),
                                                    &network_stats));
      network_stat_files.ProcessReference(network_stats);

      // Process RTCPstat.
      WebRtcNetEQ_RTCPStat rtcp_stats;
      ASSERT_EQ(0, WebRtcNetEQ_GetRTCPStats(neteq_inst_->instance(),
                                            &rtcp_stats));
      rtcp_stat_files.ProcessReference(rtcp_stats);
    }
  }
}

#if defined(WEBRTC_LINUX) && defined(WEBRTC_ARCH_64_BITS)
TEST_F(NetEqDecodingTest, TestBitExactness) {
  const std::string kInputRtpFile = webrtc::test::ProjectRootPath() +
      "test/data/audio_coding/universal.rtp";
  const std::string kInputRefFile = webrtc::test::ProjectRootPath() +
      "test/data/audio_coding/universal_ref.pcm";
  DecodeAndCompare(kInputRtpFile, kInputRefFile);
}
#endif  // defined(WEBRTC_LINUX) && defined(WEBRTC_ARCH_64_BITS)

//TODO(hlundin): Add test target NetEqDecodingTest::TestNetworkStatistics.

}  // namespace
<|endoftext|>


<commit_before>/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include <algorithm>
#include <limits>
#include "kernel/free_vars.h"
#include "kernel/replace_fn.h"
#include "kernel/instantiate.h"

namespace lean {
expr instantiate(expr const & a, unsigned s, unsigned n, expr const * subst) {
    if (s >= get_free_var_range(a) || n == 0)
        return a;
    return replace(a, [=](expr const & m, unsigned offset) -> optional<expr> {
            unsigned s1 = s + offset;
            if (s1 < s)
                return some_expr(m); // overflow, vidx can't be >= max unsigned
            if (s1 >= get_free_var_range(m))
                return some_expr(m); // expression m does not contain free variables with idx >= s1
            if (is_var(m)) {
                unsigned vidx = var_idx(m);
                if (vidx >= s1) {
                    unsigned h = s1 + n;
                    if (h < s1 /* overflow, h is bigger than any vidx */ || vidx < h) {
                        return some_expr(lift_free_vars(subst[vidx - s1], offset));
                    } else {
                        return some_expr(mk_var(vidx - n));
                    }
                }
            }
            return none_expr();
        });
}

expr instantiate(expr const & e, unsigned n, expr const * s) { return instantiate(e, 0, n, s); }
expr instantiate(expr const & e, std::initializer_list<expr> const & l) {  return instantiate(e, l.size(), l.begin()); }
expr instantiate(expr const & e, unsigned i, expr const & s) { return instantiate(e, i, 1, &s); }
expr instantiate(expr const & e, expr const & s) { return instantiate(e, 0, s); }

bool is_head_beta(expr const & t) {
    expr const * it = &t;
    while (is_app(*it)) {
        expr const & f = app_fn(*it);
        if (is_lambda(f)) {
            return true;
        } else if (is_app(f)) {
            it = &f;
        } else {
            return false;
        }
    }
    return false;
}

expr apply_beta(expr f, unsigned num_args, expr const * args) {
    lean_assert(num_args > 0);
    if (!is_lambda(f)) {
        return mk_rev_app(f, num_args, args);
    } else {
        unsigned m = 1;
        while (is_lambda(binding_body(f)) && m < num_args) {
            f = binding_body(f);
            m++;
        }
        lean_assert(m <= num_args);
        return mk_rev_app(instantiate(binding_body(f), m, args + (num_args - m)), num_args - m, args);
    }
}

expr head_beta_reduce(expr const & t) {
    if (!is_head_beta(t)) {
        return t;
    } else {
        buffer<expr> args;
        expr const * it = &t;
        while (true) {
            lean_assert(is_app(*it));
            expr const & f = app_fn(*it);
            args.push_back(app_arg(*it));
            if (is_lambda(f)) {
                return apply_beta(f, args.size(), args.data());
            } else {
                lean_assert(is_app(f));
                it = &f;
            }
        }
    }
}

expr beta_reduce(expr t) {
    auto f = [=](expr const & m, unsigned) -> optional<expr> {
        if (is_head_beta(m))
            return some_expr(head_beta_reduce(m));
        else
            return none_expr();
    };
    while (true) {
        expr new_t = replace_fn(f)(t);
        if (new_t == t)
            return new_t;
        else
            t = new_t;
    }
}

expr instantiate_params(expr const & e, level_param_names const & ps, levels const & ls) {
    if (!has_param_univ(e))
        return e;
    return replace(e, [&](expr const & e, unsigned) -> optional<expr> {
            if (!has_param_univ(e))
                return some_expr(e);
            if (is_constant(e)) {
                return some_expr(update_constant(e, map_reuse(const_levels(e),
                                                              [&](level const & l) { return instantiate(l, ps, ls); },
                                                              [](level const & l1, level const & l2) { return is_eqp(l1, l2); })));
            } else if (is_sort(e)) {
                return some_expr(update_sort(e, instantiate(sort_level(e), ps, ls)));
            } else {
                return none_expr();
            }
        });
}
}
<commit_msg>feat(kernel/instantiate): relax apply_beta pre-conditions<commit_after>/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include <algorithm>
#include <limits>
#include "kernel/free_vars.h"
#include "kernel/replace_fn.h"
#include "kernel/instantiate.h"

namespace lean {
expr instantiate(expr const & a, unsigned s, unsigned n, expr const * subst) {
    if (s >= get_free_var_range(a) || n == 0)
        return a;
    return replace(a, [=](expr const & m, unsigned offset) -> optional<expr> {
            unsigned s1 = s + offset;
            if (s1 < s)
                return some_expr(m); // overflow, vidx can't be >= max unsigned
            if (s1 >= get_free_var_range(m))
                return some_expr(m); // expression m does not contain free variables with idx >= s1
            if (is_var(m)) {
                unsigned vidx = var_idx(m);
                if (vidx >= s1) {
                    unsigned h = s1 + n;
                    if (h < s1 /* overflow, h is bigger than any vidx */ || vidx < h) {
                        return some_expr(lift_free_vars(subst[vidx - s1], offset));
                    } else {
                        return some_expr(mk_var(vidx - n));
                    }
                }
            }
            return none_expr();
        });
}

expr instantiate(expr const & e, unsigned n, expr const * s) { return instantiate(e, 0, n, s); }
expr instantiate(expr const & e, std::initializer_list<expr> const & l) {  return instantiate(e, l.size(), l.begin()); }
expr instantiate(expr const & e, unsigned i, expr const & s) { return instantiate(e, i, 1, &s); }
expr instantiate(expr const & e, expr const & s) { return instantiate(e, 0, s); }

bool is_head_beta(expr const & t) {
    expr const * it = &t;
    while (is_app(*it)) {
        expr const & f = app_fn(*it);
        if (is_lambda(f)) {
            return true;
        } else if (is_app(f)) {
            it = &f;
        } else {
            return false;
        }
    }
    return false;
}

expr apply_beta(expr f, unsigned num_args, expr const * args) {
    if (num_args == 0) {
        return f;
    } else if (!is_lambda(f)) {
        return mk_rev_app(f, num_args, args);
    } else {
        unsigned m = 1;
        while (is_lambda(binding_body(f)) && m < num_args) {
            f = binding_body(f);
            m++;
        }
        lean_assert(m <= num_args);
        return mk_rev_app(instantiate(binding_body(f), m, args + (num_args - m)), num_args - m, args);
    }
}

expr head_beta_reduce(expr const & t) {
    if (!is_head_beta(t)) {
        return t;
    } else {
        buffer<expr> args;
        expr const * it = &t;
        while (true) {
            lean_assert(is_app(*it));
            expr const & f = app_fn(*it);
            args.push_back(app_arg(*it));
            if (is_lambda(f)) {
                return apply_beta(f, args.size(), args.data());
            } else {
                lean_assert(is_app(f));
                it = &f;
            }
        }
    }
}

expr beta_reduce(expr t) {
    auto f = [=](expr const & m, unsigned) -> optional<expr> {
        if (is_head_beta(m))
            return some_expr(head_beta_reduce(m));
        else
            return none_expr();
    };
    while (true) {
        expr new_t = replace_fn(f)(t);
        if (new_t == t)
            return new_t;
        else
            t = new_t;
    }
}

expr instantiate_params(expr const & e, level_param_names const & ps, levels const & ls) {
    if (!has_param_univ(e))
        return e;
    return replace(e, [&](expr const & e, unsigned) -> optional<expr> {
            if (!has_param_univ(e))
                return some_expr(e);
            if (is_constant(e)) {
                return some_expr(update_constant(e, map_reuse(const_levels(e),
                                                              [&](level const & l) { return instantiate(l, ps, ls); },
                                                              [](level const & l1, level const & l2) { return is_eqp(l1, l2); })));
            } else if (is_sort(e)) {
                return some_expr(update_sort(e, instantiate(sort_level(e), ps, ls)));
            } else {
                return none_expr();
            }
        });
}
}
<|endoftext|>


<commit_before>#include <sstream>
#include "omxExpectation.h"
#include "path.h"
#include "Compute.h"
#include "EnableWarnings.h"

void PathCalc::prepM(FitContext *fc)
{
	if (!mio) mxThrow("PathCalc::prepM but no PathCalcIO for mean");
	mio->recompute(fc);
	if (ignoreVersion || versionM != mio->getVersion(fc)) {
		mio->refresh(fc);
		versionM = mio->getVersion(fc);
	}
	if (verbose >= 2) mxPrintMat("M", mio->full);
}

void PathCalc::prepS(FitContext *fc)
{
	sio->recompute(fc);
	if (ignoreVersion || versionS != sio->getVersion(fc)) {
		if (!useSparse) {
			sio->refresh(fc);
		} else {
			sio->refreshSparse(fc, 0.0);
		}
		versionS = sio->getVersion(fc);
	}
	if (verbose >= 2) mxPrintMat("S", sio->full);
}

void PathCalc::prepA(FitContext *fc)
{
	aio->recompute(fc);
	if (ignoreVersion || versionIA != aio->getVersion(fc)) {
		refreshA(fc, 1.0);
		versionIA = aio->getVersion(fc);
	}
}

void PathCalc::init1()
{
	if (algoSet) mxThrow("PathCalc::init() but algoSet");
	if (mio) {
		mio->full.resize(numVars, 1);
		//fullM.setZero(); all coeff are copied
	}

	if (!boker2019) {
		useSparse = numVars >= 15;
		if (!useSparse) {
			aio->full.resize(numVars, numVars);
			aio->full.setZero();
			sio->full.resize(numVars, numVars);
			sio->full.setZero();
		} else {
			aio->sparse.resize(numVars, numVars);
			aio->sparse.reserve(2*numVars);
			aio->sparse.uncompress();
			sio->sparse.resize(numVars, numVars);
			sio->sparse.reserve(2*numVars);
			sio->sparse.uncompress();
			sparseIdent.resize(numVars, numVars);
			sparseIdent.setIdentity();
			sparseIdent.makeCompressed();
		}
	}

	obsMap.resize(numVars);
	obsMap.setConstant(-1);
	auto &lf = *latentFilter;
	for (int vx=0, ox=0; vx < numVars; ++vx) {
		if (!lf[vx]) continue;
		obsMap[vx] = ox++;
	}
}

void PathCalc::init2()
{
	if (!boker2019) {
		if (numIters == NA_INTEGER) {
			if (!useSparse) {
				aio->full.diagonal().array() = 1;
			} else {
				aio->sparse.reserve(aio->sparse.nonZeros() + numVars);
				for (int vx=0; vx < numVars; ++vx) aio->sparse.coeffRef(vx,vx) = 1.0;
			}
		}
	} else { // boker2019
		aio->full.resize(numVars, numVars);
		aio->full.setZero();
		sio->full.resize(numVars, numVars);
		sio->full.setZero();
		polyRep.resize(numVars);
	}
	algoSet = true;
}

void PathCalc::setAlgo(FitContext *fc, bool _boker2019)
{
	if (!_boker2019 && std::any_of(isProductNode->begin(), isProductNode->end(),
																 [](bool x){ return x; })) {
		mxThrow("Must use Boker2019 when product nodes are present");
	}
	boker2019 = _boker2019;

	init1();

	if (!boker2019) {
		determineShallowDepth(fc);
		if (verbose >= 1) mxLog("PathCalc: sparse=%d numVars=%d depth=%d",
														useSparse, numVars, numIters);
	} else { // boker2019 P-O-V
		if (verbose >= 1) mxLog("PathCalc: Boker2019 P-O-V enabled, numVars=%d", numVars);
		// no sparse support, for now
	}

	init2();
}

void PathCalc::determineShallowDepth(FitContext *fc)
{
	if (!Global->RAMInverseOpt) return;

	int maxDepth = std::min(numVars, 30);
	if (Global->RAMMaxDepth != NA_INTEGER) {
		maxDepth = std::min(maxDepth, Global->RAMMaxDepth);
	}
	refreshA(fc, 1.0);
	if (!useSparse) {
		if ((aio->full.diagonal().array() != 0).any()) mxThrow("A matrix has non-zero diagonal");
		Eigen::MatrixXd curProd = aio->full;
		for (int tx=1; tx <= maxDepth; ++tx) {
			if (false) {
				mxLog("tx=%d", tx);
				mxPrintMat("curProd", curProd);
			}
			curProd *= aio->full.transpose();
			if ((curProd.array() == 0.0).all()) {
				numIters = tx - 1;
				break;
			}
		}
	} else {
		typeof(aio->sparse) curProd = aio->sparse;
		int prev = -1;
		for (int tx=1; tx <= maxDepth; ++tx) {
			curProd = (curProd * aio->sparse.transpose()).pruned().eval();
			if (tx == 1) prev = curProd.nonZeros();
			else if (prev <= curProd.nonZeros()) break;  // no improvement
			prev = curProd.nonZeros();
			if (prev == 0) {
				numIters = tx - 1;
				break;
			}
		}
  }
}

void PathCalc::evaluate(FitContext *fc, bool doFilter)
{
	if (boker2019) mxThrow("PathCalc::evaluate but boker2019=TRUE");

	aio->recompute(fc);
	const unsigned fver = 0xb01dface;
	if (!ignoreVersion && versionIA == aio->getVersion(fc) + doFilter*fver) {
		//mxLog("PathCalc<avft>::evaluate() in cache");
		return;
	}
	versionIA = aio->getVersion(fc) + doFilter*fver;

	if (numIters >= 0) {
		refreshA(fc, 1.0);
		// could further optimize using std::swap? (see old code)
		if (!useSparse) {
			IA = aio->full;
			IA.diagonal().array() += 1;
			for (int iter=1; iter <= numIters; ++iter) {
				IA *= aio->full;
				IA.diagonal().array() += 1;
				//{ Eigen::MatrixXd tmp = out; mxPrintMat("out", tmp); }
			}
			if (verbose >= 2) mxPrintMat("IA", IA);
		} else {
			sparseIA = aio->sparse + sparseIdent;
			for (int iter=1; iter <= numIters; ++iter) {
				sparseIA = (sparseIA * aio->sparse + sparseIdent).pruned().eval();
			}
			if (verbose >= 2) {
				IA = sparseIA;
				mxPrintMat("IA", IA);
			}
		}
	} else {
		refreshA(fc, -1.0);
		if (!useSparse) {
			Eigen::FullPivLU< Eigen::MatrixXd > lu(aio->full);
			IA.resize(numVars, numVars);
			IA.setIdentity();
			IA = lu.solve(IA);
			if (verbose >= 2) mxPrintMat("IA", IA);
		} else {
			aio->sparse.makeCompressed();
			if (!sparseLUanal) {
				sparseLUanal = true;
				sparseLU.analyzePattern(aio->sparse);
			}
			sparseLU.factorize(aio->sparse);
			if (sparseLU.info() != Eigen::Success) {
				if (fc) fc->recordIterationError("RAM's A matrix is not invertible");
				sparseIA = sparseIdent * NA_REAL;
			} else {
				sparseIA = sparseLU.solve(sparseIdent);
			}
			if (verbose >= 2) {
				IA = sparseIA;
				mxPrintMat("IA", IA);
			}
		}
	}

	if (doFilter) {
		// We built A transposed so we can quickly filter columns
		auto &lf = *latentFilter;
		if (!useSparse) {
			for (int rx=0, dx=0; rx < IA.rows(); ++rx) {
				if (!lf[rx]) continue;
				IA.col(dx) = IA.col(rx);
				dx += 1;
			}
			IA.conservativeResize(numVars, numObs);
			if (verbose >= 2) mxPrintMat("IAF", IA);
		} else {
			// Switch to filterOuter http://eigen.tuxfamily.org/bz/show_bug.cgi?id=1130 TODO
			sparseIA.uncompress();
			Eigen::SparseMatrix<double>::Index *op = sparseIA.outerIndexPtr();
			Eigen::SparseMatrix<double>::Index *nzp = sparseIA.innerNonZeroPtr();
			int dx = 0;
			for (int cx=0; cx < numVars; ++cx) {
				if (!lf[cx]) continue;
				op[dx] = op[cx];
				nzp[dx] = nzp[cx];
				++dx;
			}
			op[dx] = op[numVars];
			sparseIA.conservativeResize(numVars, numObs);
			if (verbose >= 2) {
				IA = sparseIA;
				mxPrintMat("IAF", IA);
			}
		}
	}
}

void PathCalc::appendPolyRep(int nn, std::vector<int> &status)
{
	if (status[nn] == 2) return;
	if (status[nn] == 1) mxThrow("Asymmetric matrix is cyclic");
	status[nn] = 1;

	auto &A = aio->full;
	for (int ii=0; ii < A.rows(); ++ii) {
		if (ii == nn || status[ii] == 2 || A(ii,nn) == 0) continue;
		appendPolyRep(ii, status);
	}
	for (int ii=0; ii < A.rows(); ++ii) {
		if (ii == nn || A(ii,nn) == 0) continue;
		Polynomial< double > term(A(ii,nn));
		//mxLog("A %d %d %f", ii,nn,A(ii,nn));
		//std::cout << std::string(polyRep[ii]) << "\n";
		term *= polyRep[ii];
		//std::cout << std::string(polyRep[nn]) << "OP " << isProductNode[nn] << " " << std::string(term) << "\n";
		if ((*isProductNode)[nn]) {
			polyRep[nn] *= term;
		} else {
			polyRep[nn] += term;
		}
		//std::cout << "result: " << std::string(polyRep[nn]) << "\n";
	}

	status[nn] = 2;
}

void PathCalc::buildPolynomial(FitContext *fc)
{
	prepS(fc);
	prepA(fc);
	unsigned curV = versionS + versionIA;
	if (mio) {
		prepM(fc);
		curV += versionM;
	}
	if (!ignoreVersion && versionPoly == curV) return;
	versionPoly = curV;

	if (verbose >= 2) {
		mxLog("PathCalc::buildPolynomial for %u (S%u A%u M%u)", curV,
					versionS, versionIA, versionM);
	}

	for (auto &p1 : polyRep) p1.clear();

	if (mio) {
		for (int ii=0; ii < numVars; ++ii) {
			polyRep[ii].addMonomial(Monomial< double >(mio->full(ii)));
		}
	}

	/* old version with Cholesky, doesn't work with non-positive definite S, but probably easier to extend to derivatives. Also,
	 * polynomials are more sparse with the Cholesky variant. An alternative could be to use a sign switch in the Cholesky decomposition,
	 * thereby working with normally distributed variables of variance either 1 or -1.
	 double[][] cholesky = null;
	 try {
	 cholesky = Statik.choleskyDecompose(symVal,0.001);
	 } catch (Exception e) {
	 throw new RuntimeException("Polynomial representation is impossible because symmetric matrix is not positive definite: "+e);
	 }

	 int[] x = new int[anzFac]; int k = 0; for (int i=0; i<anzFac; i++) if (cholesky[i][i]!=0.0) x[i] = k++;
	 for (int i=0; i<anzFac; i++) for (int j=0; j<=i; j++) if (cholesky[i][j] != 0.0) polynomialRepresentation[i].addMonomial(cholesky[i][j], x[j]);
	 polynomialRepresentationVariances = Statik.ensureSize(polynomialRepresentationVariances, k);
	 for (int i=0; i<polynomialRepresentationVariances.length; i++) polynomialRepresentationVariances[i] = 1.0;
	*/

	// Add option to use Cholesky with fallback to SelfAdjointEigenSolver TODO
	symSolver.compute(sio->full);
	auto &symEv = symSolver.eigenvalues();
	auto &symVec = symSolver.eigenvectors();
	for (int jj=0; jj < numVars; ++jj) {
		if (symEv(jj) == 0) continue;
		for (int ii=0; ii < numVars; ++ii) {
			if (symVec(ii,jj) == 0) continue;
			polyRep[ii].addMonomial(symVec(ii,jj), jj);
		}
	}

	// for (int ii=0; ii < numVars; ++ii) {
	// 	std::cout << ii << ":" << std::string(polyRep[ii]) << "\n";
	// }

	std::vector<int> status(numVars, 0);
	for (int ii=0; ii<numVars; ii++) {
		appendPolyRep(ii, status);
	}

	// mxPrintMat("vec", symVec);
	if (verbose >= 2) {
		std::ostringstream temp;
		for (int ii=0; ii < numVars; ++ii) {
			temp << ii << " " << symEv[ii] << ":" << std::string(polyRep[ii]) << "\n";
		}
		mxLogBig(temp.str());
	}

	// Could be smarter and avoid latents except when needed TODO
	meanOut.resize(numVars);
	for (int ii=0; ii<numVars; ++ii) {
		meanOut[ii] = polynomialToMoment(polyRep[ii], symEv);
	}
}
<commit_msg>Sparse matrix fix: makeCompressed before reserve<commit_after>#include <sstream>
#include "omxExpectation.h"
#include "path.h"
#include "Compute.h"
#include "EnableWarnings.h"

void PathCalc::prepM(FitContext *fc)
{
	if (!mio) mxThrow("PathCalc::prepM but no PathCalcIO for mean");
	mio->recompute(fc);
	if (ignoreVersion || versionM != mio->getVersion(fc)) {
		mio->refresh(fc);
		versionM = mio->getVersion(fc);
	}
	if (verbose >= 2) mxPrintMat("M", mio->full);
}

void PathCalc::prepS(FitContext *fc)
{
	sio->recompute(fc);
	if (ignoreVersion || versionS != sio->getVersion(fc)) {
		if (!useSparse) {
			sio->refresh(fc);
		} else {
			sio->refreshSparse(fc, 0.0);
		}
		versionS = sio->getVersion(fc);
	}
	if (verbose >= 2) mxPrintMat("S", sio->full);
}

void PathCalc::prepA(FitContext *fc)
{
	aio->recompute(fc);
	if (ignoreVersion || versionIA != aio->getVersion(fc)) {
		refreshA(fc, 1.0);
		versionIA = aio->getVersion(fc);
	}
}

void PathCalc::init1()
{
	if (algoSet) mxThrow("PathCalc::init() but algoSet");
	if (mio) {
		mio->full.resize(numVars, 1);
		//fullM.setZero(); all coeff are copied
	}

	if (!boker2019) {
		useSparse = numVars >= 15;
		if (!useSparse) {
			aio->full.resize(numVars, numVars);
			aio->full.setZero();
			sio->full.resize(numVars, numVars);
			sio->full.setZero();
		} else {
			aio->sparse.resize(numVars, numVars);
			aio->sparse.makeCompressed();
			aio->sparse.reserve(2*numVars);
			sio->sparse.resize(numVars, numVars);
			aio->sparse.makeCompressed();
			sio->sparse.reserve(2*numVars);
			sparseIdent.resize(numVars, numVars);
			sparseIdent.setIdentity();
			sparseIdent.makeCompressed();
		}
	}

	obsMap.resize(numVars);
	obsMap.setConstant(-1);
	auto &lf = *latentFilter;
	for (int vx=0, ox=0; vx < numVars; ++vx) {
		if (!lf[vx]) continue;
		obsMap[vx] = ox++;
	}
}

void PathCalc::init2()
{
	if (!boker2019) {
		if (numIters == NA_INTEGER) {
			if (!useSparse) {
				aio->full.diagonal().array() = 1;
			} else {
				aio->sparse.makeCompressed();
				aio->sparse.reserve(aio->sparse.nonZeros() + numVars);
				for (int vx=0; vx < numVars; ++vx) aio->sparse.coeffRef(vx,vx) = 1.0;
			}
		}
	} else { // boker2019
		aio->full.resize(numVars, numVars);
		aio->full.setZero();
		sio->full.resize(numVars, numVars);
		sio->full.setZero();
		polyRep.resize(numVars);
	}
	algoSet = true;
}

void PathCalc::setAlgo(FitContext *fc, bool _boker2019)
{
	if (!_boker2019 && std::any_of(isProductNode->begin(), isProductNode->end(),
																 [](bool x){ return x; })) {
		mxThrow("Must use Boker2019 when product nodes are present");
	}
	boker2019 = _boker2019;

	init1();

	if (!boker2019) {
		determineShallowDepth(fc);
		if (verbose >= 1) mxLog("PathCalc: sparse=%d numVars=%d depth=%d",
														useSparse, numVars, numIters);
	} else { // boker2019 P-O-V
		if (verbose >= 1) mxLog("PathCalc: Boker2019 P-O-V enabled, numVars=%d", numVars);
		// no sparse support, for now
	}

	init2();
}

void PathCalc::determineShallowDepth(FitContext *fc)
{
	if (!Global->RAMInverseOpt) return;

	int maxDepth = std::min(numVars, 30);
	if (Global->RAMMaxDepth != NA_INTEGER) {
		maxDepth = std::min(maxDepth, Global->RAMMaxDepth);
	}
	refreshA(fc, 1.0);
	if (!useSparse) {
		if ((aio->full.diagonal().array() != 0).any()) mxThrow("A matrix has non-zero diagonal");
		Eigen::MatrixXd curProd = aio->full;
		for (int tx=1; tx <= maxDepth; ++tx) {
			if (false) {
				mxLog("tx=%d", tx);
				mxPrintMat("curProd", curProd);
			}
			curProd *= aio->full.transpose();
			if ((curProd.array() == 0.0).all()) {
				numIters = tx - 1;
				break;
			}
		}
	} else {
		typeof(aio->sparse) curProd = aio->sparse;
		int prev = -1;
		for (int tx=1; tx <= maxDepth; ++tx) {
			curProd = (curProd * aio->sparse.transpose()).pruned().eval();
			if (tx == 1) prev = curProd.nonZeros();
			else if (prev <= curProd.nonZeros()) break;  // no improvement
			prev = curProd.nonZeros();
			if (prev == 0) {
				numIters = tx - 1;
				break;
			}
		}
  }
}

void PathCalc::evaluate(FitContext *fc, bool doFilter)
{
	if (boker2019) mxThrow("PathCalc::evaluate but boker2019=TRUE");

	aio->recompute(fc);
	const unsigned fver = 0xb01dface;
	if (!ignoreVersion && versionIA == aio->getVersion(fc) + doFilter*fver) {
		//mxLog("PathCalc<avft>::evaluate() in cache");
		return;
	}
	versionIA = aio->getVersion(fc) + doFilter*fver;

	if (numIters >= 0) {
		refreshA(fc, 1.0);
		// could further optimize using std::swap? (see old code)
		if (!useSparse) {
			IA = aio->full;
			IA.diagonal().array() += 1;
			for (int iter=1; iter <= numIters; ++iter) {
				IA *= aio->full;
				IA.diagonal().array() += 1;
				//{ Eigen::MatrixXd tmp = out; mxPrintMat("out", tmp); }
			}
			if (verbose >= 2) mxPrintMat("IA", IA);
		} else {
			sparseIA = aio->sparse + sparseIdent;
			for (int iter=1; iter <= numIters; ++iter) {
				sparseIA = (sparseIA * aio->sparse + sparseIdent).pruned().eval();
			}
			if (verbose >= 2) {
				IA = sparseIA;
				mxPrintMat("IA", IA);
			}
		}
	} else {
		refreshA(fc, -1.0);
		if (!useSparse) {
			Eigen::FullPivLU< Eigen::MatrixXd > lu(aio->full);
			IA.resize(numVars, numVars);
			IA.setIdentity();
			IA = lu.solve(IA);
			if (verbose >= 2) mxPrintMat("IA", IA);
		} else {
			aio->sparse.makeCompressed();
			if (!sparseLUanal) {
				sparseLUanal = true;
				sparseLU.analyzePattern(aio->sparse);
			}
			sparseLU.factorize(aio->sparse);
			if (sparseLU.info() != Eigen::Success) {
				if (fc) fc->recordIterationError("RAM's A matrix is not invertible");
				sparseIA = sparseIdent * NA_REAL;
			} else {
				sparseIA = sparseLU.solve(sparseIdent);
			}
			if (verbose >= 2) {
				IA = sparseIA;
				mxPrintMat("IA", IA);
			}
		}
	}

	if (doFilter) {
		// We built A transposed so we can quickly filter columns
		auto &lf = *latentFilter;
		if (!useSparse) {
			for (int rx=0, dx=0; rx < IA.rows(); ++rx) {
				if (!lf[rx]) continue;
				IA.col(dx) = IA.col(rx);
				dx += 1;
			}
			IA.conservativeResize(numVars, numObs);
			if (verbose >= 2) mxPrintMat("IAF", IA);
		} else {
			// Switch to filterOuter http://eigen.tuxfamily.org/bz/show_bug.cgi?id=1130 TODO
			sparseIA.uncompress();
			Eigen::SparseMatrix<double>::Index *op = sparseIA.outerIndexPtr();
			Eigen::SparseMatrix<double>::Index *nzp = sparseIA.innerNonZeroPtr();
			int dx = 0;
			for (int cx=0; cx < numVars; ++cx) {
				if (!lf[cx]) continue;
				op[dx] = op[cx];
				nzp[dx] = nzp[cx];
				++dx;
			}
			op[dx] = op[numVars];
			sparseIA.conservativeResize(numVars, numObs);
			if (verbose >= 2) {
				IA = sparseIA;
				mxPrintMat("IAF", IA);
			}
		}
	}
}

void PathCalc::appendPolyRep(int nn, std::vector<int> &status)
{
	if (status[nn] == 2) return;
	if (status[nn] == 1) mxThrow("Asymmetric matrix is cyclic");
	status[nn] = 1;

	auto &A = aio->full;
	for (int ii=0; ii < A.rows(); ++ii) {
		if (ii == nn || status[ii] == 2 || A(ii,nn) == 0) continue;
		appendPolyRep(ii, status);
	}
	for (int ii=0; ii < A.rows(); ++ii) {
		if (ii == nn || A(ii,nn) == 0) continue;
		Polynomial< double > term(A(ii,nn));
		//mxLog("A %d %d %f", ii,nn,A(ii,nn));
		//std::cout << std::string(polyRep[ii]) << "\n";
		term *= polyRep[ii];
		//std::cout << std::string(polyRep[nn]) << "OP " << isProductNode[nn] << " " << std::string(term) << "\n";
		if ((*isProductNode)[nn]) {
			polyRep[nn] *= term;
		} else {
			polyRep[nn] += term;
		}
		//std::cout << "result: " << std::string(polyRep[nn]) << "\n";
	}

	status[nn] = 2;
}

void PathCalc::buildPolynomial(FitContext *fc)
{
	prepS(fc);
	prepA(fc);
	unsigned curV = versionS + versionIA;
	if (mio) {
		prepM(fc);
		curV += versionM;
	}
	if (!ignoreVersion && versionPoly == curV) return;
	versionPoly = curV;

	if (verbose >= 2) {
		mxLog("PathCalc::buildPolynomial for %u (S%u A%u M%u)", curV,
					versionS, versionIA, versionM);
	}

	for (auto &p1 : polyRep) p1.clear();

	if (mio) {
		for (int ii=0; ii < numVars; ++ii) {
			polyRep[ii].addMonomial(Monomial< double >(mio->full(ii)));
		}
	}

	/* old version with Cholesky, doesn't work with non-positive definite S, but probably easier to extend to derivatives. Also,
	 * polynomials are more sparse with the Cholesky variant. An alternative could be to use a sign switch in the Cholesky decomposition,
	 * thereby working with normally distributed variables of variance either 1 or -1.
	 double[][] cholesky = null;
	 try {
	 cholesky = Statik.choleskyDecompose(symVal,0.001);
	 } catch (Exception e) {
	 throw new RuntimeException("Polynomial representation is impossible because symmetric matrix is not positive definite: "+e);
	 }

	 int[] x = new int[anzFac]; int k = 0; for (int i=0; i<anzFac; i++) if (cholesky[i][i]!=0.0) x[i] = k++;
	 for (int i=0; i<anzFac; i++) for (int j=0; j<=i; j++) if (cholesky[i][j] != 0.0) polynomialRepresentation[i].addMonomial(cholesky[i][j], x[j]);
	 polynomialRepresentationVariances = Statik.ensureSize(polynomialRepresentationVariances, k);
	 for (int i=0; i<polynomialRepresentationVariances.length; i++) polynomialRepresentationVariances[i] = 1.0;
	*/

	// Add option to use Cholesky with fallback to SelfAdjointEigenSolver TODO
	symSolver.compute(sio->full);
	auto &symEv = symSolver.eigenvalues();
	auto &symVec = symSolver.eigenvectors();
	for (int jj=0; jj < numVars; ++jj) {
		if (symEv(jj) == 0) continue;
		for (int ii=0; ii < numVars; ++ii) {
			if (symVec(ii,jj) == 0) continue;
			polyRep[ii].addMonomial(symVec(ii,jj), jj);
		}
	}

	// for (int ii=0; ii < numVars; ++ii) {
	// 	std::cout << ii << ":" << std::string(polyRep[ii]) << "\n";
	// }

	std::vector<int> status(numVars, 0);
	for (int ii=0; ii<numVars; ii++) {
		appendPolyRep(ii, status);
	}

	// mxPrintMat("vec", symVec);
	if (verbose >= 2) {
		std::ostringstream temp;
		for (int ii=0; ii < numVars; ++ii) {
			temp << ii << " " << symEv[ii] << ":" << std::string(polyRep[ii]) << "\n";
		}
		mxLogBig(temp.str());
	}

	// Could be smarter and avoid latents except when needed TODO
	meanOut.resize(numVars);
	for (int ii=0; ii<numVars; ++ii) {
		meanOut[ii] = polynomialToMoment(polyRep[ii], symEv);
	}
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
 * This file is part of the libone project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <stdio.h>
#include <string.h>

#include <librevenge/librevenge.h>
#include <librevenge-generators/librevenge-generators.h>
#include <librevenge-stream/librevenge-stream.h>

#include <libone/libone.h>

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifndef VERSION
#define VERSION "UNKNOWN VERSION"
#endif

namespace
{

int printUsage()
{
  printf("Usage: one2raw [OPTION] <Document>\n");
  printf("\n");
  printf("Options:\n");
  printf("--callgraph           Display the call graph nesting level\n");
  printf("--help                Shows this help message\n");
  printf("--version             Output one2raw version \n");
  return -1;
}

int printVersion()
{
  printf("one2raw %s\n", VERSION);
  return 0;
}

} // anonymous namespace

using libone::ONEDocument;

int main(int argc, char *argv[])
{
  bool printIndentLevel = false;
  char *file = 0;
  const char *p = 0;

  if (argc < 2)
    return printUsage();

  for (int i = 1; i < argc; i++)
  {
    if (!strcmp(argv[i], "--callgraph"))
      printIndentLevel = true;
    else if (!strcmp(argv[i], "--version"))
      return printVersion();
    else if (!file && strncmp(argv[i], "--", 2))
      file = argv[i];
    else
      return printUsage();
  }

  if (!file)
    return printUsage();

  std::shared_ptr<librevenge::RVNGInputStream> input(new librevenge::RVNGFileStream(file));

  ONEDocument::Type type = ONEDocument::TYPE_ONE2016;
  //ONEDocument::Confidence confidence = ONEDocument::isSupported(input.get(), &type);

  librevenge::RVNGRawDrawingGenerator documentGenerator(printIndentLevel);

  return (ONEDocument::RESULT_OK == ONEDocument::parse(input.get(), &documentGenerator, type, p)) ? 0 : 1;
}

/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */
<commit_msg>Add missing include<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
 * This file is part of the libone project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <stdio.h>
#include <string.h>

#include <memory>

#include <librevenge/librevenge.h>
#include <librevenge-generators/librevenge-generators.h>
#include <librevenge-stream/librevenge-stream.h>

#include <libone/libone.h>

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifndef VERSION
#define VERSION "UNKNOWN VERSION"
#endif

namespace
{

int printUsage()
{
  printf("Usage: one2raw [OPTION] <Document>\n");
  printf("\n");
  printf("Options:\n");
  printf("--callgraph           Display the call graph nesting level\n");
  printf("--help                Shows this help message\n");
  printf("--version             Output one2raw version \n");
  return -1;
}

int printVersion()
{
  printf("one2raw %s\n", VERSION);
  return 0;
}

} // anonymous namespace

using libone::ONEDocument;

int main(int argc, char *argv[])
{
  bool printIndentLevel = false;
  char *file = 0;
  const char *p = 0;

  if (argc < 2)
    return printUsage();

  for (int i = 1; i < argc; i++)
  {
    if (!strcmp(argv[i], "--callgraph"))
      printIndentLevel = true;
    else if (!strcmp(argv[i], "--version"))
      return printVersion();
    else if (!file && strncmp(argv[i], "--", 2))
      file = argv[i];
    else
      return printUsage();
  }

  if (!file)
    return printUsage();

  std::shared_ptr<librevenge::RVNGInputStream> input(new librevenge::RVNGFileStream(file));

  ONEDocument::Type type = ONEDocument::TYPE_ONE2016;
  //ONEDocument::Confidence confidence = ONEDocument::isSupported(input.get(), &type);

  librevenge::RVNGRawDrawingGenerator documentGenerator(printIndentLevel);

  return (ONEDocument::RESULT_OK == ONEDocument::parse(input.get(), &documentGenerator, type, p)) ? 0 : 1;
}

/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */
<|endoftext|>