<commit_before>/*
 * fMBT, free Model Based Testing tool
 * Copyright (c) 2011,2012 Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */
#include "conf.hh"
#include "dparse.h"
#include "helper.hh"
#include "history.hh"
#include <cstring>

#ifndef DROI
#include <glib.h>
#else

#endif

class EndHook;
#include "endhook.hh"
extern "C" {
  extern D_ParserTables parser_tables_conf;
}

extern Conf* conf_obj;
#define RETURN_ERROR_VOID(s) {                  \
    log.pop();                                  \
    status=false;                               \
    errormsg=s;                                 \
    return;                                     \
  }

#define RETURN_ERROR_VERDICT(s) {               \
    log.pop();                                  \
    status=false;                               \
    errormsg=s;                                 \
    exit_status=-1;                             \
    return Verdict::ERROR;                      \
  }

void Conf::load(std::string& name,std::string& content)
{
  D_Parser *p = new_D_Parser(&parser_tables_conf, 512);
  p->loc.pathname = name.c_str();
  char *s;

  Conf* tmp=conf_obj;
  log.push("conf_load");
  log.debug("Conf::load %s",name.c_str());
  conf_obj=this;

  s=readfile(name.c_str());

  if (s==NULL) {
    status=false;
    errormsg=std::string("Can't read configuration file \"")+name+"\"";
    log.pop();
    free_D_Parser(p);
    return;
  }

  std::string ss(s);
  ss=ss+"\n"+content;
  if ((name!="" && s==NULL))
    RETURN_ERROR_VOID("Loading \"" + name + "\" failed.");

  if (ss=="")
    RETURN_ERROR_VOID("Empty configuration");

  bool ret=dparse(p,(char*)ss.c_str(),std::strlen(ss.c_str()));

  ret=p->syntax_errors==0 && ret;

  if (!ret)
    RETURN_ERROR_VOID("Parsing \"" + name + "\" failed.");

  free(s);

  free_D_Parser(p);

  conf_obj=tmp;

  if ((heuristic=new_heuristic(log,heuristic_name)) == NULL)
    RETURN_ERROR_VOID("Creating heuristic \"" + heuristic_name + "\" failed.");

  if (heuristic->status==false)
    RETURN_ERROR_VOID("Error in heuristic \"" + heuristic_name + "\":" +
                      heuristic->errormsg);

  if ((model=new_model(log, model_name)) == NULL) {
    RETURN_ERROR_VOID("Creating model \"" +
                      filetype(model_name)
                      + "\" failed.");
  }

  coverage = new_coverage(log,coverage_name);

  if (coverage == NULL)
    RETURN_ERROR_VOID("Creating coverage \"" + coverage_name + "\" failed.");

  if (!coverage->status)
    RETURN_ERROR_VOID("Error in coverage \"" + coverage_name + "\": " + coverage->errormsg);

  if (!model->status || !model->init() || !model->reset())
    RETURN_ERROR_VOID("Error in model: " + model->stringify());

  heuristic->set_coverage(coverage);

  heuristic->set_model(model);

  coverage->set_model(model);

  adapter = new_adapter(log, adapter_name);

  if (adapter == NULL)
    RETURN_ERROR_VOID("Creating adapter \"" + adapter_name + "\" failed.");

  if (!adapter->status) {
    status=false;
    errormsg=adapter->errormsg;
    return;
  }

  adapter->set_tags(&model->getSPNames());

  if (!adapter->status) {
    status=false;
    errormsg=adapter->errormsg;
    return;
  }

  // Parse adapter-tags filter (if any)
  for(unsigned i=0;i<disable_tags.size();i++) {
    std::vector<std::string>& tags=model->getSPNames();
    std::vector<std::string> f;
    commalist(disable_tags[i],f);
    std::vector<int> tmp;
    find(tags,f,tmp);
    for(unsigned i=0;i<tags.size();i++) {
      if (std::find(tmp.begin(),tmp.end(),i)==tmp.end()) {
	disabled_tags[i]=true;
      }
    }

  }

  // Free some memory.
  disable_tags.clear();

  /* handle history */
  for(unsigned i=0;i<history.size();i++) {
    History* h=new_history(log,*history[i]);

    if (h) {
      h->set_coverage(coverage,model);
      if (!h->status) {
	errormsg=h->errormsg;
	delete h;
	RETURN_ERROR_VOID(errormsg);
      }
      delete h;
    } else {
      RETURN_ERROR_VOID("Creating history \""+ *history[i] + "\" failed.");
    }
  }

  adapter->set_actions(&model->getActionNames());

  if (!coverage->status)
    RETURN_ERROR_VOID("Coverage error: " + coverage->stringify());

  if (!adapter->status)
    RETURN_ERROR_VOID("Adapter error: " + adapter->stringify());

  log.pop();
}

void Conf::disable_tagchecking(std::string& s) {
  disable_tags.push_back(s);
}

#include <sstream>

std::string Conf::stringify() {
  std::ostringstream t(std::ios::out | std::ios::binary);

  if (!status) {
    return errormsg;
  }

  t << "model = \"" << removehash(model_name) << capsulate(model->stringify()) << std::endl;
  t << "heuristic = \"" << heuristic_name << "\"" << std::endl;
  t << "coverage = \"" <<  coverage_name << "\"" << std::endl;
  t << "adapter = \"" << adapter_name
    << capsulate(adapter->stringify()) << std::endl;

  // end conditions
  for(size_t i=0;i<end_conditions.size();i++) {
    t << end_conditions[i]->stringify() << std::endl;
  }

  // exit-hooks
  stringify_hooks(t,pass_hooks ,"on_pass"  );
  stringify_hooks(t,fail_hooks ,"on_fail"  );
  stringify_hooks(t,inc_hooks  ,"on_inconc");
  stringify_hooks(t,error_hooks,"on_error" );

  return t.str();
}

Verdict::Verdict Conf::execute(bool interactive) {

  Policy policy;
  log.push("conf_execute");

  if (!status) {
    errormsg = "cannot start executing test due to earlier errors: " + errormsg;
    return Verdict::ERROR;
  }

  if (!adapter->init())
    RETURN_ERROR_VERDICT("Initialising adapter failed: " + adapter->stringify());

  // Validate and finish existing end_conditions
  {
    bool end_by_tagverify = false;
    bool end_by_coverage = false;
    for (unsigned int i = 0; i < end_conditions.size(); i++) {
      End_condition* e = end_conditions[i];
      if (e->status == false)
        RETURN_ERROR_VERDICT("Error in end condition: " + e->stringify());
      if (e->counter == End_condition::ACTION) {
        // avoid string comparisons, fetch the index of the tag
        e->param_long = find(model->getActionNames(), (e->param),-1);
        if (e->param_long==-1) {
          RETURN_ERROR_VERDICT("Error in end condition: " + e->stringify());
        }
      }
      if (e->counter == End_condition::STATETAG) {
        // avoid string comparisons, fetch the index of the tag
        e->param_long = find(model->getSPNames(), (e->param),-1);
        if (e->param_long==-1) {
          RETURN_ERROR_VERDICT("Error in end condition: " + e->stringify());
        }
      }
      if (e->counter == End_condition::TAGVERIFY) {
        end_by_tagverify = true;
	((End_condition_tagverify*) e)
	  ->evaluate_filter(model->getSPNames());
      }
      if (e->counter == End_condition::COVERAGE) {
        end_by_coverage = true;
      }
      if (e->counter == End_condition::DURATION) {
        end_time = e->param_time;
      }
    }
    // Add default end conditions (if coverage is reached, test is passed)
    if (!end_by_coverage) {
      end_conditions.push_back(new End_condition_coverage(Verdict::PASS, "1.0"));
    }
    if (!end_by_tagverify && !disable_tagverify) {
      end_conditions.push_back(new End_condition_tagverify(Verdict::FAIL, ""));
    }
  }

  Test_engine engine(*heuristic,*adapter,log,policy,end_conditions,disabled_tags);

  if (interactive) {
    engine.interactive();
  } else {
    Verdict::Verdict v = engine.run(end_time,disable_tagverify);

    if (!heuristic->status) {
      fprintf(stderr,"heuristic error: %s\n",heuristic->errormsg.c_str());
    }

    if (!model->status) {
      fprintf(stderr,"model error: %s\n",model->errormsg.c_str());
    }

    if (!adapter->status) {
      fprintf(stderr,"adapter error: %s\n",adapter->errormsg.c_str());
    }

    if (!coverage->status) {
      fprintf(stderr,"coverage error: %s\n",coverage->errormsg.c_str());
    }
    handle_hooks(v);
  }
  log.pop();
  status = true;
  errormsg = engine.verdict_msg() + ": " + engine.reason_msg();

  if (adapter->status) {
    adapter->adapter_exit(engine.verdict(),engine.reason_msg());
  }

  return engine.verdict();
}

void Conf::handle_hooks(Verdict::Verdict v)
{
  std::list<EndHook*>* hooklist=NULL;

  switch (v) {
  case Verdict::FAIL: {
    hooklist=&fail_hooks;
    break;
  }
  case Verdict::PASS: {
    hooklist=&pass_hooks;
    break;
  }
  case Verdict::INCONCLUSIVE: {
    hooklist=&inc_hooks;
    break;
  }
  case Verdict::ERROR: {
    hooklist=&error_hooks;
    break;
  }
  case Verdict::NOTIFY: {
    abort();
    break;
  }
  default: {
    // unknown verdict?
  }
  }
  if (hooklist) {
    std::list<EndHook*>::iterator b,e;
    b=hooklist->begin();
    e=hooklist->end();
    if (v==Verdict::FAIL && b++ != e) {
      for_each(b++,e,hook_runner);
    } else {
      for_each(b,e,hook_runner);
    }
  }
}

void Conf::set_observe_sleep(std::string &s)
{
  Adapter::sleeptime=atoi(s.c_str());
}

void Conf::add_end_condition(Verdict::Verdict v,std::string& s)

{
  End_condition *ec = new_end_condition(v,s);

  if (ec==NULL) {
    status=false;
    errormsg=errormsg+"Creating end condition \""+s+"\" failed.\n";
  } else {
    add_end_condition(ec);
  }
}

void hook_delete(EndHook* e);

