<commit_before>/*
 * AsyncConnectionImpl.hpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#ifndef CORE_HTTP_ASYNC_CONNECTION_IMPL_HPP
#define CORE_HTTP_ASYNC_CONNECTION_IMPL_HPP

#include <boost/array.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/enable_shared_from_this.hpp>

#include <boost/asio/write.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/placeholders.hpp>

#include <core/Error.hpp>
#include <core/Log.hpp>

#include <core/http/Request.hpp>
#include <core/http/Response.hpp>
#include <core/http/SocketUtils.hpp>
#include <core/http/RequestParser.hpp>
#include <core/http/AsyncConnection.hpp>

namespace rstudio {
namespace core {
namespace http {

template <typename ProtocolType>
class AsyncConnectionImpl :
   public AsyncConnection,
   public boost::enable_shared_from_this<AsyncConnectionImpl<ProtocolType> >,
   boost::noncopyable
{
public:
   typedef boost::function<void(
         boost::shared_ptr<AsyncConnectionImpl<ProtocolType> >,
         http::Request*)> Handler;

public:
   AsyncConnectionImpl(boost::asio::io_service& ioService,
                       const Handler& handler,
                       const RequestFilter& requestFilter = RequestFilter(),
                       const ResponseFilter& responseFilter = ResponseFilter())
      : ioService_(ioService),
        socket_(ioService),
        handler_(handler),
        requestFilter_(requestFilter),
        responseFilter_(responseFilter)

   {
   }

   typename ProtocolType::socket& socket()
   {
      return socket_;
   }

   void startReading()
   {
      readSome();
   }

   virtual boost::asio::io_service& ioService()
   {
      return ioService_;
   }

   virtual const http::Request& request() const
   {
      return request_;
   }

   virtual http::Response& response()
   {
      return response_;
   }

   virtual void writeResponse(bool close = true)
   {
      // add extra response headers
      response_.setHeader("Date", util::httpDate());
      if (close)
         response_.setHeader("Connection", "close");

      // call the response filter if we have one
      if (responseFilter_)
         responseFilter_(originalUri_, &response_);

      // write
      boost::asio::async_write(
          socket_,
          response_.toBuffers(),
          boost::bind(
               &AsyncConnectionImpl<ProtocolType>::handleWrite,
               AsyncConnectionImpl<ProtocolType>::shared_from_this(),
               boost::asio::placeholders::error,
               close)
      );
   }

   virtual void writeResponse(const http::Response& response, bool close = true)
   {
      response_.assign(response);
      writeResponse(close);
   }

   virtual void writeError(const Error& error)
   {
      response_.setError(error);
      writeResponse();
   }

   // satisfy lower-level http::Socket interface (used when the connection
   // is upgraded to a websocket connection and no longer conforms to the
   // request/response protocol used by the class in the ordinary course
   // of business)

   virtual void asyncReadSome(boost::asio::mutable_buffers_1 buffer,
                              Socket::Handler handler)
   {
      socket().async_read_some(buffer, handler);
   }

   virtual void asyncWrite(
                     const std::vector<boost::asio::const_buffer>& buffers,
                     Socket::Handler handler)
   {
      boost::asio::async_write(socket(), buffers, handler);
   }

   virtual void close()
   {
      Error error = closeSocket(socket_);
      if (error && !core::http::isConnectionTerminatedError(error))
         LOG_ERROR(error);
   }

private:

   void handleRead(const boost::system::error_code& e,
                   std::size_t bytesTransferred)
   {
      try
      {
         if (!e)
         {
            // parse next chunk
            RequestParser::status status = requestParser_.parse(
                                             request_,
                                             buffer_.data(),
                                             buffer_.data() + bytesTransferred);

            // error - return bad request
            if (status == RequestParser::error)
            {
               response_.setStatusCode(http::status::BadRequest);
               writeResponse();
            }

            // incomplete -- keep reading
            else if (status == RequestParser::incomplete)
            {
               readSome();
            }

            // got valid request -- handle it
            else
            {
               // record the original uri
               originalUri_ = request_.uri();

               // call the request filter if we have one
               if (requestFilter_)
                  requestFilter_(&request_);

               // call the handler
               handler_(AsyncConnectionImpl<ProtocolType>::shared_from_this(),
                        &request_);
            }
         }
         else // error reading
         {
            // log the error if it wasn't connection terminated
            Error error(e, ERROR_LOCATION);
            if (!isConnectionTerminatedError(error))
               LOG_ERROR(error);

            // close the socket
            error = closeSocket(socket_);
            if (error)
               LOG_ERROR(error);

            //
            // no more async operations are initiated here so the shared_ptr to
            // this connection no more references and is automatically destroyed
            //
         }
      }
      CATCH_UNEXPECTED_EXCEPTION
   }

   void handleWrite(const boost::system::error_code& e, bool close)
   {
      try
      {
         if (e)
         {
            // log the error if it wasn't connection terminated
            Error error(e, ERROR_LOCATION);
            if (!http::isConnectionTerminatedError(error))
               LOG_ERROR(error);
         }

         // close the socket
         if (close)
         {
            Error error = closeSocket(socket_);
            if (error)
               LOG_ERROR(error);
         }

         //
         // no more async operations are initiated here so the shared_ptr to
         // this connection no more references and is automatically destroyed
         //
      }
      CATCH_UNEXPECTED_EXCEPTION
   }

   void readSome()
   {
      socket_.async_read_some(
         boost::asio::buffer(buffer_),
         boost::bind(
               &AsyncConnectionImpl<ProtocolType>::handleRead,
               AsyncConnectionImpl<ProtocolType>::shared_from_this(),
               boost::asio::placeholders::error,
               boost::asio::placeholders::bytes_transferred)
      );
   }

private:
   boost::asio::io_service& ioService_;
   typename ProtocolType::socket socket_;
   Handler handler_;
   RequestFilter requestFilter_;
   ResponseFilter responseFilter_;
   boost::array<char, 8192> buffer_ ;
   RequestParser requestParser_ ;
   std::string originalUri_;
   http::Request request_;
   http::Response response_;
};

} // namespace http
} // namespace core
} // namespace rstudio

#endif // CORE_HTTP_ASYNC_CONNECTION_IMPL_HPP

<commit_msg>record absolute uri for passing to response filter<commit_after>/*
 * AsyncConnectionImpl.hpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#ifndef CORE_HTTP_ASYNC_CONNECTION_IMPL_HPP
#define CORE_HTTP_ASYNC_CONNECTION_IMPL_HPP

#include <boost/array.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/enable_shared_from_this.hpp>

#include <boost/asio/write.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/placeholders.hpp>

#include <core/Error.hpp>
#include <core/Log.hpp>

#include <core/http/Request.hpp>
#include <core/http/Response.hpp>
#include <core/http/SocketUtils.hpp>
#include <core/http/RequestParser.hpp>
#include <core/http/AsyncConnection.hpp>

namespace rstudio {
namespace core {
namespace http {

template <typename ProtocolType>
class AsyncConnectionImpl :
   public AsyncConnection,
   public boost::enable_shared_from_this<AsyncConnectionImpl<ProtocolType> >,
   boost::noncopyable
{
public:
   typedef boost::function<void(
         boost::shared_ptr<AsyncConnectionImpl<ProtocolType> >,
         http::Request*)> Handler;

public:
   AsyncConnectionImpl(boost::asio::io_service& ioService,
                       const Handler& handler,
                       const RequestFilter& requestFilter = RequestFilter(),
                       const ResponseFilter& responseFilter = ResponseFilter())
      : ioService_(ioService),
        socket_(ioService),
        handler_(handler),
        requestFilter_(requestFilter),
        responseFilter_(responseFilter)

   {
   }

   typename ProtocolType::socket& socket()
   {
      return socket_;
   }

   void startReading()
   {
      readSome();
   }

   virtual boost::asio::io_service& ioService()
   {
      return ioService_;
   }

   virtual const http::Request& request() const
   {
      return request_;
   }

   virtual http::Response& response()
   {
      return response_;
   }

   virtual void writeResponse(bool close = true)
   {
      // add extra response headers
      response_.setHeader("Date", util::httpDate());
      if (close)
         response_.setHeader("Connection", "close");

      // call the response filter if we have one
      if (responseFilter_)
         responseFilter_(originalUri_, &response_);

      // write
      boost::asio::async_write(
          socket_,
          response_.toBuffers(),
          boost::bind(
               &AsyncConnectionImpl<ProtocolType>::handleWrite,
               AsyncConnectionImpl<ProtocolType>::shared_from_this(),
               boost::asio::placeholders::error,
               close)
      );
   }

   virtual void writeResponse(const http::Response& response, bool close = true)
   {
      response_.assign(response);
      writeResponse(close);
   }

   virtual void writeError(const Error& error)
   {
      response_.setError(error);
      writeResponse();
   }

   // satisfy lower-level http::Socket interface (used when the connection
   // is upgraded to a websocket connection and no longer conforms to the
   // request/response protocol used by the class in the ordinary course
   // of business)

   virtual void asyncReadSome(boost::asio::mutable_buffers_1 buffer,
                              Socket::Handler handler)
   {
      socket().async_read_some(buffer, handler);
   }

   virtual void asyncWrite(
                     const std::vector<boost::asio::const_buffer>& buffers,
                     Socket::Handler handler)
   {
      boost::asio::async_write(socket(), buffers, handler);
   }

   virtual void close()
   {
      Error error = closeSocket(socket_);
      if (error && !core::http::isConnectionTerminatedError(error))
         LOG_ERROR(error);
   }

private:

   void handleRead(const boost::system::error_code& e,
                   std::size_t bytesTransferred)
   {
      try
      {
         if (!e)
         {
            // parse next chunk
            RequestParser::status status = requestParser_.parse(
                                             request_,
                                             buffer_.data(),
                                             buffer_.data() + bytesTransferred);

            // error - return bad request
            if (status == RequestParser::error)
            {
               response_.setStatusCode(http::status::BadRequest);
               writeResponse();
            }

            // incomplete -- keep reading
            else if (status == RequestParser::incomplete)
            {
               readSome();
            }

            // got valid request -- handle it
            else
            {
               // record the original uri
               originalUri_ = request_.absoluteUri();

               // call the request filter if we have one
               if (requestFilter_)
                  requestFilter_(&request_);

               // call the handler
               handler_(AsyncConnectionImpl<ProtocolType>::shared_from_this(),
                        &request_);
            }
         }
         else // error reading
         {
            // log the error if it wasn't connection terminated
            Error error(e, ERROR_LOCATION);
            if (!isConnectionTerminatedError(error))
               LOG_ERROR(error);

            // close the socket
            error = closeSocket(socket_);
            if (error)
               LOG_ERROR(error);

            //
            // no more async operations are initiated here so the shared_ptr to
            // this connection no more references and is automatically destroyed
            //
         }
      }
      CATCH_UNEXPECTED_EXCEPTION
   }

   void handleWrite(const boost::system::error_code& e, bool close)
   {
      try
      {
         if (e)
         {
            // log the error if it wasn't connection terminated
            Error error(e, ERROR_LOCATION);
            if (!http::isConnectionTerminatedError(error))
               LOG_ERROR(error);
         }

         // close the socket
         if (close)
         {
            Error error = closeSocket(socket_);
            if (error)
               LOG_ERROR(error);
         }

         //
         // no more async operations are initiated here so the shared_ptr to
         // this connection no more references and is automatically destroyed
         //
      }
      CATCH_UNEXPECTED_EXCEPTION
   }

   void readSome()
   {
      socket_.async_read_some(
         boost::asio::buffer(buffer_),
         boost::bind(
               &AsyncConnectionImpl<ProtocolType>::handleRead,
               AsyncConnectionImpl<ProtocolType>::shared_from_this(),
               boost::asio::placeholders::error,
               boost::asio::placeholders::bytes_transferred)
      );
   }

private:
   boost::asio::io_service& ioService_;
   typename ProtocolType::socket socket_;
   Handler handler_;
   RequestFilter requestFilter_;
   ResponseFilter responseFilter_;
   boost::array<char, 8192> buffer_ ;
   RequestParser requestParser_ ;
   std::string originalUri_;
   http::Request request_;
   http::Response response_;
};

} // namespace http
} // namespace core
} // namespace rstudio

#endif // CORE_HTTP_ASYNC_CONNECTION_IMPL_HPP

<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qwidget.h"
#include "qpainter.h"
#include "qfont_p.h"
#include <private/qunicodetables_p.h>
#include "qfontdatabase.h"
#include "qtextcodec.h"
#include "qapplication.h"
#include "qfile.h"
#include "qtextstream.h"
#include "qmap.h"
//#include "qmemorymanager_qws.h"
#include "qtextengine_p.h"
#include "qfontengine_p.h"
#if !defined(QT_NO_FREETYPE)
#include "qfontengine_ft_p.h"
#endif

QT_BEGIN_NAMESPACE

void QFont::initialize()
{ }

void QFont::cleanup()
{
    QFontCache::cleanup();
}

/*****************************************************************************
  QFont member functions
 *****************************************************************************/

