decode.c

Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
00002 /*
00003   decode.c
00004   Heraia's library decode.c
00005 
00006   (C) Copyright 2008 - 2010 Sébastien Tricaud, Olivier Delhomme
00007   e-mail : heraia@delhomme.org
00008   URL    : http://heraia.tuxfamily.org
00009 
00010   This program is free software; you can redistribute it and/or modify
00011   it under the terms of the GNU General Public License as published by
00012   the Free Software Foundation; either version 2, or  (at your option)
00013   any later version.
00014 
00015   This program is distributed in the hope that it will be useful,
00016   but WITHOUT ANY WARRANTY;  without even the implied warranty of
00017   MERCHANTABILITY  or  FITNESS FOR A PARTICULAR PURPOSE.  See the
00018   GNU General Public License for more details.
00019 
00020   You should have received a copy of the GNU General Public License
00021   along with this program; if not, write to the Free Software
00022   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
00023 /**
00024  * @file decode.c
00025  * This file include all functions that may help in decoding a binary stream
00026  * to something else such as numbers, dates, other binary stream and so on
00027  * @todo I see, while putting some functions documentation that there may be
00028  *       things to do to improve speed with date calculations -> should we fill
00029  *       tab_ns_months at every function calls ? This may not be necessary
00030  */
00031 #include <libheraia.h>
00032 
00033 static gboolean bissextile_year(guint32 year);
00034 static void calc_which_month_day(date_and_time_t *mydate, guint32 day, guint tab_ns_months[12]);
00035 static void which_month_day(date_and_time_t *mydate, guint32 day, gboolean bi);
00036 static guint32 remove_days_from_first_january(guint32 base_year, guint8 base_month, guint8 base_day);
00037 static void which_year_month_day(date_and_time_t *mydate, guint32 days, guint32 base_year, guint base_month, guint8 base_day);
00038 static void make_date_and_time(date_and_time_t *mydate, guchar *data, guint8 len, guint64 nbticks, guint32 base_year, guint base_month, guint8 base_day);
00039 static void transform_bcd_to_human(gchar *bcd, guint8 part, guint8 part_number);
00040 
00041 
00042 /**
00043  *  General purpose of this function is to take a 1 byte data stream
00044  *  and convert it as if it is an 8 bits signed number
00045  *  @param data : 1 guchar
00046  *  @param data_struct a pointer to a user defined data structure
00047  *  @return returns a gchar * that may be freed when no longer needed
00048  */
00049 gchar *decode_8bits_signed(guchar *data, gpointer data_struct)
00050 {
00051     gint8 total = 0;
00052 
00053     if (data == NULL)
00054         {
00055             return NULL;
00056         }
00057     else
00058         {
00059             memcpy(&total, data, sizeof (guchar));
00060             return g_strdup_printf("%d", total);
00061         }
00062 }
00063 
00064 
00065 /**
00066  *  general purpose of this function is to take a 1 byte data stream
00067  *  and convert it as if it is an 8 bits unsigned number
00068  *  @param data : 1 guchar
00069  *  @param data_struct a pointer to a user defined data structure
00070  *  @return returns a gchar * that may be freed when no longer needed
00071 */
00072 gchar *decode_8bits_unsigned(guchar *data, gpointer data_struct)
00073 {
00074     guint8 total = 0;
00075 
00076     if (data == NULL)
00077         {
00078             return NULL;
00079         }
00080     else
00081         {
00082             memcpy(&total, data, sizeof (guchar));
00083             return g_strdup_printf("%u", total);
00084         }
00085 }
00086 
00087 
00088 /**
00089  *  general purpose of this function is to take a 2 byte data stream
00090  *  and convert it as if it is a 16 bits signed number
00091  *  @param data : 2 guchars
00092  *  @param data_struct a pointer to a user defined data structure
00093  *  @return returns a gchar * that may be freed when no longer needed
00094  */
00095 gchar *decode_16bits_signed(guchar *data, gpointer data_struct)
00096 {
00097     gint16 total = 0;
00098 
00099     if (data == NULL)
00100         {
00101             return NULL;
00102         }
00103     else
00104         {
00105             memcpy(&total, data, 2 * sizeof (guchar));
00106             return g_strdup_printf("%d", total);
00107         }
00108 }
00109 
00110 
00111 /**
00112  *  general purpose of this function is to take a 2 byte data stream
00113  *  and convert it as if it is a 16 bits unsigned number
00114  *  @param data : 2 guchars
00115  *  @param data_struct a pointer to a user defined data structure
00116  *  @return returns a gchar * that may be freed when no longer needed
00117  */
00118 gchar *decode_16bits_unsigned(guchar *data, gpointer data_struct)
00119 {
00120     guint16 total = 0;
00121 
00122     if (data == NULL)
00123         {
00124             return NULL;
00125         }
00126     else
00127         {
00128             memcpy(&total, data, 2 * sizeof (guchar));
00129             return g_strdup_printf("%u", total);
00130         }
00131 }
00132 
00133 
00134 /**
00135  *  general purpose of this function is to take a 4 byte data stream
00136  *  and convert it as if it is a 32 bits signed number
00137  *  @param data : 4 guchars
00138  *  @param data_struct a pointer to a user defined data structure
00139  *  @return returns a gchar * that may be freed when no longer needed
00140 */
00141 gchar *decode_32bits_signed(guchar *data, gpointer data_struct)
00142 {
00143     gint32 total = 0;
00144 
00145     if (data == NULL)
00146         {
00147             return NULL;
00148         }
00149     else
00150         {
00151             memcpy(&total, data, 4 * sizeof (guchar));
00152             return g_strdup_printf("%d", total);
00153         }
00154 }
00155 
00156 
00157 /**
00158  *  general purpose of this function is to take a 4 byte data stream
00159  *  and convert it as if it is a 32 bits unsigned number
00160  *  @param data : 4 guchars
00161  *  @param data_struct a pointer to a user defined data structure
00162  *  @return returns a gchar * that may be freed when no longer needed
00163 */
00164 gchar *decode_32bits_unsigned(guchar *data, gpointer data_struct)
00165 {
00166     guint32 total = 0;
00167 
00168     if (data == NULL)
00169         {
00170             return NULL;
00171         }
00172     else
00173         {
00174             memcpy(&total, data, 4 * sizeof (guchar));
00175             return g_strdup_printf("%u", total);
00176         }
00177 }
00178 
00179 
00180 /**
00181  *  general purpose of this function is to take a 8 byte data stream
00182  *  and convert it as if it is a 64 bits signed number
00183  *  @param data : 8 guchars
00184  *  @param data_struct a pointer to a user defined data structure
00185  *  @return returns a gchar * that may be freed when no longer needed
00186 */
00187 gchar *decode_64bits_signed(guchar *data, gpointer data_struct)
00188 {
00189     gint64 total = 0;
00190 
00191     if (data == NULL)
00192         {
00193             return NULL;
00194         }
00195     else
00196         {
00197             memcpy(&total, data, 8 * sizeof (guchar));
00198             return g_strdup_printf("%ld", total);
00199         }
00200 }
00201 
00202 
00203 /**
00204  *  general purpose of this function is to take a 8 byte data stream
00205  *  and convert it as if it is a 64 bits unsigned number
00206  *  @param data : 8 guchars
00207  *  @param data_struct a pointer to a user defined data structure
00208  *  @return returns a gchar * that may be freed when no longer needed
00209 */
00210 gchar *decode_64bits_unsigned(guchar *data, gpointer data_struct)
00211 {
00212     guint64 total = 0;
00213 
00214     if (data == NULL)
00215         {
00216             return NULL;
00217         }
00218     else
00219         {
00220             memcpy(&total, data, 8 * sizeof (guchar));
00221             return g_strdup_printf("%lu", total);
00222         }
00223 }
00224 
00225 
00226 /**
00227  *  general purpose of this function is to take a 4 byte data stream
00228  *  and convert it as if it is a float number normal notation
00229  *  @param data : 4 guchars
00230  *  @param data_struct a pointer to a user defined data structure
00231  *  @return returns a gchar * that may be freed when no longer needed
00232 */
00233 gchar *decode_float_normal(guchar *data, gpointer data_struct)
00234 {
00235     gfloat total = 0.0;
00236 
00237     if (data == NULL)
00238         {
00239             return NULL;
00240         }
00241     else
00242         {
00243             memcpy(&total, data, 4 * sizeof (guchar));
00244             return g_strdup_printf("%f", total);
00245         }
00246 }
00247 
00248 
00249 /**
00250  *  general purpose of this function is to take a 4 byte data stream
00251  *  and convert it as if it is a float number normal notation
00252  *  @param data : 4 guchars
00253  *  @param data_struct a pointer to a user defined data structure
00254  *  @return returns a gchar * that may be freed when no longer needed
00255 */
00256 gchar *decode_float_scientific(guchar *data, gpointer data_struct)
00257 {
00258     gfloat total = 0.0;
00259 
00260     if (data == NULL)
00261         {
00262             return NULL;
00263         }
00264     else
00265         {
00266             memcpy(&total, data, 4 * sizeof (guchar));
00267             return g_strdup_printf("%g", total);
00268         }
00269 }
00270 
00271 
00272 /**
00273  *  general purpose of this function is to take a 8 byte data stream
00274  *  and convert it as if it is a float number normal notation
00275  *  @param data : 4 guchars
00276  *  @param data_struct a pointer to a user defined data structure
00277  *  @return returns a gchar * that may be freed when no longer needed
00278 */
00279 gchar *decode_double_normal(guchar *data, gpointer data_struct)
00280 {
00281     gdouble total = 0.0;
00282 
00283     if (data == NULL)
00284         {
00285             return NULL;
00286         }
00287     else
00288         {
00289             memcpy(&total, data, 8 * sizeof (guchar));
00290             return g_strdup_printf("%f", total);
00291         }
00292 }
00293 
00294 
00295 /**
00296  *  general purpose of this function is to take a 8 byte data stream
00297  *  and convert it as if it is a float number normal notation
00298  *  @param data : 4 guchars
00299  *  @param data_struct a pointer to a user defined data structure
00300  *  @return returns a gchar * that may be freed when no longer needed
00301 */
00302 gchar *decode_double_scientific(guchar *data, gpointer data_struct)
00303 {
00304     gdouble total = 0.0;
00305 
00306     if (data == NULL)
00307         {
00308             return NULL;
00309         }
00310     else
00311         {
00312             memcpy(&total, data, 8 * sizeof (guchar));
00313             return g_strdup_printf("%g", total);
00314         }
00315 }
00316 
00317 
00318 /**
00319  *  Says whether a year is a leap one or not
00320  * @param year : a guint32 representing a year such as 2009
00321  * @return TRUE if it's a leap year FALSE instead.
00322  */
00323 static gboolean bissextile_year(guint32 year)
00324 {
00325     if ((year % 4) == 0)
00326         {
00327             if ((year % 100) == 0)
00328                 {
00329                     if ((year % 400) == 0)
00330                         {
00331                             return TRUE;
00332                         }
00333                     else
00334                         {
00335                             return FALSE;
00336                         }
00337                 }
00338             else
00339                 {
00340                     return TRUE;
00341                 }
00342         }
00343     else
00344         {
00345             return FALSE;
00346         }
00347 }
00348 
00349 
00350 /**
00351  *  Says, from a number of days (eg 154), which month it is (eg  may)
00352  *  and which day in the corresponding month (eg 2 (leap year) or 3)
00353  *  @param[out] mydate : Filled date structure
00354  *  @param day : guint32 representing the number of day in the year (1..365/366)
00355  *  @param tab_ns_months : an array filled with the cumulative number of days for each month (31 to 365/366)
00356  */
00357 static void calc_which_month_day(date_and_time_t *mydate, guint32 day, guint tab_ns_months[12])
00358 {
00359     gushort i = 0;
00360 
00361     while (i<12 && day > tab_ns_months[i])
00362         {
00363             i++;
00364         }
00365 
00366     mydate->month = i + 1;
00367 
00368     if (i == 0)
00369         {
00370             mydate->day = 1 + day;
00371         }
00372     else
00373         {
00374             mydate->day = (1 + day) - tab_ns_months[i-1];
00375         }
00376 }
00377 
00378 
00379 /**
00380  *  Front end function for the calc_which_month_day function !
00381  * @param[out] mydate : Filled date structure
00382  * @param day : guint32 representing the number of day in the year (1..365/366)
00383  * @param bi : TRUE if it's a leap year, FALSE instead
00384  */
00385 static void which_month_day(date_and_time_t *mydate, guint32 day, gboolean bi)
00386 {
00387 
00388     if (bi == TRUE)
00389         {
00390             if (day <= 366)
00391                 {
00392                     guint tab_ns_months[12] = { 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } ;
00393                     calc_which_month_day(mydate, day, tab_ns_months);
00394                 }
00395             else
00396                 {
00397                     mydate->day = 0;
00398                     mydate->month = 0;
00399                 }
00400         }
00401     else
00402         {
00403             if (day <= 365)
00404                 {
00405                     guint tab_ns_months[12] = { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
00406                     calc_which_month_day(mydate, day, tab_ns_months);
00407                 }
00408             else
00409                 {
00410                     mydate->day = 0;
00411                     mydate->month = 0;
00412                 }
00413         }
00414 }
00415 
00416 
00417 /**
00418  *  Returns the number of days since 01/01/base_year
00419  *  eg 15/02/base_year --> 31 + 15 = 46
00420  * @param base_year : year where we want to begin the calculation
00421  * @param base_month : month (in the example 02)
00422  * @param base_day : day in the month (from the example 15)
00423  * @return returns a number of days since begining of the year (eg 1..365/366)
00424  */
00425 static guint32 remove_days_from_first_january(guint32 base_year, guint8 base_month, guint8 base_day)
00426 {
00427     guint tab_ns_months[11];
00428 
00429     if (base_day > 0 && base_day < 32)
00430         {
00431             base_day -= 1;
00432         }
00433     else
00434         {
00435             return 0;  /* Obviously something might be wrong if we fall here */
00436         }
00437 
00438     tab_ns_months[0] = 31;
00439     if (bissextile_year(base_year))
00440         {
00441             tab_ns_months[1] = 60;
00442             tab_ns_months[2] = 91;
00443             tab_ns_months[3] = 121;
00444             tab_ns_months[4] = 152;
00445             tab_ns_months[5] = 182;
00446             tab_ns_months[6] = 213;
00447             tab_ns_months[7] = 244;
00448             tab_ns_months[8] = 274;
00449             tab_ns_months[9] = 305;
00450             tab_ns_months[10] = 335;
00451         }
00452     else
00453         {
00454             tab_ns_months[1] = 59;
00455             tab_ns_months[2] = 90;
00456             tab_ns_months[3] = 120;
00457             tab_ns_months[4] = 151;
00458             tab_ns_months[5] = 181;
00459             tab_ns_months[6] = 212;
00460             tab_ns_months[7] = 243;
00461             tab_ns_months[8] = 273;
00462             tab_ns_months[9] = 304;
00463             tab_ns_months[10] = 334;
00464         }
00465 
00466     if (base_month > 1 && base_month < 13)
00467         {
00468             return (tab_ns_months[base_month-2] + base_day);
00469         }
00470     else if (base_month == 1)
00471         {
00472             return base_day;
00473         }
00474     else
00475         {
00476             return 0;
00477         }
00478 }
00479 
00480 
00481 /**
00482  * About date calculation : Leap years are periods of 4 years except
00483  * the years that we can divide by 100 and not 400.
00484  * So we can distinguish 2 periods : one of 400 years and one of 4 years.
00485  *  - we have 100 bissextiles years in a period of 400 years this means that
00486  *    every 400 years we have exactly 146100 days.
00487  *  - we have 1 bissextile year every 4 years : this means that we have exactly
00488  *    1461 days every 4 years.
00489  *  As we can calculate _exactly_ the number of days in a filetime or C_date
00490  *  format, we could calculate _exactly_ the number of periods of 400 years and
00491  *  then the number of periods of 4 years.
00492  * @param[out] mydate : Filled date structure
00493  * @param days : number of days calculated
00494  * @param base_year : base year used for calculation (eg 1601 for filetime)
00495  * @param base_month : base month used for calculation (eg 01, january for filetime)
00496  * @param base_day : base day used for calculation (eg 01 for filetime)
00497 */
00498 static void which_year_month_day(date_and_time_t *mydate, guint32 days, guint32 base_year, guint base_month, guint8 base_day)
00499 {
00500     guint32 modulus = 0;
00501     guint32 reste = 0;
00502     guint32 nbdays = 0;
00503 
00504     days -= remove_days_from_first_january(base_year, base_month, base_day);
00505 
00506     if (days > 146100)
00507         {
00508             modulus = days / 146100;
00509             mydate->year = modulus * 400;
00510             reste = modulus * 3;     /* To add centuries in the 400 years modulus */
00511             days = days % 146100;
00512         }
00513 
00514     modulus = days / 1461;
00515     mydate->year += modulus * 4;
00516     reste += (modulus*4) / 100;    /* To add centuries */
00517     reste += days % 1461;
00518 
00519     mydate->year += base_year;
00520     if (bissextile_year(mydate->year))
00521         nbdays = 366;
00522     else
00523         nbdays = 365;
00524 
00525     while (reste > nbdays)
00526         {
00527             reste -= nbdays;
00528             mydate->year += 1;
00529             if (bissextile_year(mydate->year))
00530                 nbdays = 366;
00531             else
00532                 nbdays = 365;
00533         }
00534 
00535     which_month_day(mydate, reste, bissextile_year(mydate->year));
00536 }
00537 
00538 
00539 /**
00540  *  Return a gchar * that contains the date and time
00541  *  encoded from the values contained in the date_and_time_t structure
00542  *  it may be freed when no longer needed
00543  *  We do not use any of the g_date_strftime or strftime function
00544  *  because interpreted dates are not always valid !
00545  * @param[in] mydate : structure that contains a date
00546  * @return returns a gchar * printed out in a french like format "dd/mm/aaaa - hh:mm:ss"
00547  * @todo Add a way to use a user defined format and/or predefined formats
00548  */
00549 static gchar *date_printf(date_and_time_t *mydate)
00550 {
00551     return g_strdup_printf("%02u/%02u/%04u - %02u:%02u:%02u", mydate->day, mydate->month, mydate->year, mydate->hour, mydate->minutes, mydate->seconds);
00552 }
00553 
00554 
00555 /**
00556  *  general purpose of this function is to take a 4 byte data stream
00557  *  and convert it as if it is a dos date. If it is not, the result
00558  *  may be funny !
00559  *  @param data : 4 guchars
00560  *  @param data_struct a pointer to a user defined data structure
00561  *  @return returns a gchar * that may be freed when no longer needed
00562 */
00563 gchar *decode_dos_date(guchar *data, gpointer data_struct)
00564 {
00565     date_and_time_t *mydate = NULL;  /**< date resulting of interpretation               */
00566     gchar *interpreted_date =  NULL; /**< text that is the result of date interpretation */
00567 
00568     if (data == NULL)
00569         {
00570             return NULL;
00571         }
00572     else
00573         {
00574             mydate = (date_and_time_t *) g_malloc0 (sizeof(date_and_time_t));
00575 
00576             mydate->year = (data[3] >> 1) + 1980;
00577             mydate->month = ((data[3] & 0x01) << 3) + (data[2] >> 5);
00578             mydate->day = data[2] & 0x1F;
00579             mydate->hour = (data[1] & 0xF8) >> 3;
00580             mydate->minutes = ((data[1] & 0x07) << 3) + ((data[0] & 0xE0) >> 5);
00581             mydate->seconds = (data[0] & 0x1F) << 1;
00582 
00583             interpreted_date = date_printf(mydate);
00584             g_free(mydate);
00585 
00586             return interpreted_date;
00587         }
00588 }
00589 
00590 
00591 /**
00592  *  Reads the data from the stream (specified length !! <= 8 or 64 bits to decode)
00593  *  @param[out] mydate : date_and_time_t * structure that contain the resulting date
00594  *  @param data : a guchar * as a stream to decode as a date
00595  *  @param len : guint8 as length of the stream in bytes (must be <= 8 or 64 bits to decode)
00596  *  @param nbticks : guint64 that tells the number of ticks per seconds (1, 1000, ...)
00597  *  @param base_year : guint32, Epoch year (1970, 1904, ...)
00598  *  @param base_month : guint32, Epoch month (january, ...)
00599  *  @param base_day : guint32 Epoch day (01, 15, ...)
00600  *  @return populates the date_and_time_t structure (my_date)
00601 */
00602 static void make_date_and_time(date_and_time_t *mydate, guchar *data, guint8 len, guint64 nbticks, guint32 base_year, guint base_month, guint8 base_day)
00603 {
00604     guint64 total = 0;
00605     guint32 days = 0;
00606 
00607     memcpy(&total, data, len * sizeof (guchar));
00608 
00609     total = (total / nbticks);         /* 1 seconds represents nbticks */
00610     days = (guint32) (total / 86400);  /* 86400 seconds a day          */;
00611 
00612     which_year_month_day(mydate, days, base_year, base_month, base_day);
00613 
00614     mydate->hour = ((total % 86400) / 3600);  /* 3600 seconds is one hour out of one day */
00615     mydate->minutes = ((total % 3600) / 60);  /* 60 seconds is one minute out of one hour */
00616     mydate->seconds = (total % 60);
00617 }
00618 
00619 
00620 /**
00621  *  general purpose of this function is to take a 8 byte data stream
00622  *  and convert it as if it is a filetime date. If it is not, the result
00623  *  may be funny ! Counting 100th of nanoseconds from 01/01/1601
00624  *  @param data : 8 guchars
00625  *  @param data_struct a pointer to a user defined data structure
00626  *  @return returns a gchar * that may be freed when no longer needed
00627 */
00628 gchar *decode_filetime_date(guchar *data, gpointer data_struct)
00629 {
00630     date_and_time_t *mydate = NULL;  /**< date resulting of interpretation               */
00631     gchar *interpreted_date =  NULL; /**< text that is the result of date interpretation */
00632 
00633     if (data == NULL)
00634         {
00635             return NULL;
00636         }
00637     else
00638         {
00639             mydate = (date_and_time_t *) g_malloc0 (sizeof(date_and_time_t));
00640 
00641             make_date_and_time(mydate, data, 8, 10000000, 1601, 1, 1);
00642 
00643             interpreted_date = date_printf(mydate);
00644             g_free(mydate);
00645 
00646             return interpreted_date;
00647         }
00648 }
00649 
00650 
00651 /**
00652  *  general purpose of this function is to take a 4 byte data stream
00653  *  and convert it as if it is a C date. If it is not, the result may
00654  *  be funny ! Counting seconds from 01/01/1970
00655  *  @param data : 4 guchars
00656  *  @param data_struct a pointer to a user defined data structure
00657  *  @return returns a gchar * that may be freed when no longer needed
00658 */
00659 gchar *decode_C_date(guchar *data, gpointer data_struct)
00660 {
00661     date_and_time_t *mydate = NULL;  /**< date resulting of interpretation               */
00662     gchar *interpreted_date =  NULL; /**< text that is the result of date interpretation */
00663 
00664     if (data == NULL)
00665         {
00666             return NULL;
00667         }
00668     else
00669         {
00670             mydate = (date_and_time_t *) g_malloc0 (sizeof(date_and_time_t));
00671 
00672             make_date_and_time(mydate, data, 4, 1, 1970, 1, 1);
00673 
00674             interpreted_date = date_printf(mydate);
00675             g_free(mydate);
00676 
00677             return interpreted_date;
00678         }
00679 }
00680 
00681 
00682 /**
00683  *  general purpose of this function is to take a 4 byte data stream
00684  *  and convert it as if it is a HFS date. If it is not, the result may
00685  *  be funny ! Counting seconds 01/01/1904
00686  *  @param data : 4 guchars
00687  *  @param data_struct a pointer to a user defined data structure
00688  *  @return returns a gchar* that may be freed when no longer needed
00689 */
00690 gchar *decode_HFS_date(guchar *data, gpointer data_struct)
00691 {
00692     date_and_time_t *mydate = NULL;  /**< date resulting of interpretation               */
00693     gchar *interpreted_date =  NULL; /**< text that is the result of date interpretation */
00694 
00695     if (data == NULL)
00696         {
00697             return NULL;
00698         }
00699     else
00700         {
00701             mydate = (date_and_time_t *) g_malloc0 (sizeof(date_and_time_t));
00702 
00703             make_date_and_time(mydate, data, 4, 1, 1904, 1, 1);
00704 
00705             interpreted_date = date_printf(mydate);
00706             g_free(mydate);
00707 
00708             return interpreted_date;
00709         }
00710 }
00711 
00712 
00713 /**
00714  * Returns a guchar that is 1 or 0 respectiveky if data is > 0 or not
00715  * @param data : a value to analyse
00716  * @return : 1 or 0 f data is > 0 or not
00717  */
00718 static guchar data_to_one_bit(guchar data)
00719 {
00720     if (data > 0)
00721         {
00722             return '1';
00723         }
00724     else
00725         {
00726             return '0';
00727         }
00728 }
00729 
00730 
00731 /**
00732  *  decodes the stream represented by *data (one byte) to a
00733  *  string containing eight 0 or 1 (Little Endian style)
00734  *  @param data : 1 guchar
00735  *  @param data_struct a pointer to a user defined data structure
00736  *  @return n*9 gchars that are either '1' or '0' or ' ' (as a separator), the
00737  *          string may be freed when no longer needed
00738  */
00739 gchar *decode_to_bits(guchar *data, gpointer data_struct)
00740 {
00741     gchar *bits = NULL;
00742     guint i = 0;
00743     guint j = 0;
00744     decode_parameters_t *decode_parameters = (decode_parameters_t *) data_struct;
00745 
00746     if (data == NULL)
00747         {
00748             return NULL;
00749         }
00750     else
00751         {
00752             bits = (gchar *) g_malloc0(decode_parameters->stream_size * 10 * (sizeof(gchar)) + 1);
00753 
00754             j = 0;
00755             for (i = 0 ; i <  decode_parameters->stream_size ; i++)
00756                 {
00757                     bits[j] = data_to_one_bit(data[i] & 0x80);
00758                     j++;
00759 
00760                     bits[j] = data_to_one_bit(data[i] & 0x40);
00761                     j++;
00762 
00763                     bits[j] = data_to_one_bit(data[i] & 0x20);
00764                     j++;
00765 
00766                     bits[j] = data_to_one_bit(data[i] & 0x10);
00767                     j++;
00768 
00769                     bits[j] = ' ';
00770                     j++;
00771 
00772                     bits[j] = data_to_one_bit(data[i] & 0x08);
00773                     j++;
00774 
00775                     bits[j] = data_to_one_bit(data[i] & 0x04);
00776                     j++;
00777 
00778                     bits[j] = data_to_one_bit(data[i] & 0x02);
00779                     j++;
00780 
00781                     bits[j] = data_to_one_bit(data[i] & 0x01);
00782                     j++;
00783 
00784                     bits[j] = ' ';
00785                     j++;
00786                 }
00787 
00788             j--;
00789             bits[j] = (gchar) 0;
00790 
00791             return bits;
00792 
00793         }
00794 }
00795 
00796 
00797 /**
00798  *  transcribes the bcd number "part" into a
00799  *  @param[out] bcd : gchar * human readable string
00800  *  @param part : guint8 as an half byte to decode
00801  *  @param part_number : 0 or 1 as MSB and LSB
00802  *  Coding style is from ETSI GSM 04.08 ETS 300557 p387
00803  *  @todo give choice of coding style (eg for numbers >=10)
00804  */
00805 static void transform_bcd_to_human(gchar *bcd, guint8 part, guint8 part_number)
00806 {
00807     switch (part)
00808         {
00809             case 0 :
00810                 bcd[part_number] = '0';
00811                 break;
00812             case 1 :
00813                 bcd[part_number] = '1';
00814                 break;
00815             case 2 :
00816                 bcd[part_number] = '2';
00817                 break;
00818             case 3 :
00819                 bcd[part_number] = '3';
00820                 break;
00821             case 4 :
00822                 bcd[part_number] = '4';
00823                 break;
00824             case 5 :
00825                 bcd[part_number] = '5';
00826                 break;
00827             case 6 :
00828                 bcd[part_number] = '6';
00829                 break;
00830             case 7 :
00831                 bcd[part_number] = '7';
00832                 break;
00833             case 8 :
00834                 bcd[part_number] = '8';
00835                 break;
00836             case 9 :
00837                 bcd[part_number] = '9';
00838                 break;
00839             case 10 :
00840                 bcd[part_number] = '*';
00841                 break;
00842             case 11 :
00843                 bcd[part_number] = '#';
00844                 break;
00845             case 12 :
00846                 bcd[part_number] = 'a';
00847                 break;
00848             case 13 :
00849                 bcd[part_number] = 'b';
00850                 break;
00851             case 14 :
00852                 bcd[part_number] = 'c';
00853                 break;
00854             case 15 :
00855                 bcd[part_number] = ' ';  /* Endmark */
00856                 break;
00857             default :
00858                 bcd[part_number] = '?';  /* This default case should never happen */
00859                 break;
00860         }
00861 }
00862 
00863 
00864 /**
00865  *  Decode one byte as a Packed BCD (Binary Coded Decimal)
00866  *  and return a gchar* that may be freed when no longer
00867  *  needed
00868  *  @param data : stream to decode as 1 guchar
00869  *  @param data_struct a pointer to a user defined data structure
00870  *  @return returns a gchar * that contain the packed BCD interpretation
00871  */
00872 gchar *decode_packed_BCD(guchar *data, gpointer data_struct)
00873 {
00874     guint8 total = 0;
00875     guint i = 0;
00876     guint j = 0;
00877     gchar *bcd = NULL;
00878     decode_parameters_t *decode_parameters = (decode_parameters_t *) data_struct;
00879 
00880     if (data == NULL)
00881         {
00882             return NULL;
00883         }
00884     else
00885         {
00886             i = 0;
00887             j = 0;
00888             bcd = (gchar *) g_malloc0((2 * decode_parameters->stream_size + 1) * sizeof(gchar));
00889             while (i < decode_parameters->stream_size)
00890                 {
00891                     memcpy(&total, data + i, sizeof(guchar));
00892                     transform_bcd_to_human(bcd + j, (total & 0x0F), 0);
00893                     transform_bcd_to_human(bcd + j, ((total & 0xF0)>>4), 1);
00894                     i++;
00895                     j = j + 2;
00896                 }
00897             bcd[j+1] = '\0';
00898 
00899             return bcd;
00900         }
00901 }
00902 
00903 
00904 /**
00905  *  Swap bytes from the buffer to_swap
00906  *  @warning recursive function !! Call with first = 0 and last = last byte
00907  *  of buffer to swap
00908  *  @param[in,out] to_swap : buffer to swap
00909  *  @param first : first byte in the buffer to swap
00910  *  @param last : last byte in the buffer to swap
00911  *  @return returns TRUE when first is >= to last and this end recursivity
00912  */
00913 gboolean swap_bytes(guchar *to_swap, guint first, guint last)
00914 {
00915     guchar aux;
00916 
00917     if (first >= last)
00918         {
00919             return TRUE;
00920         }
00921     else
00922         {
00923             aux = to_swap[first];
00924             to_swap[first] = to_swap[last];
00925             to_swap[last] = aux;
00926             return swap_bytes(to_swap, ++first, --last);
00927         }
00928 }
00929 
00930 
00931 /**
00932  *  Reverse the byte order LSB -> MSB in MSB -> LSB
00933  *  12345678 in 87654321
00934  * @param[in,out] to_reverse : one guchar to be reversed
00935  */
00936 void reverse_byte_order(guchar *to_reverse)
00937 {
00938     guint8 car = (guint8) to_reverse[0];
00939     guint8 aux = 0;
00940 
00941     aux = ((car & 0x80) >> 7);
00942     aux += ((car & 0x40) >> 5);
00943     aux += ((car & 0x20) >> 3);
00944     aux += ((car & 0x10) >> 1);
00945     aux += ((car & 0x08) << 1);
00946     aux += ((car & 0x04) << 3);
00947     aux += ((car & 0x02) << 5);
00948     aux += ((car & 0x01) << 7);
00949 
00950     to_reverse[0] = (guchar) aux;
00951 }
00952 
00953 
00954 /**
00955  * Make an new decode_parameters_t in order to pass to the functions
00956  * @param endianness : endianness as setup in data interpertor's window
00957  * @param stream_size : stream size as setup with the spin button
00958  * @return returns a newly allocated decode_parameters_t structure which may be
00959  *         freed when no longer needed
00960  */
00961 decode_parameters_t *new_decode_parameters_t(guint endianness, guint stream_size)
00962 {
00963     decode_parameters_t *decode_parameters = NULL;
00964 
00965     decode_parameters = (decode_parameters_t *) g_malloc0(sizeof(decode_parameters_t));
00966 
00967     decode_parameters->endianness = endianness;
00968     decode_parameters->stream_size = stream_size;
00969 
00970     return decode_parameters;
00971 }
00972 
00973 
00974 /**
00975  * Make a new decode_t structure
00976  * @param decode_func : pointer to a function that may decode a stream
00977  *                      this function must follow DecodeFunc prototype
00978  * @param entry : A GtkWidget entry that will receive the result of the
00979  *                decoding function
00980  * @return returns a newly allocated decode_t structure filled with the two
00981  *         parameters.
00982  */
00983 decode_t *new_decode_t(DecodeFunc decode_func, GtkWidget *entry, const gchar *err_msg)
00984 {
00985     decode_t *decode_struct = NULL;
00986 
00987     if (decode_func != NULL && entry != NULL)
00988         {
00989             decode_struct = (decode_t *) g_malloc0(sizeof(decode_t));
00990             decode_struct->func = decode_func;
00991             decode_struct->entry = entry;
00992             decode_struct->err_msg = g_strdup(err_msg);
00993 
00994             return decode_struct;
00995         }
00996     else
00997         {
00998             return NULL;
00999         }
01000 }
01001 
01002 
01003 /**
01004  * Make a new decode_generic_t structure and creates the associated widgets
01005  * @param label : the label for this row
01006  * @param data_size : a default data_size
01007  * @param fixed_size : TRUE if the size is fixed and should not be updated,
01008  *                     FALSE otherwise
01009  * @param err_msg : an error message to be displayed if dcoding can not be
01010  *                  processed
01011  * @param nb_cols : number of decoding columns we want
01012  * @param ... : va_list of functions to fill in the columns (you MUST have the
01013  *              same number of columns and functions you passes here as
01014  *              arguments)
01015  * @return returns a newly allocated decode_generic_t structure filled with the
01016  *         right parameters
01017  */
01018 decode_generic_t *new_decode_generic_t(const gchar *label, guint data_size, gboolean fixed_size, const gchar *err_msg, guint nb_cols, ...)
01019 {
01020     va_list args;                       /**< va_list arguments : decoding function names */
01021     decode_generic_t *my_struct = NULL; /** structure to be initialized and returned     */
01022     decode_t *decode;                   /** Entry and associated function                */
01023     guint i = 0;
01024     DecodeFunc decode_it;               /**< one decoding function                       */
01025     GtkWidget *entry = NULL;            /**< entry associated to the decoding function   */
01026     GPtrArray *decode_array;            /**< To keep track of those couples              */
01027 
01028     decode_array = g_ptr_array_new();
01029 
01030     my_struct = (decode_generic_t *) g_malloc0(sizeof(decode_generic_t));
01031 
01032     va_start(args, nb_cols);
01033     for (i = 0 ; i < nb_cols ; i++)
01034         {
01035             decode_it = (DecodeFunc) va_arg(args, DecodeFunc);
01036             entry = gtk_entry_new();
01037             gtk_entry_set_editable(GTK_ENTRY(entry), FALSE);
01038             decode = new_decode_t(decode_it, entry, err_msg);
01039             g_ptr_array_add(decode_array, (gpointer) decode);
01040         }
01041     va_end(args);
01042 
01043     my_struct->decode_array = decode_array;
01044     my_struct->label = gtk_label_new(label);
01045     gtk_misc_set_padding(GTK_MISC(my_struct->label), 3, 3);
01046     gtk_misc_set_alignment(GTK_MISC(my_struct->label), 0.5, 0.5);
01047     my_struct->data_size = data_size;
01048     my_struct->fixed_size = fixed_size;
01049 
01050     return my_struct;
01051 }
Generated on Tue Aug 10 18:29:02 2010 for Heraia by  doxygen 1.6.3