Conf::~Conf() {
  for (unsigned int i = 0; i < end_conditions.size(); i++)
    delete end_conditions[i];
  log.pop();
  if (heuristic)
    delete heuristic;

  if (adapter)
    delete adapter;

  if (model)
    delete model;

  if (coverage)
    delete coverage;

  adapter=NULL;
  heuristic=NULL;
  model=NULL;
  coverage=NULL;

  for(unsigned i=0;i<history.size();i++) {
    if (history[i]) {
      delete history[i];
    }
  }

  for_each(pass_hooks.begin(),pass_hooks.end(),hook_delete);
  for_each(fail_hooks.begin(),fail_hooks.end(),hook_delete);
  for_each(inc_hooks.begin(),inc_hooks.end(),hook_delete);
  for_each(error_hooks.begin(),error_hooks.end(),hook_delete);
  log.unref();
}
<commit_msg>valgrind<commit_after>/*
 * fMBT, free Model Based Testing tool
 * Copyright (c) 2011,2012 Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */
#include "conf.hh"
#include "dparse.h"
#include "helper.hh"
#include "history.hh"
#include <cstring>

#ifndef DROI
#include <glib.h>
#else

#endif

class EndHook;
#include "endhook.hh"
extern "C" {
  extern D_ParserTables parser_tables_conf;
}

extern Conf* conf_obj;
#define RETURN_ERROR_VOID(s) {                  \
    log.pop();                                  \
    status=false;                               \
    errormsg=s;                                 \
    return;                                     \
  }

#define RETURN_ERROR_VERDICT(s) {               \
    log.pop();                                  \
    status=false;                               \
    errormsg=s;                                 \
    exit_status=-1;                             \
    return Verdict::ERROR;                      \
  }

void Conf::load(std::string& name,std::string& content)
{
  D_Parser *p = new_D_Parser(&parser_tables_conf, 512);
  p->loc.pathname = name.c_str();
  char *s;

  Conf* tmp=conf_obj;
  log.push("conf_load");
  log.debug("Conf::load %s",name.c_str());
  conf_obj=this;

  s=readfile(name.c_str());

  if (s==NULL) {
    status=false;
    errormsg=std::string("Can't read configuration file \"")+name+"\"";
    log.pop();
    free_D_Parser(p);
    return;
  }

  std::string ss(s);
  free(s);
  ss=ss+"\n"+content;
  if ((name!="" && s==NULL))
    RETURN_ERROR_VOID("Loading \"" + name + "\" failed.");

  if (ss=="")
    RETURN_ERROR_VOID("Empty configuration");

  bool ret=dparse(p,(char*)ss.c_str(),std::strlen(ss.c_str()));

  ret=p->syntax_errors==0 && ret;

  free_D_Parser(p);

  if (!ret) {
    RETURN_ERROR_VOID("Parsing \"" + name + "\" failed.");
  }

  conf_obj=tmp;

  if ((heuristic=new_heuristic(log,heuristic_name)) == NULL)
    RETURN_ERROR_VOID("Creating heuristic \"" + heuristic_name + "\" failed.");

  if (heuristic->status==false)
    RETURN_ERROR_VOID("Error in heuristic \"" + heuristic_name + "\":" +
                      heuristic->errormsg);

  if ((model=new_model(log, model_name)) == NULL) {
    RETURN_ERROR_VOID("Creating model \"" +
                      filetype(model_name)
                      + "\" failed.");
  }

  coverage = new_coverage(log,coverage_name);

  if (coverage == NULL)
    RETURN_ERROR_VOID("Creating coverage \"" + coverage_name + "\" failed.");

  if (!coverage->status)
    RETURN_ERROR_VOID("Error in coverage \"" + coverage_name + "\": " + coverage->errormsg);

  if (!model->status || !model->init() || !model->reset())
    RETURN_ERROR_VOID("Error in model: " + model->stringify());

  heuristic->set_coverage(coverage);

  heuristic->set_model(model);

  coverage->set_model(model);

  adapter = new_adapter(log, adapter_name);

  if (adapter == NULL)
    RETURN_ERROR_VOID("Creating adapter \"" + adapter_name + "\" failed.");

  if (!adapter->status) {
    status=false;
    errormsg=adapter->errormsg;
    return;
  }

  adapter->set_tags(&model->getSPNames());

  if (!adapter->status) {
    status=false;
    errormsg=adapter->errormsg;
    return;
  }

  // Parse adapter-tags filter (if any)
  for(unsigned i=0;i<disable_tags.size();i++) {
    std::vector<std::string>& tags=model->getSPNames();
    std::vector<std::string> f;
    commalist(disable_tags[i],f);
    std::vector<int> tmp;
    find(tags,f,tmp);
    for(unsigned i=0;i<tags.size();i++) {
      if (std::find(tmp.begin(),tmp.end(),i)==tmp.end()) {
	disabled_tags[i]=true;
      }
    }

  }

  // Free some memory.
  disable_tags.clear();

  /* handle history */
  for(unsigned i=0;i<history.size();i++) {
    History* h=new_history(log,*history[i]);

    if (h) {
      h->set_coverage(coverage,model);
      if (!h->status) {
	errormsg=h->errormsg;
	delete h;
	RETURN_ERROR_VOID(errormsg);
      }
      delete h;
    } else {
      RETURN_ERROR_VOID("Creating history \""+ *history[i] + "\" failed.");
    }
  }

  adapter->set_actions(&model->getActionNames());

  if (!coverage->status)
    RETURN_ERROR_VOID("Coverage error: " + coverage->stringify());

  if (!adapter->status)
    RETURN_ERROR_VOID("Adapter error: " + adapter->stringify());

  log.pop();
}

void Conf::disable_tagchecking(std::string& s) {
  disable_tags.push_back(s);
}

#include <sstream>

std::string Conf::stringify() {
  std::ostringstream t(std::ios::out | std::ios::binary);

  if (!status) {
    return errormsg;
  }

  t << "model = \"" << removehash(model_name) << capsulate(model->stringify()) << std::endl;
  t << "heuristic = \"" << heuristic_name << "\"" << std::endl;
  t << "coverage = \"" <<  coverage_name << "\"" << std::endl;
  t << "adapter = \"" << adapter_name
    << capsulate(adapter->stringify()) << std::endl;

  // end conditions
  for(size_t i=0;i<end_conditions.size();i++) {
    t << end_conditions[i]->stringify() << std::endl;
  }

  // exit-hooks
  stringify_hooks(t,pass_hooks ,"on_pass"  );
  stringify_hooks(t,fail_hooks ,"on_fail"  );
  stringify_hooks(t,inc_hooks  ,"on_inconc");
  stringify_hooks(t,error_hooks,"on_error" );

  return t.str();
}

Verdict::Verdict Conf::execute(bool interactive) {

  Policy policy;
  log.push("conf_execute");

  if (!status) {
    errormsg = "cannot start executing test due to earlier errors: " + errormsg;
    return Verdict::ERROR;
  }

  if (!adapter->init())
    RETURN_ERROR_VERDICT("Initialising adapter failed: " + adapter->stringify());

  // Validate and finish existing end_conditions
  {
    bool end_by_tagverify = false;
    bool end_by_coverage = false;
    for (unsigned int i = 0; i < end_conditions.size(); i++) {
      End_condition* e = end_conditions[i];
      if (e->status == false)
        RETURN_ERROR_VERDICT("Error in end condition: " + e->stringify());
      if (e->counter == End_condition::ACTION) {
        // avoid string comparisons, fetch the index of the tag
        e->param_long = find(model->getActionNames(), (e->param),-1);
        if (e->param_long==-1) {
          RETURN_ERROR_VERDICT("Error in end condition: " + e->stringify());
        }
      }
      if (e->counter == End_condition::STATETAG) {
        // avoid string comparisons, fetch the index of the tag
        e->param_long = find(model->getSPNames(), (e->param),-1);
        if (e->param_long==-1) {
          RETURN_ERROR_VERDICT("Error in end condition: " + e->stringify());
        }
      }
      if (e->counter == End_condition::TAGVERIFY) {
        end_by_tagverify = true;
	((End_condition_tagverify*) e)
	  ->evaluate_filter(model->getSPNames());
      }
      if (e->counter == End_condition::COVERAGE) {
        end_by_coverage = true;
      }
      if (e->counter == End_condition::DURATION) {
        end_time = e->param_time;
      }
    }
    // Add default end conditions (if coverage is reached, test is passed)
    if (!end_by_coverage) {
      end_conditions.push_back(new End_condition_coverage(Verdict::PASS, "1.0"));
    }
    if (!end_by_tagverify && !disable_tagverify) {
      end_conditions.push_back(new End_condition_tagverify(Verdict::FAIL, ""));
    }
  }

  Test_engine engine(*heuristic,*adapter,log,policy,end_conditions,disabled_tags);

  if (interactive) {
    engine.interactive();
  } else {
    Verdict::Verdict v = engine.run(end_time,disable_tagverify);

    if (!heuristic->status) {
      fprintf(stderr,"heuristic error: %s\n",heuristic->errormsg.c_str());
    }

    if (!model->status) {
      fprintf(stderr,"model error: %s\n",model->errormsg.c_str());
    }

    if (!adapter->status) {
      fprintf(stderr,"adapter error: %s\n",adapter->errormsg.c_str());
    }

    if (!coverage->status) {
      fprintf(stderr,"coverage error: %s\n",coverage->errormsg.c_str());
    }
    handle_hooks(v);
  }
  log.pop();
  status = true;
  errormsg = engine.verdict_msg() + ": " + engine.reason_msg();

  if (adapter->status) {
    adapter->adapter_exit(engine.verdict(),engine.reason_msg());
  }

  return engine.verdict();
}

void Conf::handle_hooks(Verdict::Verdict v)
{
  std::list<EndHook*>* hooklist=NULL;

  switch (v) {
  case Verdict::FAIL: {
    hooklist=&fail_hooks;
    break;
  }
  case Verdict::PASS: {
    hooklist=&pass_hooks;
    break;
  }
  case Verdict::INCONCLUSIVE: {
    hooklist=&inc_hooks;
    break;
  }
  case Verdict::ERROR: {
    hooklist=&error_hooks;
    break;
  }
  case Verdict::NOTIFY: {
    abort();
    break;
  }
  default: {
    // unknown verdict?
  }
  }
  if (hooklist) {
    std::list<EndHook*>::iterator b,e;
    b=hooklist->begin();
    e=hooklist->end();
    if (v==Verdict::FAIL && b++ != e) {
      for_each(b++,e,hook_runner);
    } else {
      for_each(b,e,hook_runner);
    }
  }
}

void Conf::set_observe_sleep(std::string &s)
{
  Adapter::sleeptime=atoi(s.c_str());
}

void Conf::add_end_condition(Verdict::Verdict v,std::string& s)

{
  End_condition *ec = new_end_condition(v,s);

  if (ec==NULL) {
    status=false;
    errormsg=errormsg+"Creating end condition \""+s+"\" failed.\n";
  } else {
    add_end_condition(ec);
  }
}

void hook_delete(EndHook* e);

