<commit_before>// Copyright 2010-2013 Google
// 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 <string>
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/hash.h"
#include "base/map_util.h"
#include "flatzinc2/model.h"
#include "flatzinc2/sat_constraint.h"
#include "flatzinc2/solver.h"
#include "constraint_solver/constraint_solver.h"
#include "util/string_array.h"

DECLARE_bool(logging);
DECLARE_bool(verbose_logging);
DEFINE_bool(use_sat, true, "Use a sat solver for propagating on booleans.");

namespace operations_research {
IntExpr* FzSolver::GetExpression(const FzArgument& arg) {
  switch (arg.type) {
    case FzArgument::INT_VALUE: {
      return solver_.MakeIntConst(arg.Value());
    }
    case FzArgument::INT_VAR_REF: {
      return Extract(arg.variables[0]);
    }
    default: {
      LOG(FATAL) << "Cannot extract " << arg.DebugString() << " as a variable";
      return nullptr;
    }
  }
}

std::vector<IntVar*> FzSolver::GetVariableArray(const FzArgument& arg) {
  std::vector<IntVar*> result;
  if (arg.type == FzArgument::INT_VAR_REF_ARRAY) {
    result.resize(arg.variables.size());
    for (int i = 0; i < arg.variables.size(); ++i) {
      result[i] = Extract(arg.variables[i])->Var();
    }
  } else {
    LOG(FATAL) << "Cannot extract " << arg.DebugString()
               << " as a variable array";
  }
  return result;
}

IntExpr* FzSolver::Extract(FzIntegerVariable* var) {
  IntExpr* result = FindPtrOrNull(extrated_map_, var);
  if (result != nullptr) {
    return result;
  }
  if (var->domain.values.size() == 1) {
    result = solver_.MakeIntConst(var->domain.values.back());
  } else if (var->domain.is_interval) {
    result = solver_.MakeIntVar(var->domain.values[0], var->domain.values[1],
                                var->name);
  } else {
    result = solver_.MakeIntVar(var->domain.values, var->name);
  }
  FZVLOG << "Extract " << var->DebugString() << " into "
         << result->DebugString() << FZENDL;
  extrated_map_[var] = result;
  return nullptr;
}

void FzSolver::SetExtracted(FzIntegerVariable* var, IntExpr* expr) {
  CHECK(!ContainsKey(extrated_map_, var));
  extrated_map_[var] = expr;
}

// The format is fixed in the flatzinc specification.
std::string FzSolver::SolutionString(const FzOnSolutionOutput& output) {
  if (output.variable != nullptr) {
    return StringPrintf("%s = %" GG_LL_FORMAT "d;", output.name.c_str(),
                        Extract(output.variable)->Var()->Value());
  } else {
    const int bound_size = output.bounds.size();
    std::string result =
        StringPrintf("%s = array%dd(", output.name.c_str(), bound_size);
    for (int i = 0; i < bound_size; ++i) {
      result.append(StringPrintf("%" GG_LL_FORMAT "d..%" GG_LL_FORMAT "d, ",
                                 output.bounds[i].min_value,
                                 output.bounds[i].max_value));
    }
    result.append("[");
    for (int i = 0; i < output.flat_variables.size(); ++i) {
      result.append(
          StringPrintf("%" GG_LL_FORMAT "d",
                       Extract(output.flat_variables[i])->Var()->Value()));
      if (i != output.flat_variables.size() - 1) {
        result.append(", ");
      }
    }
    result.append("]);");
    return result;
  }
  return "";
}

namespace {
struct ConstraintWithIo {
  FzConstraint* ct;
  int index;
  hash_set<FzIntegerVariable*> required;

  ConstraintWithIo(FzConstraint* cte, int i,
                   const hash_set<FzIntegerVariable*>& defined)
      : ct(cte), index(i) {
    // Collect required variables.
    for (const FzArgument& arg : ct->arguments) {
      for (FzIntegerVariable* const var : arg.variables) {
        if (ContainsKey(defined, var)) {
          required.insert(var);
        }
      }
    }
    // Remove the target_variable as it always appears in the constraint.
    if (ct->target_variable != nullptr) {
      required.erase(ct->target_variable);
    }
  }
};

// Comparator to sort constraints based on numbers of required
// elements and index. Reverse sorting to put elements to remove at the end.
struct ConstraintWithIoComparator {
  bool operator()(ConstraintWithIo* a, ConstraintWithIo* b) const {
    return a->required.size() > b->required.size() ||
           (a->required.size() == b->required.size() && a->index > b->index);
  }
};
}  // namespace

bool FzSolver::Extract() {
  // Create the sat solver.
  if (FLAGS_use_sat) {
    FZLOG << "  - Use sat" << FZENDL;
    sat_ = MakeSatPropagator(&solver_);
    solver_.AddConstraint(reinterpret_cast<Constraint*>(sat_));
  } else {
    sat_ = nullptr;
  }
  // Build statistics.
  statistics_.BuildStatistics();
  // Extract variables.
  hash_set<FzIntegerVariable*> defined_variables;
  for (FzIntegerVariable* const var : model_.variables()) {
    if (var->defining_constraint == nullptr && var->active) {
      Extract(var);
    } else {
      defined_variables.insert(var);
    }
  }
  // Parse model to store info.
  for (FzConstraint* const ct : model_.constraints()) {
    if (ct->type == "all_different_int") {
      StoreAllDifferent(ct->Arg(0).variables);
    }
  }
  // Sort constraints such that defined variables are created before the
  // extraction of the constraints that use them.
  int index = 0;
  std::vector<ConstraintWithIo*> to_sort;
  std::vector<FzConstraint*> sorted;
  hash_map<const FzIntegerVariable*, std::vector<ConstraintWithIo*>> dependencies;
  for (FzConstraint* ct : model_.constraints()) {
    if (ct != nullptr && ct->active) {
      ConstraintWithIo* const ctio =
          new ConstraintWithIo(ct, index++, defined_variables);
      to_sort.push_back(ctio);
      for (FzIntegerVariable* const var : ctio->required) {
        dependencies[var].push_back(ctio);
      }
    }
  }
  // Sort a first time.
  std::sort(to_sort.begin(), to_sort.end(), ConstraintWithIoComparator());
  // Topological sort.
  while (!to_sort.empty()) {
    if (!to_sort.back()->required.empty()) {
      // Sort again.
      std::sort(to_sort.begin(), to_sort.end(), ConstraintWithIoComparator());
    }
    ConstraintWithIo* const ctio = to_sort.back();
    to_sort.pop_back();
    CHECK(ctio->required.empty());
    // TODO(user): Implement recovery mode.
    sorted.push_back(ctio->ct);
    FzIntegerVariable* const var = ctio->ct->target_variable;
    if (var != nullptr && ContainsKey(dependencies, var)) {
      for (ConstraintWithIo* const to_clean : dependencies[var]) {
        to_clean->required.erase(var);
      }
    }
    delete ctio;
  }
  for (FzConstraint* const ct : sorted) {
    ExtractConstraint(ct);
  }
  // Add domain constraints to created extressions.
  for (FzIntegerVariable* const var : model_.variables()) {
    if (var->defining_constraint != nullptr && var->active) {
      const FzDomain& domain = var->domain;
      IntExpr* const expr = Extract(var);
      if (expr->IsVar() && domain.is_interval && !domain.values.empty()) {
        FZVLOG << "Reduce variable domain of " << expr->DebugString()
               << " from " << domain.DebugString() << FZENDL;
        expr->Var()->SetRange(domain.values[0], domain.values[1]);
      } else if (expr->IsVar() && !domain.is_interval) {
        FZVLOG << "Reduce variable domain of " << expr->DebugString()
               << " from " << domain.DebugString() << FZENDL;
        expr->Var()->SetValues(domain.values);
      } else if (domain.is_interval && !domain.values.empty() &&
                 (expr->Min() < domain.values[0] ||
                  expr->Max() > domain.values[1])) {
        FZVLOG << "Add domain constraint " << domain.DebugString() << " onto "
               << expr->DebugString() << FZENDL;
        solver_.AddConstraint(solver_.MakeBetweenCt(
            expr->Var(), domain.values[0], domain.values[1]));
      } else if (!domain.is_interval) {
        FZVLOG << "Add domain constraint " << domain.DebugString() << " onto "
               << expr->DebugString() << FZENDL;
        solver_.AddConstraint(solver_.MakeMemberCt(expr->Var(), domain.values));
      }
    }
  }

  return true;
}

// ----- Alldiff info support -----

void FzSolver::StoreAllDifferent(const std::vector<FzIntegerVariable*>& diffs) {
  std::vector<FzIntegerVariable*> local(diffs);
  std::sort(local.begin(), local.end());
  FZVLOG << "Store AllDifferent info for [" << JoinDebugStringPtr(diffs, ", ")
         << "]" << FZENDL;
  alldiffs_[local.front()].push_back(local);
}

namespace {
template <class T>
bool EqualVector(const std::vector<T>& v1, const std::vector<T>& v2) {
  if (v1.size() != v2.size()) return false;
  for (int i = 0; i < v1.size(); ++i) {
    if (v1[i] != v2[i]) return false;
  }
  return true;
}
}  // namespace

bool FzSolver::IsAllDifferent(const std::vector<FzIntegerVariable*>& diffs) const {
  std::vector<FzIntegerVariable*> local(diffs);
  std::sort(local.begin(), local.end());
  const FzIntegerVariable* const start = local.front();
  if (!ContainsKey(alldiffs_, start)) return false;
  const std::vector<std::vector<FzIntegerVariable*>>& stored =
      FindOrDie(alldiffs_, start);
  for (const std::vector<FzIntegerVariable*>& one_diff : stored) {
    if (EqualVector(local, one_diff)) {
      return true;
    }
  }
  return false;
}
}  // namespace operations_research
<commit_msg>remove spurrious constraints<commit_after>// Copyright 2010-2013 Google
// 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 <string>
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/hash.h"
#include "base/map_util.h"
#include "flatzinc2/model.h"
#include "flatzinc2/sat_constraint.h"
#include "flatzinc2/solver.h"
#include "constraint_solver/constraint_solver.h"
#include "util/string_array.h"

DECLARE_bool(logging);
DECLARE_bool(verbose_logging);
DEFINE_bool(use_sat, true, "Use a sat solver for propagating on booleans.");

