<commit_before>/* dlvhex -- Answer-Set Programming with external interfaces.
 * Copyright (C) 2005-2007 Roman Schindlauer
 * Copyright (C) 2006-2015 Thomas Krennwallner
 * Copyright (C) 2009-2016 Peter Schüller
 * Copyright (C) 2011-2016 Christoph Redl
 * Copyright (C) 2015-2016 Tobias Kaminski
 * Copyright (C) 2015-2016 Antonius Weinzierl
 *
 * This file is part of dlvhex.
 *
 * dlvhex 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.
 *
 * dlvhex 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with dlvhex; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA.
 */

/**
 * @file   InconsistencyAnalyzer.cpp
 * @author Christoph Redl
 * @date Wed April 20 2016
 *
 * @brief  Computes a reason for the inconsistency in a program unit.
 *
 */

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

#include "dlvhex2/BaseModelGenerator.h"
#include "dlvhex2/InconsistencyAnalyzer.h"
#include "dlvhex2/Printer.h"
#include "dlvhex2/ProgramCtx.h"
#include "dlvhex2/Benchmarking.h"
#include "dlvhex2/Benchmarking.h"
#include "dlvhex2/InternalGrounder.h"
#include "dlvhex2/SATSolver.h"

#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/visitors.hpp>
#include <boost/graph/strong_components.hpp>
#include <boost/graph/filtered_graph.hpp>

#include <boost/foreach.hpp>

DLVHEX_NAMESPACE_BEGIN

InconsistencyAnalyzer::InconsistencyAnalyzer(ProgramCtx& ctx) : ctx(ctx){
}

Nogood InconsistencyAnalyzer::getInconsistencyReason(BaseModelGenerator* mg, InterpretationConstPtr explAtoms, InterpretationConstPtr unitInput, std::vector<ID>& innerEatoms, OrdinaryASPProgram& program, AnnotatedGroundProgram& annotatedOptimizedProgram, bool* haveInconsistencyReason){

#ifndef NDEBUG
    DBGLOG(DBG, "Performing inconsistency analyzis for program:" << std::endl << *program.edb << std::endl << printManyToString<RawPrinter>(program.idb, "\n", ctx.registry()));
#endif

    // ground the program without optimization
    InternalGrounder grounder(ctx, program, InternalGrounder::builtin);
    OrdinaryASPProgram gp = grounder.getGroundProgram();

#ifndef NDEBUG
    DBGLOG(DBG, "Unoptimized grounded program:" << std::endl << *gp.edb << std::endl << printManyToString<RawPrinter>(gp.idb, "\n", ctx.registry()));
#endif

    // Construct domain of the SAT instance.
    // It consists of all external atom input atoms and all ordinary atoms in the program (to be added below).
    // It can be constructed by using the program mask of the previous (optimized) grounding and adding newly introduced atoms in the non-optimized grounding.
    // All input atoms from predecessor components are already contained in the program mask of the optimized grounding.
    InterpretationPtr domain(new Interpretation(*annotatedOptimizedProgram.getProgramMask()));

    for (int eaIndex = 0; eaIndex < innerEatoms.size(); ++eaIndex) {
        const ExternalAtom& eatom = ctx.registry()->eatoms.getByID(innerEatoms[eaIndex]);
        eatom.updatePredicateInputMask();
        domain->add(*(eatom.getPredicateInputMask()));
    }

    bm::bvector<>::enumerator en, en_end;

    // remove input from predecessor units
    InterpretationPtr newEdb(new Interpretation(*gp.edb));
    newEdb->getStorage() -= unitInput->getStorage();
    gp.edb = newEdb;

#ifndef NDEBUG
    DBGLOG(DBG, "Program to be analyzed:" << std::endl << *gp.edb << std::endl << printManyToString<RawPrinter>(gp.idb, "\n", ctx.registry()));
#endif

    NogoodSet instance;

    // add input is pseudo-nogoods to make sure they are part of the problem
    en = unitInput->getStorage().first();
    en_end = unitInput->getStorage().end();
    while (en < en_end) {
        Nogood ng;
        ng.insert(NogoodContainer::createLiteral(*en, true));
        ng.insert(NogoodContainer::createLiteral(*en, false));
        instance.addNogood(ng);
        en++;
    }

    // interprete the ground program as a set of classical implications
    if (!!gp.edb) {
        en = gp.edb->getStorage().first();
        en_end = gp.edb->getStorage().end();
        while (en < en_end) {
            Nogood ng;
            ng.insert(NogoodContainer::createLiteral(*en, false));
            instance.addNogood(ng);
//            domain->setFact(*en);
            en++;
        }
    }
    BOOST_FOREACH (ID ruleID, gp.idb) {
        const Rule& rule = ctx.registry()->rules.getByID(ruleID);
	    Nogood ng;
        BOOST_FOREACH (ID h, rule.head) { ng.insert(NogoodContainer::createLiteral(h.address, false)); domain->setFact(h.address); }
        BOOST_FOREACH (ID b, rule.body) { ng.insert(NogoodContainer::createLiteral(b.address, !b.isNaf())); domain->setFact(b.address); }
        instance.addNogood(ng);
    }
    SATSolverPtr classicalSolver = SATSolver::getInstance(ctx, instance /*, domain*/);

    // explanation atoms are all atoms from the domain which are not defined in the given program, i.e., which do not unify with a head atom in program
/*
    InterpretationPtr explanationAtoms(new Interpretation(ctx.registry()));
    en = domain->getStorage().first();
    en_end = domain->getStorage().end();
    while (en < en_end) {
        const OrdinaryAtom& datom = ctx.registry()->ogatoms.getByAddress(*en);

        bool definedInProgram = false;
        BOOST_FOREACH (ID ruleID, program.idb) {
            const Rule& rule = ctx.registry()->rules.getByID(ruleID);
            BOOST_FOREACH (ID hatomID, rule.head) {
                const OrdinaryAtom& hatom = ctx.registry()->lookupOrdinaryAtom(hatomID);
                if (datom.unifiesWith(hatom)) {
                    definedInProgram = true;
                    break;
                }
                en++;
            }
        }

        if (!definedInProgram) explanationAtoms->setFact(*en);
    }
*/
    DBGLOG(DBG, "Explanation atoms: " << *explAtoms);

    // compute the classical models and an inconsistency reason
    Nogood inconsistencyReason;
    InterpretationPtr alreadyPos(new Interpretation(ctx.registry()));
    InterpretationPtr alreadyNeg(new Interpretation(ctx.registry()));
    InterpretationConstPtr model;
    while ( (model = classicalSolver->getNextModel()) != InterpretationConstPtr() ) {
        // compatibility check
        bool verified = true;
        for (int eaIndex = 0; eaIndex < innerEatoms.size() && verified; ++eaIndex){
            BaseModelGenerator::VerifyExternalAtomCB vcb(model, ctx.registry()->eatoms.getByID(innerEatoms[eaIndex]), *(annotatedOptimizedProgram.getEAMask(eaIndex)));
            mg->evaluateExternalAtom(ctx, innerEatoms[eaIndex], model, vcb, ctx.config.getOption("ExternalLearning") ? classicalSolver : NogoodContainerPtr());
            verified &= vcb.verify();
        }

        if (verified) {
            DBGLOG(DBG, "Got classical model: " << *model);

            // add a literal "l" over some explanation atom "a", where the sign of "l" is the opposite of "a"'s sign in the model
            en = explAtoms->getStorage().first();
            en_end = explAtoms->getStorage().end();
            while (en < en_end) {
                // Use its negation in the inconsistency explanation; this will either:
                // (i) prevent super sets of this model from becoming models of the program (namely if l="F a"; then adding "a" as fact will eliminate the model because "a" must be true); or
                // (ii) ensure that there is a non-empty unfounded set (namely if l=T a); then *not* adding "a" as fact will leave "a" unfounded)
                if (model->getFact(*en)) {
                    if (alreadyPos->getFact(*en)) { en++; continue; } // cannot use this literal because it needs to be added negatively but is already positive
                    if (alreadyNeg->getFact(*en)) break; // needs to be added negatively and is already negative --> done
                    DBGLOG(DBG, "Adding -" << printToString<RawPrinter>(ctx.registry()->ogatoms.getIDByAddress(*en), ctx.registry()) << " to reason nogood");
                    inconsistencyReason.insert(NogoodContainer::createLiteral(*en, false));
                    alreadyNeg->setFact(*en);

                    // eliminate all models with this literal
                    Nogood ng;
                    ng.insert(NogoodContainer::createLiteral(*en, true));
                    classicalSolver->addNogood(ng);
                    break;
                }else{
                    if (alreadyNeg->getFact(*en)) { en++; continue; } // cannot use this literal because it needs to be added positively but is already negative
                    if (alreadyPos->getFact(*en)) break; // needs to be added positively and is already positive --> done
                    DBGLOG(DBG, "Adding " << printToString<RawPrinter>(ctx.registry()->ogatoms.getIDByAddress(*en), ctx.registry()) << " to reason nogood");
                    inconsistencyReason.insert(NogoodContainer::createLiteral(*en, true));
                    alreadyPos->setFact(*en);

                    // eliminate all models with this literal
                    Nogood ng;
                    ng.insert(NogoodContainer::createLiteral(*en, false));
                    classicalSolver->addNogood(ng);
                    break;
                }
                en++;
            }
            if (en == en_end) {
                // could not find a reason
                DBGLOG(DBG, "No inconsistency reason found");
                *haveInconsistencyReason = false;
                return Nogood();
            }
        }
    }
    DBGLOG(DBG, "Found inconsistency reason: " << inconsistencyReason.getStringRepresentation(ctx.registry()) << std::endl << "for program " << *gp.edb << std::endl << printManyToString<RawPrinter>(gp.idb, "\n", ctx.registry()) << std::endl << "wrt. explanation atoms " << *explAtoms);
    *haveInconsistencyReason = true;
    return inconsistencyReason;
}

DLVHEX_NAMESPACE_END

// vim:expandtab:ts=4:sw=4:
// mode: C++
// End:
<commit_msg>some fixes<commit_after>/* dlvhex -- Answer-Set Programming with external interfaces.
 * Copyright (C) 2005-2007 Roman Schindlauer
 * Copyright (C) 2006-2015 Thomas Krennwallner
 * Copyright (C) 2009-2016 Peter Schüller
 * Copyright (C) 2011-2016 Christoph Redl
 * Copyright (C) 2015-2016 Tobias Kaminski
 * Copyright (C) 2015-2016 Antonius Weinzierl
 *
 * This file is part of dlvhex.
 *
 * dlvhex 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.
 *
 * dlvhex 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with dlvhex; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA.
 */

/**
 * @file   InconsistencyAnalyzer.cpp
 * @author Christoph Redl
 * @date Wed April 20 2016
 *
 * @brief  Computes a reason for the inconsistency in a program unit.
 *
 */

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

#include "dlvhex2/BaseModelGenerator.h"
#include "dlvhex2/InconsistencyAnalyzer.h"
#include "dlvhex2/Printer.h"
#include "dlvhex2/ProgramCtx.h"
#include "dlvhex2/Benchmarking.h"
#include "dlvhex2/Benchmarking.h"
#include "dlvhex2/InternalGrounder.h"
#include "dlvhex2/SATSolver.h"

#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/visitors.hpp>
#include <boost/graph/strong_components.hpp>
#include <boost/graph/filtered_graph.hpp>

#include <boost/foreach.hpp>

DLVHEX_NAMESPACE_BEGIN

InconsistencyAnalyzer::InconsistencyAnalyzer(ProgramCtx& ctx) : ctx(ctx){
}

