<commit_before>//===---- tools/extra/ToolTemplate.cpp - Template for refactoring tool ----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements an empty refactoring tool using the clang tooling.
//  The goal is to lower the "barrier to entry" for writing refactoring tools.
//
//  Usage:
//  tool-template <cmake-output-dir> <file1> <file2> ...
//
//  Where <cmake-output-dir> is a CMake build directory in which a file named
//  compile_commands.json exists (enable -DCMAKE_EXPORT_COMPILE_COMMANDS in
//  CMake to get this output).
//
//  <file1> ... specify the paths of files in the CMake source tree. This path
//  is looked up in the compile command database. If the path of a file is
//  absolute, it needs to point into CMake's source tree. If the path is
//  relative, the current working directory needs to be in the CMake source
//  tree and the file must be in a subdirectory of the current working
//  directory. "./" prefixes in the relative files will be automatically
//  removed, but the rest of a relative path must be a suffix of a path in
//  the compile command line database.
//
//  For example, to use tool-template on all files in a subtree of the
//  source tree, use:
//
//    /path/in/subtree $ find . -name '*.cpp'|
//        xargs tool-template /path/to/build
//
//===----------------------------------------------------------------------===//

#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Lex/Lexer.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Refactoring.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Signals.h"

#include <iostream>

using namespace clang;
using namespace clang::ast_matchers;
using namespace clang::tooling;
using namespace llvm;

namespace {
class ToolTemplateCallback : public MatchFinder::MatchCallback {
 public:
  ToolTemplateCallback(Replacements *Replace) : Replace(Replace) {}

  void run(const MatchFinder::MatchResult &Result) override {
    // TODO: This routine will get called for each thing that the matchers find.
    // At this point, you can examine the match, and do whatever you want,
    // including replacing the matched text with other text
    (void)Replace; // This to prevent an "unused member variable" warning;

    auto tuDecl = Result.Context->getTranslationUnitDecl();

    tuDecl->dump();
  }

 private:
  Replacements *Replace;
};

class OdrASTConsumer : public clang::ASTConsumer {
 public:

  bool HandleTopLevelDecl(DeclGroupRef D) override {
    llvm::outs() << __FUNCTION__ << "\n";

    for (auto decl : D) {
      decl->dump();
    }
    return true;
  }

};

class ClangOdrCheckerFactory : public clang::ASTFrontendAction {
public:
  std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
                                                        StringRef InFile) override {
    return llvm::make_unique<OdrASTConsumer>();
  }
};

} // end anonymous namespace

// Set up the command line options
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
static cl::OptionCategory ToolTemplateCategory("odr-check options");

int main(int argc, const char **argv) {
  llvm::sys::PrintStackTraceOnErrorSignal();
  CommonOptionsParser OptionsParser(argc, argv, ToolTemplateCategory);
  ClangTool Tool(OptionsParser.getCompilations(),
                 OptionsParser.getSourcePathList());

  auto FrontendFactory = newFrontendActionFactory<ClangOdrCheckerFactory>();

  return Tool.run(FrontendFactory.get());
}
<commit_msg>Added initial implementation of checking two CXXRecordDecl objects.<commit_after>//===---- tools/extra/ToolTemplate.cpp - Template for refactoring tool ----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements an empty refactoring tool using the clang tooling.
//  The goal is to lower the "barrier to entry" for writing refactoring tools.
//
//  Usage:
//  tool-template <cmake-output-dir> <file1> <file2> ...
//
//  Where <cmake-output-dir> is a CMake build directory in which a file named
//  compile_commands.json exists (enable -DCMAKE_EXPORT_COMPILE_COMMANDS in
//  CMake to get this output).
//
//  <file1> ... specify the paths of files in the CMake source tree. This path
//  is looked up in the compile command database. If the path of a file is
//  absolute, it needs to point into CMake's source tree. If the path is
//  relative, the current working directory needs to be in the CMake source
//  tree and the file must be in a subdirectory of the current working
//  directory. "./" prefixes in the relative files will be automatically
//  removed, but the rest of a relative path must be a suffix of a path in
//  the compile command line database.
//
//  For example, to use tool-template on all files in a subtree of the
//  source tree, use:
//
//    /path/in/subtree $ find . -name '*.cpp'|
//        xargs tool-template /path/to/build
//
//===----------------------------------------------------------------------===//

#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Lex/Lexer.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Refactoring.h"
#include "clang/Tooling/Tooling.h"
#include "clang/Serialization/ASTWriter.h"
#include "clang/Serialization/ASTReader.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Signals.h"

using namespace clang;
using namespace clang::ast_matchers;
using namespace clang::tooling;
using namespace llvm;

namespace odr_check {

typedef std::vector<std::unique_ptr<ASTUnit>> ASTList;

class OdrCheckingStrategy {
public:
  virtual bool Check(ASTList& ASTs) = 0;
};

class OdrCheckAction : public ToolAction {
public:

private:
  ASTList ASTs;

public:
  OdrCheckAction(){}

  bool runInvocation(CompilerInvocation *Invocation, FileManager *Files,
                     DiagnosticConsumer *DiagConsumer) override {

    std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
        Invocation, CompilerInstance::createDiagnostics(
                        &Invocation->getDiagnosticOpts(), DiagConsumer,
                        /*ShouldOwnClient=*/false));
    if (!AST)
      return false;

    ASTs.push_back(std::move(AST));
    return true;
  }

  ASTList& getASTList() {
    return ASTs;
  }

  virtual std::unique_ptr<OdrCheckingStrategy> createOdrCheckingStrategy() = 0;
};

class OdrCheckTool : private ClangTool {
public:
  OdrCheckTool(const CompilationDatabase &Compilations,
               ArrayRef<std::string> SourcePaths)
    : ClangTool(Compilations, SourcePaths) {
  }

  int runOdrCheck(OdrCheckAction *action) {
    int Res = run(action);
    if (Res != EXIT_SUCCESS) {
      return Res;
    }
    auto CheckingStrategy = action->createOdrCheckingStrategy();
    return CheckOdr(CheckingStrategy.get(), action->getASTList());
  }

private:
  int CheckOdr(OdrCheckingStrategy* CheckingStrategy, ASTList& ASTs) {
    if (!CheckingStrategy->Check(ASTs)) {
      return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
  }
};

class SimpleComparisonCheckingStrategy : public OdrCheckingStrategy {
public:
  virtual bool Check(ASTList &ASTs) override {
    for (auto& leftAstIt : ASTs) {
      for (auto& rightAstIt : ASTs) {
        if (leftAstIt != rightAstIt) {
          if (!CheckOdrForAsts(*leftAstIt, *rightAstIt)) {
            return EXIT_FAILURE;
          }
        }
      }
    }
    return EXIT_SUCCESS;
  }

private:
  bool CheckOdrForAsts(ASTUnit& left, ASTUnit& right) const {
    return false;
  }
};

class FindCxxRecordDecl : public RecursiveASTVisitor<FindCxxRecordDecl>
{
public:
  FindCxxRecordDecl(CXXRecordDecl* root, raw_ostream& out) : Root(root), Out(out) {
  }

  bool VisitCXXRecordDecl(CXXRecordDecl* D) {
    if (D->getName() == Root->getName()) {
      Out << "found decl with name [" << D->getName() << "]\n";
      Out.flush();
    }

    return true;
  }
private:
  CXXRecordDecl* Root;
  raw_ostream& Out;
};

class RootVisitor : public RecursiveASTVisitor<RootVisitor>
{
public:

  RootVisitor(TranslationUnitDecl* other, raw_ostream& out): Other(other), Out(out) {
  }
#if 0
  bool VisitDecl(Decl *D) {
    Out << "decl begin {\n";
    Out.flush();
    D->dump(Out);
    Out.flush();
    Out << "} cxx record end\n";
    Out.flush();

    return true;
  }
#endif //0

  bool VisitCXXRecordDecl(CXXRecordDecl* D) {

    FindCxxRecordDecl other(D, Out);

    return other.TraverseDecl(Other);
#if 0
    Out << "cxx record begin {\n";
    Out.flush();
    D->dump(Out);
    Out.flush();
    Out << "} cxx record end\n";
    Out.flush();
    return true;
#endif //0
  }

private:
  TranslationUnitDecl* Other;
  raw_ostream& Out;
};

class ASTMergingCheckingStrategy : public OdrCheckingStrategy {
public:
  virtual bool Check(ASTList &ASTs) override {
    if (ASTs.empty()) {
      return true;
    }

    auto& rootAST = ASTs.front();
    for (auto astIt = ASTs.begin() + 1; astIt != ASTs.end(); ++astIt) {
      if (!MergeAsts(rootAST.get(), astIt->get())) {
        return false;
      }
    }
    return EXIT_SUCCESS;
  }

private:
  bool MergeAsts(ASTUnit* root, ASTUnit* other) const {
    ASTContext& rootCtx = root->getASTContext();
    ASTContext& otherCtx = other->getASTContext();

    TranslationUnitDecl* rootTuDecl = rootCtx.getTranslationUnitDecl();
    TranslationUnitDecl* otherTuDecl = otherCtx.getTranslationUnitDecl();

    raw_ostream& out = outs();

    out << "root\n";
    out.flush();
    rootTuDecl->dump(out);
    out.flush();

    out << "\nother\n";
    out.flush();
    otherTuDecl->dump();
    out.flush();

    out << "\nvisitor\n";
    out.flush();
    RootVisitor V(otherTuDecl, out);
    V.TraverseDecl(rootTuDecl);

    return false;
  }
};

class MergeAstsAction : public OdrCheckAction {
public:
  std::unique_ptr<OdrCheckingStrategy> createOdrCheckingStrategy() override {
    return std::unique_ptr<OdrCheckingStrategy>(new ASTMergingCheckingStrategy);
  }

};

} // odr_check namespace

