// -*- coding: utf-8 -*-

//+---------------------------------------------------------------------------+
//|          01001110 01100101 01110100 01111010 01101111 01100010            |
//|                                                                           |
//|               Netzob : Inferring communication protocols                  |
//+---------------------------------------------------------------------------+
//| Copyright (C) 2011 Georges Bossert and Frédéric Guihéry                   |
//| 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 3 of the License, or         |
//| (at your option) any later version.                                       |
//|                                                                           |
//| This program is distributed in the hope that it will be useful,           |
//| but WITHOUT ANY WARRANTY; without even the implied warranty of            |
//| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the              |
//| GNU 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/>.      |
//+---------------------------------------------------------------------------+
//| @url      : http://www.netzob.org                                         |
//| @contact  : contact@netzob.org                                            |
//| @sponsors : Amossys, http://www.amossys.fr                                |
//|             Supélec, http://www.rennes.supelec.fr/ren/rd/cidre/           |
//+---------------------------------------------------------------------------+

//Compilation Windows
//cl -Fe_libInterface.pyd -Ox -Ot -openmp -LD /I"C:\Python26\include" /I"C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include" libInterface.c "C:\Python26\libs\python26.lib" "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\lib\vcomp.lib"

//+---------------------------------------------------------------------------+
//| Import Associated Header
//+---------------------------------------------------------------------------+
#include "Interface.h"
#ifdef _WIN32
#include <stdio.h>
#include <malloc.h>
#endif

#ifdef CCALLFORDEBUG
//+---------------------------------------------------------------------------+
//| callbackStatus : displays the status on terminal when using only C calls
//+---------------------------------------------------------------------------+
int callbackStatus(int stage, double percent, char* message, ...) {
  // Variadic member
  va_list args;

  // local variables
  char buffer[4096];

  va_start(args, message);
  vsnprintf(buffer, sizeof(buffer), message, args);
  va_end(args);
  buffer[4095] = '\0';
  
  printf("[%d, %f] %s\n", stage, percent, buffer);
  return 1;

}
#endif


//+---------------------------------------------------------------------------+
//| deserializeMessages : Deserialization of messages
//+---------------------------------------------------------------------------+
unsigned int deserializeMessages(t_group * group, char *format, unsigned char *serialMessages, unsigned int nbMessages, Bool debugMode) {
  unsigned int i_message = 0;
  char * p;
  unsigned int serial_shift = 0;
  unsigned int format_shift = 0;
  unsigned int len_size_message=0;
  unsigned int size_message=0;
  char * size_message_str;
  unsigned int nbDeserializedMessages = 0;

  for (i_message=0; i_message < nbMessages; i_message++) {
    // Retrieve the size of each message
    p = strchr(format + format_shift, 'M');
    len_size_message = (unsigned int) (p - (format + format_shift));
    size_message_str = malloc((len_size_message + 1) * sizeof(char));
    memcpy(size_message_str, format + format_shift, len_size_message);
    size_message_str[len_size_message] = '\0';
    size_message = atoi(size_message_str);

    // Register the message
    group->messages[i_message].len = size_message;
    group->messages[i_message].alignment = serialMessages + serial_shift;
    group->messages[i_message].mask = malloc(size_message * sizeof(unsigned char));
    memset(group->messages[i_message].mask, '\0', size_message);
    t_score score;
    group->messages[i_message].score = &score;

    nbDeserializedMessages += 1;

    format_shift = format_shift + len_size_message + 1;
    serial_shift = serial_shift + size_message;

    // Cleaning useless allocated memory
    free(size_message_str);
  }

  if (debugMode == TRUE) {
    printf("A number of %d messages has been deserialized.\n", nbDeserializedMessages);
    for (i_message = 0; i_message<nbDeserializedMessages; i_message++) {
      printf("Message %u : \n", i_message);
      hexdump(group->messages[i_message].alignment, group->messages[i_message].len);
    }
  }
  return nbDeserializedMessages;
}

