<commit_before>#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <typeinfo>
#include <ctype.h>

enum TokenType{
  TOKEN_BRACKET_OPEN,
  TOKEN_BRACKET_CLOSE,
  TOKEN_SYMBOL,
  TOKEN_STRING,
  TOKEN_NIL,
};

class Token {
public:
  TokenType type;
  std::string value;

  Token(TokenType atype) : type(atype), value(std::string()) {
  }

  Token(TokenType atype, std::string avalue) : type(atype), value(avalue) {
  }
};

namespace Lisp {
  class Expression {
  public:
    virtual ~Expression() {}

    virtual std::string lisp_str() = 0;
  };

  class CallFunction : public Expression {
  public:
    std::string name;
    std::vector<Expression*> args;

    CallFunction(std::string aname, std::vector<Expression*> &aargs) : name(aname), args(aargs) {}
    ~CallFunction() {
      for(size_t i = 0 ; i < args.size() ; i++) {
        delete args[i];
      }
    }

    std::string lisp_str() {
      std::stringstream ss;
      ss << "(" << name << " ";
      for(Expression* arg : args) {
        ss << arg->lisp_str() << " ";
      }
      ss << ")";
      return ss.str();
    }
  };

  class String : public Expression {
  public:
    std::string value;

    String(std::string &avalue) : value(avalue) {}

    std::string lisp_str() { return '"' + value + '"'; }
  };

  class List : public Expression {
  public:
    std::vector<Expression*> values;

    List(std::vector<Expression*> &avalues) : values(avalues) {}

    std::string lisp_str() {
      std::stringstream ss;
      ss << "(";
      for(Expression* value : values) {
        ss << value->lisp_str() << " ";
      }
      ss << ")";
      return ss.str();
    }
  };

  // TODO: RubyみたくExpression*に埋め込みたい
  class Nil : public Expression {
  public:
    Nil() {}

    std::string lisp_str() { return "nil"; }
  };
}

bool is_symbol(char c) {
  return isalnum(c) && isalpha(c);
}

int main() {
  using namespace std;

  string code;
  //code.reserve(1024);
  vector<Token*> tokens;
  vector<Lisp::Expression*> exprs;

  char ch;
  while((ch = cin.get()) != std::char_traits<char>::eof()) {
    code.push_back(ch);
  }

  for(size_t i = 0 ; i < code.size() - 1 ; i++) { //TODO: -1を修正(EOFっぽい?)
    char ch = code[i];
    if(ch == '(')
      tokens.push_back(new Token(TOKEN_BRACKET_OPEN));
    else if(ch == ')')
      tokens.push_back(new Token(TOKEN_BRACKET_CLOSE));
    else if(ch == '"') { // string
      i++;

      size_t token_len = 0;
      while(code[i + token_len] != '"') {
        token_len++;
        if(i + token_len >= code.size()) {
          //TODO: raise an error
        }
      }
      tokens.push_back(new Token(TOKEN_STRING, code.substr(i, token_len)));
      i += token_len;
    }
    else if(ch == ' ' || ch == '\n')
      ;//skip
    else { // symbol
      size_t token_len = 0;
      while(is_symbol(code[i + token_len])) {
        token_len++;
        if(i + token_len >= code.size()) {
          //TODO: raise an error
        }
      }

      string token_val = code.substr(i, token_len);
      TokenType token_type;
      if(token_val == "nil")
        token_type = TOKEN_NIL;
      else
        token_type = TOKEN_SYMBOL;

      if(token_type == TOKEN_SYMBOL)
        tokens.push_back(new Token(TOKEN_SYMBOL, token_val));
      else
        tokens.push_back(new Token(token_type));

      i += token_len - 1;
    }
  }

  for(auto token : tokens) {
    cout << "token type: " << token->type << ", value: " << token->value << endl;
  }

  // parse
  for(size_t i = 0 ; i < tokens.size() ; i++) {
    Token* token = tokens[i];
    switch(token->type) {
      case TOKEN_BRACKET_OPEN: {
        string name;
        vector<Lisp::Expression*> args;

        i++;
        if(tokens[i]->type != TOKEN_STRING) {
          //TODO: raise an error
        }
        name = tokens[i]->value;

        i++;
        for(; tokens[i]->type != TOKEN_BRACKET_CLOSE ; i++) {
          switch(tokens[i]->type) {
            case TOKEN_STRING:
              args.push_back(new Lisp::String(tokens[i]->value));
              break;
            case TOKEN_NIL:
              args.push_back(new Lisp::Nil());
              break;
            default: ;
          }
        }

        exprs.push_back(new Lisp::CallFunction(name, args));

        break;
      }
      default:
        break;
    }
  }

  // evaluate
  for(size_t i = 0 ; i < exprs.size() ; i++) {
    auto expr = exprs[i];

    const type_info& id = typeid(*expr);
    if(id == typeid(Lisp::CallFunction)) {
      auto call_fun = (Lisp::CallFunction*)expr;
      auto name = call_fun->name;
      if(name == "print") {
        for(auto arg : call_fun->args) {
          cout << ((Lisp::String*)arg)->value;
        }
        exprs[i] = new Lisp::Nil;
      }
      else if(name == "inspect") {
        cout << call_fun->args[0]->lisp_str() << endl;
        exprs[i] = new Lisp::Nil;
      }
    }
  }

  // destruction
  for(size_t i = 0 ; i < tokens.size() ; i++) {
    delete tokens[i];
  }

  for(size_t i = 0 ; i < exprs.size() ; i++) {
    delete exprs[i];
  }

  return 0;
}
<commit_msg>list関数を追加<commit_after>#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <typeinfo>
#include <ctype.h>

enum TokenType{
  TOKEN_BRACKET_OPEN,
  TOKEN_BRACKET_CLOSE,
  TOKEN_SYMBOL,
  TOKEN_STRING,
  TOKEN_NIL,
};

class Token {
public:
  TokenType type;
  std::string value;

  Token(TokenType atype) : type(atype), value(std::string()) {
  }

  Token(TokenType atype, std::string avalue) : type(atype), value(avalue) {
  }
};

namespace Lisp {
  class Expression {
  public:
    virtual ~Expression() {}

    virtual std::string lisp_str() = 0;
  };

  class CallFunction : public Expression {
  public:
    std::string name;
    std::vector<Expression*> args;

    CallFunction(std::string aname, std::vector<Expression*> &aargs) : name(aname), args(aargs) {}
    ~CallFunction() {
      for(size_t i = 0 ; i < args.size() ; i++) {
        delete args[i];
      }
    }

    std::string lisp_str() {
      std::stringstream ss;
      ss << "(" << name << " ";
      for(Expression* arg : args) {
        ss << arg->lisp_str() << " ";
      }
      ss << ")";
      return ss.str();
    }
  };

  class String : public Expression {
  public:
    std::string value;

    String(std::string &avalue) : value(avalue) {}

    std::string lisp_str() { return '"' + value + '"'; }
  };

  class List : public Expression {
  public:
    std::vector<Expression*> values;

    List(std::vector<Expression*> &avalues) : values(avalues) {}

    std::string lisp_str() {
      std::stringstream ss;
      ss << "(";
      for(Expression* value : values) {
        ss << value->lisp_str() << " ";
      }
      ss << ")";
      return ss.str();
    }
  };

  // TODO: RubyみたくExpression*に埋め込みたい
  class Nil : public Expression {
  public:
    Nil() {}

    std::string lisp_str() { return "nil"; }
  };
}

bool is_symbol(char c) {
  return isalnum(c) && isalpha(c);
}

int main() {
  using namespace std;

  string code;
  //code.reserve(1024);
  vector<Token*> tokens;
  vector<Lisp::Expression*> exprs;

  char ch;
  while((ch = cin.get()) != std::char_traits<char>::eof()) {
    code.push_back(ch);
  }

  for(size_t i = 0 ; i < code.size() - 1 ; i++) { //TODO: -1を修正(EOFっぽい?)
    char ch = code[i];
    if(ch == '(')
      tokens.push_back(new Token(TOKEN_BRACKET_OPEN));
    else if(ch == ')')
      tokens.push_back(new Token(TOKEN_BRACKET_CLOSE));
    else if(ch == '"') { // string
      i++;

      size_t token_len = 0;
      while(code[i + token_len] != '"') {
        token_len++;
        if(i + token_len >= code.size()) {
          //TODO: raise an error
        }
      }
      tokens.push_back(new Token(TOKEN_STRING, code.substr(i, token_len)));
      i += token_len;
    }
    else if(ch == ' ' || ch == '\n')
      ;//skip
    else { // symbol
      size_t token_len = 0;
      while(is_symbol(code[i + token_len])) {
        token_len++;
        if(i + token_len >= code.size()) {
          //TODO: raise an error
        }
      }

      string token_val = code.substr(i, token_len);
      TokenType token_type;
      if(token_val == "nil")
        token_type = TOKEN_NIL;
      else
        token_type = TOKEN_SYMBOL;

      if(token_type == TOKEN_SYMBOL)
        tokens.push_back(new Token(TOKEN_SYMBOL, token_val));
      else
        tokens.push_back(new Token(token_type));

      i += token_len - 1;
    }
  }

  for(auto token : tokens) {
    cout << "token type: " << token->type << ", value: " << token->value << endl;
  }

  // parse
  for(size_t i = 0 ; i < tokens.size() ; i++) {
    Token* token = tokens[i];
    switch(token->type) {
      case TOKEN_BRACKET_OPEN: {
        string name;
        vector<Lisp::Expression*> args;

        i++;
        if(tokens[i]->type != TOKEN_STRING) {
          //TODO: raise an error
        }
        name = tokens[i]->value;

        i++;
        for(; tokens[i]->type != TOKEN_BRACKET_CLOSE ; i++) {
          switch(tokens[i]->type) {
            case TOKEN_STRING:
              args.push_back(new Lisp::String(tokens[i]->value));
              break;
            case TOKEN_NIL:
              args.push_back(new Lisp::Nil());
              break;
            default: ;
          }
        }

        exprs.push_back(new Lisp::CallFunction(name, args));

        break;
      }
      default:
        break;
    }
  }

  // evaluate
  for(size_t i = 0 ; i < exprs.size() ; i++) {
    auto expr = exprs[i];

    const type_info& id = typeid(*expr);
    if(id == typeid(Lisp::CallFunction)) {
      auto call_fun = (Lisp::CallFunction*)expr;
      auto name = call_fun->name;
      if(name == "print") {
        for(auto arg : call_fun->args) {
          cout << ((Lisp::String*)arg)->value;
        }
        exprs[i] = new Lisp::Nil;
      }
      else if(name == "inspect") {
        cout << call_fun->args[0]->lisp_str() << endl;
        exprs[i] = new Lisp::Nil;
      }
      else if(name == "list") {
        exprs[i] = new Lisp::List(call_fun->args);
      }
    }
  }

  // destruction
  for(size_t i = 0 ; i < tokens.size() ; i++) {
    delete tokens[i];
  }

  for(size_t i = 0 ; i < exprs.size() ; i++) {
    delete exprs[i];
  }

  return 0;
}
<|endoftext|>


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

#if defined HAVE_CONFIG_H
#include <config.h>
#endif

#include <iostream>
#include <cstring>
#include <id3/tag.h>
#include <getopt.h>
#include <cstdlib>
#include <cstdio>
#include <id3/misc_support.h>
#include "frametable.h"
#include "genre.h"

char *GetDescription(const ID3_FrameID eFrameID)
{
  for(int ii = 0; ii < frameTableCount; ii++ )
  {
    if (frameTable[ii].frameID == eFrameID)
      return frameTable[ii].frameLongName;
  }
  return NULL;
}

void PrintFrameHelp(char *sName)
{
    for(int ii = 0; ii < frameTableCount - 1; ii++ )
    {
      std::cout << "    --" << frameTable[ii].frameName << "    "
           << frameTable[ii].frameLongName << std::endl;
    }
    return;
}

void PrintGenreList()
{
  for (int ii = 0; ii < GetGenreCount(); ii++)
    printf("%3d: %s\n", ii, GetGenreFromNum(ii));
}