Qt::HANDLE QFont::handle() const
{
#ifndef QT_NO_FREETYPE
    return freetypeFace();
#endif
    return 0;
}

FT_Face QFont::freetypeFace() const
{
#ifndef QT_NO_FREETYPE
    QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
    if (engine->type() == QFontEngine::Multi)
        engine = static_cast<QFontEngineMulti *>(engine)->engine(0);
    if (engine->type() == QFontEngine::Freetype) {
        const QFontEngineFT *ft = static_cast<const QFontEngineFT *>(engine);
        return ft->non_locked_face();
    }
#endif
    return 0;
}

QString QFont::rawName() const
{
    return QLatin1String("unknown");
}

void QFont::setRawName(const QString &)
{
}

QString QFont::defaultFamily() const
{
    switch(d->request.styleHint) {
        case QFont::Times:
            //return QString::fromLatin1("times");
            return QString::fromLatin1("A-OTF Ryumin Pr6");
        case QFont::Courier:
        case QFont::Monospace:
            return QString::fromLatin1("courier");
        case QFont::Decorative:
            return QString::fromLatin1("old english");
        case QFont::Helvetica:
        case QFont::System:
        default:
            return QString::fromLatin1("A-OTF Gothic MB101 Pr6");
            //return QString::fromLatin1("helvetica");
    }
}

QString QFont::lastResortFamily() const
{
    return QString::fromLatin1("TT Gothic MB101 Pr6");
    //return QString::fromLatin1("helvetica");
}

QString QFont::lastResortFont() const
{
    qFatal("QFont::lastResortFont: Cannot find any reasonable font");
    // Shut compiler up
    return QString();
}

QT_END_NAMESPACE
<commit_msg>re-revert this nonsense.  we'll make the webviews override.<commit_after>/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qwidget.h"
#include "qpainter.h"
#include "qfont_p.h"
#include <private/qunicodetables_p.h>
#include "qfontdatabase.h"
#include "qtextcodec.h"
#include "qapplication.h"
#include "qfile.h"
#include "qtextstream.h"
#include "qmap.h"
//#include "qmemorymanager_qws.h"
#include "qtextengine_p.h"
#include "qfontengine_p.h"
#if !defined(QT_NO_FREETYPE)
#include "qfontengine_ft_p.h"
#endif

QT_BEGIN_NAMESPACE

void QFont::initialize()
{ }

void QFont::cleanup()
{
    QFontCache::cleanup();
}

/*****************************************************************************
  QFont member functions
 *****************************************************************************/

Qt::HANDLE QFont::handle() const
{
#ifndef QT_NO_FREETYPE
    return freetypeFace();
#endif
    return 0;
}

FT_Face QFont::freetypeFace() const
{
#ifndef QT_NO_FREETYPE
    QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
    if (engine->type() == QFontEngine::Multi)
        engine = static_cast<QFontEngineMulti *>(engine)->engine(0);
    if (engine->type() == QFontEngine::Freetype) {
        const QFontEngineFT *ft = static_cast<const QFontEngineFT *>(engine);
        return ft->non_locked_face();
    }
#endif
    return 0;
}

QString QFont::rawName() const
{
    return QLatin1String("unknown");
}

void QFont::setRawName(const QString &)
{
}

QString QFont::defaultFamily() const
{
    switch(d->request.styleHint) {
        case QFont::Times:
            return QString::fromLatin1("times");
        case QFont::Courier:
        case QFont::Monospace:
            return QString::fromLatin1("courier");
        case QFont::Decorative:
            return QString::fromLatin1("old english");
        case QFont::Helvetica:
        case QFont::System:
        default:
            return QString::fromLatin1("helvetica");
    }
}

QString QFont::lastResortFamily() const
{
    return QString::fromLatin1("helvetica");
}

QString QFont::lastResortFont() const
{
    qFatal("QFont::lastResortFont: Cannot find any reasonable font");
    // Shut compiler up
    return QString();
}

QT_END_NAMESPACE
<|endoftext|>


<commit_before>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <nix/util/util.hpp>

#include <nix/hdf5/DataArrayHDF5.hpp>
#include <nix/hdf5/DataSet.hpp>
#include <nix/hdf5/DimensionHDF5.hpp>

using namespace std;

