<commit_before>#include <babylon/animations/animation_group.h>

#include <babylon/animations/animatable.h>
#include <babylon/animations/animation.h>
#include <babylon/animations/ianimation_key.h>
#include <babylon/animations/targeted_animation.h>
#include <babylon/babylon_stl_util.h>
#include <babylon/engines/engine.h>
#include <babylon/engines/scene.h>

namespace BABYLON {

AnimationGroup::AnimationGroup(const std::string& iName, Scene* scene)
    : name{iName}
    , from{this, &AnimationGroup::get_from}
    , to{this, &AnimationGroup::get_to}
    , isStarted{this, &AnimationGroup::get_isStarted}
    , isPlaying{this, &AnimationGroup::get_isPlaying}
    , speedRatio{this, &AnimationGroup::get_speedRatio, &AnimationGroup::set_speedRatio}
    , loopAnimation{this, &AnimationGroup::get_loopAnimation, &AnimationGroup::set_loopAnimation}
    , isAdditive{this, &AnimationGroup::get_isAdditive, &AnimationGroup::set_isAdditive}
    , targetedAnimations{this, &AnimationGroup::get_targetedAnimations}
    , animatables{this, &AnimationGroup::get_animatables}
    , children{this, &AnimationGroup::get_children}
    , _from{std::numeric_limits<float>::max()}
    , _to{std::numeric_limits<float>::lowest()}
    , _isStarted{false}
    , _isPaused{false}
    , _speedRatio{1.f}
    , _loopAnimation{false}
    , _isAdditive{false}
    , _animationLoopCount{0}
{
  _scene   = scene ? scene : Engine::LastCreatedScene();
  uniqueId = _scene->getUniqueId();
}

AnimationGroup::~AnimationGroup() = default;

void AnimationGroup::addToScene(const AnimationGroupPtr& newAnimationGroup)
{
  _scene->addAnimationGroup(newAnimationGroup);
}

float AnimationGroup::get_from() const
{
  return _from;
}

float AnimationGroup::get_to() const
{
  return _to;
}

bool AnimationGroup::get_isStarted() const
{
  return _isStarted;
}

bool AnimationGroup::get_isPlaying() const
{
  return _isStarted && !_isPaused;
}

float AnimationGroup::get_speedRatio() const
{
  return _speedRatio;
}

void AnimationGroup::set_speedRatio(float value)
{
  if (stl_util::almost_equal(_speedRatio, value)) {
    return;
  }

  _speedRatio = value;

  for (const auto& animatable : _animatables) {
    animatable->speedRatio = _speedRatio;
  }
}

bool AnimationGroup::get_loopAnimation() const
{
  return _loopAnimation;
}

void AnimationGroup::set_loopAnimation(bool value)
{
  if (_loopAnimation == value) {
    return;
  }

  _loopAnimation = value;

  for (const auto& animatable : _animatables) {
    animatable->loopAnimation = _loopAnimation;
  }
}

bool AnimationGroup::get_isAdditive() const
{
  return _isAdditive;
}

void AnimationGroup::set_isAdditive(bool value)
{
  if (_isAdditive == value) {
    return;
  }

  _isAdditive = value;

  for (const auto& animatable : _animatables) {
    animatable->isAdditive = _isAdditive;
  }
}

std::vector<std::unique_ptr<TargetedAnimation>>& AnimationGroup::get_targetedAnimations()
{
  return _targetedAnimations;
}

std::vector<AnimatablePtr>& AnimationGroup::get_animatables()
{
  return _animatables;
}

std::vector<std::unique_ptr<TargetedAnimation>>& AnimationGroup::get_children()
{
  return _targetedAnimations;
}

TargetedAnimation AnimationGroup::addTargetedAnimation(const AnimationPtr& animation,
                                                       const IAnimatablePtr& target)
{
  TargetedAnimation targetedAnimation{
    animation, // animation,
    target     // target
  };

  const auto& keys = animation->getKeys();
  if (_from > keys.front().frame) {
    _from = keys.front().frame;
  }

  if (_to < keys.back().frame) {
    _to = keys.back().frame;
  }

  _targetedAnimations.emplace_back(std::make_unique<TargetedAnimation>(targetedAnimation));

  return targetedAnimation;
}

AnimationGroup& AnimationGroup::normalize(const std::optional<int>& iBeginFrame,
                                          const std::optional<int>& iEndFrame)
{
  auto beginFrame = iBeginFrame ? *iBeginFrame : _from;
  auto endFrame   = iEndFrame ? *iEndFrame : _to;

  for (auto& targetedAnimation : _targetedAnimations) {
    auto& keys           = targetedAnimation->animation->getKeys();
    const auto& startKey = keys.front();
    const auto& endKey   = keys.back();

    if (startKey.frame > beginFrame) {
      IAnimationKey newKey(beginFrame, startKey.value);
      newKey.inTangent     = startKey.inTangent;
      newKey.outTangent    = startKey.outTangent;
      newKey.interpolation = startKey.interpolation;
      keys.insert(keys.begin(), newKey);
    }

    if (endKey.frame < endFrame) {
      IAnimationKey newKey(endFrame, endKey.value);
      newKey.inTangent     = endKey.inTangent;
      newKey.outTangent    = endKey.outTangent;
      newKey.interpolation = endKey.interpolation;
      keys.emplace_back(newKey);
    }
  }

  _from = beginFrame;
  _to   = endFrame;

  return *this;
}

void AnimationGroup::_processLoop(const AnimatablePtr& animatable,
                                  TargetedAnimation* targetedAnimation, size_t index)
{
  animatable->onAnimationLoop = [this, targetedAnimation, index]() -> void {
    onAnimationLoopObservable.notifyObservers(targetedAnimation);

    if (index < _animationLoopFlags.size() && _animationLoopFlags[index]) {
      return;
    }

    if (index >= _animationLoopFlags.size()) {
      _animationLoopFlags.resize(index + 1);
    }

    _animationLoopFlags[index] = true;

    _animationLoopCount++;
    if (_animationLoopCount == _targetedAnimations.size()) {
      onAnimationGroupLoopObservable.notifyObservers(this);
      _animationLoopCount = 0;
      _animationLoopFlags = {};
    }
  };
}

AnimationGroup& AnimationGroup::start(bool loop, float iSpeedRatio, std::optional<float> iFrom,
                                      std::optional<float> iTo, std::optional<bool> iIsAdditive)
{
  if (_isStarted || _targetedAnimations.empty()) {
    return *this;
  }

  _loopAnimation = loop;

  _animationLoopCount = 0;
  _animationLoopFlags = {};

  size_t index = 0;
  for (const auto& targetedAnimation : _targetedAnimations) {
    auto animatable            = _scene->beginDirectAnimation(targetedAnimation->target,        //
                                                   {targetedAnimation->animation},   //
                                                   iFrom.value_or(_from),            //
                                                   iTo.value_or(_to),                //
                                                   loop,                             //
                                                   iSpeedRatio,                      //
                                                   nullptr,                          //
                                                   nullptr,                          //
                                                   iIsAdditive.value_or(_isAdditive) //
    );
    animatable->onAnimationEnd = [&]() -> void {
      onAnimationEndObservable.notifyObservers(targetedAnimation.get());
      _checkAnimationGroupEnded(animatable);
    };
    _processLoop(animatable, targetedAnimation.get(), index);
    _animatables.emplace_back(animatable);
    ++index;
  }

  _speedRatio = iSpeedRatio;

  if (iFrom.has_value() && iTo.has_value()) {
    if (*iFrom < *iTo && _speedRatio < 0.f) {
      std::swap(iFrom, iTo);
    }
    else if (*iFrom > *iTo && _speedRatio > 0.f) {
      _speedRatio = -speedRatio;
    }
  }

  _isStarted = true;
  _isPaused  = false;

  onAnimationGroupPlayObservable.notifyObservers(this);

  return *this;
}

AnimationGroup& AnimationGroup::pause()
{
  if (!_isStarted) {
    return *this;
  }

  _isPaused = true;

  for (const auto& animatable : _animatables) {
    animatable->pause();
  }

  onAnimationGroupPauseObservable.notifyObservers(this);

  return *this;
}

AnimationGroup& AnimationGroup::play(const std::optional<bool> loop)
{
  // only if all animatables are ready and exist
  if (isStarted() && _animatables.size() == _targetedAnimations.size()) {
    if (loop.has_value()) {
      loopAnimation = *loop;
    }
    restart();
  }
  else {
    stop();
    start(loop.value_or(false), _speedRatio);
  }

  _isPaused = false;

  return *this;
}

AnimationGroup& AnimationGroup::reset()
{
  if (!_isStarted) {
    return *this;
  }

  for (const auto& animatable : _animatables) {
    animatable->reset();
  }

  _isStarted = false;

  return *this;
}

AnimationGroup& AnimationGroup::restart()
{
  if (!_isStarted) {
    return *this;
  }

  for (const auto& animatable : _animatables) {
    animatable->restart();
  }

  onAnimationGroupPlayObservable.notifyObservers(this);

  return *this;
}

AnimationGroup& AnimationGroup::stop()
{
  if (!_isStarted) {
    return *this;
  }

  for (const auto& animatable : _animatables) {
    animatable->stop();
  }

  _isStarted = false;

  return *this;
}

AnimationGroup& AnimationGroup::setWeightForAllAnimatables(float weight)
{
  for (const auto& animatable : _animatables) {
    animatable->weight = weight;
  }

  return *this;
}

AnimationGroup& AnimationGroup::syncAllAnimationsWith(Animatable* root)
{
  for (const auto& animatable : _animatables) {
    animatable->syncWith(root);
  }

  return *this;
}

AnimationGroup& AnimationGroup::goToFrame(float frame)
{
  if (!_isStarted) {
    return *this;
  }

  for (const auto& animatable : _animatables) {
    animatable->goToFrame(frame);
  }

  return *this;
}

void AnimationGroup::dispose(bool /*doNotRecurse*/, bool /*disposeMaterialAndTextures*/)
{
  _targetedAnimations.clear();
  _animatables.clear();
  stl_util::remove_vector_elements_equal_sharedptr(_scene->animationGroups, this);

  onAnimationEndObservable.clear();
  onAnimationGroupEndObservable.clear();
  onAnimationGroupPauseObservable.clear();
  onAnimationGroupPlayObservable.clear();
  onAnimationLoopObservable.clear();
  onAnimationGroupLoopObservable.clear();
}

void AnimationGroup::_checkAnimationGroupEnded(const AnimatablePtr& animatable)
{
  // animatable should be taken out of the array
  _animatables.erase(std::remove(_animatables.begin(), _animatables.end(), animatable),
                     _animatables.end());

  // all animatables were removed? animation group ended!
  if (_animatables.empty()) {
    _isStarted = false;
    onAnimationGroupEndObservable.notifyObservers(this);
  }
}

AnimationGroupPtr AnimationGroup::clone(
  const std::string& newName,
  const std::function<IAnimatablePtr(const IAnimatablePtr& animatible)>& targetConverter)
{
  auto newGroup = AnimationGroup::New(newName.empty() ? name : newName, _scene);

  for (const auto& targetAnimation : _targetedAnimations) {
    newGroup->addTargetedAnimation(targetAnimation->animation->clone(),
                                   targetConverter ? targetConverter(targetAnimation->target) :
                                                     targetAnimation->target);
  }

  return newGroup;
}

json AnimationGroup::serialize() const
{
  return nullptr;
}

AnimationGroupPtr AnimationGroup::Parse(const json& /*parsedAnimationGroup*/, Scene* /*scene*/)
{
  return nullptr;
}

AnimationGroupPtr
AnimationGroup::MakeAnimationAdditive(const AnimationGroupPtr& sourceAnimationGroup,
                                      int referenceFrame, const std::string& range,
                                      bool cloneOriginal, const std::string& clonedName)
{
  auto animationGroup = sourceAnimationGroup;
  if (cloneOriginal) {
    animationGroup
      = sourceAnimationGroup->clone(!clonedName.empty() ? clonedName : animationGroup->name);
  }

  const auto& targetedAnimations = animationGroup->targetedAnimations();
  for (const auto& targetedAnimation : targetedAnimations) {
    Animation::MakeAnimationAdditive(targetedAnimation->animation, referenceFrame, range);
  }

  animationGroup->isAdditive = true;

  return animationGroup;
}

std::string AnimationGroup::getClassName() const
{
  return "AnimationGroup";
}

std::string AnimationGroup::toString(bool fullDetails) const
{
  std::ostringstream oss;
  oss << "Name: " << name;
  oss << ", type: " + getClassName();
  if (fullDetails) {
    oss << ", from: " << _from;
    oss << ", to: " << _to;
    oss << ", isStarted: " << _isStarted;
    oss << ", speedRatio: " << _speedRatio;
    oss << ", targetedAnimations length: " << _targetedAnimations.size();
    oss << ", animatables length: " << _animatables.size();
  }
  return oss.str();
}

} // end of namespace BABYLON
<commit_msg>Properly resetting animation group<commit_after>#include <babylon/animations/animation_group.h>