Nogood InconsistencyAnalyzer::getInconsistencyReason(BaseModelGenerator* mg, InterpretationConstPtr explAtoms, InterpretationConstPtr unitInput, std::vector<ID>& innerEatoms, OrdinaryASPProgram& program, AnnotatedGroundProgram& annotatedOptimizedProgram, bool* haveInconsistencyReason){

#ifndef NDEBUG
    DBGLOG(DBG, "Performing inconsistency analyzis for program:" << std::endl << *program.edb << std::endl << printManyToString<RawPrinter>(program.idb, "\n", ctx.registry()));
#endif

    // ground the program without optimization
    InternalGrounder grounder(ctx, program, InternalGrounder::builtin);
    OrdinaryASPProgram gp = grounder.getGroundProgram();

#ifndef NDEBUG
    DBGLOG(DBG, "Unoptimized grounded program:" << std::endl << *gp.edb << std::endl << printManyToString<RawPrinter>(gp.idb, "\n", ctx.registry()));
#endif

    // Construct domain of the SAT instance.
    // It consists of all external atom input atoms and all ordinary atoms in the program (to be added below).
    // It can be constructed by using the program mask of the previous (optimized) grounding and adding newly introduced atoms in the non-optimized grounding.
    // All input atoms from predecessor components are already contained in the program mask of the optimized grounding.
    InterpretationPtr domain(new Interpretation(*annotatedOptimizedProgram.getProgramMask()));

    for (int eaIndex = 0; eaIndex < innerEatoms.size(); ++eaIndex) {
        const ExternalAtom& eatom = ctx.registry()->eatoms.getByID(innerEatoms[eaIndex]);
        eatom.updatePredicateInputMask();
        domain->add(*(eatom.getPredicateInputMask()));
    }

    bm::bvector<>::enumerator en, en_end;

    // remove input from predecessor units
    InterpretationPtr newEdb(new Interpretation(*gp.edb));
    newEdb->getStorage() -= unitInput->getStorage();
    gp.edb = newEdb;

#ifndef NDEBUG
    DBGLOG(DBG, "Program to be analyzed:" << std::endl << *gp.edb << std::endl << printManyToString<RawPrinter>(gp.idb, "\n", ctx.registry()));
#endif

    NogoodSet instance;

    // add input is pseudo-nogoods to make sure they are part of the problem
    en = unitInput->getStorage().first();
    en_end = unitInput->getStorage().end();
    while (en < en_end) {
        Nogood ng;
        ng.insert(NogoodContainer::createLiteral(*en, true));
        ng.insert(NogoodContainer::createLiteral(*en, false));
        instance.addNogood(ng);
        en++;
    }

    // interprete the ground program as a set of classical implications
    if (!!gp.edb) {
        en = gp.edb->getStorage().first();
        en_end = gp.edb->getStorage().end();
        while (en < en_end) {
            Nogood ng;
            ng.insert(NogoodContainer::createLiteral(*en, false));
            instance.addNogood(ng);
//            domain->setFact(*en);
            en++;
        }
    }
    BOOST_FOREACH (ID ruleID, gp.idb) {
        const Rule& rule = ctx.registry()->rules.getByID(ruleID);
	    Nogood ng;
        BOOST_FOREACH (ID h, rule.head) { ng.insert(NogoodContainer::createLiteral(h.address, false)); domain->setFact(h.address); }
        BOOST_FOREACH (ID b, rule.body) { ng.insert(NogoodContainer::createLiteral(b.address, !b.isNaf())); domain->setFact(b.address); }
        instance.addNogood(ng);
    }
    SATSolverPtr classicalSolver = SATSolver::getInstance(ctx, instance /*, domain*/);

    // explanation atoms are all atoms from the domain which are not defined in the given program, i.e., which do not unify with a head atom in program
/*
    InterpretationPtr explanationAtoms(new Interpretation(ctx.registry()));
    en = domain->getStorage().first();
    en_end = domain->getStorage().end();
    while (en < en_end) {
        const OrdinaryAtom& datom = ctx.registry()->ogatoms.getByAddress(*en);

        bool definedInProgram = false;
        BOOST_FOREACH (ID ruleID, program.idb) {
            const Rule& rule = ctx.registry()->rules.getByID(ruleID);
            BOOST_FOREACH (ID hatomID, rule.head) {
                const OrdinaryAtom& hatom = ctx.registry()->lookupOrdinaryAtom(hatomID);
                if (datom.unifiesWith(hatom)) {
                    definedInProgram = true;
                    break;
                }
                en++;
            }
        }

        if (!definedInProgram) explanationAtoms->setFact(*en);
    }
*/
    DBGLOG(DBG, "Explanation atoms: " << *explAtoms);

    // compute the classical models and an inconsistency reason
    Nogood inconsistencyReason;
    InterpretationPtr alreadyPos(new Interpretation(ctx.registry()));
    InterpretationPtr alreadyNeg(new Interpretation(ctx.registry()));
    InterpretationConstPtr model;
    while ( (model = classicalSolver->getNextModel()) != InterpretationConstPtr() ) {
        // compatibility check
        bool verified = true;
        for (int eaIndex = 0; eaIndex < innerEatoms.size() && verified; ++eaIndex){
            BaseModelGenerator::VerifyExternalAtomCB vcb(model, ctx.registry()->eatoms.getByID(innerEatoms[eaIndex]), *(annotatedOptimizedProgram.getEAMask(eaIndex)));
            mg->evaluateExternalAtom(ctx, innerEatoms[eaIndex], model, vcb, ctx.config.getOption("ExternalLearning") ? classicalSolver : NogoodContainerPtr());
            verified &= vcb.verify();
        }

        if (verified) {
            DBGLOG(DBG, "Got classical model: " << *model);

            // add a literal "l" over some explanation atom "a", where the sign of "l" is the opposite of "a"'s sign in the model
            en = explAtoms->getStorage().first();
            en_end = explAtoms->getStorage().end();
            while (en < en_end) {
                // we want an inconsistency reason which is currently violated
                if (unitInput->getFact(*en) != model->getFact(*en)) { en++; continue; }

                // Use its negation in the inconsistency explanation; this will either:
                // (i) prevent super sets of this model from becoming models of the program (namely if l="F a"; then adding "a" as fact will eliminate the model because "a" must be true); or
                // (ii) ensure that there is a non-empty unfounded set (namely if l=T a); then *not* adding "a" as fact will leave "a" unfounded)
                if (model->getFact(*en)) {
                    if (alreadyPos->getFact(*en)) { en++; continue; } // cannot use this literal because it needs to be added negatively but is already positive
                    if (alreadyNeg->getFact(*en)) break; // needs to be added negatively and is already negative --> done
                    DBGLOG(DBG, "Adding -" << printToString<RawPrinter>(ctx.registry()->ogatoms.getIDByAddress(*en), ctx.registry()) << " to reason nogood");
                    inconsistencyReason.insert(NogoodContainer::createLiteral(*en, false));
                    alreadyNeg->setFact(*en);

                    // eliminate all models with this literal
                    if (annotatedOptimizedProgram.getProgramMask()->getFact(*en)){
                        Nogood ng;
                        ng.insert(NogoodContainer::createLiteral(*en, true));
                        DBGLOG(DBG, "Adding nogood " << ng.getStringRepresentation(ctx.registry()) << " to solver");
                        classicalSolver->addNogood(ng);
                    }
                    break;
                }else{
                    if (alreadyNeg->getFact(*en)) { en++; continue; } // cannot use this literal because it needs to be added positively but is already negative
                    if (alreadyPos->getFact(*en)) break; // needs to be added positively and is already positive --> done
                    DBGLOG(DBG, "Adding " << printToString<RawPrinter>(ctx.registry()->ogatoms.getIDByAddress(*en), ctx.registry()) << " to reason nogood");
                    inconsistencyReason.insert(NogoodContainer::createLiteral(*en, true));
                    alreadyPos->setFact(*en);

                    // eliminate all models with this literal
                    if (annotatedOptimizedProgram.getProgramMask()->getFact(*en)){
                        Nogood ng;
                        ng.insert(NogoodContainer::createLiteral(*en, false));
                        DBGLOG(DBG, "Adding nogood " << ng.getStringRepresentation(ctx.registry()) << " to solver");
                        classicalSolver->addNogood(ng);
                    }
                    break;
                }
                en++;
            }
            if (en == en_end) {
                // could not find a reason
                DBGLOG(DBG, "No inconsistency reason found");
                *haveInconsistencyReason = false;
                return Nogood();
            }
        }
    }
    DBGLOG(DBG, "Found inconsistency reason: " << inconsistencyReason.getStringRepresentation(ctx.registry()) << std::endl << "for program " << *gp.edb << std::endl << printManyToString<RawPrinter>(gp.idb, "\n", ctx.registry()) << std::endl << "wrt. explanation atoms " << *explAtoms);
    *haveInconsistencyReason = true;
    return inconsistencyReason;
}

DLVHEX_NAMESPACE_END

// vim:expandtab:ts=4:sw=4:
// mode: C++
// End:
<|endoftext|>


<commit_before>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

// STL includes
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <istream>
#include <iterator>

// MOOSE includes
#include "MooseError.h"
#include "MaterialProperty.h"

// External includes
#include "pcrecpp.h"