namespace nix {
namespace hdf5 {

DataArrayHDF5::DataArrayHDF5(const DataArrayHDF5 &data_array)
    : EntityWithSourcesHDF5(data_array.file(), data_array.block(), data_array.group(), data_array.id(), data_array.type(), data_array.name()),
      dimension_group(data_array.dimension_group)
{
}

DataArrayHDF5::DataArrayHDF5(const File &file, const Block &block, const Group &group,
                             const string &id, const string &type, const string &name)
    : DataArrayHDF5(file, block, group, id, type, name, util::getTime())
{
}

DataArrayHDF5::DataArrayHDF5(const File &file, const Block &block, const Group &group,
                             const string &id, const string &type, const string &name, time_t time)
    : EntityWithSourcesHDF5(file, block, group, id, type, name, time)
{
    dimension_group = this->group().openGroup("dimensions", true);
}

//--------------------------------------------------
// Element getters and setters
//--------------------------------------------------

boost::optional<std::string> DataArrayHDF5::label() const {
    boost::optional<std::string> ret;
    string value;
    bool have_attr = group().getAttr("label", value);

    if (have_attr) {
        ret = value;
    }

    return ret;
}

void DataArrayHDF5::label(const string &label) {
    if(label.empty()) {
        throw EmptyString("label");
    }
    else {
        group().setAttr("label", label);
        forceUpdatedAt();
    }
}

void DataArrayHDF5::label(const none_t t) {
    if(group().hasAttr("label")) {
        group().removeAttr("label");
    }
    forceUpdatedAt();
}

boost::optional<std::string> DataArrayHDF5::unit() const {
    boost::optional<std::string> ret;
    string value;
    group().getAttr("unit", value);
    ret = value;
    return ret;
}

void DataArrayHDF5::unit(const string &unit) {
    if(unit.empty()) {
        throw EmptyString("unit");
    }
    else {
        group().setAttr("unit", unit);
        forceUpdatedAt();
    }
}

void DataArrayHDF5::unit(const none_t t) {
    if(group().hasAttr("unit")) {
        group().removeAttr("unit");
    }
    forceUpdatedAt();
}

// TODO use defaults
boost::optional<double> DataArrayHDF5::expansionOrigin() const {
    boost::optional<double> ret;
    double expansion_origin;
    group().getAttr("expansion_origin", expansion_origin);
    ret = expansion_origin;
    return ret;
}

void DataArrayHDF5::expansionOrigin(double expansion_origin) {
    group().setAttr("expansion_origin", expansion_origin);
    forceUpdatedAt();
}

void DataArrayHDF5::expansionOrigin(const none_t t) {
    if(group().hasAttr("expansionOrigin")) {
        group().removeAttr("expansionOrigin");
    }
    forceUpdatedAt();
}

// TODO use defaults
vector<double> DataArrayHDF5::polynomCoefficients()const{
    vector<double> polynom_coefficients;

    if (group().hasData("polynom_coefficients")) {
        DataSet ds = group().openData("polynom_coefficients");
        ds.read(polynom_coefficients, true);
    }

    return polynom_coefficients;
}

void DataArrayHDF5::polynomCoefficients(vector<double> &coefficients) {
    DataSet ds;
    if (group().hasData("polynom_coefficients")) {
        ds = group().openData("polynom_coefficients");
        ds.setExtent({coefficients.size()});
    } else {
        ds = DataSet::create(group().h5Group(), "polynom_coefficients", coefficients);
    }
    ds.write(coefficients);
    forceUpdatedAt();
}

void DataArrayHDF5::polynomCoefficients(const none_t t) {
    if(group().hasAttr("polynom_coefficients")) {
        group().removeAttr("polynom_coefficients");
    }
    forceUpdatedAt();
}

//--------------------------------------------------
// Methods concerning dimensions
//--------------------------------------------------

size_t DataArrayHDF5::dimensionCount() const {
    return dimension_group.objectCount();
}

Dimension DataArrayHDF5::getDimension(size_t id) const {
    string str_id = util::numToStr(id);

    if (dimension_group.hasGroup(str_id)) {
        Group dim_group = dimension_group.openGroup(str_id, false);
        string dim_type_name;
        dim_group.getAttr("dimension_type", dim_type_name);
        DimensionType dim_type = dimensionTypeFromStr(dim_type_name);

        Dimension dim;

        if (dim_type == DimensionType::Set ) {
            auto tmp = make_shared<SetDimensionHDF5>(dim_group, id);
            dim = SetDimension(tmp);
        } else if (dim_type == DimensionType::Range) {
            std::vector<double> ticks;
            dim_group.getData("ticks", ticks);
            auto tmp = make_shared<RangeDimensionHDF5>(dim_group, id, ticks);
            dim = RangeDimension(tmp);
        } else if (dim_type == DimensionType::Sample) {
            double samplingInterval;
            dim_group.getAttr("sampling_interval", samplingInterval);
            auto tmp = make_shared<SampledDimensionHDF5>(dim_group, id, samplingInterval);
            dim = SampledDimension(tmp);
        } else {
            throw runtime_error("Invalid dimension type");
        }

        return dim;
    } else {
        return Dimension();
    }
}

template<DimensionType dtype, typename T>
Dimension DataArrayHDF5::_createDimension(size_t id, T var) {
    size_t dim_count = dimensionCount();

    if (id > (dim_count + 1) || id <= 0) { // dim_count+1 since index starts at 1
        runtime_error("Invalid dimension id: has to be 0 < id <= #(dimensions)+1");
    }

    string str_id = util::numToStr(id);

    if (dimension_group.hasGroup(str_id)) {
        dimension_group.removeGroup(str_id);
    }

    Group dim_group = dimension_group.openGroup(str_id, true);
    Dimension dim;

    if (dtype == DimensionType::Range || dtype == DimensionType::Sample) {
        typedef typename std::conditional<dtype == DimensionType::Range,
                                          RangeDimensionHDF5,
                                          SampledDimensionHDF5>::type
                                          dimTypeHDF5;
        typedef typename std::conditional<dtype == DimensionType::Range,
                                          RangeDimension,
                                          SampledDimension>::type
                                          dimType;
        auto tmp = make_shared<dimTypeHDF5>(dim_group, id, var);
        dim = dimType(tmp);
    } else {
        throw runtime_error("Invalid dimension type");
    }

    return dim;
}

template<>
Dimension DataArrayHDF5::_createDimension<DimensionType::Set, none_t>(size_t id, none_t var) {
    size_t dim_count = dimensionCount();

    if (id > (dim_count + 1) || id <= 0) { // dim_count+1 since index starts at 1
        runtime_error("Invalid dimension id: has to be 0 < id <= #(dimensions)+1");
    }

    string str_id = util::numToStr(id);

    if (dimension_group.hasGroup(str_id)) {
        dimension_group.removeGroup(str_id);
    }

    Group dim_group = dimension_group.openGroup(str_id, true);
    Dimension dim;

    // no dim-type check needed since method only called if type=DimensionType::Set
    auto tmp = make_shared<SetDimensionHDF5>(dim_group, id);
    dim = SetDimension(tmp);

    return dim;
}

Dimension DataArrayHDF5::createSetDimension(size_t id) {
    return _createDimension<DimensionType::Set>(id);
}

Dimension DataArrayHDF5::createRangeDimension(size_t id, std::vector<double> ticks) {
    return _createDimension<DimensionType::Range>(id, ticks);
}

Dimension DataArrayHDF5::createSampledDimension(size_t id, double samplingInterval) {
    return _createDimension<DimensionType::Sample>(id, samplingInterval);
}

bool DataArrayHDF5::deleteDimension(size_t id) {
    bool deleted = false;
    size_t dim_count = dimensionCount();
    string str_id = util::numToStr(id);

    if (dimension_group.hasGroup(str_id)) {
        dimension_group.removeGroup(str_id);
        deleted = true;
    }

    if (deleted && id < dim_count) {
        for (size_t old_id = id + 1; old_id <= dim_count; old_id++) {
            string str_old_id = util::numToStr(old_id);
            string str_new_id = util::numToStr(old_id - 1);
            dimension_group.renameGroup(str_old_id, str_new_id);
        }
    }

    return deleted;
}

//--------------------------------------------------
// Other methods and functions
//--------------------------------------------------

void DataArrayHDF5::swap(DataArrayHDF5 &other) {
    using std::swap;

    EntityWithSourcesHDF5::swap(other);
    swap(dimension_group, other.dimension_group);
}

DataArrayHDF5& DataArrayHDF5::operator=(const DataArrayHDF5 &other) {
    if (*this != other) {
        DataArrayHDF5 tmp(other);
        swap(tmp);
    }

    return *this;
}

DataArrayHDF5::~DataArrayHDF5() {}

void DataArrayHDF5::createData(DataType dtype, const NDSize &size)
{
    if (group().hasData("data")) {
        throw new std::runtime_error("DataArray alread exists"); //TODO: FIXME, better exception
    }

    DataSet::create(group().h5Group(), "data", dtype, size);
    DataSet ds = group().openData("data");
}

bool DataArrayHDF5::hasData() const
{
    return group().hasData("data");
}

void DataArrayHDF5::write(DataType dtype, const void *data, const NDSize &count, const NDSize &offset)
{
    DataSet ds;

    if (!group().hasData("data")) {
        ds = DataSet::create(group().h5Group(), "data", dtype, count);
    } else {
        ds = group().openData("data");
    }

    if (offset.size()) {
        Selection fileSel = ds.createSelection();
        fileSel.select(count, offset);
        Selection memSel(DataSpace::create(count, false));

        ds.write(dtype, data, fileSel, memSel);
    } else {
        ds.write(dtype, count, data);
    }
}

void DataArrayHDF5::read(DataType dtype, void *data, const NDSize &count, const NDSize &offset) const
{
    if (!group().hasData("data")) {
        return;
    }

    DataSet ds = group().openData("data");

    if (offset.size()) {
        Selection fileSel = ds.createSelection();
        fileSel.select(count, offset);
        Selection memSel(DataSpace::create(count, false));

        ds.read(dtype, data, fileSel, memSel);
    } else {
        ds.read(dtype, count, data);
    }

}

NDSize DataArrayHDF5::dataExtent(void) const
{
    if (!group().hasData("data")) {
        return NDSize{};
    }

    DataSet ds = group().openData("data");
    return ds.size();
}

void DataArrayHDF5::dataExtent(const NDSize &extent)
{
    if (!group().hasData("data")) {
        throw runtime_error("Data field not found in DataArray!");
    }

    DataSet ds = group().openData("data");
    ds.setExtent(extent);
}

DataType DataArrayHDF5::dataType(void) const
{
    if (!group().hasData("data")) {
        //we could also throw an exception but I think returning
        //Nothing here is better (ck) - agreed (bm)
        return DataType::Nothing;
    }

    DataSet ds = group().openData("data");
    return ds.dataType();
}

} // namespace hdf5
} // namespace nix
<commit_msg>DataArrayHDF5::unit: Fix getter for unit() [none case]<commit_after>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <nix/util/util.hpp>

#include <nix/hdf5/DataArrayHDF5.hpp>
#include <nix/hdf5/DataSet.hpp>
#include <nix/hdf5/DimensionHDF5.hpp>

using namespace std;