unsigned int deserializeGroups(t_groups * groups, char * format, unsigned char * serialGroups, int nbGroups, Bool debugMode) {
  int i_group = 0;
  int j_group = 0;
  int l = 0;
  char * p;
  char *q;
  char *r;
  char *s;
  unsigned short int format_shift = 0;
  unsigned int len_size_group = 0;
  unsigned int len_size_message = 0;
  unsigned int len_score_group = 0;
  unsigned int size_group = 0;
  unsigned int size_message = 0;
  char * size_group_str;
  char * size_message_str;
  char * score_group;
  unsigned int i_message = 0;

  for (i_group = 0; i_group <nbGroups; i_group++)  {
    //Retrieve the precompiled scores
    s = strchr(format + format_shift, 'E');
    if (s != NULL){ // Used for compatibility between version
      for (j_group = i_group + 1; j_group < nbGroups ; j_group ++){
        r = strchr(format + format_shift, 'S');
        if (r!=NULL && (int) (s - r) > 0){
          len_score_group = (unsigned int) (r - (format + format_shift));
          score_group = malloc((len_score_group + 1) * sizeof(unsigned char));
          memcpy(score_group, format + format_shift, len_score_group);
          score_group[len_score_group]='\0';
          groups->groups[i_group].scores[j_group-(i_group+1)] = atof(score_group);
          format_shift += len_score_group + 1;
          free(score_group);
        }
        else{
          break;
        }
      }
    format_shift += 1; // FOR LETTER 'E'*/
    }
    // retrieve the number of messages in the current group
    p = strchr(format + format_shift, 'G');
    len_size_group = (unsigned int) (p - (format + format_shift));
    size_group_str = malloc((len_size_group + 1) * sizeof(char));
    memcpy(size_group_str, format + format_shift, len_size_group);
    size_group_str[len_size_group] = '\0';
    size_group = (unsigned int) atoi(size_group_str);
    format_shift += len_size_group + 1;

    // Allocate pointers to store the messages of current group
    groups->groups[i_group].len = size_group;
    groups->groups[i_group].messages = malloc(size_group * sizeof(t_message));

    for (i_message = 0; i_message < size_group; i_message++) {
      // Retrieve the size of each message
      q = strchr(format + format_shift, 'M');
      len_size_message = (unsigned int) (q - (format + format_shift));
      size_message_str = malloc((len_size_message + 1) * sizeof(char));
      memcpy(size_message_str, format + format_shift, len_size_message);
      size_message_str[len_size_message] = '\0';
      size_message = atoi(size_message_str);
      format_shift += len_size_message + 1;

      // Retrieve the data of each message
      groups->groups[i_group].messages[i_message].len = size_message;
      groups->groups[i_group].messages[i_message].alignment = serialGroups + l;
      groups->groups[i_group].messages[i_message].mask = serialGroups + l + size_message;

      l += size_message * 2;
      free(size_message_str );
    }
    free(size_group_str);
  }
  if (debugMode == TRUE) {
    printf("A number of %d group has been deserialized.\n", nbGroups);
  }
  return i_group;
}

#define OPL 64

void hexdump(unsigned char *buf, int dlen) {
  char c[OPL + 1];
  int i, ct;

  if (dlen < 0) {
    printf("WARNING: computed dlen %d\n", dlen);
    dlen = 0;
  }

  for (i = 0; i < dlen; ++i) {
    if (i == 0)
      printf("DATA: ");
    else if ((i % OPL) == 0) {
      c[OPL] = '\0';
      printf("\t\"%s\"\nDATA: ", c);
    }
    ct = buf[i] & 0xff;
    c[i % OPL] = (ct >= ' ' && ct <= '~') ? ct : '.';
    printf("%02x ", ct);
  }
  c[i % OPL] = '\0';
  for (; i % OPL; ++i)
    printf("   ");
  printf("\t\"%s\"\n", c);
}


void dumpMessage(t_message message) {
  unsigned int i;
  printf("%d ", message.len);
  for(i = 0; i < message.len; i++) {
    if(message.mask[i] == 0)
      printf("%02x", (unsigned char) message.alignment[i]);
    else if(message.mask[i] == 2)
      printf("##");
    else
      printf("--");
  }
  printf("\n");
}