namespace operations_research {
IntExpr* FzSolver::GetExpression(const FzArgument& arg) {
  switch (arg.type) {
    case FzArgument::INT_VALUE: { return solver_.MakeIntConst(arg.Value()); }
    case FzArgument::INT_VAR_REF: { return Extract(arg.variables[0]); }
    default: {
      LOG(FATAL) << "Cannot extract " << arg.DebugString() << " as a variable";
      return nullptr;
    }
  }
}

std::vector<IntVar*> FzSolver::GetVariableArray(const FzArgument& arg) {
  std::vector<IntVar*> result;
  if (arg.type == FzArgument::INT_VAR_REF_ARRAY) {
    result.resize(arg.variables.size());
    for (int i = 0; i < arg.variables.size(); ++i) {
      result[i] = Extract(arg.variables[i])->Var();
    }
  } else {
    LOG(FATAL) << "Cannot extract " << arg.DebugString()
               << " as a variable array";
  }
  return result;
}

IntExpr* FzSolver::Extract(FzIntegerVariable* var) {
  IntExpr* result = FindPtrOrNull(extrated_map_, var);
  if (result != nullptr) {
    return result;
  }
  if (var->domain.values.size() == 1) {
    result = solver_.MakeIntConst(var->domain.values.back());
  } else if (var->domain.is_interval) {
    result = solver_.MakeIntVar(var->domain.values[0], var->domain.values[1],
                                var->name);
  } else {
    result = solver_.MakeIntVar(var->domain.values, var->name);
  }
  FZVLOG << "Extract " << var->DebugString() << " into "
         << result->DebugString() << FZENDL;
  extrated_map_[var] = result;
  return nullptr;
}

void FzSolver::SetExtracted(FzIntegerVariable* var, IntExpr* expr) {
  CHECK(!ContainsKey(extrated_map_, var));
  extrated_map_[var] = expr;
}

// The format is fixed in the flatzinc specification.
std::string FzSolver::SolutionString(const FzOnSolutionOutput& output) {
  if (output.variable != nullptr) {
    return StringPrintf("%s = %" GG_LL_FORMAT "d;", output.name.c_str(),
                        Extract(output.variable)->Var()->Value());
  } else {
    const int bound_size = output.bounds.size();
    std::string result =
        StringPrintf("%s = array%dd(", output.name.c_str(), bound_size);
    for (int i = 0; i < bound_size; ++i) {
      result.append(
          StringPrintf("%" GG_LL_FORMAT "d..%" GG_LL_FORMAT "d, ",
                       output.bounds[i].min_value, output.bounds[i].max_value));
    }
    result.append("[");
    for (int i = 0; i < output.flat_variables.size(); ++i) {
      result.append(
          StringPrintf("%" GG_LL_FORMAT "d",
                       Extract(output.flat_variables[i])->Var()->Value()));
      if (i != output.flat_variables.size() - 1) {
        result.append(", ");
      }
    }
    result.append("]);");
    return result;
  }
  return "";
}

namespace {
struct ConstraintWithIo {
  FzConstraint* ct;
  int index;
  hash_set<FzIntegerVariable*> required;

  ConstraintWithIo(FzConstraint* cte, int i,
                   const hash_set<FzIntegerVariable*>& defined)
      : ct(cte), index(i) {
    // Collect required variables.
    for (const FzArgument& arg : ct->arguments) {
      for (FzIntegerVariable* const var : arg.variables) {
        if (ContainsKey(defined, var)) {
          required.insert(var);
        }
      }
    }
    // Remove the target_variable as it always appears in the constraint.
    if (ct->target_variable != nullptr) {
      required.erase(ct->target_variable);
    }
  }
};

// Comparator to sort constraints based on numbers of required
// elements and index. Reverse sorting to put elements to remove at the end.
struct ConstraintWithIoComparator {
  bool operator()(ConstraintWithIo* a, ConstraintWithIo* b) const {
    return a->required.size() > b->required.size() ||
           (a->required.size() == b->required.size() && a->index > b->index);
  }
};
}  // namespace

bool FzSolver::Extract() {
  // Create the sat solver.
  if (FLAGS_use_sat) {
    FZLOG << "  - Use sat" << FZENDL;
    sat_ = MakeSatPropagator(&solver_);
    solver_.AddConstraint(reinterpret_cast<Constraint*>(sat_));
  } else {
    sat_ = nullptr;
  }
  // Build statistics.
  statistics_.BuildStatistics();
  // Extract variables.
  hash_set<FzIntegerVariable*> defined_variables;
  for (FzIntegerVariable* const var : model_.variables()) {
    if (var->defining_constraint == nullptr && var->active) {
      Extract(var);
    } else {
      defined_variables.insert(var);
    }
  }
  // Parse model to store info.
  for (FzConstraint* const ct : model_.constraints()) {
    if (ct->type == "all_different_int") {
      StoreAllDifferent(ct->Arg(0).variables);
    }
  }
  // Sort constraints such that defined variables are created before the
  // extraction of the constraints that use them.
  int index = 0;
  std::vector<ConstraintWithIo*> to_sort;
  std::vector<FzConstraint*> sorted;
  hash_map<const FzIntegerVariable*, std::vector<ConstraintWithIo*>>
      dependencies;
  for (FzConstraint* ct : model_.constraints()) {
    if (ct != nullptr && ct->active) {
      ConstraintWithIo* const ctio =
          new ConstraintWithIo(ct, index++, defined_variables);
      to_sort.push_back(ctio);
      for (FzIntegerVariable* const var : ctio->required) {
        dependencies[var].push_back(ctio);
      }
    }
  }
  // Sort a first time.
  std::sort(to_sort.begin(), to_sort.end(), ConstraintWithIoComparator());
  // Topological sort.
  while (!to_sort.empty()) {
    if (!to_sort.back()->required.empty()) {
      // Sort again.
      std::sort(to_sort.begin(), to_sort.end(), ConstraintWithIoComparator());
    }
    ConstraintWithIo* const ctio = to_sort.back();
    to_sort.pop_back();
    CHECK(ctio->required.empty());
    // TODO(user): Implement recovery mode.
    sorted.push_back(ctio->ct);
    FzIntegerVariable* const var = ctio->ct->target_variable;
    if (var != nullptr && ContainsKey(dependencies, var)) {
      for (ConstraintWithIo* const to_clean : dependencies[var]) {
        to_clean->required.erase(var);
      }
    }
    delete ctio;
  }
  for (FzConstraint* const ct : sorted) {
    ExtractConstraint(ct);
  }
  // Add domain constraints to created extressions.
  for (FzIntegerVariable* const var : model_.variables()) {
    if (var->defining_constraint != nullptr && var->active) {
      const FzDomain& domain = var->domain;
      IntExpr* const expr = Extract(var);
      if (expr->IsVar() && domain.is_interval && !domain.values.empty() &&
          (expr->Min() < domain.values[0] || expr->Max() > domain.values[1])) {
        FZVLOG << "Reduce variable domain of " << expr->DebugString()
               << " from " << domain.DebugString() << FZENDL;
        expr->Var()->SetRange(domain.values[0], domain.values[1]);
      } else if (expr->IsVar() && !domain.is_interval) {
        FZVLOG << "Reduce variable domain of " << expr->DebugString()
               << " from " << domain.DebugString() << FZENDL;
        expr->Var()->SetValues(domain.values);
      } else if (domain.is_interval && !domain.values.empty() &&
                 (expr->Min() < domain.values[0] ||
                  expr->Max() > domain.values[1])) {
        FZVLOG << "Add domain constraint " << domain.DebugString() << " onto "
               << expr->DebugString() << FZENDL;
        solver_.AddConstraint(solver_.MakeBetweenCt(
            expr->Var(), domain.values[0], domain.values[1]));
      } else if (!domain.is_interval) {
        FZVLOG << "Add domain constraint " << domain.DebugString() << " onto "
               << expr->DebugString() << FZENDL;
        solver_.AddConstraint(solver_.MakeMemberCt(expr->Var(), domain.values));
      }
    }
  }

  return true;
}

// ----- Alldiff info support -----

void FzSolver::StoreAllDifferent(const std::vector<FzIntegerVariable*>& diffs) {
  std::vector<FzIntegerVariable*> local(diffs);
  std::sort(local.begin(), local.end());
  FZVLOG << "Store AllDifferent info for [" << JoinDebugStringPtr(diffs, ", ")
         << "]" << FZENDL;
  alldiffs_[local.front()].push_back(local);
}

namespace {
template <class T>
bool EqualVector(const std::vector<T>& v1, const std::vector<T>& v2) {
  if (v1.size() != v2.size()) return false;
  for (int i = 0; i < v1.size(); ++i) {
    if (v1[i] != v2[i]) return false;
  }
  return true;
}
}  // namespace

bool FzSolver::IsAllDifferent(
    const std::vector<FzIntegerVariable*>& diffs) const {
  std::vector<FzIntegerVariable*> local(diffs);
  std::sort(local.begin(), local.end());
  const FzIntegerVariable* const start = local.front();
  if (!ContainsKey(alldiffs_, start)) return false;
  const std::vector<std::vector<FzIntegerVariable*>>& stored =
      FindOrDie(alldiffs_, start);
  for (const std::vector<FzIntegerVariable*>& one_diff : stored) {
    if (EqualVector(local, one_diff)) {
      return true;
    }
  }
  return false;
}
}  // namespace operations_research
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* librevenge
 * Version: MPL 2.0 / LGPLv2.1+
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Major Contributor(s):
 * Copyright (C) 2012 Fridrich Strba (fridrich.strba@bluewin.ch)
 *
 * For minor contributions see the git repository.
 *
 * Alternatively, the contents of this file may be used under the terms
 * of the GNU Lesser General Public License Version 2.1 or later
 * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
 * applicable instead of those above.
 */

#include <string>
#include <string.h>
#include <stdio.h>
#include <zlib.h>
#include "RVNGZipStream.h"
#include <librevenge-stream/librevenge-stream.h>