int PrintInformation(char *sFileName, const ID3_Tag &myTag)
{
  bool firstLine = true;
  const ID3_Frame * myFrame;
  ID3_Tag::ConstIterator *Iter=myTag.CreateIterator();
  for (size_t nFrames = 0; nFrames < myTag.NumFrames(); nFrames++)
  {
    myFrame = Iter->GetNext();

    if(firstLine) {
      std::cout << "id3v2 tag info for " << sFileName << ":" << std::endl;
      firstLine = false;
    }

    if (NULL != myFrame)
    {
      const char* desc = myFrame->GetDescription();
      if (!desc) desc = "";
      std::cout << myFrame->GetTextID() << " (" << desc << "): ";
      ID3_FrameID eFrameID = myFrame->GetID();

      switch (eFrameID)
      {
        case ID3FID_ALBUM:
        case ID3FID_BPM:
        case ID3FID_COMPOSER:
        case ID3FID_COPYRIGHT:
        case ID3FID_DATE:
        case ID3FID_PLAYLISTDELAY:
        case ID3FID_ENCODEDBY:
        case ID3FID_LYRICIST:
        case ID3FID_FILETYPE:
        case ID3FID_TIME:
        case ID3FID_CONTENTGROUP:
        case ID3FID_TITLE:
        case ID3FID_SUBTITLE:
        case ID3FID_INITIALKEY:
        case ID3FID_LANGUAGE:
        case ID3FID_SONGLEN:
        case ID3FID_MEDIATYPE:
        case ID3FID_ORIGALBUM:
        case ID3FID_ORIGFILENAME:
        case ID3FID_ORIGLYRICIST:
        case ID3FID_ORIGARTIST:
        case ID3FID_ORIGYEAR:
        case ID3FID_FILEOWNER:
        case ID3FID_LEADARTIST:
        case ID3FID_BAND:
        case ID3FID_CONDUCTOR:
        case ID3FID_MIXARTIST:
        case ID3FID_PARTINSET:
        case ID3FID_PUBLISHER:
        case ID3FID_TRACKNUM:
        case ID3FID_RECORDINGDATES:
        case ID3FID_NETRADIOSTATION:
        case ID3FID_NETRADIOOWNER:
        case ID3FID_SIZE:
        case ID3FID_ISRC:
        case ID3FID_ENCODERSETTINGS:
        case ID3FID_YEAR:
        {
          char *sText = ID3_GetString(myFrame, ID3FN_TEXT);
          std::cout << sText << std::endl;
          delete [] sText;
          break;
        }
        case ID3FID_CONTENTTYPE:
        {
          const char* genre_str;
          int genre_id = 255;
          char *sText = ID3_GetString(myFrame, ID3FN_TEXT);
          sscanf(sText, "(%d)", &genre_id);
          if (genre_id == 255) {
            genre_str = sText;
            genre_id = GetNumFromGenre(sText);
          }
          else
            genre_str = GetGenreFromNum(genre_id);
          std::cout << genre_str << " (" << genre_id << ")" << std::endl;
          delete [] sText;
          break;
        }
        case ID3FID_USERTEXT:
        {
          char
            *sText = ID3_GetString(myFrame, ID3FN_TEXT),
            *sDesc = ID3_GetString(myFrame, ID3FN_DESCRIPTION);
          std::cout << "(" << sDesc << "): " << sText << std::endl;
          delete [] sText;
          delete [] sDesc;
          break;
        }
        case ID3FID_COMMENT:
        case ID3FID_UNSYNCEDLYRICS:
        {
          char
            *sText = ID3_GetString(myFrame, ID3FN_TEXT),
            *sDesc = ID3_GetString(myFrame, ID3FN_DESCRIPTION),
            *sLang = ID3_GetString(myFrame, ID3FN_LANGUAGE);
          std::cout << "(" << sDesc << ")[" << sLang << "]: "
               << sText << std::endl;
          delete [] sText;
          delete [] sDesc;
          delete [] sLang;
          break;
        }
        case ID3FID_WWWAUDIOFILE:
        case ID3FID_WWWARTIST:
        case ID3FID_WWWAUDIOSOURCE:
        case ID3FID_WWWCOMMERCIALINFO:
        case ID3FID_WWWCOPYRIGHT:
        case ID3FID_WWWPUBLISHER:
        case ID3FID_WWWPAYMENT:
        case ID3FID_WWWRADIOPAGE:
        {
          char *sURL = ID3_GetString(myFrame, ID3FN_URL);
          std::cout << sURL << std::endl;
          delete [] sURL;
          break;
        }
        case ID3FID_WWWUSER:
        {
          char
            *sURL = ID3_GetString(myFrame, ID3FN_URL),
            *sDesc = ID3_GetString(myFrame, ID3FN_DESCRIPTION);
          std::cout << "(" << sDesc << "): " << sURL << std::endl;
          delete [] sURL;
          delete [] sDesc;
          break;
        }
        case ID3FID_INVOLVEDPEOPLE:
        {
          // This isn't the right way to do it---will only get first person
          size_t nItems = myFrame->Field(ID3FN_TEXT).GetNumTextItems();
          for (size_t nIndex = 1; nIndex <= nItems; nIndex++)
          {
            char *sPeople = ID3_GetString(myFrame, ID3FN_TEXT, nIndex);
            std::cout << sPeople;
            delete [] sPeople;
            if (nIndex < nItems)
            {
              std::cout << ", ";
            }
          }
          std::cout << std::endl;
          break;
        }
        case ID3FID_PICTURE:
        {
          char
            *sMimeType = ID3_GetString(myFrame, ID3FN_MIMETYPE),
            *sDesc     = ID3_GetString(myFrame, ID3FN_DESCRIPTION),
            *sFormat   = ID3_GetString(myFrame, ID3FN_IMAGEFORMAT);
          size_t
            nPicType   = myFrame->Field(ID3FN_PICTURETYPE).Get(),
            nDataSize  = myFrame->Field(ID3FN_DATA).Size();
          std::cout << "(" << sDesc << ")[" << sFormat << ", "
               << nPicType << "]: " << sMimeType << ", " << nDataSize
               << " bytes" << std::endl;
          delete [] sMimeType;
          delete [] sDesc;
          delete [] sFormat;
          break;
        }
        case ID3FID_GENERALOBJECT:
        {
          char
          *sMimeType = ID3_GetString(myFrame, ID3FN_MIMETYPE),
          *sDesc = ID3_GetString(myFrame, ID3FN_DESCRIPTION),
          *sFileName = ID3_GetString(myFrame, ID3FN_FILENAME);
          size_t nDataSize = myFrame->GetField(ID3FN_DATA)->Size();
          std::cout << "(" << sDesc << ")["
               << sFileName << "]: " << sMimeType << ", " << nDataSize
               << " bytes" << std::endl;
          delete [] sMimeType;
          delete [] sDesc;
          delete [] sFileName;
          break;
        }
        case ID3FID_UNIQUEFILEID:
        {
          char *sOwner = ID3_GetString(myFrame, ID3FN_OWNER);
          size_t nDataSize = myFrame->Field(ID3FN_DATA).Size();
          std::cout << sOwner << ", " << nDataSize
               << " bytes" << std::endl;
          delete [] sOwner;
          break;
        }
        case ID3FID_PLAYCOUNTER:
        {
          size_t nCounter = myFrame->Field(ID3FN_COUNTER).Get();
          std::cout << nCounter << std::endl;
          break;
        }
        case ID3FID_POPULARIMETER:
        {
          char *sEmail = ID3_GetString(myFrame, ID3FN_EMAIL);
          size_t
            nCounter = myFrame->Field(ID3FN_COUNTER).Get(),
            nRating = myFrame->Field(ID3FN_RATING).Get();
          std::cout << sEmail << ", counter="
               << nCounter << " rating=" << nRating;
          delete [] sEmail;
          break;
        }
        case ID3FID_CRYPTOREG:
        case ID3FID_GROUPINGREG:
        {
          char *sOwner = ID3_GetString(myFrame, ID3FN_OWNER);
          size_t
            nSymbol = myFrame->Field(ID3FN_ID).Get(),
            nDataSize = myFrame->Field(ID3FN_DATA).Size();
          std::cout << "(" << nSymbol << "): " << sOwner
               << ", " << nDataSize << " bytes";
          break;
        }
        case ID3FID_AUDIOCRYPTO:
        case ID3FID_EQUALIZATION:
        case ID3FID_EVENTTIMING:
        case ID3FID_CDID:
        case ID3FID_MPEGLOOKUP:
        case ID3FID_OWNERSHIP:
        case ID3FID_PRIVATE:
        case ID3FID_POSITIONSYNC:
        case ID3FID_BUFFERSIZE:
        case ID3FID_VOLUMEADJ:
        case ID3FID_REVERB:
        case ID3FID_SYNCEDLYRICS:
        case ID3FID_SYNCEDTEMPO:
        case ID3FID_METACRYPTO:
        {
          std::cout << " (unimplemented)" << std::endl;
          break;
        }
        default:
        {
          std::cout << " frame" << std::endl;
          break;
        }
      }
    }
  }
  if(firstLine)
    return 1;

  return 0;
}

int PrintID3v1Tag(char *sFileName)
// code from id3
{
  struct id3 {
    char tag[3];
    char title[30];
    char artist[30];
    char album[30];
    char year[4];
    /* With ID3 v1.0, the comment is 30 chars long */
    /* With ID3 v1.1, if comment[28] == 0 then comment[29] == tracknum */
    char comment[30];
    unsigned char genre;
  } id3v1tag;
  FILE *fp;

  fp = fopen(sFileName, "r"); /* read only */

  if (fp == NULL) { /* file didn't open */
    fprintf(stderr, "fopen: %s: ", sFileName);
    perror("id3v2");
    return -1;
  }
  if (fseek(fp, -128, SEEK_END) < 0) {
    /* problem rewinding */
  } else { /* we rewound successfully */
    if (fread(&id3v1tag, 128, 1, fp) != 1) {
      /* read error */
      fprintf(stderr, "fread: %s: ", sFileName);
      perror("");
    }
  }

  fclose(fp);

    /* This simple detection code has a 1 in 16777216
     * chance of misrecognizing or deleting the last 128
     * bytes of your mp3 if it isn't tagged. ID3 ain't
     * world peace, live with it.
     */

  if (!strncmp(id3v1tag.tag, "TAG", 3))
  {
    std::cout << "id3v1 tag info for " << sFileName << ":" << std::endl;
    printf("Title  : %-30.30s  Artist: %-30.30s\n",
            id3v1tag.title, id3v1tag.artist);
    printf("Album  : %-30.30s  Year: %-4.4s, Genre: %s (%d)\n",
            id3v1tag.album, id3v1tag.year,
            (id3v1tag.genre < GetGenreCount())
            ? GetGenreFromNum(id3v1tag.genre) :
            "Unknown", id3v1tag.genre);
    if (!id3v1tag.comment[28])
      printf("Comment: %-28.28s    Track: %d\n",
             id3v1tag.comment, id3v1tag.comment[29]);
    else
      printf("Comment: %-30.30s\n", id3v1tag.comment);
  }
  else
  {
    return 1;
  }
  return 0;
}

void ListTag(int argc, char *argv[], int optind, int rfc822)
{
  int ret;
  for (size_t nIndex = optind; nIndex < argc; nIndex++)
  {
    bool tags = false;
    ID3_Tag myTag;

    ret = PrintID3v1Tag(argv[nIndex]);
    if (ret == -1)
    {
      continue;
    }
    else if(ret == 0)
    {
      tags = true;
    }
    myTag.Link(argv[nIndex], ID3TT_ID3V2);
    if(!PrintInformation(argv[nIndex],myTag))
      tags = true;
    if(!tags)
      std::cout << argv[nIndex] << ": No ID3 tag" << std::endl;
  }

  return;
}

<commit_msg>make the rfc822 mode work a bit better.  I think rfc822 should have no spaces to the left of the ':', but this is better that what it was before.<commit_after>// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

#if defined HAVE_CONFIG_H
#include <config.h>
#endif

#include <iostream>
#include <cstring>
#include <id3/tag.h>
#include <getopt.h>
#include <cstdlib>
#include <cstdio>
#include <id3/misc_support.h>
#include "frametable.h"
#include "genre.h"

char *GetDescription(const ID3_FrameID eFrameID)
{
  for(int ii = 0; ii < frameTableCount; ii++ )
  {
    if (frameTable[ii].frameID == eFrameID)
      return frameTable[ii].frameLongName;
  }
  return NULL;
}

void PrintFrameHelp(char *sName)
{
    for(int ii = 0; ii < frameTableCount - 1; ii++ )
    {
      std::cout << "    --" << frameTable[ii].frameName << "    "
           << frameTable[ii].frameLongName << std::endl;
    }
    return;
}

void PrintGenreList()
{
  for (int ii = 0; ii < GetGenreCount(); ii++)
    printf("%3d: %s\n", ii, GetGenreFromNum(ii));
}