using namespace odr_check;

// Set up the command line options
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
static cl::OptionCategory ToolTemplateCategory("odr-check options");

int main(int argc, const char **argv) {
  llvm::sys::PrintStackTraceOnErrorSignal();
  CommonOptionsParser OptionsParser(argc, argv, ToolTemplateCategory);
  OdrCheckTool Tool(OptionsParser.getCompilations(),
                    OptionsParser.getSourcePathList());

  MergeAstsAction Action;
  return Tool.runOdrCheck(&Action);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2003-2007 Funambol
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "base/Log.h"
#include "base/util/utils.h"

#define FUNAMBOL_HEADER "Funambol Windows Mobile Plug-in Log"
Log LOG = Log(false);

char logmsg[512];

static FILE* logFile = NULL;
static char logFullName[512] = "\\" LOG_NAME ;
static char logName[128] = LOG_NAME;
static char logPath[256] = "\\" ;

//-------------------------------------------------------------- Static Functions

/*
* return a the time to write into log file. If complete is true, it return
* the date too, else only hours, minutes, seconds and milliseconds
*/
static char* createCurrentTime(BOOL complete) {

    SYSTEMTIME sys_time;
    TIME_ZONE_INFORMATION timezone;
    GetLocalTime(&sys_time);
    GetTimeZoneInformation(&timezone);

    char fmtComplete[] = "%04d-%02d-%02d %02d:%02d:%02d GMT %c%d:%02d";
    char fmt[]         = "%02d:%02d:%02d GMT %c%d:%02d";

    char*  ret = new char [64];

    // calculate offset from UTC/GMT in hours:min, positive value
    // means east of Greenwich (e.g. CET = GMT +1)

    char direction = timezone.Bias <= 0 ? '+' : '-';
    int hours = abs(timezone.Bias / 60) ;
    int minutes = abs(timezone.Bias % 60);

    if (complete) {
        sprintf(ret, fmtComplete, sys_time.wYear, sys_time.wMonth, sys_time.wDay,
                 sys_time.wHour, sys_time.wMinute, sys_time.wSecond,
                direction, hours, minutes);
    } else {
        sprintf(ret, fmt, sys_time.wHour, sys_time.wMinute, sys_time.wSecond,
                direction, hours, minutes);
    }
    return ret;
}

//------------------------------------------------------------------ Constructors

Log::Log(BOOL resetLog, const char*  path, const char*  name) {

    setLogPath(path);
    setLogName(name);
	if (resetLog) {
        reset(FUNAMBOL_HEADER);
    }
}

Log::~Log() {
    if (logFile != NULL) {
        fclose(logFile);
    }
}

//---------------------------------------------------------------- Public methods

void Log::setLogPath(const char*  configLogPath) {

    if (configLogPath != NULL) {
        sprintf(logPath, "%s/", configLogPath);
    } else {
        sprintf(logPath, "%s", "./");
    }
}

void Log::setLogName(const char*  configLogName) {

    if (configLogName != NULL) {
        sprintf(logName, "%s", configLogName);
    }
    else {
        sprintf(logName, "%s", LOG_NAME);
    }
}

void Log::error(const char*  msg, ...) {
    va_list argList;
    va_start (argList, msg);
    printMessage(LOG_ERROR, msg, argList);
    va_end(argList);
}

void Log::info(const char*  msg, ...) {
    if (logLevel >= LOG_LEVEL_INFO) {
        va_list argList;
	    va_start (argList, msg);
        printMessage(LOG_INFO, msg, argList);
	    va_end(argList);

    }
}

void Log::debug(const char*  msg, ...) {
    if (logLevel >= LOG_LEVEL_DEBUG) {
	    va_list argList;
        va_start (argList, msg);
        printMessage(LOG_DEBUG, msg, argList);
        va_end(argList);

    }
}

void Log::trace(const char*  msg) {
}

void Log::setLevel(LogLevel level) {
    logLevel = level;
}

LogLevel Log::getLevel() {
    return logLevel;
}

BOOL Log::isLoggable(LogLevel level) {
    return (level >= logLevel);
}

void Log::printMessage(const char*  level, const char*  msg, va_list argList) {

	char*  currentTime = createCurrentTime(false);
    logFile = fopen(logFullName, "a+");

	fprintf(logFile, "%s [%s] - ", currentTime, level);
    vfprintf(logFile, msg, argList);
	fprintf(logFile, "\n");
	fclose(logFile);

    delete[] currentTime;
}

void Log::reset(const char*  title) {

    const char *t = (title) ? title : FUNAMBOL_HEADER;

    char*  currentTime = createCurrentTime(true);
    memset(logFullName, 0, 512*sizeof(char));
    sprintf(logFullName, "%s%s", logPath, logName);
    logFile = fopen(logFullName, "w+");
    fprintf(logFile, "%s - %s\n", t, currentTime);
    fclose(logFile);

    delete[] currentTime;
}

<commit_msg>Code reformatted<commit_after>/*
 * Copyright (C) 2003-2007 Funambol
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "base/Log.h"
#include "base/util/utils.h"

#define FUNAMBOL_HEADER "Funambol Windows Mobile Plug-in Log"
Log LOG = Log(false);

char logmsg[512];

static FILE* logFile = NULL;
static char logFullName[512] = "\\" LOG_NAME ;
static char logName[128] = LOG_NAME;
static char logPath[256] = "\\" ;

//-------------------------------------------------------------- Static Functions

/*
* return a the time to write into log file. If complete is true, it return
* the date too, else only hours, minutes, seconds and milliseconds
*/
static char* createCurrentTime(BOOL complete) {

    SYSTEMTIME sys_time;
    TIME_ZONE_INFORMATION timezone;
    GetLocalTime(&sys_time);
    GetTimeZoneInformation(&timezone);

    char fmtComplete[] = "%04d-%02d-%02d %02d:%02d:%02d GMT %c%d:%02d";
    char fmt[]         = "%02d:%02d:%02d GMT %c%d:%02d";

    char*  ret = new char [64];

    // calculate offset from UTC/GMT in hours:min, positive value
    // means east of Greenwich (e.g. CET = GMT +1)

    char direction = timezone.Bias <= 0 ? '+' : '-';
    int hours = abs(timezone.Bias / 60) ;
    int minutes = abs(timezone.Bias % 60);

    if (complete) {
        sprintf(ret, fmtComplete, sys_time.wYear, sys_time.wMonth, sys_time.wDay,
                 sys_time.wHour, sys_time.wMinute, sys_time.wSecond,
                direction, hours, minutes);
    } else {
        sprintf(ret, fmt, sys_time.wHour, sys_time.wMinute, sys_time.wSecond,
                direction, hours, minutes);
    }
    return ret;
}

//------------------------------------------------------------------ Constructors

Log::Log(BOOL resetLog, const char*  path, const char*  name) {

    setLogPath(path);
    setLogName(name);
    if (resetLog) {
        reset(FUNAMBOL_HEADER);
    }
}

Log::~Log() {
    if (logFile != NULL) {
        fclose(logFile);
    }
}

//---------------------------------------------------------------- Public methods

void Log::setLogPath(const char*  configLogPath) {

    if (configLogPath != NULL) {
        sprintf(logPath, "%s/", configLogPath);
    } else {
        sprintf(logPath, "%s", "./");
    }
}

void Log::setLogName(const char*  configLogName) {

    if (configLogName != NULL) {
        sprintf(logName, "%s", configLogName);
    }
    else {
        sprintf(logName, "%s", LOG_NAME);
    }
}

void Log::error(const char*  msg, ...) {
    va_list argList;
    va_start (argList, msg);
    printMessage(LOG_ERROR, msg, argList);
    va_end(argList);
}

void Log::info(const char*  msg, ...) {
    if (logLevel >= LOG_LEVEL_INFO) {
        va_list argList;
	    va_start (argList, msg);
        printMessage(LOG_INFO, msg, argList);
	    va_end(argList);

    }
}

void Log::debug(const char*  msg, ...) {
    if (logLevel >= LOG_LEVEL_DEBUG) {
	    va_list argList;
        va_start (argList, msg);
        printMessage(LOG_DEBUG, msg, argList);
        va_end(argList);

    }
}

void Log::trace(const char*  msg) {
}

void Log::setLevel(LogLevel level) {
    logLevel = level;
}

LogLevel Log::getLevel() {
    return logLevel;
}

BOOL Log::isLoggable(LogLevel level) {
    return (level >= logLevel);
}

void Log::printMessage(const char*  level, const char*  msg, va_list argList) {

	char*  currentTime = createCurrentTime(false);
    logFile = fopen(logFullName, "a+");

	fprintf(logFile, "%s [%s] - ", currentTime, level);
    vfprintf(logFile, msg, argList);
	fprintf(logFile, "\n");
	fclose(logFile);

    delete[] currentTime;
}

void Log::reset(const char*  title) {

    const char *t = (title) ? title : FUNAMBOL_HEADER;

    char*  currentTime = createCurrentTime(true);
    memset(logFullName, 0, 512*sizeof(char));
    sprintf(logFullName, "%s%s", logPath, logName);
    logFile = fopen(logFullName, "w+");
    fprintf(logFile, "%s - %s\n", t, currentTime);
    fclose(logFile);

    delete[] currentTime;
}

<|endoftext|>


<commit_before>//****************************************************************************//
// morphtargetmixer.cpp                                                       //
// Copyright (C) 2001, 2002 Bruno 'Beosil' Heidelberger                       //
//****************************************************************************//
// This library is free software; you can redistribute it and/or modify it    //
// under the terms of the GNU Lesser General Public License as published by   //
// the Free Software Foundation; either version 2.1 of the License, or (at    //
// your option) any later version.                                            //
//****************************************************************************//

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

//****************************************************************************//
// Includes                                                                   //
//****************************************************************************//

#include "cal3d/error.h"
#include "cal3d/morphtargetmixer.h"
#include "cal3d/mesh.h"
#include "cal3d/submesh.h"
#include "cal3d/coremesh.h"
#include "cal3d/coresubmesh.h"

 /*****************************************************************************/
/** Constructs the morph target mixer instance.
  *
  * This function is the default constructor of the morph target mixer instance.
  *****************************************************************************/

CalMorphTargetMixer::CalMorphTargetMixer()
  : m_pMesh(0)
{
}

 /*****************************************************************************/
/** Destructs the morph target mixer instance.
  *
  * This function is the destructor of the morph target mixer instance.
  *****************************************************************************/

CalMorphTargetMixer::~CalMorphTargetMixer()
{
}

 /*****************************************************************************/
/** Interpolates the weight of a morph target.
  *
  * This function interpolates the weight of a morph target a new value
  * in a given amount of time.
  *
  * @param id The ID of the morph target that should be blended.
  * @param weight The weight to interpolate the morph target to.
  * @param delay The time in seconds until the new weight should be reached.
  *
  * @return One of the following values:
  *         \li \b true if successful
  *         \li \b false if an error happend
  *****************************************************************************/
bool CalMorphTargetMixer::blend(int id, float weight, float delay)
{
  if((id < 0) || (id >= (int)m_vectorCurrentWeight.size()))
  {
    CalError::setLastError(CalError::INVALID_HANDLE, __FILE__, __LINE__);
    return false;
  }
  float currentWeight = 1.0f - m_vectorCurrentWeight[id];
  float endWeight = 1.0f - weight;
  if(currentWeight != 0.0f)
  {
    float factor = endWeight/currentWeight;
    std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
    {
      (*iteratorEndWeight) = (*iteratorCurrentWeight)*factor;
      ++iteratorCurrentWeight;
      ++iteratorEndWeight;
    }
  }
  else
  {
    float factor = endWeight/((float)m_vectorEndWeight.size());
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorEndWeight!=m_vectorEndWeight.end())
    {
      (*iteratorEndWeight) = factor;
      ++iteratorEndWeight;
    }
  }
  m_vectorEndWeight[id] = weight;
  m_duration = delay;
  return true;
}

 /*****************************************************************************/
