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