int PrintInformation(char *sFileName, const ID3_Tag &myTag, int rfc822)
{
  bool firstLine = true;
  const ID3_Frame * myFrame;
  ID3_Tag::ConstIterator *Iter=myTag.CreateIterator();
  for (size_t nFrames = 0; nFrames < myTag.NumFrames(); nFrames++)
  {
    myFrame = Iter->GetNext();

    if(firstLine) {
      if (rfc822)
        std::cout << "\nFilename: " << sFileName << std::endl;
      else
        std::cout << "id3v2 tag info for " << sFileName << ":" << std::endl;
      firstLine = false;
    }

    if (NULL != myFrame)
    {
      const char* desc = myFrame->GetDescription();
      if (!desc) desc = "";
      std::cout << myFrame->GetTextID() << " (" << desc << "): ";
      ID3_FrameID eFrameID = myFrame->GetID();

      switch (eFrameID)
      {
        case ID3FID_ALBUM:
        case ID3FID_BPM:
        case ID3FID_COMPOSER:
        case ID3FID_COPYRIGHT:
        case ID3FID_DATE:
        case ID3FID_PLAYLISTDELAY:
        case ID3FID_ENCODEDBY:
        case ID3FID_LYRICIST:
        case ID3FID_FILETYPE:
        case ID3FID_TIME:
        case ID3FID_CONTENTGROUP:
        case ID3FID_TITLE:
        case ID3FID_SUBTITLE:
        case ID3FID_INITIALKEY:
        case ID3FID_LANGUAGE:
        case ID3FID_SONGLEN:
        case ID3FID_MEDIATYPE:
        case ID3FID_ORIGALBUM:
        case ID3FID_ORIGFILENAME:
        case ID3FID_ORIGLYRICIST:
        case ID3FID_ORIGARTIST:
        case ID3FID_ORIGYEAR:
        case ID3FID_FILEOWNER:
        case ID3FID_LEADARTIST:
        case ID3FID_BAND:
        case ID3FID_CONDUCTOR:
        case ID3FID_MIXARTIST:
        case ID3FID_PARTINSET:
        case ID3FID_PUBLISHER:
        case ID3FID_TRACKNUM:
        case ID3FID_RECORDINGDATES:
        case ID3FID_NETRADIOSTATION:
        case ID3FID_NETRADIOOWNER:
        case ID3FID_SIZE:
        case ID3FID_ISRC:
        case ID3FID_ENCODERSETTINGS:
        case ID3FID_YEAR:
        {
          char *sText = ID3_GetString(myFrame, ID3FN_TEXT);
          std::cout << sText << std::endl;
          delete [] sText;
          break;
        }
        case ID3FID_CONTENTTYPE:
        {
          const char* genre_str;
          int genre_id = 255;
          char *sText = ID3_GetString(myFrame, ID3FN_TEXT);
          sscanf(sText, "(%d)", &genre_id);
          if (genre_id == 255) {
            genre_str = sText;
            genre_id = GetNumFromGenre(sText);
          }
          else
            genre_str = GetGenreFromNum(genre_id);
          std::cout << genre_str << " (" << genre_id << ")" << std::endl;
          delete [] sText;
          break;
        }
        case ID3FID_USERTEXT:
        {
          char
            *sText = ID3_GetString(myFrame, ID3FN_TEXT),
            *sDesc = ID3_GetString(myFrame, ID3FN_DESCRIPTION);
          std::cout << "(" << sDesc << "): " << sText << std::endl;
          delete [] sText;
          delete [] sDesc;
          break;
        }
        case ID3FID_COMMENT:
        case ID3FID_UNSYNCEDLYRICS:
        {
          char
            *sText = ID3_GetString(myFrame, ID3FN_TEXT),
            *sDesc = ID3_GetString(myFrame, ID3FN_DESCRIPTION),
            *sLang = ID3_GetString(myFrame, ID3FN_LANGUAGE);
          std::cout << "(" << sDesc << ")[" << sLang << "]: "
               << sText << std::endl;
          delete [] sText;
          delete [] sDesc;
          delete [] sLang;
          break;
        }
        case ID3FID_WWWAUDIOFILE:
        case ID3FID_WWWARTIST:
        case ID3FID_WWWAUDIOSOURCE:
        case ID3FID_WWWCOMMERCIALINFO:
        case ID3FID_WWWCOPYRIGHT:
        case ID3FID_WWWPUBLISHER:
        case ID3FID_WWWPAYMENT:
        case ID3FID_WWWRADIOPAGE:
        {
          char *sURL = ID3_GetString(myFrame, ID3FN_URL);
          std::cout << sURL << std::endl;
          delete [] sURL;
          break;
        }
        case ID3FID_WWWUSER:
        {
          char
            *sURL = ID3_GetString(myFrame, ID3FN_URL),
            *sDesc = ID3_GetString(myFrame, ID3FN_DESCRIPTION);
          std::cout << "(" << sDesc << "): " << sURL << std::endl;
          delete [] sURL;
          delete [] sDesc;
          break;
        }
        case ID3FID_INVOLVEDPEOPLE:
        {
          // This isn't the right way to do it---will only get first person
          size_t nItems = myFrame->Field(ID3FN_TEXT).GetNumTextItems();
          for (size_t nIndex = 1; nIndex <= nItems; nIndex++)
          {
            char *sPeople = ID3_GetString(myFrame, ID3FN_TEXT, nIndex);
            std::cout << sPeople;
            delete [] sPeople;
            if (nIndex < nItems)
            {
              std::cout << ", ";
            }
          }
          std::cout << std::endl;
          break;
        }
        case ID3FID_PICTURE:
        {
          char
            *sMimeType = ID3_GetString(myFrame, ID3FN_MIMETYPE),
            *sDesc     = ID3_GetString(myFrame, ID3FN_DESCRIPTION),
            *sFormat   = ID3_GetString(myFrame, ID3FN_IMAGEFORMAT);
          size_t
            nPicType   = myFrame->Field(ID3FN_PICTURETYPE).Get(),
            nDataSize  = myFrame->Field(ID3FN_DATA).Size();
          std::cout << "(" << sDesc << ")[" << sFormat << ", "
               << nPicType << "]: " << sMimeType << ", " << nDataSize
               << " bytes" << std::endl;
          delete [] sMimeType;
          delete [] sDesc;
          delete [] sFormat;
          break;
        }
        case ID3FID_GENERALOBJECT:
        {
          char
          *sMimeType = ID3_GetString(myFrame, ID3FN_MIMETYPE),
          *sDesc = ID3_GetString(myFrame, ID3FN_DESCRIPTION),
          *sFileName = ID3_GetString(myFrame, ID3FN_FILENAME);
          size_t nDataSize = myFrame->GetField(ID3FN_DATA)->Size();
          std::cout << "(" << sDesc << ")["
               << sFileName << "]: " << sMimeType << ", " << nDataSize
               << " bytes" << std::endl;
          delete [] sMimeType;
          delete [] sDesc;
          delete [] sFileName;
          break;
        }
        case ID3FID_UNIQUEFILEID:
        {
          char *sOwner = ID3_GetString(myFrame, ID3FN_OWNER);
          size_t nDataSize = myFrame->Field(ID3FN_DATA).Size();
          std::cout << sOwner << ", " << nDataSize
               << " bytes" << std::endl;
          delete [] sOwner;
          break;
        }
        case ID3FID_PLAYCOUNTER:
        {
          size_t nCounter = myFrame->Field(ID3FN_COUNTER).Get();
          std::cout << nCounter << std::endl;
          break;
        }
        case ID3FID_POPULARIMETER:
        {
          char *sEmail = ID3_GetString(myFrame, ID3FN_EMAIL);
          size_t
            nCounter = myFrame->Field(ID3FN_COUNTER).Get(),
            nRating = myFrame->Field(ID3FN_RATING).Get();
          std::cout << sEmail << ", counter="
               << nCounter << " rating=" << nRating;
          delete [] sEmail;
          break;
        }
        case ID3FID_CRYPTOREG:
        case ID3FID_GROUPINGREG:
        {
          char *sOwner = ID3_GetString(myFrame, ID3FN_OWNER);
          size_t
            nSymbol = myFrame->Field(ID3FN_ID).Get(),
            nDataSize = myFrame->Field(ID3FN_DATA).Size();
          std::cout << "(" << nSymbol << "): " << sOwner
               << ", " << nDataSize << " bytes";
          break;
        }
        case ID3FID_AUDIOCRYPTO:
        case ID3FID_EQUALIZATION:
        case ID3FID_EVENTTIMING:
        case ID3FID_CDID:
        case ID3FID_MPEGLOOKUP:
        case ID3FID_OWNERSHIP:
        case ID3FID_PRIVATE:
        case ID3FID_POSITIONSYNC:
        case ID3FID_BUFFERSIZE:
        case ID3FID_VOLUMEADJ:
        case ID3FID_REVERB:
        case ID3FID_SYNCEDLYRICS:
        case ID3FID_SYNCEDTEMPO:
        case ID3FID_METACRYPTO:
        {
          std::cout << " (unimplemented)" << std::endl;
          break;
        }
        default:
        {
          std::cout << " frame" << std::endl;
          break;
        }
      }
    }
  }
  if(firstLine)
    return 1;

  return 0;
}

int PrintID3v1Tag(char *sFileName)
// code from id3
{
  struct id3 {
    char tag[3];
    char title[30];
    char artist[30];
    char album[30];
    char year[4];
    /* With ID3 v1.0, the comment is 30 chars long */
    /* With ID3 v1.1, if comment[28] == 0 then comment[29] == tracknum */
    char comment[30];
    unsigned char genre;
  } id3v1tag;
  FILE *fp;

  fp = fopen(sFileName, "r"); /* read only */

  if (fp == NULL) { /* file didn't open */
    fprintf(stderr, "fopen: %s: ", sFileName);
    perror("id3v2");
    return -1;
  }
  if (fseek(fp, -128, SEEK_END) < 0) {
    /* problem rewinding */
  } else { /* we rewound successfully */
    if (fread(&id3v1tag, 128, 1, fp) != 1) {
      /* read error */
      fprintf(stderr, "fread: %s: ", sFileName);
      perror("");
    }
  }

  fclose(fp);

    /* This simple detection code has a 1 in 16777216
     * chance of misrecognizing or deleting the last 128
     * bytes of your mp3 if it isn't tagged. ID3 ain't
     * world peace, live with it.
     */

  if (!strncmp(id3v1tag.tag, "TAG", 3))
  {
    std::cout << "id3v1 tag info for " << sFileName << ":" << std::endl;
    printf("Title  : %-30.30s  Artist: %-30.30s\n",
            id3v1tag.title, id3v1tag.artist);
    printf("Album  : %-30.30s  Year: %-4.4s, Genre: %s (%d)\n",
            id3v1tag.album, id3v1tag.year,
            (id3v1tag.genre < GetGenreCount())
            ? GetGenreFromNum(id3v1tag.genre) :
            "Unknown", id3v1tag.genre);
    if (!id3v1tag.comment[28])
      printf("Comment: %-28.28s    Track: %d\n",
             id3v1tag.comment, id3v1tag.comment[29]);
    else
      printf("Comment: %-30.30s\n", id3v1tag.comment);
  }
  else
  {
    return 1;
  }
  return 0;
}

void ListTag(int argc, char *argv[], int optind, int rfc822)
{
  int ret;
  for (size_t nIndex = optind; nIndex < argc; nIndex++)
  {
    bool tags = false;
    ID3_Tag myTag;

    if (!rfc822)
    {
      ret = PrintID3v1Tag(argv[nIndex]);
      if (ret == -1)
      {
        continue;
      }
      else if(ret == 0)
      {
        tags = true;
      }
    }
    myTag.Link(argv[nIndex], ID3TT_ID3V2);
    if(!PrintInformation(argv[nIndex],myTag,rfc822))
      tags = true;
    if(!tags)
      std::cout << argv[nIndex] << ": No ID3 tag" << std::endl;
  }

  return;
}

<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#define DEBUG

#ifdef DEBUG
static const bool debug = true;
#else
static const bool debug = false;
#endif

#define TIMER_START(name) Timer name_timer;
#define TIMER_END(name) std::cout << #name << " took " << name_timer.elapsed() << "s" << std::endl;

#include <iostream>
#include <cstdio>

#include "Compiler.hpp"

#include "Timer.hpp"
#include "DebugTimer.hpp"
#include "Options.hpp"

#include "StringPool.hpp"
#include "FunctionTable.hpp"

#include "ast/Program.hpp"

#include "AssemblyFileWriter.hpp"
#include "ContextAnnotator.hpp"
#include "VariableChecker.hpp"
#include "StringChecker.hpp"
#include "FunctionChecker.hpp"
#include "OptimizationEngine.hpp"
#include "IntermediateCompiler.hpp"

#include "SemanticalException.hpp"

#include "parser/SpiritParser.hpp"

#include "il/IntermediateProgram.hpp"

using std::string;
using std::cout;
using std::endl;

using namespace eddic;

int Compiler::compile(const string& file) {
    cout << "Compile " << file << endl;

    Timer timer;

    string output = Options::get(ValueOption::OUTPUT);

    int code = 0;
    try {
        TIMER_START(parsing)

        SpiritParser parser;

        //The program to build
        ASTProgram program;

        //Parse the file into the program
        bool parsing = parser.parse(file, program);

        TIMER_END(parsing)

        if(parsing){
            defineContexts(program);

            StringPool pool;
            FunctionTable functionTable;

            //Semantical analysis
            checkVariables(program);
            checkStrings(program, pool);
            checkFunctions(program, functionTable);

            //Optimize the AST
            optimize(program);

            //Write Intermediate representation of the parse tree
            IntermediateProgram il;
            writeIL(program, pool, il);

            AssemblyFileWriter writer("output.asm");

            //Write assembly code
            il.writeAsm(writer);

            if(!Options::isSet(BooleanOption::ASSEMBLY_ONLY)){
                execCommand("as --32 -o output.o output.asm");

                string ldCommand = "gcc -m32 -static -o ";
                ldCommand += output;
                ldCommand += " output.o -lc";

                execCommand(ldCommand);

                //Remove temporary files
                remove("output.asm");
                remove("output.o");
            }

        }
    } catch (const SemanticalException& e) {
        cout << e.what() << endl;
        code = 1;
    }

    cout << "Compilation took " << timer.elapsed() << "s" << endl;

    return code;
}