/** Interpolates the weight of the base vertices.
  *
  * This function interpolates the weight of the base vertices a new value
  * in a given amount of time.
  *
  * @param weight The weight to interpolate the base vertices to.
  * @param delay The time in seconds until the new weight should be reached.
  *
  * @return One of the following values:
  *         \li \b true if successful
  *         \li \b false if an error happend
  *****************************************************************************/

bool CalMorphTargetMixer::blendBase(float weight, float delay)
{
  float currentWeight = 0.0f;
  std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
  while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
  {
    currentWeight +=(*iteratorCurrentWeight);
    ++iteratorCurrentWeight;
  }
  float endWeight = 1.0f - weight;
  if(currentWeight != 0.0f)
  {
    float factor = endWeight/currentWeight;
    std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
    {
      (*iteratorEndWeight) = (*iteratorCurrentWeight)*factor;
      ++iteratorCurrentWeight;
      ++iteratorEndWeight;
    }
  }
  else
  {
    float factor = endWeight/((float)m_vectorEndWeight.size());
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorEndWeight!=m_vectorEndWeight.end())
    {
      (*iteratorEndWeight) = factor;
      ++iteratorEndWeight;
    }
  }
  m_duration = delay;
  return true;
}

 /*****************************************************************************/
/** Fades a morph target out.
  *
  * This function fades a morph target out in a given amount of time.
  *
  * @param id The ID of the morph target that should be faded out.
  * @param delay The time in seconds until the the morph target is
  *              completely removed.
  *
  * @return One of the following values:
  *         \li \b true if successful
  *         \li \b false if an error happend
  *****************************************************************************/

bool CalMorphTargetMixer::clear(int id, float delay)
{
  if((id < 0) || (id >= (int)m_vectorCurrentWeight.size()))
  {
    CalError::setLastError(CalError::INVALID_HANDLE, __FILE__, __LINE__);
    return false;
  }
  float currentWeight = 1.0f - m_vectorCurrentWeight[id];
  if(currentWeight != 0.0f)
  {
    float factor = 1.0f/currentWeight;
    std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
    {
      (*iteratorEndWeight) = (*iteratorCurrentWeight)*factor;
      ++iteratorCurrentWeight;
      ++iteratorEndWeight;
    }
  }
  else
  {
    float factor = 1.0f/((float)m_vectorEndWeight.size());
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorEndWeight!=m_vectorEndWeight.end())
    {
      (*iteratorEndWeight) = factor;
      ++iteratorEndWeight;
    }
  }
  m_vectorEndWeight[id] = 0.0f;
  m_duration = delay;
  return true;
}

 /*****************************************************************************/
/** Fades the base vertices out.
  *
  * This function fades the base vertices out in a given amount of time.
  *
  * @param delay The time in seconds until the the base vertices is
  *              completely removed.
  *
  * @return One of the following values:
  *         \li \b true if successful
  *         \li \b false if an error happend
  *****************************************************************************/

bool CalMorphTargetMixer::clearBase(float delay)
{
  float currentWeight = 0.0f;
  std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
  while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
  {
    currentWeight +=(*iteratorCurrentWeight);
    ++iteratorCurrentWeight;
  }
  if(currentWeight != 0.0f)
  {
    float factor = 1.0f/currentWeight;
    std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
    {
      (*iteratorEndWeight) = (*iteratorCurrentWeight)*factor;
      ++iteratorCurrentWeight;
      ++iteratorEndWeight;
    }
  }
  else
  {
    float factor = 1.0f/((float)m_vectorEndWeight.size());
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorEndWeight!=m_vectorEndWeight.end())
    {
      (*iteratorEndWeight) = factor;
      ++iteratorEndWeight;
    }
  }
  m_duration = delay;
  return true;
}

 /*****************************************************************************/
/** Get the weight of a morph target.
  *
  * @param id The id of the morph target which weight you want.
  *
  * @return The weight of the morph target with the given id.
  *****************************************************************************/
float CalMorphTargetMixer::getCurrentWeight(int id)
{
  if((id < 0) || (id >= (int)m_vectorCurrentWeight.size()))
  {
    CalError::setLastError(CalError::INVALID_HANDLE, __FILE__, __LINE__);
    return false;
  }
  return m_vectorCurrentWeight[id];
}

 /*****************************************************************************/
/** Get the weight of the base vertices.
  *
  * @return The weight of the base vertices.
  *****************************************************************************/
float CalMorphTargetMixer::getCurrentWeightBase()
{
  float currentWeight = 1.0f;
  std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
  while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
  {
    currentWeight -=(*iteratorCurrentWeight);
    ++iteratorCurrentWeight;
  }
  return currentWeight;
}
 /*****************************************************************************/
/** Creates the morph target mixer instance.
  *
  * This function creates the mixer instance.
  *
  * @param pMesh A pointer to the mesh that should be managed with this
  *               morph target mixer instance.
  *
  * @return One of the following values:
  *         \li \b true if successful
  *         \li \b false if an error happend
  *****************************************************************************/

