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

Generated on Sat Mar 14 13:44:29 2009 for Heraia by  doxygen 1.5.6