#include <babylon/animations/animatable.h>
#include <babylon/animations/animation.h>
#include <babylon/animations/ianimation_key.h>
#include <babylon/animations/targeted_animation.h>
#include <babylon/babylon_stl_util.h>
#include <babylon/engines/engine.h>
#include <babylon/engines/scene.h>

namespace BABYLON {

AnimationGroup::AnimationGroup(const std::string& iName, Scene* scene)
    : name{iName}
    , from{this, &AnimationGroup::get_from}
    , to{this, &AnimationGroup::get_to}
    , isStarted{this, &AnimationGroup::get_isStarted}
    , isPlaying{this, &AnimationGroup::get_isPlaying}
    , speedRatio{this, &AnimationGroup::get_speedRatio, &AnimationGroup::set_speedRatio}
    , loopAnimation{this, &AnimationGroup::get_loopAnimation, &AnimationGroup::set_loopAnimation}
    , isAdditive{this, &AnimationGroup::get_isAdditive, &AnimationGroup::set_isAdditive}
    , targetedAnimations{this, &AnimationGroup::get_targetedAnimations}
    , animatables{this, &AnimationGroup::get_animatables}
    , children{this, &AnimationGroup::get_children}
    , _from{std::numeric_limits<float>::max()}
    , _to{std::numeric_limits<float>::lowest()}
    , _isStarted{false}
    , _isPaused{false}
    , _speedRatio{1.f}
    , _loopAnimation{false}
    , _isAdditive{false}
    , _animationLoopCount{0}
{
  _scene   = scene ? scene : Engine::LastCreatedScene();
  uniqueId = _scene->getUniqueId();
}

AnimationGroup::~AnimationGroup() = default;

void AnimationGroup::addToScene(const AnimationGroupPtr& newAnimationGroup)
{
  _scene->addAnimationGroup(newAnimationGroup);
}

float AnimationGroup::get_from() const
{
  return _from;
}

float AnimationGroup::get_to() const
{
  return _to;
}

bool AnimationGroup::get_isStarted() const
{
  return _isStarted;
}

bool AnimationGroup::get_isPlaying() const
{
  return _isStarted && !_isPaused;
}

float AnimationGroup::get_speedRatio() const
{
  return _speedRatio;
}

void AnimationGroup::set_speedRatio(float value)
{
  if (stl_util::almost_equal(_speedRatio, value)) {
    return;
  }

  _speedRatio = value;

  for (const auto& animatable : _animatables) {
    animatable->speedRatio = _speedRatio;
  }
}

bool AnimationGroup::get_loopAnimation() const
{
  return _loopAnimation;
}

void AnimationGroup::set_loopAnimation(bool value)
{
  if (_loopAnimation == value) {
    return;
  }

  _loopAnimation = value;

  for (const auto& animatable : _animatables) {
    animatable->loopAnimation = _loopAnimation;
  }
}

bool AnimationGroup::get_isAdditive() const
{
  return _isAdditive;
}

void AnimationGroup::set_isAdditive(bool value)
{
  if (_isAdditive == value) {
    return;
  }

  _isAdditive = value;

  for (const auto& animatable : _animatables) {
    animatable->isAdditive = _isAdditive;
  }
}

std::vector<std::unique_ptr<TargetedAnimation>>& AnimationGroup::get_targetedAnimations()
{
  return _targetedAnimations;
}

std::vector<AnimatablePtr>& AnimationGroup::get_animatables()
{
  return _animatables;
}

std::vector<std::unique_ptr<TargetedAnimation>>& AnimationGroup::get_children()
{
  return _targetedAnimations;
}

TargetedAnimation AnimationGroup::addTargetedAnimation(const AnimationPtr& animation,
                                                       const IAnimatablePtr& target)
{
  TargetedAnimation targetedAnimation{
    animation, // animation,
    target     // target
  };

  const auto& keys = animation->getKeys();
  if (_from > keys.front().frame) {
    _from = keys.front().frame;
  }

  if (_to < keys.back().frame) {
    _to = keys.back().frame;
  }

  _targetedAnimations.emplace_back(std::make_unique<TargetedAnimation>(targetedAnimation));

  return targetedAnimation;
}

AnimationGroup& AnimationGroup::normalize(const std::optional<int>& iBeginFrame,
                                          const std::optional<int>& iEndFrame)
{
  auto beginFrame = iBeginFrame ? *iBeginFrame : _from;
  auto endFrame   = iEndFrame ? *iEndFrame : _to;

  for (auto& targetedAnimation : _targetedAnimations) {
    auto& keys           = targetedAnimation->animation->getKeys();
    const auto& startKey = keys.front();
    const auto& endKey   = keys.back();

    if (startKey.frame > beginFrame) {
      IAnimationKey newKey(beginFrame, startKey.value);
      newKey.inTangent     = startKey.inTangent;
      newKey.outTangent    = startKey.outTangent;
      newKey.interpolation = startKey.interpolation;
      keys.insert(keys.begin(), newKey);
    }

    if (endKey.frame < endFrame) {
      IAnimationKey newKey(endFrame, endKey.value);
      newKey.inTangent     = endKey.inTangent;
      newKey.outTangent    = endKey.outTangent;
      newKey.interpolation = endKey.interpolation;
      keys.emplace_back(newKey);
    }
  }

  _from = beginFrame;
  _to   = endFrame;

  return *this;
}

void AnimationGroup::_processLoop(const AnimatablePtr& animatable,
                                  TargetedAnimation* targetedAnimation, size_t index)
{
  animatable->onAnimationLoop = [this, targetedAnimation, index]() -> void {
    onAnimationLoopObservable.notifyObservers(targetedAnimation);

    if (index < _animationLoopFlags.size() && _animationLoopFlags[index]) {
      return;
    }

    if (index >= _animationLoopFlags.size()) {
      _animationLoopFlags.resize(index + 1);
    }

    _animationLoopFlags[index] = true;

    _animationLoopCount++;
    if (_animationLoopCount == _targetedAnimations.size()) {
      onAnimationGroupLoopObservable.notifyObservers(this);
      _animationLoopCount = 0;
      _animationLoopFlags = {};
    }
  };
}

AnimationGroup& AnimationGroup::start(bool loop, float iSpeedRatio, std::optional<float> iFrom,
                                      std::optional<float> iTo, std::optional<bool> iIsAdditive)
{
  if (_isStarted || _targetedAnimations.empty()) {
    return *this;
  }

  _loopAnimation = loop;

  _animationLoopCount = 0;
  _animationLoopFlags = {};

  size_t index = 0;
  for (const auto& targetedAnimation : _targetedAnimations) {
    auto animatable            = _scene->beginDirectAnimation(targetedAnimation->target,        //
                                                   {targetedAnimation->animation},   //
                                                   iFrom.value_or(_from),            //
                                                   iTo.value_or(_to),                //
                                                   loop,                             //
                                                   iSpeedRatio,                      //
                                                   nullptr,                          //
                                                   nullptr,                          //
                                                   iIsAdditive.value_or(_isAdditive) //
    );
    animatable->onAnimationEnd = [&]() -> void {
      onAnimationEndObservable.notifyObservers(targetedAnimation.get());
      _checkAnimationGroupEnded(animatable);
    };
    _processLoop(animatable, targetedAnimation.get(), index);
    _animatables.emplace_back(animatable);
    ++index;
  }

  _speedRatio = iSpeedRatio;

  if (iFrom.has_value() && iTo.has_value()) {
    if (*iFrom < *iTo && _speedRatio < 0.f) {
      std::swap(iFrom, iTo);
    }
    else if (*iFrom > *iTo && _speedRatio > 0.f) {
      _speedRatio = -speedRatio;
    }
  }

  _isStarted = true;
  _isPaused  = false;

  onAnimationGroupPlayObservable.notifyObservers(this);

  return *this;
}

AnimationGroup& AnimationGroup::pause()
{
  if (!_isStarted) {
    return *this;
  }

  _isPaused = true;

  for (const auto& animatable : _animatables) {
    animatable->pause();
  }

  onAnimationGroupPauseObservable.notifyObservers(this);

  return *this;
}

AnimationGroup& AnimationGroup::play(const std::optional<bool> loop)
{
  // only if all animatables are ready and exist
  if (isStarted() && _animatables.size() == _targetedAnimations.size()) {
    if (loop.has_value()) {
      loopAnimation = *loop;
    }
    restart();
  }
  else {
    stop();
    start(loop.value_or(false), _speedRatio);
  }

  _isPaused = false;

  return *this;
}

AnimationGroup& AnimationGroup::reset()
{
  if (!_isStarted) {
    play();
    goToFrame(0.f);
    stop();
    return *this;
  }

  for (const auto& animatable : _animatables) {
    animatable->reset();
  }

  _isStarted = false;

  return *this;
}

AnimationGroup& AnimationGroup::restart()
{
  if (!_isStarted) {
    return *this;
  }

  for (const auto& animatable : _animatables) {
    animatable->restart();
  }

  onAnimationGroupPlayObservable.notifyObservers(this);

  return *this;
}

AnimationGroup& AnimationGroup::stop()
{
  if (!_isStarted) {
    return *this;
  }

  for (const auto& animatable : _animatables) {
    animatable->stop();
  }

  _isStarted = false;

  return *this;
}

AnimationGroup& AnimationGroup::setWeightForAllAnimatables(float weight)
{
  for (const auto& animatable : _animatables) {
    animatable->weight = weight;
  }

  return *this;
}

AnimationGroup& AnimationGroup::syncAllAnimationsWith(Animatable* root)
{
  for (const auto& animatable : _animatables) {
    animatable->syncWith(root);
  }

  return *this;
}

AnimationGroup& AnimationGroup::goToFrame(float frame)
{
  if (!_isStarted) {
    return *this;
  }

  for (const auto& animatable : _animatables) {
    animatable->goToFrame(frame);
  }

  return *this;
}

void AnimationGroup::dispose(bool /*doNotRecurse*/, bool /*disposeMaterialAndTextures*/)
{
  _targetedAnimations.clear();
  _animatables.clear();
  stl_util::remove_vector_elements_equal_sharedptr(_scene->animationGroups, this);

  onAnimationEndObservable.clear();
  onAnimationGroupEndObservable.clear();
  onAnimationGroupPauseObservable.clear();
  onAnimationGroupPlayObservable.clear();
  onAnimationLoopObservable.clear();
  onAnimationGroupLoopObservable.clear();
}

void AnimationGroup::_checkAnimationGroupEnded(const AnimatablePtr& animatable)
{
  // animatable should be taken out of the array
  _animatables.erase(std::remove(_animatables.begin(), _animatables.end(), animatable),
                     _animatables.end());

  // all animatables were removed? animation group ended!
  if (_animatables.empty()) {
    _isStarted = false;
    onAnimationGroupEndObservable.notifyObservers(this);
  }
}

AnimationGroupPtr AnimationGroup::clone(
  const std::string& newName,
  const std::function<IAnimatablePtr(const IAnimatablePtr& animatible)>& targetConverter)
{
  auto newGroup = AnimationGroup::New(newName.empty() ? name : newName, _scene);

  for (const auto& targetAnimation : _targetedAnimations) {
    newGroup->addTargetedAnimation(targetAnimation->animation->clone(),
                                   targetConverter ? targetConverter(targetAnimation->target) :
                                                     targetAnimation->target);
  }

  return newGroup;
}

json AnimationGroup::serialize() const
{
  return nullptr;
}

AnimationGroupPtr AnimationGroup::Parse(const json& /*parsedAnimationGroup*/, Scene* /*scene*/)
{
  return nullptr;
}

AnimationGroupPtr
AnimationGroup::MakeAnimationAdditive(const AnimationGroupPtr& sourceAnimationGroup,
                                      int referenceFrame, const std::string& range,
                                      bool cloneOriginal, const std::string& clonedName)
{
  auto animationGroup = sourceAnimationGroup;
  if (cloneOriginal) {
    animationGroup
      = sourceAnimationGroup->clone(!clonedName.empty() ? clonedName : animationGroup->name);
  }

  const auto& targetedAnimations = animationGroup->targetedAnimations();
  for (const auto& targetedAnimation : targetedAnimations) {
    Animation::MakeAnimationAdditive(targetedAnimation->animation, referenceFrame, range);
  }

  animationGroup->isAdditive = true;

  return animationGroup;
}

std::string AnimationGroup::getClassName() const
{
  return "AnimationGroup";
}

std::string AnimationGroup::toString(bool fullDetails) const
{
  std::ostringstream oss;
  oss << "Name: " << name;
  oss << ", type: " + getClassName();
  if (fullDetails) {
    oss << ", from: " << _from;
    oss << ", to: " << _to;
    oss << ", isStarted: " << _isStarted;
    oss << ", speedRatio: " << _speedRatio;
    oss << ", targetedAnimations length: " << _targetedAnimations.size();
    oss << ", animatables length: " << _animatables.size();
  }
  return oss.str();
}

} // end of namespace BABYLON
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2015 Mark Charlebois. 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. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS 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
 * COPYRIGHT OWNER OR 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.
 *
 ****************************************************************************/