Conf::~Conf() {
  for (unsigned int i = 0; i < end_conditions.size(); i++)
    delete end_conditions[i];
  log.pop();
  if (heuristic)
    delete heuristic;

  if (adapter)
    delete adapter;

  if (model)
    delete model;

  if (coverage)
    delete coverage;

  adapter=NULL;
  heuristic=NULL;
  model=NULL;
  coverage=NULL;

  for(unsigned i=0;i<history.size();i++) {
    if (history[i]) {
      delete history[i];
    }
  }

  for_each(pass_hooks.begin(),pass_hooks.end(),hook_delete);
  for_each(fail_hooks.begin(),fail_hooks.end(),hook_delete);
  for_each(inc_hooks.begin(),inc_hooks.end(),hook_delete);
  for_each(error_hooks.begin(),error_hooks.end(),hook_delete);
  log.unref();
}
<|endoftext|>


<commit_before>/** \file oai_pmh_harvester.cc
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2017 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <iostream>
#include <cctype>
#include "Compiler.h"
#include "Downloader.h"
#include "FileUtil.h"
#include "HttpHeader.h"
#include "MarcRecord.h"
#include "MarcReader.h"
#include "MarcWriter.h"
#include "SimpleXmlParser.h"
#include "StringDataSource.h"
#include "StringUtil.h"
#include "UrlUtil.h"
#include "util.h"

//https://memory.loc.gov/cgi-bin/oai2_0?verb=ListRecords&metadataPrefix=marc21&set=mussm
void Usage() {
    std::cerr << "Usage: " << ::progname
              << " base_url metadata_prefix [harvest_set] control_number_prefix output_filename"
              << " time_limit_per_request\n"
              << "       \"control_number_prefix\" will be used if the received records have no control numbers\n"
              << "       to autogenerate our own control numbers.  \"time_limit_per_request\" is in seconds. (Some\n"
              << "       servers are very slow so we recommend at least 20 seconds!)\n\n";
    std::exit(EXIT_FAILURE);
}

std::string ExtractResumptionToken(const std::string &xml_document) {
    StringDataSource data_source(xml_document);
    SimpleXmlParser<StringDataSource> xml_parser(&data_source);
    if (not xml_parser.skipTo(SimpleXmlParser<StringDataSource>::OPENING_TAG, "resumptionToken"))
        return "";

    SimpleXmlParser<StringDataSource>::Type type;
    std::map<std::string, std::string> attrib_map;
    std::string data;
    if (not xml_parser.getNext(&type, &attrib_map, &data) or type == SimpleXmlParser<StringDataSource>::CLOSING_TAG)
        return "";
    if (type != SimpleXmlParser<StringDataSource>::CHARACTERS)
        Error("strange resumption token XML structure!");
    return data;
}

// Helper for ExtractEncapsulatedRecordData.  Removes the trailing whitespace and </metadata>.
bool StripOffTrailingGarbage(std::string * const extracted_records) {
    // 1. back skip over the "</metadata>":
    size_t pos(extracted_records->rfind('<'));
    if (unlikely(pos == std::string::npos))
        return false;

    // 2. Now remove any trailing whitespace:
    while (likely(pos > 0) and isspace((*extracted_records)[--pos]))
        /* Intentionally empty! */;

    extracted_records->resize(pos + 1);
    return true;
}

// Returns the number of extracted records.
unsigned ExtractEncapsulatedRecordData(SimpleXmlParser<StringDataSource> * const xml_parser,
                                       std::string * const extracted_records)
{
    unsigned record_count(0);
    while (xml_parser->skipTo(SimpleXmlParser<StringDataSource>::OPENING_TAG, "record")) {
        ++record_count;
        if (not xml_parser->skipTo(SimpleXmlParser<StringDataSource>::OPENING_TAG, "metadata"))
            Error("no <metadata> tag found after a <record> tag!");
        xml_parser->skipWhiteSpace();

        if (not xml_parser->skipTo(SimpleXmlParser<StringDataSource>::CLOSING_TAG, "metadata",
                                   /* attrib_map = */ nullptr, extracted_records))
            Error("no </metadata> tag found after a <metadata> tag!");

        StripOffTrailingGarbage(extracted_records);
        *extracted_records += '\n';
    }

    return record_count;
}

bool ListRecords(const std::string &url, const unsigned time_limit_in_seconds_per_request, File * const output,
                 std::string * const resumption_token, unsigned * total_record_count)
{
    const TimeLimit time_limit(time_limit_in_seconds_per_request * 1000);
    Downloader downloader(url, Downloader::Params(), time_limit);
    if (downloader.anErrorOccurred())
        Error("harvest failed: " + downloader.getLastErrorMessage());

    const HttpHeader http_header(downloader.getMessageHeader());
    const unsigned status_code(http_header.getStatusCode());
    if (status_code < 200 or status_code > 299)
        Error("server returned a status code of " + std::to_string(status_code) + "!");

    const std::string message_body(downloader.getMessageBody());
    std::string extracted_records;
    StringDataSource data_source(message_body);
    SimpleXmlParser<StringDataSource> xml_parser(&data_source);
    const unsigned record_count(ExtractEncapsulatedRecordData(&xml_parser, &extracted_records));
    if (record_count == 0) {
        xml_parser.rewind();
        std::map<std::string, std::string> attrib_map;
        if (not xml_parser.skipTo(SimpleXmlParser<StringDataSource>::OPENING_TAG, "error", &attrib_map))
            return 0;
        const auto key_and_value(attrib_map.find("code"));
        std::string error_msg;
        if (key_and_value != attrib_map.cend())
            error_msg += key_and_value->second + ": ";
        SimpleXmlParser<StringDataSource>::Type type;
        std::string data;
        if (xml_parser.getNext(&type, &attrib_map, &data) and type == SimpleXmlParser<StringDataSource>::CHARACTERS)
            error_msg += data;
        Error("OAI-PMH server returned an error: " + error_msg + " (We sent \"" + url + "\")");
    } else { // record_count > 0
        *total_record_count += record_count;
        if (not output->write(extracted_records))
            Error("failed to write to \"" + output->getPath() + "\"! (Disc full?)");
    }

    *resumption_token = ExtractResumptionToken(message_body);
    return not resumption_token->empty();
}

std::string MakeRequestURL(const std::string &base_url, const std::string &metadata_prefix,
                           const std::string &harvest_set, const std::string &resumption_token)
{
    if (not resumption_token.empty())
        return base_url + "?verb=ListRecords&resumptionToken=" + UrlUtil::UrlEncode(resumption_token);
    if (harvest_set.empty())
        return base_url + "?verb=ListRecords&metadataPrefix=" + metadata_prefix;
    return base_url + "?verb=ListRecords&metadataPrefix=" + metadata_prefix + "&set=" + harvest_set;
}

void GenerateValidatedOutput(MarcReader * const marc_reader, const std::string &control_number_prefix,
                             MarcWriter * const marc_writer)
{
    unsigned counter(0);
    while (MarcRecord record = marc_reader->read()) {
        std::string control_number(record.getFieldData("001"));
        if (control_number.empty()) {
            control_number = control_number_prefix + StringUtil::ToString(++counter, 10, 10);
            record.insertField("001", control_number);
        }

        marc_writer->write(record);
    }
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 5 and argc != 6)
        Usage();

    const std::string base_url(argv[1]);
    const std::string metadata_prefix(argv[2]);
    const std::string harvest_set(argc == 6 ? argv[3] : "");
    const std::string control_number_prefix(argc == 6 ? argv[4] : argv[3]);
    const std::string output_filename(argc == 7 ? argv[5] : argv[4]);
    const std::string time_limit_per_request_as_string(argc == 7 ? argv[6] : argv[5]);

    unsigned time_limit_per_request_in_seconds;
    if (not StringUtil::ToUnsigned(time_limit_per_request_as_string, &time_limit_per_request_in_seconds))
        Error("\"" + time_limit_per_request_as_string + "\" is not a valid time limit!");

    try {
        const std::string TEMP_FILENAME("/tmp/oai_pmh_harvester.temp.xml");
        std::unique_ptr<File> temp_output(FileUtil::OpenOutputFileOrDie(TEMP_FILENAME));

        const std::string COLLECTION_OPEN(
            "<collection xmlns=\"http://www.loc.gov/MARC21/slim\" "
            "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
            "xsi:schemaLocation=\"http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd\">");
        temp_output->write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + COLLECTION_OPEN + "\n");

        std::string resumption_token;
        unsigned total_record_count(0);
        while (ListRecords(MakeRequestURL(base_url, metadata_prefix, harvest_set, resumption_token),
                           time_limit_per_request_in_seconds, temp_output.get(), &resumption_token,
                           &total_record_count))
            std::cerr << "Continuing download, resumption token was: \"" << resumption_token << "\".\n";

        const std::string COLLECTION_CLOSE("</collection>");
        temp_output->write(COLLECTION_CLOSE + "\n");
        temp_output->close();
        std::cerr << "Downloaded " << total_record_count << " record(s).\n";

        std::unique_ptr<MarcReader> marc_reader(MarcReader::Factory(TEMP_FILENAME, MarcReader::XML));
        std::unique_ptr<MarcWriter> marc_writer(MarcWriter::Factory(output_filename));
        GenerateValidatedOutput(marc_reader.get(), control_number_prefix, marc_writer.get());
        ::unlink(TEMP_FILENAME.c_str());
    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<commit_msg>Fixed some command-line argument-handling problems.<commit_after>/** \file oai_pmh_harvester.cc
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2017 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <iostream>
#include <cctype>
#include "Compiler.h"
#include "Downloader.h"
#include "FileUtil.h"
#include "HttpHeader.h"
#include "MarcRecord.h"
#include "MarcReader.h"
#include "MarcWriter.h"
#include "SimpleXmlParser.h"
#include "StringDataSource.h"
#include "StringUtil.h"
#include "UrlUtil.h"
#include "util.h"

//https://memory.loc.gov/cgi-bin/oai2_0?verb=ListRecords&metadataPrefix=marc21&set=mussm
void Usage() {
    std::cerr << "Usage: " << ::progname
              << " base_url metadata_prefix [harvest_set] control_number_prefix output_filename"
              << " time_limit_per_request\n"
              << "       \"control_number_prefix\" will be used if the received records have no control numbers\n"
              << "       to autogenerate our own control numbers.  \"time_limit_per_request\" is in seconds. (Some\n"
              << "       servers are very slow so we recommend at least 20 seconds!)\n\n";
    std::exit(EXIT_FAILURE);
}

std::string ExtractResumptionToken(const std::string &xml_document) {
    StringDataSource data_source(xml_document);
    SimpleXmlParser<StringDataSource> xml_parser(&data_source);
    if (not xml_parser.skipTo(SimpleXmlParser<StringDataSource>::OPENING_TAG, "resumptionToken"))
        return "";

    SimpleXmlParser<StringDataSource>::Type type;
    std::map<std::string, std::string> attrib_map;
    std::string data;
    if (not xml_parser.getNext(&type, &attrib_map, &data) or type == SimpleXmlParser<StringDataSource>::CLOSING_TAG)
        return "";
    if (type != SimpleXmlParser<StringDataSource>::CHARACTERS)
        Error("strange resumption token XML structure!");
    return data;
}

// Helper for ExtractEncapsulatedRecordData.  Removes the trailing whitespace and </metadata>.
bool StripOffTrailingGarbage(std::string * const extracted_records) {
    // 1. back skip over the "</metadata>":
    size_t pos(extracted_records->rfind('<'));
    if (unlikely(pos == std::string::npos))
        return false;

    // 2. Now remove any trailing whitespace:
    while (likely(pos > 0) and isspace((*extracted_records)[--pos]))
        /* Intentionally empty! */;

    extracted_records->resize(pos + 1);
    return true;
}