void eddic::defineContexts(ASTProgram& program){
    DebugTimer<debug> timer("Annotate contexts");
    ContextAnnotator annotator;
    annotator.annotate(program);
}

void eddic::checkVariables(ASTProgram& program){
    DebugTimer<debug> timer("Variable checking");
    VariableChecker checker;
    checker.check(program);
}

void eddic::checkStrings(ASTProgram& program, StringPool& pool){
    DebugTimer<debug> timer("Strings checking");
    StringChecker checker;
    checker.check(program, pool);
}

void eddic::checkFunctions(ASTProgram& program, FunctionTable& functionTable){
    DebugTimer<debug> timer("Functions checking");
    FunctionChecker checker;
    checker.check(program, functionTable);
}

void eddic::optimize(ASTProgram& program){
    DebugTimer<debug> timer("Optimization");
    OptimizationEngine engine;
    engine.optimize(program);
}

void eddic::writeIL(ASTProgram& program, StringPool& pool, IntermediateProgram& intermediateProgram){
    DebugTimer<debug> timer("Compile into intermediate level");
    IntermediateCompiler compiler;
    compiler.compile(program, pool, intermediateProgram);
}

void eddic::execCommand(const string& command) {
    DebugTimer<debug> timer("Exec " + command);
    cout << "eddic : exec command : " << command << endl;

    char buffer[1024];

    FILE* stream = popen(command.c_str(), "r");

    while (fgets(buffer, 1024, stream) != NULL) {
        cout << buffer;
    }

    pclose(stream);
}
<commit_msg>Debug compiler<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#define DEBUG

#ifdef DEBUG
static const bool debug = true;
#else
static const bool debug = false;
#endif

#define TIMER_START(name) Timer name_timer;
#define TIMER_END(name) std::cout << #name << " took " << name_timer.elapsed() << "s" << std::endl;

#include <iostream>
#include <cstdio>

#include "Compiler.hpp"

#include "Timer.hpp"
#include "DebugTimer.hpp"
#include "Options.hpp"

#include "StringPool.hpp"
#include "FunctionTable.hpp"

#include "ast/Program.hpp"

#include "AssemblyFileWriter.hpp"
#include "ContextAnnotator.hpp"
#include "VariableChecker.hpp"
#include "StringChecker.hpp"
#include "FunctionChecker.hpp"
#include "OptimizationEngine.hpp"
#include "IntermediateCompiler.hpp"

#include "SemanticalException.hpp"

#include "parser/SpiritParser.hpp"

#include "il/IntermediateProgram.hpp"

using std::string;
using std::cout;
using std::endl;

using namespace eddic;

int Compiler::compile(const string& file) {
    cout << "Compile " << file << endl;

    Timer timer;

    string output = Options::get(ValueOption::OUTPUT);

    int code = 0;
    try {
        TIMER_START(parsing)

        SpiritParser parser;

        //The program to build
        ASTProgram program;

        //Parse the file into the program
        bool parsing = parser.parse(file, program);

        TIMER_END(parsing)

        if(parsing){
            defineContexts(program);

            StringPool pool;
            FunctionTable functionTable;

            //Semantical analysis
            checkVariables(program);
            checkStrings(program, pool);
            checkFunctions(program, functionTable);

            //Optimize the AST
            optimize(program);

            //Write Intermediate representation of the parse tree
            IntermediateProgram il;
            writeIL(program, pool, il);

            TIMER_START(write_asm)
            AssemblyFileWriter writer("output.asm");

            //Write assembly code
            il.writeAsm(writer);
            TIMER_END(write_asm)

            if(!Options::isSet(BooleanOption::ASSEMBLY_ONLY)){
                execCommand("as --32 -o output.o output.asm");

                string ldCommand = "gcc -m32 -static -o ";
                ldCommand += output;
                ldCommand += " output.o -lc";

                execCommand(ldCommand);

                //Remove temporary files
                remove("output.asm");
                remove("output.o");
            }

        }
    } catch (const SemanticalException& e) {
        cout << e.what() << endl;
        code = 1;
    }

    cout << "Compilation took " << timer.elapsed() << "s" << endl;

    return code;
}

void eddic::defineContexts(ASTProgram& program){
    DebugTimer<debug> timer("Annotate contexts");
    ContextAnnotator annotator;
    annotator.annotate(program);
}

void eddic::checkVariables(ASTProgram& program){
    DebugTimer<debug> timer("Variable checking");
    VariableChecker checker;
    checker.check(program);
}

void eddic::checkStrings(ASTProgram& program, StringPool& pool){
    DebugTimer<debug> timer("Strings checking");
    StringChecker checker;
    checker.check(program, pool);
}

void eddic::checkFunctions(ASTProgram& program, FunctionTable& functionTable){
    DebugTimer<debug> timer("Functions checking");
    FunctionChecker checker;
    checker.check(program, functionTable);
}

void eddic::optimize(ASTProgram& program){
    DebugTimer<debug> timer("Optimization");
    OptimizationEngine engine;
    engine.optimize(program);
}

void eddic::writeIL(ASTProgram& program, StringPool& pool, IntermediateProgram& intermediateProgram){
    DebugTimer<debug> timer("Compile into intermediate level");
    IntermediateCompiler compiler;
    compiler.compile(program, pool, intermediateProgram);
}

void eddic::execCommand(const string& command) {
    DebugTimer<debug> timer("Exec " + command);
    cout << "eddic : exec command : " << command << endl;

    char buffer[1024];

    FILE* stream = popen(command.c_str(), "r");

    while (fgets(buffer, 1024, stream) != NULL) {
        cout << buffer;
    }

    pclose(stream);
}
<|endoftext|>


<commit_before>/**
 * @file    Database.cpp
 * @ingroup SQLiteCpp
 * @brief   Management of a SQLite Database Connection.
 *
 * Copyright (c) 2012-2019 Sebastien Rombauts (sebastien.rombauts@gmail.com)
 *
 * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
 * or copy at http://opensource.org/licenses/MIT)
 */
#include <SQLiteCpp/Database.h>

#include <SQLiteCpp/Statement.h>
#include <SQLiteCpp/Assertion.h>
#include <SQLiteCpp/Exception.h>

#include <sqlite3.h>
#include <fstream>
#include <string.h>

#ifndef SQLITE_DETERMINISTIC
#define SQLITE_DETERMINISTIC 0x800
#endif // SQLITE_DETERMINISTIC

namespace SQLite
{

const int   OPEN_READONLY   = SQLITE_OPEN_READONLY;
const int   OPEN_READWRITE  = SQLITE_OPEN_READWRITE;
const int   OPEN_CREATE     = SQLITE_OPEN_CREATE;
const int   OPEN_URI        = SQLITE_OPEN_URI;

const int   OK              = SQLITE_OK;

const char* VERSION         = SQLITE_VERSION;
const int   VERSION_NUMBER  = SQLITE_VERSION_NUMBER;

// Return SQLite version string using runtime call to the compiled library
const char* getLibVersion() noexcept // nothrow
{
    return sqlite3_libversion();
}

// Return SQLite version number using runtime call to the compiled library
int getLibVersionNumber() noexcept // nothrow
{
    return sqlite3_libversion_number();
}

// Open the provided database UTF-8 filename with SQLite::OPEN_xxx provided flags.
Database::Database(const char* apFilename,
                   const int   aFlags         /* = SQLite::OPEN_READONLY*/,
                   const int   aBusyTimeoutMs /* = 0 */,
                   const char* apVfs          /* = nullptr*/) :
    mpSQLite(nullptr),
    mFilename(apFilename)
{
    const int ret = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, apVfs);
    if (SQLITE_OK != ret)
    {
        const SQLite::Exception exception(mpSQLite, ret); // must create before closing
        sqlite3_close(mpSQLite); // close is required even in case of error on opening
        throw exception;
    }
    if (aBusyTimeoutMs > 0)
    {
        setBusyTimeout(aBusyTimeoutMs);
    }
}

// Open the provided database UTF-8 filename with SQLite::OPEN_xxx provided flags.
Database::Database(const std::string& aFilename,
                   const int          aFlags         /* = SQLite::OPEN_READONLY*/,
                   const int          aBusyTimeoutMs /* = 0 */,
                   const std::string& aVfs           /* = "" */) :
    mpSQLite(nullptr),
    mFilename(aFilename)
{
    const int ret = sqlite3_open_v2(aFilename.c_str(), &mpSQLite, aFlags, aVfs.empty() ? nullptr : aVfs.c_str());
    if (SQLITE_OK != ret)
    {
        const SQLite::Exception exception(mpSQLite, ret); // must create before closing
        sqlite3_close(mpSQLite); // close is required even in case of error on opening
        throw exception;
    }
    if (aBusyTimeoutMs > 0)
    {
        setBusyTimeout(aBusyTimeoutMs);
    }
}

// Close the SQLite database connection.
Database::~Database()
{
    const int ret = sqlite3_close(mpSQLite);

    // Avoid unreferenced variable warning when build in release mode
    (void) ret;

    // Only case of error is SQLITE_BUSY: "database is locked" (some statements are not finalized)
    // Never throw an exception in a destructor :
    SQLITECPP_ASSERT(SQLITE_OK == ret, "database is locked");  // See SQLITECPP_ENABLE_ASSERT_HANDLER
}

/**
 * @brief Set a busy handler that sleeps for a specified amount of time when a table is locked.
 *
 *  This is useful in multithreaded program to handle case where a table is locked for writting by a thread.
 *  Any other thread cannot access the table and will receive a SQLITE_BUSY error:
 *  setting a timeout will wait and retry up to the time specified before returning this SQLITE_BUSY error.
 *  Reading the value of timeout for current connection can be done with SQL query "PRAGMA busy_timeout;".
 *  Default busy timeout is 0ms.
 *
 * @param[in] aBusyTimeoutMs    Amount of milliseconds to wait before returning SQLITE_BUSY
 *
 * @throw SQLite::Exception in case of error
 */
void Database::setBusyTimeout(const int aBusyTimeoutMs)
{
    const int ret = sqlite3_busy_timeout(mpSQLite, aBusyTimeoutMs);
    check(ret);
}

// Shortcut to execute one or multiple SQL statements without results (UPDATE, INSERT, ALTER, COMMIT, CREATE...).
int Database::exec(const char* apQueries)
{
    const int ret = sqlite3_exec(mpSQLite, apQueries, nullptr, nullptr, nullptr);
    check(ret);

    // Return the number of rows modified by those SQL statements (INSERT, UPDATE or DELETE only)
    return sqlite3_changes(mpSQLite);
}

// Shortcut to execute a one step query and fetch the first column of the result.
// WARNING: Be very careful with this dangerous method: you have to
// make a COPY OF THE result, else it will be destroy before the next line
// (when the underlying temporary Statement and Column objects are destroyed)
// this is an issue only for pointer type result (ie. char* and blob)
// (use the Column copy-constructor)
Column Database::execAndGet(const char* apQuery)
{
    Statement query(*this, apQuery);
    (void)query.executeStep(); // Can return false if no result, which will throw next line in getColumn()
    return query.getColumn(0);
}

// Shortcut to test if a table exists.
bool Database::tableExists(const char* apTableName)
{
    Statement query(*this, "SELECT count(*) FROM sqlite_master WHERE type='table' AND name=?");
    query.bind(1, apTableName);
    (void)query.executeStep(); // Cannot return false, as the above query always return a result
    return (1 == query.getColumn(0).getInt());
}

// Get the rowid of the most recent successful INSERT into the database from the current connection.
long long Database::getLastInsertRowid() const noexcept // nothrow
{
    return sqlite3_last_insert_rowid(mpSQLite);
}

// Get total number of rows modified by all INSERT, UPDATE or DELETE statement since connection.
int Database::getTotalChanges() const noexcept // nothrow
{
    return sqlite3_total_changes(mpSQLite);
}

// Return the numeric result code for the most recent failed API call (if any).
int Database::getErrorCode() const noexcept // nothrow
{
    return sqlite3_errcode(mpSQLite);
}

// Return the extended numeric result code for the most recent failed API call (if any).
int Database::getExtendedErrorCode() const noexcept // nothrow
{
    return sqlite3_extended_errcode(mpSQLite);
}

// Return UTF-8 encoded English language explanation of the most recent failed API call (if any).
const char* Database::getErrorMsg() const noexcept // nothrow
{
    return sqlite3_errmsg(mpSQLite);
}