/**
 * @file px4_linux_impl.cpp
 *
 * PX4 Middleware Wrapper Linux Implementation
 */

#include <px4_defines.h>
#include <px4_tasks.h>
#include <px4_middleware.h>
#include <px4_workqueue.h>
#include <dataman/dataman.h>
#include <stdint.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <semaphore.h>
#include <systemlib/param/param.h>
#include "hrt_work.h"
#include "px4_log.h"

//extern pthread_t _shell_task_id;

__BEGIN_DECLS
extern uint64_t get_ticks_per_us();

//long PX4_TICKS_PER_SEC = 1000L;

unsigned int sleep(unsigned int sec)
{
	for (unsigned int i = 0; i < sec; i++) {
		usleep(1000000);
	}

	return 0;
}

extern void hrt_init(void);
extern void init_params();

#if 0
void qurt_log(const char *fmt, ...)
{
	va_list	args;
	va_start(args, fmt);
	printf(fmt, args);
	printf("n");
}
#endif

//extern int _posix_init(void);

__END_DECLS

extern struct wqueue_s gwork[NWORKERS];

namespace px4
{

void init_once(void);

void init_once(void)
{
	// Required for QuRT
	//_posix_init();

//	_shell_task_id = pthread_self();
//	PX4_INFO("Shell id is %lu", _shell_task_id);

	work_queues_init();
	hrt_work_queue_init();
	hrt_init();
	param_init();

	/* Shared memory param sync*/
	init_params();
}

void init(int argc, char *argv[], const char *app_name)
{
	PX4_DEBUG("App name: %s\n", app_name);
}

}

/** Retrieve from the data manager store */
ssize_t
dm_read(
	dm_item_t item,                 /* The item type to retrieve */
	unsigned char index,            /* The index of the item */
	void *buffer,                   /* Pointer to caller data buffer */
	size_t buflen                   /* Length in bytes of data to retrieve */
)
{
	return 0;
}

/** write to the data manager store */
ssize_t
dm_write(
	dm_item_t  item,                /* The item type to store */
	unsigned char index,            /* The index of the item */
	dm_persitence_t persistence,    /* The persistence level of this item */
	const void *buffer,             /* Pointer to caller data buffer */
	size_t buflen                   /* Length in bytes of data to retrieve */
)
{
	return 0;
}

size_t strnlen(const char *s, size_t maxlen)
{
	size_t i = 0;

	while (s[i] != '\0' && i < maxlen) {
		++i;
	}

	return i;
}

int fprintf(FILE *stream, const char *format, ...)
{
	PX4_ERR("Error: Calling unresolved symbol stub:[%s(%s,...)]", __FUNCTION__, format);
	return 0;
}

int fputc(int c, FILE *stream)
{
	return c;
}
<commit_msg>Resolves a conflict in the type of the index parameter in the dm_read and dm_write function signature, caused by a recent change in the dataman code.  This problem was causing the loading of the flight stack to fail on the aDSP.<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2015 Mark Charlebois. 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. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS 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
 * COPYRIGHT OWNER OR 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.
 *
 ****************************************************************************/

/**
 * @file px4_linux_impl.cpp
 *
 * PX4 Middleware Wrapper Linux Implementation
 */

#include <px4_defines.h>
#include <px4_tasks.h>
#include <px4_middleware.h>
#include <px4_workqueue.h>
#include <dataman/dataman.h>
#include <stdint.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <semaphore.h>
#include <systemlib/param/param.h>
#include "hrt_work.h"
#include "px4_log.h"

//extern pthread_t _shell_task_id;

__BEGIN_DECLS
extern uint64_t get_ticks_per_us();

//long PX4_TICKS_PER_SEC = 1000L;

unsigned int sleep(unsigned int sec)
{
	for (unsigned int i = 0; i < sec; i++) {
		usleep(1000000);
	}

	return 0;
}

extern void hrt_init(void);
extern void init_params();

#if 0
void qurt_log(const char *fmt, ...)
{
	va_list	args;
	va_start(args, fmt);
	printf(fmt, args);
	printf("n");
}
#endif

//extern int _posix_init(void);

__END_DECLS

extern struct wqueue_s gwork[NWORKERS];

namespace px4
{

void init_once(void);

void init_once(void)
{
	// Required for QuRT
	//_posix_init();

//	_shell_task_id = pthread_self();
//	PX4_INFO("Shell id is %lu", _shell_task_id);

	work_queues_init();
	hrt_work_queue_init();
	hrt_init();
	param_init();

	/* Shared memory param sync*/
	init_params();
}

void init(int argc, char *argv[], const char *app_name)
{
	PX4_DEBUG("App name: %s\n", app_name);
}

}

/** Retrieve from the data manager store */
ssize_t
dm_read(
	dm_item_t item,                 /* The item type to retrieve */
	unsigned index,                 /* The index of the item */
	void *buffer,                   /* Pointer to caller data buffer */
	size_t buflen                   /* Length in bytes of data to retrieve */
)
{
	return 0;
}

/** write to the data manager store */
ssize_t
dm_write(
	dm_item_t  item,                /* The item type to store */
	unsigned index,                 /* The index of the item */
	dm_persitence_t persistence,    /* The persistence level of this item */
	const void *buffer,             /* Pointer to caller data buffer */
	size_t buflen                   /* Length in bytes of data to retrieve */
)
{
	return 0;
}

size_t strnlen(const char *s, size_t maxlen)
{
	size_t i = 0;

	while (s[i] != '\0' && i < maxlen) {
		++i;
	}

	return i;
}

int fprintf(FILE *stream, const char *format, ...)
{
	PX4_ERR("Error: Calling unresolved symbol stub:[%s(%s,...)]", __FUNCTION__, format);
	return 0;
}

int fputc(int c, FILE *stream)
{
	return c;
}
<|endoftext|>


<commit_before>// CA4.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

const int cbCodeId = 0x3EB;
const int btnDecompId = 0x3EC;
const int btnCancelId = 2;

const SIZE_T fbRecordSize = 0xB4;

const LPVOID fileObjectAddr = (LPVOID)0x4101d8;
const SIZE_T fileObjectSize = 0x3A4;

const char *_7zExe = "\"c:\\Program Files\\7-Zip\\7z.exe\" a -sdel output.zip @listfile";

struct FileObject
{
    LPVOID vtable;
    DWORD d2;
    char  error[0x100];
    char  scode[0x20]; //0x108
    DWORD type; //0x128
    DWORD d3;
    DWORD d4;
    DWORD maskmode;
    DWORD markettype; // 0x138
    char  filename[0x100];
    HANDLE dataheap; // 0x23c
    LPVOID filedata;
    DWORD totalsize;
    DWORD datasize;
    HANDLE codeheap;
    LPVOID codetable; //0x250
    DWORD tablesize;
    DWORD codesize;
    DWORD d10;
    HANDLE decodeheap; //0x260
    LPVOID decodedata;
    DWORD decodesize;
    DWORD decodebufsize;
    BYTE  b270_256[0xb4]; // 0x270
    BYTE  b324_40[0x28];  // 0x324
    BYTE  b34c_80[0x50];  // 0x34c
    DWORD d12;
    DWORD d13; // 0x3a0
};

int _tmain_message(int argc, _TCHAR* argv[])
{
    if (argc != 3)
    {
        printf("specify a file name.\n");
        return 0;
    }

    if (!argv[2][0] || argv[2][1])
    {
        printf("specify a market marker (h/s).\n");
        return 0;
    }

    char p[0x100];
    ZeroMemory(p, sizeof(p));
    strcpy_s(p, sizeof(p), argv[1]);

    FILE *paramfp = NULL;
    int err = fopen_s(&paramfp, "dzhtest.exe.param", "rb+");
    if (!err)
    {
        fseek(paramfp, 0, FILE_BEGIN);
        fwrite(p, sizeof(char), sizeof(p), paramfp);
        fseek(paramfp, 0x110, FILE_BEGIN);
        if (argv[2][0] == 'h')
        {
            // sh 0x1e
            fwrite("\x1e", sizeof(char), 1, paramfp);
        }
        else if (argv[2][0] == 's')
        {
            // sz 0x25
            fwrite("\x25", sizeof(char), 1, paramfp);
        }
        fclose(paramfp);
    }
    else
    {
        printf("failed to open param file.\n");
        return -1;
    }

    char fn[0x100];
    GetCurrentDirectoryA(sizeof(fn), fn);
    strcat_s(fn, sizeof(fn), "\\dzhtest.exe");

    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    ZeroMemory(&si, sizeof(si));
    ZeroMemory(&pi, sizeof(pi));
    if (!CreateProcessA(NULL, fn,
            NULL, NULL, FALSE, 0, NULL,
            NULL, // current directory
            &si,
            &pi))
    {
        printf("CreateProcess failed (%d)\n", GetLastError());
        return -2;
    }

    // wait for dzhtest bootstrap
    WaitForSingleObject(pi.hProcess, 3000);

    HWND target = FindWindowA(NULL, "dzhtest");
    if (!target)
    {
        // if it's still not running, give up
        printf("target window not found!\n");
        return -3;
    }
    HWND btnWnd = GetDlgItem(target, btnDecompId);
    HWND cbWnd = GetDlgItem(target, cbCodeId);

    LRESULT r = SendMessage(cbWnd, CB_GETCOUNT, 0, 0);
    char scodesel[32];
    char *fl = new char[r * (sizeof(scodesel) + 1)];
    char *flpointer = fl;

    LPVOID fp;
    FileObject fo;
    SIZE_T bytesRead;
    ReadProcessMemory(pi.hProcess, (LPCVOID)fileObjectAddr, (LPVOID)&fp, sizeof(fp), &bytesRead);
    ReadProcessMemory(pi.hProcess, fp, &fo, fileObjectSize, &bytesRead);

    LPVOID initial = fo.decodedata;

    for (int i = 0; i < r; i++)
    {
        LRESULT re = SendMessage(cbWnd, CB_SETCURSEL, (WPARAM)i, 0);

        re = SendMessage(cbWnd, WM_GETTEXT, (WPARAM)sizeof(scodesel), (LPARAM)scodesel);
        strncpy_s(flpointer, (size_t) re + 1, scodesel, (size_t) re);
        flpointer[re] = '\r';
        flpointer = flpointer + re + 1;

        re = SendMessage(target, WM_COMMAND, MAKEWPARAM(btnDecompId, BN_CLICKED), (LPARAM)btnWnd);

        ReadProcessMemory(pi.hProcess, fp, &fo, fileObjectSize, &bytesRead);

        if (initial && fo.decodedata != initial)
        {
            printf("decoded data buffer changed! %p %p", initial, fo.decodedata);
        }

        BYTE *pData = new BYTE[fo.decodesize];
        ReadProcessMemory(pi.hProcess, fo.decodedata, pData, fo.decodesize, &bytesRead);
        FILE *outfp = NULL;
        err = fopen_s(&outfp, scodesel, "wb");
        if (!err)
        {
            fwrite(pData, 1, bytesRead, outfp);
            fclose(outfp);
        }
        else
        {
            printf("failed to open [%s].\n", scodesel);
        }
        delete pData;
    }

    FILE *outflist = NULL;
    err = fopen_s(&outflist, "listfile", "wb");
    if (!err)
    {
        fwrite(fl, sizeof(char), flpointer - fl, outflist);
        fclose(outflist);
    }
    else
    {
        printf("failed to open [%s].\n", "listfile");
    }
    delete fl;

    SendMessage(target, WM_COMMAND, MAKEWPARAM(btnCancelId, BN_CLICKED), (LPARAM)GetDlgItem(target, btnCancelId));
    WaitForSingleObject( pi.hProcess, INFINITE );
    CloseHandle( pi.hProcess );
    CloseHandle( pi.hThread );

    ZeroMemory(&si, sizeof(si));
    ZeroMemory(&pi, sizeof(pi));
    if (!CreateProcessA(NULL, (LPSTR)_7zExe,
        NULL, NULL, FALSE, 0, NULL,
        NULL, // current directory
        &si,
        &pi))
    {
        printf("CreateProcess failed (%d)\n", GetLastError());
        return -2;
    }

    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    return 0;
}