// Returns the number of extracted records.
unsigned ExtractEncapsulatedRecordData(SimpleXmlParser<StringDataSource> * const xml_parser,
                                       std::string * const extracted_records)
{
    unsigned record_count(0);
    while (xml_parser->skipTo(SimpleXmlParser<StringDataSource>::OPENING_TAG, "record")) {
        ++record_count;
        if (not xml_parser->skipTo(SimpleXmlParser<StringDataSource>::OPENING_TAG, "metadata"))
            Error("no <metadata> tag found after a <record> tag!");
        xml_parser->skipWhiteSpace();

        if (not xml_parser->skipTo(SimpleXmlParser<StringDataSource>::CLOSING_TAG, "metadata",
                                   /* attrib_map = */ nullptr, extracted_records))
            Error("no </metadata> tag found after a <metadata> tag!");

        StripOffTrailingGarbage(extracted_records);
        *extracted_records += '\n';
    }

    return record_count;
}

bool ListRecords(const std::string &url, const unsigned time_limit_in_seconds_per_request, File * const output,
                 std::string * const resumption_token, unsigned * total_record_count)
{
    const TimeLimit time_limit(time_limit_in_seconds_per_request * 1000);
    Downloader downloader(url, Downloader::Params(), time_limit);
    if (downloader.anErrorOccurred())
        Error("harvest failed: " + downloader.getLastErrorMessage());

    const HttpHeader http_header(downloader.getMessageHeader());
    const unsigned status_code(http_header.getStatusCode());
    if (status_code < 200 or status_code > 299)
        Error("server returned a status code of " + std::to_string(status_code) + "!");

    const std::string message_body(downloader.getMessageBody());
    std::string extracted_records;
    StringDataSource data_source(message_body);
    SimpleXmlParser<StringDataSource> xml_parser(&data_source);
    const unsigned record_count(ExtractEncapsulatedRecordData(&xml_parser, &extracted_records));
    if (record_count == 0) {
        xml_parser.rewind();
        std::map<std::string, std::string> attrib_map;
        if (not xml_parser.skipTo(SimpleXmlParser<StringDataSource>::OPENING_TAG, "error", &attrib_map))
            return 0;
        const auto key_and_value(attrib_map.find("code"));
        std::string error_msg;
        if (key_and_value != attrib_map.cend())
            error_msg += key_and_value->second + ": ";
        SimpleXmlParser<StringDataSource>::Type type;
        std::string data;
        if (xml_parser.getNext(&type, &attrib_map, &data) and type == SimpleXmlParser<StringDataSource>::CHARACTERS)
            error_msg += data;
        Error("OAI-PMH server returned an error: " + error_msg + " (We sent \"" + url + "\")");
    } else { // record_count > 0
        *total_record_count += record_count;
        if (not output->write(extracted_records))
            Error("failed to write to \"" + output->getPath() + "\"! (Disc full?)");
    }

    *resumption_token = ExtractResumptionToken(message_body);
    return not resumption_token->empty();
}

std::string MakeRequestURL(const std::string &base_url, const std::string &metadata_prefix,
                           const std::string &harvest_set, const std::string &resumption_token)
{
    if (not resumption_token.empty())
        return base_url + "?verb=ListRecords&resumptionToken=" + UrlUtil::UrlEncode(resumption_token);
    if (harvest_set.empty())
        return base_url + "?verb=ListRecords&metadataPrefix=" + metadata_prefix;
    return base_url + "?verb=ListRecords&metadataPrefix=" + metadata_prefix + "&set=" + harvest_set;
}

void GenerateValidatedOutput(MarcReader * const marc_reader, const std::string &control_number_prefix,
                             MarcWriter * const marc_writer)
{
    unsigned counter(0);
    while (MarcRecord record = marc_reader->read()) {
        std::string control_number(record.getFieldData("001"));
        if (control_number.empty()) {
            control_number = control_number_prefix + StringUtil::Map(StringUtil::ToString(++counter, 10, 10),
                                                                     ' ', '0');
            record.insertField("001", control_number);
        }

        marc_writer->write(record);
    }
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 6 and argc != 7)
        Usage();

    const std::string base_url(argv[1]);
    const std::string metadata_prefix(argv[2]);
    const std::string harvest_set(argc == 6 ? argv[3] : "");
    const std::string control_number_prefix(argc == 7 ? argv[3] : argv[2]);
    const std::string output_filename(argc == 7 ? argv[5] : argv[4]);
    const std::string time_limit_per_request_as_string(argc == 7 ? argv[6] : argv[5]);

    unsigned time_limit_per_request_in_seconds;
    if (not StringUtil::ToUnsigned(time_limit_per_request_as_string, &time_limit_per_request_in_seconds))
        Error("\"" + time_limit_per_request_as_string + "\" is not a valid time limit!");

    try {
        const std::string TEMP_FILENAME("/tmp/oai_pmh_harvester.temp.xml");
        std::unique_ptr<File> temp_output(FileUtil::OpenOutputFileOrDie(TEMP_FILENAME));

        const std::string COLLECTION_OPEN(
            "<collection xmlns=\"http://www.loc.gov/MARC21/slim\" "
            "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
            "xsi:schemaLocation=\"http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd\">");
        temp_output->write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + COLLECTION_OPEN + "\n");

        std::string resumption_token;
        unsigned total_record_count(0);
        while (ListRecords(MakeRequestURL(base_url, metadata_prefix, harvest_set, resumption_token),
                           time_limit_per_request_in_seconds, temp_output.get(), &resumption_token,
                           &total_record_count))
            std::cerr << "Continuing download, resumption token was: \"" << resumption_token << "\".\n";

        const std::string COLLECTION_CLOSE("</collection>");
        temp_output->write(COLLECTION_CLOSE + "\n");
        temp_output->close();
        std::cerr << "Downloaded " << total_record_count << " record(s).\n";

        std::unique_ptr<MarcReader> marc_reader(MarcReader::Factory(TEMP_FILENAME, MarcReader::XML));
        std::unique_ptr<MarcWriter> marc_writer(MarcWriter::Factory(output_filename));
        GenerateValidatedOutput(marc_reader.get(), control_number_prefix, marc_writer.get());
        ::unlink(TEMP_FILENAME.c_str());
    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2009-2010 by Bjoern Kolbeck, Zuse Institute Berlin
 *               2011-2012 by Michael Berlin, Zuse Institute Berlin
 *
 * Licensed under the BSD License, see LICENSE file for details.
 *
 */
#include "util/logging.h"

#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <ctime>
#endif

#include <boost/thread.hpp>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <ostream>
#include <string>

using namespace std;

namespace xtreemfs {
namespace util {

Logging::Logging(LogLevel level, std::ostream* stream)
    : log_stream_(*stream), log_file_stream_(stream), level_(level) {
}

Logging::Logging(LogLevel level)
    : log_stream_(std::cout), log_file_stream_(NULL), level_(level) {
}

Logging::~Logging() {
  if (log_file_stream_) {
    delete log_file_stream_;
  }
}

std::ostream& Logging::getLog(LogLevel level, const char* file, int line) {
#ifdef WIN32
  SYSTEMTIME st, lt;
  GetSystemTime(&st);
  GetLocalTime(&lt);
#else
  timeval current_time;
  gettimeofday(&current_time, 0);
  struct tm* tm = localtime(&current_time.tv_sec);
#endif

  log_stream_
      << "[ " << levelToChar(level) << " | "
      // NOTE(mberlin): Disabled output of __FILE__ and __LINE__ since they are
      // not used in the current (3/2012) code base.
//      << file << ":" << line << " | "

      << setiosflags(ios::dec)
#ifdef WIN32
      << setw(2) << lt.wMonth << "/" << setw(2) << lt.wDay << " "
      << setfill('0') << setw(2) << lt.wHour << ":"
      << setfill('0') << setw(2) << lt.wMinute << ":"
      << setfill('0') << setw(2) << lt.wSecond << "."
      << setfill('0') << setw(3) << lt.wMilliseconds << " | "
#else
      << setw(2) << (tm->tm_mon + 1) << "/" << setw(2) << tm->tm_mday << " "
      << setfill('0') << setw(2) << tm->tm_hour << ":"
      << setfill('0') << setw(2) << tm->tm_min << ":"
      << setfill('0') << setw(2) << tm->tm_sec << "."
      << setfill('0') << setw(3) << (current_time.tv_usec / 1000) << " | "
#endif
      << left << setfill(' ') << setw(14)
      << boost::this_thread::get_id() << " ] "
      // Reset modifiers.
      << setfill(' ') << resetiosflags(ios::hex | ios::left);
  return log_stream_;
}

char Logging::levelToChar(LogLevel level) {
  switch (level) {
    case LEVEL_EMERG: return 'e';
    case LEVEL_ALERT: return 'A';
    case LEVEL_CRIT: return 'C';
    case LEVEL_ERROR: return 'E';
    case LEVEL_WARN: return 'W';
    case LEVEL_NOTICE: return 'N';
    case LEVEL_INFO: return 'I';
    case LEVEL_DEBUG: return 'D';
  }
  std::cerr << "Could not determine log level." << std::endl;
  return 'U';  // unkown
}

bool Logging::loggingActive(LogLevel level) {
  return (level <= level_);
}

LogLevel stringToLevel(std::string stringLevel, LogLevel defaultLevel) {
  if (stringLevel == "EMERG") {
    return LEVEL_EMERG;
  } else if (stringLevel == "ALERT") {
    return LEVEL_ALERT;
  } else if (stringLevel == "CRIT") {
    return LEVEL_CRIT;
  } else if (stringLevel == "ERR") {
    return LEVEL_ERROR;
  } else if (stringLevel == "WARNING") {
    return LEVEL_WARN;
  } else if (stringLevel == "NOTICE") {
    return LEVEL_NOTICE;
  } else if (stringLevel == "INFO") {
    return LEVEL_INFO;
  } else if (stringLevel == "DEBUG") {
    return LEVEL_DEBUG;
  } else {
    // Return the default.
    return defaultLevel;
  }
}

void initialize_logger(std::string stringLevel,
                       std::string logfilePath,
                       LogLevel defaultLevel) {
  initialize_logger(stringToLevel(stringLevel, defaultLevel), logfilePath);
}

/**
 * Log to a file given by logfilePath. If logfilePath is empty,
 * stdout is used.
 */
void initialize_logger(LogLevel level, std::string logfilePath) {
  // Do not initialize the logging multiple times.
  if (Logging::log) {
    return;
  }

  if (!logfilePath.empty()) {
    ofstream* logfile = new std::ofstream(logfilePath.c_str());
    if (logfile != NULL && logfile->is_open()) {
      cerr << "Logging to file " << logfilePath.c_str() << "." << endl;
      Logging::log = new Logging(level, logfile);
      return;
    }
    cerr << "Could not log to file " << logfilePath.c_str()
        << ". Fallback to stdout." << endl;
  }
  // in case of an error, log to stdout
  Logging::log = new Logging(level);
}

/**
 * Log to stdout
 */
void initialize_logger(LogLevel level) {
  // Do not initialize the logging multiple times.
  if (Logging::log) {
    return;
  }
  Logging::log = new Logging(level);
}

void shutdown_logger() {
  delete Logging::log;
  Logging::log = NULL;
}

Logging* Logging::log = NULL;

}  // namespace util
}  // namespace xtreemfs