namespace MooseUtils
{

void
tokenize(const std::string &str, std::vector<std::string> &elements, unsigned int min_len, const std::string &delims)
{
  elements.clear();

  std::string::size_type last_pos = str.find_first_not_of(delims, 0);
  std::string::size_type pos = str.find_first_of(delims, std::min(last_pos + min_len, str.size()));

  while (last_pos != std::string::npos)
  {
    elements.push_back(str.substr(last_pos, pos - last_pos));
    // skip delims between tokens
    last_pos = str.find_first_not_of(delims, pos);
    if (last_pos == std::string::npos) break;
    pos = str.find_first_of(delims, std::min(last_pos + min_len, str.size()));
  }
}

void
escape(std::string &str)
{
  std::map<char, std::string> escapes;
  escapes['\a'] = "\\a";
  escapes['\b'] = "\\b";
  escapes['\f'] = "\\f";
  escapes['\n'] = "\\n";
  escapes['\t'] = "\\t";
  escapes['\v'] = "\\v";
  escapes['\r'] = "\\r";

  for (std::map<char, std::string>::iterator it = escapes.begin(); it != escapes.end(); ++it)
    for (size_t pos=0; (pos=str.find(it->first, pos)) != std::string::npos; pos+=it->second.size())
      str.replace(pos, 1, it->second);
}

std::string
trim(std::string str, const std::string &white_space)
{
  std::string r = str.erase(str.find_last_not_of(white_space)+1);
  return r.erase(0,r.find_first_not_of(white_space));
}

bool pathContains(const std::string &expression,
                          const std::string &string_to_find,
                          const std::string &delims)
{
  std::vector<std::string> elements;

  tokenize(expression, elements, 0, delims);

  std::vector<std::string>::iterator found_it = std::find(elements.begin(), elements.end(), string_to_find);
  if (found_it != elements.end())
    return true;
  else
    return false;
}

bool
checkFileReadable(const std::string & filename, bool check_line_endings, bool throw_on_unreadable)
{
  std::ifstream in(filename.c_str(), std::ifstream::in);
  if (in.fail())
  {
    if (throw_on_unreadable)
      mooseError((std::string("Unable to open file \"") + filename
                  + std::string("\". Check to make sure that it exists and that you have read permission.")).c_str());
    else
      return false;
  }

  if (check_line_endings)
  {
    std::istream_iterator<char> iter(in);
    std::istream_iterator<char> eos;
    in >> std::noskipws;
    while (iter != eos)
      if (*iter++ == '\r')
        mooseError(filename + " contains Windows(DOS) line endings which are not supported.");
  }

  in.close();

  return true;
}

bool
checkFileWriteable(const std::string & filename, bool throw_on_unwritable)
{
  std::ofstream out(filename.c_str(), std::ofstream::out);
  if (out.fail())
  {
    if (throw_on_unwritable)
      mooseError((std::string("Unable to open file \"") + filename
                  + std::string("\". Check to make sure that it exists and that you have write permission.")).c_str());
    else
      return false;
  }

  out.close();

  return true;
}

void
parallelBarrierNotify(const Parallel::Communicator & comm)
{
  processor_id_type slave_processor_id;

  if (comm.rank() == 0)
  {
    // The master process is already through, so report it
    Moose::out << "Jobs complete: 1/" << comm.size() << (1 == comm.size() ? "\n" : "\r") << std::flush;
    for (unsigned int i=2; i<=comm.size(); ++i)
    {
      comm.receive(MPI_ANY_SOURCE, slave_processor_id);
      Moose::out << "Jobs complete: " << i << "/" << comm.size() << (i == comm.size() ? "\n" : "\r") << std::flush;
    }
  }
  else
  {
    slave_processor_id = comm.rank();
    comm.send(0, slave_processor_id);
  }

  comm.barrier();
}

bool
hasExtension(const std::string & filename, std::string ext, bool strip_exodus_ext)
{
  // Extract the extension, w/o the '.'
  std::string file_ext;
  if (strip_exodus_ext)
  {
    pcrecpp::RE re(".*\\.([^\\.]*?)(?:-s\\d+)?\\s*$"); // capture the complete extension, ignoring -s*
    re.FullMatch(filename, &file_ext);
  }
  else
  {
    pcrecpp::RE re(".*\\.([^\\.]*?)\\s*$"); // capture the complete extension
    re.FullMatch(filename, &file_ext);
  }

  // Perform the comparision
  if (file_ext == ext)
    return true;
  else
    return false;
}

std::pair<std::string, std::string>
splitFileName(std::string full_file)
{
  // Error if path ends with /
  if (full_file[full_file.size()-1] == '/')
    mooseError("Invalid full file name: " << full_file);

  // Define the variables to output
  std::string path;
  std::string file;

  // Locate the / sepearting the file from path
  std::size_t found = full_file.find_last_of("/");

  // If no / is found used "." for the path, otherwise seperate the two
  if (found == std::string::npos)
  {
    path = ".";
    file = full_file;
  }
  else
  {
    path = full_file.substr(0, found);
    file = full_file.substr(found+1);
  }

  // Return the path and file as a pair
  return std::pair<std::string, std::string>(path, file);
}

std::string
camelCaseToUnderscore(const std::string & camel_case_name)
{
  string replaced = camel_case_name;
  // Put underscores in front of each contiguous set of capital letters
  pcrecpp::RE("(?!^)([A-Z]+)").GlobalReplace("_\\1", &replaced);

  // Convert all capital letters to lower case
  std::transform(replaced.begin(), replaced.end(), replaced.begin(), ::tolower);
  return replaced;
}

std::string
underscoreToCamelCase(const std::string & underscore_name, bool leading_upper_case)
{
  pcrecpp::StringPiece input(underscore_name);
  pcrecpp::RE re("([^_]*)(_|$)");

  std::string result;
  std::string us, not_us;
  bool make_upper = leading_upper_case;
  while (re.Consume(&input, &not_us, &us))
  {
    if (not_us.length() > 0)
    {
      if (make_upper)
      {
        result += std::toupper(not_us[0]);
        if (not_us.length() > 1)
          result += not_us.substr(1);
      }
      else
        result += not_us;
    }
    if (us == "")
      break;

    // Toggle flag so next match is upper cased
    make_upper = true;
  }

  return result;
}

std::string
shortName(const std::string & name)
{
  return name.substr(name.find_last_of('/') != std::string::npos ? name.find_last_of('/') + 1 : 0);
}

bool
absoluteFuzzyEqual(const Real & var1, const Real & var2, const Real & tol)
{
  return (std::abs(var1 - var2) < tol);
}

bool
absoluteFuzzyGreaterEqual(const Real & var1, const Real & var2, const Real & tol)
{
  return (var1 > (var2 - tol));
}

bool
absoluteFuzzyGreaterThan(const Real & var1, const Real & var2, const Real & tol)
{
  return (var1 > (var2 + tol));
}

bool
absoluteFuzzyLessEqual(const Real & var1, const Real & var2, const Real & tol)
{
  return (var1 < (var2 + tol));
}

bool
absoluteFuzzyLessThan(const Real & var1, const Real & var2, const Real & tol)
{
  return (var1 < (var2 - tol));
}

bool
relativeFuzzyEqual(const Real & var1, const Real & var2, const Real & tol)
{
  return (absoluteFuzzyEqual(var1, var2, tol*(std::abs(var1)+std::abs(var2))));
}

bool
relativeFuzzyGreaterEqual(const Real & var1, const Real & var2, const Real & tol)
{
  return (absoluteFuzzyGreaterEqual(var1, var2, tol*(std::abs(var1)+std::abs(var2))));
}

bool
relativeFuzzyGreaterThan(const Real & var1, const Real & var2, const Real & tol)
{
  return (absoluteFuzzyGreaterThan(var1, var2, tol*(std::abs(var1)+std::abs(var2))));
}

bool
relativeFuzzyLessEqual(const Real & var1, const Real & var2, const Real & tol)
{
  return (absoluteFuzzyLessEqual(var1, var2, tol*(std::abs(var1)+std::abs(var2))));
}

bool
relativeFuzzyLessThan(const Real & var1, const Real & var2, const Real & tol)
{
  return (absoluteFuzzyLessThan(var1, var2, tol*(std::abs(var1)+std::abs(var2))));
}

void
MaterialPropertyStorageDump(const HashMap<const libMesh::Elem *, HashMap<unsigned int, MaterialProperties> > & props)
{
  // Define the iterators
  HashMap<const Elem *, HashMap<unsigned int, MaterialProperties> >::const_iterator elem_it;
  HashMap<unsigned int, MaterialProperties>::const_iterator side_it;
  MaterialProperties::const_iterator prop_it;

  // Loop through the elements
  for (elem_it = props.begin(); elem_it != props.end(); ++elem_it)
  {
    Moose::out << "Element " << elem_it->first->id() << '\n';

    // Loop through the sides
    for (side_it = elem_it->second.begin(); side_it != elem_it->second.end(); ++side_it)
    {
      Moose::out << "  Side " << side_it->first << '\n';

      // Loop over properties
      unsigned int cnt = 0;
      for (prop_it = side_it->second.begin(); prop_it != side_it->second.end(); ++prop_it)
      {
        MaterialProperty<Real> * mp = dynamic_cast<MaterialProperty<Real> *>(*prop_it);
        if (mp)
        {
          Moose::out << "    Property " << cnt << '\n';
          cnt++;

          // Loop over quadrature points
          for (unsigned int qp = 0; qp < mp->size(); ++qp)
            Moose::out << "      prop[" << qp << "] = " << (*mp)[qp] << '\n';
        }
      }
    }
  }
}

} // MooseUtils namespace
<commit_msg>Fix fuzzy functions closes #5408<commit_after>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

// STL includes
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <istream>
#include <iterator>

// MOOSE includes
#include "MooseError.h"
#include "MaterialProperty.h"

// External includes
#include "pcrecpp.h"

namespace MooseUtils
{

void
tokenize(const std::string &str, std::vector<std::string> &elements, unsigned int min_len, const std::string &delims)
{
  elements.clear();

  std::string::size_type last_pos = str.find_first_not_of(delims, 0);
  std::string::size_type pos = str.find_first_of(delims, std::min(last_pos + min_len, str.size()));

  while (last_pos != std::string::npos)
  {
    elements.push_back(str.substr(last_pos, pos - last_pos));
    // skip delims between tokens
    last_pos = str.find_first_not_of(delims, pos);
    if (last_pos == std::string::npos) break;
    pos = str.find_first_of(delims, std::min(last_pos + min_len, str.size()));
  }
}

void
escape(std::string &str)
{
  std::map<char, std::string> escapes;
  escapes['\a'] = "\\a";
  escapes['\b'] = "\\b";
  escapes['\f'] = "\\f";
  escapes['\n'] = "\\n";
  escapes['\t'] = "\\t";
  escapes['\v'] = "\\v";
  escapes['\r'] = "\\r";

  for (std::map<char, std::string>::iterator it = escapes.begin(); it != escapes.end(); ++it)
    for (size_t pos=0; (pos=str.find(it->first, pos)) != std::string::npos; pos+=it->second.size())
      str.replace(pos, 1, it->second);
}

std::string
trim(std::string str, const std::string &white_space)
{
  std::string r = str.erase(str.find_last_not_of(white_space)+1);
  return r.erase(0,r.find_first_not_of(white_space));
}

bool pathContains(const std::string &expression,
                          const std::string &string_to_find,
                          const std::string &delims)
{
  std::vector<std::string> elements;

  tokenize(expression, elements, 0, delims);

  std::vector<std::string>::iterator found_it = std::find(elements.begin(), elements.end(), string_to_find);
  if (found_it != elements.end())
    return true;
  else
    return false;
}

bool
checkFileReadable(const std::string & filename, bool check_line_endings, bool throw_on_unreadable)
{
  std::ifstream in(filename.c_str(), std::ifstream::in);
  if (in.fail())
  {
    if (throw_on_unreadable)
      mooseError((std::string("Unable to open file \"") + filename
                  + std::string("\". Check to make sure that it exists and that you have read permission.")).c_str());
    else
      return false;
  }

  if (check_line_endings)
  {
    std::istream_iterator<char> iter(in);
    std::istream_iterator<char> eos;
    in >> std::noskipws;
    while (iter != eos)
      if (*iter++ == '\r')
        mooseError(filename + " contains Windows(DOS) line endings which are not supported.");
  }

  in.close();

  return true;
}

bool
checkFileWriteable(const std::string & filename, bool throw_on_unwritable)
{
  std::ofstream out(filename.c_str(), std::ofstream::out);
  if (out.fail())
  {
    if (throw_on_unwritable)
      mooseError((std::string("Unable to open file \"") + filename
                  + std::string("\". Check to make sure that it exists and that you have write permission.")).c_str());
    else
      return false;
  }

  out.close();

  return true;
}

void
parallelBarrierNotify(const Parallel::Communicator & comm)
{
  processor_id_type slave_processor_id;

  if (comm.rank() == 0)
  {
    // The master process is already through, so report it
    Moose::out << "Jobs complete: 1/" << comm.size() << (1 == comm.size() ? "\n" : "\r") << std::flush;
    for (unsigned int i=2; i<=comm.size(); ++i)
    {
      comm.receive(MPI_ANY_SOURCE, slave_processor_id);
      Moose::out << "Jobs complete: " << i << "/" << comm.size() << (i == comm.size() ? "\n" : "\r") << std::flush;
    }
  }
  else
  {
    slave_processor_id = comm.rank();
    comm.send(0, slave_processor_id);
  }

  comm.barrier();
}

bool
hasExtension(const std::string & filename, std::string ext, bool strip_exodus_ext)
{
  // Extract the extension, w/o the '.'
  std::string file_ext;
  if (strip_exodus_ext)
  {
    pcrecpp::RE re(".*\\.([^\\.]*?)(?:-s\\d+)?\\s*$"); // capture the complete extension, ignoring -s*
    re.FullMatch(filename, &file_ext);
  }
  else
  {
    pcrecpp::RE re(".*\\.([^\\.]*?)\\s*$"); // capture the complete extension
    re.FullMatch(filename, &file_ext);
  }

  // Perform the comparision
  if (file_ext == ext)
    return true;
  else
    return false;
}

std::pair<std::string, std::string>
splitFileName(std::string full_file)
{
  // Error if path ends with /
  if (full_file[full_file.size()-1] == '/')
    mooseError("Invalid full file name: " << full_file);

  // Define the variables to output
  std::string path;
  std::string file;

  // Locate the / sepearting the file from path
  std::size_t found = full_file.find_last_of("/");

  // If no / is found used "." for the path, otherwise seperate the two
  if (found == std::string::npos)
  {
    path = ".";
    file = full_file;
  }
  else
  {
    path = full_file.substr(0, found);
    file = full_file.substr(found+1);
  }

  // Return the path and file as a pair
  return std::pair<std::string, std::string>(path, file);
}

std::string
camelCaseToUnderscore(const std::string & camel_case_name)
{
  string replaced = camel_case_name;
  // Put underscores in front of each contiguous set of capital letters
  pcrecpp::RE("(?!^)([A-Z]+)").GlobalReplace("_\\1", &replaced);

  // Convert all capital letters to lower case
  std::transform(replaced.begin(), replaced.end(), replaced.begin(), ::tolower);
  return replaced;
}

std::string
underscoreToCamelCase(const std::string & underscore_name, bool leading_upper_case)
{
  pcrecpp::StringPiece input(underscore_name);
  pcrecpp::RE re("([^_]*)(_|$)");

  std::string result;
  std::string us, not_us;
  bool make_upper = leading_upper_case;
  while (re.Consume(&input, &not_us, &us))
  {
    if (not_us.length() > 0)
    {
      if (make_upper)
      {
        result += std::toupper(not_us[0]);
        if (not_us.length() > 1)
          result += not_us.substr(1);
      }
      else
        result += not_us;
    }
    if (us == "")
      break;

    // Toggle flag so next match is upper cased
    make_upper = true;
  }

  return result;
}

std::string
shortName(const std::string & name)
{
  return name.substr(name.find_last_of('/') != std::string::npos ? name.find_last_of('/') + 1 : 0);
}

bool
absoluteFuzzyEqual(const Real & var1, const Real & var2, const Real & tol)
{
  return (std::abs(var1 - var2) < tol);
}

bool
absoluteFuzzyGreaterEqual(const Real & var1, const Real & var2, const Real & tol)
{
  return (var1 >= (var2 - tol));
}

bool
absoluteFuzzyGreaterThan(const Real & var1, const Real & var2, const Real & tol)
{
  return (var1 > (var2 + tol));
}

bool
absoluteFuzzyLessEqual(const Real & var1, const Real & var2, const Real & tol)
{
  return (var1 <= (var2 + tol));
}

bool
absoluteFuzzyLessThan(const Real & var1, const Real & var2, const Real & tol)
{
  return (var1 < (var2 - tol));
}

bool
relativeFuzzyEqual(const Real & var1, const Real & var2, const Real & tol)
{
  return (absoluteFuzzyEqual(var1, var2, tol*(std::abs(var1)+std::abs(var2))));
}

bool
relativeFuzzyGreaterEqual(const Real & var1, const Real & var2, const Real & tol)
{
  return (absoluteFuzzyGreaterEqual(var1, var2, tol*(std::abs(var1)+std::abs(var2))));
}

bool
relativeFuzzyGreaterThan(const Real & var1, const Real & var2, const Real & tol)
{
  return (absoluteFuzzyGreaterThan(var1, var2, tol*(std::abs(var1)+std::abs(var2))));
}

bool
relativeFuzzyLessEqual(const Real & var1, const Real & var2, const Real & tol)
{
  return (absoluteFuzzyLessEqual(var1, var2, tol*(std::abs(var1)+std::abs(var2))));
}

bool
relativeFuzzyLessThan(const Real & var1, const Real & var2, const Real & tol)
{
  return (absoluteFuzzyLessThan(var1, var2, tol*(std::abs(var1)+std::abs(var2))));
}

void
MaterialPropertyStorageDump(const HashMap<const libMesh::Elem *, HashMap<unsigned int, MaterialProperties> > & props)
{
  // Define the iterators
  HashMap<const Elem *, HashMap<unsigned int, MaterialProperties> >::const_iterator elem_it;
  HashMap<unsigned int, MaterialProperties>::const_iterator side_it;
  MaterialProperties::const_iterator prop_it;

  // Loop through the elements
  for (elem_it = props.begin(); elem_it != props.end(); ++elem_it)
  {
    Moose::out << "Element " << elem_it->first->id() << '\n';

    // Loop through the sides
    for (side_it = elem_it->second.begin(); side_it != elem_it->second.end(); ++side_it)
    {
      Moose::out << "  Side " << side_it->first << '\n';

      // Loop over properties
      unsigned int cnt = 0;
      for (prop_it = side_it->second.begin(); prop_it != side_it->second.end(); ++prop_it)
      {
        MaterialProperty<Real> * mp = dynamic_cast<MaterialProperty<Real> *>(*prop_it);
        if (mp)
        {
          Moose::out << "    Property " << cnt << '\n';
          cnt++;

          // Loop over quadrature points
          for (unsigned int qp = 0; qp < mp->size(); ++qp)
            Moose::out << "      prop[" << qp << "] = " << (*mp)[qp] << '\n';
        }
      }
    }
  }
}

} // MooseUtils namespace
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <cstring>
using namespace std;

