1 /* ------------------------------------------------------------------ */
2 /* Packed Decimal conversion module                                   */
3 /* ------------------------------------------------------------------ */
4 /* Copyright (c) IBM Corporation, 2000, 2002.  All rights reserved.   */
5 /*                                                                    */
6 /* This software is made available under the terms of the             */
7 /* ICU License -- ICU 1.8.1 and later.                                */
8 /*                                                                    */
9 /* The description and User's Guide ("The decNumber C Library") for   */
10 /* this software is called decNumber.pdf.  This document is           */
11 /* available, together with arithmetic and format specifications,     */
12 /* testcases, and Web links, at: http://www2.hursley.ibm.com/decimal  */
13 /*                                                                    */
14 /* Please send comments, suggestions, and corrections to the author:  */
15 /*   mfc@uk.ibm.com                                                   */
16 /*   Mike Cowlishaw, IBM Fellow                                       */
17 /*   IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK         */
18 /* ------------------------------------------------------------------ */
19 /* This module comprises the routines for Packed Decimal format       */
20 /* numbers.  Conversions are supplied to and from decNumber, which in */
21 /* turn supports:                                                     */
22 /*   conversions to and from string                                   */
23 /*   arithmetic routines                                              */
24 /*   utilities.                                                       */
25 /* Conversions from decNumber to and from densely packed decimal      */
26 /* formats are provided by the decimal32 through decimal128 modules.  */
27 /* ------------------------------------------------------------------ */
28 
29 #include <string.h>           // for NULL
30 #if defined(_MSVC_)
31 #pragma warning(disable:4244) // [for win64]
32 #endif /*defined(_MSVC_)*/
33 #include "decNumber.h"        // base number library
34 #include "decPacked.h"        // packed decimal
35 #include "decNumberLocal.h"   // decNumber local types, etc.
36 
37 /* ------------------------------------------------------------------ */
38 /* decPackedFromNumber -- convert decNumber to BCD Packed Decimal     */
39 /*                                                                    */
40 /*   bcd    is the BCD bytes                                          */
41 /*   length is the length of the BCD array                            */
42 /*   scale  is the scale result                                       */
43 /*   dn     is the decNumber                                          */
44 /*   returns bcd, or NULL if error                                    */
45 /*                                                                    */
46 /* The number is converted to a BCD packed decimal byte array,        */
47 /* right aligned in the bcd array, whose length is indicated by the   */
48 /* second parameter.  The final 4-bit nibble in the array will be a   */
49 /* sign nibble, C (1100) for + and D (1101) for -.  Unused bytes and  */
50 /* nibbles to the left of the number are set to 0.                    */
51 /*                                                                    */
52 /* scale is set to the scale of the number (this is the exponent,     */
53 /* negated).  To force the number to a specified scale, first use the */
54 /* decNumberRescale routine, which will round and change the exponent */
55 /* as necessary.                                                      */
56 /*                                                                    */
57 /* If there is an error (that is, the decNumber has too many digits   */
58 /* to fit in length bytes, or it is a NaN or Infinity), NULL is       */
59 /* returned and the bcd and scale results are unchanged.  Otherwise   */
60 /* bcd is returned.                                                   */
61 /* ------------------------------------------------------------------ */
decPackedFromNumber(uByte * bcd,Int length,Int * scale,const decNumber * dn)62 uByte * decPackedFromNumber(uByte *bcd, Int length, Int *scale,
63                             const decNumber *dn) {
64   const Unit *up=dn->lsu;     // Unit array pointer
65   uByte obyte, *out;          // current output byte, and where it goes
66   Int indigs=dn->digits;      // digits processed
67   uInt cut=DECDPUN;           // downcounter per Unit
68   uInt u=*up;                 // work
69   uInt nib;                   // ..
70   #if DECDPUN<=4
71   uInt temp;                  // ..
72   #endif
73 
74   if (dn->digits>length*2-1                  // too long ..
75    ||(dn->bits & DECSPECIAL)) return NULL;   // .. or special -- hopeless
76 
77   if (dn->bits&DECNEG) obyte=DECPMINUS;      // set the sign ..
78    else                obyte=DECPPLUS;
79   *scale=-dn->exponent;                      // .. and scale
80 
81   // loop from lowest (rightmost) byte
82   out=bcd+length-1;                          // -> final byte
83   for (; out>=bcd; out--) {
84     if (indigs>0) {
85       if (cut==0) {
86         up++;
87         u=*up;
88         cut=DECDPUN;
89         }
90       #if DECDPUN<=4
91         temp=(u*6554)>>16;         // fast /10
92         nib=u-X10(temp);
93         u=temp;
94       #else
95         nib=u%10;                  // cannot use *6554 trick :-(
96         u=u/10;
97       #endif
98       obyte|=(nib<<4);
99       indigs--;
100       cut--;
101       }
102     *out=obyte;
103     obyte=0;                       // assume 0
104     if (indigs>0) {
105       if (cut==0) {
106         up++;
107         u=*up;
108         cut=DECDPUN;
109         }
110       #if DECDPUN<=4
111         temp=(u*6554)>>16;         // as above
112         obyte=(uByte)(u-X10(temp));
113         u=temp;
114       #else
115         obyte=(uByte)(u%10);
116         u=u/10;
117       #endif
118       indigs--;
119       cut--;
120       }
121     } // loop
122 
123   return bcd;
124   } // decPackedFromNumber
125 
126 /* ------------------------------------------------------------------ */
127 /* decPackedToNumber -- convert BCD Packed Decimal to a decNumber     */
128 /*                                                                    */
129 /*   bcd    is the BCD bytes                                          */
130 /*   length is the length of the BCD array                            */
131 /*   scale  is the scale associated with the BCD integer              */
132 /*   dn     is the decNumber [with space for length*2 digits]         */
133 /*   returns dn, or NULL if error                                     */
134 /*                                                                    */
135 /* The BCD packed decimal byte array, together with an associated     */
136 /* scale, is converted to a decNumber.  The BCD array is assumed full */
137 /* of digits, and must be ended by a 4-bit sign nibble in the least   */
138 /* significant four bits of the final byte.                           */
139 /*                                                                    */
140 /* The scale is used (negated) as the exponent of the decNumber.      */
141 /* Note that zeros may have a sign and/or a scale.                    */
142 /*                                                                    */
143 /* The decNumber structure is assumed to have sufficient space to     */
144 /* hold the converted number (that is, up to length*2-1 digits), so   */
145 /* no error is possible unless the adjusted exponent is out of range, */
146 /* no sign nibble was found, or a sign nibble was found before the    */
147 /* final nibble.  In these error cases, NULL is returned and the      */
148 /* decNumber will be 0.                                               */
149 /* ------------------------------------------------------------------ */
decPackedToNumber(const uByte * bcd,Int length,const Int * scale,decNumber * dn)150 decNumber * decPackedToNumber(const uByte *bcd, Int length,
151                               const Int *scale, decNumber *dn) {
152   const uByte *last=bcd+length-1;  // -> last byte
153   const uByte *first;              // -> first non-zero byte
154   uInt  nib;                       // work nibble
155   Unit  *up=dn->lsu;               // output pointer
156   Int   digits;                    // digits count
157   Int   cut=0;                     // phase of output
158 
159   decNumberZero(dn);               // default result
160   last=&bcd[length-1];
161   nib=*last & 0x0f;                // get the sign
162   if (nib==DECPMINUS || nib==DECPMINUSALT) dn->bits=DECNEG;
163    else if (nib<=9) return NULL;   // not a sign nibble
164 
165   // skip leading zero bytes [final byte is always non-zero, due to sign]
166   for (first=bcd; *first==0;) first++;
167   digits=(last-first)*2+1;              // calculate digits ..
168   if ((*first & 0xf0)==0) digits--;     // adjust for leading zero nibble
169   if (digits!=0) dn->digits=digits;     // count of actual digits [if 0,
170                                         // leave as 1]
171 
172   // check the adjusted exponent; note that scale could be unbounded
173   dn->exponent=-*scale;                 // set the exponent
174   if (*scale>=0) {                      // usual case
175     if ((dn->digits-*scale-1)<-DECNUMMAXE) {      // underflow
176       decNumberZero(dn);
177       return NULL;}
178     }
179    else { // -ve scale; +ve exponent
180     // need to be careful to avoid wrap, here, also BADINT case
181     if ((*scale<-DECNUMMAXE)            // overflow even without digits
182          || ((dn->digits-*scale-1)>DECNUMMAXE)) { // overflow
183       decNumberZero(dn);
184       return NULL;}
185     }
186   if (digits==0) return dn;             // result was zero
187 
188   // copy the digits to the number's units, starting at the lsu
189   // [unrolled]
190   for (;;) {                            // forever
191     // left nibble first
192     nib=(unsigned)(*last & 0xf0)>>4;
193     // got a digit, in nib
194     if (nib>9) {decNumberZero(dn); return NULL;}
195 
196     if (cut==0) *up=(Unit)nib;
197      else *up=(Unit)(*up+nib*powers[cut]);
198     digits--;
199     if (digits==0) break;               // got them all
200     cut++;
201     if (cut==DECDPUN) {
202       up++;
203       cut=0;
204       }
205     last--;                             // ready for next
206     nib=*last & 0x0f;                   // get right nibble
207     if (nib>9) {decNumberZero(dn); return NULL;}
208 
209     // got a digit, in nib
210     if (cut==0) *up=(Unit)nib;
211      else *up=(Unit)(*up+nib*powers[cut]);
212     digits--;
213     if (digits==0) break;               // got them all
214     cut++;
215     if (cut==DECDPUN) {
216       up++;
217       cut=0;
218       }
219     } // forever
220 
221   return dn;
222   } // decPackedToNumber
223 
224