bool CalMorphTargetMixer::create(CalMesh *pMesh)
{
  if(pMesh == 0)
  {
    CalError::setLastError(CalError::INVALID_HANDLE, __FILE__, __LINE__);
    return false;
  }

  m_pMesh = pMesh;

  CalCoreSubmesh *coreSubmesh = pMesh->getCoreMesh()->getCoreSubmesh(0);
  if (coreSubmesh == 0)
  {
    CalError::setLastError(CalError::INTERNAL, __FILE__, __LINE__);//HMMM
    return false;
  }
  int subMorphTargetCount = coreSubmesh->getCoreSubMorphTargetCount();
  // reserve the space needed in all the vectors
  m_vectorCurrentWeight.reserve(subMorphTargetCount);
  m_vectorCurrentWeight.resize(subMorphTargetCount);
  m_vectorEndWeight.reserve(subMorphTargetCount);
  m_vectorEndWeight.resize(subMorphTargetCount);
  std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
  std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
  while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
  {
    (*iteratorCurrentWeight) = 0.0f;
    (*iteratorEndWeight) = 0.0f;
    ++iteratorCurrentWeight;
    ++iteratorEndWeight;
  }
  m_duration = 0.0f;

  return true;
}

 /*****************************************************************************/
/** Destroys the morph target mixer instance.
  *
  * This function destroys all data stored in the mixer instance and frees all
  * allocated memory.
  *****************************************************************************/

void CalMorphTargetMixer::destroy()
{
  m_pMesh = 0;
}

 /*****************************************************************************/
/** Updates all morph targets.
  *
  * This function updates all morph targets of the mixer instance for a
  * given amount of time.
  *
  * @param deltaTime The elapsed time in seconds since the last update.
  *****************************************************************************/

void CalMorphTargetMixer::update(float deltaTime)
{
  if(deltaTime >= m_duration)
  {
    std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
    {
      (*iteratorCurrentWeight) = (*iteratorEndWeight);
      ++iteratorCurrentWeight;
      ++iteratorEndWeight;
    }
    m_duration = 0.0f;
  }
  else
  {
    std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
    {
      (*iteratorCurrentWeight) += ((*iteratorEndWeight)-(*iteratorCurrentWeight))*deltaTime/m_duration;
      ++iteratorCurrentWeight;
      ++iteratorEndWeight;
    }
    m_duration -= deltaTime;
  }
  std::vector<CalSubmesh *> &vectorSubmesh = m_pMesh->getVectorSubmesh();
  int morphTargetCount = m_vectorCurrentWeight.size();
  int submeshCount = vectorSubmesh.size();
  int submeshId;
  for(submeshId=0;submeshId<submeshCount;++submeshId)
  {
    int morphTargetId;
    for(morphTargetId=0;morphTargetId<morphTargetCount;++morphTargetId)
    {
      vectorSubmesh[submeshId]->setMorphTargetWeight(morphTargetId,m_vectorCurrentWeight[morphTargetId]);
    }
  }
}

 /*****************************************************************************/
/** Returns the number of morph targets this morph target mixer mixes.
  *
  * @return The number of morph targets this morph target mixer mixes.
  *****************************************************************************/

int CalMorphTargetMixer::getMorphTargetCount()
{
  return m_vectorCurrentWeight.size();
}

//****************************************************************************//
<commit_msg>Made the code a bit more robust.<commit_after>//****************************************************************************//
// morphtargetmixer.cpp                                                       //
// Copyright (C) 2001, 2002 Bruno 'Beosil' Heidelberger                       //
//****************************************************************************//
// This library is free software; you can redistribute it and/or modify it    //
// under the terms of the GNU Lesser General Public License as published by   //
// the Free Software Foundation; either version 2.1 of the License, or (at    //
// your option) any later version.                                            //
//****************************************************************************//

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

//****************************************************************************//
// Includes                                                                   //
//****************************************************************************//

#include "cal3d/error.h"
#include "cal3d/morphtargetmixer.h"
#include "cal3d/mesh.h"
#include "cal3d/submesh.h"
#include "cal3d/coremesh.h"
#include "cal3d/coresubmesh.h"

 /*****************************************************************************/
/** Constructs the morph target mixer instance.
  *
  * This function is the default constructor of the morph target mixer instance.
  *****************************************************************************/

CalMorphTargetMixer::CalMorphTargetMixer()
  : m_pMesh(0)
{
}

 /*****************************************************************************/
/** Destructs the morph target mixer instance.
  *
  * This function is the destructor of the morph target mixer instance.
  *****************************************************************************/

CalMorphTargetMixer::~CalMorphTargetMixer()
{
}

 /*****************************************************************************/
/** Interpolates the weight of a morph target.
  *
  * This function interpolates the weight of a morph target a new value
  * in a given amount of time.
  *
  * @param id The ID of the morph target that should be blended.
  * @param weight The weight to interpolate the morph target to.
  * @param delay The time in seconds until the new weight should be reached.
  *
  * @return One of the following values:
  *         \li \b true if successful
  *         \li \b false if an error happend
  *****************************************************************************/
bool CalMorphTargetMixer::blend(int id, float weight, float delay)
{
  if((id < 0) || (id >= (int)m_vectorCurrentWeight.size()))
  {
    CalError::setLastError(CalError::INVALID_HANDLE, __FILE__, __LINE__);
    return false;
  }
  float currentWeight = 1.0f - m_vectorCurrentWeight[id];
  float endWeight = 1.0f - weight;
  if(currentWeight != 0.0f)
  {
    float factor = endWeight/currentWeight;
    std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
    {
      (*iteratorEndWeight) = (*iteratorCurrentWeight)*factor;
      ++iteratorCurrentWeight;
      ++iteratorEndWeight;
    }
  }
  else
  {
    float factor = endWeight/((float)m_vectorEndWeight.size());
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorEndWeight!=m_vectorEndWeight.end())
    {
      (*iteratorEndWeight) = factor;
      ++iteratorEndWeight;
    }
  }
  m_vectorEndWeight[id] = weight;
  m_duration = delay;
  return true;
}

 /*****************************************************************************/
/** Interpolates the weight of the base vertices.
  *
  * This function interpolates the weight of the base vertices a new value
  * in a given amount of time.
  *
  * @param weight The weight to interpolate the base vertices to.
  * @param delay The time in seconds until the new weight should be reached.
  *
  * @return One of the following values:
  *         \li \b true if successful
  *         \li \b false if an error happend
  *****************************************************************************/

bool CalMorphTargetMixer::blendBase(float weight, float delay)
{
  float currentWeight = 0.0f;
  std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
  while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
  {
    currentWeight +=(*iteratorCurrentWeight);
    ++iteratorCurrentWeight;
  }
  float endWeight = 1.0f - weight;
  if(currentWeight != 0.0f)
  {
    float factor = endWeight/currentWeight;
    std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
    {
      (*iteratorEndWeight) = (*iteratorCurrentWeight)*factor;
      ++iteratorCurrentWeight;
      ++iteratorEndWeight;
    }
  }
  else
  {
    float factor = endWeight/((float)m_vectorEndWeight.size());
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorEndWeight!=m_vectorEndWeight.end())
    {
      (*iteratorEndWeight) = factor;
      ++iteratorEndWeight;
    }
  }
  m_duration = delay;
  return true;
}

 /*****************************************************************************/
/** Fades a morph target out.
  *
  * This function fades a morph target out in a given amount of time.
  *
  * @param id The ID of the morph target that should be faded out.
  * @param delay The time in seconds until the the morph target is
  *              completely removed.
  *
  * @return One of the following values:
  *         \li \b true if successful
  *         \li \b false if an error happend
  *****************************************************************************/

bool CalMorphTargetMixer::clear(int id, float delay)
{
  if((id < 0) || (id >= (int)m_vectorCurrentWeight.size()))
  {
    CalError::setLastError(CalError::INVALID_HANDLE, __FILE__, __LINE__);
    return false;
  }
  float currentWeight = 1.0f - m_vectorCurrentWeight[id];
  if(currentWeight != 0.0f)
  {
    float factor = 1.0f/currentWeight;
    std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
    {
      (*iteratorEndWeight) = (*iteratorCurrentWeight)*factor;
      ++iteratorCurrentWeight;
      ++iteratorEndWeight;
    }
  }
  else
  {
    float factor = 1.0f/((float)m_vectorEndWeight.size());
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorEndWeight!=m_vectorEndWeight.end())
    {
      (*iteratorEndWeight) = factor;
      ++iteratorEndWeight;
    }
  }
  m_vectorEndWeight[id] = 0.0f;
  m_duration = delay;
  return true;
}

 /*****************************************************************************/
/** Fades the base vertices out.
  *
  * This function fades the base vertices out in a given amount of time.
  *
  * @param delay The time in seconds until the the base vertices is
  *              completely removed.
  *
  * @return One of the following values:
  *         \li \b true if successful
  *         \li \b false if an error happend
  *****************************************************************************/