int _tmain_inject(int argc, _TCHAR* argv[])
{
    if (argc != 3)
    {
        return -1;
    }

    HANDLE processHandle;
    HANDLE threadHandle;
    HMODULE dllHandle;
    DWORD processID;
    FARPROC loadLibraryAddress;
    LPVOID baseAddress;

    processID = (DWORD)_ttol(argv[1]);

    processHandle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,processID);

    if(processHandle == NULL)
    {
        printf("Error unable to open process. Error code: %d", GetLastError());

        return -2;
    }

    printf("Process handle %d is ready",processID);

    dllHandle = GetModuleHandle("Kernel32");

    if(dllHandle == NULL)
    {
        printf("Error unable to allocate kernel32 handle..Error code: %d. Press any key to exit...",GetLastError());
    }

    printf("kernel32 handle is ready\n");

    loadLibraryAddress = GetProcAddress(dllHandle,"LoadLibraryA");

    if(loadLibraryAddress == NULL)
    {
        printf("Cannot get LoadLibraryA() address. Error code: %d. Press any key to exit",GetLastError());

        return -2;
    }

    printf("LoadLibrary() address is ready\n");

    baseAddress = VirtualAllocEx(
        processHandle,
        NULL,
        2048,
        MEM_COMMIT|MEM_RESERVE,
        PAGE_READWRITE);

    if(baseAddress == NULL)
    {
        printf("Error unable to alocate memmory in remote process. Error code: %d. Press any key to exit", GetLastError());

        return 0;
    }

    printf("Memory allocation succeeded\n");

    BOOL isSucceeded = WriteProcessMemory(
        processHandle,
        baseAddress,
        argv[2],
        strlen(argv[2])+1,
        NULL);

    if(isSucceeded == 0)
    {
        printf("Error unable to write memory . Error code: %d Press any key to exit...",GetLastError());

        return 0;
    }

    printf("Argument has been written\n");

    threadHandle = CreateRemoteThread(
        processHandle,
        NULL,
        0,
        (LPTHREAD_START_ROUTINE)loadLibraryAddress,
        baseAddress,
        NULL,
        0);

    if(threadHandle != NULL)
    {
        printf("Remote thread has been created\n");
    }

    return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
    // return _tmain_inject(argc, argv);

    //FILE *fp = fopen("C:\\BaiduYunDownload\\DN.txt", "rb");
    //fseek(fp, -100L * 1024L * 1024L, FILE_END);
    //if (fp){
    //    for (int i = 0; i < 10; i++)
    //    {
    //        BYTE buf[256];
    //        fread(buf, 1, 256, fp);
    //        printf("%d", buf[0]);
    //    }
    //    fclose(fp);
    //}

    return _tmain_message(argc, argv);
}
<commit_msg>decode record<commit_after>// CA4.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

const int cbCodeId = 0x3EB;
const int btnDecompId = 0x3EC;
const int btnCancelId = 2;

const SIZE_T fbRecordSize = 0xB4;

const LPVOID fileObjectAddr = (LPVOID)0x4101d8;
const SIZE_T fileObjectSize = 0x3A4;

const char *_7zExe = "\"c:\\Program Files\\7-Zip\\7z.exe\" a -sdel output.zip @listfile";

const bool g_dumpRecords = false;

struct FileObject
{
    LPVOID vtable;
    DWORD d2;
    char  error[0x100];
    char  scode[0x20]; //0x108
    DWORD type; //0x128
    DWORD d3;
    DWORD d4;
    DWORD maskmode;
    DWORD markettype; // 0x138
    char  filename[0x100];
    HANDLE dataheap; // 0x23c
    LPVOID filedata;
    DWORD totalsize;
    DWORD datasize;
    HANDLE codeheap;
    LPVOID codetable; //0x250
    DWORD tablesize;
    DWORD codesize;
    DWORD d10;
    HANDLE decodeheap; //0x260
    LPVOID decodedata;
    DWORD decodesize;
    DWORD decodebufsize;
    BYTE  b270_256[0xb4]; // 0x270
    BYTE  b324_40[0x28];  // 0x324
    BYTE  b34c_80[0x50];  // 0x34c
    DWORD d12;
    DWORD d13; // 0x3a0
};

struct RecordObject
{
    DWORD dt;
    DWORD time;
    DWORD close;
    DWORD volumeLow;
    DWORD volumeHigh;
    DWORD amountLow;
    DWORD amountHigh;
    DWORD transactions;
    DWORD accVolumeLow;
    DWORD accVolumeHigh;
    DWORD accAmountLow;
    DWORD accAmountHigh;
    DWORD flag;
    DWORD prices[10];
    DWORD volumes[20];
    DWORD reservedLow;
    DWORD reservedHigh;
};

#define MAKELONGLONG(l, h) ((LONGLONG)(l & 0xffffffff) | (LONGLONG)h << 32)

void DumpRecords(BYTE *pData, int records)
{
    RecordObject* pRec = (RecordObject *)pData;
    DWORD accTxn = 0;
    LONGLONG llReserved = MAKELONGLONG(pRec[0].reservedLow, pRec[0].reservedHigh);
    for (int i = 0; i < records; i++)
    {
        DWORD txn = pRec[i].transactions;
        if (MAKELONGLONG(pRec[i].reservedLow, pRec[i].reservedHigh) != llReserved)
        {
            txn = pRec[i].transactions - accTxn;
            llReserved = MAKELONGLONG(pRec[i].reservedLow, pRec[i].reservedHigh);
            accTxn = pRec[i].transactions;
        }
        else
        {
            accTxn += pRec[i].transactions;
        }
        printf("%u %06u %u %u %I64u %I64u\n", pRec[i].dt, pRec[i].time, pRec[i].close, txn,
                MAKELONGLONG(pRec[i].amountLow, pRec[i].amountHigh),
                MAKELONGLONG(pRec[i].volumeLow, pRec[i].volumeHigh));
    }
}

int _tmain_message(int argc, _TCHAR* argv[])
{
    if (argc != 3)
    {
        printf("specify a file name.\n");
        return 0;
    }

    if (!argv[2][0] || argv[2][1])
    {
        printf("specify a market marker (h/s).\n");
        return 0;
    }

    char p[0x100];
    ZeroMemory(p, sizeof(p));
    strcpy_s(p, sizeof(p), argv[1]);

    FILE *paramfp = NULL;
    int err = fopen_s(&paramfp, "dzhtest.exe.param", "rb+");
    if (!err)
    {
        fseek(paramfp, 0, FILE_BEGIN);
        fwrite(p, sizeof(char), sizeof(p), paramfp);
        fseek(paramfp, 0x110, FILE_BEGIN);
        if (argv[2][0] == 'h')
        {
            // sh 0x1e
            fwrite("\x1e", sizeof(char), 1, paramfp);
        }
        else if (argv[2][0] == 's')
        {
            // sz 0x25
            fwrite("\x25", sizeof(char), 1, paramfp);
        }
        fclose(paramfp);
    }
    else
    {
        printf("failed to open param file.\n");
        return -1;
    }

    char fn[0x100];
    GetCurrentDirectoryA(sizeof(fn), fn);
    strcat_s(fn, sizeof(fn), "\\dzhtest.exe");

    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    ZeroMemory(&si, sizeof(si));
    ZeroMemory(&pi, sizeof(pi));
    if (!CreateProcessA(NULL, fn,
            NULL, NULL, FALSE, 0, NULL,
            NULL, // current directory
            &si,
            &pi))
    {
        printf("CreateProcess failed (%d)\n", GetLastError());
        return -2;
    }

    // wait for dzhtest bootstrap
    WaitForSingleObject(pi.hProcess, 3000);

    HWND target = FindWindowA(NULL, "dzhtest");
    if (!target)
    {
        // if it's still not running, give up
        printf("target window not found!\n");
        return -3;
    }
    HWND btnWnd = GetDlgItem(target, btnDecompId);
    HWND cbWnd = GetDlgItem(target, cbCodeId);

    LRESULT r = SendMessage(cbWnd, CB_GETCOUNT, 0, 0);
    char scodesel[32];
    char *fl = new char[r * (sizeof(scodesel) + 1)];
    char *flpointer = fl;

    LPVOID fp;
    FileObject fo;
    SIZE_T bytesRead;
    ReadProcessMemory(pi.hProcess, (LPCVOID)fileObjectAddr, (LPVOID)&fp, sizeof(fp), &bytesRead);
    ReadProcessMemory(pi.hProcess, fp, &fo, fileObjectSize, &bytesRead);

    LPVOID initial = fo.decodedata;

    for (int i = 0; i < r; i++)
    {
        LRESULT re = SendMessage(cbWnd, CB_SETCURSEL, (WPARAM)i, 0);

        re = SendMessage(cbWnd, WM_GETTEXT, (WPARAM)sizeof(scodesel), (LPARAM)scodesel);
        strncpy_s(flpointer, (size_t) re + 1, scodesel, (size_t) re);
        flpointer[re] = '\r';
        flpointer = flpointer + re + 1;

        re = SendMessage(target, WM_COMMAND, MAKEWPARAM(btnDecompId, BN_CLICKED), (LPARAM)btnWnd);

        ReadProcessMemory(pi.hProcess, fp, &fo, fileObjectSize, &bytesRead);

        if (initial && fo.decodedata != initial)
        {
            printf("decoded data buffer changed! %p %p", initial, fo.decodedata);
        }

        BYTE *pData = new BYTE[fo.decodesize];
        ReadProcessMemory(pi.hProcess, fo.decodedata, pData, fo.decodesize, &bytesRead);
        FILE *outfp = NULL;
        err = fopen_s(&outfp, scodesel, "wb");
        if (!err)
        {
            fwrite(pData, 1, bytesRead, outfp);
            fclose(outfp);
        }
        else
        {
            printf("failed to open [%s].\n", scodesel);
        }

        if (bytesRead % fbRecordSize == 0)
        {
            if (g_dumpRecords)
            {
                DumpRecords(pData, bytesRead / fbRecordSize);
            }
        }
        else
        {
            printf("probably wrong buffer length!\n");
        }
        delete pData;
    }

    FILE *outflist = NULL;
    err = fopen_s(&outflist, "listfile", "wb");
    if (!err)
    {
        fwrite(fl, sizeof(char), flpointer - fl, outflist);
        fclose(outflist);
    }
    else
    {
        printf("failed to open [%s].\n", "listfile");
    }
    delete fl;

    SendMessage(target, WM_COMMAND, MAKEWPARAM(btnCancelId, BN_CLICKED), (LPARAM)GetDlgItem(target, btnCancelId));
    WaitForSingleObject( pi.hProcess, INFINITE );
    CloseHandle( pi.hProcess );
    CloseHandle( pi.hThread );

    ZeroMemory(&si, sizeof(si));
    ZeroMemory(&pi, sizeof(pi));
    if (!CreateProcessA(NULL, (LPSTR)_7zExe,
        NULL, NULL, FALSE, 0, NULL,
        NULL, // current directory
        &si,
        &pi))
    {
        printf("CreateProcess failed (%d)\n", GetLastError());
        return -2;
    }

    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    return 0;
}