void isPalin(const char *str) {
  int n = strlen(str);
  bool P[n][n];
  int i, j, L; // 表示字串的长度

  // 长度为1的都是回文
  for (i = 0; i < n; i++) {
    P[i][i] = true;
  }

  // 长度可能从2开始
  for (L = 2; L <= n; L++) {
    for (i = 0; i < n - L + 1; i++) {
      j = i + L - 1; // 设置结束的位置
      if (L == 2) // 长度为2的情况
        P[i][j] = (str[i] == str[j]);
      else //其他情况
        P[i][j] = (str[i] == str[j]) && P[i + 1][j - 1];
    }
  }

  int maxi = 0, maxj = 0, maxlen = 0;
  for (i = 0; i < n; i++) {
    for (j = i; j < n; j++) {
      if (P[i][j] && maxlen < j - i + 1) {
        maxi = i;
        maxj = j;
        maxlen = j - i + 1;
      }
    }
  }

  printf("The longest palin substr is ");
  for(i = maxi; i <= maxj; i++) {
    printf("%c", str[i]);
  }
  printf(", maxlen is %d\n\n", maxlen);

  cout << string(str + maxi, maxlen) << endl;

  return;
}

int main() {
  //isPalin("abccba");
  isPalin(string("abccba").c_str());

}
<commit_msg>add time space description<commit_after>#include <iostream>
#include <string>
#include <cstring>
using namespace std;

// Manacher算法，时间复杂度O(n), 空间复杂度O(n)

// DP: Time O(n^2) Space O(n^2)
void isPalin(const char *str) {
  int n = strlen(str);
  bool P[n][n];
  int i, j, L; // 表示字串的长度

  // 长度为1的都是回文
  for (i = 0; i < n; i++) {
    P[i][i] = true;
  }

  // 长度可能从2开始
  for (L = 2; L <= n; L++) {
    for (i = 0; i < n - L + 1; i++) {
      j = i + L - 1; // 设置结束的位置
      if (L == 2) // 长度为2的情况
        P[i][j] = (str[i] == str[j]);
      else //其他情况
        P[i][j] = (str[i] == str[j]) && P[i + 1][j - 1];
    }
  }

  int maxi = 0, maxj = 0, maxlen = 0;
  for (i = 0; i < n; i++) {
    for (j = i; j < n; j++) {
      if (P[i][j] && maxlen < j - i + 1) {
        maxi = i;
        maxj = j;
        maxlen = j - i + 1;
      }
    }
  }

  printf("The longest palin substr is ");
  for(i = maxi; i <= maxj; i++) {
    printf("%c", str[i]);
  }
  printf(", maxlen is %d\n\n", maxlen);

  cout << string(str + maxi, maxlen) << endl;

  return;
}

int main() {
  //isPalin("abccba");
  isPalin(string("abccba").c_str());

}
<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  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 of the License, or (at your option) any later version.
//
//  This library 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
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "OGLImagingContext.h"

#include "../base/Exception.h"

#include <assert.h>
#include <iostream>

namespace avg {

using namespace std;

#ifdef _WIN32
LONG WINAPI imagingWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

void registerWindowClass()
{
  static char * pClassName;
  if (pClassName) {
      return;
  }
  pClassName = "GLUT";

  HINSTANCE hInstance = GetModuleHandle(NULL);
  WNDCLASS  wc;
  memset(&wc, 0, sizeof(WNDCLASS));
  wc.style = CS_OWNDC;
  wc.lpfnWndProc = (WNDPROC)imagingWindowProc;
  wc.hInstance = hInstance;
  wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
  wc.hCursor = LoadCursor(hInstance, IDC_ARROW);
  wc.hbrBackground = NULL;
  wc.lpszMenuName = NULL;
  wc.lpszClassName = pClassName;

  BOOL bOK = RegisterClass(&wc);
  assert(bOK);
}
#endif

OGLImagingContext::OGLImagingContext(const IntPoint & size)
{
#ifdef __APPLE__
    GLint attributes[] = {AGL_RGBA, AGL_ALL_RENDERERS,AGL_NONE};
    AGLPixelFormat format;
    format = aglChoosePixelFormat(NULL, 0, attributes);
    assert(format);

    m_Context = aglCreateContext(format, NULL);
    assert(m_Context);
    aglDestroyPixelFormat(format);

    bool bOk = aglSetCurrentContext(m_Context);
    assert (bOk);
#else
#ifdef linux
    Display *dpy;
    dpy = XOpenDisplay(0);
    XVisualInfo *vi;
    static int attributes[] = {GLX_RGBA, 0};
    vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributes);
    m_Context = glXCreateContext(dpy, vi, 0, GL_TRUE);
    assert(m_Context);
    Pixmap pmp = XCreatePixmap(dpy, RootWindow(dpy, vi->screen),
            8, 8, vi->depth);
    GLXPixmap pixmap = glXCreateGLXPixmap(dpy, vi, pmp);
    glXMakeCurrent(dpy, pixmap, m_Context);
#else
#ifdef _WIN32
    registerWindowClass();
    m_hwnd = CreateWindow("GLUT", "GLUT",
            WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
            0, 0, 500, 300, 0, 0, GetModuleHandle(NULL), 0);
    winOGLErrorCheck(m_hDC != 0, "CreateWindow");

    m_hDC = GetDC(m_hwnd);
    winOGLErrorCheck(m_hDC != 0, "GetDC");

    PIXELFORMATDESCRIPTOR pfd;
    ZeroMemory(&pfd, sizeof(pfd));
    pfd.nSize = sizeof(pfd);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 32;
    pfd.cDepthBits = 32;
    pfd.iLayerType = PFD_MAIN_PLANE;

    int iFormat = ChoosePixelFormat(m_hDC, &pfd);
    winOGLErrorCheck(iFormat != 0, "ChoosePixelFormat");
    SetPixelFormat(m_hDC, iFormat, &pfd);
    m_Context = wglCreateContext(m_hDC);
    winOGLErrorCheck(m_Context != 0, "wglCreateContext");

    BOOL bOK = wglMakeCurrent(m_hDC, m_Context);
    winOGLErrorCheck(bOK, "wglMakeCurrent");
#endif
#endif
#endif
    glproc::init();

    if (!isSupported()) {
        throw Exception(AVG_ERR_VIDEO_GENERAL,
                "GPU imaging not supported by current OpenGL configuration.");
    }

    // Coordinates
    setSize(size);

    // Shading etc.
    glDisable(GL_BLEND);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glDisable(GL_BLEND)");
    glShadeModel(GL_FLAT);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glShadeModel(GL_FLAT)");
    glDisable(GL_DEPTH_TEST);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glDisable(GL_DEPTH_TEST)");
    glDisable(GL_STENCIL_TEST);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glDisable(GL_STENCIL_TEST)");

    // Texturing
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glTexEnvf()");
    glBlendFunc(GL_ONE, GL_ZERO);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glBlendFunc()");
    glEnable(GL_TEXTURE_RECTANGLE_ARB);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glEnable(GL_TEXTURE_RECTANGLE_ARB);");
    glDisable(GL_MULTISAMPLE);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glDisable(GL_MULTISAMPLE);");

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glPixelStorei(GL_PACK_ALIGNMENT, 1);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}

OGLImagingContext::~OGLImagingContext()
{
#ifdef __APPLE__
    if (m_Context) {
        aglSetCurrentContext(0);
        aglDestroyContext(m_Context);
        m_Context = 0;
    }
#endif
#ifdef _WIN32
    if (m_Context) {
        wglDeleteContext(m_Context);
        DeleteDC(m_hDC);
        DestroyWindow(m_hwnd);
    }
#endif
}

void OGLImagingContext::activate()
{
#ifdef __APPLE__
    bool bOk = aglSetCurrentContext(m_Context);
    assert(bOk);
#else
#endif
#ifdef _WIN32
	wglDeleteContext( m_Context );
#endif

}

void OGLImagingContext::setSize(const IntPoint& size)
{
    m_Size = size;
    glViewport(0, 0, m_Size.x, m_Size.y);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glViewport()");
    glMatrixMode(GL_PROJECTION);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glMatrixMode()");
    glLoadIdentity();
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glLoadIdentity()");
    gluOrtho2D(0, m_Size.x, m_Size.y, 0);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "gluOrtho2D()");
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glLoadIdentity()");
}

bool OGLImagingContext::isSupported()
{
    int glMajorVer;
    int glMinorVer;
    int slMajorVer;
    int slMinorVer;
    getGLVersion(glMajorVer, glMinorVer);
    getGLShadingLanguageVersion(slMajorVer, slMinorVer);
    // Not sure if we need shader version 1.2 as well - we'll see.
    return (glMajorVer > 1 && queryOGLExtension("GL_ARB_texture_rectangle") &&
            queryOGLExtension("GL_ARB_pixel_buffer_object") &&
            queryOGLExtension("GL_EXT_framebuffer_object"));
}

}

<commit_msg>Error instead of segfault in testgpu if X display is not available.<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  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 of the License, or (at your option) any later version.
//
//  This library 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
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "OGLImagingContext.h"

#include "../base/Exception.h"

#include <assert.h>
#include <iostream>

namespace avg {

using namespace std;

#ifdef _WIN32
LONG WINAPI imagingWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

void registerWindowClass()
{
  static char * pClassName;
  if (pClassName) {
      return;
  }
  pClassName = "GLUT";

  HINSTANCE hInstance = GetModuleHandle(NULL);
  WNDCLASS  wc;
  memset(&wc, 0, sizeof(WNDCLASS));
  wc.style = CS_OWNDC;
  wc.lpfnWndProc = (WNDPROC)imagingWindowProc;
  wc.hInstance = hInstance;
  wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
  wc.hCursor = LoadCursor(hInstance, IDC_ARROW);
  wc.hbrBackground = NULL;
  wc.lpszMenuName = NULL;
  wc.lpszClassName = pClassName;

  BOOL bOK = RegisterClass(&wc);
  assert(bOK);
}
#endif

OGLImagingContext::OGLImagingContext(const IntPoint & size)
{
#ifdef __APPLE__
    GLint attributes[] = {AGL_RGBA, AGL_ALL_RENDERERS,AGL_NONE};
    AGLPixelFormat format;
    format = aglChoosePixelFormat(NULL, 0, attributes);
    assert(format);

    m_Context = aglCreateContext(format, NULL);
    assert(m_Context);
    aglDestroyPixelFormat(format);

    bool bOk = aglSetCurrentContext(m_Context);
    assert (bOk);
#else
#ifdef linux
    Display *dpy;
    dpy = XOpenDisplay(0);
    if (!dpy) {
        throw Exception(AVG_ERR_VIDEO_GENERAL, "No X windows display available.");
    }
    XVisualInfo *vi;
    static int attributes[] = {GLX_RGBA, 0};
    vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributes);
    m_Context = glXCreateContext(dpy, vi, 0, GL_TRUE);
    assert(m_Context);
    Pixmap pmp = XCreatePixmap(dpy, RootWindow(dpy, vi->screen),
            8, 8, vi->depth);
    GLXPixmap pixmap = glXCreateGLXPixmap(dpy, vi, pmp);
    glXMakeCurrent(dpy, pixmap, m_Context);
#else
#ifdef _WIN32
    registerWindowClass();
    m_hwnd = CreateWindow("GLUT", "GLUT",
            WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
            0, 0, 500, 300, 0, 0, GetModuleHandle(NULL), 0);
    winOGLErrorCheck(m_hDC != 0, "CreateWindow");