namespace librevenge
{

namespace
{
class StreamException
{
};

struct LocalFileHeader
{
	unsigned short min_version;
	unsigned short general_flag;
	unsigned short compression;
	unsigned short lastmod_time;
	unsigned short lastmod_date;
	unsigned crc32;
	unsigned compressed_size;
	unsigned uncompressed_size;
	unsigned short filename_size;
	unsigned short extra_field_size;
	std::string filename;
	std::string extra_field;
	LocalFileHeader()
		: min_version(0), general_flag(0), compression(0), lastmod_time(0), lastmod_date(0),
		  crc32(0), compressed_size(0), uncompressed_size(0), filename_size(0), extra_field_size(0),
		  filename(), extra_field() {}
	~LocalFileHeader() {}
};

struct CentralDirectoryEntry
{
	unsigned short creator_version;
	unsigned short min_version;
	unsigned short general_flag;
	unsigned short compression;
	unsigned short lastmod_time;
	unsigned short lastmod_date;
	unsigned crc32;
	unsigned compressed_size;
	unsigned uncompressed_size;
	unsigned short filename_size;
	unsigned short extra_field_size;
	unsigned short file_comment_size;
	unsigned short disk_num;
	unsigned short internal_attr;
	unsigned external_attr;
	unsigned offset;
	std::string filename;
	std::string extra_field;
	std::string file_comment;
	CentralDirectoryEntry()
		: creator_version(0), min_version(0), general_flag(0), compression(0), lastmod_time(0),
		  lastmod_date(0), crc32(0), compressed_size(0), uncompressed_size(0), filename_size(0),
		  extra_field_size(0), file_comment_size(0), disk_num(0), internal_attr(0),
		  external_attr(0), offset(0), filename(), extra_field(), file_comment() {}
	~CentralDirectoryEntry() {}
};

struct CentralDirectoryEnd
{
	unsigned short disk_num;
	unsigned short cdir_disk;
	unsigned short disk_entries;
	unsigned short cdir_entries;
	unsigned cdir_size;
	unsigned cdir_offset;
	unsigned short comment_size;
	std::string comment;
	CentralDirectoryEnd()
		: disk_num(0), cdir_disk(0), disk_entries(0), cdir_entries(0),
		  cdir_size(0), cdir_offset(0), comment_size(0), comment() {}
	~CentralDirectoryEnd() {}
};

#define CDIR_ENTRY_SIG 0x02014b50
#define LOC_FILE_HEADER_SIG 0x04034b50
#define CDIR_END_SIG 0x06054b50

static unsigned char getByte(RVNGInputStream *input)
{
	unsigned long numBytesRead = 0;
	const unsigned char *ret = input->read(1, numBytesRead);
	if (numBytesRead != 1)
		throw StreamException();
	return ret[0];
}

static unsigned short getShort(RVNGInputStream *input)
{
	unsigned long numBytesRead = 0;
	const unsigned char *ret = input->read(2, numBytesRead);
	if (numBytesRead != 2)
		throw StreamException();
	return (unsigned short)(ret[0]|((unsigned short)ret[1]<<8));
}

static unsigned getInt(RVNGInputStream *input)
{
	unsigned long numBytesRead = 0;
	const unsigned char *ret = input->read(4, numBytesRead);
	if (numBytesRead != 4)
		throw StreamException();
	return (unsigned)(ret[0]|((unsigned)ret[1]<<8)|((unsigned)ret[2]<<16)|((unsigned)ret[3]<<24));
}

static bool readCentralDirectoryEnd(RVNGInputStream *input, CentralDirectoryEnd &end)
{
	try
	{
		unsigned signature = getInt(input);
		if (signature != CDIR_END_SIG)
			return false;

		end.disk_num = getShort(input);
		end.cdir_disk = getShort(input);
		end.disk_entries = getShort(input);
		end.cdir_entries = getShort(input);
		end.cdir_size = getInt(input);
		end.cdir_offset = getInt(input);
		end.comment_size = getShort(input);
		end.comment.clear();
		for (unsigned short i = 0; i < end.comment_size; i++)
			end.comment.append(1, (char)getByte(input));
	}
	catch (...)
	{
		return false;
	}
	return true;
}

static bool readCentralDirectoryEntry(RVNGInputStream *input, CentralDirectoryEntry &entry)
{
	try
	{
		unsigned signature = getInt(input);
		if (signature != CDIR_ENTRY_SIG)
			return false;

		entry.creator_version = getShort(input);
		entry.min_version = getShort(input);
		entry.general_flag = getShort(input);
		entry.compression = getShort(input);
		entry.lastmod_time = getShort(input);
		entry.lastmod_date = getShort(input);
		entry.crc32 = getInt(input);
		entry.compressed_size = getInt(input);
		entry.uncompressed_size = getInt(input);
		entry.filename_size = getShort(input);
		entry.extra_field_size = getShort(input);
		entry.file_comment_size = getShort(input);
		entry.disk_num = getShort(input);
		entry.internal_attr = getShort(input);
		entry.external_attr = getInt(input);
		entry.offset = getInt(input);
		unsigned short i = 0;
		entry.filename.clear();
		for (i=0; i < entry.filename_size; i++)
			entry.filename.append(1, (char)getByte(input));
		entry.extra_field.clear();
		for (i=0; i < entry.extra_field_size; i++)
			entry.extra_field.append(1, (char)getByte(input));
		entry.file_comment.clear();
		for (i=0; i < entry.file_comment_size; i++)
			entry.file_comment.append(1, (char)getByte(input));
	}
	catch (...)
	{
		return false;
	}
	return true;
}

static bool readLocalFileHeader(RVNGInputStream *input, LocalFileHeader &header)
{
	try
	{
		unsigned signature = getInt(input);
		if (signature != LOC_FILE_HEADER_SIG)
			return false;

		header.min_version = getShort(input);
		header.general_flag = getShort(input);
		header.compression = getShort(input);
		header.lastmod_time = getShort(input);
		header.lastmod_date = getShort(input);
		header.crc32 = getInt(input);
		header.compressed_size = getInt(input);
		header.uncompressed_size = getInt(input);
		header.filename_size = getShort(input);
		header.extra_field_size = getShort(input);
		unsigned short i = 0;
		header.filename.clear();
		for (i=0; i < header.filename_size; i++)
			header.filename.append(1, (char)getByte(input));
		header.extra_field.clear();
		for (i=0; i < header.extra_field_size; i++)
			header.extra_field.append(1, (char)getByte(input));
	}
	catch (...)
	{
		return false;
	}
	return true;
}

static bool areHeadersConsistent(const LocalFileHeader &header, const CentralDirectoryEntry &entry)
{
	if (header.min_version != entry.min_version)
		return false;
	if (header.general_flag != entry.general_flag)
		return false;
	if (header.compression != entry.compression)
		return false;
	if (!(header.general_flag & 0x08))
	{
		if (header.crc32 != entry.crc32)
			return false;
		if (header.compressed_size != entry.compressed_size)
			return false;
		if (header.uncompressed_size != entry.uncompressed_size)
			return false;
	}
	return true;
}

static bool findCentralDirectoryEnd(RVNGInputStream *input)
{
	if (input->seek(-1024, RVNG_SEEK_END))
		input->seek(0, RVNG_SEEK_SET);

	try
	{
		while (!input->isEnd())
		{
			unsigned signature = getInt(input);
			if (signature == CDIR_END_SIG)
			{
				input->seek(-4, RVNG_SEEK_CUR);
				return true;
			}
			else
				input->seek(-3, RVNG_SEEK_CUR);
		}
	}
	catch (...)
	{
		return false;
	}
	return false;
}

static bool findDataStream(RVNGInputStream *input, CentralDirectoryEntry &entry, const char *name)
{
	size_t name_size = strlen(name);
	if (!findCentralDirectoryEnd(input))
		return false;
	CentralDirectoryEnd end;
	if (!readCentralDirectoryEnd(input, end))
		return false;
	input->seek(end.cdir_offset, RVNG_SEEK_SET);
	while (!input->isEnd() && (unsigned)input->tell() < end.cdir_offset + end.cdir_size)
	{
		if (!readCentralDirectoryEntry(input, entry))
			return false;
		if (name_size == entry.filename_size && entry.filename == name)
			break;
	}
	if (name_size != entry.filename_size)
		return false;
	if (entry.filename != name)
		return false;
	input->seek(entry.offset, RVNG_SEEK_SET);
	LocalFileHeader header;
	if (!readLocalFileHeader(input, header))
		return false;
	if (!areHeadersConsistent(header, entry))
		return false;
	return true;
}

static std::vector<std::string> getSubStreamNamesInZip(RVNGInputStream *input, bool all=false)
{
	std::vector<std::string> res;
	if (!input || !findCentralDirectoryEnd(input))
		return res;
	CentralDirectoryEnd end;
	if (!readCentralDirectoryEnd(input, end))
		return res;
	input->seek(long(end.cdir_offset), RVNG_SEEK_SET);
	while (!input->isEnd() && (unsigned)input->tell() < end.cdir_offset + end.cdir_size)
	{
		CentralDirectoryEntry entry;
		if (!readCentralDirectoryEntry(input, entry))
			break;
		if (!entry.filename_size || (!all && entry.filename[entry.filename.size()-1]=='/')) continue;
		res.push_back(entry.filename);
	}
	return res;
}
} // anonymous namespace

bool RVNGZipStream::isZipFile(RVNGInputStream *input)
{
	// look for central directory end
	if (!findCentralDirectoryEnd(input))
		return false;
	CentralDirectoryEnd end;
	if (!readCentralDirectoryEnd(input, end))
		return false;
	input->seek(end.cdir_offset, RVNG_SEEK_SET);
	// read first entry in the central directory
	CentralDirectoryEntry entry;
	if (!readCentralDirectoryEntry(input, entry))
		return false;
	input->seek(entry.offset, RVNG_SEEK_SET);
	// read the local file header and compare with the central directory information
	LocalFileHeader header;
	if (!readLocalFileHeader(input, header))
		return false;
	if (!areHeadersConsistent(header, entry))
		return false;
	return true;
}

std::vector<std::string> RVNGZipStream::getSubStreamNamesList(RVNGInputStream *input)
{
	return getSubStreamNamesInZip(input,false);
}

RVNGInputStream *RVNGZipStream::getSubstream(RVNGInputStream *input, const char *name)
{
	CentralDirectoryEntry entry;
	if (!findDataStream(input, entry, name))
		return 0;
	if (!entry.compressed_size)
		return 0;
	unsigned long numBytesRead = 0;
	unsigned char *compressedData = const_cast<unsigned char *>(input->read(entry.compressed_size, numBytesRead));
	if (numBytesRead != entry.compressed_size)
		return 0;
	if (!entry.compression)
		return new RVNGStringStream(compressedData, (unsigned)numBytesRead);
	else
	{
		int ret;
		z_stream strm;

		/* allocate inflate state */
		strm.zalloc = Z_NULL;
		strm.zfree = Z_NULL;
		strm.opaque = Z_NULL;
		strm.avail_in = 0;
		strm.next_in = Z_NULL;
		ret = inflateInit2(&strm,-MAX_WBITS);
		if (ret != Z_OK)
			return 0;

		strm.avail_in = (unsigned)numBytesRead;
		strm.next_in = (Bytef *)compressedData;

		std::vector<unsigned char>data(entry.uncompressed_size);

		strm.avail_out = entry.uncompressed_size;
		strm.next_out = reinterpret_cast<Bytef *>(&data[0]);
		ret = inflate(&strm, Z_FINISH);
		switch (ret)
		{
		case Z_NEED_DICT:
		case Z_DATA_ERROR:
		case Z_MEM_ERROR:
			(void)inflateEnd(&strm);
			data.clear();
			return 0;
		default:
			break;
		}
		(void)inflateEnd(&strm);
		return new RVNGStringStream(&data[0], (unsigned)data.size());
	}
}

}

/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */
<commit_msg>RVNGZipStream: try to optimize a little findCentralDirectoryEnd...<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* librevenge
 * Version: MPL 2.0 / LGPLv2.1+
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Major Contributor(s):
 * Copyright (C) 2012 Fridrich Strba (fridrich.strba@bluewin.ch)
 *
 * For minor contributions see the git repository.
 *
 * Alternatively, the contents of this file may be used under the terms
 * of the GNU Lesser General Public License Version 2.1 or later
 * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
 * applicable instead of those above.
 */

#include <string>
#include <string.h>
#include <stdio.h>
#include <zlib.h>
#include "RVNGZipStream.h"
#include <librevenge-stream/librevenge-stream.h>