int _tmain_inject(int argc, _TCHAR* argv[])
{
    if (argc != 3)
    {
        return -1;
    }

    HANDLE processHandle;
    HANDLE threadHandle;
    HMODULE dllHandle;
    DWORD processID;
    FARPROC loadLibraryAddress;
    LPVOID baseAddress;

    processID = (DWORD)_ttol(argv[1]);

    processHandle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,processID);

    if(processHandle == NULL)
    {
        printf("Error unable to open process. Error code: %d", GetLastError());

        return -2;
    }

    printf("Process handle %d is ready",processID);

    dllHandle = GetModuleHandle("Kernel32");

    if(dllHandle == NULL)
    {
        printf("Error unable to allocate kernel32 handle..Error code: %d. Press any key to exit...",GetLastError());
    }

    printf("kernel32 handle is ready\n");

    loadLibraryAddress = GetProcAddress(dllHandle,"LoadLibraryA");

    if(loadLibraryAddress == NULL)
    {
        printf("Cannot get LoadLibraryA() address. Error code: %d. Press any key to exit",GetLastError());

        return -2;
    }

    printf("LoadLibrary() address is ready\n");

    baseAddress = VirtualAllocEx(
        processHandle,
        NULL,
        2048,
        MEM_COMMIT|MEM_RESERVE,
        PAGE_READWRITE);

    if(baseAddress == NULL)
    {
        printf("Error unable to alocate memmory in remote process. Error code: %d. Press any key to exit", GetLastError());

        return 0;
    }

    printf("Memory allocation succeeded\n");

    BOOL isSucceeded = WriteProcessMemory(
        processHandle,
        baseAddress,
        argv[2],
        strlen(argv[2])+1,
        NULL);

    if(isSucceeded == 0)
    {
        printf("Error unable to write memory . Error code: %d Press any key to exit...",GetLastError());

        return 0;
    }

    printf("Argument has been written\n");

    threadHandle = CreateRemoteThread(
        processHandle,
        NULL,
        0,
        (LPTHREAD_START_ROUTINE)loadLibraryAddress,
        baseAddress,
        NULL,
        0);

    if(threadHandle != NULL)
    {
        printf("Remote thread has been created\n");
    }

    return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
    // return _tmain_inject(argc, argv);

    //FILE *fp = fopen("C:\\BaiduYunDownload\\DN.txt", "rb");
    //fseek(fp, -100L * 1024L * 1024L, FILE_END);
    //if (fp){
    //    for (int i = 0; i < 10; i++)
    //    {
    //        BYTE buf[256];
    //        fread(buf, 1, 256, fp);
    //        printf("%d", buf[0]);
    //    }
    //    fclose(fp);
    //}

    return _tmain_message(argc, argv);
}
<|endoftext|>


<commit_before>//----------------------------  vectors_rhs_hp_02.cc  ---------------------------
//    $Id: vectors_rhs_hp_02.cc 23710 2011-05-17 04:50:10Z bangerth $
//    Version: $Name$
//
//    Copyright (C) 2000, 2001, 2003, 2004, 2006, 2007, 2011 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  vectors_rhs_hp_02.cc  ---------------------------

// we get this crash:
//
// An error occurred in line <4677> of file </scratch/deal-trunk/deal.II/include/deal.II/numerics/vectors.templates.h> in function
//     void dealii::VectorTools::compute_no_normal_flux_constraints(const DH<dim, spacedim>&, unsigned int, const std::set<unsigned char>&, dealii::ConstraintMatrix&, const dealii::Mapping<dim, spacedim>&) [with int dim = 2, DH = dealii::DoFHandler, int spacedim = 2]
// The violated condition was:
//     std::fabs(determinant (t)) > 1e-3
// The name and call sequence of the exception was:
//     ExcMessage("Found a set of normal vectors that are nearly collinear.")
// Additional Information:
// Found a set of normal vectors that are nearly collinear.

// the crash does not happen without a boundary object. Same error occures with HyperShellBoundary instead of HalfHyperShellBoundary.

#include "../tests.h"

#include <grid/tria.h>
#include <grid/grid_generator.h>
#include <grid/tria_boundary_lib.h>
#include <dofs/dof_handler.h>
#include <fe/fe_system.h>
#include <fe/mapping_q1.h>
#include <numerics/vectors.h>

using namespace dealii;

template <int dim>
void run()
{
 Triangulation<dim> triangulation;
 FESystem<dim> fe(FE_Q<dim>(1), dim);
 DoFHandler<dim> dof_handler (triangulation);
 ConstraintMatrix constraints;
 MappingQ<dim> mapping(1);

 GridGenerator::half_hyper_shell (triangulation,
                                  Point<dim>(),
                                  0.5,
                                  1);

 static HalfHyperShellBoundary<dim> boundary;
 triangulation.set_boundary (0, boundary);

 dof_handler.distribute_dofs (fe);

 std::set<unsigned char> no_normal_flux_boundaries;
 no_normal_flux_boundaries.insert (0);
 VectorTools::compute_no_normal_flux_constraints
   (dof_handler, 0,
    no_normal_flux_boundaries,
    constraints, mapping);
}

int main (int argc, char *argv[])
{
  std::ofstream logfile ("no_flux_10/output");
  logfile.precision (4);
  logfile.setf(std::ios::fixed);
  deallog.attach(logfile);
  deallog.depth_console (0);

  run<2> ();
}
<commit_msg>Reindent and simplify.<commit_after>//----------------------------  vectors_rhs_hp_02.cc  ---------------------------
//    $Id: vectors_rhs_hp_02.cc 23710 2011-05-17 04:50:10Z bangerth $
//    Version: $Name$
//
//    Copyright (C) 2000, 2001, 2003, 2004, 2006, 2007, 2011, 2012 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  vectors_rhs_hp_02.cc  ---------------------------

// we get this crash:
//
// An error occurred in line <4677> of file </scratch/deal-trunk/deal.II/include/deal.II/numerics/vectors.templates.h> in function
//     void dealii::VectorTools::compute_no_normal_flux_constraints(const DH<dim, spacedim>&, unsigned int, const std::set<unsigned char>&, dealii::ConstraintMatrix&, const dealii::Mapping<dim, spacedim>&) [with int dim = 2, DH = dealii::DoFHandler, int spacedim = 2]
// The violated condition was:
//     std::fabs(determinant (t)) > 1e-3
// The name and call sequence of the exception was:
//     ExcMessage("Found a set of normal vectors that are nearly collinear.")
// Additional Information:
// Found a set of normal vectors that are nearly collinear.

// the crash does not happen without a boundary object. Same error occures with HyperShellBoundary instead of HalfHyperShellBoundary.

#include "../tests.h"

#include <grid/tria.h>
#include <grid/grid_generator.h>
#include <grid/tria_boundary_lib.h>
#include <dofs/dof_handler.h>
#include <fe/fe_system.h>
#include <fe/mapping_q1.h>
#include <numerics/vectors.h>

using namespace dealii;

template <int dim>
void run()
{
  Triangulation<dim> triangulation;
  FESystem<dim> fe(FE_Q<dim>(1), dim);
  DoFHandler<dim> dof_handler (triangulation);
  ConstraintMatrix constraints;
  MappingQ<dim> mapping(1);

  GridGenerator::half_hyper_shell (triangulation,
				   Point<dim>(),
				   0.5,
				   1,
				   2);

  static HalfHyperShellBoundary<dim> boundary;
  triangulation.set_boundary (0, boundary);

  dof_handler.distribute_dofs (fe);

  std::set<unsigned char> no_normal_flux_boundaries;
  no_normal_flux_boundaries.insert (0);
  VectorTools::compute_no_normal_flux_constraints
    (dof_handler, 0,
     no_normal_flux_boundaries,
     constraints, mapping);
}

int main (int argc, char *argv[])
{
  std::ofstream logfile ("no_flux_10/output");
  logfile.precision (4);
  logfile.setf(std::ios::fixed);
  deallog.attach(logfile);
  deallog.depth_console (0);

  run<2> ();
}
<|endoftext|>


<commit_before>/**
 * The goal of these tests is to verify the behavior of all blob commands given
 * the current state is uploadInProgress.  This state is achieved when an image
 * or hash blob is opened and the handler is expected to receive bytes.
 */
#include "firmware_handler.hpp"
#include "firmware_unittest.hpp"

#include <cstdint>
#include <string>
#include <vector>

#include <gtest/gtest.h>

namespace ipmi_flash
{
namespace
{

using ::testing::ContainerEq;
using ::testing::IsEmpty;
using ::testing::Return;
using ::testing::UnorderedElementsAreArray;

/*
 * There are the following calls (parameters may vary):
 * canHandleBlob(blob)
 * getBlobIds
 * deleteBlob(blob)
 * stat(blob)
 * stat(session)
 * open(blob)
 * close(session)
 * writemeta(session)
 * write(session)
 * read(session)
 * commit(session)
 *
 * Testing canHandleBlob is uninteresting in this state.  Getting the BlobIDs
 * will inform what canHandleBlob will return.
 */
class FirmwareHandlerUploadInProgressTest : public IpmiOnlyFirmwareStaticTest
{
};

TEST_F(FirmwareHandlerUploadInProgressTest, GetBlobIdsVerifyOutputActiveImage)
{
    /* Opening the image file will add the active image blob id */
    openToInProgress(staticLayoutBlobId);

    std::vector<std::string> expectedAfterImage = {
        staticLayoutBlobId, hashBlobId, activeImageBlobId};
    EXPECT_THAT(handler->getBlobIds(),
                UnorderedElementsAreArray(expectedAfterImage));
}

TEST_F(FirmwareHandlerUploadInProgressTest, GetBlobIdsVerifyOutputActiveHash)
{
    /* Opening the image file will add the active image blob id */
    openToInProgress(hashBlobId);

    std::vector<std::string> expectedAfterImage = {
        staticLayoutBlobId, hashBlobId, activeHashBlobId};
    EXPECT_THAT(handler->getBlobIds(),
                UnorderedElementsAreArray(expectedAfterImage));
}

/* TODO: Try deleting some blobs -- in this state it will depend on what the
 * blob id is, but it's not yet implemented
 */

/*
 * stat(blob)
 */
TEST_F(FirmwareHandlerUploadInProgressTest, StatOnActiveImageReturnsFailure)
{
    /* you cannot call stat() on the active image or the active hash or the
     * verify blob.
     */
    openToInProgress(staticLayoutBlobId);
    ASSERT_TRUE(handler->canHandleBlob(activeImageBlobId));

    blobs::BlobMeta meta;
    EXPECT_FALSE(handler->stat(activeImageBlobId, &meta));
}

TEST_F(FirmwareHandlerUploadInProgressTest, StatOnActiveHashReturnsFailure)
{
    /* this test is separate from the active image one so that the state doesn't
     * change from close.
     */
    openToInProgress(hashBlobId);
    ASSERT_TRUE(handler->canHandleBlob(activeHashBlobId));

    blobs::BlobMeta meta;
    EXPECT_FALSE(handler->stat(activeHashBlobId, &meta));
}

TEST_F(FirmwareHandlerUploadInProgressTest, StatOnNormalBlobsReturnsSuccess)
{
    /* Calling stat() on the normal blobs (not the active) ones will work and
     * return the same information as in the notYetStarted state.
     */
    blobs::BlobMeta expected;
    expected.blobState = FirmwareBlobHandler::UpdateFlags::ipmi;
    expected.size = 0;

    openToInProgress(staticLayoutBlobId);

    std::vector<std::string> testBlobs = {staticLayoutBlobId, hashBlobId};
    for (const auto& blob : testBlobs)
    {
        blobs::BlobMeta meta = {};
        EXPECT_TRUE(handler->stat(blob, &meta));
        EXPECT_EQ(expected, meta);
    }
}

/*
 * stat(session)
 */
TEST_F(FirmwareHandlerUploadInProgressTest,
       CallingStatOnActiveImageOrHashSessionReturnsDetails)
{
    /* This test will verify that the underlying image handler is called with
     * this stat, in addition to the normal information.
     */
    openToInProgress(staticLayoutBlobId);

    EXPECT_CALL(imageMock, getSize()).WillOnce(Return(32));

    blobs::BlobMeta meta, expectedMeta = {};
    expectedMeta.size = 32;
    expectedMeta.blobState =
        blobs::OpenFlags::write | FirmwareBlobHandler::UpdateFlags::ipmi;
    EXPECT_TRUE(handler->stat(session, &meta));
    EXPECT_EQ(expectedMeta, meta);
}

/*
 * open(blob) - While any blob is open, all other fail.
 *
 * The fullBlobsList is all the blob_ids present if both /flash/image and
 * /flash/hash are opened, and one is left open (so there's no verify blob). if
 * left closed, we'd be in verificationPending, not uploadInProgress.
 */
const std::vector<std::string> fullBlobsList = {
    activeHashBlobId, activeImageBlobId, hashBlobId, staticLayoutBlobId};

TEST_F(FirmwareHandlerUploadInProgressTest, OpeningHashFileWhileImageOpenFails)
{
    /* To be in this state, something must be open (and specifically either an
     * active image (or tarball) or the hash file. Also verifies you can't just
     * re-open the currently open file.
     */
    openToInProgress(staticLayoutBlobId);

    for (const auto& blob : fullBlobsList)
    {
        EXPECT_FALSE(handler->open(2, flags, blob));
    }
}

TEST_F(FirmwareHandlerUploadInProgressTest, OpeningImageFileWhileHashOpenFails)
{
    openToInProgress(hashBlobId);

    for (const auto& blob : fullBlobsList)
    {
        EXPECT_FALSE(handler->open(2, flags, blob));
    }
}

/*
 * close(session) - closing the hash or image will trigger a state transition to
 * verificationPending.
 *
 * NOTE: Re-opening /flash/image will transition back to uploadInProgress, but
 * that is verified in the verificationPending::open tests.
 */
TEST_F(FirmwareHandlerUploadInProgressTest,
       ClosingImageFileTransitionsToVerificationPending)
{
    EXPECT_FALSE(handler->canHandleBlob(verifyBlobId));
    openToInProgress(staticLayoutBlobId);

    handler->close(session);
    expectedState(FirmwareBlobHandler::UpdateState::verificationPending);

    EXPECT_TRUE(handler->canHandleBlob(verifyBlobId));
}

TEST_F(FirmwareHandlerUploadInProgressTest,
       ClosingHashFileTransitionsToVerificationPending)
{
    EXPECT_FALSE(handler->canHandleBlob(verifyBlobId));
    openToInProgress(hashBlobId);

    handler->close(session);
    expectedState(FirmwareBlobHandler::UpdateState::verificationPending);

    EXPECT_TRUE(handler->canHandleBlob(verifyBlobId));
}

/*
 * writemeta(session)
 */
TEST_F(FirmwareHandlerUploadInProgressTest,
       WriteMetaAgainstImageReturnsFailureIfNoDataHandler)
{
    /* Calling write/read/writeMeta are uninteresting against the open blob in
     * this case because the blob will just pass the call along.  Whereas
     * calling against the verify or update blob may be more interesting.
     */
    openToInProgress(staticLayoutBlobId);

    /* TODO: Consider adding a test that has a data handler, but that test
     * already exists under the general writeMeta test suite.
     */
    /* Note: with IPMI as the transport there's no data handler, so this should
     * fail nicely. */
    std::vector<std::uint8_t> bytes = {0x01, 0x02};
    EXPECT_FALSE(handler->writeMeta(session, 0, bytes));
}

/*
 * write(session)
 */
TEST_F(FirmwareHandlerUploadInProgressTest, WriteToImageReturnsSuccess)
{
    openToInProgress(staticLayoutBlobId);
    std::vector<std::uint8_t> bytes = {0x01, 0x02};
    EXPECT_CALL(imageMock, write(0, ContainerEq(bytes))).WillOnce(Return(true));
    EXPECT_TRUE(handler->write(session, 0, bytes));
}

TEST_F(FirmwareHandlerUploadInProgressTest, WriteToHashReturnsSuccess)
{
    openToInProgress(hashBlobId);
    std::vector<std::uint8_t> bytes = {0x01, 0x02};
    EXPECT_CALL(imageMock, write(0, ContainerEq(bytes))).WillOnce(Return(true));
    EXPECT_TRUE(handler->write(session, 0, bytes));
}

/*
 * read(session)
 */
TEST_F(FirmwareHandlerUploadInProgressTest, ReadImageFileReturnsFailure)
{
    /* Read is not supported. */
    openToInProgress(staticLayoutBlobId);
    EXPECT_THAT(handler->read(session, 0, 32), IsEmpty());
}

/*
 * commit(session)
 */
TEST_F(FirmwareHandlerUploadInProgressTest,
       CommitAgainstImageFileReturnsFailure)
{
    /* Commit is only valid against specific blobs. */
    openToInProgress(staticLayoutBlobId);
    EXPECT_FALSE(handler->commit(session, {}));
}

TEST_F(FirmwareHandlerUploadInProgressTest, CommitAgainstHashFileReturnsFailure)
{
    openToInProgress(hashBlobId);
    EXPECT_FALSE(handler->commit(session, {}));
}

/*
 * deleteBlob(blob)
 */
TEST_F(FirmwareHandlerUploadInProgressTest, DeleteBlobReturnsFalse)
{
    /* Try deleting all blobs, it doesn't really matter which though because you
     * cannot close out an open session, therefore you must fail to delete
     * anything unless everything is closed.
     */
    openToInProgress(staticLayoutBlobId);
    auto blobs = handler->getBlobIds();
    for (const auto& b : blobs)
    {
        EXPECT_FALSE(handler->deleteBlob(b));
    }
}

} // namespace
} // namespace ipmi_flash
<commit_msg>test: uploadinprogress: cut obsolete todo<commit_after>/**
 * The goal of these tests is to verify the behavior of all blob commands given
 * the current state is uploadInProgress.  This state is achieved when an image
 * or hash blob is opened and the handler is expected to receive bytes.
 */