namespace nix {
namespace hdf5 {

DataArrayHDF5::DataArrayHDF5(const DataArrayHDF5 &data_array)
    : EntityWithSourcesHDF5(data_array.file(), data_array.block(), data_array.group(), data_array.id(), data_array.type(), data_array.name()),
      dimension_group(data_array.dimension_group)
{
}

DataArrayHDF5::DataArrayHDF5(const File &file, const Block &block, const Group &group,
                             const string &id, const string &type, const string &name)
    : DataArrayHDF5(file, block, group, id, type, name, util::getTime())
{
}

DataArrayHDF5::DataArrayHDF5(const File &file, const Block &block, const Group &group,
                             const string &id, const string &type, const string &name, time_t time)
    : EntityWithSourcesHDF5(file, block, group, id, type, name, time)
{
    dimension_group = this->group().openGroup("dimensions", true);
}

//--------------------------------------------------
// Element getters and setters
//--------------------------------------------------

boost::optional<std::string> DataArrayHDF5::label() const {
    boost::optional<std::string> ret;
    string value;
    bool have_attr = group().getAttr("label", value);

    if (have_attr) {
        ret = value;
    }

    return ret;
}

void DataArrayHDF5::label(const string &label) {
    if(label.empty()) {
        throw EmptyString("label");
    }
    else {
        group().setAttr("label", label);
        forceUpdatedAt();
    }
}

void DataArrayHDF5::label(const none_t t) {
    if(group().hasAttr("label")) {
        group().removeAttr("label");
    }
    forceUpdatedAt();
}

boost::optional<std::string> DataArrayHDF5::unit() const {
    boost::optional<std::string> ret;
    string value;
    bool have_attr = group().getAttr("unit", value);
    if (have_attr) {
        ret = value;
    }
    return ret;
}

void DataArrayHDF5::unit(const string &unit) {
    if(unit.empty()) {
        throw EmptyString("unit");
    }
    else {
        group().setAttr("unit", unit);
        forceUpdatedAt();
    }
}

void DataArrayHDF5::unit(const none_t t) {
    if(group().hasAttr("unit")) {
        group().removeAttr("unit");
    }
    forceUpdatedAt();
}

// TODO use defaults
boost::optional<double> DataArrayHDF5::expansionOrigin() const {
    boost::optional<double> ret;
    double expansion_origin;
    group().getAttr("expansion_origin", expansion_origin);
    ret = expansion_origin;
    return ret;
}

void DataArrayHDF5::expansionOrigin(double expansion_origin) {
    group().setAttr("expansion_origin", expansion_origin);
    forceUpdatedAt();
}

void DataArrayHDF5::expansionOrigin(const none_t t) {
    if(group().hasAttr("expansionOrigin")) {
        group().removeAttr("expansionOrigin");
    }
    forceUpdatedAt();
}

// TODO use defaults
vector<double> DataArrayHDF5::polynomCoefficients()const{
    vector<double> polynom_coefficients;

    if (group().hasData("polynom_coefficients")) {
        DataSet ds = group().openData("polynom_coefficients");
        ds.read(polynom_coefficients, true);
    }

    return polynom_coefficients;
}

void DataArrayHDF5::polynomCoefficients(vector<double> &coefficients) {
    DataSet ds;
    if (group().hasData("polynom_coefficients")) {
        ds = group().openData("polynom_coefficients");
        ds.setExtent({coefficients.size()});
    } else {
        ds = DataSet::create(group().h5Group(), "polynom_coefficients", coefficients);
    }
    ds.write(coefficients);
    forceUpdatedAt();
}

void DataArrayHDF5::polynomCoefficients(const none_t t) {
    if(group().hasAttr("polynom_coefficients")) {
        group().removeAttr("polynom_coefficients");
    }
    forceUpdatedAt();
}

//--------------------------------------------------
// Methods concerning dimensions
//--------------------------------------------------

size_t DataArrayHDF5::dimensionCount() const {
    return dimension_group.objectCount();
}

Dimension DataArrayHDF5::getDimension(size_t id) const {
    string str_id = util::numToStr(id);

    if (dimension_group.hasGroup(str_id)) {
        Group dim_group = dimension_group.openGroup(str_id, false);
        string dim_type_name;
        dim_group.getAttr("dimension_type", dim_type_name);
        DimensionType dim_type = dimensionTypeFromStr(dim_type_name);

        Dimension dim;

        if (dim_type == DimensionType::Set ) {
            auto tmp = make_shared<SetDimensionHDF5>(dim_group, id);
            dim = SetDimension(tmp);
        } else if (dim_type == DimensionType::Range) {
            std::vector<double> ticks;
            dim_group.getData("ticks", ticks);
            auto tmp = make_shared<RangeDimensionHDF5>(dim_group, id, ticks);
            dim = RangeDimension(tmp);
        } else if (dim_type == DimensionType::Sample) {
            double samplingInterval;
            dim_group.getAttr("sampling_interval", samplingInterval);
            auto tmp = make_shared<SampledDimensionHDF5>(dim_group, id, samplingInterval);
            dim = SampledDimension(tmp);
        } else {
            throw runtime_error("Invalid dimension type");
        }

        return dim;
    } else {
        return Dimension();
    }
}

template<DimensionType dtype, typename T>
Dimension DataArrayHDF5::_createDimension(size_t id, T var) {
    size_t dim_count = dimensionCount();

    if (id > (dim_count + 1) || id <= 0) { // dim_count+1 since index starts at 1
        runtime_error("Invalid dimension id: has to be 0 < id <= #(dimensions)+1");
    }

    string str_id = util::numToStr(id);

    if (dimension_group.hasGroup(str_id)) {
        dimension_group.removeGroup(str_id);
    }

    Group dim_group = dimension_group.openGroup(str_id, true);
    Dimension dim;

    if (dtype == DimensionType::Range || dtype == DimensionType::Sample) {
        typedef typename std::conditional<dtype == DimensionType::Range,
                                          RangeDimensionHDF5,
                                          SampledDimensionHDF5>::type
                                          dimTypeHDF5;
        typedef typename std::conditional<dtype == DimensionType::Range,
                                          RangeDimension,
                                          SampledDimension>::type
                                          dimType;
        auto tmp = make_shared<dimTypeHDF5>(dim_group, id, var);
        dim = dimType(tmp);
    } else {
        throw runtime_error("Invalid dimension type");
    }

    return dim;
}

template<>
Dimension DataArrayHDF5::_createDimension<DimensionType::Set, none_t>(size_t id, none_t var) {
    size_t dim_count = dimensionCount();

    if (id > (dim_count + 1) || id <= 0) { // dim_count+1 since index starts at 1
        runtime_error("Invalid dimension id: has to be 0 < id <= #(dimensions)+1");
    }

    string str_id = util::numToStr(id);

    if (dimension_group.hasGroup(str_id)) {
        dimension_group.removeGroup(str_id);
    }

    Group dim_group = dimension_group.openGroup(str_id, true);
    Dimension dim;

    // no dim-type check needed since method only called if type=DimensionType::Set
    auto tmp = make_shared<SetDimensionHDF5>(dim_group, id);
    dim = SetDimension(tmp);

    return dim;
}

Dimension DataArrayHDF5::createSetDimension(size_t id) {
    return _createDimension<DimensionType::Set>(id);
}

Dimension DataArrayHDF5::createRangeDimension(size_t id, std::vector<double> ticks) {
    return _createDimension<DimensionType::Range>(id, ticks);
}

Dimension DataArrayHDF5::createSampledDimension(size_t id, double samplingInterval) {
    return _createDimension<DimensionType::Sample>(id, samplingInterval);
}

bool DataArrayHDF5::deleteDimension(size_t id) {
    bool deleted = false;
    size_t dim_count = dimensionCount();
    string str_id = util::numToStr(id);

    if (dimension_group.hasGroup(str_id)) {
        dimension_group.removeGroup(str_id);
        deleted = true;
    }

    if (deleted && id < dim_count) {
        for (size_t old_id = id + 1; old_id <= dim_count; old_id++) {
            string str_old_id = util::numToStr(old_id);
            string str_new_id = util::numToStr(old_id - 1);
            dimension_group.renameGroup(str_old_id, str_new_id);
        }
    }

    return deleted;
}

//--------------------------------------------------
// Other methods and functions
//--------------------------------------------------

void DataArrayHDF5::swap(DataArrayHDF5 &other) {
    using std::swap;

    EntityWithSourcesHDF5::swap(other);
    swap(dimension_group, other.dimension_group);
}

DataArrayHDF5& DataArrayHDF5::operator=(const DataArrayHDF5 &other) {
    if (*this != other) {
        DataArrayHDF5 tmp(other);
        swap(tmp);
    }

    return *this;
}

DataArrayHDF5::~DataArrayHDF5() {}

void DataArrayHDF5::createData(DataType dtype, const NDSize &size)
{
    if (group().hasData("data")) {
        throw new std::runtime_error("DataArray alread exists"); //TODO: FIXME, better exception
    }

    DataSet::create(group().h5Group(), "data", dtype, size);
    DataSet ds = group().openData("data");
}

bool DataArrayHDF5::hasData() const
{
    return group().hasData("data");
}

void DataArrayHDF5::write(DataType dtype, const void *data, const NDSize &count, const NDSize &offset)
{
    DataSet ds;

    if (!group().hasData("data")) {
        ds = DataSet::create(group().h5Group(), "data", dtype, count);
    } else {
        ds = group().openData("data");
    }

    if (offset.size()) {
        Selection fileSel = ds.createSelection();
        fileSel.select(count, offset);
        Selection memSel(DataSpace::create(count, false));

        ds.write(dtype, data, fileSel, memSel);
    } else {
        ds.write(dtype, count, data);
    }
}

void DataArrayHDF5::read(DataType dtype, void *data, const NDSize &count, const NDSize &offset) const
{
    if (!group().hasData("data")) {
        return;
    }

    DataSet ds = group().openData("data");

    if (offset.size()) {
        Selection fileSel = ds.createSelection();
        fileSel.select(count, offset);
        Selection memSel(DataSpace::create(count, false));

        ds.read(dtype, data, fileSel, memSel);
    } else {
        ds.read(dtype, count, data);
    }

}

NDSize DataArrayHDF5::dataExtent(void) const
{
    if (!group().hasData("data")) {
        return NDSize{};
    }

    DataSet ds = group().openData("data");
    return ds.size();
}

void DataArrayHDF5::dataExtent(const NDSize &extent)
{
    if (!group().hasData("data")) {
        throw runtime_error("Data field not found in DataArray!");
    }

    DataSet ds = group().openData("data");
    ds.setExtent(extent);
}

DataType DataArrayHDF5::dataType(void) const
{
    if (!group().hasData("data")) {
        //we could also throw an exception but I think returning
        //Nothing here is better (ck) - agreed (bm)
        return DataType::Nothing;
    }

    DataSet ds = group().openData("data");
    return ds.dataType();
}

} // namespace hdf5
} // namespace nix
<|endoftext|>