<commit_msg>Fix for issue 274.<commit_after>/*
 * Copyright (c) 2009-2010 by Bjoern Kolbeck, Zuse Institute Berlin
 *               2011-2012 by Michael Berlin, Zuse Institute Berlin
 *
 * Licensed under the BSD License, see LICENSE file for details.
 *
 */
#include "util/logging.h"

#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <ctime>
#endif

#include <boost/thread.hpp>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <ostream>
#include <string>

using namespace std;

namespace xtreemfs {
namespace util {

Logging::Logging(LogLevel level, std::ostream* stream)
    : log_stream_(*stream), log_file_stream_(stream), level_(level) {
}

Logging::Logging(LogLevel level)
    : log_stream_(std::cout), log_file_stream_(NULL), level_(level) {
}

Logging::~Logging() {
  if (log_file_stream_) {
    delete log_file_stream_;
  }
}

std::ostream& Logging::getLog(LogLevel level, const char* file, int line) {
#ifdef WIN32
  SYSTEMTIME st, lt;
  GetSystemTime(&st);
  GetLocalTime(&lt);
#else
  timeval current_time;
  gettimeofday(&current_time, 0);
  struct tm* tm = localtime(&current_time.tv_sec);
#endif

  log_stream_
      << "[ " << levelToChar(level) << " | "
      // NOTE(mberlin): Disabled output of __FILE__ and __LINE__ since they are
      // not used in the current (3/2012) code base.
//      << file << ":" << line << " | "

      << setiosflags(ios::dec)
#ifdef WIN32
      << setw(2) << lt.wMonth << "/" << setw(2) << lt.wDay << " "
      << setfill('0') << setw(2) << lt.wHour << ":"
      << setfill('0') << setw(2) << lt.wMinute << ":"
      << setfill('0') << setw(2) << lt.wSecond << "."
      << setfill('0') << setw(3) << lt.wMilliseconds << " | "
#else
      << setw(2) << (tm->tm_mon + 1) << "/" << setw(2) << tm->tm_mday << " "
      << setfill('0') << setw(2) << tm->tm_hour << ":"
      << setfill('0') << setw(2) << tm->tm_min << ":"
      << setfill('0') << setw(2) << tm->tm_sec << "."
      << setfill('0') << setw(3) << (current_time.tv_usec / 1000) << " | "
#endif
      << left << setfill(' ') << setw(14)
      << boost::this_thread::get_id() << " ] "
      // Reset modifiers.
      << setfill(' ') << resetiosflags(ios::hex | ios::left);
  return log_stream_;
}

char Logging::levelToChar(LogLevel level) {
  switch (level) {
    case LEVEL_EMERG: return 'e';
    case LEVEL_ALERT: return 'A';
    case LEVEL_CRIT: return 'C';
    case LEVEL_ERROR: return 'E';
    case LEVEL_WARN: return 'W';
    case LEVEL_NOTICE: return 'N';
    case LEVEL_INFO: return 'I';
    case LEVEL_DEBUG: return 'D';
  }
  std::cerr << "Could not determine log level." << std::endl;
  return 'U';  // unkown
}

bool Logging::loggingActive(LogLevel level) {
  return (level <= level_);
}

LogLevel stringToLevel(std::string stringLevel, LogLevel defaultLevel) {
  if (stringLevel == "EMERG") {
    return LEVEL_EMERG;
  } else if (stringLevel == "ALERT") {
    return LEVEL_ALERT;
  } else if (stringLevel == "CRIT") {
    return LEVEL_CRIT;
  } else if (stringLevel == "ERR") {
    return LEVEL_ERROR;
  } else if (stringLevel == "WARNING") {
    return LEVEL_WARN;
  } else if (stringLevel == "NOTICE") {
    return LEVEL_NOTICE;
  } else if (stringLevel == "INFO") {
    return LEVEL_INFO;
  } else if (stringLevel == "DEBUG") {
    return LEVEL_DEBUG;
  } else {
    // Return the default.
    return defaultLevel;
  }
}

void initialize_logger(std::string stringLevel,
                       std::string logfilePath,
                       LogLevel defaultLevel) {
  initialize_logger(stringToLevel(stringLevel, defaultLevel), logfilePath);
}

/**
 * Log to a file given by logfilePath. If logfilePath is empty,
 * stdout is used.
 */
void initialize_logger(LogLevel level, std::string logfilePath) {
  // Do not initialize the logging multiple times.
  if (Logging::log) {
    return;
  }

  if (!logfilePath.empty()) {
    ofstream* logfile = new std::ofstream(logfilePath.c_str(),
                                          std::ios_base::out |
                                          std::ios_base::app);
    if (logfile != NULL && logfile->is_open()) {
      cerr << "Logging to file " << logfilePath.c_str() << "." << endl;
      Logging::log = new Logging(level, logfile);
      return;
    }
    cerr << "Could not log to file " << logfilePath.c_str()
        << ". Fallback to stdout." << endl;
  }
  // in case of an error, log to stdout
  Logging::log = new Logging(level);
}

/**
 * Log to stdout
 */
void initialize_logger(LogLevel level) {
  // Do not initialize the logging multiple times.
  if (Logging::log) {
    return;
  }
  Logging::log = new Logging(level);
}

void shutdown_logger() {
  delete Logging::log;
  Logging::log = NULL;
}

Logging* Logging::log = NULL;

}  // namespace util
}  // namespace xtreemfs

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: propertysetinfo.cxx,v $
 *
 *  $Revision: 1.1 $
 *
 *  last change: $Author: cl $ $Date: 2001-03-04 21:47:46 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

#include "unotools/propertysetinfo.hxx"

using namespace ::utl;
using namespace ::rtl;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::lang;

namespace utl
{
class PropertyMapImpl
{
public:
    PropertyMapImpl() throw();
    virtual ~PropertyMapImpl() throw();

    void add( PropertyMapEntry* pMap ) throw();
    void remove( const OUString& aName ) throw();

    Sequence< Property > getProperties() throw();

    const PropertyMap* getPropertyMap() const throw();

    Property getPropertyByName( const OUString& aName ) throw( UnknownPropertyException );
    sal_Bool hasPropertyByName( const OUString& aName ) throw();

private:
    PropertyMap maPropertyMap;
    Sequence< Property > maProperties;
};
}

PropertyMapImpl::PropertyMapImpl() throw()
{
}

PropertyMapImpl::~PropertyMapImpl() throw()
{
}

void PropertyMapImpl::add( PropertyMapEntry* pMap ) throw()
{
    while( pMap->mpName )
    {
        OUString aName( pMap->mpName, pMap->mnNameLen, RTL_TEXTENCODING_ASCII_US );

#ifndef PRODUCT
        PropertyMap::iterator aIter = maPropertyMap.find( aName );
        if( aIter != maPropertyMap.end() )
        {
            DBG_ERROR( "Warning: PropertyMapEntry added twice, possible error!" );
        }
#endif
        if( NULL == pMap->mpType )
        {
            DBG_ERROR( "No type in PropertyMapEntry!" );
            pMap->mpType = &::getCppuType((const sal_Int32*)0);
        }

        maPropertyMap[aName] = pMap;

        if( maProperties.getLength() )
            maProperties.realloc( 0 );

        pMap = &pMap[1];
    }
}

void PropertyMapImpl::remove( const OUString& aName ) throw()
{
    maPropertyMap.erase( aName );

    if( maProperties.getLength() )
        maProperties.realloc( 0 );
}

Sequence< Property > PropertyMapImpl::getProperties() throw()
{
    // maybe we have to generate the properties after
    // a change in the property map or at first call
    // to getProperties
    if( maProperties.getLength() != (sal_Int32)maPropertyMap.size() )
    {
        maProperties = Sequence< Property >( maPropertyMap.size() );
        Property* pProperties = maProperties.getArray();

        PropertyMap::iterator aIter = maPropertyMap.begin();
        const PropertyMap::iterator aEnd = maPropertyMap.end();
        while( aIter != aEnd )
        {
            PropertyMapEntry* pEntry = (*aIter).second;

            pProperties->Name = OUString( pEntry->mpName, pEntry->mnNameLen, RTL_TEXTENCODING_ASCII_US );
            pProperties->Handle = pEntry->mnWhich;
            pProperties->Type = *pEntry->mpType;
            pProperties->Attributes = pEntry->mnFlags;

            aIter++;
        }
    }

    return maProperties;
}

const PropertyMap* PropertyMapImpl::getPropertyMap() const throw()
{
    return &maPropertyMap;
}

Property PropertyMapImpl::getPropertyByName( const OUString& aName ) throw( UnknownPropertyException )
{
    PropertyMap::iterator aIter = maPropertyMap.find( aName );

    if( maPropertyMap.end() == aIter )
        throw UnknownPropertyException();

    PropertyMapEntry* pEntry = (*aIter).second;

    return Property( aName, pEntry->mnWhich, *pEntry->mpType, pEntry->mnFlags );
}

sal_Bool PropertyMapImpl::hasPropertyByName( const OUString& aName ) throw()
{
    return maPropertyMap.find( aName ) != maPropertyMap.end();
}

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