bool CalMorphTargetMixer::clearBase(float delay)
{
  float currentWeight = 0.0f;
  std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
  while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
  {
    currentWeight +=(*iteratorCurrentWeight);
    ++iteratorCurrentWeight;
  }
  if(currentWeight != 0.0f)
  {
    float factor = 1.0f/currentWeight;
    std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
    {
      (*iteratorEndWeight) = (*iteratorCurrentWeight)*factor;
      ++iteratorCurrentWeight;
      ++iteratorEndWeight;
    }
  }
  else
  {
    float factor = 1.0f/((float)m_vectorEndWeight.size());
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorEndWeight!=m_vectorEndWeight.end())
    {
      (*iteratorEndWeight) = factor;
      ++iteratorEndWeight;
    }
  }
  m_duration = delay;
  return true;
}

 /*****************************************************************************/
/** Get the weight of a morph target.
  *
  * @param id The id of the morph target which weight you want.
  *
  * @return The weight of the morph target with the given id.
  *****************************************************************************/
float CalMorphTargetMixer::getCurrentWeight(int id)
{
  if((id < 0) || (id >= (int)m_vectorCurrentWeight.size()))
  {
    CalError::setLastError(CalError::INVALID_HANDLE, __FILE__, __LINE__);
    return false;
  }
  return m_vectorCurrentWeight[id];
}

 /*****************************************************************************/
/** Get the weight of the base vertices.
  *
  * @return The weight of the base vertices.
  *****************************************************************************/
float CalMorphTargetMixer::getCurrentWeightBase()
{
  float currentWeight = 1.0f;
  std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
  while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
  {
    currentWeight -=(*iteratorCurrentWeight);
    ++iteratorCurrentWeight;
  }
  return currentWeight;
}
 /*****************************************************************************/
/** Creates the morph target mixer instance.
  *
  * This function creates the mixer instance.
  *
  * @param pMesh A pointer to the mesh that should be managed with this
  *               morph target mixer instance.
  *
  * @return One of the following values:
  *         \li \b true if successful
  *         \li \b false if an error happend
  *****************************************************************************/

bool CalMorphTargetMixer::create(CalMesh *pMesh)
{
  if(pMesh == 0)
  {
    CalError::setLastError(CalError::INVALID_HANDLE, __FILE__, __LINE__);
    return false;
  }
  m_pMesh = pMesh;

  if(pMesh->getCoreMesh()->getCoreSubmeshCount() != 0)
  {
    CalCoreSubmesh *coreSubmesh = pMesh->getCoreMesh()->getCoreSubmesh(0);
    if (coreSubmesh == 0)
    {
      CalError::setLastError(CalError::INTERNAL, __FILE__, __LINE__);//HMMM
      return false;
    }
    int subMorphTargetCount = coreSubmesh->getCoreSubMorphTargetCount();
    // reserve the space needed in all the vectors
    m_vectorCurrentWeight.reserve(subMorphTargetCount);
    m_vectorCurrentWeight.resize(subMorphTargetCount);
    m_vectorEndWeight.reserve(subMorphTargetCount);
    m_vectorEndWeight.resize(subMorphTargetCount);
    std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
    {
      (*iteratorCurrentWeight) = 0.0f;
      (*iteratorEndWeight) = 0.0f;
      ++iteratorCurrentWeight;
      ++iteratorEndWeight;
    }
  }
  m_duration = 0.0f;

  return true;
}

 /*****************************************************************************/
/** Destroys the morph target mixer instance.
  *
  * This function destroys all data stored in the mixer instance and frees all
  * allocated memory.
  *****************************************************************************/

void CalMorphTargetMixer::destroy()
{
  m_pMesh = 0;
}

 /*****************************************************************************/
/** Updates all morph targets.
  *
  * This function updates all morph targets of the mixer instance for a
  * given amount of time.
  *
  * @param deltaTime The elapsed time in seconds since the last update.
  *****************************************************************************/

void CalMorphTargetMixer::update(float deltaTime)
{
  if(deltaTime >= m_duration)
  {
    std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
    {
      (*iteratorCurrentWeight) = (*iteratorEndWeight);
      ++iteratorCurrentWeight;
      ++iteratorEndWeight;
    }
    m_duration = 0.0f;
  }
  else
  {
    std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
    std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
    while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
    {
      (*iteratorCurrentWeight) += ((*iteratorEndWeight)-(*iteratorCurrentWeight))*deltaTime/m_duration;
      ++iteratorCurrentWeight;
      ++iteratorEndWeight;
    }
    m_duration -= deltaTime;
  }
  std::vector<CalSubmesh *> &vectorSubmesh = m_pMesh->getVectorSubmesh();
  int morphTargetCount = m_vectorCurrentWeight.size();
  int submeshCount = vectorSubmesh.size();
  int submeshId;
  for(submeshId=0;submeshId<submeshCount;++submeshId)
  {
    int morphTargetId;
    for(morphTargetId=0;morphTargetId<morphTargetCount;++morphTargetId)
    {
      vectorSubmesh[submeshId]->setMorphTargetWeight(morphTargetId,m_vectorCurrentWeight[morphTargetId]);
    }
  }
}

 /*****************************************************************************/
/** Returns the number of morph targets this morph target mixer mixes.
  *
  * @return The number of morph targets this morph target mixer mixes.
  *****************************************************************************/

int CalMorphTargetMixer::getMorphTargetCount()
{
  return m_vectorCurrentWeight.size();
}

//****************************************************************************//
<|endoftext|>


<commit_before>/* ---------------------------------------------------------------------------
** This software is implemented as part of the course Dynamic Algorithms
** (Q4 2015) at Aarhus Univerity Denmark.
**
** TD_EAGER.cpp
** Implementation of a truly dynamic algorithm for dynamic transitive closure
** based on Shankowsis randomized reduction of dynamic transitive closure to dynamic matrix adjoint.
**
** Author: Martin Storgaard and Konstantinos Mampentzidis
** -------------------------------------------------------------------------*/

#include "TD_EAGER.h"
using namespace std;
void TD_EAGER::init(int n) {
	//initialize the adjacency matrix where we will store all the edges that are part of the graph
	//we need it in case our randomized algorithm fails (division by zero) to be able to reconstruct
	//the
	if(adjacency_matrix != NULL) delete[] adjacency_matrix;
	this->n = n;
	adjacency_matrix = new uint32_t[n*n];
	memset(adjacency_matrix, 0, n*n*sizeof(uint32_t));
	//initialize the inverse matrix to be I-A, A is zero at first at the moment so I-A = I.
	inverse_matrix = new uint32_t[n*n];
	memset(inverse_matrix, 0, n*n*sizeof(uint32_t));
	for(int i=0;i<n;i++) {
        inverse_matrix[i*n + i] = 1;
        adjacency_matrix[i*n + i] = 1;
    }
	//initialize the counter to be 0 since no edges are part of the transitive closure within a graph with 0
	//edges.
	count = 0;
}

void TD_EAGER::updateInverseMatrix(int i, int j, uint32_t u)
{
	uint32_t v = 1;
	int k,m;
	//find (A^(-1)*u) => pick i-th column of A^(-1) and multiply every value by u
	uint32_t *a = new uint32_t[n];
	for(k=0;k<n;k++)
		a[k] = mod_mul(inverse_matrix[k*n+i],u);

	//find (v^T*A^(-1)) => pick j-th row of A^(-1) and multiply every value by v
	uint32_t *b = new uint32_t[n];
	for(k=0;k<n;k++)
		b[k] = mod_mul(inverse_matrix[j*n+k],v);

	//find v^T*A^(-1)*u
	uint32_t c = 0;
	for(k=0;k<n;k++)
		c = mod_add(c, mod_mul(a[k],b[k]));

	//find the denominator of sherman morisson formula
	uint32_t d = mod_add(c,1);

	if(d == 0){
		std::cout<<"Division by zero!!!!!!!!"<<std::endl;
		exit(1);
	}

	//find the nominator of sherman morisson formula and divide with the denominator at the same time.
	uint32_t *e = new uint32_t[n*n];
	for(k=0;k<n;k++)
		for(m=0;m<n;m++)
			e[k*n+m] = mod_mul(mod_inv(d),mod_mul(a[k],b[m]));

	//update the inverse matrix and counter
	count = 0;
	for(k=0;k<n;k++){
		for(m=0;m<n;m++){
			int index = k*n+m;
			inverse_matrix[index] = mod_sub(inverse_matrix[index], e[index]);
			if(inverse_matrix[index]!=0) count++;
		}
	}

	delete[] a;
	delete[] b;
	delete[] e;

}

void TD_EAGER::ins(int i, int j) {
	uint32_t v = next();
	adjacency_matrix[i*n + j] = v;
	updateInverseMatrix(i,j, v);
	/*cout << "INSERT" << endl;
	printMatrix(adjacency_matrix, n);
	printMatrix(inverse_matrix, n);
	cout << endl << endl;*/
}