#include "firmware_handler.hpp"
#include "firmware_unittest.hpp"

#include <cstdint>
#include <string>
#include <vector>

#include <gtest/gtest.h>

namespace ipmi_flash
{
namespace
{

using ::testing::ContainerEq;
using ::testing::IsEmpty;
using ::testing::Return;
using ::testing::UnorderedElementsAreArray;

/*
 * There are the following calls (parameters may vary):
 * canHandleBlob(blob)
 * getBlobIds
 * deleteBlob(blob)
 * stat(blob)
 * stat(session)
 * open(blob)
 * close(session)
 * writemeta(session)
 * write(session)
 * read(session)
 * commit(session)
 *
 * Testing canHandleBlob is uninteresting in this state.  Getting the BlobIDs
 * will inform what canHandleBlob will return.
 */
class FirmwareHandlerUploadInProgressTest : public IpmiOnlyFirmwareStaticTest
{
};

TEST_F(FirmwareHandlerUploadInProgressTest, GetBlobIdsVerifyOutputActiveImage)
{
    /* Opening the image file will add the active image blob id */
    openToInProgress(staticLayoutBlobId);

    std::vector<std::string> expectedAfterImage = {
        staticLayoutBlobId, hashBlobId, activeImageBlobId};
    EXPECT_THAT(handler->getBlobIds(),
                UnorderedElementsAreArray(expectedAfterImage));
}

TEST_F(FirmwareHandlerUploadInProgressTest, GetBlobIdsVerifyOutputActiveHash)
{
    /* Opening the image file will add the active image blob id */
    openToInProgress(hashBlobId);

    std::vector<std::string> expectedAfterImage = {
        staticLayoutBlobId, hashBlobId, activeHashBlobId};
    EXPECT_THAT(handler->getBlobIds(),
                UnorderedElementsAreArray(expectedAfterImage));
}

/*
 * stat(blob)
 */
TEST_F(FirmwareHandlerUploadInProgressTest, StatOnActiveImageReturnsFailure)
{
    /* you cannot call stat() on the active image or the active hash or the
     * verify blob.
     */
    openToInProgress(staticLayoutBlobId);
    ASSERT_TRUE(handler->canHandleBlob(activeImageBlobId));

    blobs::BlobMeta meta;
    EXPECT_FALSE(handler->stat(activeImageBlobId, &meta));
}

TEST_F(FirmwareHandlerUploadInProgressTest, StatOnActiveHashReturnsFailure)
{
    /* this test is separate from the active image one so that the state doesn't
     * change from close.
     */
    openToInProgress(hashBlobId);
    ASSERT_TRUE(handler->canHandleBlob(activeHashBlobId));

    blobs::BlobMeta meta;
    EXPECT_FALSE(handler->stat(activeHashBlobId, &meta));
}

TEST_F(FirmwareHandlerUploadInProgressTest, StatOnNormalBlobsReturnsSuccess)
{
    /* Calling stat() on the normal blobs (not the active) ones will work and
     * return the same information as in the notYetStarted state.
     */
    blobs::BlobMeta expected;
    expected.blobState = FirmwareBlobHandler::UpdateFlags::ipmi;
    expected.size = 0;

    openToInProgress(staticLayoutBlobId);

    std::vector<std::string> testBlobs = {staticLayoutBlobId, hashBlobId};
    for (const auto& blob : testBlobs)
    {
        blobs::BlobMeta meta = {};
        EXPECT_TRUE(handler->stat(blob, &meta));
        EXPECT_EQ(expected, meta);
    }
}

/*
 * stat(session)
 */
TEST_F(FirmwareHandlerUploadInProgressTest,
       CallingStatOnActiveImageOrHashSessionReturnsDetails)
{
    /* This test will verify that the underlying image handler is called with
     * this stat, in addition to the normal information.
     */
    openToInProgress(staticLayoutBlobId);

    EXPECT_CALL(imageMock, getSize()).WillOnce(Return(32));

    blobs::BlobMeta meta, expectedMeta = {};
    expectedMeta.size = 32;
    expectedMeta.blobState =
        blobs::OpenFlags::write | FirmwareBlobHandler::UpdateFlags::ipmi;
    EXPECT_TRUE(handler->stat(session, &meta));
    EXPECT_EQ(expectedMeta, meta);
}

/*
 * open(blob) - While any blob is open, all other fail.
 *
 * The fullBlobsList is all the blob_ids present if both /flash/image and
 * /flash/hash are opened, and one is left open (so there's no verify blob). if
 * left closed, we'd be in verificationPending, not uploadInProgress.
 */
const std::vector<std::string> fullBlobsList = {
    activeHashBlobId, activeImageBlobId, hashBlobId, staticLayoutBlobId};

TEST_F(FirmwareHandlerUploadInProgressTest, OpeningHashFileWhileImageOpenFails)
{
    /* To be in this state, something must be open (and specifically either an
     * active image (or tarball) or the hash file. Also verifies you can't just
     * re-open the currently open file.
     */
    openToInProgress(staticLayoutBlobId);

    for (const auto& blob : fullBlobsList)
    {
        EXPECT_FALSE(handler->open(2, flags, blob));
    }
}

TEST_F(FirmwareHandlerUploadInProgressTest, OpeningImageFileWhileHashOpenFails)
{
    openToInProgress(hashBlobId);

    for (const auto& blob : fullBlobsList)
    {
        EXPECT_FALSE(handler->open(2, flags, blob));
    }
}

/*
 * close(session) - closing the hash or image will trigger a state transition to
 * verificationPending.
 *
 * NOTE: Re-opening /flash/image will transition back to uploadInProgress, but
 * that is verified in the verificationPending::open tests.
 */
TEST_F(FirmwareHandlerUploadInProgressTest,
       ClosingImageFileTransitionsToVerificationPending)
{
    EXPECT_FALSE(handler->canHandleBlob(verifyBlobId));
    openToInProgress(staticLayoutBlobId);

    handler->close(session);
    expectedState(FirmwareBlobHandler::UpdateState::verificationPending);

    EXPECT_TRUE(handler->canHandleBlob(verifyBlobId));
}

TEST_F(FirmwareHandlerUploadInProgressTest,
       ClosingHashFileTransitionsToVerificationPending)
{
    EXPECT_FALSE(handler->canHandleBlob(verifyBlobId));
    openToInProgress(hashBlobId);

    handler->close(session);
    expectedState(FirmwareBlobHandler::UpdateState::verificationPending);

    EXPECT_TRUE(handler->canHandleBlob(verifyBlobId));
}

/*
 * writemeta(session)
 */
TEST_F(FirmwareHandlerUploadInProgressTest,
       WriteMetaAgainstImageReturnsFailureIfNoDataHandler)
{
    /* Calling write/read/writeMeta are uninteresting against the open blob in
     * this case because the blob will just pass the call along.  Whereas
     * calling against the verify or update blob may be more interesting.
     */
    openToInProgress(staticLayoutBlobId);

    /* TODO: Consider adding a test that has a data handler, but that test
     * already exists under the general writeMeta test suite.
     */
    /* Note: with IPMI as the transport there's no data handler, so this should
     * fail nicely. */
    std::vector<std::uint8_t> bytes = {0x01, 0x02};
    EXPECT_FALSE(handler->writeMeta(session, 0, bytes));
}

/*
 * write(session)
 */
TEST_F(FirmwareHandlerUploadInProgressTest, WriteToImageReturnsSuccess)
{
    openToInProgress(staticLayoutBlobId);
    std::vector<std::uint8_t> bytes = {0x01, 0x02};
    EXPECT_CALL(imageMock, write(0, ContainerEq(bytes))).WillOnce(Return(true));
    EXPECT_TRUE(handler->write(session, 0, bytes));
}

TEST_F(FirmwareHandlerUploadInProgressTest, WriteToHashReturnsSuccess)
{
    openToInProgress(hashBlobId);
    std::vector<std::uint8_t> bytes = {0x01, 0x02};
    EXPECT_CALL(imageMock, write(0, ContainerEq(bytes))).WillOnce(Return(true));
    EXPECT_TRUE(handler->write(session, 0, bytes));
}

/*
 * read(session)
 */
TEST_F(FirmwareHandlerUploadInProgressTest, ReadImageFileReturnsFailure)
{
    /* Read is not supported. */
    openToInProgress(staticLayoutBlobId);
    EXPECT_THAT(handler->read(session, 0, 32), IsEmpty());
}

/*
 * commit(session)
 */
TEST_F(FirmwareHandlerUploadInProgressTest,
       CommitAgainstImageFileReturnsFailure)
{
    /* Commit is only valid against specific blobs. */
    openToInProgress(staticLayoutBlobId);
    EXPECT_FALSE(handler->commit(session, {}));
}

TEST_F(FirmwareHandlerUploadInProgressTest, CommitAgainstHashFileReturnsFailure)
{
    openToInProgress(hashBlobId);
    EXPECT_FALSE(handler->commit(session, {}));
}

/*
 * deleteBlob(blob)
 */
TEST_F(FirmwareHandlerUploadInProgressTest, DeleteBlobReturnsFalse)
{
    /* Try deleting all blobs, it doesn't really matter which though because you
     * cannot close out an open session, therefore you must fail to delete
     * anything unless everything is closed.
     */
    openToInProgress(staticLayoutBlobId);
    auto blobs = handler->getBlobIds();
    for (const auto& b : blobs)
    {
        EXPECT_FALSE(handler->deleteBlob(b));
    }
}

} // namespace
} // namespace ipmi_flash
<|endoftext|>