PropertySetInfo::PropertySetInfo() throw()
{
    mpMap = new PropertyMapImpl();
}

PropertySetInfo::~PropertySetInfo() throw()
{
    delete mpMap;
}

void PropertySetInfo::add( PropertyMapEntry* pMap ) throw()
{
    mpMap->add( pMap );
}

void PropertySetInfo::remove( const rtl::OUString& aName ) throw()
{
    mpMap->remove( aName );
}

Sequence< ::com::sun::star::beans::Property > SAL_CALL PropertySetInfo::getProperties() throw(::com::sun::star::uno::RuntimeException)
{
    return mpMap->getProperties();
}

Property SAL_CALL PropertySetInfo::getPropertyByName( const ::rtl::OUString& aName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException)
{
    return mpMap->getPropertyByName( aName );
}

sal_Bool SAL_CALL PropertySetInfo::hasPropertyByName( const ::rtl::OUString& Name ) throw(::com::sun::star::uno::RuntimeException)
{
    return mpMap->hasPropertyByName( Name );
}

const PropertyMap* PropertySetInfo::getPropertyMap() const throw()
{
    return mpMap->getPropertyMap();
}
<commit_msg>::getProperties corrected<commit_after>/*************************************************************************
 *
 *  $RCSfile: propertysetinfo.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: os $ $Date: 2001-03-13 14:32:17 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

#include "unotools/propertysetinfo.hxx"

using namespace ::utl;
using namespace ::rtl;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::lang;

namespace utl
{
class PropertyMapImpl
{
public:
    PropertyMapImpl() throw();
    virtual ~PropertyMapImpl() throw();

    void add( PropertyMapEntry* pMap ) throw();
    void remove( const OUString& aName ) throw();

    Sequence< Property > getProperties() throw();

    const PropertyMap* getPropertyMap() const throw();

    Property getPropertyByName( const OUString& aName ) throw( UnknownPropertyException );
    sal_Bool hasPropertyByName( const OUString& aName ) throw();

private:
    PropertyMap maPropertyMap;
    Sequence< Property > maProperties;
};
}

PropertyMapImpl::PropertyMapImpl() throw()
{
}

PropertyMapImpl::~PropertyMapImpl() throw()
{
}

void PropertyMapImpl::add( PropertyMapEntry* pMap ) throw()
{
    while( pMap->mpName )
    {
        OUString aName( pMap->mpName, pMap->mnNameLen, RTL_TEXTENCODING_ASCII_US );

#ifndef PRODUCT
        PropertyMap::iterator aIter = maPropertyMap.find( aName );
        if( aIter != maPropertyMap.end() )
        {
            DBG_ERROR( "Warning: PropertyMapEntry added twice, possible error!" );
        }
#endif
        if( NULL == pMap->mpType )
        {
            DBG_ERROR( "No type in PropertyMapEntry!" );
            pMap->mpType = &::getCppuType((const sal_Int32*)0);
        }

        maPropertyMap[aName] = pMap;

        if( maProperties.getLength() )
            maProperties.realloc( 0 );

        pMap = &pMap[1];
    }
}

void PropertyMapImpl::remove( const OUString& aName ) throw()
{
    maPropertyMap.erase( aName );

    if( maProperties.getLength() )
        maProperties.realloc( 0 );
}

Sequence< Property > PropertyMapImpl::getProperties() throw()
{
    // maybe we have to generate the properties after
    // a change in the property map or at first call
    // to getProperties
    if( maProperties.getLength() != (sal_Int32)maPropertyMap.size() )
    {
        maProperties = Sequence< Property >( maPropertyMap.size() );
        Property* pProperties = maProperties.getArray();

        PropertyMap::iterator aIter = maPropertyMap.begin();
        const PropertyMap::iterator aEnd = maPropertyMap.end();
        while( aIter != aEnd )
        {
            PropertyMapEntry* pEntry = (*aIter).second;

            pProperties->Name = OUString( pEntry->mpName, pEntry->mnNameLen, RTL_TEXTENCODING_ASCII_US );
            pProperties->Handle = pEntry->mnWhich;
            pProperties->Type = *pEntry->mpType;
            pProperties->Attributes = pEntry->mnFlags;
            pProperties++;
            aIter++;
        }
    }

    return maProperties;
}

const PropertyMap* PropertyMapImpl::getPropertyMap() const throw()
{
    return &maPropertyMap;
}

Property PropertyMapImpl::getPropertyByName( const OUString& aName ) throw( UnknownPropertyException )
{
    PropertyMap::iterator aIter = maPropertyMap.find( aName );

    if( maPropertyMap.end() == aIter )
        throw UnknownPropertyException();

    PropertyMapEntry* pEntry = (*aIter).second;

    return Property( aName, pEntry->mnWhich, *pEntry->mpType, pEntry->mnFlags );
}

sal_Bool PropertyMapImpl::hasPropertyByName( const OUString& aName ) throw()
{
    return maPropertyMap.find( aName ) != maPropertyMap.end();
}

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

PropertySetInfo::PropertySetInfo() throw()
{
    mpMap = new PropertyMapImpl();
}

PropertySetInfo::~PropertySetInfo() throw()
{
    delete mpMap;
}

void PropertySetInfo::add( PropertyMapEntry* pMap ) throw()
{
    mpMap->add( pMap );
}

void PropertySetInfo::remove( const rtl::OUString& aName ) throw()
{
    mpMap->remove( aName );
}

Sequence< ::com::sun::star::beans::Property > SAL_CALL PropertySetInfo::getProperties() throw(::com::sun::star::uno::RuntimeException)
{
    return mpMap->getProperties();
}

Property SAL_CALL PropertySetInfo::getPropertyByName( const ::rtl::OUString& aName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException)
{
    return mpMap->getPropertyByName( aName );
}

sal_Bool SAL_CALL PropertySetInfo::hasPropertyByName( const ::rtl::OUString& Name ) throw(::com::sun::star::uno::RuntimeException)
{
    return mpMap->hasPropertyByName( Name );
}

const PropertyMap* PropertySetInfo::getPropertyMap() const throw()
{
    return mpMap->getPropertyMap();
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "driver/uart.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "soc/uart_struct.h"

#include "MFRC522.h"

//------------------MFRC522 register ---------------
#define         COMMAND_WAIT        0x02
#define         COMMAND_READBLOCK   0x03
#define         COMMAND_WRITEBLOCK  0x04
#define         MFRC522_HEADER      0xAB

#define         STATUS_ERROR        0
#define         STATUS_OK           1

#define         MIFARE_KEYA         0x00
#define         MIFARE_KEYB         0x01

/**
 * Constructor.
 */
MFRC522::MFRC522() {
}

/**
 * Description： Obtiene control del Serial para controlar MFRC522.
 * Ademas, pone MFRC522 en modo de espera.
 */
void MFRC522::begin(void) {
    int uart_num = UART_NUM_2;
    uart_config_t uart_config = {
       .baud_rate = 9600,
       .data_bits = UART_DATA_8_BITS,
       .parity = UART_PARITY_DISABLE,
       .stop_bits = UART_STOP_BITS_1,
       .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
       .rx_flow_ctrl_thresh = 122,
    };
    //Set UART parameters
    uart_param_config(uart_num, &uart_config);
    //Set UART log level
    esp_log_level_set(TAG, ESP_LOG_INFO);
    //Set UART pins,(-1: default pin, no change.)
    //For UART2, we can just use the default pins.
    uart_set_pin(uart_num, NFC_UART_TXD, NFC_UART_RXD, NFC_UART_RTS, NFC_UART_CTS);
    //Install UART driver, and get the queue.
    esp_err_t installed =  uart_driver_install(uart_num, BUF_SIZE * 2, BUF_SIZE * 2, 10, &uart2_queue, 0);
    printf("installed : %d\n", installed);
    wait();
}

/**
 * Description：Pone MFRC522 en modo espera.
 */
void MFRC522::wait() {
    write(COMMAND_WAIT);
}

/**
 * Description：Returns true if detect card in MFRC522.
 */
bool MFRC522::available() {
    return false;
}

/**
 * Description：Read the serial number of the card.
 */
void MFRC522::readCardSerial() {
    for (int i = 0; i < sizeof(cardSerial); ){
        if (available()){
            cardSerial[i] = read();
            i++;
        }
    }
}

/**
 * Description：Returns a pointer to array with card serial.
 */
byte *MFRC522::getCardSerial() {
    return cardSerial;
}

/**
 * Description：Read a block data of the card.
 * Return：Return STATUS_OK if success.
 */
bool MFRC522::getBlock(byte block, byte keyType, byte *key, byte *returnBlock) {
    byte sendData[8] = {
        block,      // block
        keyType,    // key type
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF  // key
    };
    byte returnBlockLength;

    for (int i = 0; i < 6; ++i) {
        sendData[2 + i] = key[i];
    }

    return communicate(
        COMMAND_READBLOCK,  // command
        sendData,           // sendData
        0x0A,               // length
        returnBlock,        // returnData
        &returnBlockLength  // returnDataLength
    );
}

/**
 * Description：Write a block data in the card.
 * Return：Return STATUS_OK if success.
 */
bool MFRC522::writeBlock(byte block, byte keyType, byte *key, byte *data) {
    byte sendData[24] = {
        block,      // block
        keyType,    // key type
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  // key
        0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // Data
    };
    byte returnBlock[3];
    byte returnBlockLength;

    for (int i = 0; i < 6; ++i) {
        sendData[2 + i] = key[i];
    }

    for (int i = 0; i < 16; ++i) {
        sendData[8 + i] = data[i];
    }

    byte result = communicate(
        COMMAND_WRITEBLOCK, // command
        sendData,           // sendData
        0x1A,               // length
        returnBlock,        // returnData
        &returnBlockLength  // returnDataLength
    );

    return result;
}

/**
 * Description：Comunication between MFRC522 and ISO14443.
 * Return：Return STATUS_OK if success.
 */
bool MFRC522::communicate(byte command, byte *sendData, byte sendDataLength, byte *returnData, byte *returnDataLength) {
    // Send instruction to MFRC522
    write(MFRC522_HEADER);      // Header
    write(sendDataLength);      // Length (Length + Command + Data)
    write(command);             // Command

    for (int i = 0; i < sendDataLength - 2; i++) {
        write(sendData[i]);     // Data
    }

    // Read response to MFRC522
    while (!available());
    byte header = read();           // Header
    while (!available());
    *returnDataLength = read();     // Length (Length + Command + Data)
    while (!available());
    byte commandResult = read();    // Command result

    for (int i = 0; i < *returnDataLength - 2; i=i) {
        if (available()) {
            returnData[i] = read(); // Data
            i++;
        }
    }

    // Return
    if (command != commandResult) {
        return STATUS_ERROR;
    }

    return STATUS_OK;
}