void TD_EAGER::del(int i, int j) {
	updateInverseMatrix(i, j, (uint32_t) (P - adjacency_matrix[i*n + j]));
	adjacency_matrix[i*n + j] = 0;
    cout << "DELETE" << endl;
    printMatrix(adjacency_matrix, n);
    printMatrix(inverse_matrix, n);
    cout << endl << endl;
}

unsigned int TD_EAGER::query() {
	return count;
}
<commit_msg>attempt to fix delete function<commit_after>/* ---------------------------------------------------------------------------
** This software is implemented as part of the course Dynamic Algorithms
** (Q4 2015) at Aarhus Univerity Denmark.
**
** TD_EAGER.cpp
** Implementation of a truly dynamic algorithm for dynamic transitive closure
** based on Shankowsis randomized reduction of dynamic transitive closure to dynamic matrix adjoint.
**
** Author: Martin Storgaard and Konstantinos Mampentzidis
** -------------------------------------------------------------------------*/

#include "TD_EAGER.h"
using namespace std;
void TD_EAGER::init(int n) {
	//initialize the adjacency matrix where we will store all the edges that are part of the graph
	//we need it in case our randomized algorithm fails (division by zero) to be able to reconstruct
	//the
	if(adjacency_matrix != NULL) delete[] adjacency_matrix;
	this->n = n;
	adjacency_matrix = new uint32_t[n*n];
	memset(adjacency_matrix, 0, n*n*sizeof(uint32_t));
	//initialize the inverse matrix to be I-A, A is zero at first at the moment so I-A = I.
	inverse_matrix = new uint32_t[n*n];
	memset(inverse_matrix, 0, n*n*sizeof(uint32_t));
	for(int i=0;i<n;i++) {
        inverse_matrix[i*n + i] = 1;
        adjacency_matrix[i*n + i] = 1;
    }
	//initialize the counter to be 0 since no edges are part of the transitive closure within a graph with 0
	//edges.
	count = 0;
}

void TD_EAGER::updateInverseMatrix(int i, int j, uint32_t u)
{
	uint32_t v = 1;
	int k,m;
	//find (A^(-1)*u) => pick i-th column of A^(-1) and multiply every value by u
	uint32_t *a = new uint32_t[n];
	for(k=0;k<n;k++)
		a[k] = mod_mul(inverse_matrix[k*n+i],u);

	//find (v^T*A^(-1)) => pick j-th row of A^(-1) and multiply every value by v
	uint32_t *b = new uint32_t[n];
	for(k=0;k<n;k++)
		b[k] = mod_mul(inverse_matrix[j*n+k],v);

	//find v^T*A^(-1)*u
	uint32_t c = 0;
	for(k=0;k<n;k++)
		c = mod_add(c, mod_mul(a[k],b[k]));

	//find the denominator of sherman morisson formula
	uint32_t d = mod_add(c,1);

	if(d == 0){
		std::cout<<"Division by zero!!!!!!!!"<<std::endl;
		exit(1);
	}

	//find the nominator of sherman morisson formula and divide with the denominator at the same time.
	uint32_t *e = new uint32_t[n*n];
	for(k=0;k<n;k++)
		for(m=0;m<n;m++)
			e[k*n+m] = mod_mul(mod_inv(d),mod_mul(a[k],b[m]));

	//update the inverse matrix and counter
	count = 0;
	for(k=0;k<n;k++){
		for(m=0;m<n;m++){
			int index = k*n+m;
			inverse_matrix[index] = mod_sub(inverse_matrix[index], e[index]);
			if(inverse_matrix[index]!=0) count++;
		}
	}

	delete[] a;
	delete[] b;
	delete[] e;

}

void TD_EAGER::ins(int i, int j) {
	uint32_t u = next();
	adjacency_matrix[i*n + j] = u;

	//update the inverse matrix

	uint32_t v = 1;
	int k,m;
	//find (A^(-1)*u) => pick i-th column of A^(-1) and multiply every value by u
	uint32_t *a = new uint32_t[n];
	for(k=0;k<n;k++)
		a[k] = mod_mul(inverse_matrix[k*n+i],u);

	//find (v^T*A^(-1)) => pick j-th row of A^(-1) and multiply every value by v
	uint32_t *b = new uint32_t[n];
	for(k=0;k<n;k++)
		b[k] = mod_mul(inverse_matrix[j*n+k],v);

	//find v^T*A^(-1)*u
	uint32_t c = 0;
	for(k=0;k<n;k++)
		c = mod_add(c, mod_mul(a[k],b[k]));

	//find the denominator of sherman morisson formula
	uint32_t d = mod_add(c,1);

	if(d == 0){
		std::cout<<"Division by zero!!!!!!!!"<<std::endl;
		exit(1);
	}

	//find the nominator of sherman morisson formula and divide with the denominator at the same time.
	uint32_t *e = new uint32_t[n*n];
	for(k=0;k<n;k++)
		for(m=0;m<n;m++)
			e[k*n+m] = mod_mul(mod_inv(d),mod_mul(a[k],b[m]));

	//update the inverse matrix and counter
	count = 0;
	for(k=0;k<n;k++){
		for(m=0;m<n;m++){
			int index = k*n+m;
			inverse_matrix[index] = mod_sub(inverse_matrix[index], e[index]);
			if(inverse_matrix[index]!=0) count++;
		}
	}

	delete[] a;
	delete[] b;
	delete[] e;
	/*cout << "INSERT" << endl;
	printMatrix(adjacency_matrix, n);
	printMatrix(inverse_matrix, n);
	cout << endl << endl;*/
}

void TD_EAGER::del(int i, int j) {
	//update inverse matrix

	uint32_t u = adjacency_matrix[i*n + j];
	adjacency_matrix[i*n + j] = 0;

	//update the inverse matrix

	uint32_t v = 1;
	int k,m;
	//find (A^(-1)*u) => pick i-th column of A^(-1) and multiply every value by u
	uint32_t *a = new uint32_t[n];
	for(k=0;k<n;k++)
		a[k] = mod_mul(inverse_matrix[k*n+i],u);

	//find (v^T*A^(-1)) => pick j-th row of A^(-1) and multiply every value by v
	uint32_t *b = new uint32_t[n];
	for(k=0;k<n;k++)
		b[k] = mod_mul(inverse_matrix[j*n+k],v);

	//find v^T*A^(-1)*u
	uint32_t c = 0;
	for(k=0;k<n;k++)
		c = mod_add(c, mod_mul(a[k],b[k]));

	//find the denominator of sherman morisson formula
	uint32_t d = mod_sub(1,c);

	if(d == 0){
		std::cout<<"Division by zero!!!!!!!!"<<std::endl;
		exit(1);
	}

	//find the nominator of sherman morisson formula and divide with the denominator at the same time.
	uint32_t *e = new uint32_t[n*n];
	for(k=0;k<n;k++)
		for(m=0;m<n;m++)
			e[k*n+m] = mod_mul(mod_inv(d),mod_mul(a[k],b[m]));

	//update the inverse matrix and counter
	count = 0;
	for(k=0;k<n;k++){
		for(m=0;m<n;m++){
			int index = k*n+m;
			inverse_matrix[index] = mod_add(inverse_matrix[index], e[index]);
			if(inverse_matrix[index]!=0) count++;
		}
	}

	delete[] a;
	delete[] b;
	delete[] e;
    /*cout << "DELETE" << endl;
    printMatrix(adjacency_matrix, n);
    printMatrix(inverse_matrix, n);
    cout << endl << endl;*/
}

unsigned int TD_EAGER::query() {
	return count;
}
<|endoftext|>


<commit_before>#include "Expression.hpp"
#include "gtest/gtest.h"

TEST(LMCh04Ex05, DISABLED_willAddNumbers)
{
    auto expression = lm::Expression("1.0 + 2.0");
    ASSERT_DOUBLE_EQ(3.0, expression.getResult());
}

TEST(LMCh04Ex05, DISABLED_willSubtractNumbers)
{
    auto expression = lm::Expression("3.1 - 5.3");
    ASSERT_DOUBLE_EQ(-2.2, expression.getResult());
}

TEST(LMCh04Ex05, DISABLED_willMultiplyNumbers)
{
    auto expression = lm::Expression("20.1 * -0.128");
    ASSERT_DOUBLE_EQ(-2.5728, expression.getResult());
}

TEST(LMCh04Ex05, DISABLED_willDivideNumbers)
{
    auto expression = lm::Expression("128.0 / 64.0");
    ASSERT_DOUBLE_EQ(2.0, expression.getResult());
}

TEST(LMCh04Ex05, willThrowExceptionOnUnknownOp)
{
    std::cout << "start test" << std::endl;
    auto expression = lm::Expression("12.0 ^ 14.1");
    std::cout << "before throw" << std::endl;
    ASSERT_THROW(expression.getResult(), std::runtime_error);
    std::cout << "after throw" << std::endl;
}
<commit_msg>travis test<commit_after>#include "Expression.hpp"
#include "gtest/gtest.h"