<commit_before>/**********************************************************************
* File:        tessedit.cpp  (Formerly tessedit.c)
* Description: Main program for merge of tess and editor.
* Author:                  Ray Smith
* Created:                 Tue Jan 07 15:21:46 GMT 1992
*
* (C) Copyright 1992, Hewlett-Packard Ltd.
** 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 automatically generated configuration file if running autoconf
#ifdef HAVE_CONFIG_H
#include "config_auto.h"
#endif

#ifdef _WIN32
#include <fcntl.h>
#include <io.h>
#endif  // _WIN32
#include <iostream>

#include "allheaders.h"
#include "baseapi.h"
#include "basedir.h"
#include "renderer.h"
#include "strngs.h"
#include "tprintf.h"
#include "openclwrapper.h"

/**********************************************************************
 *  main()
 *
 **********************************************************************/

int main(int argc, char **argv) {
  if ((argc == 2 && strcmp(argv[1], "-v") == 0) ||
      (argc == 2 && strcmp(argv[1], "--version") == 0)) {
    char *versionStrP;

    fprintf(stderr, "tesseract %s\n", tesseract::TessBaseAPI::Version());

    versionStrP = getLeptonicaVersion();
    fprintf(stderr, " %s\n", versionStrP);
    lept_free(versionStrP);

    versionStrP = getImagelibVersions();
    fprintf(stderr, "  %s\n", versionStrP);
    lept_free(versionStrP);

#ifdef USE_OPENCL
    cl_platform_id platform;
    cl_uint num_platforms;
    cl_device_id devices[2];
    cl_uint num_devices;
    cl_int err;
    char info[256];
    int i;

    fprintf(stderr, " OpenCL info:\n");
    clGetPlatformIDs(1, &platform, &num_platforms);
    fprintf(stderr, "  Found %d platforms.\n", num_platforms);
    clGetPlatformInfo(platform, CL_PLATFORM_NAME, 256, info, 0);
    fprintf(stderr, "  Platform name: %s.\n", info);
    clGetPlatformInfo(platform, CL_PLATFORM_VERSION, 256, info, 0);
    fprintf(stderr, "  Version: %s.\n", info);
    clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 2, devices, &num_devices);
    fprintf(stderr, "  Found %d devices.\n", num_devices);
    for (i = 0; i < num_devices; ++i) {
      clGetDeviceInfo(devices[i], CL_DEVICE_NAME, 256, info, 0);
      fprintf(stderr, "    Device %d name: %s.\n", i+1, info);
    }
#endif
    exit(0);
  }

  // Make the order of args a bit more forgiving than it used to be.
  const char* lang = "eng";
  const char* image = NULL;
  const char* output = NULL;
  const char* datapath = NULL;
  bool noocr = false;
  bool list_langs = false;
  bool print_parameters = false;

  tesseract::PageSegMode pagesegmode = tesseract::PSM_AUTO;
  int arg = 1;
  while (arg < argc && (output == NULL || argv[arg][0] == '-')) {
    if (strcmp(argv[arg], "-l") == 0 && arg + 1 < argc) {
      lang = argv[arg + 1];
      ++arg;
    } else if (strcmp(argv[arg], "--tessdata-dir") == 0 && arg + 1 < argc) {
      datapath = argv[arg + 1];
      ++arg;
    } else if (strcmp(argv[arg], "--list-langs") == 0) {
      noocr = true;
      list_langs = true;
    } else if (strcmp(argv[arg], "-psm") == 0 && arg + 1 < argc) {
      pagesegmode = static_cast<tesseract::PageSegMode>(atoi(argv[arg + 1]));
      ++arg;
    } else if (strcmp(argv[arg], "--print-parameters") == 0) {
      noocr = true;
      print_parameters = true;
    } else if (strcmp(argv[arg], "-c") == 0 && arg + 1 < argc) {
      // handled properly after api init
      ++arg;
    } else if (image == NULL) {
      image = argv[arg];
    } else if (output == NULL) {
      output = argv[arg];
    }
    ++arg;
  }

  if (argc == 2 && strcmp(argv[1], "--list-langs") == 0) {
    list_langs = true;
    noocr = true;
  }

  if (output == NULL && noocr == false) {
    fprintf(stderr, "Usage:\n  %s imagename|stdin outputbase|stdout "
            "[options...] [configfile...]\n\n", argv[0]);

    fprintf(stderr, "OCR options:\n");
    fprintf(stderr, "  --tessdata-dir /path\tspecify location of tessdata"
                      " path\n");
    fprintf(stderr, "  -l lang[+lang]\tspecify language(s) used for OCR\n");
    fprintf(stderr, "  -c configvar=value\tset value for control parameter.\n"
                      "\t\t\tMultiple -c arguments are allowed.\n");
    fprintf(stderr, "  -psm pagesegmode\tspecify page segmentation mode.\n");
    fprintf(stderr, "These options must occur before any configfile.\n\n");
    fprintf(stderr,
            "pagesegmode values are:\n"
            "  0 = Orientation and script detection (OSD) only.\n"
            "  1 = Automatic page segmentation with OSD.\n"
            "  2 = Automatic page segmentation, but no OSD, or OCR\n"
            "  3 = Fully automatic page segmentation, but no OSD. (Default)\n"
            "  4 = Assume a single column of text of variable sizes.\n"
            "  5 = Assume a single uniform block of vertically aligned text.\n"
            "  6 = Assume a single uniform block of text.\n"
            "  7 = Treat the image as a single text line.\n"
            "  8 = Treat the image as a single word.\n"
            "  9 = Treat the image as a single word in a circle.\n"
            "  10 = Treat the image as a single character.\n\n");
    fprintf(stderr, "Single options:\n");
    fprintf(stderr, "  -v --version: version info\n");
    fprintf(stderr, "  --list-langs: list available languages for tesseract "
                      "engine. Can be used with --tessdata-dir.\n");
    fprintf(stderr, "  --print-parameters: print tesseract parameters to the "
                      "stdout.\n");
    exit(1);
  }

  tprintf("Tesseract Open Source OCR Engine v%s with Leptonica\n",
           tesseract::TessBaseAPI::Version());
  PERF_COUNT_START("Tesseract:main")
  tesseract::TessBaseAPI api;

  api.SetOutputName(output);
  int rc = api.Init(datapath, lang, tesseract::OEM_DEFAULT,
                &(argv[arg]), argc - arg, NULL, NULL, false);

  if (rc) {
    fprintf(stderr, "Could not initialize tesseract.\n");
    exit(1);
  }

  char opt1[255], opt2[255];
  for (arg = 0; arg < argc; arg++) {
    if (strcmp(argv[arg], "-c") == 0 && arg + 1 < argc) {
      strncpy(opt1, argv[arg + 1], 255);
      *(strchr(opt1, '=')) = 0;
      strncpy(opt2, strchr(argv[arg + 1], '=') + 1, 255);
      opt2[254] = 0;
      ++arg;

      if (!api.SetVariable(opt1, opt2)) {
        fprintf(stderr, "Could not set option: %s=%s\n", opt1, opt2);
      }
    }
  }

  if (list_langs) {
     GenericVector<STRING> languages;
     api.GetAvailableLanguagesAsVector(&languages);
     fprintf(stderr, "List of available languages (%d):\n",
             languages.size());
     for (int index = 0; index < languages.size(); ++index) {
       STRING& string = languages[index];
       fprintf(stderr, "%s\n", string.string());
     }
     api.End();
     exit(0);
  }

  if (print_parameters) {
     FILE* fout = stdout;
     fprintf(stdout, "Tesseract parameters:\n");
     api.PrintVariables(fout);
     api.End();
     exit(0);
  }

  // We have 2 possible sources of pagesegmode: a config file and
  // the command line. For backwards compatability reasons, the
  // default in tesseract is tesseract::PSM_SINGLE_BLOCK, but the
  // default for this program is tesseract::PSM_AUTO. We will let
  // the config file take priority, so the command-line default
  // can take priority over the tesseract default, so we use the
  // value from the command line only if the retrieved mode
  // is still tesseract::PSM_SINGLE_BLOCK, indicating no change
  // in any config file. Therefore the only way to force
  // tesseract::PSM_SINGLE_BLOCK is from the command line.
  // It would be simpler if we could set the value before Init,
  // but that doesn't work.
  if (api.GetPageSegMode() == tesseract::PSM_SINGLE_BLOCK)
     api.SetPageSegMode(pagesegmode);

  bool stdInput = !strcmp(image, "stdin") || !strcmp(image, "-");
  Pix* pixs = NULL;
  if (stdInput) {
    char byt;
    GenericVector<l_uint8> ch_data;
    std::istream file(std::cin.rdbuf());

#ifdef WIN32
    if (_setmode(_fileno(stdin), _O_BINARY) == -1)
      tprintf("ERROR: cin to binary: %s", strerror(errno));
#endif  // WIN32

    while (file.get(byt)) {
      ch_data.push_back(byt);
    }
    std::cin.ignore(std::cin.rdbuf()->in_avail() + 1);

    pixs = pixReadMem(&ch_data[0], ch_data.size());
  }

  if (pagesegmode == tesseract::PSM_AUTO_OSD) {
    tesseract::Orientation orientation;
    tesseract::WritingDirection direction;
    tesseract::TextlineOrder order;
    float deskew_angle;
    int ret_val = 0;

    if (!pixs)
      pixs = pixRead(image);
    api.SetImage(pixs);
    tesseract::PageIterator* it =  api.AnalyseLayout();
    if (it) {
      it->Orientation(&orientation, &direction, &order, &deskew_angle);
      tprintf("Orientation: %d\nWritingDirection: %d\nTextlineOrder: %d\n" \
              "Deskew angle: %.4f\n",
               orientation, direction, order, deskew_angle);
    } else {
      ret_val = 1;
    }
    pixDestroy(&pixs);
    delete it;
    exit(ret_val);
  }

  tesseract::TessResultRenderer* renderer = NULL;
  bool b;
  api.GetBoolVariable("tessedit_create_hocr", &b);
  if (b && renderer == NULL) renderer = new tesseract::TessHOcrRenderer();

  api.GetBoolVariable("tessedit_create_pdf", &b);
  if (b && renderer == NULL)
    renderer = new tesseract::TessPDFRenderer(api.GetDatapath());

  api.GetBoolVariable("tessedit_create_boxfile", &b);
  if (b && renderer == NULL) renderer = new tesseract::TessBoxTextRenderer();

  if (renderer == NULL) renderer = new tesseract::TessTextRenderer();

  if (pixs) {
    api.ProcessPage(pixs, 0, NULL, NULL, 0, renderer);
    pixDestroy(&pixs);
  } else {
    FILE* fin = fopen(image, "rb");
    if (fin == NULL) {
      fprintf(stderr, "Cannot open input file: %s\n", image);
      exit(2);
    }
    fclose(fin);
    if (!api.ProcessPages(image, NULL, 0, renderer)) {
      fprintf(stderr, "Error during processing.\n");
      exit(1);
    }
  }

  FILE* fout = stdout;
  if (strcmp(output, "-") && strcmp(output, "stdout")) {
    STRING outfile = STRING(output)
        + STRING(".")
        + STRING(renderer->file_extension());
    fout = fopen(outfile.string(), "wb");
    if (fout == NULL) {
      fprintf(stderr, "Cannot create output file %s\n", outfile.string());
      exit(1);
    }
  }

  const char* data;
  inT32 data_len;
  if (renderer->GetOutput(&data, &data_len)) {
    fwrite(data, 1, data_len, fout);
    if (fout != stdout)
      fclose(fout);
    else
      clearerr(fout);
  }
  PERF_COUNT_END
  return 0;                      // Normal exit
}
<commit_msg>don't display tesseract info line if output is stdout<commit_after>/**********************************************************************
* File:        tessedit.cpp  (Formerly tessedit.c)
* Description: Main program for merge of tess and editor.
* Author:                  Ray Smith
* Created:                 Tue Jan 07 15:21:46 GMT 1992
*
* (C) Copyright 1992, Hewlett-Packard Ltd.
** 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 automatically generated configuration file if running autoconf
#ifdef HAVE_CONFIG_H
#include "config_auto.h"
#endif