/*
 * Description：Write a byte data into MFRC522.
 */
void MFRC522::write(byte value) {
    int uart_num = UART_NUM_2;
    uart_write_bytes(uart_num, (const char*)value, 1);
}

/*
 * Description：Read a byte data of MFRC522
 * Return：Return the read value.
 */
byte MFRC522::read() {
    int uart_num = UART_NUM_2;
    uint8_t *data = (uint8_t *)malloc(1);
    TickType_t ticks_to_wait = portTICK_RATE_MS;
    uart_read_bytes(uart_num,data,1,ticks_to_wait);
    return *data;
}
<commit_msg>Update MFRC522.cpp<commit_after>#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "driver/uart.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "soc/uart_struct.h"

#include "MFRC522.h"

//------------------MFRC522 register ---------------
#define         COMMAND_WAIT        0x02
#define         COMMAND_READBLOCK   0x03
#define         COMMAND_WRITEBLOCK  0x04
#define         MFRC522_HEADER      0xAB

#define         STATUS_ERROR        0
#define         STATUS_OK           1

#define         MIFARE_KEYA         0x00
#define         MIFARE_KEYB         0x01

/**
 * Constructor.
 */
MFRC522::MFRC522() {
}

/**
 * Description： Obtiene control del Serial para controlar MFRC522.
 * Ademas, pone MFRC522 en modo de espera.
 */
void MFRC522::begin(void) {
    uart_port_t uart_num = UART_NUM_2;
    uart_config_t uart_config = {
       .baud_rate = 9600,
       .data_bits = UART_DATA_8_BITS,
       .parity = UART_PARITY_DISABLE,
       .stop_bits = UART_STOP_BITS_1,
       .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
       .rx_flow_ctrl_thresh = 122,
    };
    //Set UART parameters
    uart_param_config(uart_num, &uart_config);
    //Set UART log level
    esp_log_level_set(TAG, ESP_LOG_INFO);
    //Set UART pins,(-1: default pin, no change.)
    //For UART2, we can just use the default pins.
    uart_set_pin(uart_num, NFC_UART_TXD, NFC_UART_RXD, NFC_UART_RTS, NFC_UART_CTS);
    //Install UART driver, and get the queue.
    esp_err_t installed =  uart_driver_install(uart_num, BUF_SIZE * 2, BUF_SIZE * 2, 10, &uart2_queue, 0);
    printf("installed : %d\n", installed);
    wait();
}

/**
 * Description：Pone MFRC522 en modo espera.
 */
void MFRC522::wait() {
    write(COMMAND_WAIT);
}

/**
 * Description：Returns true if detect card in MFRC522.
 */
bool MFRC522::available() {
    return false;
}

/**
 * Description：Read the serial number of the card.
 */
void MFRC522::readCardSerial() {
    for (int i = 0; i < sizeof(cardSerial); ){
        if (available()){
            cardSerial[i] = read();
            i++;
        }
    }
}

/**
 * Description：Returns a pointer to array with card serial.
 */
byte *MFRC522::getCardSerial() {
    return cardSerial;
}

/**
 * Description：Read a block data of the card.
 * Return：Return STATUS_OK if success.
 */
bool MFRC522::getBlock(byte block, byte keyType, byte *key, byte *returnBlock) {
    byte sendData[8] = {
        block,      // block
        keyType,    // key type
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF  // key
    };
    byte returnBlockLength;

    for (int i = 0; i < 6; ++i) {
        sendData[2 + i] = key[i];
    }

    return communicate(
        COMMAND_READBLOCK,  // command
        sendData,           // sendData
        0x0A,               // length
        returnBlock,        // returnData
        &returnBlockLength  // returnDataLength
    );
}

/**
 * Description：Write a block data in the card.
 * Return：Return STATUS_OK if success.
 */
bool MFRC522::writeBlock(byte block, byte keyType, byte *key, byte *data) {
    byte sendData[24] = {
        block,      // block
        keyType,    // key type
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  // key
        0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // Data
    };
    byte returnBlock[3];
    byte returnBlockLength;

    for (int i = 0; i < 6; ++i) {
        sendData[2 + i] = key[i];
    }

    for (int i = 0; i < 16; ++i) {
        sendData[8 + i] = data[i];
    }

    byte result = communicate(
        COMMAND_WRITEBLOCK, // command
        sendData,           // sendData
        0x1A,               // length
        returnBlock,        // returnData
        &returnBlockLength  // returnDataLength
    );

    return result;
}

/**
 * Description：Comunication between MFRC522 and ISO14443.
 * Return：Return STATUS_OK if success.
 */
bool MFRC522::communicate(byte command, byte *sendData, byte sendDataLength, byte *returnData, byte *returnDataLength) {
    // Send instruction to MFRC522
    write(MFRC522_HEADER);      // Header
    write(sendDataLength);      // Length (Length + Command + Data)
    write(command);             // Command

    for (int i = 0; i < sendDataLength - 2; i++) {
        write(sendData[i]);     // Data
    }

    // Read response to MFRC522
    while (!available());
    byte header = read();           // Header
    while (!available());
    *returnDataLength = read();     // Length (Length + Command + Data)
    while (!available());
    byte commandResult = read();    // Command result

    for (int i = 0; i < *returnDataLength - 2; i=i) {
        if (available()) {
            returnData[i] = read(); // Data
            i++;
        }
    }

    // Return
    if (command != commandResult) {
        return STATUS_ERROR;
    }

    return STATUS_OK;
}

/*
 * Description：Write a byte data into MFRC522.
 */
void MFRC522::write(byte value) {
    int uart_num = UART_NUM_2;
    uart_write_bytes(uart_num, (const char*)value, 1);
}

/*
 * Description：Read a byte data of MFRC522
 * Return：Return the read value.
 */
byte MFRC522::read() {
    uart_port_t uart_num = UART_NUM_2;
    uint8_t *data = (uint8_t *)malloc(1);
    TickType_t ticks_to_wait = portTICK_RATE_MS;
    uart_read_bytes(uart_num,data,1,ticks_to_wait);
    return *data;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: cairo_canvasbitmap.cxx,v $
 * $Revision: 1.4 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_canvas.hxx"

#include <canvas/debug.hxx>
#include <canvas/canvastools.hxx>

#include "cairo_canvasbitmap.hxx"

using namespace ::cairo;
using namespace ::com::sun::star;

namespace cairocanvas
{
    CanvasBitmap::CanvasBitmap( const ::basegfx::B2ISize& rSize,
                                const DeviceRef&          rDevice,
                                bool                      bHasAlpha ) :
        mpDevice( rDevice )
    {
        ENSURE_AND_THROW( mpDevice.is(),
                          "CanvasBitmap::CanvasBitmap(): Invalid surface or device" );

        OSL_TRACE( "bitmap size: %dx%d", rSize.getX(), rSize.getY() );

        mpBufferSurface = mpDevice->getSurface( rSize, bHasAlpha ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR );
        mpBufferCairo = mpBufferSurface->getCairo();

        maCanvasHelper.init( rSize, *mpDevice.get() );
        maCanvasHelper.setSurface( mpBufferSurface, bHasAlpha );

        mbHasAlpha = bHasAlpha;
    }

    void SAL_CALL CanvasBitmap::disposing()
    {
        mpDevice.clear();

        if( mpBufferCairo ) {
            cairo_destroy( mpBufferCairo );
            mpBufferCairo = NULL;
        }

        if( mpBufferSurface ) {
            mpBufferSurface->Unref();
            mpBufferSurface = NULL;
        }

        // forward to parent
        CanvasBitmap_Base::disposing();
    }

    Surface* CanvasBitmap::getSurface()
    {
        return mpBufferSurface;
    }

    bool CanvasBitmap::repaint( Surface* pSurface,
                                const rendering::ViewState& viewState,
                                const rendering::RenderState&   renderState )
    {
        return maCanvasHelper.repaint( pSurface, viewState, renderState );
    }

#define IMPLEMENTATION_NAME "CairoCanvas.CanvasBitmap"
#define SERVICE_NAME "com.sun.star.rendering.CanvasBitmap"

    ::rtl::OUString SAL_CALL CanvasBitmap::getImplementationName(  ) throw (uno::RuntimeException)
    {
        return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) );
    }

    sal_Bool SAL_CALL CanvasBitmap::supportsService( const ::rtl::OUString& ServiceName ) throw (uno::RuntimeException)
    {
        return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) );
    }

    uno::Sequence< ::rtl::OUString > SAL_CALL CanvasBitmap::getSupportedServiceNames(  ) throw (uno::RuntimeException)
    {
        uno::Sequence< ::rtl::OUString > aRet(1);
        aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) );

        return aRet;
    }

}
<commit_msg>INTEGRATION: CWS canvas05 (1.3.68); FILE MERGED 2008/05/21 13:32:03 thb 1.3.68.10: Made vcl and cairo canvas work with emf+ patches; smoothed out internal cairo makefile changes; corrected cairocanvas sprite update 2008/04/21 07:32:10 thb 1.3.68.9: RESYNC: (1.3-1.4); FILE MERGED 2008/04/16 13:47:38 thb 1.3.68.8: Made cairocanvas build on Win32 again 2008/04/10 21:18:37 mox 1.3.68.7: Making cairo quartz buildable. Some pieces still missing. 2008/04/04 22:08:33 thb 1.3.68.6: Fixed output of bezier polygons for cairo; fixed missing surfaces here and there; removed useless refcounted SurfaceProvider arguments (that lead to premature canvas death, as called during ctor) 2008/04/02 22:56:26 thb 1.3.68.5: Reworked Surface class to abstract interface; changed all manual refcount handling to RAII 2008/03/18 22:00:55 thb 1.3.68.4: Implementing non-backbuffered canvas for cairocanvas as well - reworked to share most of the code 2008/03/13 22:48:50 thb 1.3.68.3: merging in remaining ooo-build cairocanvas fixes; completing std color space implementation 2007/12/20 22:18:56 thb 1.3.68.2: #i81092# #i78888# #i78925# #i79258# #i79437# #i84784# Large canvas rework, completing various areas such as color spaces, bitmap data access, true sprite and non-sprite implementations, and upstreaming the canvas parts of rodos emf+ rendering 2007/10/01 13:02:01 thb 1.3.68.1: #i78888# #i78925# #i79258# #i79437# Merge from CWS picom<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: cairo_canvasbitmap.cxx,v $
 * $Revision: 1.5 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_canvas.hxx"

#include <canvas/debug.hxx>
#include <canvas/canvastools.hxx>
#include <tools/diagnose_ex.h>