    m_hDC = GetDC(m_hwnd);
    winOGLErrorCheck(m_hDC != 0, "GetDC");

    PIXELFORMATDESCRIPTOR pfd;
    ZeroMemory(&pfd, sizeof(pfd));
    pfd.nSize = sizeof(pfd);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 32;
    pfd.cDepthBits = 32;
    pfd.iLayerType = PFD_MAIN_PLANE;

    int iFormat = ChoosePixelFormat(m_hDC, &pfd);
    winOGLErrorCheck(iFormat != 0, "ChoosePixelFormat");
    SetPixelFormat(m_hDC, iFormat, &pfd);
    m_Context = wglCreateContext(m_hDC);
    winOGLErrorCheck(m_Context != 0, "wglCreateContext");

    BOOL bOK = wglMakeCurrent(m_hDC, m_Context);
    winOGLErrorCheck(bOK, "wglMakeCurrent");
#endif
#endif
#endif
    glproc::init();

    if (!isSupported()) {
        throw Exception(AVG_ERR_VIDEO_GENERAL,
                "GPU imaging not supported by current OpenGL configuration.");
    }

    // Coordinates
    setSize(size);

    // Shading etc.
    glDisable(GL_BLEND);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glDisable(GL_BLEND)");
    glShadeModel(GL_FLAT);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glShadeModel(GL_FLAT)");
    glDisable(GL_DEPTH_TEST);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glDisable(GL_DEPTH_TEST)");
    glDisable(GL_STENCIL_TEST);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glDisable(GL_STENCIL_TEST)");

    // Texturing
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glTexEnvf()");
    glBlendFunc(GL_ONE, GL_ZERO);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glBlendFunc()");
    glEnable(GL_TEXTURE_RECTANGLE_ARB);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glEnable(GL_TEXTURE_RECTANGLE_ARB);");
    glDisable(GL_MULTISAMPLE);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glDisable(GL_MULTISAMPLE);");

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glPixelStorei(GL_PACK_ALIGNMENT, 1);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}

OGLImagingContext::~OGLImagingContext()
{
#ifdef __APPLE__
    if (m_Context) {
        aglSetCurrentContext(0);
        aglDestroyContext(m_Context);
        m_Context = 0;
    }
#endif
#ifdef _WIN32
    if (m_Context) {
        wglDeleteContext(m_Context);
        DeleteDC(m_hDC);
        DestroyWindow(m_hwnd);
    }
#endif
}

void OGLImagingContext::activate()
{
#ifdef __APPLE__
    bool bOk = aglSetCurrentContext(m_Context);
    assert(bOk);
#else
#endif
#ifdef _WIN32
	wglDeleteContext( m_Context );
#endif

}

void OGLImagingContext::setSize(const IntPoint& size)
{
    m_Size = size;
    glViewport(0, 0, m_Size.x, m_Size.y);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glViewport()");
    glMatrixMode(GL_PROJECTION);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glMatrixMode()");
    glLoadIdentity();
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glLoadIdentity()");
    gluOrtho2D(0, m_Size.x, m_Size.y, 0);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "gluOrtho2D()");
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "glLoadIdentity()");
}

bool OGLImagingContext::isSupported()
{
    int glMajorVer;
    int glMinorVer;
    int slMajorVer;
    int slMinorVer;
    getGLVersion(glMajorVer, glMinorVer);
    getGLShadingLanguageVersion(slMajorVer, slMinorVer);
    // Not sure if we need shader version 1.2 as well - we'll see.
    return (glMajorVer > 1 && queryOGLExtension("GL_ARB_texture_rectangle") &&
            queryOGLExtension("GL_ARB_pixel_buffer_object") &&
            queryOGLExtension("GL_EXT_framebuffer_object"));
}

}

<|endoftext|>


<commit_before>#include "tabs/image-preview.h"
#include <QDir>
#include <QEventLoop>
#include <QFile>
#include <QFileDialog>
#include <QLabel>
#include <QMenu>
#include <QMovie>
#include <QRandomGenerator>
#include <QSettings>
#include <QtMath>
#include <QUrl>
#include <QVBoxLayout>
#include <QWidget>
#include "downloader/download-queue.h"
#include "downloader/image-downloader.h"
#include "functions.h"
#include "helpers.h"
#include "image-context-menu.h"
#include "logger.h"
#include "models/image.h"
#include "models/profile.h"
#include "models/site.h"
#include "network/network-reply.h"
#include "ui/QBouton.h"

QMovie *ImagePreview::m_loadingMovie = nullptr;

ImagePreview::ImagePreview(QSharedPointer<Image> image, QWidget *container, Profile *profile, DownloadQueue *downloadQueue, MainWindow *mainWindow, QObject *parent)
	: QObject(parent), m_image(image), m_container(container), m_profile(profile), m_downloadQueue(downloadQueue), m_mainWindow(mainWindow)
{
	m_thumbnailUrl = image->url(Image::Size::Thumbnail);
	m_name = image->name();
	m_childrenCount = image->counter().toInt();

	auto *layout = new QVBoxLayout();
	layout->setContentsMargins(0, 0, 0, 0);
	container->setLayout(layout);

	container->setContextMenuPolicy(Qt::CustomContextMenu);
	connect(container, &QWidget::customContextMenuRequested, this, &ImagePreview::customContextMenuRequested);
}

ImagePreview::~ImagePreview()
{
	m_reply->deleteLater();
	m_reply = nullptr;
}

void ImagePreview::showLoadingMessage()
{
	if (m_loadingMovie == nullptr) {
		auto *loadingMovie = new QMovie(":/images/loading.gif");
		if (m_loadingMovie == nullptr) {
			m_loadingMovie = loadingMovie;
			m_loadingMovie->start();
		} else {
			loadingMovie->deleteLater();
		}
	}

	auto *loadingLabel = new QLabel();
	loadingLabel->setMovie(m_loadingMovie);
	loadingLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
	loadingLabel->setScaledContents(true);

	auto *layout = m_container->layout();
	layout->addWidget(loadingLabel);
}

void ImagePreview::load()
{
	if (m_thumbnailUrl.isValid()) {
		if (m_reply != nullptr) {
			m_reply->deleteLater();
		} else {
			showLoadingMessage();
		}

		Site *site = m_image->parentSite();
		m_reply = site->get(site->fixUrl(m_thumbnailUrl.toString()), Site::QueryType::Thumbnail, m_image->parentUrl(), "preview");
		connect(m_reply, &NetworkReply::finished, this, &ImagePreview::finishedLoadingPreview);
	} else {
		finishedLoading();
	}
}

void ImagePreview::abort()
{
	m_aborted = true;
	if (m_reply->isRunning()) {
		m_reply->abort();
	}
}

void ImagePreview::setChecked(bool checked)
{
	m_checked = checked;

	if (m_bouton != nullptr) {
		m_bouton->setChecked(checked);
	}
}

void ImagePreview::setDownloadProgress(qint64 v1, qint64 v2)
{
	if (m_bouton != nullptr) {
		m_bouton->setProgress(v1, v2);
	}
}

void ImagePreview::finishedLoadingPreview()
{
	if (m_aborted) {
		return;
	}

	// Aborted
	if (m_reply->error() == NetworkReply::NetworkError::OperationCanceledError) {
		return;
	}

	// Check redirection
	QUrl redirection = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
	if (!redirection.isEmpty()) {
		m_thumbnailUrl = redirection;
		load();
		return;
	}

	// Loading error
	if (m_reply->error() != NetworkReply::NetworkError::NoError) {
		const QString ext = getExtension(m_reply->url());
		if (ext != "jpg") {
			log(QStringLiteral("Error loading thumbnail (%1), new try with extension JPG").arg(m_reply->errorString()), Logger::Warning);
			m_thumbnailUrl = setExtension(m_reply->url(), "jpg");
			load();
		} else {
			log(QStringLiteral("Error loading thumbnail (%1)").arg(m_reply->errorString()), Logger::Error);
		}
		return;
	}

	// Load preview from result
	QPixmap thumbnail;
	thumbnail.loadFromData(m_reply->readAll());
	if (thumbnail.isNull()) {
		log(QStringLiteral("One of the thumbnails is empty (`%1`).").arg(m_image->url(Image::Size::Thumbnail).toString()), Logger::Error);
		if (m_image->hasTag(QStringLiteral("flash"))) {
			thumbnail.load(QStringLiteral(":/images/flash.png"));
		} else {
			return;
		}
	}
	m_image->setPreviewImage(thumbnail);

	finishedLoading();
}

void ImagePreview::finishedLoading()
{
	auto *layout = m_container->layout();

	clearLayout(layout);

	if (m_reply != nullptr) {
		QSettings *settings = m_profile->getSettings();
		const bool resizeInsteadOfCropping = settings->value("resizeInsteadOfCropping", true).toBool();
		const bool resultsScrollArea = settings->value("resultsScrollArea", true).toBool();
		const int borderSize = settings->value("borders", 3).toInt();
		const qreal upscale = settings->value("thumbnailUpscale", 1.0).toDouble();
		const int imageSize = qFloor(150 * upscale);

		QBouton *l = new QBouton(0, resizeInsteadOfCropping, resultsScrollArea, borderSize, m_image->color(), m_container);
		l->setCheckable(true);
		l->setFlat(true);
		l->setChecked(m_checked);
		l->setInvertToggle(settings->value("invertToggle", false).toBool());
		l->setToolTip(m_image->tooltip());

		const QPixmap &thumbnail = m_image->previewImage();
		if (thumbnail.isNull()) {
			l->scale(QPixmap(":/images/noimage.png"), QSize(imageSize, imageSize));
		} else {
			l->scale(thumbnail, QSize(imageSize, imageSize));
		}
		if (m_childrenCount > 0) {
			l->setCounter(QString::number(m_childrenCount));
		}

		connect(l, SIGNAL(appui(int)), this, SIGNAL(clicked()));
		connect(l, SIGNAL(toggled(int, bool, bool)), this, SLOT(toggledWithId(int, bool, bool)));

		layout->addWidget(l);
		m_bouton = l;
	}

	if (!m_name.isEmpty()) {
		layout->addWidget(new QLabel(m_name));
	}

	emit finished();
}

void ImagePreview::toggledWithId(int id, bool toggle, bool range)
{
	Q_UNUSED(id);

	emit toggled(toggle, range);
}

QStringList getImageAlreadyExists(const QSharedPointer<Image> &img, Profile *profile)
{
	QSettings *settings = profile->getSettings();
	const QString path = settings->value("Save/path").toString().replace("\\", "/");
	const QString fn = settings->value("Save/filename").toString();

	if (Filename(fn).needExactTags(img->parentSite(), settings) == 0) {
		QStringList ret;
		QStringList files = img->paths(fn, path, 0);
		for (const QString &file : files) {
			if (QFile(file).exists()) {
				ret.append(file);
			}
		}
		if (!ret.isEmpty()) {
			return ret;
		}
	}

	return profile->md5Exists(img->md5());
}

void ImagePreview::customContextMenuRequested()
{
	QMenu *menu = new ImageContextMenu(m_profile->getSettings(), m_image, m_mainWindow, m_container);
	QAction *first = menu->actions().first();

	// Save image
	QAction *actionSave;
	if (!getImageAlreadyExists(m_image, m_profile).isEmpty()) {
		actionSave = new QAction(QIcon(":/images/status/error.png"), tr("Delete"), menu);
	} else {
		actionSave = new QAction(QIcon(":/images/icons/save.png"), tr("Save"), menu);
	}
	connect(actionSave, &QAction::triggered, this, &ImagePreview::contextSaveImage);
	menu->insertAction(first, actionSave);

	// Save image as...
	QAction *actionSaveAs = new QAction(QIcon(":/images/icons/save-as.png"), tr("Save as..."), menu);
	connect(actionSaveAs, &QAction::triggered, this, &ImagePreview::contextSaveImageAs);
	menu->insertAction(first, actionSaveAs);

	// Custom elements
	if (m_customContextMenu != nullptr) {
		m_customContextMenu(menu, m_image);
	}

	menu->insertSeparator(first);

	menu->exec(QCursor::pos());
}