namespace librevenge
{

namespace
{
class StreamException
{
};

struct LocalFileHeader
{
	unsigned short min_version;
	unsigned short general_flag;
	unsigned short compression;
	unsigned short lastmod_time;
	unsigned short lastmod_date;
	unsigned crc32;
	unsigned compressed_size;
	unsigned uncompressed_size;
	unsigned short filename_size;
	unsigned short extra_field_size;
	std::string filename;
	std::string extra_field;
	LocalFileHeader()
		: min_version(0), general_flag(0), compression(0), lastmod_time(0), lastmod_date(0),
		  crc32(0), compressed_size(0), uncompressed_size(0), filename_size(0), extra_field_size(0),
		  filename(), extra_field() {}
	~LocalFileHeader() {}
};

struct CentralDirectoryEntry
{
	unsigned short creator_version;
	unsigned short min_version;
	unsigned short general_flag;
	unsigned short compression;
	unsigned short lastmod_time;
	unsigned short lastmod_date;
	unsigned crc32;
	unsigned compressed_size;
	unsigned uncompressed_size;
	unsigned short filename_size;
	unsigned short extra_field_size;
	unsigned short file_comment_size;
	unsigned short disk_num;
	unsigned short internal_attr;
	unsigned external_attr;
	unsigned offset;
	std::string filename;
	std::string extra_field;
	std::string file_comment;
	CentralDirectoryEntry()
		: creator_version(0), min_version(0), general_flag(0), compression(0), lastmod_time(0),
		  lastmod_date(0), crc32(0), compressed_size(0), uncompressed_size(0), filename_size(0),
		  extra_field_size(0), file_comment_size(0), disk_num(0), internal_attr(0),
		  external_attr(0), offset(0), filename(), extra_field(), file_comment() {}
	~CentralDirectoryEntry() {}
};

struct CentralDirectoryEnd
{
	unsigned short disk_num;
	unsigned short cdir_disk;
	unsigned short disk_entries;
	unsigned short cdir_entries;
	unsigned cdir_size;
	unsigned cdir_offset;
	unsigned short comment_size;
	std::string comment;
	CentralDirectoryEnd()
		: disk_num(0), cdir_disk(0), disk_entries(0), cdir_entries(0),
		  cdir_size(0), cdir_offset(0), comment_size(0), comment() {}
	~CentralDirectoryEnd() {}
};

#define CDIR_ENTRY_SIG 0x02014b50
#define LOC_FILE_HEADER_SIG 0x04034b50
#define CDIR_END_SIG 0x06054b50

static unsigned char getByte(RVNGInputStream *input)
{
	unsigned long numBytesRead = 0;
	const unsigned char *ret = input->read(1, numBytesRead);
	if (numBytesRead != 1)
		throw StreamException();
	return ret[0];
}

static unsigned short getShort(RVNGInputStream *input)
{
	unsigned long numBytesRead = 0;
	const unsigned char *ret = input->read(2, numBytesRead);
	if (numBytesRead != 2)
		throw StreamException();
	return (unsigned short)(ret[0]|((unsigned short)ret[1]<<8));
}

static unsigned getInt(RVNGInputStream *input)
{
	unsigned long numBytesRead = 0;
	const unsigned char *ret = input->read(4, numBytesRead);
	if (numBytesRead != 4)
		throw StreamException();
	return (unsigned)(ret[0]|((unsigned)ret[1]<<8)|((unsigned)ret[2]<<16)|((unsigned)ret[3]<<24));
}

static bool readCentralDirectoryEnd(RVNGInputStream *input, CentralDirectoryEnd &end)
{
	try
	{
		unsigned signature = getInt(input);
		if (signature != CDIR_END_SIG)
			return false;

		end.disk_num = getShort(input);
		end.cdir_disk = getShort(input);
		end.disk_entries = getShort(input);
		end.cdir_entries = getShort(input);
		end.cdir_size = getInt(input);
		end.cdir_offset = getInt(input);
		end.comment_size = getShort(input);
		end.comment.clear();
		for (unsigned short i = 0; i < end.comment_size; i++)
			end.comment.append(1, (char)getByte(input));
	}
	catch (...)
	{
		return false;
	}
	return true;
}

static bool readCentralDirectoryEntry(RVNGInputStream *input, CentralDirectoryEntry &entry)
{
	try
	{
		unsigned signature = getInt(input);
		if (signature != CDIR_ENTRY_SIG)
			return false;

		entry.creator_version = getShort(input);
		entry.min_version = getShort(input);
		entry.general_flag = getShort(input);
		entry.compression = getShort(input);
		entry.lastmod_time = getShort(input);
		entry.lastmod_date = getShort(input);
		entry.crc32 = getInt(input);
		entry.compressed_size = getInt(input);
		entry.uncompressed_size = getInt(input);
		entry.filename_size = getShort(input);
		entry.extra_field_size = getShort(input);
		entry.file_comment_size = getShort(input);
		entry.disk_num = getShort(input);
		entry.internal_attr = getShort(input);
		entry.external_attr = getInt(input);
		entry.offset = getInt(input);
		unsigned short i = 0;
		entry.filename.clear();
		for (i=0; i < entry.filename_size; i++)
			entry.filename.append(1, (char)getByte(input));
		entry.extra_field.clear();
		for (i=0; i < entry.extra_field_size; i++)
			entry.extra_field.append(1, (char)getByte(input));
		entry.file_comment.clear();
		for (i=0; i < entry.file_comment_size; i++)
			entry.file_comment.append(1, (char)getByte(input));
	}
	catch (...)
	{
		return false;
	}
	return true;
}

static bool readLocalFileHeader(RVNGInputStream *input, LocalFileHeader &header)
{
	try
	{
		unsigned signature = getInt(input);
		if (signature != LOC_FILE_HEADER_SIG)
			return false;

		header.min_version = getShort(input);
		header.general_flag = getShort(input);
		header.compression = getShort(input);
		header.lastmod_time = getShort(input);
		header.lastmod_date = getShort(input);
		header.crc32 = getInt(input);
		header.compressed_size = getInt(input);
		header.uncompressed_size = getInt(input);
		header.filename_size = getShort(input);
		header.extra_field_size = getShort(input);
		unsigned short i = 0;
		header.filename.clear();
		for (i=0; i < header.filename_size; i++)
			header.filename.append(1, (char)getByte(input));
		header.extra_field.clear();
		for (i=0; i < header.extra_field_size; i++)
			header.extra_field.append(1, (char)getByte(input));
	}
	catch (...)
	{
		return false;
	}
	return true;
}

static bool areHeadersConsistent(const LocalFileHeader &header, const CentralDirectoryEntry &entry)
{
	if (header.min_version != entry.min_version)
		return false;
	if (header.general_flag != entry.general_flag)
		return false;
	if (header.compression != entry.compression)
		return false;
	if (!(header.general_flag & 0x08))
	{
		if (header.crc32 != entry.crc32)
			return false;
		if (header.compressed_size != entry.compressed_size)
			return false;
		if (header.uncompressed_size != entry.uncompressed_size)
			return false;
	}
	return true;
}

static bool findCentralDirectoryEnd(RVNGInputStream *input)
{
	if (input->seek(-1024, RVNG_SEEK_END))
		input->seek(0, RVNG_SEEK_SET);

	try
	{
		input->seek(0, RVNG_SEEK_END);
		long size = input->tell();

		// CentralDirectoryEnd is CDIR_END_SIG:4+at least 18 other bytes
		if (size < 22) return false;
		if (input->seek(size>1024 ? size-1024 : 0, RVNG_SEEK_SET))
			return false;
		long pos=input->tell();
		long toCheck=(size-18)-pos;
		unsigned long numBytesRead = 0;
		unsigned char const *ret =
		    input->read((unsigned long) toCheck, numBytesRead);
		if (!ret || long(numBytesRead)!=toCheck)
			return false;
		unsigned const sigRev=
		    ((CDIR_END_SIG&0xFF)<<24)|
		    ((CDIR_END_SIG&0xFF00)<<8)|
		    ((CDIR_END_SIG&0xFF0000)>>8)|
		    ((CDIR_END_SIG&0xFF000000)>>24);
		unsigned signature=0;
		for (long p=0; p < toCheck; p++)
		{
			signature=((signature&0xFFFFFF)<<8)|*(ret++);
			if (signature == sigRev)
			{
				input->seek(pos+p-3, RVNG_SEEK_SET);
				return true;
			}
		}

	}
	catch (...)
	{
		return false;
	}
	return false;
}

static bool findDataStream(RVNGInputStream *input, CentralDirectoryEntry &entry, const char *name)
{
	size_t name_size = strlen(name);
	if (!findCentralDirectoryEnd(input))
		return false;
	CentralDirectoryEnd end;
	if (!readCentralDirectoryEnd(input, end))
		return false;
	input->seek(end.cdir_offset, RVNG_SEEK_SET);
	while (!input->isEnd() && (unsigned)input->tell() < end.cdir_offset + end.cdir_size)
	{
		if (!readCentralDirectoryEntry(input, entry))
			return false;
		if (name_size == entry.filename_size && entry.filename == name)
			break;
	}
	if (name_size != entry.filename_size)
		return false;
	if (entry.filename != name)
		return false;
	input->seek(entry.offset, RVNG_SEEK_SET);
	LocalFileHeader header;
	if (!readLocalFileHeader(input, header))
		return false;
	if (!areHeadersConsistent(header, entry))
		return false;
	return true;
}

static std::vector<std::string> getSubStreamNamesInZip(RVNGInputStream *input, bool all=false)
{
	std::vector<std::string> res;
	if (!input || !findCentralDirectoryEnd(input))
		return res;
	CentralDirectoryEnd end;
	if (!readCentralDirectoryEnd(input, end))
		return res;
	input->seek(long(end.cdir_offset), RVNG_SEEK_SET);
	while (!input->isEnd() && (unsigned)input->tell() < end.cdir_offset + end.cdir_size)
	{
		CentralDirectoryEntry entry;
		if (!readCentralDirectoryEntry(input, entry))
			break;
		if (!entry.filename_size || (!all && entry.filename[entry.filename.size()-1]=='/')) continue;
		res.push_back(entry.filename);
	}
	return res;
}
} // anonymous namespace

bool RVNGZipStream::isZipFile(RVNGInputStream *input)
{
	// look for central directory end
	if (!findCentralDirectoryEnd(input))
		return false;
	CentralDirectoryEnd end;
	if (!readCentralDirectoryEnd(input, end))
		return false;
	input->seek(end.cdir_offset, RVNG_SEEK_SET);
	// read first entry in the central directory
	CentralDirectoryEntry entry;
	if (!readCentralDirectoryEntry(input, entry))
		return false;
	input->seek(entry.offset, RVNG_SEEK_SET);
	// read the local file header and compare with the central directory information
	LocalFileHeader header;
	if (!readLocalFileHeader(input, header))
		return false;
	if (!areHeadersConsistent(header, entry))
		return false;
	return true;
}

std::vector<std::string> RVNGZipStream::getSubStreamNamesList(RVNGInputStream *input)
{
	return getSubStreamNamesInZip(input,false);
}

RVNGInputStream *RVNGZipStream::getSubstream(RVNGInputStream *input, const char *name)
{
	CentralDirectoryEntry entry;
	if (!findDataStream(input, entry, name))
		return 0;
	if (!entry.compressed_size)
		return 0;
	unsigned long numBytesRead = 0;
	unsigned char *compressedData = const_cast<unsigned char *>(input->read(entry.compressed_size, numBytesRead));
	if (numBytesRead != entry.compressed_size)
		return 0;
	if (!entry.compression)
		return new RVNGStringStream(compressedData, (unsigned)numBytesRead);
	else
	{
		int ret;
		z_stream strm;

		/* allocate inflate state */
		strm.zalloc = Z_NULL;
		strm.zfree = Z_NULL;
		strm.opaque = Z_NULL;
		strm.avail_in = 0;
		strm.next_in = Z_NULL;
		ret = inflateInit2(&strm,-MAX_WBITS);
		if (ret != Z_OK)
			return 0;

		strm.avail_in = (unsigned)numBytesRead;
		strm.next_in = (Bytef *)compressedData;

		std::vector<unsigned char>data(entry.uncompressed_size);

		strm.avail_out = entry.uncompressed_size;
		strm.next_out = reinterpret_cast<Bytef *>(&data[0]);
		ret = inflate(&strm, Z_FINISH);
		switch (ret)
		{
		case Z_NEED_DICT:
		case Z_DATA_ERROR:
		case Z_MEM_ERROR:
			(void)inflateEnd(&strm);
			data.clear();
			return 0;
		default:
			break;
		}
		(void)inflateEnd(&strm);
		return new RVNGStringStream(&data[0], (unsigned)data.size());
	}
}

}

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