#include "cairo_canvasbitmap.hxx"

#ifdef CAIRO_HAS_XLIB_SURFACE
# include "cairo_xlib_cairo.hxx"
#elif defined CAIRO_HAS_QUARTZ_SURFACE
# include "cairo_quartz_cairo.hxx"
#elif defined CAIRO_HAS_WIN32_SURFACE
# include "cairo_win32_cairo.hxx"
# include <cairo-win32.h>
#else
# error Native API needed.
#endif

using namespace ::cairo;
using namespace ::com::sun::star;

#ifdef CAIRO_HAS_WIN32_SURFACE
namespace
{
    HBITMAP surface2HBitmap( const SurfaceSharedPtr& rSurface, const basegfx::B2ISize& rSize )
    {
        // cant seem to retrieve HBITMAP from cairo. copy content then
        HDC hScreenDC=GetDC(NULL);
        HBITMAP hBmpBitmap = CreateCompatibleBitmap( hScreenDC,
                                                     rSize.getX(),
                                                     rSize.getY() );

        HDC     hBmpDC = CreateCompatibleDC( 0 );
        HBITMAP hBmpOld = (HBITMAP) SelectObject( hBmpDC, hBmpBitmap );

        BitBlt( hBmpDC, 0, 0, rSize.getX(), rSize.getX(),
                cairo_win32_surface_get_dc(rSurface->getCairoSurface().get()),
                0, 0, SRCCOPY );

        SelectObject( hBmpDC, hBmpOld );
        DeleteDC( hBmpDC );

        return hBmpBitmap;
    }
}
#endif

namespace cairocanvas
{
    CanvasBitmap::CanvasBitmap( const ::basegfx::B2ISize&  rSize,
                                const SurfaceProviderRef&  rSurfaceProvider,
                                rendering::XGraphicDevice* pDevice,
                                bool                       bHasAlpha ) :
        mpSurfaceProvider( rSurfaceProvider ),
        mpBufferSurface(),
        mpBufferCairo(),
        maSize(rSize),
        mbHasAlpha(bHasAlpha)
    {
        ENSURE_OR_THROW( mpSurfaceProvider.is(),
                          "CanvasBitmap::CanvasBitmap(): Invalid surface or device" );

        OSL_TRACE( "bitmap size: %dx%d", rSize.getX(), rSize.getY() );

        mpBufferSurface = mpSurfaceProvider->createSurface( rSize, bHasAlpha ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR );
        mpBufferCairo = mpBufferSurface->getCairo();

        maCanvasHelper.init( rSize, *mpSurfaceProvider, pDevice );
        maCanvasHelper.setSurface( mpBufferSurface, bHasAlpha );

        // clear bitmap to 100% transparent
        maCanvasHelper.clear();
    }

    void SAL_CALL CanvasBitmap::disposing()
    {
        mpSurfaceProvider.clear();

        mpBufferCairo.reset();
        mpBufferSurface.reset();

        // forward to parent
        CanvasBitmap_Base::disposing();
    }

    SurfaceSharedPtr CanvasBitmap::getSurface()
    {
        return mpBufferSurface;
    }

    SurfaceSharedPtr CanvasBitmap::createSurface( const ::basegfx::B2ISize& rSize, Content aContent )
    {
        return mpSurfaceProvider->createSurface(rSize,aContent);
    }

    SurfaceSharedPtr CanvasBitmap::createSurface( ::Bitmap& rBitmap )
    {
        return mpSurfaceProvider->createSurface(rBitmap);
    }

    SurfaceSharedPtr CanvasBitmap::changeSurface( bool, bool )
    {
        // non-modifiable surface here
        return SurfaceSharedPtr();
    }

    OutputDevice* CanvasBitmap::getOutputDevice()
    {
        return mpSurfaceProvider->getOutputDevice();
    }

    bool CanvasBitmap::repaint( const SurfaceSharedPtr&       pSurface,
                                const rendering::ViewState&   viewState,
                                const rendering::RenderState& renderState )
    {
        return maCanvasHelper.repaint( pSurface, viewState, renderState );
    }

    uno::Any SAL_CALL CanvasBitmap::getFastPropertyValue( sal_Int32 nHandle )  throw (uno::RuntimeException)
    {
        uno::Any aRV( sal_Int32(0) );
        // 0 ... get BitmapEx
        // 1 ... get Pixbuf with bitmap RGB content
        // 2 ... get Pixbuf with bitmap alpha mask
        switch( nHandle )
        {
            case 0:
            {
                aRV = uno::Any( reinterpret_cast<sal_Int64>( (BitmapEx*) NULL ) );
                break;
            }
            case 1:
            {
#ifdef CAIRO_HAS_XLIB_SURFACE
                X11Surface* pXlibSurface=dynamic_cast<X11Surface*>(mpBufferSurface.get());
                OSL_ASSERT(pXlibSurface);
                uno::Sequence< uno::Any > args( 3 );
                args[0] = uno::Any( false );  // do not call XFreePixmap on it
                args[1] = uno::Any( pXlibSurface->getPixmap()->mhDrawable );
                args[2] = uno::Any( sal_Int32( pXlibSurface->getDepth() ) );

                aRV = uno::Any( args );
#elif defined CAIRO_HAS_QUARTZ_SURFACE
                QuartzSurface* pQuartzSurface = dynamic_cast<QuartzSurface*>(mpBufferSurface.get());
                OSL_ASSERT(pQuartzSurface);
                uno::Sequence< uno::Any > args( 1 );
                args[0] = uno::Any( sal_IntPtr (pQuartzSurface->getCGContext()) );
                aRV = uno::Any( args );
#elif defined CAIRO_HAS_WIN32_SURFACE
                // TODO(F2): check whether under all circumstances,
                // the alpha channel is ignored here.
                uno::Sequence< uno::Any > args( 1 );
                args[1] = uno::Any( sal_Int64(surface2HBitmap(mpBufferSurface,maSize)) );

                aRV = uno::Any( args );
                // caller frees the bitmap
#else
# error Please define fast prop retrieval for your platform!
#endif
                break;
            }
            case 2:
            {
#ifdef CAIRO_HAS_XLIB_SURFACE
                uno::Sequence< uno::Any > args( 3 );
                SurfaceSharedPtr pAlphaSurface = mpSurfaceProvider->createSurface( maSize, CAIRO_CONTENT_COLOR );
                CairoSharedPtr   pAlphaCairo = pAlphaSurface->getCairo();
                X11Surface* pXlibSurface=dynamic_cast<X11Surface*>(pAlphaSurface.get());
                OSL_ASSERT(pXlibSurface);

                // create RGB image (levels of gray) of alpha channel of original picture
                cairo_set_source_rgba( pAlphaCairo.get(), 1, 1, 1, 1 );
                cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_SOURCE );
                cairo_paint( pAlphaCairo.get() );
                cairo_set_source_surface( pAlphaCairo.get(), mpBufferSurface->getCairoSurface().get(), 0, 0 );
                cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_XOR );
                cairo_paint( pAlphaCairo.get() );
                pAlphaCairo.reset();

                X11PixmapSharedPtr pPixmap = pXlibSurface->getPixmap();
                args[0] = uno::Any( true );
                args[1] = ::com::sun::star::uno::Any( pPixmap->mhDrawable );
                args[2] = ::com::sun::star::uno::Any( sal_Int32( pXlibSurface->getDepth () ) );
                pPixmap->clear(); // caller takes ownership of pixmap

                // return pixmap and alphachannel pixmap - it will be used in BitmapEx
                aRV = uno::Any( args );
#elif defined CAIRO_HAS_QUARTZ_SURFACE
                SurfaceSharedPtr pAlphaSurface = mpSurfaceProvider->createSurface( maSize, CAIRO_CONTENT_COLOR );
                CairoSharedPtr   pAlphaCairo = pAlphaSurface->getCairo();
                QuartzSurface* pQuartzSurface=dynamic_cast<QuartzSurface*>(pAlphaSurface.get());
                OSL_ASSERT(pQuartzSurface);

                // create RGB image (levels of gray) of alpha channel of original picture
                cairo_set_source_rgba( pAlphaCairo.get(), 1, 1, 1, 1 );
                cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_SOURCE );
                cairo_paint( pAlphaCairo.get() );
                cairo_set_source_surface( pAlphaCairo.get(), mpBufferSurface->getCairoSurface().get(), 0, 0 );
                cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_XOR );
                cairo_paint( pAlphaCairo.get() );
                pAlphaCairo.reset();

                uno::Sequence< uno::Any > args( 1 );
                args[0] = uno::Any( sal_IntPtr (pQuartzSurface->getCGContext()) );
                // return ??? and alphachannel ??? - it will be used in BitmapEx
                aRV = uno::Any( args );
#elif defined CAIRO_HAS_WIN32_SURFACE
                SurfaceSharedPtr pAlphaSurface = mpSurfaceProvider->createSurface( maSize, CAIRO_CONTENT_COLOR );
                CairoSharedPtr   pAlphaCairo = pAlphaSurface->getCairo();

                // create RGB image (levels of gray) of alpha channel of original picture
                cairo_set_source_rgba( pAlphaCairo.get(), 1, 1, 1, 1 );
                cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_SOURCE );
                cairo_paint( pAlphaCairo.get() );
                cairo_set_source_surface( pAlphaCairo.get(), mpBufferSurface->getCairoSurface().get(), 0, 0 );
                cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_XOR );
                cairo_paint( pAlphaCairo.get() );
                pAlphaCairo.reset();

                // cant seem to retrieve HBITMAP from cairo. copy content then
                uno::Sequence< uno::Any > args( 1 );
                args[1] = uno::Any( sal_Int64(surface2HBitmap(pAlphaSurface,maSize)) );

                aRV = uno::Any( args );
                // caller frees the bitmap
#else
# error Please define fast prop retrieval for your platform!
#endif
                break;
            }
        }

        return aRV;
    }

#define IMPLEMENTATION_NAME "CairoCanvas.CanvasBitmap"
#define SERVICE_NAME "com.sun.star.rendering.CanvasBitmap"

    ::rtl::OUString SAL_CALL CanvasBitmap::getImplementationName(  ) throw (uno::RuntimeException)
    {
        return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) );
    }

    sal_Bool SAL_CALL CanvasBitmap::supportsService( const ::rtl::OUString& ServiceName ) throw (uno::RuntimeException)
    {
        return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) );
    }

    uno::Sequence< ::rtl::OUString > SAL_CALL CanvasBitmap::getSupportedServiceNames(  ) throw (uno::RuntimeException)
    {
        uno::Sequence< ::rtl::OUString > aRet(1);
        aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) );

        return aRet;
    }

}
<|endoftext|>