<commit_before>/* libs/graphics/images/SkImageDecoder_libgif.cpp
**
** Copyright 2006, The Android Open Source Project
**
** 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.
*/

#include "SkMovie.h"
#include "SkColor.h"
#include "SkColorPriv.h"
#include "SkStream.h"
#include "SkTemplates.h"

#include "gif_lib.h"

class SkGIFMovie : public SkMovie {
public:
    SkGIFMovie(SkStream* stream);
    virtual ~SkGIFMovie();

protected:
    virtual bool onGetInfo(Info*);
    virtual bool onSetTime(SkMSec);
    virtual bool onGetBitmap(SkBitmap*);

private:
    GifFileType* fGIF;
    SavedImage* fCurrSavedImage;
};

static int Decode(GifFileType* fileType, GifByteType* out, int size) {
    SkStream* stream = (SkStream*) fileType->UserData;
    return (int) stream->read(out, size);
}

SkGIFMovie::SkGIFMovie(SkStream* stream)
{
    fGIF = DGifOpen( stream, Decode );
    if (NULL == fGIF)
        return;

    if (DGifSlurp(fGIF) != GIF_OK)
    {
        DGifCloseFile(fGIF);
        fGIF = NULL;
    }
    fCurrSavedImage = NULL;
}

SkGIFMovie::~SkGIFMovie()
{
    if (fGIF)
        DGifCloseFile(fGIF);
}

static SkMSec savedimage_duration(const SavedImage* image)
{
    for (int j = 0; j < image->ExtensionBlockCount; j++)
    {
        if (image->ExtensionBlocks[j].Function == GRAPHICS_EXT_FUNC_CODE)
        {
            int size = image->ExtensionBlocks[j].ByteCount;
            SkASSERT(size >= 4);
            const uint8_t* b = (const uint8_t*)image->ExtensionBlocks[j].Bytes;
            return ((b[2] << 8) | b[1]) * 10;
        }
    }
    return 0;
}

bool SkGIFMovie::onGetInfo(Info* info)
{
    if (NULL == fGIF)
        return false;

    SkMSec dur = 0;
    for (int i = 0; i < fGIF->ImageCount; i++)
        dur += savedimage_duration(&fGIF->SavedImages[i]);

    info->fDuration = dur;
    info->fWidth = fGIF->SWidth;
    info->fHeight = fGIF->SHeight;
    info->fIsOpaque = false;    // how to compute?
    return true;
}

bool SkGIFMovie::onSetTime(SkMSec time)
{
    if (NULL == fGIF)
        return false;

    SkMSec dur = 0;
    for (int i = 0; i < fGIF->ImageCount; i++)
    {
        dur += savedimage_duration(&fGIF->SavedImages[i]);
        if (dur >= time)
        {
            SavedImage* prev = fCurrSavedImage;
            fCurrSavedImage = &fGIF->SavedImages[i];
            return prev != fCurrSavedImage;
        }
    }
    fCurrSavedImage = &fGIF->SavedImages[fGIF->ImageCount - 1];
    return true;
}

bool SkGIFMovie::onGetBitmap(SkBitmap* bm)
{
    GifFileType* gif = fGIF;
    if (NULL == gif)
        return false;

    // should we check for the Image cmap or the global (SColorMap) first?
    ColorMapObject* cmap = gif->SColorMap;
    if (cmap == NULL)
        cmap = gif->Image.ColorMap;

    if (cmap == NULL || gif->ImageCount < 1 || cmap->ColorCount != (1 << cmap->BitsPerPixel))
    {
        SkASSERT(!"bad colortable setup");
        return false;
    }

    const int width = gif->SWidth;
    const int height = gif->SHeight;
    if (width <= 0 || height <= 0) {
        return false;
    }

    SavedImage*      gif_image = fCurrSavedImage;
    SkBitmap::Config config = SkBitmap::kIndex8_Config;

    SkColorTable* colorTable = SkNEW_ARGS(SkColorTable, (cmap->ColorCount));
    SkAutoUnref aur(colorTable);

    bm->setConfig(config, width, height, 0);
    if (!bm->allocPixels(colorTable)) {
        return false;
    }

    int transparent = -1;
    for (int i = 0; i < gif_image->ExtensionBlockCount; ++i) {
      ExtensionBlock* eb = gif_image->ExtensionBlocks + i;
      if (eb->Function == 0xF9 &&
          eb->ByteCount == 4) {
        bool has_transparency = ((eb->Bytes[0] & 1) == 1);
        if (has_transparency) {
          transparent = (unsigned char)eb->Bytes[3];
        }
      }
    }

    SkPMColor* colorPtr = colorTable->lockColors();

    if (transparent >= 0)
        memset(colorPtr, 0, cmap->ColorCount * 4);
    else
        colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOpaque_Flag);

    for (int index = 0; index < cmap->ColorCount; index++)
    {
        if (transparent != index)
            colorPtr[index] = SkPackARGB32(0xFF, cmap->Colors[index].Red,
                cmap->Colors[index].Green, cmap->Colors[index].Blue);
    }
    colorTable->unlockColors(true);

    unsigned char* in = (unsigned char*)gif_image->RasterBits;
    unsigned char* out = bm->getAddr8(0, 0);
    if (gif->Image.Interlace) {

      // deinterlace
        int row;
      // group 1 - every 8th row, starting with row 0
      for (row = 0; row < height; row += 8) {
        memcpy(out + width * row, in, width);
        in += width;
      }

      // group 2 - every 8th row, starting with row 4
      for (row = 4; row < height; row += 8) {
        memcpy(out + width * row, in, width);
        in += width;
      }

      // group 3 - every 4th row, starting with row 2
      for (row = 2; row < height; row += 4) {
        memcpy(out + width * row, in, width);
        in += width;
      }

      for (row = 1; row < height; row += 2) {
        memcpy(out + width * row, in, width);
        in += width;
      }

    } else {
      memcpy(out, in, width * height);
    }
    return true;
}

///////////////////////////////////////////////////////////////////////////////

#include "SkTRegistry.h"

SkMovie* Factory(SkStream* stream) {
    char buf[GIF_STAMP_LEN];
    if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN) {
        if (memcmp(GIF_STAMP,   buf, GIF_STAMP_LEN) == 0 ||
                memcmp(GIF87_STAMP, buf, GIF_STAMP_LEN) == 0 ||
                memcmp(GIF89_STAMP, buf, GIF_STAMP_LEN) == 0) {
            // must rewind here, since our construct wants to re-read the data
            stream->rewind();
            return SkNEW_ARGS(SkGIFMovie, (stream));
        }
    }
    return NULL;
}

static SkTRegistry<SkMovie*, SkStream*> gReg(Factory);
<commit_msg>Support various types of animation gif.<commit_after>/* libs/graphics/images/SkImageDecoder_libgif.cpp
**
** Copyright 2006, The Android Open Source Project
**
** 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.
*/

#include "SkMovie.h"
#include "SkColor.h"
#include "SkColorPriv.h"
#include "SkStream.h"
#include "SkTemplates.h"
#include "SkUtils.h"

#include "gif_lib.h"

class SkGIFMovie : public SkMovie {
public:
    SkGIFMovie(SkStream* stream);
    virtual ~SkGIFMovie();

protected:
    virtual bool onGetInfo(Info*);
    virtual bool onSetTime(SkMSec);
    virtual bool onGetBitmap(SkBitmap*);

private:
    GifFileType* fGIF;
    int fCurrIndex;
    int fLastDrawIndex;
    SkBitmap fBackup;
};

static int Decode(GifFileType* fileType, GifByteType* out, int size) {
    SkStream* stream = (SkStream*) fileType->UserData;
    return (int) stream->read(out, size);
}

SkGIFMovie::SkGIFMovie(SkStream* stream)
{
    fGIF = DGifOpen( stream, Decode );
    if (NULL == fGIF)
        return;

    if (DGifSlurp(fGIF) != GIF_OK)
    {
        DGifCloseFile(fGIF);
        fGIF = NULL;
    }
    fCurrIndex = -1;
    fLastDrawIndex = -1;
}

SkGIFMovie::~SkGIFMovie()
{
    if (fGIF)
        DGifCloseFile(fGIF);
}

static SkMSec savedimage_duration(const SavedImage* image)
{
    for (int j = 0; j < image->ExtensionBlockCount; j++)
    {
        if (image->ExtensionBlocks[j].Function == GRAPHICS_EXT_FUNC_CODE)
        {
            int size = image->ExtensionBlocks[j].ByteCount;
            SkASSERT(size >= 4);
            const uint8_t* b = (const uint8_t*)image->ExtensionBlocks[j].Bytes;
            return ((b[2] << 8) | b[1]) * 10;
        }
    }
    return 0;
}

bool SkGIFMovie::onGetInfo(Info* info)
{
    if (NULL == fGIF)
        return false;

    SkMSec dur = 0;
    for (int i = 0; i < fGIF->ImageCount; i++)
        dur += savedimage_duration(&fGIF->SavedImages[i]);

    info->fDuration = dur;
    info->fWidth = fGIF->SWidth;
    info->fHeight = fGIF->SHeight;
    info->fIsOpaque = false;    // how to compute?
    return true;
}

bool SkGIFMovie::onSetTime(SkMSec time)
{
    if (NULL == fGIF)
        return false;

    SkMSec dur = 0;
    for (int i = 0; i < fGIF->ImageCount; i++)
    {
        dur += savedimage_duration(&fGIF->SavedImages[i]);
        if (dur >= time)
        {
            fCurrIndex = i;
            return fLastDrawIndex != fCurrIndex;
        }
    }
    fCurrIndex = fGIF->ImageCount - 1;
    return true;
}