<commit_before>/*
 * Copyright (c) 2015-2019 Dubalu LLC
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#pragma once

#include <chrono>            // for std::chrono
#include <cmath>             // for std::pow, std::floor, std::log10
#include <errno.h>           // for errno
#include <time.h>            // for nanosleep

inline void nanosleep(unsigned long long nsec) {
	if (nsec > 0) {
		struct timespec ts;
		ts.tv_sec = static_cast<long>(nsec / 1000000000);
		ts.tv_nsec = static_cast<long>(nsec % 1000000000);
		while (nanosleep(&ts, &ts) < 0 && errno == EINTR) { }
	}
}

struct Clk {
unsigned long long mul;

Clk() {
	auto a = std::chrono::steady_clock::now();
	nanosleep(5000000);  // sleep for 5 milliseconds
	auto b = std::chrono::steady_clock::now();
	auto delta = *reinterpret_cast<unsigned long long*>(&b) - *reinterpret_cast<unsigned long long*>(&a);
	mul = 1000000 / static_cast<unsigned long long>(std::pow(10, std::floor(std::log10(delta))));
}

template <typename T>
unsigned long long time_point_to_ullong(std::chrono::time_point<T> t) const {
	return *reinterpret_cast<unsigned long long*>(&t) * mul;
}

template <typename T = std::chrono::steady_clock>
std::chrono::time_point<T> time_point_from_ullong(unsigned long long t) const {
	t /= mul;
	return *reinterpret_cast<std::chrono::time_point<T>*>(&t);
}

static const Clk& clk() {
	static const Clk clk;
	return clk;
}
};

template <typename T>
inline unsigned long long
time_point_to_ullong(std::chrono::time_point<T> t) {
	return Clk::clk().time_point_to_ullong<T>(t);
}

template <typename T = std::chrono::steady_clock>
inline std::chrono::time_point<T>
time_point_from_ullong(unsigned long long t) {
	return Clk::clk().time_point_from_ullong<T>(t);
}
<commit_msg>Time Point: Formatting<commit_after>/*
 * Copyright (c) 2015-2019 Dubalu LLC
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#pragma once

#include <chrono>            // for std::chrono
#include <cmath>             // for std::pow, std::floor, std::log10
#include <errno.h>           // for errno
#include <time.h>            // for nanosleep

inline void nanosleep(unsigned long long nsec) {
	if (nsec > 0) {
		struct timespec ts;
		ts.tv_sec = static_cast<long>(nsec / 1000000000);
		ts.tv_nsec = static_cast<long>(nsec % 1000000000);
		while (nanosleep(&ts, &ts) < 0 && errno == EINTR) { }
	}
}

struct Clk {
	unsigned long long mul;

	Clk() {
		auto a = std::chrono::steady_clock::now();
		nanosleep(5000000);  // sleep for 5 milliseconds
		auto b = std::chrono::steady_clock::now();
		auto delta = *reinterpret_cast<unsigned long long*>(&b) - *reinterpret_cast<unsigned long long*>(&a);
		mul = 1000000 / static_cast<unsigned long long>(std::pow(10, std::floor(std::log10(delta))));
	}

	template <typename T>
	unsigned long long
	time_point_to_ullong(std::chrono::time_point<T> t) const {
		return *reinterpret_cast<unsigned long long*>(&t) * mul;
	}

	template <typename T = std::chrono::steady_clock>
	std::chrono::time_point<T>
	time_point_from_ullong(unsigned long long t) const {
		t /= mul;
		return *reinterpret_cast<std::chrono::time_point<T>*>(&t);
	}

	static const Clk& clk() {static const Clk clk;
		return clk;
	}
};

template <typename T>
inline unsigned long long
time_point_to_ullong(std::chrono::time_point<T> t) {
	return Clk::clk().time_point_to_ullong<T>(t);
}

template <typename T = std::chrono::steady_clock>
inline std::chrono::time_point<T>
time_point_from_ullong(unsigned long long t) {
	return Clk::clk().time_point_from_ullong<T>(t);
}
<|endoftext|>


<commit_before>/* ***************************************************************************

	Copyright: 2013 Hericus Software, LLC

	License: The MIT License (MIT)

	Authors: Steven M. Cherry

*************************************************************************** */

#include <AnException.h>
#include <Log.h>
#include <xmlinc.h>
#include <XmlHelpers.h>
#include <twine.h>
#include <File.h>
#include <Timer.h>
using namespace SLib;

#include <vector>

#include "HelixConfig.h"
#include "HelixFS.h"
#include "HelixBuilder.h"
#include "HelixWorker.h"
#include "HelixAutoAsset.h"
#include "HelixExtractStrings.h"
#include "HelixJSGenTask.h"
using namespace Helix::Build;

twine m_platform;
std::vector<twine> m_targets;

void handleAll();
void handleClean();
void handleGen(bool displayBanner = true);
void handleReGen(bool displayBanner = true);
void handleJSApiGen(bool displayBanner = true);
void handleJSGen(bool displayBanner = true);
void handleCS(bool displayBanner = true);
void handleInstall(bool displayBanner = true);
void handleDeploy(bool displayBanner = true);
void handleAsset(bool displayBanner = true);
void handleStrings(bool displayBanner = true);
void testDep();
void CopyCore();
void describe();

int main (int argc, char** argv)
{
	if(argc > 1){
		for(int i = 1; i < argc; i++){
			twine argv1(argv[i]);
			m_targets.push_back( argv1 );
		}
	}

	Log::SetPanic( true );
	Log::SetError( true );
	Log::SetWarn( true );
	Log::SetInfo( true );
	Log::SetDebug( false );
	Log::SetTrace( false );

	printf("============================================================================\n");
#ifdef _WIN32
#	ifdef _X86_
	m_platform = "WIN32_x86";
#	else
	m_platform = "WIN32_x64";
#	endif
#else
	m_platform = "LINUX_x64";
#endif
	printf("Helix Build Running for a %s platform.\n", m_platform());
	printf("============================================================================\n");

	Timer timer;
	try {
		// Load our config file and make sure it exists
		HelixConfig::getInstance();
		CopyCore();

		printf("Loading the helix filesystem");
		timer.Start();
		HelixFS::getInstance();
		timer.Finish(); printf(" - duration: %f seconds\n", timer.Duration() );

		if(m_targets.size() == 0){
			handleAll();
		} else {
			bool didClean = false;
			for( auto const& targ : m_targets){
				if(didClean){
					didClean = false;
					CopyCore();
				}
				if(targ == "clean") { handleClean(); didClean = true; }
				else if(targ == "all") handleAll();
				else if(targ == "gen") handleGen();
				else if(targ == "regen") handleReGen();
				else if(targ == "jsapi") handleJSApiGen();
				else if(targ == "jsgen") handleJSGen();
				else if(targ == "cs") handleCS();
				else if(targ == "install") handleInstall();
				else if(targ == "dep") handleDeploy();
				else if(targ == "testdep") testDep();
				else if(targ == "asset") handleAsset();
				else if(targ == "strings") handleStrings();
				else if(targ == "?") describe();
				else if(targ == "help") describe();
				else if(targ == "-?") describe();
			}
		}

		HelixWorker::getInstance().Finish();
		HelixFS::getInstance().SaveCache();

		/* Use this for profiling what's going on and what's taking up the time
		twine hitmap;
		EnEx::PrintGlobalHitMap( hitmap );
		printf("\n\n%s\n\n", hitmap() );
		*/

	} catch(AnException& e){
		printf("%s\n", e.Msg());
		printf("%s\n", e.Stack());
		printf("============================================================================\n");
		printf("== hbuild complete - with errors\n");
		printf("============================================================================\n");
		return 1; // Errors
	}

	if(HelixWorker::getInstance().HasError()){
		printf("============================================================================\n");
		printf("== hbuild complete - with errors\n");
		printf("============================================================================\n");
		return 1; // Errors
	} else {
		printf("============================================================================\n");
		printf("== hbuild complete.\n");
		printf("============================================================================\n");
		return 0; // No error
	}
}

void describe()
{
	printf("============================================================================\n");
	printf("== HBuild Options\n");
	printf("============================================================================\n");
	printf("== clean - cleans the build target\n");
	printf("== all - does everything except dep\n");
	printf("== gen - Generates the C++, JS, and C# from .sql.xml files as required\n");
	printf("== regen - Forces a regeneration of the C++, JS, and C# from all .sql.xml\n");
	printf("== jsapi - Generates the Api.js file in each of our QX projects\n");
	printf("== jsgen - runs generate.py for all QX projects (build and source-hybrid)\n");
	printf("== cs - recompiles the C# HelixPdfGen project if present\n");
	printf("== install - Runs the install lines from the hbuild.xml file\n");
	printf("== dep - Runs the Deploy section from the hbuild.xml file\n");
	printf("== asset - Runs the auto-asset function against all QX projects\n");
	printf("== strings - Runs the extract-strings process to build translation files\n");
	printf("\n");
	printf("== If no target is specified, the 'all' target is invoked.\n");
	printf("\n");
}

void handleAll()
{
	printf("============================================================================\n");
	printf("== All Target\n");
	printf("============================================================================\n");

	HelixBuilder builder;
	handleGen(false);

	if(!HelixConfig::getInstance().UseCore()){
		// Only build these if we're not using a core folder
		builder.Build( "logic/util" );
		builder.Build( "logic/admin" );
		builder.Build( "glob" );
		builder.Build( "server" );
		builder.Build( "client" );
	}

	// Use the config file to tell us which logics to build, and in what order
	for(auto& logic : HelixConfig::getInstance().Logics() ){
		twine repo = HelixConfig::getInstance().LogicRepo( logic );
		if(repo.empty()){
			// Normal local logic folder
			builder.Build( "logic/" + logic );
		} else {
			// Logic folder from another repo - adjust the path
			builder.Build( "../../../" + repo + "/server/c/logic/" + logic );
		}
	}

	if(!HelixConfig::getInstance().UseCore()){
		// Only build these if we're not using a core folder
		builder.Build( "HelixMain" );
		builder.Build( "HelixDaemon" );
	}

	handleAsset(false);
	handleStrings(false);
	handleJSApiGen(false);

	if(HelixWorker::getInstance().NeedsCSRebuild()){
		handleCS( false );
	}

	// Handle all of our installation tasks
	handleInstall( false );

}