#ifdef _WIN32
#include <fcntl.h>
#include <io.h>
#endif  // _WIN32
#include <iostream>

#include "allheaders.h"
#include "baseapi.h"
#include "basedir.h"
#include "renderer.h"
#include "strngs.h"
#include "tprintf.h"
#include "openclwrapper.h"

/**********************************************************************
 *  main()
 *
 **********************************************************************/

int main(int argc, char **argv) {
  if ((argc == 2 && strcmp(argv[1], "-v") == 0) ||
      (argc == 2 && strcmp(argv[1], "--version") == 0)) {
    char *versionStrP;

    fprintf(stderr, "tesseract %s\n", tesseract::TessBaseAPI::Version());

    versionStrP = getLeptonicaVersion();
    fprintf(stderr, " %s\n", versionStrP);
    lept_free(versionStrP);

    versionStrP = getImagelibVersions();
    fprintf(stderr, "  %s\n", versionStrP);
    lept_free(versionStrP);

#ifdef USE_OPENCL
    cl_platform_id platform;
    cl_uint num_platforms;
    cl_device_id devices[2];
    cl_uint num_devices;
    cl_int err;
    char info[256];
    int i;

    fprintf(stderr, " OpenCL info:\n");
    clGetPlatformIDs(1, &platform, &num_platforms);
    fprintf(stderr, "  Found %d platforms.\n", num_platforms);
    clGetPlatformInfo(platform, CL_PLATFORM_NAME, 256, info, 0);
    fprintf(stderr, "  Platform name: %s.\n", info);
    clGetPlatformInfo(platform, CL_PLATFORM_VERSION, 256, info, 0);
    fprintf(stderr, "  Version: %s.\n", info);
    clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 2, devices, &num_devices);
    fprintf(stderr, "  Found %d devices.\n", num_devices);
    for (i = 0; i < num_devices; ++i) {
      clGetDeviceInfo(devices[i], CL_DEVICE_NAME, 256, info, 0);
      fprintf(stderr, "    Device %d name: %s.\n", i+1, info);
    }
#endif
    exit(0);
  }

  // Make the order of args a bit more forgiving than it used to be.
  const char* lang = "eng";
  const char* image = NULL;
  const char* output = NULL;
  const char* datapath = NULL;
  bool noocr = false;
  bool list_langs = false;
  bool print_parameters = false;

  tesseract::PageSegMode pagesegmode = tesseract::PSM_AUTO;
  int arg = 1;
  while (arg < argc && (output == NULL || argv[arg][0] == '-')) {
    if (strcmp(argv[arg], "-l") == 0 && arg + 1 < argc) {
      lang = argv[arg + 1];
      ++arg;
    } else if (strcmp(argv[arg], "--tessdata-dir") == 0 && arg + 1 < argc) {
      datapath = argv[arg + 1];
      ++arg;
    } else if (strcmp(argv[arg], "--list-langs") == 0) {
      noocr = true;
      list_langs = true;
    } else if (strcmp(argv[arg], "-psm") == 0 && arg + 1 < argc) {
      pagesegmode = static_cast<tesseract::PageSegMode>(atoi(argv[arg + 1]));
      ++arg;
    } else if (strcmp(argv[arg], "--print-parameters") == 0) {
      noocr = true;
      print_parameters = true;
    } else if (strcmp(argv[arg], "-c") == 0 && arg + 1 < argc) {
      // handled properly after api init
      ++arg;
    } else if (image == NULL) {
      image = argv[arg];
    } else if (output == NULL) {
      output = argv[arg];
    }
    ++arg;
  }

  if (argc == 2 && strcmp(argv[1], "--list-langs") == 0) {
    list_langs = true;
    noocr = true;
  }

  if (output == NULL && noocr == false) {
    fprintf(stderr, "Usage:\n  %s imagename|stdin outputbase|stdout "
            "[options...] [configfile...]\n\n", argv[0]);

    fprintf(stderr, "OCR options:\n");
    fprintf(stderr, "  --tessdata-dir /path\tspecify location of tessdata"
                      " path\n");
    fprintf(stderr, "  -l lang[+lang]\tspecify language(s) used for OCR\n");
    fprintf(stderr, "  -c configvar=value\tset value for control parameter.\n"
                      "\t\t\tMultiple -c arguments are allowed.\n");
    fprintf(stderr, "  -psm pagesegmode\tspecify page segmentation mode.\n");
    fprintf(stderr, "These options must occur before any configfile.\n\n");
    fprintf(stderr,
            "pagesegmode values are:\n"
            "  0 = Orientation and script detection (OSD) only.\n"
            "  1 = Automatic page segmentation with OSD.\n"
            "  2 = Automatic page segmentation, but no OSD, or OCR\n"
            "  3 = Fully automatic page segmentation, but no OSD. (Default)\n"
            "  4 = Assume a single column of text of variable sizes.\n"
            "  5 = Assume a single uniform block of vertically aligned text.\n"
            "  6 = Assume a single uniform block of text.\n"
            "  7 = Treat the image as a single text line.\n"
            "  8 = Treat the image as a single word.\n"
            "  9 = Treat the image as a single word in a circle.\n"
            "  10 = Treat the image as a single character.\n\n");
    fprintf(stderr, "Single options:\n");
    fprintf(stderr, "  -v --version: version info\n");
    fprintf(stderr, "  --list-langs: list available languages for tesseract "
                      "engine. Can be used with --tessdata-dir.\n");
    fprintf(stderr, "  --print-parameters: print tesseract parameters to the "
                      "stdout.\n");
    exit(1);
  }

  if (strcmp(output, "-") && strcmp(output, "stdout")) {
    tprintf("Tesseract Open Source OCR Engine v%s with Leptonica\n",
           tesseract::TessBaseAPI::Version());
  }
  PERF_COUNT_START("Tesseract:main")
  tesseract::TessBaseAPI api;

  api.SetOutputName(output);
  int rc = api.Init(datapath, lang, tesseract::OEM_DEFAULT,
                &(argv[arg]), argc - arg, NULL, NULL, false);

  if (rc) {
    fprintf(stderr, "Could not initialize tesseract.\n");
    exit(1);
  }

  char opt1[255], opt2[255];
  for (arg = 0; arg < argc; arg++) {
    if (strcmp(argv[arg], "-c") == 0 && arg + 1 < argc) {
      strncpy(opt1, argv[arg + 1], 255);
      *(strchr(opt1, '=')) = 0;
      strncpy(opt2, strchr(argv[arg + 1], '=') + 1, 255);
      opt2[254] = 0;
      ++arg;

      if (!api.SetVariable(opt1, opt2)) {
        fprintf(stderr, "Could not set option: %s=%s\n", opt1, opt2);
      }
    }
  }

  if (list_langs) {
     GenericVector<STRING> languages;
     api.GetAvailableLanguagesAsVector(&languages);
     fprintf(stderr, "List of available languages (%d):\n",
             languages.size());
     for (int index = 0; index < languages.size(); ++index) {
       STRING& string = languages[index];
       fprintf(stderr, "%s\n", string.string());
     }
     api.End();
     exit(0);
  }

  if (print_parameters) {
     FILE* fout = stdout;
     fprintf(stdout, "Tesseract parameters:\n");
     api.PrintVariables(fout);
     api.End();
     exit(0);
  }

  // We have 2 possible sources of pagesegmode: a config file and
  // the command line. For backwards compatability reasons, the
  // default in tesseract is tesseract::PSM_SINGLE_BLOCK, but the
  // default for this program is tesseract::PSM_AUTO. We will let
  // the config file take priority, so the command-line default
  // can take priority over the tesseract default, so we use the
  // value from the command line only if the retrieved mode
  // is still tesseract::PSM_SINGLE_BLOCK, indicating no change
  // in any config file. Therefore the only way to force
  // tesseract::PSM_SINGLE_BLOCK is from the command line.
  // It would be simpler if we could set the value before Init,
  // but that doesn't work.
  if (api.GetPageSegMode() == tesseract::PSM_SINGLE_BLOCK)
     api.SetPageSegMode(pagesegmode);

  bool stdInput = !strcmp(image, "stdin") || !strcmp(image, "-");
  Pix* pixs = NULL;
  if (stdInput) {
    char byt;
    GenericVector<l_uint8> ch_data;
    std::istream file(std::cin.rdbuf());

#ifdef WIN32
    if (_setmode(_fileno(stdin), _O_BINARY) == -1)
      tprintf("ERROR: cin to binary: %s", strerror(errno));
#endif  // WIN32

    while (file.get(byt)) {
      ch_data.push_back(byt);
    }
    std::cin.ignore(std::cin.rdbuf()->in_avail() + 1);

    pixs = pixReadMem(&ch_data[0], ch_data.size());
  }

  if (pagesegmode == tesseract::PSM_AUTO_OSD) {
    tesseract::Orientation orientation;
    tesseract::WritingDirection direction;
    tesseract::TextlineOrder order;
    float deskew_angle;
    int ret_val = 0;

    if (!pixs)
      pixs = pixRead(image);
    api.SetImage(pixs);
    tesseract::PageIterator* it =  api.AnalyseLayout();
    if (it) {
      it->Orientation(&orientation, &direction, &order, &deskew_angle);
      tprintf("Orientation: %d\nWritingDirection: %d\nTextlineOrder: %d\n" \
              "Deskew angle: %.4f\n",
               orientation, direction, order, deskew_angle);
    } else {
      ret_val = 1;
    }
    pixDestroy(&pixs);
    delete it;
    exit(ret_val);
  }

  tesseract::TessResultRenderer* renderer = NULL;
  bool b;
  api.GetBoolVariable("tessedit_create_hocr", &b);
  if (b && renderer == NULL) renderer = new tesseract::TessHOcrRenderer();

  api.GetBoolVariable("tessedit_create_pdf", &b);
  if (b && renderer == NULL)
    renderer = new tesseract::TessPDFRenderer(api.GetDatapath());

  api.GetBoolVariable("tessedit_create_boxfile", &b);
  if (b && renderer == NULL) renderer = new tesseract::TessBoxTextRenderer();

  if (renderer == NULL) renderer = new tesseract::TessTextRenderer();

  if (pixs) {
    api.ProcessPage(pixs, 0, NULL, NULL, 0, renderer);
    pixDestroy(&pixs);
  } else {
    FILE* fin = fopen(image, "rb");
    if (fin == NULL) {
      fprintf(stderr, "Cannot open input file: %s\n", image);
      exit(2);
    }
    fclose(fin);
    if (!api.ProcessPages(image, NULL, 0, renderer)) {
      fprintf(stderr, "Error during processing.\n");
      exit(1);
    }
  }

  FILE* fout = stdout;
  if (strcmp(output, "-") && strcmp(output, "stdout")) {
    STRING outfile = STRING(output)
        + STRING(".")
        + STRING(renderer->file_extension());
    fout = fopen(outfile.string(), "wb");
    if (fout == NULL) {
      fprintf(stderr, "Cannot create output file %s\n", outfile.string());
      exit(1);
    }
  }

  const char* data;
  inT32 data_len;
  if (renderer->GetOutput(&data, &data_len)) {
    fwrite(data, 1, data_len, fout);
    if (fout != stdout)
      fclose(fout);
    else
      clearerr(fout);
  }
  PERF_COUNT_END
  return 0;                      // Normal exit
}
<|endoftext|>