void ImagePreview::contextSaveImage()
{
	QStringList already = getImageAlreadyExists(m_image, m_profile);
	if (!already.isEmpty()) {
		for (const QString &path : already) {
			QFile(path).remove();
			m_profile->removeMd5(m_image->md5(), path);
		}
	} else {
		QSettings *settings = m_profile->getSettings();
		const QString fn = settings->value("Save/filename").toString();
		const QString path = settings->value("Save/path").toString();

		auto downloader = new ImageDownloader(m_profile, m_image, fn, path, 1, true, true, m_downloadQueue);
		connect(downloader, &ImageDownloader::downloadProgress, this, &ImagePreview::contextSaveImageProgress);
		m_downloadQueue->add(DownloadQueue::Manual, downloader);
	}
}

void ImagePreview::contextSaveImageAs()
{
	QSettings *settings = m_profile->getSettings();

	Filename format(settings->value("Save/filename").toString());
	QString tmpPath;

	// If the MD5 is required for the filename, we first download the image
	if (format.needTemporaryFile(m_image->tokens(m_profile))) {
		tmpPath = QDir::temp().absoluteFilePath("grabber-saveAs-" + QString::number(QRandomGenerator::global()->generate(), 16));

		QEventLoop loop;
		ImageDownloader downloader(m_profile, m_image, { tmpPath }, 1, true, true, this);
		connect(&downloader, &ImageDownloader::saved, &loop, &QEventLoop::quit);
		downloader.save();
		loop.exec();
	}

	const QStringList filenames = format.path(*m_image, m_profile);
	const QString filename = filenames.first().section(QDir::separator(), -1);
	const QString lastDir = settings->value("Zoom/lastDir").toString();

	QString path = QFileDialog::getSaveFileName(m_container, tr("Save image"), QDir::toNativeSeparators(lastDir + "/" + filename), "Images (*.png *.gif *.jpg *.jpeg)");
	if (!path.isEmpty()) {
		path = QDir::toNativeSeparators(path);
		settings->setValue("Zoom/lastDir", path.section(QDir::separator(), 0, -2));

		if (!tmpPath.isEmpty()) {
			QFile::rename(tmpPath, path);
		} else {
			auto downloader = new ImageDownloader(m_profile, m_image, { path }, 1, true, true, this, true, false, Image::Size::Unknown, true, true);
			connect(downloader, &ImageDownloader::downloadProgress, this, &ImagePreview::contextSaveImageProgress);
			m_downloadQueue->add(DownloadQueue::Manual, downloader);
		}
	} else if (!tmpPath.isEmpty()) {
		QFile::remove(tmpPath);
	}
}

void ImagePreview::contextSaveImageProgress(const QSharedPointer<Image> &img, qint64 v1, qint64 v2)
{
	Q_UNUSED(img);
	setDownloadProgress(v1, v2);
}