// Attach a custom function to your sqlite database. Assumes UTF8 text representation.
// Parameter details can be found here: http://www.sqlite.org/c3ref/create_function.html
void Database::createFunction(const char*   apFuncName,
                              int           aNbArg,
                              bool          abDeterministic,
                              void*         apApp,
                              void        (*apFunc)(sqlite3_context *, int, sqlite3_value **),
                              void        (*apStep)(sqlite3_context *, int, sqlite3_value **) /* = nullptr */,
                              void        (*apFinal)(sqlite3_context *) /* = nullptr */, // NOLINT(readability/casting)
                              void        (*apDestroy)(void *) /* = nullptr */)
{
    int textRep = SQLITE_UTF8;
    // optimization if deterministic function (e.g. of nondeterministic function random())
    if (abDeterministic)
    {
        textRep = textRep | SQLITE_DETERMINISTIC;
    }
    const int ret = sqlite3_create_function_v2(mpSQLite, apFuncName, aNbArg, textRep,
                                               apApp, apFunc, apStep, apFinal, apDestroy);
    check(ret);
}

// Load an extension into the sqlite database. Only affects the current connection.
// Parameter details can be found here: http://www.sqlite.org/c3ref/load_extension.html
void Database::loadExtension(const char* apExtensionName, const char *apEntryPointName)
{
#ifdef SQLITE_OMIT_LOAD_EXTENSION
    // Unused
    (void)apExtensionName;
    (void)apEntryPointName;

    throw std::runtime_error("sqlite extensions are disabled");
#else
#ifdef SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION // Since SQLite 3.13 (2016-05-18):
    // Security warning:
    // It is recommended that the SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION method be used to enable only this interface.
    // The use of the sqlite3_enable_load_extension() interface should be avoided to keep the SQL load_extension()
    // disabled and prevent SQL injections from giving attackers access to extension loading capabilities.
    // (NOTE: not using nullptr: cannot pass object of non-POD type 'std::__1::nullptr_t' through variadic function)
    int ret = sqlite3_db_config(mpSQLite, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, NULL); // NOTE: not using nullptr
#else
    int ret = sqlite3_enable_load_extension(mpSQLite, 1);
#endif
    check(ret);

    ret = sqlite3_load_extension(mpSQLite, apExtensionName, apEntryPointName, 0);
    check(ret);
#endif
}

// Set the key for the current sqlite database instance.
void Database::key(const std::string& aKey) const
{
    int passLen = static_cast<int>(aKey.length());
#ifdef SQLITE_HAS_CODEC
    if (passLen > 0)
    {
        const int ret = sqlite3_key(mpSQLite, aKey.c_str(), passLen);
        check(ret);
    }
#else // SQLITE_HAS_CODEC
    if (passLen > 0)
    {
        const SQLite::Exception exception("No encryption support, recompile with SQLITE_HAS_CODEC to enable.");
        throw exception;
    }
#endif // SQLITE_HAS_CODEC
}

// Reset the key for the current sqlite database instance.
void Database::rekey(const std::string& aNewKey) const
{
#ifdef SQLITE_HAS_CODEC
    int passLen = aNewKey.length();
    if (passLen > 0)
    {
        const int ret = sqlite3_rekey(mpSQLite, aNewKey.c_str(), passLen);
        check(ret);
    }
    else
    {
        const int ret = sqlite3_rekey(mpSQLite, nullptr, 0);
        check(ret);
    }
#else // SQLITE_HAS_CODEC
    static_cast<void>(aNewKey); // silence unused parameter warning
    const SQLite::Exception exception("No encryption support, recompile with SQLITE_HAS_CODEC to enable.");
    throw exception;
#endif // SQLITE_HAS_CODEC
}

// Test if a file contains an unencrypted database.
bool Database::isUnencrypted(const std::string& aFilename)
{
    if (aFilename.length() > 0)
    {
        std::ifstream fileBuffer(aFilename.c_str(), std::ios::in | std::ios::binary);
        char header[16];
        if (fileBuffer.is_open())
        {
            fileBuffer.seekg(0, std::ios::beg);
            fileBuffer.getline(header, 16);
            fileBuffer.close();
        }
        else
        {
            const SQLite::Exception exception("Error opening file: " + aFilename);
            throw exception;
        }
        return strncmp(header, "SQLite format 3\000", 16) == 0;
    }
    const SQLite::Exception exception("Could not open database, the aFilename parameter was empty.");
    throw exception;
}

// This is a reference implementation of live backup taken from the official sit:
// https://www.sqlite.org/backup.html

int Database::backup(const char* zFilename, BackupType type) {
    /* Open the database file identified by zFilename. Exit early if this fails. */
    sqlite3* pFile;
    int rc = sqlite3_open(zFilename, &pFile);
    if (rc == SQLITE_OK)
    {
        /* If this is a 'load' operation (isSave==0), then data is copied
        ** from the database file just opened to database mpSQLite.
        ** Otherwise, if this is a 'save' operation (isSave==1), then data
        ** is copied from mpSQLite to pFile.  Set the variables pFrom and
        ** pTo accordingly. */
        sqlite3* pFrom = (type == Save ? mpSQLite : pFile);
        sqlite3* pTo = (type == Save ? pFile : mpSQLite);

        /* Set up the backup procedure to copy from the "main" database of
        ** connection pFile to the main database of connection mpSQLite.
        ** If something goes wrong, pBackup will be set to NULL and an error
        ** code and message left in connection pTo.
        **
        ** If the backup object is successfully created, call backup_step()
        ** to copy data from pFile to mpSQLite. Then call backup_finish()
        ** to release resources associated with the pBackup object.  If an
        ** error occurred, then an error code and message will be left in
        ** connection pTo. If no error occurred, then the error code belonging
        ** to pTo is set to SQLITE_OK.
        */
        sqlite3_backup *pBackup = sqlite3_backup_init(pTo, "main", pFrom, "main");
        if (pBackup)
        {
            sqlite3_backup_step(pBackup, -1);
            sqlite3_backup_finish(pBackup);
        }
        rc = sqlite3_errcode(pTo);
    }

    /* Close the database connection opened on database file zFilename
    ** and return the result of this function. */
    sqlite3_close(pFile);
    return rc;
}

}  // namespace SQLite
<commit_msg>Minor cleanup on throwing exception in Database<commit_after>/**
 * @file    Database.cpp
 * @ingroup SQLiteCpp
 * @brief   Management of a SQLite Database Connection.
 *
 * Copyright (c) 2012-2019 Sebastien Rombauts (sebastien.rombauts@gmail.com)
 *
 * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
 * or copy at http://opensource.org/licenses/MIT)
 */
#include <SQLiteCpp/Database.h>

#include <SQLiteCpp/Statement.h>
#include <SQLiteCpp/Assertion.h>
#include <SQLiteCpp/Exception.h>

#include <sqlite3.h>
#include <fstream>
#include <string.h>

#ifndef SQLITE_DETERMINISTIC
#define SQLITE_DETERMINISTIC 0x800
#endif // SQLITE_DETERMINISTIC

namespace SQLite
{

const int   OPEN_READONLY   = SQLITE_OPEN_READONLY;
const int   OPEN_READWRITE  = SQLITE_OPEN_READWRITE;
const int   OPEN_CREATE     = SQLITE_OPEN_CREATE;
const int   OPEN_URI        = SQLITE_OPEN_URI;

const int   OK              = SQLITE_OK;

const char* VERSION         = SQLITE_VERSION;
const int   VERSION_NUMBER  = SQLITE_VERSION_NUMBER;

// Return SQLite version string using runtime call to the compiled library
const char* getLibVersion() noexcept // nothrow
{
    return sqlite3_libversion();
}

// Return SQLite version number using runtime call to the compiled library
int getLibVersionNumber() noexcept // nothrow
{
    return sqlite3_libversion_number();
}

// Open the provided database UTF-8 filename with SQLite::OPEN_xxx provided flags.
Database::Database(const char* apFilename,
                   const int   aFlags         /* = SQLite::OPEN_READONLY*/,
                   const int   aBusyTimeoutMs /* = 0 */,
                   const char* apVfs          /* = nullptr*/) :
    mpSQLite(nullptr),
    mFilename(apFilename)
{
    const int ret = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, apVfs);
    if (SQLITE_OK != ret)
    {
        const SQLite::Exception exception(mpSQLite, ret); // must create before closing
        sqlite3_close(mpSQLite); // close is required even in case of error on opening
        throw exception;
    }
    if (aBusyTimeoutMs > 0)
    {
        setBusyTimeout(aBusyTimeoutMs);
    }
}

// Open the provided database UTF-8 filename with SQLite::OPEN_xxx provided flags.
Database::Database(const std::string& aFilename,
                   const int          aFlags         /* = SQLite::OPEN_READONLY*/,
                   const int          aBusyTimeoutMs /* = 0 */,
                   const std::string& aVfs           /* = "" */) :
    mpSQLite(nullptr),
    mFilename(aFilename)
{
    const int ret = sqlite3_open_v2(aFilename.c_str(), &mpSQLite, aFlags, aVfs.empty() ? nullptr : aVfs.c_str());
    if (SQLITE_OK != ret)
    {
        const SQLite::Exception exception(mpSQLite, ret); // must create before closing
        sqlite3_close(mpSQLite); // close is required even in case of error on opening
        throw exception;
    }
    if (aBusyTimeoutMs > 0)
    {
        setBusyTimeout(aBusyTimeoutMs);
    }
}

// Close the SQLite database connection.
Database::~Database()
{
    const int ret = sqlite3_close(mpSQLite);

    // Avoid unreferenced variable warning when build in release mode
    (void) ret;

    // Only case of error is SQLITE_BUSY: "database is locked" (some statements are not finalized)
    // Never throw an exception in a destructor :
    SQLITECPP_ASSERT(SQLITE_OK == ret, "database is locked");  // See SQLITECPP_ENABLE_ASSERT_HANDLER
}

/**
 * @brief Set a busy handler that sleeps for a specified amount of time when a table is locked.
 *
 *  This is useful in multithreaded program to handle case where a table is locked for writting by a thread.
 *  Any other thread cannot access the table and will receive a SQLITE_BUSY error:
 *  setting a timeout will wait and retry up to the time specified before returning this SQLITE_BUSY error.
 *  Reading the value of timeout for current connection can be done with SQL query "PRAGMA busy_timeout;".
 *  Default busy timeout is 0ms.
 *
 * @param[in] aBusyTimeoutMs    Amount of milliseconds to wait before returning SQLITE_BUSY
 *
 * @throw SQLite::Exception in case of error
 */
void Database::setBusyTimeout(const int aBusyTimeoutMs)
{
    const int ret = sqlite3_busy_timeout(mpSQLite, aBusyTimeoutMs);
    check(ret);
}

// Shortcut to execute one or multiple SQL statements without results (UPDATE, INSERT, ALTER, COMMIT, CREATE...).
int Database::exec(const char* apQueries)
{
    const int ret = sqlite3_exec(mpSQLite, apQueries, nullptr, nullptr, nullptr);
    check(ret);

    // Return the number of rows modified by those SQL statements (INSERT, UPDATE or DELETE only)
    return sqlite3_changes(mpSQLite);
}

// Shortcut to execute a one step query and fetch the first column of the result.
// WARNING: Be very careful with this dangerous method: you have to
// make a COPY OF THE result, else it will be destroy before the next line
// (when the underlying temporary Statement and Column objects are destroyed)
// this is an issue only for pointer type result (ie. char* and blob)
// (use the Column copy-constructor)
Column Database::execAndGet(const char* apQuery)
{
    Statement query(*this, apQuery);
    (void)query.executeStep(); // Can return false if no result, which will throw next line in getColumn()
    return query.getColumn(0);
}

// Shortcut to test if a table exists.
bool Database::tableExists(const char* apTableName)
{
    Statement query(*this, "SELECT count(*) FROM sqlite_master WHERE type='table' AND name=?");
    query.bind(1, apTableName);
    (void)query.executeStep(); // Cannot return false, as the above query always return a result
    return (1 == query.getColumn(0).getInt());
}

// Get the rowid of the most recent successful INSERT into the database from the current connection.
long long Database::getLastInsertRowid() const noexcept // nothrow
{
    return sqlite3_last_insert_rowid(mpSQLite);
}

// Get total number of rows modified by all INSERT, UPDATE or DELETE statement since connection.
int Database::getTotalChanges() const noexcept // nothrow
{
    return sqlite3_total_changes(mpSQLite);
}

// Return the numeric result code for the most recent failed API call (if any).
int Database::getErrorCode() const noexcept // nothrow
{
    return sqlite3_errcode(mpSQLite);
}

// Return the extended numeric result code for the most recent failed API call (if any).
int Database::getExtendedErrorCode() const noexcept // nothrow
{
    return sqlite3_extended_errcode(mpSQLite);
}

// Return UTF-8 encoded English language explanation of the most recent failed API call (if any).
const char* Database::getErrorMsg() const noexcept // nothrow
{
    return sqlite3_errmsg(mpSQLite);
}