static void copyLine(uint32_t* dst, const unsigned char* src, const ColorMapObject* cmap,
                     int transparent, int width)
{
    for (; width > 0; width--, src++, dst++) {
        if (*src != transparent) {
            const GifColorType& col = cmap->Colors[*src];
            *dst = SkPackARGB32(0xFF, col.Red, col.Green, col.Blue);
        }
    }
}

static void copyInterlaceGroup(SkBitmap* bm, const unsigned char*& src,
                               const ColorMapObject* cmap, int transparent, int copyWidth,
                               int copyHeight, const GifImageDesc& imageDesc, int rowStep,
                               int startRow)
{
    int row;
    // every 'rowStep'th row, starting with row 'startRow'
    for (row = startRow; row < copyHeight; row += rowStep) {
        uint32_t* dst = bm->getAddr32(imageDesc.Left, imageDesc.Top + row);
        copyLine(dst, src, cmap, transparent, copyWidth);
        src += imageDesc.Width;
    }

    // pad for rest height
    src += imageDesc.Width * ((imageDesc.Height - row + rowStep - 1) / rowStep);
}

static void blitInterlace(SkBitmap* bm, const SavedImage* frame, const ColorMapObject* cmap,
                          int transparent)
{
    int width = bm->width();
    int height = bm->height();
    GifWord copyWidth = frame->ImageDesc.Width;
    if (frame->ImageDesc.Left + copyWidth > width) {
        copyWidth = width - frame->ImageDesc.Left;
    }

    GifWord copyHeight = frame->ImageDesc.Height;
    if (frame->ImageDesc.Top + copyHeight > height) {
        copyHeight = height - frame->ImageDesc.Top;
    }

    // deinterlace
    const unsigned char* src = (unsigned char*)frame->RasterBits;

    // group 1 - every 8th row, starting with row 0
    copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 8, 0);

    // group 2 - every 8th row, starting with row 4
    copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 8, 4);

    // group 3 - every 4th row, starting with row 2
    copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 4, 2);

    copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 2, 1);
}

static void blitNormal(SkBitmap* bm, const SavedImage* frame, const ColorMapObject* cmap,
                       int transparent)
{
    int width = bm->width();
    int height = bm->height();
    const unsigned char* src = (unsigned char*)frame->RasterBits;
    uint32_t* dst = bm->getAddr32(frame->ImageDesc.Left, frame->ImageDesc.Top);
    GifWord copyWidth = frame->ImageDesc.Width;
    if (frame->ImageDesc.Left + copyWidth > width) {
        copyWidth = width - frame->ImageDesc.Left;
    }

    GifWord copyHeight = frame->ImageDesc.Height;
    if (frame->ImageDesc.Top + copyHeight > height) {
        copyHeight = height - frame->ImageDesc.Top;
    }

    int srcPad, dstPad;
    dstPad = width - copyWidth;
    srcPad = frame->ImageDesc.Width - copyWidth;
    for (; copyHeight > 0; copyHeight--) {
        copyLine(dst, src, cmap, transparent, copyWidth);
        src += frame->ImageDesc.Width;
        dst += width;
    }
}

static void fillRect(SkBitmap* bm, GifWord left, GifWord top, GifWord width, GifWord height,
                     uint32_t col)
{
    int bmWidth = bm->width();
    int bmHeight = bm->height();
    uint32_t* dst = bm->getAddr32(left, top);
    GifWord copyWidth = width;
    if (left + copyWidth > bmWidth) {
        copyWidth = bmWidth - left;
    }

    GifWord copyHeight = height;
    if (top + copyHeight > bmHeight) {
        copyHeight = bmHeight - top;
    }

    for (; copyHeight > 0; copyHeight--) {
        sk_memset32(dst, col, copyWidth);
        dst += bmWidth;
    }
}

static void drawFrame(SkBitmap* bm, const SavedImage* frame, const ColorMapObject* cmap)
{
    int transparent = -1;

    for (int i = 0; i < frame->ExtensionBlockCount; ++i) {
        ExtensionBlock* eb = frame->ExtensionBlocks + i;
        if (eb->Function == GRAPHICS_EXT_FUNC_CODE &&
            eb->ByteCount == 4) {
            bool has_transparency = ((eb->Bytes[0] & 1) == 1);
            if (has_transparency) {
                transparent = (unsigned char)eb->Bytes[3];
            }
        }
    }

    if (frame->ImageDesc.ColorMap != NULL) {
        // use local color table
        cmap = frame->ImageDesc.ColorMap;
    }

    if (cmap == NULL || cmap->ColorCount != (1 << cmap->BitsPerPixel)) {
        SkASSERT(!"bad colortable setup");
        return;
    }

    if (frame->ImageDesc.Interlace) {
        blitInterlace(bm, frame, cmap, transparent);
    } else {
        blitNormal(bm, frame, cmap, transparent);
    }
}

static bool checkIfWillBeCleared(const SavedImage* frame)
{
    for (int i = 0; i < frame->ExtensionBlockCount; ++i) {
        ExtensionBlock* eb = frame->ExtensionBlocks + i;
        if (eb->Function == GRAPHICS_EXT_FUNC_CODE &&
            eb->ByteCount == 4) {
            // check disposal method
            int disposal = ((eb->Bytes[0] >> 2) & 7);
            if (disposal == 2 || disposal == 3) {
                return true;
            }
        }
    }
    return false;
}

static void getTransparencyAndDisposalMethod(const SavedImage* frame, bool* trans, int* disposal)
{
    *trans = false;
    *disposal = 0;
    for (int i = 0; i < frame->ExtensionBlockCount; ++i) {
        ExtensionBlock* eb = frame->ExtensionBlocks + i;
        if (eb->Function == GRAPHICS_EXT_FUNC_CODE &&
            eb->ByteCount == 4) {
            *trans = ((eb->Bytes[0] & 1) == 1);
            *disposal = ((eb->Bytes[0] >> 2) & 7);
        }
    }
}

// return true if area of 'target' is completely covers area of 'covered'
static bool checkIfCover(const SavedImage* target, const SavedImage* covered)
{
    if (target->ImageDesc.Left <= covered->ImageDesc.Left
        && covered->ImageDesc.Left + covered->ImageDesc.Width <=
               target->ImageDesc.Left + target->ImageDesc.Width
        && target->ImageDesc.Top <= covered->ImageDesc.Top
        && covered->ImageDesc.Top + covered->ImageDesc.Height <=
               target->ImageDesc.Top + target->ImageDesc.Height) {
        return true;
    }
    return false;
}

static void disposeFrameIfNeeded(SkBitmap* bm, const SavedImage* cur, const SavedImage* next,
                                 SkBitmap* backup, SkColor color)
{
    // We can skip disposal process if next frame is not transparent
    // and completely covers current area
    bool curTrans;
    int curDisposal;
    getTransparencyAndDisposalMethod(cur, &curTrans, &curDisposal);
    bool nextTrans;
    int nextDisposal;
    getTransparencyAndDisposalMethod(next, &nextTrans, &nextDisposal);
    if ((curDisposal == 2 || curDisposal == 3)
        && (nextTrans || !checkIfCover(next, cur))) {
        switch (curDisposal) {
        // restore to background color
        // -> 'background' means background under this image.
        case 2:
            fillRect(bm, cur->ImageDesc.Left, cur->ImageDesc.Top,
                     cur->ImageDesc.Width, cur->ImageDesc.Height,
                     color);
            break;

        // restore to previous
        case 3:
            bm->swap(*backup);
            break;
        }
    }

    // Save current image if next frame's disposal method == 3
    if (nextDisposal == 3) {
        const uint32_t* src = bm->getAddr32(0, 0);
        uint32_t* dst = backup->getAddr32(0, 0);
        int cnt = bm->width() * bm->height();
        memcpy(dst, src, cnt*sizeof(uint32_t));
    }
}

bool SkGIFMovie::onGetBitmap(SkBitmap* bm)
{
    const GifFileType* gif = fGIF;
    if (NULL == gif)
        return false;

    if (gif->ImageCount < 1) {
        return false;
    }

    const int width = gif->SWidth;
    const int height = gif->SHeight;
    if (width <= 0 || height <= 0) {
        return false;
    }

    // no need to draw
    if (fLastDrawIndex >= 0 && fLastDrawIndex == fCurrIndex) {
        return true;
    }

    int startIndex = fLastDrawIndex + 1;
    if (fLastDrawIndex < 0 || !bm->readyToDraw()) {
        // first time

        startIndex = 0;

        // create bitmap
        bm->setConfig(SkBitmap::kARGB_8888_Config, width, height, 0);
        if (!bm->allocPixels(NULL)) {
            return false;
        }
        // create bitmap for backup
        fBackup.setConfig(SkBitmap::kARGB_8888_Config, width, height, 0);
        if (!fBackup.allocPixels(NULL)) {
            return false;
        }
    } else if (startIndex > fCurrIndex) {
        // rewind to 1st frame for repeat
        startIndex = 0;
    }

    int lastIndex = fCurrIndex;
    if (lastIndex < 0) {
        // first time
        lastIndex = 0;
    } else if (lastIndex > fGIF->ImageCount - 1) {
        // this block must not be reached.
        lastIndex = fGIF->ImageCount - 1;
    }

    SkColor bgColor = SkPackARGB32(0, 0, 0, 0);
    if (gif->SColorMap != NULL) {
        const GifColorType& col = gif->SColorMap->Colors[fGIF->SBackGroundColor];
        bgColor = SkColorSetARGB(0xFF, col.Red, col.Green, col.Blue);
    }

    static SkColor paintingColor = SkPackARGB32(0, 0, 0, 0);
    // draw each frames - not intelligent way
    for (int i = startIndex; i <= lastIndex; i++) {
        const SavedImage* cur = &fGIF->SavedImages[i];
        if (i == 0) {
            bool trans;
            int disposal;
            getTransparencyAndDisposalMethod(cur, &trans, &disposal);
            if (!trans && gif->SColorMap != NULL) {
                paintingColor = bgColor;
            } else {
                paintingColor = SkColorSetARGB(0, 0, 0, 0);
            }

            bm->eraseColor(paintingColor);
            fBackup.eraseColor(paintingColor);
        } else {
            // Dispose previous frame before move to next frame.
            const SavedImage* prev = &fGIF->SavedImages[i-1];
            disposeFrameIfNeeded(bm, prev, cur, &fBackup, paintingColor);
        }

        // Draw frame
        // We can skip this process if this index is not last and disposal
        // method == 2 or method == 3
        if (i == lastIndex || !checkIfWillBeCleared(cur)) {
            drawFrame(bm, cur, gif->SColorMap);
        }
    }

    // save index
    fLastDrawIndex = lastIndex;
    return true;
}