void handleClean()
{
	printf("============================================================================\n");
	printf("== Clean Target\n");
	printf("============================================================================\n");

	HelixBuilder builder;
	builder.CleanSqldo();

	if(!HelixConfig::getInstance().UseCore()){
		// Only build these if we're not using a core folder
		builder.Clean( "logic/util" );
		builder.Clean( "logic/admin" );
		builder.Clean( "glob" );
		builder.Clean( "server" );
	}

	// Use the config file to tell us which logics to build, and in what order
	for(auto& logic : HelixConfig::getInstance().Logics() ){
		twine repo = HelixConfig::getInstance().LogicRepo( logic );
		if(repo.empty()){
			// Normal local logic folder
			builder.Clean( "logic/" + logic);
		} else {
			// Logic folder from another repo - adjust the path
			builder.Clean( "../../../" + repo + "/server/c/logic/" + logic );
		}
	}

	if(!HelixConfig::getInstance().UseCore()){
		// Only build these if we're not using a core folder
		builder.Clean( "client" );
		builder.Clean( "HelixDaemon" );
	}
	builder.Clean( "HelixMain" ); // Clean's out the bin folder for core and non-core projects

	builder.CleanCS();
	builder.CleanCSTest();
}

void handleGen(bool displayBanner)
{
	if(displayBanner){
		printf("============================================================================\n");
		printf("== Gen Target\n");
		printf("============================================================================\n");
	}

	HelixBuilder builder;
	builder.GenerateSqldo();
	HelixFS::getInstance().Load(); // Re-load the file system because GenerateSqldo creates files
}

void handleReGen(bool displayBanner)
{
	if(displayBanner){
		printf("============================================================================\n");
		printf("== Re-Gen Target\n");
		printf("============================================================================\n");
	}

	HelixBuilder builder;
	builder.GenerateSqldo(true);
	HelixFS::getInstance().Load(); // Re-load the file system because GenerateSqldo creates files
}

void handleAsset(bool displayBanner)
{
	if(HelixWorker::getInstance().HasError()){
		return;
	}
	if(displayBanner){
		printf("============================================================================\n");
		printf("== Auto-Asset Target\n");
		printf("============================================================================\n");
	}

	HelixAutoAsset asset;
	asset.Generate();
}

void handleStrings(bool displayBanner)
{
	if(HelixWorker::getInstance().HasError()){
		return;
	}
	if(displayBanner){
		printf("============================================================================\n");
		printf("== Extract Strings Target\n");
		printf("============================================================================\n");
	}

	HelixExtractStrings strings;
	strings.Generate();
}

void handleJSApiGen(bool displayBanner)
{
	if(HelixWorker::getInstance().HasError()){
		return;
	}
	if(displayBanner){
		printf("============================================================================\n");
		printf("== JS API Gen Target\n");
		printf("============================================================================\n");
	}

	HelixBuilder builder;
	builder.GenerateJSApi();
}

void handleJSGen(bool displayBanner)
{
	if(HelixWorker::getInstance().HasError()){
		return;
	}
	if(displayBanner){
		printf("============================================================================\n");
		printf("== JS Gen Target\n");
		printf("============================================================================\n");
	}

	HelixJSGenTask jsgen;
	for(auto app : HelixConfig::getInstance().QxAppsAll()){
		jsgen.Generate( app );
	}
}

void handleCS(bool displayBanner)
{
	if(HelixWorker::getInstance().HasError()){
		return;
	}
	if(displayBanner){
		printf("============================================================================\n");
		printf("== CS Target\n");
		printf("============================================================================\n");
	}

	HelixBuilder builder;
	builder.BuildCS();
	builder.BuildCSTest();
}

void handleInstall(bool displayBanner)
{
	if(HelixWorker::getInstance().HasError()){
		return;
	}
	if(displayBanner){
		printf("============================================================================\n");
		printf("== Install Target\n");
		printf("============================================================================\n");
	}

	for(auto install : HelixConfig::getInstance().Installs() ){
		twine from(install, "from");
		twine ends(install, "endsWith");
		twine to(install, "to");
		twine newName(install, "newName");
		HelixWorker::getInstance().Add( new HelixInstallTask( from, ends, to, newName ) );
	}
}

void handleDeploy(bool displayBanner)
{
	if(HelixWorker::getInstance().HasError()){
		return;
	}
	if(displayBanner){
		printf("============================================================================\n");
		printf("== Deploy Target\n");
		printf("============================================================================\n");
	}

	for(auto install : HelixConfig::getInstance().Deploy() ){
		twine from(install, "from");
		twine ends(install, "endsWith");
		twine to(install, "to");
		twine newName(install, "newName");
		HelixWorker::getInstance().Add( new HelixInstallTask( from, ends, to, newName) );
	}
}

void testDep()
{
	HelixFS& fs = HelixFS::getInstance();
	auto fsFile = fs.FindFile( "GenerateWeeklyTimesheetReport.cpp" );
	if(fsFile){
		printf("GenerateWeeklyTimesheetReport.cpp - dependencies:\n");
		for(auto file : fsFile->Dependencies()){
			printf( "\t%s\n", file->PhysicalFileName()() );
		}
	}
}

void CopyCore()
{
	if(HelixConfig::getInstance().UseCore() == false){
		// Just make sure that the bin folder exists
		File::EnsurePath( "./bin/" );
		return;
	}

	printf("============================================================================\n");
	printf("== Copy Core Binaries and Files\n");
	printf("============================================================================\n");

	// Copy over the core binaries that we will need
	twine core = HelixConfig::getInstance().CoreFolder();
#ifdef _WIN32
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "HelixSvc.exe", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "HelixMain.exe", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.client.dll", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.client.lib", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.glob.dll", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.glob.lib", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.logic.dev.dll", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.logic.dev.lib", "bin", ""));
#else
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "HelixDaemon", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "HelixMain", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.client.so", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.glob.so", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.logic.dev.so", "bin", ""));
#endif

	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "db.xml", "bin", ""));
}
<commit_msg>Adding a dm logic folder to core.<commit_after>/* ***************************************************************************

	Copyright: 2013 Hericus Software, LLC

	License: The MIT License (MIT)

	Authors: Steven M. Cherry

*************************************************************************** */

#include <AnException.h>
#include <Log.h>
#include <xmlinc.h>
#include <XmlHelpers.h>
#include <twine.h>
#include <File.h>
#include <Timer.h>
using namespace SLib;

#include <vector>

#include "HelixConfig.h"
#include "HelixFS.h"
#include "HelixBuilder.h"
#include "HelixWorker.h"
#include "HelixAutoAsset.h"
#include "HelixExtractStrings.h"
#include "HelixJSGenTask.h"
using namespace Helix::Build;

twine m_platform;
std::vector<twine> m_targets;

void handleAll();
void handleClean();
void handleGen(bool displayBanner = true);
void handleReGen(bool displayBanner = true);
void handleJSApiGen(bool displayBanner = true);
void handleJSGen(bool displayBanner = true);
void handleCS(bool displayBanner = true);
void handleInstall(bool displayBanner = true);
void handleDeploy(bool displayBanner = true);
void handleAsset(bool displayBanner = true);
void handleStrings(bool displayBanner = true);
void testDep();
void CopyCore();
void describe();

int main (int argc, char** argv)
{
	if(argc > 1){
		for(int i = 1; i < argc; i++){
			twine argv1(argv[i]);
			m_targets.push_back( argv1 );
		}
	}

	Log::SetPanic( true );
	Log::SetError( true );
	Log::SetWarn( true );
	Log::SetInfo( true );
	Log::SetDebug( false );
	Log::SetTrace( false );

	printf("============================================================================\n");
#ifdef _WIN32
#	ifdef _X86_
	m_platform = "WIN32_x86";
#	else
	m_platform = "WIN32_x64";
#	endif
#else
	m_platform = "LINUX_x64";
#endif
	printf("Helix Build Running for a %s platform.\n", m_platform());
	printf("============================================================================\n");

	Timer timer;
	try {
		// Load our config file and make sure it exists
		HelixConfig::getInstance();
		CopyCore();

		printf("Loading the helix filesystem");
		timer.Start();
		HelixFS::getInstance();
		timer.Finish(); printf(" - duration: %f seconds\n", timer.Duration() );

		if(m_targets.size() == 0){
			handleAll();
		} else {
			bool didClean = false;
			for( auto const& targ : m_targets){
				if(didClean){
					didClean = false;
					CopyCore();
				}
				if(targ == "clean") { handleClean(); didClean = true; }
				else if(targ == "all") handleAll();
				else if(targ == "gen") handleGen();
				else if(targ == "regen") handleReGen();
				else if(targ == "jsapi") handleJSApiGen();
				else if(targ == "jsgen") handleJSGen();
				else if(targ == "cs") handleCS();
				else if(targ == "install") handleInstall();
				else if(targ == "dep") handleDeploy();
				else if(targ == "testdep") testDep();
				else if(targ == "asset") handleAsset();
				else if(targ == "strings") handleStrings();
				else if(targ == "?") describe();
				else if(targ == "help") describe();
				else if(targ == "-?") describe();
			}
		}

		HelixWorker::getInstance().Finish();
		HelixFS::getInstance().SaveCache();

		/* Use this for profiling what's going on and what's taking up the time
		twine hitmap;
		EnEx::PrintGlobalHitMap( hitmap );
		printf("\n\n%s\n\n", hitmap() );
		*/

	} catch(AnException& e){
		printf("%s\n", e.Msg());
		printf("%s\n", e.Stack());
		printf("============================================================================\n");
		printf("== hbuild complete - with errors\n");
		printf("============================================================================\n");
		return 1; // Errors
	}

	if(HelixWorker::getInstance().HasError()){
		printf("============================================================================\n");
		printf("== hbuild complete - with errors\n");
		printf("============================================================================\n");
		return 1; // Errors
	} else {
		printf("============================================================================\n");
		printf("== hbuild complete.\n");
		printf("============================================================================\n");
		return 0; // No error
	}
}

void describe()
{
	printf("============================================================================\n");
	printf("== HBuild Options\n");
	printf("============================================================================\n");
	printf("== clean - cleans the build target\n");
	printf("== all - does everything except dep\n");
	printf("== gen - Generates the C++, JS, and C# from .sql.xml files as required\n");
	printf("== regen - Forces a regeneration of the C++, JS, and C# from all .sql.xml\n");
	printf("== jsapi - Generates the Api.js file in each of our QX projects\n");
	printf("== jsgen - runs generate.py for all QX projects (build and source-hybrid)\n");
	printf("== cs - recompiles the C# HelixPdfGen project if present\n");
	printf("== install - Runs the install lines from the hbuild.xml file\n");
	printf("== dep - Runs the Deploy section from the hbuild.xml file\n");
	printf("== asset - Runs the auto-asset function against all QX projects\n");
	printf("== strings - Runs the extract-strings process to build translation files\n");
	printf("\n");
	printf("== If no target is specified, the 'all' target is invoked.\n");
	printf("\n");
}