// Attach a custom function to your sqlite database. Assumes UTF8 text representation.
// Parameter details can be found here: http://www.sqlite.org/c3ref/create_function.html
void Database::createFunction(const char*   apFuncName,
                              int           aNbArg,
                              bool          abDeterministic,
                              void*         apApp,
                              void        (*apFunc)(sqlite3_context *, int, sqlite3_value **),
                              void        (*apStep)(sqlite3_context *, int, sqlite3_value **) /* = nullptr */,
                              void        (*apFinal)(sqlite3_context *) /* = nullptr */, // NOLINT(readability/casting)
                              void        (*apDestroy)(void *) /* = nullptr */)
{
    int textRep = SQLITE_UTF8;
    // optimization if deterministic function (e.g. of nondeterministic function random())
    if (abDeterministic)
    {
        textRep = textRep | SQLITE_DETERMINISTIC;
    }
    const int ret = sqlite3_create_function_v2(mpSQLite, apFuncName, aNbArg, textRep,
                                               apApp, apFunc, apStep, apFinal, apDestroy);
    check(ret);
}

// Load an extension into the sqlite database. Only affects the current connection.
// Parameter details can be found here: http://www.sqlite.org/c3ref/load_extension.html
void Database::loadExtension(const char* apExtensionName, const char *apEntryPointName)
{
#ifdef SQLITE_OMIT_LOAD_EXTENSION
    // Unused
    (void)apExtensionName;
    (void)apEntryPointName;

    throw SQLite::Exception("sqlite extensions are disabled");
#else
#ifdef SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION // Since SQLite 3.13 (2016-05-18):
    // Security warning:
    // It is recommended that the SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION method be used to enable only this interface.
    // The use of the sqlite3_enable_load_extension() interface should be avoided to keep the SQL load_extension()
    // disabled and prevent SQL injections from giving attackers access to extension loading capabilities.
    // (NOTE: not using nullptr: cannot pass object of non-POD type 'std::__1::nullptr_t' through variadic function)
    int ret = sqlite3_db_config(mpSQLite, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, NULL); // NOTE: not using nullptr
#else
    int ret = sqlite3_enable_load_extension(mpSQLite, 1);
#endif
    check(ret);

    ret = sqlite3_load_extension(mpSQLite, apExtensionName, apEntryPointName, 0);
    check(ret);
#endif
}

// Set the key for the current sqlite database instance.
void Database::key(const std::string& aKey) const
{
    int passLen = static_cast<int>(aKey.length());
#ifdef SQLITE_HAS_CODEC
    if (passLen > 0)
    {
        const int ret = sqlite3_key(mpSQLite, aKey.c_str(), passLen);
        check(ret);
    }
#else // SQLITE_HAS_CODEC
    if (passLen > 0)
    {
        throw SQLite::Exception("No encryption support, recompile with SQLITE_HAS_CODEC to enable.");
    }
#endif // SQLITE_HAS_CODEC
}

// Reset the key for the current sqlite database instance.
void Database::rekey(const std::string& aNewKey) const
{
#ifdef SQLITE_HAS_CODEC
    int passLen = aNewKey.length();
    if (passLen > 0)
    {
        const int ret = sqlite3_rekey(mpSQLite, aNewKey.c_str(), passLen);
        check(ret);
    }
    else
    {
        const int ret = sqlite3_rekey(mpSQLite, nullptr, 0);
        check(ret);
    }
#else // SQLITE_HAS_CODEC
    static_cast<void>(aNewKey); // silence unused parameter warning
    throw SQLite::Exception("No encryption support, recompile with SQLITE_HAS_CODEC to enable.");
#endif // SQLITE_HAS_CODEC
}

// Test if a file contains an unencrypted database.
bool Database::isUnencrypted(const std::string& aFilename)
{
    if (aFilename.empty())
    {
        throw SQLite::Exception("Could not open database, the aFilename parameter was empty.");
    }

    std::ifstream fileBuffer(aFilename.c_str(), std::ios::in | std::ios::binary);
    char header[16];
    if (fileBuffer.is_open())
    {
        fileBuffer.seekg(0, std::ios::beg);
        fileBuffer.getline(header, 16);
        fileBuffer.close();
    }
    else
    {
        throw SQLite::Exception("Error opening file: " + aFilename);
    }

    return strncmp(header, "SQLite format 3\000", 16) == 0;
}

// This is a reference implementation of live backup taken from the official sit:
// https://www.sqlite.org/backup.html

int Database::backup(const char* zFilename, BackupType type) {
    /* Open the database file identified by zFilename. Exit early if this fails. */
    sqlite3* pFile;
    int rc = sqlite3_open(zFilename, &pFile);
    if (rc == SQLITE_OK)
    {
        /* If this is a 'load' operation (isSave==0), then data is copied
        ** from the database file just opened to database mpSQLite.
        ** Otherwise, if this is a 'save' operation (isSave==1), then data
        ** is copied from mpSQLite to pFile.  Set the variables pFrom and
        ** pTo accordingly. */
        sqlite3* pFrom = (type == Save ? mpSQLite : pFile);
        sqlite3* pTo = (type == Save ? pFile : mpSQLite);

        /* Set up the backup procedure to copy from the "main" database of
        ** connection pFile to the main database of connection mpSQLite.
        ** If something goes wrong, pBackup will be set to NULL and an error
        ** code and message left in connection pTo.
        **
        ** If the backup object is successfully created, call backup_step()
        ** to copy data from pFile to mpSQLite. Then call backup_finish()
        ** to release resources associated with the pBackup object.  If an
        ** error occurred, then an error code and message will be left in
        ** connection pTo. If no error occurred, then the error code belonging
        ** to pTo is set to SQLITE_OK.
        */
        sqlite3_backup *pBackup = sqlite3_backup_init(pTo, "main", pFrom, "main");
        if (pBackup)
        {
            sqlite3_backup_step(pBackup, -1);
            sqlite3_backup_finish(pBackup);
        }
        rc = sqlite3_errcode(pTo);
    }

    /* Close the database connection opened on database file zFilename
    ** and return the result of this function. */
    sqlite3_close(pFile);
    return rc;
}

}  // namespace SQLite
<|endoftext|>


<commit_before>// Copyright 2015 Nikita Chudinov

#include "Database.h"
#include <string>
#include <cstring>

Database::Database() {
  try {
    db->open(NULL, "integrity.db", NULL, DB_BTREE, DB_CREATE, 0);
  } catch (DbException &e) {
    std::cerr << "Error opening db" << std::endl;
  }
}

Database::~Database() {
  db->close(0);
}

void Database::Store(std::string filename, unsigned char *digest) {
  char *cstr = new char[filename.length() + 1];
  std::snprintf(cstr, filename.length() + 1, filename.c_str());

  Dbt key(cstr, static_cast<uint32_t>(filename.length()));
  Dbt value(digest, DIGEST_SIZE);

  int ret = db->put(NULL, &key, &value, DB_OVERWRITE_DUP);
}

int Database::Get(std::string filename, unsigned char *digest) {
  int ret = 0;

  char *cstr = new char[filename.length() + 1];
  std::snprintf(cstr, filename.length()+1, filename.c_str());

  Dbt key(cstr, static_cast<uint32_t>(filename.length()));
  Dbt data(digest, DIGEST_SIZE);
  data.set_ulen(DIGEST_SIZE);
  data.set_flags(DB_DBT_USERMEM);

  ret = db->get(NULL, &key, &data, 0);

  if (ret == DB_NOTFOUND) {
    return 1;
  } else {
    return 0;
  }
}<commit_msg>Removed unneeded statement<commit_after>// Copyright 2015 Nikita Chudinov

#include "Database.h"
#include <string>
#include <cstring>

Database::Database() {
  try {
    db->open(NULL, "integrity.db", NULL, DB_BTREE, DB_CREATE, 0);
  } catch (DbException &e) {
    std::cerr << "Error opening db" << std::endl;
  }
}

Database::~Database() {
  db->close(0);
}

void Database::Store(std::string filename, unsigned char *digest) {
  char *cstr = new char[filename.length() + 1];
  std::snprintf(cstr, filename.length() + 1, filename.c_str());

  Dbt key(cstr, static_cast<uint32_t>(filename.length()));
  Dbt value(digest, DIGEST_SIZE);

  db->put(NULL, &key, &value, DB_OVERWRITE_DUP);
}

int Database::Get(std::string filename, unsigned char *digest) {
  int ret = 0;

  char *cstr = new char[filename.length() + 1];
  std::snprintf(cstr, filename.length()+1, filename.c_str());

  Dbt key(cstr, static_cast<uint32_t>(filename.length()));
  Dbt data(digest, DIGEST_SIZE);
  data.set_ulen(DIGEST_SIZE);
  data.set_flags(DB_DBT_USERMEM);

  ret = db->get(NULL, &key, &data, 0);

  if (ret == DB_NOTFOUND) {
    return 1;
  } else {
    return 0;
  }
}<|endoftext|>


<commit_before>#include "FlowView.hpp"

#include <QtWidgets/QGraphicsScene>

#include <QtGui/QPen>
#include <QtGui/QBrush>
#include <QtWidgets/QMenu>

#include <QtCore/QRectF>

#include <QtOpenGL>
#include <QtWidgets>

#include <QDebug>
#include <iostream>

#include "FlowScene.hpp"
#include "DataModelRegistry.hpp"
#include "Node.hpp"
#include "NodeGraphicsObject.hpp"
#include "ConnectionGraphicsObject.hpp"
#include "StyleCollection.hpp"

using QtNodes::FlowView;
using QtNodes::FlowScene;

FlowView::
FlowView(FlowScene *scene)
  : QGraphicsView(scene)
  , _scene(scene)
{
  setDragMode(QGraphicsView::ScrollHandDrag);
  setRenderHint(QPainter::Antialiasing);

  auto const &flowViewStyle = StyleCollection::flowViewStyle();

  setBackgroundBrush(flowViewStyle.BackgroundColor);

  //setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
  //setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
  setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
  setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);

  setTransformationAnchor(QGraphicsView::AnchorUnderMouse);

  setCacheMode(QGraphicsView::CacheBackground);

  //setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
}

void
FlowView::
contextMenuEvent(QContextMenuEvent *event)
{
  QMenu modelMenu;

  auto filterActionText = QStringLiteral("skip me");

  auto *txtBox = new QLineEdit(&modelMenu);
  txtBox->setPlaceholderText(QStringLiteral("Filter"));
  txtBox->setClearButtonEnabled(true);

  auto *txtBoxAction = new QWidgetAction(&modelMenu);
  txtBoxAction->setDefaultWidget(txtBox);
  txtBoxAction->setText(filterActionText);

  modelMenu.addAction(txtBoxAction);

  connect(txtBox, &QLineEdit::textChanged, [&](const QString &text)
  {
    for (auto action : modelMenu.actions())
    {
      auto actionText = action->text();
      if (actionText != filterActionText && !actionText.contains(text, Qt::CaseInsensitive))
      {
        action->setVisible(false);
      }
      else
      {
        action->setVisible(true);
      }
    }
  });

  for (auto const &modelRegistry : _scene->registry().registeredModels())
  {
    QString const &modelName = modelRegistry.first;
    modelMenu.addAction(modelName);
  }

  if (QAction * action = modelMenu.exec(event->globalPos()))
  {
    QString modelName = action->text();

    auto type = _scene->registry().create(modelName);

    if (type)
    {
      auto& node = _scene->createNode(std::move(type));

      QPoint pos = event->pos();

      QPointF posView = this->mapToScene(pos);

      node.nodeGraphicsObject().setPos(posView);
    }
    else
    {
      qDebug() << "Model not found";
    }
  }
}

void
FlowView::
wheelEvent(QWheelEvent *event)
{
  QPoint delta = event->angleDelta();

  if (delta.y() == 0)
  {
    event->ignore();
    return;
  }

  double const d = delta.y() / std::abs(delta.y());

  if (d > 0.0)
    scaleUp();
  else
    scaleDown();
}

void
FlowView::
scaleUp()
{
  double const step   = 1.2;
  double const factor = std::pow(step, 1.0);

  QTransform t = transform();

  if (t.m11() > 2.0)
    return;

  scale(factor, factor);
}

void
FlowView::
scaleDown()
{
  double const step   = 1.2;
  double const factor = std::pow(step, -1.0);

  scale(factor, factor);
}

void
FlowView::
keyPressEvent(QKeyEvent *event)
{
  switch (event->key())
  {
    case Qt::Key_Escape:
      _scene->clearSelection();
      break;

    case Qt::Key_Delete:
    {
      std::vector<Node*> nodesToDelete;
      std::vector<Connection*> connectionsToDelete;
      for (QGraphicsItem * item : _scene->selectedItems())
      {
        if (auto n = dynamic_cast<NodeGraphicsObject*>(item))
          nodesToDelete.push_back(&n->node());

        if (auto c = dynamic_cast<ConnectionGraphicsObject*>(item))
          connectionsToDelete.push_back(&c->connection());
      }

      for( auto & n : nodesToDelete )
        _scene->removeNode(*n);

      for( auto & c : connectionsToDelete )
        _scene->deleteConnection(*c);

    }

    break;

    case Qt::Key_Shift:
      setDragMode(QGraphicsView::RubberBandDrag);
      break;

    default:
      break;
  }

  QGraphicsView::keyPressEvent(event);
}

