1 : /* -*- Mode: C; tab-width: 3; indent-tabs-mode: t; c-basic-offset: 3 -*- */
2 : /*
3 : decode.c
4 : heraia - an hexadecimal file editor and analyser based on ghex
5 :
6 : (C) Copyright 2005 - 2007 Olivier Delhomme
7 : e-mail : heraia@delhomme.org
8 : URL : http://heraia.tuxfamily.org
9 :
10 : This program is free software; you can redistribute it and/or modify
11 : it under the terms of the GNU General Public License as published by
12 : the Free Software Foundation; either version 2, or (at your option)
13 : any later version.
14 :
15 : This program is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : GNU General Public License for more details.
19 :
20 : You should have received a copy of the GNU General Public License
21 : along with this program; if not, write to the Free Software
22 : Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 : */
24 :
25 : #include "heraia_types.h"
26 :
27 : static gboolean bissextile_year(guint32 year);
28 : static void calc_which_month_day(date_and_time_t *mydate, guint32 day, guint tab_ns_months[12]);
29 : static void which_month_day(date_and_time_t *mydate, guint32 day, gboolean bi);
30 : static guint32 remove_days_from_first_january(guint32 base_year, guint8 base_month, guint8 base_day);
31 : static void which_year_month_day(date_and_time_t *mydate, guint32 days, guint32 base_year, guint base_month, guint8 base_day);
32 : 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);
33 : static void transform_bcd_to_human(gchar *bcd, guint8 part, guint8 part_number);
34 :
35 : /**
36 : * Says whether a year is a leap one or not
37 : */
38 : static gboolean bissextile_year(guint32 year)
39 17 : {
40 :
41 17 : if ((year % 4) == 0)
42 : {
43 3 : if ((year % 100) == 0)
44 : {
45 0 : if ((year % 400) == 0)
46 : {
47 0 : return TRUE;
48 : }
49 : else
50 : {
51 0 : return FALSE;
52 : }
53 : }
54 : else
55 : {
56 3 : return TRUE;
57 : }
58 : }
59 : else
60 : {
61 14 : return FALSE;
62 : }
63 : }
64 :
65 : /**
66 : * Says, from a number of days (eg 154), which month it is (eg may)
67 : * and which day in the corresponding month (eg 2 (leap year) or 3)
68 : */
69 : static void calc_which_month_day(date_and_time_t *mydate, guint32 day, guint tab_ns_months[12])
70 : {
71 3 : gushort i = 0;
72 :
73 36 : while (i<12 && day > tab_ns_months[i])
74 : {
75 33 : i++;
76 : }
77 :
78 3 : mydate->month = i + 1;
79 :
80 3 : if (i == 0)
81 : {
82 0 : mydate->day = 1 + day;
83 : }
84 : else
85 : {
86 3 : mydate->day = (1 + day) - tab_ns_months[i-1];
87 : }
88 : }
89 :
90 : /**
91 : * Front end function for the calc_which_month_day function !
92 : */
93 : static void which_month_day(date_and_time_t *mydate, guint32 day, gboolean bi)
94 : {
95 :
96 3 : if (bi == TRUE)
97 : {
98 0 : if (day <= 366)
99 : {
100 : guint tab_ns_months[12] = { 31, 60, 91, 121, 152, 182,
101 0 : 213, 244, 274, 305, 335, 366 } ;
102 : calc_which_month_day(mydate, day, tab_ns_months);
103 : }
104 : else
105 : {
106 0 : mydate->day = 0;
107 0 : mydate->month = 0;
108 : }
109 : }
110 : else
111 : {
112 3 : if (day <= 365)
113 : {
114 : guint tab_ns_months[12] = { 31, 59, 90, 120, 151, 181,
115 3 : 212, 243, 273, 304, 334, 365 };
116 : calc_which_month_day(mydate, day, tab_ns_months);
117 : }
118 : else
119 : {
120 0 : mydate->day = 0;
121 0 : mydate->month = 0;
122 : }
123 : }
124 : }
125 :
126 : /**
127 : * Returns the number of days since 01/01/base_year
128 : * eg 15/02/base_year --> 31 + 15 = 46
129 : */
130 : static guint32 remove_days_from_first_january(guint32 base_year, guint8 base_month, guint8 base_day)
131 : {
132 : guint tab_ns_months[11];
133 :
134 3 : if (base_day > 0 && base_day < 32)
135 : {
136 3 : base_day -= 1;
137 : }
138 : else
139 : {
140 0 : return 0; /* Obviously something might be wrong if we fall here */
141 : }
142 :
143 3 : tab_ns_months[0] = 31;
144 3 : if (bissextile_year(base_year))
145 : {
146 1 : tab_ns_months[1] = 60;
147 1 : tab_ns_months[2] = 91;
148 1 : tab_ns_months[3] = 121;
149 1 : tab_ns_months[4] = 152;
150 1 : tab_ns_months[5] = 182;
151 1 : tab_ns_months[6] = 213;
152 1 : tab_ns_months[7] = 244;
153 1 : tab_ns_months[8] = 274;
154 1 : tab_ns_months[9] = 305;
155 1 : tab_ns_months[10] = 335;
156 : }
157 : else
158 : {
159 2 : tab_ns_months[1] = 59;
160 2 : tab_ns_months[2] = 90;
161 2 : tab_ns_months[3] = 120;
162 2 : tab_ns_months[4] = 151;
163 2 : tab_ns_months[5] = 181;
164 2 : tab_ns_months[6] = 212;
165 2 : tab_ns_months[7] = 243;
166 2 : tab_ns_months[8] = 273;
167 2 : tab_ns_months[9] = 304;
168 2 : tab_ns_months[10] = 334;
169 : }
170 :
171 3 : if (base_month > 1 && base_month < 13)
172 : {
173 0 : return (tab_ns_months[base_month-2] + base_day);
174 : }
175 3 : else if (base_month == 1)
176 : {
177 3 : return base_day;
178 : }
179 : else
180 : {
181 0 : return 0;
182 : }
183 : }
184 :
185 :
186 :
187 : /**
188 : * About date calculation : Leap years are periods of 4 years except
189 : * the years that we can divide by 100 and not 400.
190 : * So we can distinguish 2 periods : one of 400 years and one of 4 years.
191 : * - we have 100 bissextiles years in a period of 400 years this means that
192 : * every 400 years we have exactly 146100 days.
193 : * - we have 1 bissextile year every 4 years : this means that we have exactly
194 : * 1461 days every 4 years.
195 : * As we can calculate _exactly_ the number of days in a filetime or C_date
196 : * format, we could calculate _exactly_ the number of periods of 400 years and
197 : * then the number of periods of 4 years.
198 : */
199 : static void which_year_month_day (date_and_time_t *mydate, guint32 days, guint32 base_year, guint base_month, guint8 base_day)
200 3 : {
201 3 : guint32 modulus = 0;
202 3 : guint32 reste = 0;
203 3 : guint32 nbdays = 0;
204 :
205 6 : days -= remove_days_from_first_january(base_year, base_month, base_day);
206 :
207 3 : if (days > 146100)
208 : {
209 1 : modulus = days / 146100;
210 1 : mydate->year = modulus * 400;
211 1 : reste = modulus * 3; /* To add centuries in the 400 years modulus */
212 1 : days = days % 146100;
213 : }
214 :
215 3 : modulus = days / 1461;
216 3 : mydate->year += modulus * 4;
217 3 : reste += (modulus*4) / 100; /* To add centuries */
218 3 : reste += days % 1461;
219 :
220 3 : mydate->year += base_year;
221 3 : if (bissextile_year(mydate->year))
222 1 : nbdays = 366;
223 : else
224 2 : nbdays = 365;
225 :
226 11 : while (reste > nbdays)
227 : {
228 8 : reste -= nbdays;
229 8 : mydate->year += 1;
230 8 : if (bissextile_year(mydate->year))
231 1 : nbdays = 366;
232 : else
233 7 : nbdays = 365;
234 : }
235 :
236 3 : which_month_day(mydate, reste, bissextile_year(mydate->year));
237 3 : }
238 :
239 :
240 : /**
241 : * Return a gchar* that contains the date and time
242 : * encoded from the values contained in the date_and_time_t structure
243 : * it may be freed when no longer needed
244 : * We do not use any of the g_date_strftime or strftime function
245 : * because interpreted dates are not always valid !
246 : */
247 : static gchar *date_printf(date_and_time_t *mydate)
248 : {
249 4 : return g_strdup_printf("%02u/%02u/%04u - %02u:%02u:%02u", mydate->day, mydate->month, mydate->year, mydate->hour, mydate->minutes, mydate->seconds);
250 : }
251 :
252 :
253 : /**
254 : * general purpose of this function is to take a 4 byte data stream
255 : * and convert it as if it is a dos date. If it is not, the result
256 : * may be funny !
257 : * data : 4 guchars
258 : * returns a gchar* that may be freed when no longer needed
259 : */
260 : gchar *decode_dos_date(guchar *data, date_and_time_t *mydate)
261 1 : {
262 :
263 1 : if (data == NULL)
264 : {
265 0 : return NULL;
266 : }
267 : else
268 : {
269 1 : mydate->year = (data[3] >> 1) + 1980;
270 1 : mydate->month = ((data[3] & 0x01) << 3) + (data[2] >> 5);
271 1 : mydate->day = data[2] & 0x1F;
272 1 : mydate->hour = (data[1] & 0xF8) >> 3;
273 1 : mydate->minutes = ((data[1] & 0x07) << 3) + ((data[0] & 0xE0) >> 5);
274 1 : mydate->seconds = (data[0] & 0x1F) << 1;
275 :
276 1 : return date_printf(mydate);
277 : }
278 : }
279 :
280 :
281 : /**
282 : * Reads the data from the stream (specified length !! <= 64 bits )
283 : * . date_and_time_t *mydate : the resulting date
284 : * . guchar *data : the stream
285 : * . guint8 len : length of the stream in bytes ( must be <= 64 bits)
286 : * . guint64 nbticks : number of ticks per seconds (1, 1000, ...)
287 : * . guint32 base_year : Epoch year (1970, 1904, ...)
288 : * . guint8 base_month : Epoch month (january, ...)
289 : * . guint8 base_day : Epoch day (01, 15, ...)
290 : * populates the date_and_time_t structure
291 : */
292 : 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)
293 3 : {
294 3 : guint64 total = 0;
295 3 : guint32 days = 0;
296 :
297 3 : memcpy(&total, data, len * sizeof (guchar));
298 :
299 3 : total = (total / nbticks); /* 1 seconds represents nbticks */
300 3 : days = (guint32) (total / 86400); /* 86400 seconds a day */;
301 :
302 3 : which_year_month_day(mydate, days, base_year, base_month, base_day);
303 :
304 3 : mydate->hour = ((total % 86400) / 3600); /* 3600 seconds is one hour out of one day */
305 3 : mydate->minutes = ((total % 3600) / 60); /* 60 seconds is one minute out of one hour */
306 3 : mydate->seconds = (total % 60);
307 3 : }
308 :
309 :
310 : /**
311 : * general purpose of this function is to take a 8 byte data stream
312 : * and convert it as if it is a filetime date. If it is not, the result
313 : * may be funny ! Counting 100th of nanoseconds from 01/01/1601
314 : * data : 8 guchars
315 : * returns a gchar* that may be freed when no longer needed
316 : */
317 : gchar *decode_filetime_date(guchar *data, date_and_time_t *mydate)
318 1 : {
319 1 : if (data == NULL)
320 : {
321 0 : return NULL;
322 : }
323 : else
324 : {
325 1 : make_date_and_time(mydate, data, 8, 10000000, 1601, 1, 1);
326 1 : return date_printf(mydate);
327 : }
328 : }
329 :
330 :
331 : /**
332 : * general purpose of this function is to take a 4 byte data stream
333 : * and convert it as if it is a C date. If it is not, the result may
334 : * be funny ! Counting seconds from 01/01/1970
335 : * data : 4 guchars
336 : * returns a gchar* that may be freed when no longer needed
337 : */
338 : gchar *decode_C_date(guchar *data, date_and_time_t *mydate)
339 1 : {
340 1 : if (data == NULL)
341 : {
342 0 : return NULL;
343 : }
344 : else
345 : {
346 1 : make_date_and_time(mydate, data, 4, 1, 1970, 1, 1);
347 1 : return date_printf(mydate);
348 : }
349 : }
350 :
351 : /**
352 : * general purpose of this function is to take a 4 byte data stream
353 : * and convert it as if it is a HFS date. If it is not, the result may
354 : * be funny ! Counting seconds 01/01/1904
355 : * data : 4 guchars
356 : * returns a gchar* that may be freed when no longer needed
357 : */
358 : gchar *decode_HFS_date(guchar *data, date_and_time_t *mydate)
359 1 : {
360 1 : if (data == NULL)
361 : {
362 0 : return NULL;
363 : }
364 : else
365 : {
366 1 : make_date_and_time(mydate, data, 4, 1, 1904, 1, 1);
367 1 : return date_printf(mydate);
368 : }
369 : }
370 :
371 :
372 :
373 : /**
374 : * decodes the stream represented by *data (one byte) to a
375 : * string containing eight 0 or 1 (Little Endian style)
376 : */
377 : gchar *decode_to_bits(guchar *data)
378 1 : {
379 :
380 1 : if (data == NULL)
381 : {
382 0 : return NULL;
383 : }
384 : else
385 : {
386 1 : return g_strdup_printf("%1u%1u%1u%1u%1u%1u%1u%1u",
387 : (data[0] & 0x80) > 0 ? 1 : 0,
388 : (data[0] & 0x40) > 0 ? 1 : 0,
389 : (data[0] & 0x20) > 0 ? 1 : 0,
390 : (data[0] & 0x10) > 0 ? 1 : 0,
391 : (data[0] & 0x08) > 0 ? 1 : 0,
392 : (data[0] & 0x04) > 0 ? 1 : 0,
393 : (data[0] & 0x02) > 0 ? 1 : 0,
394 : (data[0] & 0x01));
395 : }
396 : }
397 :
398 :
399 : /**
400 : * transcribes the bcd number "part" into a
401 : * gchar * human readable string
402 : * Coding style is from ETSI GSM 04.08 ETS 300557 p387
403 : * TODO : give choice of coding style (eg for numbers >=10)
404 : */
405 : static void transform_bcd_to_human(gchar *bcd, guint8 part, guint8 part_number)
406 2 : {
407 2 : switch (part)
408 : {
409 : case 0 :
410 0 : bcd[part_number] = '0';
411 0 : break;
412 : case 1 :
413 0 : bcd[part_number] = '1';
414 0 : break;
415 : case 2 :
416 1 : bcd[part_number] = '2';
417 1 : break;
418 : case 3 :
419 0 : bcd[part_number] = '3';
420 0 : break;
421 : case 4 :
422 0 : bcd[part_number] = '4';
423 0 : break;
424 : case 5 :
425 0 : bcd[part_number] = '5';
426 0 : break;
427 : case 6 :
428 0 : bcd[part_number] = '6';
429 0 : break;
430 : case 7 :
431 0 : bcd[part_number] = '7';
432 0 : break;
433 : case 8 :
434 0 : bcd[part_number] = '8';
435 0 : break;
436 : case 9 :
437 0 : bcd[part_number] = '9';
438 0 : break;
439 : case 10 :
440 0 : bcd[part_number] = '*';
441 0 : break;
442 : case 11 :
443 0 : bcd[part_number] = '#';
444 0 : break;
445 : case 12 :
446 0 : bcd[part_number] = 'a';
447 0 : break;
448 : case 13 :
449 0 : bcd[part_number] = 'b';
450 0 : break;
451 : case 14 :
452 0 : bcd[part_number] = 'c';
453 0 : break;
454 : case 15 :
455 1 : bcd[part_number] = ' '; /* Endmark */
456 1 : break;
457 : default :
458 0 : bcd[part_number] = '?'; /* This default case should never happen */
459 : break;
460 : }
461 2 : }
462 :
463 :
464 : /**
465 : * Decode one byte as a Packed BCD (Binary Coded Decimal)
466 : * and return a gchar* that me be freed when no longer
467 : * needed
468 : */
469 : gchar *decode_packed_BCD(guchar *data)
470 1 : {
471 1 : guint8 total = 0;
472 1 : gchar *bcd = NULL;
473 :
474 1 : if (data == NULL)
475 : {
476 0 : return NULL;
477 : }
478 : else
479 : {
480 1 : memcpy(&total, data, sizeof(guchar));
481 1 : bcd = (gchar *) g_malloc0(3 * sizeof(gchar));
482 1 : transform_bcd_to_human(bcd, (total & 0x0F), 0);
483 1 : transform_bcd_to_human(bcd, ((total & 0xF0)>>4), 1);
484 1 : bcd[2] = '\0';
485 :
486 1 : return bcd;
487 : }
488 : }
489 :
490 :
491 : /**
492 : * general purpose of this function is to take a 1 byte data stream
493 : * and convert it as if it is an 8 bits signed number
494 : * data : 1 guchar
495 : * returns a gchar* that may be freed when no longer needed
496 : */
497 : gchar *decode_8bits_signed(guchar *data)
498 1 : {
499 1 : gint8 total = 0;
500 :
501 1 : if (data == NULL)
502 : {
503 0 : return NULL;
504 : }
505 : else
506 : {
507 1 : memcpy(&total, data, sizeof (guchar));
508 1 : return g_strdup_printf("%d", total);
509 : }
510 : }
511 :
512 :
513 : /**
514 : * general purpose of this function is to take a 1 byte data stream
515 : * and convert it as if it is an 8 bits unsigned number
516 : * data : 1 guchar
517 : * returns a gchar* that may be freed when no longer needed
518 : */
519 : gchar *decode_8bits_unsigned(guchar *data)
520 1 : {
521 1 : guint8 total = 0;
522 :
523 1 : if (data == NULL)
524 : {
525 0 : return NULL;
526 : }
527 : else
528 : {
529 1 : memcpy(&total, data, sizeof (guchar));
530 1 : return g_strdup_printf("%u", total);
531 : }
532 : }
533 :
534 :
535 : /**
536 : * general purpose of this function is to take a 2 byte data stream
537 : * and convert it as if it is a 16 bits signed number
538 : * data : 2 guchars
539 : * returns a gchar* that may be freed when no longer needed
540 : */
541 : gchar *decode_16bits_signed(guchar *data)
542 1 : {
543 1 : gint16 total = 0;
544 :
545 1 : if (data == NULL)
546 : {
547 0 : return NULL;
548 : }
549 : else
550 : {
551 1 : memcpy(&total, data, 2 * sizeof (guchar));
552 1 : return g_strdup_printf("%d", total);
553 : }
554 : }
555 :
556 :
557 : /**
558 : * general purpose of this function is to take a 2 byte data stream
559 : * and convert it as if it is a 16 bits unsigned number
560 : * data : 2 guchars
561 : * returns a gchar* that may be freed when no longer needed
562 : */
563 : gchar *decode_16bits_unsigned(guchar *data)
564 1 : {
565 1 : guint16 total = 0;
566 :
567 1 : if (data == NULL)
568 : {
569 0 : return NULL;
570 : }
571 : else
572 : {
573 1 : memcpy(&total, data, 2 * sizeof (guchar));
574 1 : return g_strdup_printf("%u", total);
575 : }
576 : }
577 :
578 :
579 : /**
580 : * general purpose of this function is to take a 4 byte data stream
581 : * and convert it as if it is a 32 bits signed number
582 : * data : 4 guchars
583 : * returns a gchar* that may be freed when no longer needed
584 : */
585 : gchar *decode_32bits_signed(guchar *data)
586 1 : {
587 1 : gint32 total = 0;
588 :
589 1 : if (data == NULL)
590 : {
591 0 : return NULL;
592 : }
593 : else
594 : {
595 1 : memcpy(&total, data, 4 * sizeof (guchar));
596 1 : return g_strdup_printf("%d", total);
597 : }
598 : }
599 :
600 :
601 : /**
602 : * general purpose of this function is to take a 4 byte data stream
603 : * and convert it as if it is a 32 bits unsigned number
604 : * data : 4 guchars
605 : * returns a gchar* that may be freed when no longer needed
606 : */
607 : gchar *decode_32bits_unsigned(guchar *data)
608 1 : {
609 1 : guint32 total = 0;
610 :
611 1 : if (data == NULL)
612 : {
613 0 : return NULL;
614 : }
615 : else
616 : {
617 1 : memcpy(&total, data, 4 * sizeof (guchar));
618 1 : return g_strdup_printf("%u", total);
619 : }
620 : }
621 :
622 : /**
623 : * general purpose of this function is to take a 8 byte data stream
624 : * and convert it as if it is a 64 bits signed number
625 : * data : 8 guchars
626 : * returns a gchar* that may be freed when no longer needed
627 : */
628 : gchar *decode_64bits_signed(guchar *data)
629 1 : {
630 1 : gint64 total = 0;
631 :
632 1 : if (data == NULL)
633 : {
634 0 : return NULL;
635 : }
636 : else
637 : {
638 1 : memcpy(&total, data, 8 * sizeof (guchar));
639 1 : return g_strdup_printf("%lld", total);
640 : }
641 : }
642 :
643 :
644 : /**
645 : * general purpose of this function is to take a 8 byte data stream
646 : * and convert it as if it is a 64 bits unsigned number
647 : * data : 8 guchars
648 : * returns a gchar* that may be freed when no longer needed
649 : */
650 : gchar *decode_64bits_unsigned(guchar *data)
651 1 : {
652 1 : guint64 total = 0;
653 :
654 1 : if (data == NULL)
655 : {
656 0 : return NULL;
657 : }
658 : else
659 : {
660 1 : memcpy(&total, data, 8 * sizeof (guchar));
661 1 : return g_strdup_printf("%llu", total);
662 : }
663 : }
664 :
665 :
666 : /**
667 : * Swap bytes from the buffer to_swap
668 : * recursive function !!
669 : * call with first = 0 and last = last byte of buffer to swap
670 : */
671 : gboolean swap_bytes(guchar *to_swap, guint first, guint last)
672 0 : {
673 : guchar aux;
674 :
675 0 : if (first >= last)
676 : {
677 0 : return TRUE;
678 : }
679 : else
680 : {
681 0 : aux = to_swap[first];
682 0 : to_swap[first] = to_swap[last];
683 0 : to_swap[last] = aux;
684 0 : return swap_bytes(to_swap, ++first, --last);
685 : }
686 : }
687 :
688 : /**
689 : * Reverse the byte order LSB -> MSB in MSB -> LSB
690 : * 12345678 in 87654321
691 : */
692 : void reverse_byte_order(guchar *to_reverse)
693 0 : {
694 0 : guint8 car = (guint8) to_reverse[0];
695 0 : guint8 aux = 0;
696 :
697 0 : aux = ((car & 0x80) >> 7);
698 0 : aux += ((car & 0x40) >> 5);
699 0 : aux += ((car & 0x20) >> 3);
700 0 : aux += ((car & 0x10) >> 1);
701 0 : aux += ((car & 0x08) << 1);
702 0 : aux += ((car & 0x04) << 3);
703 0 : aux += ((car & 0x02) << 5);
704 0 : aux += ((car & 0x01) << 7);
705 :
706 0 : to_reverse[0] = (guchar) aux;
707 0 : }
|