void handleAll()
{
	printf("============================================================================\n");
	printf("== All Target\n");
	printf("============================================================================\n");

	HelixBuilder builder;
	handleGen(false);

	if(!HelixConfig::getInstance().UseCore()){
		// Only build these if we're not using a core folder
		builder.Build( "logic/util" );
		builder.Build( "logic/admin" );
		builder.Build( "glob" );
		builder.Build( "server" );
		builder.Build( "client" );
	}

	// Use the config file to tell us which logics to build, and in what order
	for(auto& logic : HelixConfig::getInstance().Logics() ){
		twine repo = HelixConfig::getInstance().LogicRepo( logic );
		if(repo.empty()){
			// Normal local logic folder
			builder.Build( "logic/" + logic );
		} else {
			// Logic folder from another repo - adjust the path
			builder.Build( "../../../" + repo + "/server/c/logic/" + logic );
		}
	}

	if(!HelixConfig::getInstance().UseCore()){
		// Only build these if we're not using a core folder
		builder.Build( "HelixMain" );
		builder.Build( "HelixDaemon" );
	}

	handleAsset(false);
	handleStrings(false);
	handleJSApiGen(false);

	if(HelixWorker::getInstance().NeedsCSRebuild()){
		handleCS( false );
	}

	// Handle all of our installation tasks
	handleInstall( false );

}

void handleClean()
{
	printf("============================================================================\n");
	printf("== Clean Target\n");
	printf("============================================================================\n");

	HelixBuilder builder;
	builder.CleanSqldo();

	if(!HelixConfig::getInstance().UseCore()){
		// Only build these if we're not using a core folder
		builder.Clean( "logic/util" );
		builder.Clean( "logic/admin" );
		builder.Clean( "glob" );
		builder.Clean( "server" );
	}

	// Use the config file to tell us which logics to build, and in what order
	for(auto& logic : HelixConfig::getInstance().Logics() ){
		twine repo = HelixConfig::getInstance().LogicRepo( logic );
		if(repo.empty()){
			// Normal local logic folder
			builder.Clean( "logic/" + logic);
		} else {
			// Logic folder from another repo - adjust the path
			builder.Clean( "../../../" + repo + "/server/c/logic/" + logic );
		}
	}

	if(!HelixConfig::getInstance().UseCore()){
		// Only build these if we're not using a core folder
		builder.Clean( "client" );
		builder.Clean( "HelixDaemon" );
	}
	builder.Clean( "HelixMain" ); // Clean's out the bin folder for core and non-core projects

	builder.CleanCS();
	builder.CleanCSTest();
}

void handleGen(bool displayBanner)
{
	if(displayBanner){
		printf("============================================================================\n");
		printf("== Gen Target\n");
		printf("============================================================================\n");
	}

	HelixBuilder builder;
	builder.GenerateSqldo();
	HelixFS::getInstance().Load(); // Re-load the file system because GenerateSqldo creates files
}

void handleReGen(bool displayBanner)
{
	if(displayBanner){
		printf("============================================================================\n");
		printf("== Re-Gen Target\n");
		printf("============================================================================\n");
	}

	HelixBuilder builder;
	builder.GenerateSqldo(true);
	HelixFS::getInstance().Load(); // Re-load the file system because GenerateSqldo creates files
}

void handleAsset(bool displayBanner)
{
	if(HelixWorker::getInstance().HasError()){
		return;
	}
	if(displayBanner){
		printf("============================================================================\n");
		printf("== Auto-Asset Target\n");
		printf("============================================================================\n");
	}

	HelixAutoAsset asset;
	asset.Generate();
}

void handleStrings(bool displayBanner)
{
	if(HelixWorker::getInstance().HasError()){
		return;
	}
	if(displayBanner){
		printf("============================================================================\n");
		printf("== Extract Strings Target\n");
		printf("============================================================================\n");
	}

	HelixExtractStrings strings;
	strings.Generate();
}

void handleJSApiGen(bool displayBanner)
{
	if(HelixWorker::getInstance().HasError()){
		return;
	}
	if(displayBanner){
		printf("============================================================================\n");
		printf("== JS API Gen Target\n");
		printf("============================================================================\n");
	}

	HelixBuilder builder;
	builder.GenerateJSApi();
}

void handleJSGen(bool displayBanner)
{
	if(HelixWorker::getInstance().HasError()){
		return;
	}
	if(displayBanner){
		printf("============================================================================\n");
		printf("== JS Gen Target\n");
		printf("============================================================================\n");
	}

	HelixJSGenTask jsgen;
	for(auto app : HelixConfig::getInstance().QxAppsAll()){
		jsgen.Generate( app );
	}
}

void handleCS(bool displayBanner)
{
	if(HelixWorker::getInstance().HasError()){
		return;
	}
	if(displayBanner){
		printf("============================================================================\n");
		printf("== CS Target\n");
		printf("============================================================================\n");
	}

	HelixBuilder builder;
	builder.BuildCS();
	builder.BuildCSTest();
}

void handleInstall(bool displayBanner)
{
	if(HelixWorker::getInstance().HasError()){
		return;
	}
	if(displayBanner){
		printf("============================================================================\n");
		printf("== Install Target\n");
		printf("============================================================================\n");
	}

	for(auto install : HelixConfig::getInstance().Installs() ){
		twine from(install, "from");
		twine ends(install, "endsWith");
		twine to(install, "to");
		twine newName(install, "newName");
		HelixWorker::getInstance().Add( new HelixInstallTask( from, ends, to, newName ) );
	}
}

void handleDeploy(bool displayBanner)
{
	if(HelixWorker::getInstance().HasError()){
		return;
	}
	if(displayBanner){
		printf("============================================================================\n");
		printf("== Deploy Target\n");
		printf("============================================================================\n");
	}

	for(auto install : HelixConfig::getInstance().Deploy() ){
		twine from(install, "from");
		twine ends(install, "endsWith");
		twine to(install, "to");
		twine newName(install, "newName");
		HelixWorker::getInstance().Add( new HelixInstallTask( from, ends, to, newName) );
	}
}

void testDep()
{
	HelixFS& fs = HelixFS::getInstance();
	auto fsFile = fs.FindFile( "GenerateWeeklyTimesheetReport.cpp" );
	if(fsFile){
		printf("GenerateWeeklyTimesheetReport.cpp - dependencies:\n");
		for(auto file : fsFile->Dependencies()){
			printf( "\t%s\n", file->PhysicalFileName()() );
		}
	}
}

void CopyCore()
{
	if(HelixConfig::getInstance().UseCore() == false){
		// Just make sure that the bin folder exists
		File::EnsurePath( "./bin/" );
		return;
	}

	printf("============================================================================\n");
	printf("== Copy Core Binaries and Files\n");
	printf("============================================================================\n");

	// Copy over the core binaries that we will need
	twine core = HelixConfig::getInstance().CoreFolder();
#ifdef _WIN32
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "HelixSvc.exe", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "HelixMain.exe", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.client.dll", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.client.lib", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.glob.dll", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.glob.lib", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.logic.dev.dll", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.logic.dev.lib", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.logic.dm.dll", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.logic.dm.lib", "bin", ""));
#else
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "HelixDaemon", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "HelixMain", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.client.so", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.glob.so", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.logic.dev.so", "bin", ""));
	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "libhelix.logic.dm.so", "bin", ""));
#endif

	HelixWorker::getInstance().Add( new HelixInstallTask(core + "/server/c/bin", "db.xml", "bin", ""));
}
<|endoftext|>


<commit_before>#include "art.h"
#include <core/path.h>
#include <text/text.h>

#include <iostream>
#include <Magick++.h>
#include <stdio.h>
#include <unistd.h>

Art::Art(int tid){
    _tid = tid;
    if(access(filepath().c_str(), R_OK)) // file doesn't exist
        _tid = 0;
}

std::string Art::filepath(Art::Size sz) const{
    return eqbeatsDir() + "/art/" +
        (sz==Medium ? "medium/" : sz==Thumbnail ? "thumb/" : "") + number(_tid) + (sz==Full?"":".png");
}

std::string Art::url(Art::Size sz) const{
    return "/track/" + number(_tid) + "/art" +
        (sz==Medium ? "/medium" : sz==Thumbnail ? "/thumb" : "");
}

std::string getFormat(const char *filepath){
    FILE *f = fopen(filepath, "rb");
    std::string format = "";
    unsigned char magic[4];
    fread(&magic, 1, 4, f);
    // JPEG: 0xffd8
    // PNG:  0x89504e470d0a1a0a
    // GIF:  0x47494638
    // TIFF: 0x49492a00
    if(magic[0] == 0xff && magic[1] == 0xd8) format = "jpg";
    if(magic[0] == 0x89 && magic[1] == 'P' &&
       magic[2] == 'N'  && magic[3] == 'G') format = "png";
    if(magic[0] == 'G'  && magic[1] == 'I' &&
       magic[2] == 'F'  && magic[3] == '8') format = "gif";
    if(magic[0] == 'I'  && magic[1] == 'I' &&
       magic[2] == '*'  && magic[3] == 0) format = "tif";
    fclose(f);
    return format;
}

void Art::makeThumbs(){
    if(_tid<=0) return;
    Magick::Image i;
    // Remove previously existing thumbnails
    unlink(filepath(Medium).c_str());
    unlink(filepath(Thumbnail).c_str());
    try {
        try{ i.read(filepath()); }
        catch(Magick::Warning &warn){
            std::cerr << "ImageMagick Warning : " << warn.what() << std::endl;
        }
        std::string f = getFormat(filepath().c_str());
        if(f!="gif" && (i.size().height()>480 || (f!="jpg" && f!="png"))){
            // ^ Don't make a medium thumbnail for GIF (to preserve animation)
            // Otherwise make the thumbnail if the pic is large OR if the format isn't known
            if(i.size().height() > 480) // scale in the first case
                i.scale("x480");
            i.write(filepath(Medium)); // convert to PNG
        }
        if(i.size().height() > 64) // resize (most of the time)
            i.scale("x64");
        i.write(filepath(Thumbnail)); // convert to PNG
    } catch ( Magick::Exception &err ) {
        std::cerr << "ImageMagick Exceptions : " << err.what() << std::endl;
    }
}

void Art::remove(){
    if(_tid <= 0) return;
    unlink(filepath(Full).c_str());
    unlink(filepath(Medium).c_str());
    unlink(filepath(Thumbnail).c_str());
}

File Art::thumbnail() const{
    return File("art/thumb/" + number(_tid) + ".png", "thumbnail.png");
}

File Art::medium() const{
    if(access(filepath(Medium).c_str(), R_OK)) // medium thumbnail doesn't exist
        return full();
    return File("art/medium/" + number(_tid) + ".png", "medium.png");
}