void
FlowView::
keyReleaseEvent(QKeyEvent *event)
{
  switch (event->key())
  {
    case Qt::Key_Shift:
      setDragMode(QGraphicsView::ScrollHandDrag);
      break;

    default:
      break;
  }
  QGraphicsView::keyReleaseEvent(event);
}

void
FlowView::
drawBackground(QPainter* painter, const QRectF& r)
{
  QGraphicsView::drawBackground(painter, r);

  auto drawGrid =
  [&](double gridStep)
  {
    QRect   windowRect = rect();
    QPointF tl = mapToScene(windowRect.topLeft());
    QPointF br = mapToScene(windowRect.bottomRight());

    double left   = std::floor(tl.x() / gridStep - 0.5);
    double right  = std::floor(br.x() / gridStep + 1.0);
    double bottom = std::floor(tl.y() / gridStep - 0.5);
    double top    = std::floor (br.y() / gridStep + 1.0);

    // vertical lines
    for (int xi = int(left); xi <= int(right); ++xi)
    {
      QLineF line(xi * gridStep, bottom * gridStep,
                  xi * gridStep, top * gridStep );

      painter->drawLine(line);
    }

    // horizontal lines
    for (int yi = int(bottom); yi <= int(top); ++yi)
    {
      QLineF line(left * gridStep, yi * gridStep,
                  right * gridStep, yi * gridStep );
      painter->drawLine(line);
    }
  };

  auto const &flowViewStyle = StyleCollection::flowViewStyle();

  QBrush bBrush = backgroundBrush();

  QPen pfine(flowViewStyle.FineGridColor, 1.0);

  painter->setPen(pfine);
  drawGrid(15);

  QPen p(flowViewStyle.CoarseGridColor, 1.0);

  painter->setPen(p);
  drawGrid(150);
}

void
FlowView::
showEvent(QShowEvent *event)
{
  _scene->setSceneRect(this->rect());
  QGraphicsView::showEvent(event);
}

void
FlowView::
mousePressEvent(QMouseEvent* event)
{
  QGraphicsView::mousePressEvent(event);
}

void
FlowView::
mouseMoveEvent(QMouseEvent* event)
{
  QGraphicsView::mouseMoveEvent(event);
}
<commit_msg>Make the filter bar in the context menu have focus by default. (#55)<commit_after>#include "FlowView.hpp"

#include <QtWidgets/QGraphicsScene>

#include <QtGui/QPen>
#include <QtGui/QBrush>
#include <QtWidgets/QMenu>

#include <QtCore/QRectF>

#include <QtOpenGL>
#include <QtWidgets>

#include <QDebug>
#include <iostream>

#include "FlowScene.hpp"
#include "DataModelRegistry.hpp"
#include "Node.hpp"
#include "NodeGraphicsObject.hpp"
#include "ConnectionGraphicsObject.hpp"
#include "StyleCollection.hpp"

using QtNodes::FlowView;
using QtNodes::FlowScene;

FlowView::
FlowView(FlowScene *scene)
  : QGraphicsView(scene)
  , _scene(scene)
{
  setDragMode(QGraphicsView::ScrollHandDrag);
  setRenderHint(QPainter::Antialiasing);

  auto const &flowViewStyle = StyleCollection::flowViewStyle();

  setBackgroundBrush(flowViewStyle.BackgroundColor);

  //setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
  //setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
  setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
  setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);

  setTransformationAnchor(QGraphicsView::AnchorUnderMouse);

  setCacheMode(QGraphicsView::CacheBackground);

  //setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
}

void
FlowView::
contextMenuEvent(QContextMenuEvent *event)
{
  QMenu modelMenu;

  auto filterActionText = QStringLiteral("skip me");

  auto *txtBox = new QLineEdit(&modelMenu);
  txtBox->setPlaceholderText(QStringLiteral("Filter"));
  txtBox->setClearButtonEnabled(true);

  auto *txtBoxAction = new QWidgetAction(&modelMenu);
  txtBoxAction->setDefaultWidget(txtBox);
  txtBoxAction->setText(filterActionText);

  modelMenu.addAction(txtBoxAction);

  connect(txtBox, &QLineEdit::textChanged, [&](const QString &text)
  {
    for (auto action : modelMenu.actions())
    {
      auto actionText = action->text();
      if (actionText != filterActionText && !actionText.contains(text, Qt::CaseInsensitive))
      {
        action->setVisible(false);
      }
      else
      {
        action->setVisible(true);
      }
    }
  });

  for (auto const &modelRegistry : _scene->registry().registeredModels())
  {
    QString const &modelName = modelRegistry.first;
    modelMenu.addAction(modelName);
  }

  // make sure the text box gets focus so the user doesn't have to click on it
  txtBox->setFocus();

  if (QAction * action = modelMenu.exec(event->globalPos()))
  {
    QString modelName = action->text();

    auto type = _scene->registry().create(modelName);

    if (type)
    {
      auto& node = _scene->createNode(std::move(type));

      QPoint pos = event->pos();

      QPointF posView = this->mapToScene(pos);

      node.nodeGraphicsObject().setPos(posView);
    }
    else
    {
      qDebug() << "Model not found";
    }
  }
}

void
FlowView::
wheelEvent(QWheelEvent *event)
{
  QPoint delta = event->angleDelta();

  if (delta.y() == 0)
  {
    event->ignore();
    return;
  }

  double const d = delta.y() / std::abs(delta.y());

  if (d > 0.0)
    scaleUp();
  else
    scaleDown();
}

void
FlowView::
scaleUp()
{
  double const step   = 1.2;
  double const factor = std::pow(step, 1.0);

  QTransform t = transform();

  if (t.m11() > 2.0)
    return;

  scale(factor, factor);
}

void
FlowView::
scaleDown()
{
  double const step   = 1.2;
  double const factor = std::pow(step, -1.0);

  scale(factor, factor);
}

void
FlowView::
keyPressEvent(QKeyEvent *event)
{
  switch (event->key())
  {
    case Qt::Key_Escape:
      _scene->clearSelection();
      break;

    case Qt::Key_Delete:
    {
      std::vector<Node*> nodesToDelete;
      std::vector<Connection*> connectionsToDelete;
      for (QGraphicsItem * item : _scene->selectedItems())
      {
        if (auto n = dynamic_cast<NodeGraphicsObject*>(item))
          nodesToDelete.push_back(&n->node());

        if (auto c = dynamic_cast<ConnectionGraphicsObject*>(item))
          connectionsToDelete.push_back(&c->connection());
      }

      for( auto & n : nodesToDelete )
        _scene->removeNode(*n);

      for( auto & c : connectionsToDelete )
        _scene->deleteConnection(*c);

    }

    break;

    case Qt::Key_Shift:
      setDragMode(QGraphicsView::RubberBandDrag);
      break;

    default:
      break;
  }

  QGraphicsView::keyPressEvent(event);
}

void
FlowView::
keyReleaseEvent(QKeyEvent *event)
{
  switch (event->key())
  {
    case Qt::Key_Shift:
      setDragMode(QGraphicsView::ScrollHandDrag);
      break;

    default:
      break;
  }
  QGraphicsView::keyReleaseEvent(event);
}

void
FlowView::
drawBackground(QPainter* painter, const QRectF& r)
{
  QGraphicsView::drawBackground(painter, r);

  auto drawGrid =
  [&](double gridStep)
  {
    QRect   windowRect = rect();
    QPointF tl = mapToScene(windowRect.topLeft());
    QPointF br = mapToScene(windowRect.bottomRight());

    double left   = std::floor(tl.x() / gridStep - 0.5);
    double right  = std::floor(br.x() / gridStep + 1.0);
    double bottom = std::floor(tl.y() / gridStep - 0.5);
    double top    = std::floor (br.y() / gridStep + 1.0);

    // vertical lines
    for (int xi = int(left); xi <= int(right); ++xi)
    {
      QLineF line(xi * gridStep, bottom * gridStep,
                  xi * gridStep, top * gridStep );

      painter->drawLine(line);
    }

    // horizontal lines
    for (int yi = int(bottom); yi <= int(top); ++yi)
    {
      QLineF line(left * gridStep, yi * gridStep,
                  right * gridStep, yi * gridStep );
      painter->drawLine(line);
    }
  };

  auto const &flowViewStyle = StyleCollection::flowViewStyle();

  QBrush bBrush = backgroundBrush();

  QPen pfine(flowViewStyle.FineGridColor, 1.0);

  painter->setPen(pfine);
  drawGrid(15);

  QPen p(flowViewStyle.CoarseGridColor, 1.0);

  painter->setPen(p);
  drawGrid(150);
}

void
FlowView::
showEvent(QShowEvent *event)
{
  _scene->setSceneRect(this->rect());
  QGraphicsView::showEvent(event);
}

void
FlowView::
mousePressEvent(QMouseEvent* event)
{
  QGraphicsView::mousePressEvent(event);
}

void
FlowView::
mouseMoveEvent(QMouseEvent* event)
{
  QGraphicsView::mouseMoveEvent(event);
}
<|endoftext|>


<commit_before>// $Id$
// Category: event
//
// See the class description in the header file.

#include "AliTrackingAction.h"
#include "AliTrackingActionMessenger.h"
#include "AliRun.h"
#include "AliGlobals.h"
#include "TG4StepManager.h"

#include <G4TrackingManager.hh>
#include <G4Track.hh>

#include <TTree.h>
#include <TParticle.h>
#include <TClonesArray.h>

// static data members
AliTrackingAction* AliTrackingAction::fgInstance = 0;

// static methods
AliTrackingAction* AliTrackingAction::Instance() {
//
  return fgInstance;
}

AliTrackingAction::AliTrackingAction()
  : fParticles(0),
    fPrimaryTrackID(0),
    fVerboseLevel(2),
    fSavePrimaries(true),
    fPrimariesCounter(0),
    fParticlesCounter(0),
    fTrackCounter(0),
    fLastParticleIndex(-1)
{
//
  if (fgInstance) {
    AliGlobals::Exception("AliTrackingAction constructed twice.");
  }

  fMessenger = new AliTrackingActionMessenger(this);
  fgInstance = this;
}

AliTrackingAction::AliTrackingAction(const AliTrackingAction& right) {
//
  AliGlobals::Exception("AliTrackingAction is protected from copying.");
}

AliTrackingAction::~AliTrackingAction() {
//
  delete fMessenger;
}

// operators

AliTrackingAction&
AliTrackingAction::operator=(const AliTrackingAction &right)
{
  // check assignement to self
  if (this == &right) return *this;

  AliGlobals::Exception("AliTrackingAction is protected from assigning.");

  return *this;
}

// public methods

void AliTrackingAction::PrepareNewEvent()
{
// Called by G4 kernel at the beginning of event.
// ---

  fTrackCounter = 0;

  // aliroot
  if (!fParticles) fParticles = gAlice->Particles();

  // set the particles and primaries counter to the
  // number of tracks already stored in AliRun::fParticles
  // (fParticles can already contain primary particles
  //  saved by AliGenerator)
  G4int nofTracks = gAlice->GetNtrack();
  fPrimariesCounter = nofTracks;
  fParticlesCounter = nofTracks;
  fLastParticleIndex = nofTracks-1;

  // set g4 stepping manager pointer
  G4SteppingManager* pG4StepManager
    = fpTrackingManager->GetSteppingManager();
  TG4StepManager* pStepManager = TG4StepManager::Instance();
  pStepManager->SetSteppingManager(pG4StepManager);
}

void AliTrackingAction::PreTrackingAction(const G4Track* aTrack)
{
// Called by G4 kernel before starting tracking.
// ---

  // aliroot
  // track index in the particles array
  G4int trackID = aTrack->GetTrackID();
  G4int parentID = aTrack->GetParentID();
  Int_t trackIndex;
  if (parentID==0) {
    trackIndex = trackID;
  }
  else {
    trackIndex = GetNofSavedTracks();
  }

  // in AliRoot (from V3.0) track numbering starts from 0
  gAlice->SetCurrentTrack(--trackIndex);

  if (parentID == 0) {
    // save primary track
    SaveAndDestroyTrack();
    fPrimaryTrackID = aTrack->GetTrackID();
  }
  else {
    // save secondary particles info
    // improve this later with retrieving the generation process
    // (primary particles are stored
    //  by AlStackingAction in ClassifyNewTrack() method)
    G4String origin = "secondary";
    SaveParticle(aTrack, origin);
  }

  gAlice->PreTrack();
}

void AliTrackingAction::PostTrackingAction(const G4Track* aTrack)
{
// Called by G4 kernel after finishing tracking.
// ---

  fTrackCounter++;

  gAlice->PostTrack();
}