void ImagePreview::setCustomContextMenu(std::function<void (QMenu *, const QSharedPointer<Image> &)> customContextMenu)
{
	m_customContextMenu = customContextMenu;
}
<commit_msg>Load tags before 'save as...' when necessary (fix #2234)<commit_after>#include "tabs/image-preview.h"
#include <QDir>
#include <QEventLoop>
#include <QFile>
#include <QFileDialog>
#include <QLabel>
#include <QMenu>
#include <QMovie>
#include <QRandomGenerator>
#include <QSettings>
#include <QtMath>
#include <QUrl>
#include <QVBoxLayout>
#include <QWidget>
#include "downloader/download-queue.h"
#include "downloader/image-downloader.h"
#include "functions.h"
#include "helpers.h"
#include "image-context-menu.h"
#include "logger.h"
#include "models/image.h"
#include "models/profile.h"
#include "models/site.h"
#include "network/network-reply.h"
#include "ui/QBouton.h"

QMovie *ImagePreview::m_loadingMovie = nullptr;

ImagePreview::ImagePreview(QSharedPointer<Image> image, QWidget *container, Profile *profile, DownloadQueue *downloadQueue, MainWindow *mainWindow, QObject *parent)
	: QObject(parent), m_image(image), m_container(container), m_profile(profile), m_downloadQueue(downloadQueue), m_mainWindow(mainWindow)
{
	m_thumbnailUrl = image->url(Image::Size::Thumbnail);
	m_name = image->name();
	m_childrenCount = image->counter().toInt();

	auto *layout = new QVBoxLayout();
	layout->setContentsMargins(0, 0, 0, 0);
	container->setLayout(layout);

	container->setContextMenuPolicy(Qt::CustomContextMenu);
	connect(container, &QWidget::customContextMenuRequested, this, &ImagePreview::customContextMenuRequested);
}

ImagePreview::~ImagePreview()
{
	m_reply->deleteLater();
	m_reply = nullptr;
}

void ImagePreview::showLoadingMessage()
{
	if (m_loadingMovie == nullptr) {
		auto *loadingMovie = new QMovie(":/images/loading.gif");
		if (m_loadingMovie == nullptr) {
			m_loadingMovie = loadingMovie;
			m_loadingMovie->start();
		} else {
			loadingMovie->deleteLater();
		}
	}

	auto *loadingLabel = new QLabel();
	loadingLabel->setMovie(m_loadingMovie);
	loadingLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
	loadingLabel->setScaledContents(true);

	auto *layout = m_container->layout();
	layout->addWidget(loadingLabel);
}

void ImagePreview::load()
{
	if (m_thumbnailUrl.isValid()) {
		if (m_reply != nullptr) {
			m_reply->deleteLater();
		} else {
			showLoadingMessage();
		}

		Site *site = m_image->parentSite();
		m_reply = site->get(site->fixUrl(m_thumbnailUrl.toString()), Site::QueryType::Thumbnail, m_image->parentUrl(), "preview");
		connect(m_reply, &NetworkReply::finished, this, &ImagePreview::finishedLoadingPreview);
	} else {
		finishedLoading();
	}
}

void ImagePreview::abort()
{
	m_aborted = true;
	if (m_reply->isRunning()) {
		m_reply->abort();
	}
}

void ImagePreview::setChecked(bool checked)
{
	m_checked = checked;

	if (m_bouton != nullptr) {
		m_bouton->setChecked(checked);
	}
}

void ImagePreview::setDownloadProgress(qint64 v1, qint64 v2)
{
	if (m_bouton != nullptr) {
		m_bouton->setProgress(v1, v2);
	}
}

void ImagePreview::finishedLoadingPreview()
{
	if (m_aborted) {
		return;
	}

	// Aborted
	if (m_reply->error() == NetworkReply::NetworkError::OperationCanceledError) {
		return;
	}

	// Check redirection
	QUrl redirection = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
	if (!redirection.isEmpty()) {
		m_thumbnailUrl = redirection;
		load();
		return;
	}

	// Loading error
	if (m_reply->error() != NetworkReply::NetworkError::NoError) {
		const QString ext = getExtension(m_reply->url());
		if (ext != "jpg") {
			log(QStringLiteral("Error loading thumbnail (%1), new try with extension JPG").arg(m_reply->errorString()), Logger::Warning);
			m_thumbnailUrl = setExtension(m_reply->url(), "jpg");
			load();
		} else {
			log(QStringLiteral("Error loading thumbnail (%1)").arg(m_reply->errorString()), Logger::Error);
		}
		return;
	}

	// Load preview from result
	QPixmap thumbnail;
	thumbnail.loadFromData(m_reply->readAll());
	if (thumbnail.isNull()) {
		log(QStringLiteral("One of the thumbnails is empty (`%1`).").arg(m_image->url(Image::Size::Thumbnail).toString()), Logger::Error);
		if (m_image->hasTag(QStringLiteral("flash"))) {
			thumbnail.load(QStringLiteral(":/images/flash.png"));
		} else {
			return;
		}
	}
	m_image->setPreviewImage(thumbnail);

	finishedLoading();
}

void ImagePreview::finishedLoading()
{
	auto *layout = m_container->layout();

	clearLayout(layout);

	if (m_reply != nullptr) {
		QSettings *settings = m_profile->getSettings();
		const bool resizeInsteadOfCropping = settings->value("resizeInsteadOfCropping", true).toBool();
		const bool resultsScrollArea = settings->value("resultsScrollArea", true).toBool();
		const int borderSize = settings->value("borders", 3).toInt();
		const qreal upscale = settings->value("thumbnailUpscale", 1.0).toDouble();
		const int imageSize = qFloor(150 * upscale);

		QBouton *l = new QBouton(0, resizeInsteadOfCropping, resultsScrollArea, borderSize, m_image->color(), m_container);
		l->setCheckable(true);
		l->setFlat(true);
		l->setChecked(m_checked);
		l->setInvertToggle(settings->value("invertToggle", false).toBool());
		l->setToolTip(m_image->tooltip());

		const QPixmap &thumbnail = m_image->previewImage();
		if (thumbnail.isNull()) {
			l->scale(QPixmap(":/images/noimage.png"), QSize(imageSize, imageSize));
		} else {
			l->scale(thumbnail, QSize(imageSize, imageSize));
		}
		if (m_childrenCount > 0) {
			l->setCounter(QString::number(m_childrenCount));
		}

		connect(l, SIGNAL(appui(int)), this, SIGNAL(clicked()));
		connect(l, SIGNAL(toggled(int, bool, bool)), this, SLOT(toggledWithId(int, bool, bool)));

		layout->addWidget(l);
		m_bouton = l;
	}

	if (!m_name.isEmpty()) {
		layout->addWidget(new QLabel(m_name));
	}

	emit finished();
}

void ImagePreview::toggledWithId(int id, bool toggle, bool range)
{
	Q_UNUSED(id);

	emit toggled(toggle, range);
}

QStringList getImageAlreadyExists(const QSharedPointer<Image> &img, Profile *profile)
{
	QSettings *settings = profile->getSettings();
	const QString path = settings->value("Save/path").toString().replace("\\", "/");
	const QString fn = settings->value("Save/filename").toString();

	if (Filename(fn).needExactTags(img->parentSite(), settings) == 0) {
		QStringList ret;
		QStringList files = img->paths(fn, path, 0);
		for (const QString &file : files) {
			if (QFile(file).exists()) {
				ret.append(file);
			}
		}
		if (!ret.isEmpty()) {
			return ret;
		}
	}

	return profile->md5Exists(img->md5());
}

void ImagePreview::customContextMenuRequested()
{
	QMenu *menu = new ImageContextMenu(m_profile->getSettings(), m_image, m_mainWindow, m_container);
	QAction *first = menu->actions().first();

	// Save image
	QAction *actionSave;
	if (!getImageAlreadyExists(m_image, m_profile).isEmpty()) {
		actionSave = new QAction(QIcon(":/images/status/error.png"), tr("Delete"), menu);
	} else {
		actionSave = new QAction(QIcon(":/images/icons/save.png"), tr("Save"), menu);
	}
	connect(actionSave, &QAction::triggered, this, &ImagePreview::contextSaveImage);
	menu->insertAction(first, actionSave);

	// Save image as...
	QAction *actionSaveAs = new QAction(QIcon(":/images/icons/save-as.png"), tr("Save as..."), menu);
	connect(actionSaveAs, &QAction::triggered, this, &ImagePreview::contextSaveImageAs);
	menu->insertAction(first, actionSaveAs);

	// Custom elements
	if (m_customContextMenu != nullptr) {
		m_customContextMenu(menu, m_image);
	}

	menu->insertSeparator(first);

	menu->exec(QCursor::pos());
}

void ImagePreview::contextSaveImage()
{
	QStringList already = getImageAlreadyExists(m_image, m_profile);
	if (!already.isEmpty()) {
		for (const QString &path : already) {
			QFile(path).remove();
			m_profile->removeMd5(m_image->md5(), path);
		}
	} else {
		QSettings *settings = m_profile->getSettings();
		const QString fn = settings->value("Save/filename").toString();
		const QString path = settings->value("Save/path").toString();

		auto downloader = new ImageDownloader(m_profile, m_image, fn, path, 1, true, true, m_downloadQueue);
		connect(downloader, &ImageDownloader::downloadProgress, this, &ImagePreview::contextSaveImageProgress);
		m_downloadQueue->add(DownloadQueue::Manual, downloader);
	}
}

void ImagePreview::contextSaveImageAs()
{
	QSettings *settings = m_profile->getSettings();

	Filename format(settings->value("Save/filename").toString());
	QString tmpPath;

	// If we need detailed tags for the filename, we first load them
	const int needTags = format.needExactTags(m_image->parentSite(), settings);
	if (needTags == 2 || (needTags == 1 && m_image->hasUnknownTag())) {
		QEventLoop loop;
		m_image->loadDetails();
		connect(m_image.data(), &Image::finishedLoadingTags, &loop, &QEventLoop::quit);
		loop.exec();
	}

	// If the MD5 is required for the filename, we first download the image
	if (format.needTemporaryFile(m_image->tokens(m_profile))) {
		tmpPath = QDir::temp().absoluteFilePath("grabber-saveAs-" + QString::number(QRandomGenerator::global()->generate(), 16));

		QEventLoop loop;
		ImageDownloader downloader(m_profile, m_image, { tmpPath }, 1, true, true, this);
		connect(&downloader, &ImageDownloader::saved, &loop, &QEventLoop::quit);
		downloader.save();
		loop.exec();
	}

	const QStringList filenames = format.path(*m_image, m_profile);
	const QString filename = filenames.first().section(QDir::separator(), -1);
	const QString lastDir = settings->value("Zoom/lastDir").toString();

	QString path = QFileDialog::getSaveFileName(m_container, tr("Save image"), QDir::toNativeSeparators(lastDir + "/" + filename), "Images (*.png *.gif *.jpg *.jpeg)");
	if (!path.isEmpty()) {
		path = QDir::toNativeSeparators(path);
		settings->setValue("Zoom/lastDir", path.section(QDir::separator(), 0, -2));

		if (!tmpPath.isEmpty()) {
			QFile::rename(tmpPath, path);
		} else {
			auto downloader = new ImageDownloader(m_profile, m_image, { path }, 1, true, true, this, true, false, Image::Size::Unknown, true, true);
			connect(downloader, &ImageDownloader::downloadProgress, this, &ImagePreview::contextSaveImageProgress);
			m_downloadQueue->add(DownloadQueue::Manual, downloader);
		}
	} else if (!tmpPath.isEmpty()) {
		QFile::remove(tmpPath);
	}
}

void ImagePreview::contextSaveImageProgress(const QSharedPointer<Image> &img, qint64 v1, qint64 v2)
{
	Q_UNUSED(img);
	setDownloadProgress(v1, v2);
}

void ImagePreview::setCustomContextMenu(std::function<void (QMenu *, const QSharedPointer<Image> &)> customContextMenu)
{
	m_customContextMenu = customContextMenu;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017-2018 Baidu Inc.
 *
 * 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 "openrasp_inject.h"
#include "openrasp_ini.h"
#include <string>
#include <vector>
#include <fstream>
#include <chrono>
#include <new>

ZEND_DECLARE_MODULE_GLOBALS(openrasp_inject)
std::vector<char> inject_html;

void openrasp_load_inject_html(TSRMLS_D)
{
    std::vector<char> inject;
    char *path;
    spprintf(&path, 0, "%s%cassets%cinject.html", openrasp_ini.root_dir, DEFAULT_SLASH, DEFAULT_SLASH);
    std::ifstream file(path, std::ios::binary | std::ios::ate);
    efree(path);
    if (file.is_open())
    {
        std::streamsize size = file.tellg();
        file.seekg(0, std::ios::beg);
        inject.resize(size);
        file.read(inject.data(), size);
    }
    inject_html = std::move(inject);
}

PHP_GINIT_FUNCTION(openrasp_inject)
{
#ifdef ZTS
    new (openrasp_inject_globals) _zend_openrasp_inject_globals;
#endif
}

PHP_GSHUTDOWN_FUNCTION(openrasp_inject)
{
#ifdef ZTS
    openrasp_inject_globals->~_zend_openrasp_inject_globals();
#endif
}

PHP_MINIT_FUNCTION(openrasp_inject)
{
    ZEND_INIT_MODULE_GLOBALS(openrasp_inject, PHP_GINIT(openrasp_inject), PHP_GSHUTDOWN(openrasp_inject));
    openrasp_load_inject_html(TSRMLS_C);
    return SUCCESS;
}

PHP_MSHUTDOWN_FUNCTION(openrasp_inject)
{
    ZEND_SHUTDOWN_MODULE_GLOBALS(openrasp_inject, PHP_GSHUTDOWN(openrasp_inject));
    return SUCCESS;
}

PHP_RINIT_FUNCTION(openrasp_inject)
{
    {
        auto time_point = std::chrono::steady_clock::now();
        long long nano = time_point.time_since_epoch().count();
        unsigned long hash = zend_inline_hash_func(reinterpret_cast<const char *>(&nano), sizeof(nano));
        spprintf(&OPENRASP_INJECT_G(request_id), 32, "%016lx%016llx", hash, nano);
        char *uuid_header = nullptr;
        int uuid_header_len = spprintf(&uuid_header, 0, "X-Request-ID: %s", OPENRASP_INJECT_G(request_id));
        if (uuid_header)
        {
            sapi_header_line header;
            header.line = uuid_header;
            header.line_len = uuid_header_len;
            header.response_code = 0;
            sapi_header_op(SAPI_HEADER_REPLACE, &header TSRMLS_CC);
        }
        efree(uuid_header);
    }
    {
        sapi_header_line header;
        header.line = "X-Protected-By: OpenRASP";
        header.line_len = sizeof("X-Protected-By: OpenRASP") - 1;
        header.response_code = 0;
        sapi_header_op(SAPI_HEADER_REPLACE, &header TSRMLS_CC);
    }
    return SUCCESS;
}
PHP_RSHUTDOWN_FUNCTION(openrasp_inject)
{
    static const char REQUEST_URI[] = "REQUEST_URI";
    static const ulong REQUEST_URI_HASH = zend_get_hash_value(ZEND_STRS(REQUEST_URI));
    if (inject_html.size())
    {
        bool is_match_inject_prefix = true;
        if (openrasp_ini.inject_html_urlprefix && strlen(openrasp_ini.inject_html_urlprefix) > 0)
        {
            is_match_inject_prefix = false;
            if (PG(http_globals)[TRACK_VARS_SERVER] || zend_is_auto_global(ZEND_STRL("_SERVER") TSRMLS_CC))
            {
                zval **value;
                if (zend_hash_quick_find(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]), ZEND_STRS(REQUEST_URI), REQUEST_URI_HASH, (void **)&value) == SUCCESS &&
                    Z_TYPE_PP(value) == IS_STRING &&
                    strncasecmp(Z_STRVAL_PP(value), openrasp_ini.inject_html_urlprefix, strlen(openrasp_ini.inject_html_urlprefix)) == 0)
                {
                    is_match_inject_prefix = true;
                }
            }
        }
        if (is_match_inject_prefix)
        {
            char target_header[] = "text/html";
            for (zend_llist_element *element = SG(sapi_headers).headers.head; element; element = element->next)
            {
                sapi_header_struct *sapi_header = (sapi_header_struct *)element->data;
                if (sapi_header->header_len > 0 &&
                    strncasecmp(sapi_header->header, "content-type", sizeof("content-type") - 1) == 0 &&
                    php_stristr(sapi_header->header, target_header, sapi_header->header_len, strlen(target_header)) != nullptr)
                {
#if PHP_MINOR_VERSION > 3
                    php_output_write(inject_html.data(), inject_html.size() TSRMLS_CC);
#else
                    php_body_write(inject_html.data(), inject_html.size() TSRMLS_CC);
#endif
                    break;
                }
            }
        }
    }
    efree(OPENRASP_INJECT_G(request_id));
    return SUCCESS;
}<commit_msg>[PHP5]is_match_inject_prefix 初始值<commit_after>/*
 * Copyright 2017-2018 Baidu Inc.
 *
 * 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 "openrasp_inject.h"
#include "openrasp_ini.h"
#include <string>
#include <vector>
#include <fstream>
#include <chrono>
#include <new>

ZEND_DECLARE_MODULE_GLOBALS(openrasp_inject)
std::vector<char> inject_html;

void openrasp_load_inject_html(TSRMLS_D)
{
    std::vector<char> inject;
    char *path;
    spprintf(&path, 0, "%s%cassets%cinject.html", openrasp_ini.root_dir, DEFAULT_SLASH, DEFAULT_SLASH);
    std::ifstream file(path, std::ios::binary | std::ios::ate);
    efree(path);
    if (file.is_open())
    {
        std::streamsize size = file.tellg();
        file.seekg(0, std::ios::beg);
        inject.resize(size);
        file.read(inject.data(), size);
    }
    inject_html = std::move(inject);
}

PHP_GINIT_FUNCTION(openrasp_inject)
{
#ifdef ZTS
    new (openrasp_inject_globals) _zend_openrasp_inject_globals;
#endif
}

PHP_GSHUTDOWN_FUNCTION(openrasp_inject)
{
#ifdef ZTS
    openrasp_inject_globals->~_zend_openrasp_inject_globals();
#endif
}

PHP_MINIT_FUNCTION(openrasp_inject)
{
    ZEND_INIT_MODULE_GLOBALS(openrasp_inject, PHP_GINIT(openrasp_inject), PHP_GSHUTDOWN(openrasp_inject));
    openrasp_load_inject_html(TSRMLS_C);
    return SUCCESS;
}

PHP_MSHUTDOWN_FUNCTION(openrasp_inject)
{
    ZEND_SHUTDOWN_MODULE_GLOBALS(openrasp_inject, PHP_GSHUTDOWN(openrasp_inject));
    return SUCCESS;
}

PHP_RINIT_FUNCTION(openrasp_inject)
{
    {
        auto time_point = std::chrono::steady_clock::now();
        long long nano = time_point.time_since_epoch().count();
        unsigned long hash = zend_inline_hash_func(reinterpret_cast<const char *>(&nano), sizeof(nano));
        spprintf(&OPENRASP_INJECT_G(request_id), 32, "%016lx%016llx", hash, nano);
        char *uuid_header = nullptr;
        int uuid_header_len = spprintf(&uuid_header, 0, "X-Request-ID: %s", OPENRASP_INJECT_G(request_id));
        if (uuid_header)
        {
            sapi_header_line header;
            header.line = uuid_header;
            header.line_len = uuid_header_len;
            header.response_code = 0;
            sapi_header_op(SAPI_HEADER_REPLACE, &header TSRMLS_CC);
        }
        efree(uuid_header);
    }
    {
        sapi_header_line header;
        header.line = "X-Protected-By: OpenRASP";
        header.line_len = sizeof("X-Protected-By: OpenRASP") - 1;
        header.response_code = 0;
        sapi_header_op(SAPI_HEADER_REPLACE, &header TSRMLS_CC);
    }
    return SUCCESS;
}
PHP_RSHUTDOWN_FUNCTION(openrasp_inject)
{
    static const char REQUEST_URI[] = "REQUEST_URI";
    static const ulong REQUEST_URI_HASH = zend_get_hash_value(ZEND_STRS(REQUEST_URI));
    if (inject_html.size())
    {
        bool is_match_inject_prefix = false;
        if (openrasp_ini.inject_html_urlprefix && strlen(openrasp_ini.inject_html_urlprefix) > 0)
        {
            is_match_inject_prefix = false;
            if (PG(http_globals)[TRACK_VARS_SERVER] || zend_is_auto_global(ZEND_STRL("_SERVER") TSRMLS_CC))
            {
                zval **value;
                if (zend_hash_quick_find(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]), ZEND_STRS(REQUEST_URI), REQUEST_URI_HASH, (void **)&value) == SUCCESS &&
                    Z_TYPE_PP(value) == IS_STRING &&
                    strncasecmp(Z_STRVAL_PP(value), openrasp_ini.inject_html_urlprefix, strlen(openrasp_ini.inject_html_urlprefix)) == 0)
                {
                    is_match_inject_prefix = true;
                }
            }
        }
        if (is_match_inject_prefix)
        {
            char target_header[] = "text/html";
            for (zend_llist_element *element = SG(sapi_headers).headers.head; element; element = element->next)
            {
                sapi_header_struct *sapi_header = (sapi_header_struct *)element->data;
                if (sapi_header->header_len > 0 &&
                    strncasecmp(sapi_header->header, "content-type", sizeof("content-type") - 1) == 0 &&
                    php_stristr(sapi_header->header, target_header, sapi_header->header_len, strlen(target_header)) != nullptr)
                {
#if PHP_MINOR_VERSION > 3
                    php_output_write(inject_html.data(), inject_html.size() TSRMLS_CC);
#else
                    php_body_write(inject_html.data(), inject_html.size() TSRMLS_CC);
#endif
                    break;
                }
            }
        }
    }
    efree(OPENRASP_INJECT_G(request_id));
    return SUCCESS;
}<|endoftext|>


<commit_before>#include "LIBGPU.H"

#include "EMULATOR.H"

#define GL_GLEXT_PROTOTYPES 1
#include <SDL.h>
#include <SDL_opengl.h>
#include <SDL_opengl_glext.h>

#include <stdio.h>
#include <cstring>
#include <cassert>
#include <LIBETC.H>

unsigned short vram[1024 * 512];
DISPENV word_33BC;
int dword_3410 = 0;
char byte_3352 = 0;

void* off_3348[]=
{
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL
};

int ClearImage(RECT16* rect, u_char r, u_char g, u_char b)
{
#if USE_FRAME_BUFFERS
	char* pixelData = new char[rect->w*rect->h * 3];
	memset(pixelData, 0, rect->w*rect->h * 3);

	for (int y = 0; y < rect->w*rect->h * 3; y += 3)
	{
		pixelData[y + 0] = r;
		pixelData[y + 1] = g;
		pixelData[y + 2] = b;
	}

	GLuint blitFramebufferName = 0;
	glGenFramebuffers(1, &blitFramebufferName);
	glBindFramebuffer(GL_FRAMEBUFFER, blitFramebufferName);

	GLuint blitTexture = 0;
	glGenTextures(1, &blitTexture);

	glBindTexture(GL_TEXTURE_2D, blitTexture);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, rect->w, rect->h, 0, GL_RGB, GL_UNSIGNED_BYTE, pixelData);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

	glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, blitTexture, 0);
	glBindFramebuffer(GL_FRAMEBUFFER, blitFramebufferName);

	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, blitTexture, 0);
	glReadBuffer(GL_COLOR_ATTACHMENT0);

	glBindFramebuffer(GL_FRAMEBUFFER, vramFramebufferName);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, vramTexture, 0);
	glDrawBuffer(GL_COLOR_ATTACHMENT1);

	//tr glBlitNamedFramebuffer(blitFramebufferName, vramFramebufferName, 0, 0, rect->w, rect->h, 512,   0, 512+(rect->y*2), 256, GL_COLOR_BUFFER_BIT, GL_NEAREST);
	//tl glBlitNamedFramebuffer(blitFramebufferName, vramFramebufferName, 0, 0, rect->w, rect->h, 0  ,   0, 512+(rect->y*2), 256, GL_COLOR_BUFFER_BIT, GL_NEAREST);
	//bl glBlitNamedFramebuffer(blitFramebufferName, vramFramebufferName, 0, 0, rect->w, rect->h, 0,   256, 512,             512 + (rect->y * 2), GL_COLOR_BUFFER_BIT, GL_NEAREST);

	glBlitNamedFramebuffer(blitFramebufferName, vramFramebufferName, 0, 0, rect->w, rect->h, rect->x, rect->y, 512 + (rect->x * 2), 256 + rect->y, GL_COLOR_BUFFER_BIT, GL_NEAREST);
	printf("X: %d Y: %d W: %d H: %d\n", 0, rect->y, 512 + (rect->x * 2), rect->h);

#else
	for (int y = 0; y < 512; y++)
	{
		for (int x = 0; x < 1024; x++)
		{
			unsigned short* pixel = vram + (y * 1024 + x);

			if (x >= rect->x && x < rect->x + rect->w &&
				y >= rect->y && y < rect->y + rect->h)
			{
				pixel[0] = ((r >> 3) << 11) | ((g >> 3) << 6) | ((b >> 3) << 1) | 1;
			}
		}
	}
#endif
	return 0;
}

int DrawSync(int mode)
{
	return 0;
}

int LoadImagePSX(RECT16* rect, u_long* p)
{
#if USE_FRAME_BUFFERS
	GLuint blitFramebufferName = 0;
	glGenFramebuffers(1, &blitFramebufferName);
	glBindFramebuffer(GL_FRAMEBUFFER, blitFramebufferName);

	GLuint blitTexture = 0;
	glGenTextures(1, &blitTexture);

	// "Bind" the newly created texture : all future texture functions will modify this texture
	glBindTexture(GL_TEXTURE_2D, blitTexture);

	// Give an empty image to OpenGL ( the last "0" )
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, rect->w, rect->h, 0, GL_RGB, GL_UNSIGNED_SHORT_4_4_4_4_REV, (unsigned short*)p);

	///glCopyBufferSubData(blitTexture, vramTexture, 0, 0, rect->w * rect->h * 4)

	// Poor filtering. Needed !
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

	glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, blitTexture, 0);

	glBindFramebuffer(GL_FRAMEBUFFER, blitFramebufferName);
	// Bind input FBO + texture to a color attachment

	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, blitTexture, 0);
	glReadBuffer(GL_COLOR_ATTACHMENT0);

	// Bind destination FBO + texture to another color attachment
	glBindFramebuffer(GL_FRAMEBUFFER, vramFramebufferName);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, vramTexture, 0);
	glDrawBuffer(GL_COLOR_ATTACHMENT1);

	//	glBlitFramebuffer(0, 0, rect->w, rect->h, 0, 0, rect->w, rect->h, GL_COLOR_BUFFER_BIT, GL_NEAREST);

	glBlitNamedFramebuffer(blitFramebufferName, vramFramebufferName, 0, 0, rect->w, rect->h, rect->x, rect->y, 512 + (rect->x * 2), 256 + rect->y, GL_COLOR_BUFFER_BIT, GL_NEAREST);

#else
	unsigned short* dst = (unsigned short*)p;

	for (int y = 0; y < 512; y++)
	{
		for (int x = 0; x < 1024; x++)
		{
			unsigned short* src = vram + (y * 1024 + x);

			if (x >= rect->x && x < rect->x + rect->w &&
				y >= rect->y && y < rect->y + rect->h)
			{
				src[0] = *dst++;
			}
		}
	}
#endif

#if 1
	FILE* f = fopen("VRAM.BIN", "wb");
	fwrite(&vram[0], 1, 1024 * 512 * 2, f);
	fclose(f);
#endif

	return 0;
}

int ResetGraph(int mode)
{
	return 0;
}

int SetGraphDebug(int level)
{
	return 0;
}

int StoreImage(RECT16 * RECT16, u_long * p)
{
	return 0;
}

u_long * ClearOTag(u_long * ot, int n)
{
	assert(0);
	return 0;
}

u_long* ClearOTagR(u_long* ot, int n)
{
	//v0 = byte_3352;
	//s0 = ot
	//s1 = n

	//v0 = v0 < 2 ? 1 : 0
	if (byte_3352 > 1)
	{
		///GPU_printf("ClearOTagR(%08x,%d)...\n", ot, n);
	}

	//loc_CB0
//	((void*)off_3348[11])();

	return 0;
}

void SetDispMask(int mask)
{
}

DISPENV* GetDispEnv(DISPENV* env)//(F)
{
	memcpy(env, &word_33BC, sizeof(DISPENV));
	return env;
}

DISPENV* PutDispEnv(DISPENV* env)//To Finish
{
	memcpy((char*)&word_33BC, env, sizeof(DISPENV));
	return 0;
}

DISPENV* SetDefDispEnv(DISPENV* env, int x, int y, int w, int h)//(F)
{
	env->disp.x = x;
	env->disp.y = y;
	env->disp.w = w;
	env->screen.x = 0;
	env->screen.y = 0;
	env->screen.w = 0;
	env->screen.h = 0;
	env->isrgb24 = 0;
	env->isinter = 0;
	env->pad1 = 0;
	env->pad0 = 0;
	env->disp.h = h;
	return 0;
}

DRAWENV* PutDrawEnv(DRAWENV* env)
{
	return NULL;
}

DRAWENV* SetDefDrawEnv(DRAWENV* env, int x, int y, int w, int h)//(F)
{
	env->clip.x = x;
	env->clip.y = y;
	env->clip.w = w;
	env->tw.x = 0;
	env->tw.y = 0;
	env->tw.w = 0;
	env->tw.h = 0;
	env->r0 = 0;
	env->g0 = 0;
	env->b0 = 0;
	env->dtd = 1;
	env->clip.h = h;

	if (GetVideoMode() == 0)
	{
		env->dfe = h < 0x121 ? 1 : 0;
	}
	else
	{
		env->dfe = h < 0x101 ? 1 : 0;
	}

	env->ofs[0] = x;
	env->ofs[1] = y;

	env->tpage = 10;
	env->isbg = 0;

	return env;
}

u_long DrawSyncCallback(void(*func)(void))
{

	return u_long();
}

void DrawOTagEnv(u_long* p, DRAWENV* env)
{
	printf("Debug");
}
<commit_msg>Optimise LIBGPU.C and clean.<commit_after>#include "LIBGPU.H"

#include "EMULATOR.H"

#define GL_GLEXT_PROTOTYPES 1
#include <SDL.h>
#include <SDL_opengl.h>
#include <SDL_opengl_glext.h>

#include <stdio.h>
#include <cstring>
#include <cassert>
#include <LIBETC.H>

unsigned short vram[1024 * 512];
DISPENV word_33BC;
int dword_3410 = 0;
char byte_3352 = 0;

void* off_3348[]=
{
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL
};

int ClearImage(RECT16* rect, u_char r, u_char g, u_char b)
{
	for (int y = rect->y; y < 512; y++)
	{
		for (int x = rect->x; x < 1024; x++)
		{
			unsigned short* pixel = vram + (y * 1024 + x);

			if (x >= rect->x && x < rect->x + rect->w &&
				y >= rect->y && y < rect->y + rect->h)
			{
				pixel[0] = ((r >> 3) << 11) | ((g >> 3) << 6) | ((b >> 3) << 1) | 0;
			}
		}
	}

	return 0;
}

int DrawSync(int mode)
{
	return 0;
}

int LoadImagePSX(RECT16* rect, u_long* p)
{
	unsigned short* dst = (unsigned short*)p;

	for (int y = rect->y; y < 512; y++)
	{
		for (int x = rect->x; x < 1024; x++)
		{
			unsigned short* src = vram + (y * 1024 + x);

			if (x >= rect->x && x < rect->x + rect->w &&
				y >= rect->y && y < rect->y + rect->h)
			{
				src[0] = *dst++;
			}
		}
	}

#if _DEBUG
	FILE* f = fopen("VRAM.BIN", "wb");
	fwrite(&vram[0], 1, 1024 * 512 * 2, f);
	fclose(f);
#endif

	return 0;
}

int ResetGraph(int mode)
{
	return 0;
}

int SetGraphDebug(int level)
{
	return 0;
}

int StoreImage(RECT16 * RECT16, u_long * p)
{
	return 0;
}

u_long * ClearOTag(u_long * ot, int n)
{
	assert(0);
	return 0;
}

u_long* ClearOTagR(u_long* ot, int n)
{
	//v0 = byte_3352;
	//s0 = ot
	//s1 = n

	//v0 = v0 < 2 ? 1 : 0
	if (byte_3352 > 1)
	{
		///GPU_printf("ClearOTagR(%08x,%d)...\n", ot, n);
	}

	//loc_CB0
//	((void*)off_3348[11])();

	return 0;
}

void SetDispMask(int mask)
{
}

DISPENV* GetDispEnv(DISPENV* env)//(F)
{
	memcpy(env, &word_33BC, sizeof(DISPENV));
	return env;
}

DISPENV* PutDispEnv(DISPENV* env)//To Finish
{
	memcpy((char*)&word_33BC, env, sizeof(DISPENV));
	return 0;
}

DISPENV* SetDefDispEnv(DISPENV* env, int x, int y, int w, int h)//(F)
{
	env->disp.x = x;
	env->disp.y = y;
	env->disp.w = w;
	env->screen.x = 0;
	env->screen.y = 0;
	env->screen.w = 0;
	env->screen.h = 0;
	env->isrgb24 = 0;
	env->isinter = 0;
	env->pad1 = 0;
	env->pad0 = 0;
	env->disp.h = h;
	return 0;
}

DRAWENV* PutDrawEnv(DRAWENV* env)
{
	return NULL;
}

DRAWENV* SetDefDrawEnv(DRAWENV* env, int x, int y, int w, int h)//(F)
{
	env->clip.x = x;
	env->clip.y = y;
	env->clip.w = w;
	env->tw.x = 0;
	env->tw.y = 0;
	env->tw.w = 0;
	env->tw.h = 0;
	env->r0 = 0;
	env->g0 = 0;
	env->b0 = 0;
	env->dtd = 1;
	env->clip.h = h;

	if (GetVideoMode() == 0)
	{
		env->dfe = h < 0x121 ? 1 : 0;
	}
	else
	{
		env->dfe = h < 0x101 ? 1 : 0;
	}

	env->ofs[0] = x;
	env->ofs[1] = y;

	env->tpage = 10;
	env->isbg = 0;

	return env;
}

u_long DrawSyncCallback(void(*func)(void))
{

	return u_long();
}

void DrawOTagEnv(u_long* p, DRAWENV* env)
{
	printf("Debug");
}
<|endoftext|>