Coverage Report

Created: 2026-09-20 07:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mdbtools/src/libmdb/money.c
Line
Count
Source
1
/* MDB Tools - A library for reading MS Access database file
2
 * Copyright (C) 1998-1999  Brian Bruns
3
 *
4
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Library General Public
6
 * License as published by the Free Software Foundation; either
7
 * version 2 of the License, or (at your option) any later version.
8
 *
9
 * This library is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Library General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Library General Public
15
 * License along with this library; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17
 */
18
19
#include <stdio.h>
20
#include "mdbtools.h"
21
22
#define MAX_MONEY_PRECISION   20
23
#define MAX_NUMERIC_PRECISION 40
24
/* 
25
** these routines are copied from the freetds project which does something
26
** very similiar
27
*/
28
29
static int multiply_byte(unsigned char *product, int num, unsigned char *multiplier, size_t len);
30
static int do_carry(unsigned char *product, size_t len);
31
static char *array_to_string(unsigned char *array, size_t len, int unsigned scale, int neg);
32
33
/**
34
 * mdb_money_to_string
35
 * @mdb: Handle to open MDB database file
36
 * @start: Offset of the field within the current page
37
 *
38
 * Returns: the allocated string that has received the value.
39
 */
40
char *mdb_money_to_string(MdbHandle *mdb, int start)
41
188
{
42
188
  const int num_bytes=8, scale=4;
43
188
  int i;
44
188
  int neg=0;
45
188
  unsigned char multiplier[MAX_MONEY_PRECISION] = { 1 };
46
188
  unsigned char temp[MAX_MONEY_PRECISION];
47
188
  unsigned char product[MAX_MONEY_PRECISION] = { 0 };
48
188
  unsigned char bytes[num_bytes];
49
50
188
  memcpy(bytes, mdb->pg_buf + start, num_bytes);
51
52
  /* Perform two's complement for negative numbers */
53
188
  if (bytes[num_bytes-1] & 0x80) {
54
50
    neg = 1;
55
450
    for (i=0;i<num_bytes;i++) {
56
400
                       bytes[i] = ~bytes[i];
57
400
    }
58
69
    for (i=0; i<num_bytes; i++) {
59
69
                       bytes[i] ++;
60
69
                       if (bytes[i]!=0) break;
61
69
    }
62
50
  }
63
64
1.69k
  for (i=0;i<num_bytes;i++) {
65
    /* product += multiplier * current byte */
66
1.50k
               multiply_byte(product, bytes[i], multiplier, sizeof(multiplier));
67
68
    /* multiplier = multiplier * 256 */
69
1.50k
               memcpy(temp, multiplier, sizeof(multiplier));
70
1.50k
               memset(multiplier, 0, sizeof(multiplier));
71
1.50k
    multiply_byte(multiplier, 256, temp, sizeof(multiplier));
72
1.50k
  }
73
188
       return array_to_string(product, sizeof(product), scale, neg);
74
75
188
}
76
77
467
char *mdb_numeric_to_string(MdbHandle *mdb, int start, int scale, int prec) {
78
467
       const int num_bytes = 16;
79
467
       int i;
80
467
       int neg=0;
81
467
       unsigned char multiplier[MAX_NUMERIC_PRECISION] = { 1 };
82
467
       unsigned char temp[MAX_NUMERIC_PRECISION];
83
467
       unsigned char product[MAX_NUMERIC_PRECISION] = { 0 };
84
467
       unsigned char bytes[num_bytes];
85
86
467
       memcpy(bytes, mdb->pg_buf + start + 1, num_bytes);
87
88
       /* Negative bit is stored in first byte */
89
467
       if (mdb->pg_buf[start] & 0x80) neg = 1;
90
7.93k
       for (i=0;i<num_bytes;i++) {
91
               /* product += multiplier * current byte */
92
7.47k
               multiply_byte(product, bytes[12-4*(i/4)+i%4], multiplier, sizeof(multiplier));
93
94
               /* multiplier = multiplier * 256 */
95
7.47k
               memcpy(temp, multiplier, sizeof(multiplier));
96
7.47k
               memset(multiplier, 0, sizeof(multiplier));
97
7.47k
               multiply_byte(multiplier, 256, temp, sizeof(multiplier));
98
7.47k
       }
99
467
       return array_to_string(product, sizeof(product), prec, neg);
100
467
}
101
102
static int multiply_byte(unsigned char *product, int num, unsigned char *multiplier, size_t len)
103
17.9k
{
104
17.9k
  unsigned char number[3] = { num % 10, (num/10) % 10, (num/100) % 10 };
105
17.9k
  unsigned int i, j;
106
107
675k
  for (i=0;i<len;i++) {
108
657k
    if (multiplier[i] == 0) continue;
109
1.11M
    for (j=0;j<3 && i+j<len;j++) {
110
836k
      if (number[j] == 0) continue;
111
633k
      product[i+j] += multiplier[i]*number[j];
112
633k
    }
113
278k
    do_carry(product, len);
114
278k
  }
115
17.9k
  return 0;
116
17.9k
}
117
static int do_carry(unsigned char *product, size_t len)
118
278k
{
119
278k
  unsigned int j;
120
121
10.6M
       for (j=0;j<len-1;j++) {
122
10.3M
    if (product[j]>9) {
123
565k
      product[j+1]+=product[j]/10;
124
565k
      product[j]%=10;
125
565k
    }
126
10.3M
  }
127
278k
  if (product[j]>9) {
128
0
    product[j]%=10;
129
0
  }
130
278k
  return 0;
131
278k
}
132
static char *array_to_string(unsigned char *array, size_t len, unsigned int scale, int neg)
133
655
{
134
655
  char *s;
135
655
  unsigned int top, i, j=0;
136
  
137
1.33k
       for (top=len;(top>0) && (top-1>scale) && !array[top-1];top--);
138
139
       /* allocate enough space for all digits + minus sign + decimal point + trailing NULL byte */
140
655
       s = g_malloc(len+3);
141
142
655
  if (neg)
143
122
    s[j++] = '-';
144
145
655
  if (top == 0) {
146
0
    s[j++] = '0';
147
655
  } else {
148
22.4k
    for (i=top; i>0; i--) {
149
21.7k
      if (i == scale) s[j++]='.';
150
21.7k
      s[j++]=array[i-1]+'0';
151
21.7k
    }
152
655
  }
153
655
  s[j]='\0';
154
155
655
  return s;
156
655
}