///////////////////////////////////////////////////////////////////////////////

#include "SkTRegistry.h"

SkMovie* Factory(SkStream* stream) {
    char buf[GIF_STAMP_LEN];
    if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN) {
        if (memcmp(GIF_STAMP,   buf, GIF_STAMP_LEN) == 0 ||
                memcmp(GIF87_STAMP, buf, GIF_STAMP_LEN) == 0 ||
                memcmp(GIF89_STAMP, buf, GIF_STAMP_LEN) == 0) {
            // must rewind here, since our construct wants to re-read the data
            stream->rewind();
            return SkNEW_ARGS(SkGIFMovie, (stream));
        }
    }
    return NULL;
}

static SkTRegistry<SkMovie*, SkStream*> gReg(Factory);
<|endoftext|>


<commit_before>

#pragma once

#include <vector>
using namespace std;

#include "util/Iterator.hpp"
using namespace util;

namespace internals {

class FrequentIterator;
class FrequentsIterator;

class Counters
{
public:
    int32_t minSupport;
    int32_t transactionsCount;
    int32_t distinctTransactionsCount;
    int32_t distinctTransactionLengthSum;
    vector<int32_t>* supportCounts;
    vector<int32_t>* distinctTransactionsCounts;
    int32_t nbFrequents;

protected:
    vector<int32_t>* closure;
    int32_t maxFrequent;
    vector<int32_t>* reverseRenaming;
    vector<int32_t>* renaming;
    bool compactedArrays;
    int32_t maxCandidate;

private:
    static thread_local FrequentIterator* localFrequentsIterator;

public:
    Counters* clone();
    int32_t getMaxFrequent();
    vector<int32_t>* getRenaming();
    vector<int32_t>* getReverseRenaming();

protected:
    void reuseRenaming(vector<int32_t>* olderReverseRenaming);

public:
    vector<int32_t>* compressRenaming(vector<int32_t>* olderReverseRenaming);
    int32_t getMaxCandidate();
    FrequentsIterator* getExtensionsIterator();
    FrequentsIterator* getLocalFrequentsIterator(int32_t from, int32_t to);

    Counters(int32_t minimumSupport, unique_ptr<Iterator<TransactionReader>> transactions, int32_t extension, vector<int32_t>* ignoredItems, int32_t maxItem);

protected:
    Counters(int32_t minimumSupport, unique_ptr<Iterator<TransactionReader>> transactions);

private:
    Counters(int32_t minSupport, int32_t transactionsCount, int32_t distinctTransactionsCount, int32_t distinctTransactionLengthSum, vector<int32_t>* supportCounts, vector<int32_t>* distinctTransactionsCounts, vector<int32_t>* closure, int32_t nbFrequents, int32_t maxFrequent, vector<int32_t>* reverseRenaming, vector<int32_t>* renaming, bool compactedArrays, int32_t maxCandidate);
};

}
<commit_msg>Fix missing inclusion in Counters.hpp<commit_after>

#pragma once

#include <vector>
using namespace std;

#include "internals/TransactionReader.hpp"
#include "util/Iterator.hpp"
using namespace util;

namespace internals {

class FrequentIterator;
class FrequentsIterator;

class Counters
{
public:
    int32_t minSupport;
    int32_t transactionsCount;
    int32_t distinctTransactionsCount;
    int32_t distinctTransactionLengthSum;
    vector<int32_t>* supportCounts;
    vector<int32_t>* distinctTransactionsCounts;
    int32_t nbFrequents;

protected:
    vector<int32_t>* closure;
    int32_t maxFrequent;
    vector<int32_t>* reverseRenaming;
    vector<int32_t>* renaming;
    bool compactedArrays;
    int32_t maxCandidate;

private:
    static thread_local FrequentIterator* localFrequentsIterator;

public:
    Counters* clone();
    int32_t getMaxFrequent();
    vector<int32_t>* getRenaming();
    vector<int32_t>* getReverseRenaming();

protected:
    void reuseRenaming(vector<int32_t>* olderReverseRenaming);

public:
    vector<int32_t>* compressRenaming(vector<int32_t>* olderReverseRenaming);
    int32_t getMaxCandidate();
    FrequentsIterator* getExtensionsIterator();
    FrequentsIterator* getLocalFrequentsIterator(int32_t from, int32_t to);

    Counters(int32_t minimumSupport, unique_ptr<Iterator<TransactionReader>> transactions, int32_t extension, vector<int32_t>* ignoredItems, int32_t maxItem);

protected:
    Counters(int32_t minimumSupport, unique_ptr<Iterator<TransactionReader>> transactions);

private:
    Counters(int32_t minSupport, int32_t transactionsCount, int32_t distinctTransactionsCount, int32_t distinctTransactionLengthSum, vector<int32_t>* supportCounts, vector<int32_t>* distinctTransactionsCounts, vector<int32_t>* closure, int32_t nbFrequents, int32_t maxFrequent, vector<int32_t>* reverseRenaming, vector<int32_t>* renaming, bool compactedArrays, int32_t maxCandidate);
};

}
<|endoftext|>


<commit_before>#ifdef _WIN32
#include <windows.h>
#else
#include <sys/stat.h>
#include <dirent.h>
#endif

#include <map>

#include "nod/DirectoryEnumerator.hpp"

namespace nod
{

DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
                                         bool sizeSort, bool reverse, bool noHidden)
{
    Sstat theStat;
    if (Stat(path, &theStat) || !S_ISDIR(theStat.st_mode))
        return;

#if _WIN32
    SystemString wc(path);
    wc += _S("/*");
    WIN32_FIND_DATAW d;
    HANDLE dir = FindFirstFileW(wc.c_str(), &d);
    if (dir == INVALID_HANDLE_VALUE)
        return;
    switch (mode)
    {
    case Mode::Native:
        do
        {
            if (!wcscmp(d.cFileName, _S(".")) || !wcscmp(d.cFileName, _S("..")))
                continue;
            if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
                continue;
            SystemString fp(path);
            fp += _S('/');
            fp += d.cFileName;
            Sstat st;
            if (Stat(fp.c_str(), &st))
                continue;

            size_t sz = 0;
            bool isDir = false;
            if (S_ISDIR(st.st_mode))
                isDir = true;
            else if (S_ISREG(st.st_mode))
                sz = st.st_size;
            else
                continue;

            m_entries.push_back(std::move(Entry(std::move(fp), d.cFileName, sz, isDir)));
        } while (FindNextFileW(dir, &d));
        break;
    case Mode::DirsThenFilesSorted:
    case Mode::DirsSorted:
    {
        std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
        do
        {
            if (!wcscmp(d.cFileName, _S(".")) || !wcscmp(d.cFileName, _S("..")))
                continue;
            if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
                continue;
            SystemString fp(path);
            fp +=_S('/');
            fp += d.cFileName;
            Sstat st;
            if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode))
                continue;
            sort.emplace(std::make_pair(d.cFileName, Entry(std::move(fp), d.cFileName, 0, true)));
        } while (FindNextFileW(dir, &d));

        if (reverse)
            for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
                m_entries.push_back(std::move(it->second));
        else
            for (auto& e : sort)
                m_entries.push_back(std::move(e.second));

        if (mode == Mode::DirsSorted)
            break;
        FindClose(dir);
        dir = FindFirstFileW(wc.c_str(), &d);
    }
    case Mode::FilesSorted:
    {
        if (mode == Mode::FilesSorted)
            m_entries.clear();

        if (sizeSort)
        {
            std::multimap<size_t, Entry> sort;
            do
            {
                if (!wcscmp(d.cFileName, _S(".")) || !wcscmp(d.cFileName, _S("..")))
                    continue;
                if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
                    continue;
                SystemString fp(path);
                fp += _S('/');
                fp += d.cFileName;
                Sstat st;
                if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
                    continue;
                sort.emplace(std::make_pair(st.st_size, Entry(std::move(fp), d.cFileName, st.st_size, false)));
            } while (FindNextFileW(dir, &d));

            if (reverse)
                for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
                    m_entries.push_back(std::move(it->second));
            else
                for (auto& e : sort)
                    m_entries.push_back(std::move(e.second));
        }
        else
        {
            std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
            do
            {
                if (!wcscmp(d.cFileName, _S(".")) || !wcscmp(d.cFileName, _S("..")))
                    continue;
                if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
                    continue;
                SystemString fp(path);
                fp += _S('/');
                fp += d.cFileName;
                Sstat st;
                if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
                    continue;
                sort.emplace(std::make_pair(d.cFileName, Entry(std::move(fp), d.cFileName, st.st_size, false)));
            } while (FindNextFileW(dir, &d));

            if (reverse)
                for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
                    m_entries.push_back(std::move(it->second));
            else
                for (auto& e : sort)
                    m_entries.push_back(std::move(e.second));
        }

        break;
    }
    }
    FindClose(dir);

