| 1064 | } |
| 1065 | |
| 1066 | ULONG Decimal128::makeBcdKey(vary* buf, unsigned char *coeff, int sign, int exp, const int bias, const unsigned pMax) |
| 1067 | { |
| 1068 | // normalize coeff & exponent |
| 1069 | unsigned dig = digits(pMax, coeff, exp); |
| 1070 | |
| 1071 | // exponent bias and sign |
| 1072 | exp += (bias + 1); |
| 1073 | if (!dig) |
| 1074 | exp = 0; |
| 1075 | if (sign) |
| 1076 | exp = -exp; |
| 1077 | exp += 2 * (bias + 1); // make it positive |
| 1078 | fb_assert(exp >= 0 && exp < 64 * 1024); |
| 1079 | |
| 1080 | // encode exp |
| 1081 | char* k = buf->vary_string; |
| 1082 | *k++ = exp >> 8; |
| 1083 | *k++ = exp & 0xff; |
| 1084 | |
| 1085 | // invert negative |
| 1086 | unsigned char* const end = &coeff[dig]; |
| 1087 | if (sign && dig) |
| 1088 | { |
| 1089 | fb_assert(end[-1]); |
| 1090 | --end[-1]; |
| 1091 | |
| 1092 | for (unsigned char* p = coeff; p < end; ++p) |
| 1093 | *p = 9 - *p; |
| 1094 | } |
| 1095 | |
| 1096 | // Some 0's in the end - caller, do not forget to reserve additional space on stack |
| 1097 | end[0] = end[1] = 0; |
| 1098 | |
| 1099 | // Avoid bad data in k in case when coeff is zero |
| 1100 | *k = 0; |
| 1101 | |
| 1102 | // Shifts for moving 10-bit values to bytes buffer |
| 1103 | struct ShiftTable { UCHAR rshift, lshift; }; |
| 1104 | static ShiftTable table[4] = |
| 1105 | { |
| 1106 | { 2, 6 }, |
| 1107 | { 4, 4 }, |
| 1108 | { 6, 2 }, |
| 1109 | { 8, 0 } |
| 1110 | }; |
| 1111 | |
| 1112 | // compress coeff - 3 decimal digits (999) per 10 bits (1023) |
| 1113 | unsigned char* p = coeff; |
| 1114 | for (ShiftTable* t = table; p < end; p += 3) |
| 1115 | { |
| 1116 | USHORT val = p[0] * 100 + p[1] * 10 + p[2]; |
| 1117 | fb_assert(val < 1000); // 1024, 10 bit |
| 1118 | *k |= (val >> t->rshift); |
| 1119 | ++k; |
| 1120 | *k = (val << t->lshift); |
| 1121 | if (!t->lshift) |
| 1122 | { |
| 1123 | ++k; |