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