1
2
3
4
5
6
7
8
9
10
11 package com.legstar.coxb.convert.simple;
12
13 import com.legstar.coxb.CobolContext;
14 import com.legstar.coxb.ICobolArrayPackedDecimalBinding;
15 import com.legstar.coxb.ICobolPackedDecimalBinding;
16 import com.legstar.coxb.convert.ICobolPackedDecimalConverter;
17 import com.legstar.coxb.convert.CobolConversionException;
18 import com.legstar.coxb.host.HostData;
19 import com.legstar.coxb.host.HostException;
20
21 import java.math.BigDecimal;
22 import java.util.ArrayList;
23 import java.util.List;
24
25
26
27
28
29
30
31
32 public class CobolPackedDecimalSimpleConverter extends CobolSimpleConverter
33 implements ICobolPackedDecimalConverter {
34
35
36 private static final char[] JAVA_DIGITS = new char[] { '0',
37 '1', '2', '3', '4', '5', '6', '7', '8', '9' };
38
39
40
41
42
43 private static final int MAX_PACKED_CHARS = 128;
44
45
46
47
48 public CobolPackedDecimalSimpleConverter(final CobolContext cobolContext) {
49 super(cobolContext);
50 }
51
52
53 public int toHost(
54 final ICobolPackedDecimalBinding ce,
55 final byte[] hostTarget,
56 final int offset)
57 throws HostException {
58 int newOffset = 0;
59 try {
60 newOffset = toHostSingle(ce.getBigDecimalValue(),
61 ce.getByteLength(),
62 ce.getTotalDigits(),
63 ce.getFractionDigits(),
64 ce.isSigned(),
65 hostTarget,
66 offset);
67 } catch (CobolConversionException e) {
68 throwHostException(ce, e);
69 }
70 return newOffset;
71 }
72
73
74 public int toHost(
75 final ICobolArrayPackedDecimalBinding ce,
76 final byte[] hostTarget,
77 final int offset,
78 final int currentOccurs)
79 throws HostException {
80 int newOffset = offset;
81 try {
82 for (BigDecimal javaSource : ce.getBigDecimalList()) {
83 newOffset = toHostSingle(javaSource,
84 ce.getItemByteLength(),
85 ce.getTotalDigits(),
86 ce.getFractionDigits(),
87 ce.isSigned(),
88 hostTarget,
89 newOffset);
90 }
91
92 for (int i = ce.getBigDecimalList().size(); i < currentOccurs; i++) {
93 newOffset = toHostSingle(BigDecimal.ZERO,
94 ce.getItemByteLength(),
95 ce.getTotalDigits(),
96 ce.getFractionDigits(),
97 ce.isSigned(),
98 hostTarget,
99 newOffset);
100 }
101 } catch (CobolConversionException e) {
102 throwHostException(ce, e);
103 }
104 return newOffset;
105 }
106
107
108 public int fromHost(
109 final ICobolPackedDecimalBinding ce,
110 final byte[] hostSource,
111 final int offset)
112 throws HostException {
113 int newOffset = offset;
114 try {
115 BigDecimal javaDecimal = fromHostSingle(ce.getByteLength(),
116 ce.getTotalDigits(),
117 ce.getFractionDigits(),
118 hostSource,
119 newOffset);
120 ce.setBigDecimalValue(javaDecimal);
121 newOffset += ce.getByteLength();
122 } catch (CobolConversionException e) {
123 throwHostException(ce, e);
124 }
125 return newOffset;
126 }
127
128
129 public int fromHost(
130 final ICobolArrayPackedDecimalBinding ce,
131 final byte[] hostSource,
132 final int offset,
133 final int currentOccurs)
134 throws HostException {
135 List < BigDecimal > lArray = new ArrayList < BigDecimal >();
136 int newOffset = offset;
137 try {
138 for (int i = 0; i < currentOccurs; i++) {
139 BigDecimal javaDecimal = fromHostSingle(ce.getItemByteLength(),
140 ce.getTotalDigits(),
141 ce.getFractionDigits(),
142 hostSource,
143 newOffset);
144 lArray.add(javaDecimal);
145 newOffset += ce.getItemByteLength();
146 }
147 ce.setBigDecimalList(lArray);
148 } catch (CobolConversionException e) {
149 throwHostException(ce, e);
150 }
151 return newOffset;
152 }
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167 public static final int toHostSingle(
168 final BigDecimal javaDecimal,
169 final int cobolByteLength,
170 final int totalDigits,
171 final int fractionDigits,
172 final boolean isSigned,
173 final byte[] hostTarget,
174 final int offset)
175 throws CobolConversionException {
176
177
178 int lastOffset = offset + cobolByteLength;
179 if (lastOffset > hostTarget.length) {
180 throw (new CobolConversionException(
181 "Attempt to write past end of host source buffer",
182 new HostData(hostTarget), offset, cobolByteLength));
183 }
184
185
186 BigDecimal localDecimal = javaDecimal;
187 if (localDecimal == null) {
188 localDecimal = BigDecimal.ZERO;
189 }
190
191
192 String sDecimal = localDecimal.toString();
193
194
195
196
197
198 if (localDecimal.scale() != fractionDigits) {
199 sDecimal = localDecimal.setScale(
200 fractionDigits, BigDecimal.ROUND_DOWN).toString();
201 }
202
203
204 int javaDigits = 0;
205 for (int i = 0; i < sDecimal.length(); i++) {
206 if (Character.isDigit(sDecimal.charAt(i))) {
207 javaDigits++;
208 }
209 }
210
211 if (javaDigits > totalDigits) {
212 throw (new CobolConversionException(
213 "BigDecimal value too large for target Cobol field",
214 new HostData(hostTarget), offset, cobolByteLength));
215 }
216
217
218
219
220
221 int pad = totalDigits - javaDigits;
222
223
224
225
226
227
228
229 int iTarget = offset;
230 boolean flip = false;
231
232
233
234 int bByte = 0;
235
236
237
238
239
240
241
242
243 if (totalDigits % 2 == 0) {
244 flip = true;
245 }
246
247
248 for (int i = 0; i < pad; i++) {
249 if (flip) {
250 hostTarget[iTarget] = (byte) 0x00;
251 iTarget++;
252 flip = false;
253 } else {
254 flip = true;
255 }
256 }
257
258
259
260
261
262 for (int i = 0; i < sDecimal.length(); i++) {
263 char sC = sDecimal.charAt(i);
264 if (Character.isDigit(sC)) {
265 int digit = Character.digit(sC, 10);
266 if (flip) {
267 bByte += digit;
268 hostTarget[iTarget] = (byte) bByte;
269 iTarget++;
270 flip = false;
271 } else {
272 bByte = digit * 16;
273 flip = true;
274 }
275 }
276 }
277
278
279
280
281
282 if (!isSigned) {
283 bByte += 0x0F;
284 } else {
285 if (localDecimal.signum() == -1) {
286 bByte += 0x0D;
287 } else {
288 bByte += 0x0C;
289 }
290 }
291 hostTarget[iTarget] = (byte) bByte;
292 iTarget++;
293
294 return iTarget;
295 }
296
297
298
299
300
301
302
303
304
305
306
307
308 public static final BigDecimal fromHostSingle(
309 final int cobolByteLength,
310 final int totalDigits,
311 final int fractionDigits,
312 final byte[] hostSource,
313 final int offset)
314 throws CobolConversionException {
315
316
317
318
319
320 char[] sDecimal = new char[MAX_PACKED_CHARS];
321
322 int lastOffset = offset + cobolByteLength;
323 int pos = 0;
324
325
326
327
328
329
330
331
332 if (lastOffset > hostSource.length) {
333 return new BigDecimal(0).setScale(fractionDigits);
334 }
335 if (lastOffset < 1) {
336 throw (new CobolConversionException(
337 "Invalid host byte length",
338 new HostData(hostSource), offset, cobolByteLength));
339 }
340
341
342 int s = (hostSource[lastOffset - 1] & 0x0F);
343 if (s == 0x0d) {
344 sDecimal[pos++] = '-';
345 } else {
346 if (s != 0x0c && s != 0x0f) {
347 throw (new CobolConversionException(
348 "Host data last byte is not a valid packed decimal byte",
349 new HostData(hostSource), offset, cobolByteLength));
350 }
351 }
352
353
354 int integerPart = 0;
355 int[] d = new int[2];
356 for (int i = offset; i < lastOffset; i++) {
357
358 d[0] = (hostSource[i] & 0xF0) >>> 4;
359 d[1] = hostSource[i] & 0x0F;
360
361 for (int j = 0; j < 2; j++) {
362
363
364
365
366
367
368
369 if ((j == 0 && (i != offset || (totalDigits % 2 != 0)))
370 || (j == 1 && i != (lastOffset - 1))) {
371
372
373 if (integerPart == (totalDigits - fractionDigits)) {
374 sDecimal[pos++] = '.';
375 }
376
377
378 if (d[j] >= JAVA_DIGITS.length) {
379 throw (new CobolConversionException(
380 "Host data contains a byte that is not a valid packed decimal byte",
381 new HostData(hostSource), offset,
382 cobolByteLength));
383 }
384
385 sDecimal[pos++] = JAVA_DIGITS[d[j]];
386 integerPart++;
387 }
388
389 }
390 }
391
392 return new BigDecimal(sDecimal, 0, pos);
393 }
394
395 }