void AliTrackingAction::SaveAndDestroyTrack()
{
// Calls AliRun::PurifyKine and fills trees of hits
// after finishing tracking of each primary track.
// !! This method has to be also called from AlEventAction::EndOfEventAction()
// for storing the last primary track of the current event.
// ---

  if (fPrimaryTrackID>0)
  {
     if (fVerboseLevel == 3) {
       G4cout << "$$$ Primary track " << fPrimaryTrackID << G4endl;
     }
     else if ( fVerboseLevel == 2 &&  fPrimaryTrackID % 10 == 0 ) {
         G4cout << "$$$ Primary track " << fPrimaryTrackID  << G4endl;
     }
     else if ( fVerboseLevel == 1 &&  fPrimaryTrackID % 100 == 0 ) {
         G4cout << "$$$ Primary track " << fPrimaryTrackID  << G4endl;
     }

     // aliroot
     G4int lastSavedTrack
       = gAlice->PurifyKine(fLastParticleIndex, fParticlesCounter);
     G4int nofPuredSavedTracks
       = gAlice->GetNtrack();
     fLastParticleIndex = lastSavedTrack;
     fParticlesCounter = nofPuredSavedTracks;

     if(gAlice->TreeH()) gAlice->TreeH()->Fill();
     gAlice->ResetHits();
   }
   else {
     fLastParticleIndex = fPrimariesCounter-1;
   }
   fPrimaryTrackID = 0;
}

void AliTrackingAction::SaveParticle(const G4Track* track,
                                     G4String processName)
{
// Converts G4track to TParticle and saves it in AliRun::fParticles
// array.
// ----

  fParticlesCounter++;

  // track history
  G4int firstDaughter = -1;
  G4int lastDaughter = -1;
  G4int parentID = track->GetParentID();
  G4int motherIndex1;
  G4int motherIndex2 = -1;
  if (parentID == 0) {
    motherIndex1 = -1;
    fPrimariesCounter++;
  }
  else {
    // set first/last child for already defined particles
    motherIndex1 = GetParticleIndex(parentID);
    // aliroot
    TParticle* parent
      = dynamic_cast<TParticle*>(fParticles->UncheckedAt(motherIndex1));
    if (parent) {
      if (parent->GetFirstDaughter()<0)
        parent->SetFirstDaughter(fParticlesCounter);
      parent->SetLastDaughter(fParticlesCounter);
    }
    else {
      AliGlobals::Exception(
        "AliTrackingAction::SaveParticle: Unknown particle type");
    }
  };

  // ?? status of particle
  // temporarily used for storing trackID from G4
  G4int ks = track->GetTrackID();

  // particle type
  // is this G3 ekvivalent ?? - check
  G4int pdg = track->GetDefinition()->GetPDGEncoding();

  // track kinematics
  G4ThreeVector momentum = track->GetMomentum();
  G4double px = momentum.x()/GeV;
  G4double py = momentum.y()/GeV;
  G4double pz = momentum.z()/GeV;
  G4double e = track->GetTotalEnergy()/GeV;

  G4ThreeVector position = track->GetPosition();
  G4double vx = position.x()/cm;
  G4double vy = position.y()/cm;
  G4double vz = position.z()/cm;
  // time of production - check if ekvivalent with G4
  G4double t = track->GetGlobalTime();

  G4ThreeVector polarization = track->GetPolarization();
  G4double polX = polarization.x();
  G4double polY = polarization.y();
  G4double polZ = polarization.z();

  // aliroot
  TClonesArray& theCollectionRef = *fParticles;
  G4int nofParticles = theCollectionRef.GetEntriesFast();
  TParticle* particle
   = new(theCollectionRef[nofParticles])
       TParticle(pdg, ks, motherIndex1, motherIndex1,
         firstDaughter, lastDaughter, px, py, pz, e, vx, vy, vz, t);
  particle->SetPolarisation(polX, polY, polZ);
  particle->SetBit(kKeepBit, false);
}

G4int AliTrackingAction::GetParticleIndex(G4int trackID)
{
// Converts the trackID into the index of the particle
// in AliRun::fParticles array.
// ---

  if (trackID <= fPrimariesCounter) {
    return trackID-1;
  }
  else
    for (G4int i=fLastParticleIndex+1; i<fParticlesCounter; i++) {
      // aliroot
      TParticle* particle
        = (TParticle*)fParticles->UncheckedAt(i);
      if (trackID == particle->GetStatusCode()) return i;
    }

  AliGlobals::Exception("AliTrackingAction::GetParticleIndex() has failed.");
  return 0;
}
<commit_msg>SaveParticle: setting of production process to TParticle added<commit_after>// $Id$
// Category: event
//
// See the class description in the header file.

#include "AliTrackingAction.h"
#include "AliTrackingActionMessenger.h"
#include "AliRun.h"
#include "AliGlobals.h"
#include "TG4StepManager.h"
#include "TG4PhysicsManager.h"

#include <G4TrackingManager.hh>
#include <G4Track.hh>

#include <TTree.h>
#include <TParticle.h>
#include <TClonesArray.h>

// static data members
AliTrackingAction* AliTrackingAction::fgInstance = 0;

// static methods
AliTrackingAction* AliTrackingAction::Instance() {
//
  return fgInstance;
}

AliTrackingAction::AliTrackingAction()
  : fParticles(0),
    fPrimaryTrackID(0),
    fVerboseLevel(2),
    fSavePrimaries(true),
    fPrimariesCounter(0),
    fParticlesCounter(0),
    fTrackCounter(0),
    fLastParticleIndex(-1)
{
//
  if (fgInstance) {
    AliGlobals::Exception("AliTrackingAction constructed twice.");
  }

  fMessenger = new AliTrackingActionMessenger(this);
  fgInstance = this;
}

AliTrackingAction::AliTrackingAction(const AliTrackingAction& right) {
//
  AliGlobals::Exception("AliTrackingAction is protected from copying.");
}

AliTrackingAction::~AliTrackingAction() {
//
  delete fMessenger;
}

// operators

AliTrackingAction&
AliTrackingAction::operator=(const AliTrackingAction &right)
{
  // check assignement to self
  if (this == &right) return *this;

  AliGlobals::Exception("AliTrackingAction is protected from assigning.");

  return *this;
}

// public methods

void AliTrackingAction::PrepareNewEvent()
{
// Called by G4 kernel at the beginning of event.
// ---

  fTrackCounter = 0;

  // aliroot
  if (!fParticles) fParticles = gAlice->Particles();

  // set the particles and primaries counter to the
  // number of tracks already stored in AliRun::fParticles
  // (fParticles can already contain primary particles
  //  saved by AliGenerator)
  G4int nofTracks = gAlice->GetNtrack();
  fPrimariesCounter = nofTracks;
  fParticlesCounter = nofTracks;
  fLastParticleIndex = nofTracks-1;

  // set g4 stepping manager pointer
  G4SteppingManager* pG4StepManager
    = fpTrackingManager->GetSteppingManager();
  TG4StepManager* pStepManager = TG4StepManager::Instance();
  pStepManager->SetSteppingManager(pG4StepManager);
}

void AliTrackingAction::PreTrackingAction(const G4Track* aTrack)
{
// Called by G4 kernel before starting tracking.
// ---

  // aliroot
  // track index in the particles array
  G4int trackID = aTrack->GetTrackID();
  G4int parentID = aTrack->GetParentID();
  Int_t trackIndex;
  if (parentID==0) {
    trackIndex = trackID;
  }
  else {
    trackIndex = GetNofSavedTracks();
  }

  // in AliRoot (from V3.0) track numbering starts from 0
  gAlice->SetCurrentTrack(--trackIndex);

  if (parentID == 0) {
    // save primary track
    SaveAndDestroyTrack();
    fPrimaryTrackID = aTrack->GetTrackID();
  }
  else {
    // save secondary particles info
    SaveParticle(aTrack);
  }

  gAlice->PreTrack();
}

void AliTrackingAction::PostTrackingAction(const G4Track* aTrack)
{
// Called by G4 kernel after finishing tracking.
// ---

  fTrackCounter++;

  gAlice->PostTrack();
}

void AliTrackingAction::SaveAndDestroyTrack()
{
// Calls AliRun::PurifyKine and fills trees of hits
// after finishing tracking of each primary track.
// !! This method has to be also called from AlEventAction::EndOfEventAction()
// for storing the last primary track of the current event.
// ---

  if (fPrimaryTrackID>0)
  {
     if (fVerboseLevel == 3) {
       G4cout << "$$$ Primary track " << fPrimaryTrackID << G4endl;
     }
     else if ( fVerboseLevel == 2 &&  fPrimaryTrackID % 10 == 0 ) {
         G4cout << "$$$ Primary track " << fPrimaryTrackID  << G4endl;
     }
     else if ( fVerboseLevel == 1 &&  fPrimaryTrackID % 100 == 0 ) {
         G4cout << "$$$ Primary track " << fPrimaryTrackID  << G4endl;
     }

     // aliroot
     G4int lastSavedTrack
       = gAlice->PurifyKine(fLastParticleIndex, fParticlesCounter);
     G4int nofPuredSavedTracks
       = gAlice->GetNtrack();
     fLastParticleIndex = lastSavedTrack;
     fParticlesCounter = nofPuredSavedTracks;

     if(gAlice->TreeH()) gAlice->TreeH()->Fill();
     gAlice->ResetHits();
   }
   else {
     fLastParticleIndex = fPrimariesCounter-1;
   }
   fPrimaryTrackID = 0;
}

void AliTrackingAction::SaveParticle(const G4Track* track)
{
// Converts G4track to TParticle and saves it in AliRun::fParticles
// array.
// ----

  fParticlesCounter++;

  // track history
  G4int firstDaughter = -1;
  G4int lastDaughter = -1;
  G4int parentID = track->GetParentID();
  G4int motherIndex1;
  G4int motherIndex2 = -1;
  if (parentID == 0) {
    motherIndex1 = -1;
    fPrimariesCounter++;
  }
  else {
    // set first/last child for already defined particles
    motherIndex1 = GetParticleIndex(parentID);
    // aliroot
    TParticle* parent
      = dynamic_cast<TParticle*>(fParticles->UncheckedAt(motherIndex1));
    if (parent) {
      if (parent->GetFirstDaughter()<0)
        parent->SetFirstDaughter(fParticlesCounter);
      parent->SetLastDaughter(fParticlesCounter);
    }
    else {
      AliGlobals::Exception(
        "AliTrackingAction::SaveParticle: Unknown particle type");
    }
  };

  // ?? status of particle
  // temporarily used for storing trackID from G4
  G4int ks = track->GetTrackID();

  // particle type
  // is this G3 ekvivalent ?? - check
  G4int pdg = track->GetDefinition()->GetPDGEncoding();

  // track kinematics
  G4ThreeVector momentum = track->GetMomentum();
  G4double px = momentum.x()/GeV;
  G4double py = momentum.y()/GeV;
  G4double pz = momentum.z()/GeV;
  G4double e = track->GetTotalEnergy()/GeV;

  G4ThreeVector position = track->GetPosition();
  G4double vx = position.x()/cm;
  G4double vy = position.y()/cm;
  G4double vz = position.z()/cm;
  // time of production - check if ekvivalent with G4
  G4double t = track->GetGlobalTime();

  G4ThreeVector polarization = track->GetPolarization();
  G4double polX = polarization.x();
  G4double polY = polarization.y();
  G4double polZ = polarization.z();

  // create TParticle
  TClonesArray& theCollectionRef = *fParticles;
  G4int nofParticles = theCollectionRef.GetEntriesFast();
  TParticle* particle
   = new(theCollectionRef[nofParticles])
       TParticle(pdg, ks, motherIndex1, motherIndex1,
         firstDaughter, lastDaughter, px, py, pz, e, vx, vy, vz, t);
  particle->SetPolarisation(polX, polY, polZ);
  particle->SetBit(kKeepBit, false);

  // set production process
  AliMCProcess mcProcess;
  const G4VProcess* kpProcess = track->GetCreatorProcess();
  if (!kpProcess) {
    mcProcess = kPPrimary;
  }
  else {
    TG4PhysicsManager* pPhysicsManager = TG4PhysicsManager::Instance();
    mcProcess = pPhysicsManager->GetMCProcess(kpProcess->GetProcessName());
    // distinguish kPDeltaRay from kPEnergyLoss
    if (mcProcess == kPEnergyLoss) mcProcess = kPDeltaRay;
  }
  particle->SetUniqueID(mcProcess);
}

G4int AliTrackingAction::GetParticleIndex(G4int trackID)
{
// Converts the trackID into the index of the particle
// in AliRun::fParticles array.
// ---

  if (trackID <= fPrimariesCounter) {
    return trackID-1;
  }
  else
    for (G4int i=fLastParticleIndex+1; i<fParticlesCounter; i++) {
      // aliroot
      TParticle* particle
        = (TParticle*)fParticles->UncheckedAt(i);
      if (trackID == particle->GetStatusCode()) return i;
    }

  AliGlobals::Exception("AliTrackingAction::GetParticleIndex() has failed.");
  return 0;
}
<|endoftext|>