text: /*
   LICENSE
  
   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, see <http://www.gnu.org/licenses/>. 
  */
  
  /*
   Package:
      MiFare Classic Universal toolKit (MFCUK)
   
   Package version:
      0.1
   
   Filename:
      mfcuk_finger.c
  
   Description:
      MFCUK fingerprinting and specific data-decoding functionality.
  
   License:
      GPL2, Copyright (C) 2009, Andrei Costin
  
   * @file mfcuk_finger.c
   * @brief MFCUK fingerprinting and specific data-decoding functionality.
   * @todo add proper error codes
  */
  
  #include "mfcuk_finger.h"
  
  mfcuk_finger_tmpl_entry mfcuk_finger_db[] = 
  {
      { "./data/tmpls_fingerprints/mfcuk_tmpl_skgt.mfd", "Sofia SKGT", mfcuk_finger_default_comparator, mfcuk_finger_skgt_decoder, NULL },
      { "./data/tmpls_fingerprints/mfcuk_tmpl_ratb.mfd", "Bucharest RATB", mfcuk_finger_default_comparator, mfcuk_finger_default_decoder, NULL },
      { "./data/tmpls_fingerprints/mfcuk_tmpl_oyster.mfd", "London OYSTER", mfcuk_finger_default_comparator, mfcuk_finger_default_decoder, NULL },
  };
  
  int mfcuk_finger_db_entries = sizeof(mfcuk_finger_db)/sizeof(mfcuk_finger_db[0]);
  
  int mfcuk_finger_default_decoder(mifare_classic_tag *dump)
  {
      if (!dump)
      {
          fprintf(stderr, "ERROR: cannot decode a NULL pointer :)\n");
          return 0;
      }
      
      printf("UID:\t%02x%02x%02x%02x\n", dump->amb[0].mbm.abtUID[0], dump->amb[0].mbm.abtUID[1], dump->amb[0].mbm.abtUID[2], dump->amb[0].mbm.abtUID[3]);
      printf("TYPE:\t%02x\n", dump->amb[0].mbm.btUnknown);
      
      return 1;
  }
  
  // Yes, I know C++ class inheritance would perfectly fit the decoders/comparators... Though C is more to my heart. Anyone to rewrite in C++?
  int mfcuk_finger_skgt_decoder(mifare_classic_tag *dump)
  {
      unsigned char *dump_ptr = NULL;
      unsigned short car_number = 0;
      
      if (!dump)
      {
          fprintf(stderr, "ERROR: cannot decode a NULL pointer :)\n");
          return 0;
      }
      
      dump_ptr = (unsigned char *) dump;
      
      printf("Bulgaria/Sofia/SKGT public transport card information decoder (info credits to Andy)\n");
      mfcuk_finger_default_decoder(dump);
      
      printf("LAST TRAVEL DATA\n");
      
      // TODO: get proper information
      
      return 1;
  }
  
  int mfcuk_finger_default_comparator(mifare_classic_tag *dump, mfcuk_finger_template *tmpl, float *score)
  {
      int max_bytes = 0;
      int i;
      int num_bytes_tomatch = 0;
      int num_bytes_matched = 0;
      
      if ( (!dump) || (!tmpl) || (!score) )
      {
          return 0;
      }
      
      if (IS_MIFARE_CLASSIC_1K_TAG(dump))
      {
          max_bytes = MIFARE_CLASSIC_BYTES_PER_BLOCK * MIFARE_CLASSIC_1K_MAX_BLOCKS;
      }
      else if (IS_MIFARE_CLASSIC_4K_TAG(dump))
      {
          max_bytes = MIFARE_CLASSIC_BYTES_PER_BLOCK * MIFARE_CLASSIC_4K_MAX_BLOCKS;
      }
      else
      {
          return 0;
      }
      
      for (i=0; i<max_bytes; i++)
      {
          if ( ((char *)(&tmpl->mask))[i] == 0x0 )
          {
              continue;
          }
          
          num_bytes_tomatch++;
          
          if ( ((char *)(&tmpl->values))[i] == ((char *)dump)[i] )
          {
              num_bytes_matched++;
          }
      }
      
      if (num_bytes_tomatch == 0)
      {
          return 0;
      }
      else
      {
          *score = (float)(num_bytes_matched)/num_bytes_tomatch;
      }
      
      return 1;
  }
  
  int mfcuk_finger_load()
  {
      int i;
      mifare_classic_tag mask;
      mifare_classic_tag values;
      FILE *fp = NULL;
      size_t result = 0;
      mfcuk_finger_template *tmpl_new = NULL;
  
      int template_loaded_count = 0;
      for (i = 0; i<mfcuk_finger_db_entries; i++)
      {
          fp = fopen(mfcuk_finger_db[i].tmpl_filename, "rb");
          
          if (!fp)
          {
              fprintf(stderr, "WARN: cannot open template file '%s'\n", mfcuk_finger_db[i].tmpl_filename);
              continue;
          }
          
          // If not read exactly 1 record, something is wrong
          if ( (result = fread((void *)(&mask), sizeof(mask), 1, fp)) != 1)
          {
              fprintf(stderr, "WARN: cannot read MASK from template file '%s'\n", mfcuk_finger_db[i].tmpl_filename);
              fclose(fp);
              continue;
          }
          
          // If not read exactly 1 record, something is wrong
          if ( (result = fread((void *)(&values), sizeof(values), 1, fp)) != 1)
          {
              fprintf(stderr, "WARN: cannot read VALUES template file '%s'\n", mfcuk_finger_db[i].tmpl_filename);
              fclose(fp);
              continue;
          }
          
          if (mfcuk_finger_db[i].tmpl_data == NULL)
          {
              if ( (tmpl_new = (mfcuk_finger_template *) malloc(sizeof(mfcuk_finger_template))) == NULL)
              {
                  fprintf(stderr, "WARN: cannot allocate memory to template record %d\n", i);
                  fclose(fp);
                  continue;
              }
              
              memcpy( &(tmpl_new->mask), &(mask), sizeof(mask));
              memcpy( &(tmpl_new->values), &(values), sizeof(values));
              
              mfcuk_finger_db[i].tmpl_data = tmpl_new;
              template_loaded_count++;
          }
          
          if (fp)
          {
              fclose(fp);
              fp = NULL;
          }
      }
      
      return template_loaded_count;
  }
  
  int mfcuk_finger_unload()
  {
      int i;
      
      for (i = 0; i<mfcuk_finger_db_entries; i++)
      {
          if (mfcuk_finger_db[i].tmpl_data != NULL)
          {
              free(mfcuk_finger_db[i].tmpl_data);
              mfcuk_finger_db[i].tmpl_data = NULL;
          }
      }
      
      return 1;
  }
  