#else

    DIR* dir = opendir(path);
    if (!dir)
        return;
    const dirent* d;
    switch (mode)
    {
    case Mode::Native:
        while ((d = readdir(dir)))
        {
            if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                continue;
            if (noHidden && d->d_name[0] == '.')
                continue;
            SystemString fp(path);
            fp += '/';
            fp += d->d_name;
            Sstat st;
            if (Stat(fp.c_str(), &st))
                continue;

            size_t sz = 0;
            bool isDir = false;
            if (S_ISDIR(st.st_mode))
                isDir = true;
            else if (S_ISREG(st.st_mode))
                sz = st.st_size;
            else
                continue;

            m_entries.push_back(Entry(std::move(fp), d->d_name, sz, isDir));
        }
        break;
    case Mode::DirsThenFilesSorted:
    case Mode::DirsSorted:
    {
        std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
        while ((d = readdir(dir)))
        {
            if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                continue;
            if (noHidden && d->d_name[0] == '.')
                continue;
            SystemString fp(path);
            fp += '/';
            fp += d->d_name;
            Sstat st;
            if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode))
                continue;
            sort.emplace(std::make_pair(d->d_name, Entry(std::move(fp), d->d_name, 0, true)));
        }

        if (reverse)
            for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
                m_entries.push_back(std::move(it->second));
        else
            for (auto& e : sort)
                m_entries.push_back(std::move(e.second));

        if (mode == Mode::DirsSorted)
            break;
        rewinddir(dir);
    }
    case Mode::FilesSorted:
    {
        if (mode == Mode::FilesSorted)
            m_entries.clear();

        if (sizeSort)
        {
            std::multimap<size_t, Entry> sort;
            while ((d = readdir(dir)))
            {
                if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                    continue;
                if (noHidden && d->d_name[0] == '.')
                    continue;
                SystemString fp(path);
                fp += '/';
                fp += d->d_name;
                Sstat st;
                if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
                    continue;
                sort.emplace(std::make_pair(st.st_size, Entry(std::move(fp), d->d_name, st.st_size, false)));
            }

            if (reverse)
                for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
                    m_entries.push_back(std::move(it->second));
            else
                for (auto& e : sort)
                    m_entries.push_back(std::move(e.second));
        }
        else
        {
            std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
            while ((d = readdir(dir)))
            {
                if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                    continue;
                if (noHidden && d->d_name[0] == '.')
                    continue;
                SystemString fp(path);
                fp += '/';
                fp += d->d_name;
                Sstat st;
                if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
                    continue;
                sort.emplace(std::make_pair(d->d_name, Entry(std::move(fp), d->d_name, st.st_size, false)));
            }

            if (reverse)
                for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
                    m_entries.push_back(std::move(it->second));
            else
                for (auto& e : sort)
                    m_entries.push_back(std::move(e.second));
        }

        break;
    }
    }
    closedir(dir);

#endif
}

}
<commit_msg>Add some reserve() calls<commit_after>#ifdef _WIN32
#include <windows.h>
#else
#include <sys/stat.h>
#include <dirent.h>
#endif

#include <map>

#include "nod/DirectoryEnumerator.hpp"

namespace nod
{

DirectoryEnumerator::DirectoryEnumerator(const SystemChar* path, Mode mode,
                                         bool sizeSort, bool reverse, bool noHidden)
{
    Sstat theStat;
    if (Stat(path, &theStat) || !S_ISDIR(theStat.st_mode))
        return;

#if _WIN32
    SystemString wc(path);
    wc += _S("/*");
    WIN32_FIND_DATAW d;
    HANDLE dir = FindFirstFileW(wc.c_str(), &d);
    if (dir == INVALID_HANDLE_VALUE)
        return;
    switch (mode)
    {
    case Mode::Native:
        do
        {
            if (!wcscmp(d.cFileName, _S(".")) || !wcscmp(d.cFileName, _S("..")))
                continue;
            if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
                continue;
            SystemString fp(path);
            fp += _S('/');
            fp += d.cFileName;
            Sstat st;
            if (Stat(fp.c_str(), &st))
                continue;

            size_t sz = 0;
            bool isDir = false;
            if (S_ISDIR(st.st_mode))
                isDir = true;
            else if (S_ISREG(st.st_mode))
                sz = st.st_size;
            else
                continue;

            m_entries.push_back(std::move(Entry(std::move(fp), d.cFileName, sz, isDir)));
        } while (FindNextFileW(dir, &d));
        break;
    case Mode::DirsThenFilesSorted:
    case Mode::DirsSorted:
    {
        std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
        do
        {
            if (!wcscmp(d.cFileName, _S(".")) || !wcscmp(d.cFileName, _S("..")))
                continue;
            if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
                continue;
            SystemString fp(path);
            fp +=_S('/');
            fp += d.cFileName;
            Sstat st;
            if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode))
                continue;
            sort.emplace(std::make_pair(d.cFileName, Entry(std::move(fp), d.cFileName, 0, true)));
        } while (FindNextFileW(dir, &d));

        m_entries.reserve(sort.size());
        if (reverse)
            for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
                m_entries.push_back(std::move(it->second));
        else
            for (auto& e : sort)
                m_entries.push_back(std::move(e.second));

        if (mode == Mode::DirsSorted)
            break;
        FindClose(dir);
        dir = FindFirstFileW(wc.c_str(), &d);
    }
    case Mode::FilesSorted:
    {
        if (mode == Mode::FilesSorted)
            m_entries.clear();

        if (sizeSort)
        {
            std::multimap<size_t, Entry> sort;
            do
            {
                if (!wcscmp(d.cFileName, _S(".")) || !wcscmp(d.cFileName, _S("..")))
                    continue;
                if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
                    continue;
                SystemString fp(path);
                fp += _S('/');
                fp += d.cFileName;
                Sstat st;
                if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
                    continue;
                sort.emplace(std::make_pair(st.st_size, Entry(std::move(fp), d.cFileName, st.st_size, false)));
            } while (FindNextFileW(dir, &d));

            m_entries.reserve(sort.size());
            if (reverse)
                for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
                    m_entries.push_back(std::move(it->second));
            else
                for (auto& e : sort)
                    m_entries.push_back(std::move(e.second));
        }
        else
        {
            std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
            do
            {
                if (!wcscmp(d.cFileName, _S(".")) || !wcscmp(d.cFileName, _S("..")))
                    continue;
                if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
                    continue;
                SystemString fp(path);
                fp += _S('/');
                fp += d.cFileName;
                Sstat st;
                if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
                    continue;
                sort.emplace(std::make_pair(d.cFileName, Entry(std::move(fp), d.cFileName, st.st_size, false)));
            } while (FindNextFileW(dir, &d));

            m_entries.reserve(sort.size());
            if (reverse)
                for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
                    m_entries.push_back(std::move(it->second));
            else
                for (auto& e : sort)
                    m_entries.push_back(std::move(e.second));
        }

        break;
    }
    }
    FindClose(dir);

#else

    DIR* dir = opendir(path);
    if (!dir)
        return;
    const dirent* d;
    switch (mode)
    {
    case Mode::Native:
        while ((d = readdir(dir)))
        {
            if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                continue;
            if (noHidden && d->d_name[0] == '.')
                continue;
            SystemString fp(path);
            fp += '/';
            fp += d->d_name;
            Sstat st;
            if (Stat(fp.c_str(), &st))
                continue;

            size_t sz = 0;
            bool isDir = false;
            if (S_ISDIR(st.st_mode))
                isDir = true;
            else if (S_ISREG(st.st_mode))
                sz = st.st_size;
            else
                continue;

            m_entries.push_back(Entry(std::move(fp), d->d_name, sz, isDir));
        }
        break;
    case Mode::DirsThenFilesSorted:
    case Mode::DirsSorted:
    {
        std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
        while ((d = readdir(dir)))
        {
            if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                continue;
            if (noHidden && d->d_name[0] == '.')
                continue;
            SystemString fp(path);
            fp += '/';
            fp += d->d_name;
            Sstat st;
            if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode))
                continue;
            sort.emplace(std::make_pair(d->d_name, Entry(std::move(fp), d->d_name, 0, true)));
        }

        m_entries.reserve(sort.size());
        if (reverse)
            for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
                m_entries.push_back(std::move(it->second));
        else
            for (auto& e : sort)
                m_entries.push_back(std::move(e.second));

        if (mode == Mode::DirsSorted)
            break;
        rewinddir(dir);
    }
    case Mode::FilesSorted:
    {
        if (mode == Mode::FilesSorted)
            m_entries.clear();

        if (sizeSort)
        {
            std::multimap<size_t, Entry> sort;
            while ((d = readdir(dir)))
            {
                if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                    continue;
                if (noHidden && d->d_name[0] == '.')
                    continue;
                SystemString fp(path);
                fp += '/';
                fp += d->d_name;
                Sstat st;
                if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
                    continue;
                sort.emplace(std::make_pair(st.st_size, Entry(std::move(fp), d->d_name, st.st_size, false)));
            }

            m_entries.reserve(sort.size());
            if (reverse)
                for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
                    m_entries.push_back(std::move(it->second));
            else
                for (auto& e : sort)
                    m_entries.push_back(std::move(e.second));
        }
        else
        {
            std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
            while ((d = readdir(dir)))
            {
                if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                    continue;
                if (noHidden && d->d_name[0] == '.')
                    continue;
                SystemString fp(path);
                fp += '/';
                fp += d->d_name;
                Sstat st;
                if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
                    continue;
                sort.emplace(std::make_pair(d->d_name, Entry(std::move(fp), d->d_name, st.st_size, false)));
            }

            m_entries.reserve(sort.size());
            if (reverse)
                for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
                    m_entries.push_back(std::move(it->second));
            else
                for (auto& e : sort)
                    m_entries.push_back(std::move(e.second));
        }

        break;
    }
    }
    closedir(dir);

#endif
}

}
<|endoftext|>