TEST(LMCh04Ex05, DISABLED_willAddNumbers)
{
    auto expression = lm::Expression("1.0 + 2.0");
    ASSERT_DOUBLE_EQ(3.0, expression.getResult());
}

TEST(LMCh04Ex05, DISABLED_willSubtractNumbers)
{
    auto expression = lm::Expression("3.1 - 5.3");
    ASSERT_DOUBLE_EQ(-2.2, expression.getResult());
}

TEST(LMCh04Ex05, DISABLED_willMultiplyNumbers)
{
    auto expression = lm::Expression("20.1 * -0.128");
    ASSERT_DOUBLE_EQ(-2.5728, expression.getResult());
}

TEST(LMCh04Ex05, DISABLED_willDivideNumbers)
{
    auto expression = lm::Expression("128.0 / 64.0");
    ASSERT_DOUBLE_EQ(2.0, expression.getResult());
}

TEST(LMCh04Ex05, willThrowExceptionOnUnknownOp)
{
    std::cout << "start test" << std::endl;
    std::string input{"12.0 ^ 14.1"};
    auto expression = lm::Expression(input);
    std::cout << "before throw" << std::endl;
    ASSERT_THROW(expression.getResult(), std::runtime_error);
    std::cout << "after throw" << std::endl;
}
<|endoftext|>


<commit_before>#include "Triangle.h"

void Triangle::Move(uint16_t dirX, uint16_t dirY)
{
	{
		lastX = X;
		lastY = Y;

		X += dirX;
		X += dirY;

		HasMoved = true;
	}
}

void Triangle::Update()
{

}

void Triangle::Render(Adafruit_ST7735 *tftDisplay, boolean clear)
{
	/* In this method we only draw the rectangle if it has moved.
	 * We also only clear where the last triangle was instead of the whole frame,
	 * this is is because it is slow to write to the display, so we have to keep it to the minimum.
	 */

	if (!HasMoved) return;
	/* Clear old triangle */
	if (clear) Clear(tftDisplay);
	/* Draw new triangle */
	DrawTriangle(tftDisplay);
	/* Set back the HasMoved flag because it has now been drawn.*/
	lastX = X;
	lastY = Y;
	PrevDirection = Direction;
	HasMoved = false;
}

void Triangle::Clear(Adafruit_ST7735 *tftDisplay)
{
	// I'm using rectangle to fill so that I don't have to calculate diagonal lines.
	tftDisplay->fillRect(lastX -1, lastY -1, Width + 4, Height + 4, ClearColor);
}

void Triangle::DrawTriangle(Adafruit_ST7735 *tftDisplay)
{
	switch (Direction)
	{
	case GLB_LEFT:
		tftDisplay->fillTriangle(X, Y, X, Y + Height, X + Width, Y + Height / 2 , Color);
		break;
	case GLB_RIGHT:
		tftDisplay->fillTriangle(X, Y + Height / 2, X + Width, Y + Height, X + Width, Y, Color);
		break;
	case GLB_UP:
		tftDisplay->fillTriangle(X, Y, X + Width / 2, Y + Height, X + Width, Y, Color);
		break;
	case GLB_DOWN:
		tftDisplay->fillTriangle(X, Y + Height, X + Width / 2, Y, X + Width, Y + Height, Color);
		break;
	default:
		break;
	}

}
<commit_msg>fixed wrong draw direction on triangle<commit_after>#include "Triangle.h"

void Triangle::Move(uint16_t dirX, uint16_t dirY)
{
	{
		lastX = X;
		lastY = Y;

		X += dirX;
		X += dirY;

		HasMoved = true;
	}
}

void Triangle::Update()
{

}

void Triangle::Render(Adafruit_ST7735 *tftDisplay, boolean clear)
{
	/* In this method we only draw the rectangle if it has moved.
	 * We also only clear where the last triangle was instead of the whole frame,
	 * this is is because it is slow to write to the display, so we have to keep it to the minimum.
	 */

	if (!HasMoved) return;
	/* Clear old triangle */
	if (clear) Clear(tftDisplay);
	/* Draw new triangle */
	DrawTriangle(tftDisplay);
	/* Set back the HasMoved flag because it has now been drawn.*/
	lastX = X;
	lastY = Y;
	PrevDirection = Direction;
	HasMoved = false;
}

void Triangle::Clear(Adafruit_ST7735 *tftDisplay)
{
	// I'm using rectangle to fill so that I don't have to calculate diagonal lines.
	tftDisplay->fillRect(lastX -1, lastY -1, Width + 4, Height + 4, ClearColor);
}

void Triangle::DrawTriangle(Adafruit_ST7735 *tftDisplay)
{
	switch (Direction)
	{
	case GLB_LEFT:
		tftDisplay->fillTriangle(X, Y, X, Y + Height, X + Width, Y + Height / 2 , Color);
		break;
	case GLB_RIGHT:
		tftDisplay->fillTriangle(X, Y + Height / 2, X + Width, Y + Height, X + Width, Y, Color);
		break;
	case GLB_DOWN:
		tftDisplay->fillTriangle(X, Y, X + Width / 2, Y + Height, X + Width, Y, Color);
		break;
	case GLB_UP:
		tftDisplay->fillTriangle(X, Y + Height, X + Width / 2, Y, X + Width, Y + Height, Color);
		break;
	default:
		break;
	}

}
<|endoftext|>


<commit_before>// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * 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.
//     * Neither the name of Google Inc. 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.

// macho_walker.cc: Iterate over the load commands in a mach-o file
//
// See macho_walker.h for documentation
//
// Author: Dan Waylonis

#include <assert.h>
#include <fcntl.h>
#include <mach-o/arch.h>
#include <mach-o/loader.h>
#include <mach-o/swap.h>
#include <string.h>
#include <unistd.h>

#include "common/mac/macho_walker.h"
#include "common/mac/macho_utilities.h"

namespace MacFileUtilities {

MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback,
                         void *context)
    : callback_(callback),
      callback_context_(context) {
  file_ = open(path, O_RDONLY);
}

MachoWalker::~MachoWalker() {
  if (file_ != -1)
    close(file_);
}

int MachoWalker::ValidateCPUType(int cpu_type) {
  // If the user didn't specify, try to use the local architecture.  If that
  // fails, use the base type for the executable.
  if (cpu_type == 0) {
    const NXArchInfo *arch = NXGetLocalArchInfo();
    if (arch)
      cpu_type = arch->cputype;
    else
#if __ppc__
      cpu_type = CPU_TYPE_POWERPC;
#elif __i386__
    cpu_type = CPU_TYPE_X86;
#else
#error Unknown architecture -- are you on a PDP-11?
#endif
  }

  return cpu_type;
}

bool MachoWalker::WalkHeader(int cpu_type) {
  int valid_cpu_type = ValidateCPUType(cpu_type);
  off_t offset;
  if (FindHeader(valid_cpu_type, offset)) {
    if (cpu_type & CPU_ARCH_ABI64)
      return WalkHeader64AtOffset(offset);

    return WalkHeaderAtOffset(offset);
  }

  return false;
}

bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) {
  return pread(file_, buffer, size, offset) == (ssize_t)size;
}

bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) {
  if (current_header_) {
    memcpy(header, current_header_, sizeof(mach_header_64));
    *offset = current_header_offset_;
    return true;
  }

  return false;
}

bool MachoWalker::FindHeader(int cpu_type, off_t &offset) {
  int valid_cpu_type = ValidateCPUType(cpu_type);
  // Read the magic bytes that's common amongst all mach-o files
  uint32_t magic;
  if (!ReadBytes(&magic, sizeof(magic), 0))
    return false;

  offset = sizeof(magic);

  // Figure out what type of file we've got
  bool is_fat = false;
  if (magic == FAT_MAGIC || magic == FAT_CIGAM) {
    is_fat = true;
  }
  else if (magic != MH_MAGIC && magic != MH_CIGAM && magic != MH_MAGIC_64 &&
           magic != MH_CIGAM_64) {
    return false;
  }

  if (!is_fat) {
    // If we don't have a fat header, check if the cpu type matches the single
    // header
    cpu_type_t header_cpu_type;
    if (!ReadBytes(&header_cpu_type, sizeof(header_cpu_type), offset))
      return false;

    if (magic == MH_CIGAM || magic == MH_CIGAM_64)
      header_cpu_type = NXSwapInt(header_cpu_type);

    if (valid_cpu_type != header_cpu_type)
      return false;

    offset = 0;
    return true;
  } else {
    // Read the fat header and find an appropriate architecture
    offset = 0;
    struct fat_header fat;
    if (!ReadBytes(&fat, sizeof(fat), offset))
      return false;

    if (NXHostByteOrder() != NX_BigEndian)
      swap_fat_header(&fat, NXHostByteOrder());

    offset += sizeof(fat);

    // Search each architecture for the desired one
    struct fat_arch arch;
    for (uint32_t i = 0; i < fat.nfat_arch; ++i) {
      if (!ReadBytes(&arch, sizeof(arch), offset))
        return false;

      if (NXHostByteOrder() != NX_BigEndian)
        swap_fat_arch(&arch, 1, NXHostByteOrder());

      if (arch.cputype == valid_cpu_type) {
        offset = arch.offset;
        return true;
      }

      offset += sizeof(arch);
    }
  }

  return false;
}