File Art::full() const{
    std::string f = getFormat(filepath().c_str());
    return File("art/" + number(_tid), "cover" + (f.empty() ? "" : "." + f));
}
<commit_msg>stop making thumbnails if we can't access the file<commit_after>#include "art.h"
#include <core/path.h>
#include <text/text.h>

#include <iostream>
#include <Magick++.h>
#include <stdio.h>
#include <unistd.h>

Art::Art(int tid){
    _tid = tid;
    if(access(filepath().c_str(), R_OK)) // file doesn't exist
        _tid = 0;
}

std::string Art::filepath(Art::Size sz) const{
    return eqbeatsDir() + "/art/" +
        (sz==Medium ? "medium/" : sz==Thumbnail ? "thumb/" : "") + number(_tid) + (sz==Full?"":".png");
}

std::string Art::url(Art::Size sz) const{
    return "/track/" + number(_tid) + "/art" +
        (sz==Medium ? "/medium" : sz==Thumbnail ? "/thumb" : "");
}

std::string getFormat(const char *filepath){
    FILE *f = fopen(filepath, "rb");
    std::string format = "";
    unsigned char magic[4];
    fread(&magic, 1, 4, f);
    // JPEG: 0xffd8
    // PNG:  0x89504e470d0a1a0a
    // GIF:  0x47494638
    // TIFF: 0x49492a00
    if(magic[0] == 0xff && magic[1] == 0xd8) format = "jpg";
    if(magic[0] == 0x89 && magic[1] == 'P' &&
       magic[2] == 'N'  && magic[3] == 'G') format = "png";
    if(magic[0] == 'G'  && magic[1] == 'I' &&
       magic[2] == 'F'  && magic[3] == '8') format = "gif";
    if(magic[0] == 'I'  && magic[1] == 'I' &&
       magic[2] == '*'  && magic[3] == 0) format = "tif";
    fclose(f);
    return format;
}

void Art::makeThumbs(){
    if(_tid<=0) return;
    Magick::Image i;
    // Remove previously existing thumbnails
    unlink(filepath(Medium).c_str());
    unlink(filepath(Thumbnail).c_str());
    try {
        try{ i.read(filepath()); }
        catch(Magick::Warning &warn){
            std::cerr << "ImageMagick Warning : " << warn.what() << std::endl;
            return;
        }
        std::string f = getFormat(filepath().c_str());
        if(f!="gif" && (i.size().height()>480 || (f!="jpg" && f!="png"))){
            // ^ Don't make a medium thumbnail for GIF (to preserve animation)
            // Otherwise make the thumbnail if the pic is large OR if the format isn't known
            if(i.size().height() > 480) // scale in the first case
                i.scale("x480");
            i.write(filepath(Medium)); // convert to PNG
        }
        if(i.size().height() > 64) // resize (most of the time)
            i.scale("x64");
        i.write(filepath(Thumbnail)); // convert to PNG
    } catch ( Magick::Exception &err ) {
        std::cerr << "ImageMagick Exceptions : " << err.what() << std::endl;
    }
}

void Art::remove(){
    if(_tid <= 0) return;
    unlink(filepath(Full).c_str());
    unlink(filepath(Medium).c_str());
    unlink(filepath(Thumbnail).c_str());
}

File Art::thumbnail() const{
    return File("art/thumb/" + number(_tid) + ".png", "thumbnail.png");
}

File Art::medium() const{
    if(access(filepath(Medium).c_str(), R_OK)) // medium thumbnail doesn't exist
        return full();
    return File("art/medium/" + number(_tid) + ".png", "medium.png");
}

File Art::full() const{
    std::string f = getFormat(filepath().c_str());
    return File("art/" + number(_tid), "cover" + (f.empty() ? "" : "." + f));
}
<|endoftext|>


<commit_before>// __BEGIN_LICENSE__
// Copyright (C) 2006, 2007 United States Government as represented by
// the Administrator of the National Aeronautics and Space Administration.
// All Rights Reserved.
// __END_LICENSE__

#include <gtest/gtest.h>
#include <vw/tests/config_test.h>
#include <vw/Math/ParticleSwarmOptimization.h>

using namespace vw;
using namespace vw::math;

// This quadratic function has a single minimum at [0.1962, 0.4846].
struct QuadraticFunction {
  typedef double result_type;
  typedef Vector2 domain_type;
  typedef Vector2 gradient_type;

  result_type operator()( domain_type const& x ) const {
    return 1.2 * pow(x[0] - 0.6, 2) + 1.7 * pow(x[1] - 0.6, 2) + 2 * x[0] * x[1];
  }
  gradient_type gradient( domain_type const& x ) const {
    return Vector2( 2.4*x[0]-1.44+2*x[1],
                    3.4*x[1]-2.04+2*x[0]);
  }

  unsigned dimension() const { return 2; }
};

struct SinFunction {
  typedef double result_type;
  typedef Vector4 domain_type;
  typedef Vector4 gradient_type;

  result_type operator()( domain_type const& x ) const {
    return std::sin(x[0])*std::sin(x[1])*std::sin(x[2])*std::sin(x[3]);
  }

  gradient_type gradient( domain_type const& x ) const {
    return Vector4( std::cos(x[0])*std::sin(x[1])*std::sin(x[2])*std::sin(x[3]),
                    std::sin(x[0])*std::cos(x[1])*std::sin(x[2])*std::sin(x[3]),
                    std::sin(x[0])*std::sin(x[1])*std::cos(x[2])*std::sin(x[3]),
                    std::sin(x[0])*std::sin(x[1])*std::sin(x[2])*std::cos(x[3]) );
  }

  unsigned dimension() const { return 4; }
};

inline double modulo(double v, double d) {
  return (v/d - static_cast<int>(v/d))*d;
}

TEST(ParticleSwarmOptimization, quadratic) {
  Vector2 min(-2, -2);
  Vector2 max(2, 2);

  QuadraticFunction::domain_type result = particle_swarm_optimization( QuadraticFunction(), min, max );
  EXPECT_VECTOR_NEAR( Vector2(0.1962, 0.4846), result, 1e-2 );
}

TEST(ParticleSwarmOptimization, quadratic_large_search) {
  Vector2 min(-200, -200);
  Vector2 max(200, 200);

  QuadraticFunction::domain_type result = particle_swarm_optimization( QuadraticFunction(), min, max, false, 5, 1000, 2000);
  EXPECT_VECTOR_NEAR( Vector2(0.1962, 0.4846), result, 1e-3 );
}

TEST(ParticleSwarmOptimization, sinus_function) {
  Vector4 min(-200, -200, -200, -200);
  Vector4 max(200, 200, 200, 200);

  SinFunction cost_functor;
  SinFunction::domain_type result = particle_swarm_optimization( cost_functor, min, max, false, 2, 100, 2000);

  EXPECT_NEAR( -1.0, cost_functor(result), 1e-3 );

  double pi2 = static_cast<double>(M_PI)/2;

  // TODO: Trig precision is so bad...
  EXPECT_NEAR( pi2, std::fabs(modulo(result(0), M_PI)), 1e-1 );
  EXPECT_NEAR( pi2, std::fabs(modulo(result(1), M_PI)), 1e-1 );
  EXPECT_NEAR( pi2, std::fabs(modulo(result(2), M_PI)), 1e-1 );
  EXPECT_NEAR( pi2, std::fabs(modulo(result(3), M_PI)), 1e-1 );
}
<commit_msg>yet another precision bump for octo<commit_after>// __BEGIN_LICENSE__
// Copyright (C) 2006, 2007 United States Government as represented by
// the Administrator of the National Aeronautics and Space Administration.
// All Rights Reserved.
// __END_LICENSE__

#include <gtest/gtest.h>
#include <vw/tests/config_test.h>
#include <vw/Math/ParticleSwarmOptimization.h>

using namespace vw;
using namespace vw::math;

// This quadratic function has a single minimum at [0.1962, 0.4846].
struct QuadraticFunction {
  typedef double result_type;
  typedef Vector2 domain_type;
  typedef Vector2 gradient_type;

  result_type operator()( domain_type const& x ) const {
    return 1.2 * pow(x[0] - 0.6, 2) + 1.7 * pow(x[1] - 0.6, 2) + 2 * x[0] * x[1];
  }
  gradient_type gradient( domain_type const& x ) const {
    return Vector2( 2.4*x[0]-1.44+2*x[1],
                    3.4*x[1]-2.04+2*x[0]);
  }

  unsigned dimension() const { return 2; }
};

struct SinFunction {
  typedef double result_type;
  typedef Vector4 domain_type;
  typedef Vector4 gradient_type;

  result_type operator()( domain_type const& x ) const {
    return std::sin(x[0])*std::sin(x[1])*std::sin(x[2])*std::sin(x[3]);
  }

  gradient_type gradient( domain_type const& x ) const {
    return Vector4( std::cos(x[0])*std::sin(x[1])*std::sin(x[2])*std::sin(x[3]),
                    std::sin(x[0])*std::cos(x[1])*std::sin(x[2])*std::sin(x[3]),
                    std::sin(x[0])*std::sin(x[1])*std::cos(x[2])*std::sin(x[3]),
                    std::sin(x[0])*std::sin(x[1])*std::sin(x[2])*std::cos(x[3]) );
  }

  unsigned dimension() const { return 4; }
};

inline double modulo(double v, double d) {
  return (v/d - static_cast<int>(v/d))*d;
}

TEST(ParticleSwarmOptimization, quadratic) {
  Vector2 min(-2, -2);
  Vector2 max(2, 2);

  QuadraticFunction::domain_type result = particle_swarm_optimization( QuadraticFunction(), min, max );
  EXPECT_VECTOR_NEAR( Vector2(0.1962, 0.4846), result, 1e-2 );
}

TEST(ParticleSwarmOptimization, quadratic_large_search) {
  Vector2 min(-200, -200);
  Vector2 max(200, 200);

  QuadraticFunction::domain_type result = particle_swarm_optimization( QuadraticFunction(), min, max, false, 5, 1000, 2000);
  EXPECT_VECTOR_NEAR( Vector2(0.1962, 0.4846), result, 1e-3 );
}

TEST(ParticleSwarmOptimization, sinus_function) {
  Vector4 min(-200, -200, -200, -200);
  Vector4 max(200, 200, 200, 200);

  SinFunction cost_functor;
  SinFunction::domain_type result = particle_swarm_optimization( cost_functor, min, max, false, 2, 100, 2000);

  EXPECT_NEAR( -1.0, cost_functor(result), 1.1e-3 );

  double pi2 = static_cast<double>(M_PI)/2;

  // TODO: Trig precision is so bad...
  EXPECT_NEAR( pi2, std::fabs(modulo(result(0), M_PI)), 1e-1 );
  EXPECT_NEAR( pi2, std::fabs(modulo(result(1), M_PI)), 1e-1 );
  EXPECT_NEAR( pi2, std::fabs(modulo(result(2), M_PI)), 1e-1 );
  EXPECT_NEAR( pi2, std::fabs(modulo(result(3), M_PI)), 1e-1 );
}
<|endoftext|>