bool MachoWalker::WalkHeaderAtOffset(off_t offset) {
  struct mach_header header;
  if (!ReadBytes(&header, sizeof(header), offset))
    return false;

  bool swap = (header.magic == MH_CIGAM);
  if (swap)
    swap_mach_header(&header, NXHostByteOrder());

  // Copy the data into the mach_header_64 structure.  Since the 32-bit and
  // 64-bit only differ in the last field (reserved), this is safe to do.
  struct mach_header_64 header64;
  memcpy((void *)&header64, (const void *)&header, sizeof(header));
  header64.reserved = 0;

  current_header_ = &header64;
  current_header_size_ = sizeof(header); // 32-bit, not 64-bit
  current_header_offset_ = offset;
  offset += current_header_size_;
  bool result = WalkHeaderCore(offset, header.ncmds, swap);
  current_header_ = NULL;
  current_header_size_ = 0;
  current_header_offset_ = 0;
  return result;
}

bool MachoWalker::WalkHeader64AtOffset(off_t offset) {
  struct mach_header_64 header;
  if (!ReadBytes(&header, sizeof(header), offset))
    return false;

  bool swap = (header.magic == MH_CIGAM_64);
  if (swap)
    breakpad_swap_mach_header_64(&header, NXHostByteOrder());

  current_header_ = &header;
  current_header_size_ = sizeof(header);
  current_header_offset_ = offset;
  offset += current_header_size_;
  bool result = WalkHeaderCore(offset, header.ncmds, swap);
  current_header_ = NULL;
  current_header_size_ = 0;
  current_header_offset_ = 0;
  return result;
}

bool MachoWalker::WalkHeaderCore(off_t offset, uint32_t number_of_commands,
                                 bool swap) {
  for (uint32_t i = 0; i < number_of_commands; ++i) {
    struct load_command cmd;
    if (!ReadBytes(&cmd, sizeof(cmd), offset))
      return false;

    if (swap)
      swap_load_command(&cmd, NXHostByteOrder());

    // Call the user callback
    if (callback_ && !callback_(this, &cmd, offset, swap, callback_context_))
      break;

    offset += cmd.cmdsize;
  }

  return true;
}

}  // namespace MacFileUtilities
<commit_msg>Issue 197: reviewed by Waylonis<commit_after>// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * 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.
//     * Neither the name of Google Inc. 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.

// macho_walker.cc: Iterate over the load commands in a mach-o file
//
// See macho_walker.h for documentation
//
// Author: Dan Waylonis

extern "C" {  // necessary for Leopard
  #include <assert.h>
  #include <fcntl.h>
  #include <mach-o/arch.h>
  #include <mach-o/loader.h>
  #include <mach-o/swap.h>
  #include <string.h>
  #include <unistd.h>
}

#include "common/mac/macho_walker.h"
#include "common/mac/macho_utilities.h"

namespace MacFileUtilities {

MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback,
                         void *context)
    : callback_(callback),
      callback_context_(context) {
  file_ = open(path, O_RDONLY);
}

MachoWalker::~MachoWalker() {
  if (file_ != -1)
    close(file_);
}

int MachoWalker::ValidateCPUType(int cpu_type) {
  // If the user didn't specify, try to use the local architecture.  If that
  // fails, use the base type for the executable.
  if (cpu_type == 0) {
    const NXArchInfo *arch = NXGetLocalArchInfo();
    if (arch)
      cpu_type = arch->cputype;
    else
#if __ppc__
      cpu_type = CPU_TYPE_POWERPC;
#elif __i386__
    cpu_type = CPU_TYPE_X86;
#else
#error Unknown architecture -- are you on a PDP-11?
#endif
  }

  return cpu_type;
}

bool MachoWalker::WalkHeader(int cpu_type) {
  int valid_cpu_type = ValidateCPUType(cpu_type);
  off_t offset;
  if (FindHeader(valid_cpu_type, offset)) {
    if (cpu_type & CPU_ARCH_ABI64)
      return WalkHeader64AtOffset(offset);

    return WalkHeaderAtOffset(offset);
  }

  return false;
}

bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) {
  return pread(file_, buffer, size, offset) == (ssize_t)size;
}

bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) {
  if (current_header_) {
    memcpy(header, current_header_, sizeof(mach_header_64));
    *offset = current_header_offset_;
    return true;
  }

  return false;
}

bool MachoWalker::FindHeader(int cpu_type, off_t &offset) {
  int valid_cpu_type = ValidateCPUType(cpu_type);
  // Read the magic bytes that's common amongst all mach-o files
  uint32_t magic;
  if (!ReadBytes(&magic, sizeof(magic), 0))
    return false;

  offset = sizeof(magic);

  // Figure out what type of file we've got
  bool is_fat = false;
  if (magic == FAT_MAGIC || magic == FAT_CIGAM) {
    is_fat = true;
  }
  else if (magic != MH_MAGIC && magic != MH_CIGAM && magic != MH_MAGIC_64 &&
           magic != MH_CIGAM_64) {
    return false;
  }

  if (!is_fat) {
    // If we don't have a fat header, check if the cpu type matches the single
    // header
    cpu_type_t header_cpu_type;
    if (!ReadBytes(&header_cpu_type, sizeof(header_cpu_type), offset))
      return false;

    if (magic == MH_CIGAM || magic == MH_CIGAM_64)
      header_cpu_type = NXSwapInt(header_cpu_type);

    if (valid_cpu_type != header_cpu_type)
      return false;

    offset = 0;
    return true;
  } else {
    // Read the fat header and find an appropriate architecture
    offset = 0;
    struct fat_header fat;
    if (!ReadBytes(&fat, sizeof(fat), offset))
      return false;

    if (NXHostByteOrder() != NX_BigEndian)
      swap_fat_header(&fat, NXHostByteOrder());

    offset += sizeof(fat);

    // Search each architecture for the desired one
    struct fat_arch arch;
    for (uint32_t i = 0; i < fat.nfat_arch; ++i) {
      if (!ReadBytes(&arch, sizeof(arch), offset))
        return false;

      if (NXHostByteOrder() != NX_BigEndian)
        swap_fat_arch(&arch, 1, NXHostByteOrder());

      if (arch.cputype == valid_cpu_type) {
        offset = arch.offset;
        return true;
      }

      offset += sizeof(arch);
    }
  }

  return false;
}

bool MachoWalker::WalkHeaderAtOffset(off_t offset) {
  struct mach_header header;
  if (!ReadBytes(&header, sizeof(header), offset))
    return false;

  bool swap = (header.magic == MH_CIGAM);
  if (swap)
    swap_mach_header(&header, NXHostByteOrder());

  // Copy the data into the mach_header_64 structure.  Since the 32-bit and
  // 64-bit only differ in the last field (reserved), this is safe to do.
  struct mach_header_64 header64;
  memcpy((void *)&header64, (const void *)&header, sizeof(header));
  header64.reserved = 0;

  current_header_ = &header64;
  current_header_size_ = sizeof(header); // 32-bit, not 64-bit
  current_header_offset_ = offset;
  offset += current_header_size_;
  bool result = WalkHeaderCore(offset, header.ncmds, swap);
  current_header_ = NULL;
  current_header_size_ = 0;
  current_header_offset_ = 0;
  return result;
}

bool MachoWalker::WalkHeader64AtOffset(off_t offset) {
  struct mach_header_64 header;
  if (!ReadBytes(&header, sizeof(header), offset))
    return false;

  bool swap = (header.magic == MH_CIGAM_64);
  if (swap)
    breakpad_swap_mach_header_64(&header, NXHostByteOrder());

  current_header_ = &header;
  current_header_size_ = sizeof(header);
  current_header_offset_ = offset;
  offset += current_header_size_;
  bool result = WalkHeaderCore(offset, header.ncmds, swap);
  current_header_ = NULL;
  current_header_size_ = 0;
  current_header_offset_ = 0;
  return result;
}

bool MachoWalker::WalkHeaderCore(off_t offset, uint32_t number_of_commands,
                                 bool swap) {
  for (uint32_t i = 0; i < number_of_commands; ++i) {
    struct load_command cmd;
    if (!ReadBytes(&cmd, sizeof(cmd), offset))
      return false;

    if (swap)
      swap_load_command(&cmd, NXHostByteOrder());

    // Call the user callback
    if (callback_ && !callback_(this, &cmd, offset, swap, callback_context_))
      break;

    offset += cmd.cmdsize;
  }

  return true;
}

}  // namespace MacFileUtilities
<|endoftext|>