PageRenderTime 66ms CodeModel.GetById 35ms RepoModel.GetById 0ms app.codeStats 1ms

/ojc-core/encodersl/encoder-coco/src/com/sun/encoder/coco/runtime/CobolDataConverter.java

https://bitbucket.org/openesb/openesb-components
Java | 2554 lines | 1486 code | 242 blank | 826 comment | 291 complexity | 36f5586553d4da33ef0a550252a543bd MD5 | raw file
Possible License(s): AGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * BEGIN_HEADER - DO NOT EDIT
  3. *
  4. * The contents of this file are subject to the terms
  5. * of the Common Development and Distribution License
  6. * (the "License"). You may not use this file except
  7. * in compliance with the License.
  8. *
  9. * You can obtain a copy of the license at
  10. * https://open-jbi-components.dev.java.net/public/CDDLv1.0.html.
  11. * See the License for the specific language governing
  12. * permissions and limitations under the License.
  13. *
  14. * When distributing Covered Code, include this CDDL
  15. * HEADER in each file and include the License file at
  16. * https://open-jbi-components.dev.java.net/public/CDDLv1.0.html.
  17. * If applicable add the following below this CDDL HEADER,
  18. * with the fields enclosed by brackets "[]" replaced with
  19. * your own identifying information: Portions Copyright
  20. * [year] [name of copyright owner]
  21. */
  22. /*
  23. * @(#)CobolDataConverter.java
  24. *
  25. * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
  26. *
  27. * END_HEADER - DO NOT EDIT
  28. */
  29. package com.sun.encoder.coco.runtime;
  30. import java.io.ByteArrayOutputStream;
  31. import java.io.IOException;
  32. import java.io.InputStream;
  33. import java.io.InputStreamReader;
  34. import java.io.OutputStream;
  35. import java.io.OutputStreamWriter;
  36. import java.io.UnsupportedEncodingException;
  37. import java.math.BigDecimal;
  38. import java.math.BigInteger;
  39. import java.nio.ByteBuffer;
  40. import java.nio.CharBuffer;
  41. import java.nio.charset.CharacterCodingException;
  42. import java.nio.charset.Charset;
  43. import java.util.Arrays;
  44. import java.util.Collections;
  45. import java.util.HashMap;
  46. import java.util.Map;
  47. import com.sun.encoder.coco.runtime.messages.ErrorManager;
  48. import com.sun.encoder.coco.runtime.messages.Message;
  49. import com.sun.encoder.coco.runtime.messages.MessageCatalog;
  50. /**
  51. * Principal class for converting between Copybook data and Java data
  52. * reprseentations.
  53. *
  54. * @author Noel Ang
  55. * @version $Revision: 1.4 $
  56. */
  57. public class CobolDataConverter {
  58. private static final int MAX_EXFLOAT_EXPONENT = 99;
  59. private static final byte LIT_BYTE = (byte) 0xFF;
  60. private static final byte ZONE_NYBBLE_SIGN_BYTEMASK = (byte) 0xF0;
  61. private static final byte ZONE_NYBBLE_VALUE_BYTEMASK = (byte) 0x0F;
  62. private static final byte PACKED_NYBBLE_SIGN_BYTEMASK = (byte) 0x0F;
  63. private static final byte POSITIVE_ZONE_SIGN = (byte) 0xC0;
  64. private static final byte NEGATIVE_ZONE_SIGN = (byte) 0xD0;
  65. private static final byte UNSIGNED_ZONE_SIGN = (byte) 0xF0;
  66. private static final byte POSITIVE_PACK_SIGN = 0x0C;
  67. private static final byte NEGATIVE_PACK_SIGN = 0x0D;
  68. private static final byte UNSIGNED_PACK_SIGN = 0x0F;
  69. private static final byte[] DBCSSPACE = {0x40, 0x40};
  70. private static final char[] SPACE = {' '};
  71. private static final char[] PLUS = {'+'};
  72. private static final char[] MINUS = {'-'};
  73. private static final Map<String, byte[]> mSpaceEncodings =
  74. Collections.synchronizedMap(new HashMap<String, byte[]>());
  75. private static final Map<String, byte[]> mPlusEncodings =
  76. Collections.synchronizedMap(new HashMap<String, byte[]>());
  77. private static final Map<String, byte[]> mMinusEncodings =
  78. Collections.synchronizedMap(new HashMap<String, byte[]>());
  79. private static final ErrorManager cErrorMgr =
  80. ErrorManager.getManager("OpenESB.encoder.COBOLCopybook." + CobolDataConverter.class.getName());
  81. private CobolDataConverter() {
  82. }
  83. /**
  84. * Write a value as a Cobol display usage item. Use for alphabetic,
  85. * alphanumeric, alphanumeric-edited, and numeric-edited items. If the
  86. * value's size is less than the item size, it is padded with trailing space
  87. * characters.
  88. *
  89. * @param outStream Outlet for data
  90. * @param data The value to write
  91. * @param spec Characteristics of the item;
  92. * see {@link CobolCharacteristics#toString()}
  93. * @param enc Encoding to use for the output
  94. *
  95. * @throws IOException if an I/O error occurs in writing the value,
  96. * or if the supplied writer does not use the
  97. * required character encoding
  98. */
  99. public static void encodeToDisplay(OutputStream outStream,
  100. String data,
  101. CobolCharacteristics specs,
  102. String enc)
  103. throws IOException {
  104. final int size;
  105. OutputStreamWriter writer = new OutputStreamWriter(outStream, enc);
  106. size = specs.getSize();
  107. if (data.length() > size) {
  108. Message msg = MessageCatalog.getMessage("CCCR3002");
  109. cErrorMgr.log(ErrorManager.Severity.WARN,
  110. null,
  111. msg.formatText(new Object[]{data, String.valueOf(size)}));
  112. data = data.substring(0, size);
  113. }
  114. writer.write(data);
  115. writer.flush();
  116. for (int i = 0, pad = size - data.length(); i < pad; i++) {
  117. writer.write(' ');
  118. }
  119. }
  120. /**
  121. * Write a value as an external floating point (display usage) item.
  122. *
  123. * @param outStream Outlet for data
  124. * @param data Value to write
  125. * @param picture Cobol picture string associated with the item
  126. * @param spec Characteristics of the item;
  127. * see {@link CobolCharacteristics#toString()}
  128. * @param enc Encoding to use for the output
  129. *
  130. * @throws IOException if an I/O error occurs in writing the value,
  131. * or if the supplied writer does not use the
  132. * required character encoding
  133. * @throws ArithmeticException if the data exponent is too large
  134. */
  135. public static void encodeToExternalFloat(OutputStream outStream,
  136. BigDecimal data,
  137. String picture,
  138. CobolCharacteristics specs,
  139. String enc)
  140. throws IOException {
  141. final StringBuffer value = new StringBuffer(data.unscaledValue().toString());
  142. final int scalePic = specs.getDecimalPosition();
  143. int scale = data.scale();
  144. int exponent = 0 - scale;
  145. int digitsPic = 0;
  146. int digits = value.length();
  147. OutputStreamWriter writer = new OutputStreamWriter(outStream, enc);
  148. /* calc picture's digit requirements */
  149. digitsPic = 0;
  150. for (int i = 0;
  151. i < picture.length() && picture.charAt(i) != 'E'; i++) {
  152. if (picture.charAt(i) == '9') {
  153. digitsPic++;
  154. }
  155. }
  156. /* remove sign from value */
  157. if (data.signum() == -1) {
  158. value.delete(0, 1);
  159. digits--;
  160. }
  161. // truncate if needed
  162. if (digitsPic < digits) {
  163. int snip = digits - digitsPic;
  164. value.delete(digits - snip, digits);
  165. scale = Math.max(0, scale - snip);
  166. exponent += snip;
  167. digits = value.length();
  168. }
  169. // pad if needed
  170. if (digits < digitsPic) {
  171. int snip = digitsPic - digits;
  172. for (int i = 0; i < snip; i++) {
  173. value.append('0');
  174. }
  175. scale += (scale > 0 ? snip : 0);
  176. exponent -= snip;
  177. digits = value.length();
  178. }
  179. // reconcile data and picture scales;
  180. // compensate for their decimal positions' misalignment
  181. exponent = scalePic + exponent;
  182. // adjust exponent now that all padding, truncation, and
  183. // decimal point insertion are completed
  184. int dotLoc = picture.indexOf('.');
  185. boolean haveExplicitDecimal = (dotLoc != -1);
  186. // picture offset - 1 == value offset
  187. if (haveExplicitDecimal) {
  188. value.insert(dotLoc - 1, '.');
  189. }
  190. // exponent range check
  191. if (Math.abs(exponent) > MAX_EXFLOAT_EXPONENT) {
  192. Message msg = MessageCatalog.getMessage("CCCR4009");
  193. String err = msg.formatText(new Object[]{
  194. String.valueOf(exponent)
  195. });
  196. cErrorMgr.log(ErrorManager.Severity.ERROR, null, err);
  197. throw new ArithmeticException(err);
  198. }
  199. // write sign
  200. boolean negValue = (data.signum() == -1);
  201. boolean needSignificandSign = !Character.isDigit(picture.charAt(0));
  202. boolean explicitSignificandSign = needSignificandSign && picture.charAt(0) == '+';
  203. if (needSignificandSign) {
  204. if (negValue && new BigDecimal(
  205. value.toString()).unscaledValue().intValue() != 0) {
  206. writer.write('-');
  207. } else if (explicitSignificandSign) {
  208. writer.write('+');
  209. }
  210. }
  211. // write significand and exponent
  212. boolean explicitExponentSign = picture.charAt(picture.indexOf('E') + 1) == '+';
  213. writer.write(value.toString() + 'E');
  214. if (exponent < 0) {
  215. writer.write('-');
  216. } else if (explicitExponentSign) {
  217. writer.write('+');
  218. }
  219. exponent = Math.abs(exponent);
  220. if (exponent < 10) {
  221. writer.write('0');
  222. }
  223. writer.write(Integer.toString(exponent));
  224. writer.flush();
  225. }
  226. /**
  227. * Write a value as a Cobol COMP-1 usage, floating point item.
  228. *
  229. * @param stream Outlet for data
  230. * @param val The value to write
  231. *
  232. * @throws IOException if an I/O error occurs in writing the value
  233. */
  234. public static void encodeToFloat(OutputStream stream,
  235. float val)
  236. throws IOException {
  237. int value = Float.floatToIntBits(val);
  238. byte[] bytes = new byte[]{
  239. (byte) ((value & 0xFF000000) >> 24),
  240. (byte) ((value & 0x00FF0000) >> 16),
  241. (byte) ((value & 0x0000FF00) >> 8),
  242. (byte) (value & 0x000000FF)
  243. };
  244. stream.write(bytes, 0, bytes.length);
  245. stream.flush();
  246. }
  247. /**
  248. * Write a value as a Cobol COMP-2 usage, floating point item.
  249. *
  250. * @param stream Outlet for data
  251. * @param val The value to write
  252. *
  253. * @throws IOException if an I/O error occurs in writing the value
  254. */
  255. public static void encodeToDouble(OutputStream stream,
  256. double val)
  257. throws IOException {
  258. long value = Double.doubleToLongBits(val);
  259. byte[] bytes = new byte[]{
  260. (byte) ((value & 0xFF00000000000000L) >> 56),
  261. (byte) ((value & 0x00FF000000000000L) >> 48),
  262. (byte) ((value & 0x0000FF0000000000L) >> 40),
  263. (byte) ((value & 0x000000FF00000000L) >> 32),
  264. (byte) ((value & 0x00000000FF000000L) >> 24),
  265. (byte) ((value & 0x0000000000FF0000L) >> 16),
  266. (byte) ((value & 0x000000000000FF00L) >> 8),
  267. (byte) (value & 0x00000000000000FFL)
  268. };
  269. stream.write(bytes, 0, bytes.length);
  270. stream.flush();
  271. }
  272. /**
  273. * Write a value as a Cobol display usage, zoned item. Use for external
  274. * decimal (zoned) items.
  275. *
  276. * @param stream Outlet for data
  277. * @param data The value to write
  278. * @param picture Cobol item picture for the value
  279. * @param spec Characteristics of the item;
  280. * see {@link CobolCharacteristics#toString()}
  281. * @param enc Encoding to use for the output
  282. *
  283. * @throws IOException if an I/O error occurs in writing the value
  284. */
  285. public static void encodeToZoned(OutputStream stream,
  286. BigDecimal data,
  287. String picture,
  288. CobolCharacteristics specs,
  289. String enc)
  290. throws IOException {
  291. final StringBuffer value = new StringBuffer(data.unscaledValue().toString());
  292. final boolean needSign = specs.isSigned();
  293. final boolean separateSign = specs.isSignSeparate();
  294. final boolean leadingSign = specs.isSignLeading();
  295. final int scalePic = specs.getDecimalPosition();
  296. final int scalingPositions = specs.getDecimalScalingPositions();
  297. int digitsPic;
  298. byte signByte = 0;
  299. int scale;
  300. // Count number of digits in the picture
  301. digitsPic = 0;
  302. for (int i = 0, len = picture.length(); i < len; i++) {
  303. if (picture.charAt(i) == '9') {
  304. digitsPic += 1;
  305. }
  306. }
  307. // Scale value to its picture
  308. scale = data.scale();
  309. scale =
  310. fitToNumericPicture(value,
  311. scale,
  312. digitsPic,
  313. scalePic,
  314. scalingPositions);
  315. // Remove negative sign for convenience
  316. if (data.signum() == -1) {
  317. value.delete(0, 1);
  318. }
  319. // Add sign
  320. if (needSign) {
  321. // Two ways to add it:
  322. // Prepend/append if separate sign requested,
  323. if (separateSign) {
  324. if (leadingSign) {
  325. switch (data.signum()) {
  326. case -1:
  327. value.insert(0, '-');
  328. break;
  329. case 0:
  330. value.insert(0, '+');
  331. break;
  332. case 1:
  333. value.insert(0, '+');
  334. break;
  335. default:
  336. }
  337. } else {
  338. switch (data.signum()) {
  339. case -1:
  340. value.append('-');
  341. break;
  342. case 0:
  343. value.append('+');
  344. break;
  345. case 1:
  346. value.append('+');
  347. break;
  348. default:
  349. }
  350. }
  351. } // Or add it to first/last digit's fist nybble if non-separate sign
  352. else {
  353. // for a non-separate, leading sign, embed it into the
  354. // first nybble of the first digit
  355. if (leadingSign) {
  356. signByte = (byte) Character.digit(value.charAt(0), 10);
  357. value.delete(0, 1);
  358. } // for a non-separate, trailing sign, embed it into the
  359. // first nybble of the last digit
  360. else {
  361. int last = value.length() - 1;
  362. signByte =
  363. (byte) Character.digit(value.charAt(last), 10);
  364. value.delete(last, last + 1);
  365. }
  366. switch (data.signum()) {
  367. case -1:
  368. signByte |= NEGATIVE_ZONE_SIGN;
  369. break;
  370. case 0:
  371. signByte |= POSITIVE_ZONE_SIGN;
  372. break;
  373. case 1:
  374. signByte |= POSITIVE_ZONE_SIGN;
  375. break;
  376. default:
  377. }
  378. }
  379. }
  380. // Write the data out
  381. if (needSign && !separateSign && leadingSign) {
  382. stream.write((int) signByte);
  383. stream.flush();
  384. }
  385. OutputStreamWriter writer = new OutputStreamWriter(stream, enc);
  386. writer.write(value.toString());
  387. writer.flush();
  388. if (needSign && !separateSign && !leadingSign) {
  389. stream.write((int) signByte);
  390. stream.flush();
  391. }
  392. }
  393. /**
  394. * Write a value as a Cobol display usage, zoned item. Use for internal
  395. * decimal (zoned) items. If the value's size is less than the item's size,
  396. * the item is padded with leading zeroes.
  397. *
  398. * @param stream Outlet for data
  399. * @param data The value to write
  400. * @param picture Cobol item picture
  401. * @param spec Characteristics of the item;
  402. * see {@link CobolCharacteristics#toString()}
  403. * @param enc Encoding to use for the output
  404. *
  405. * @throws IOException if an I/O error occurs in writing the value
  406. */
  407. public static void encodeToZoned(OutputStream stream,
  408. long data,
  409. String picture,
  410. CobolCharacteristics specs,
  411. String enc)
  412. throws IOException {
  413. // Legacy behaviour: when setting zoned values
  414. // (which may have scale > 0) using long or int (which cannot store
  415. // information about scale > 0), treat the input not as an integral,
  416. // but as floating point value. This means applying scale info
  417. // of the item to the input after it is converted to a BigDecimal.
  418. //
  419. // A proposal to clean up this mess by removing int- and long-based
  420. // getters and setters for zoned items has been rejected on grounds of
  421. // backward compatibility.
  422. BigDecimal decimal;
  423. decimal = new BigDecimal(Long.toString(data));
  424. decimal.movePointLeft(specs.getDecimalPosition());
  425. encodeToZoned(stream, decimal, picture, specs, enc);
  426. }
  427. /**
  428. * Write a value as a Cobol display usage, zoned item. Use for internal
  429. * decimal (zoned) items. If the value's size is less than the item's size,
  430. * the item is padded with leading zeroes.
  431. *
  432. * @param stream Outlet for data
  433. * @param data The value to write
  434. * @param picture Cobol item picture
  435. * @param spec Characteristics of the item;
  436. * see {@link CobolCharacteristics#toString()}
  437. * @param enc Encoding to use for the output
  438. *
  439. * @throws IOException if an I/O error occurs in writing the value
  440. */
  441. public static void encodeToZoned(OutputStream stream,
  442. int data,
  443. String picture,
  444. CobolCharacteristics specs,
  445. String enc)
  446. throws IOException {
  447. // Legacy behaviour: when setting zoned values
  448. // (which may have scale > 0) using long or int (which cannot store
  449. // information about scale > 0), treat the input not as an integral,
  450. // but as floating point value. This means applying scale info
  451. // of the item to the input after it is converted to a BigDecimal.
  452. //
  453. // A proposal to clean up this mess by removing int- and long-based
  454. // getters and setters for zoned items has been rejected on grounds of
  455. // backward compatibility.
  456. BigDecimal decimal;
  457. decimal = new BigDecimal(Integer.toString(data));
  458. decimal.movePointLeft(specs.getDecimalPosition());
  459. encodeToZoned(stream, decimal, picture, specs, enc);
  460. }
  461. /**
  462. * Write a value as a Cobol display-1 usage item. Use for DBCS items. If the
  463. * value's size is less than the item size, the item is padded with trailing
  464. * spaces.
  465. *
  466. * @param stream Outlet for data
  467. * @param data The value to write
  468. * @param size Item size
  469. *
  470. * @throws IllegalArgumentException if the data size exceeds the item size,
  471. * or the number of bytes in the data is
  472. * not a multiple of 2.
  473. * @throws IOException if an I/O error occurs in writing the
  474. * value
  475. */
  476. public static void encodeToDbcs(OutputStream stream,
  477. byte[] data,
  478. int size)
  479. throws IOException {
  480. int length = data.length;
  481. if ((length % 2) != 0) {
  482. Message msg = MessageCatalog.getMessage("CCCR4010");
  483. String err = msg.formatText(new Object[]{
  484. String.valueOf(length)
  485. });
  486. cErrorMgr.log(ErrorManager.Severity.ERROR,
  487. null,
  488. err);
  489. throw new IllegalArgumentException(err);
  490. }
  491. if (length > size) {
  492. Message msg = MessageCatalog.getMessage("CCCR3003");
  493. cErrorMgr.log(ErrorManager.Severity.WARN,
  494. null,
  495. msg.formatText(new Object[]{
  496. String.valueOf(length),
  497. String.valueOf(size)
  498. }));
  499. byte[] copy = new byte[size];
  500. System.arraycopy(data, 0, copy, 0, size);
  501. data = copy;
  502. }
  503. stream.write(data);
  504. for (int i = 0, pad = (size - length) / DBCSSPACE.length;
  505. i < pad; i++) {
  506. stream.write(DBCSSPACE, 0, DBCSSPACE.length);
  507. }
  508. stream.flush();
  509. }
  510. /**
  511. * Write a value as a Cobol 2-, 4- or 8-byte binary (usage BINARY/COMP)
  512. * item. The binary item width used depends on the number of digits in the
  513. * picture, as specified in IBM Cobol Reference:
  514. * <p/>
  515. * <pre>
  516. * 1-4 digits: 2 bytes
  517. * 5-9 digits: 4 bytes
  518. * 10-18 digits: 8 bytes
  519. * </pre>
  520. * <p/>
  521. * However, note that the width computation <em>is not derived from the
  522. * supplied picture</em>, it is taken from the pre-computed value encoded in
  523. * the characteristics bit vector <code>parms</code>.
  524. *
  525. * @param stream Outlet for data
  526. * @param data The value to write
  527. * @param picture Cobol item picture
  528. * @param spec Characteristics of the item;
  529. * see {@link CobolCharacteristics#toString()}
  530. *
  531. * @throws IOException if an I/O error occurs in writing the value
  532. */
  533. public static void encodeToBinary(OutputStream stream,
  534. BigDecimal data,
  535. String picture,
  536. CobolCharacteristics specs)
  537. throws IOException {
  538. final StringBuffer svalue = new StringBuffer(data.unscaledValue().toString());
  539. final int size = specs.getSize();
  540. final boolean signed = specs.isSigned();
  541. final int scalePic = specs.getDecimalPosition();
  542. final int scalingPositions = specs.getDecimalScalingPositions();
  543. int digitsPic;
  544. BigInteger value;
  545. byte[] valueBytes;
  546. int valueLen;
  547. // Remove sign info from value if item is unsigned
  548. if (!signed && data.signum() == -1) {
  549. svalue.delete(0, 1);
  550. }
  551. // Count number of digits in the picture
  552. digitsPic = 0;
  553. for (int i = 0, len = picture.length(); i < len; i++) {
  554. if (picture.charAt(i) == '9') {
  555. digitsPic += 1;
  556. }
  557. }
  558. fitToNumericPicture(svalue,
  559. data.scale(),
  560. digitsPic,
  561. scalePic,
  562. scalingPositions);
  563. value = new BigInteger(svalue.toString());
  564. valueBytes = value.toByteArray();
  565. valueLen = valueBytes.length;
  566. // Add byte padding
  567. if (size - valueLen > 0) {
  568. int padding = size - valueLen;
  569. byte[] newbytes = new byte[size];
  570. byte pad;
  571. int pos = 0;
  572. if (signed && data.signum() == -1) {
  573. pad = LIT_BYTE;
  574. } else {
  575. pad = 0;
  576. }
  577. while (padding-- > 0) {
  578. newbytes[pos] = pad;
  579. pos += 1;
  580. }
  581. for (int i = 0; i < valueLen; i++) {
  582. newbytes[pos] = valueBytes[i];
  583. pos += 1;
  584. }
  585. valueBytes = newbytes;
  586. }
  587. stream.write(valueBytes);
  588. }
  589. /**
  590. * Write a value as a Cobol 2-, 4- or 8-byte native binary (usage COMP5 or
  591. * INDEX) item. The binary item width used depends on the number of digits
  592. * in the picture, as specified in IBM Cobol Reference:
  593. * <p/>
  594. * <pre>
  595. * 1-4 digits: 2 bytes
  596. * 5-9 digits: 4 bytes
  597. * 10-18 digits: 8 bytes
  598. * </pre>
  599. * <p/>
  600. * However, note that the width computation <em>is not derived from the
  601. * supplied picture</em>, it is taken from the pre-computed value encoded in
  602. * the characteristics bit vector <code>parms</code>.
  603. *
  604. * @param stream Outlet for data
  605. * @param data The value to write
  606. * @param picture Cobol item picture
  607. * @param spec Characteristics of the item;
  608. * see {@link CobolCharacteristics#toString()}
  609. *
  610. * @throws IOException if an I/O error occurs in writing the value
  611. */
  612. public static void encodeToNativeBinary(OutputStream stream,
  613. BigDecimal data,
  614. String picture,
  615. CobolCharacteristics specs)
  616. throws IOException {
  617. final StringBuffer svalue = new StringBuffer(data.unscaledValue().toString());
  618. final int size = specs.getSize();
  619. final boolean signed = specs.isSigned();
  620. final int scalePic = specs.getDecimalPosition();
  621. final int scalingPositions = specs.getDecimalScalingPositions();
  622. int digitsPic;
  623. BigInteger value;
  624. byte[] valueBytes;
  625. int valueLen;
  626. // Remove sign info from value if item is unsigned
  627. if (!signed && data.signum() == -1) {
  628. svalue.delete(0, 1);
  629. }
  630. // Count number of digits in the picture
  631. digitsPic = 0;
  632. for (int i = 0, len = picture.length(); i < len; i++) {
  633. if (picture.charAt(i) == '9') {
  634. digitsPic += 1;
  635. }
  636. }
  637. fitToNumericNativePicture(svalue,
  638. data.scale(),
  639. digitsPic,
  640. scalePic,
  641. scalingPositions,
  642. size);
  643. value = new BigInteger(svalue.toString());
  644. valueBytes = value.toByteArray();
  645. valueLen = valueBytes.length;
  646. // Add byte padding
  647. if (size - valueLen > 0) {
  648. int padding = size - valueLen;
  649. byte[] newbytes = new byte[size];
  650. byte pad;
  651. int pos = 0;
  652. if (signed && value.signum() == -1) {
  653. pad = LIT_BYTE;
  654. } else {
  655. pad = 0;
  656. }
  657. while (padding-- > 0) {
  658. newbytes[pos] = pad;
  659. pos += 1;
  660. }
  661. for (int i = 0; i < valueLen; i++) {
  662. newbytes[pos] = valueBytes[i];
  663. pos += 1;
  664. }
  665. valueBytes = newbytes;
  666. }
  667. stream.write(valueBytes);
  668. }
  669. /**
  670. * Write a value as a Cobol 2-, 4- or 8-byte binary item (usage
  671. * BINARY/COMP). Delegates to
  672. * {@link #convertToBinary(OutputStream, BigDecimal, String, String)}
  673. * so see that method for additional details.
  674. *
  675. * @param stream Outlet for data
  676. * @param data The value to write
  677. * @param picture Cobol item picture
  678. * @param spec Characteristics of the item;
  679. * see {@link CobolCharacteristics#toString()}
  680. *
  681. * @throws IOException if an I/O error occurs in writing the value
  682. */
  683. public static void encodeToBinary(OutputStream stream,
  684. long data,
  685. String picture,
  686. CobolCharacteristics specs)
  687. throws IOException {
  688. // Legacy behaviour: when setting binary values
  689. // (which may have scale > 0) using long or int (which cannot store
  690. // information about scale > 0), treat the input not as an integral,
  691. // but as floating point value. This means applying scale info
  692. // of the item to the input after it is converted to a BigDecimal.
  693. //
  694. // A proposal to clean up this mess by removing int- and long-based
  695. // getters and setters for binary items has been rejected on grounds of
  696. // backward compatibility.
  697. BigDecimal decimal;
  698. decimal = new BigDecimal(Long.toString(data));
  699. decimal.movePointLeft(specs.getDecimalPosition());
  700. encodeToBinary(stream, decimal, picture, specs);
  701. }
  702. /**
  703. * Write a value as a Cobol 2-, 4- or 8-byte binary item (usage
  704. * BINARY/COMP). Delegates to
  705. * {@link #convertToBinary(OutputStream, BigDecimal, String, String)}
  706. * so see that method for additional details.
  707. *
  708. * @param stream Outlet for data
  709. * @param data The value to write
  710. * @param picture Cobol item picture
  711. * @param spec Characteristics of the item;
  712. * see {@link CobolCharacteristics#toString()}
  713. *
  714. * @throws IOException if an I/O error occurs in writing the value
  715. */
  716. public static void encodeToBinary(OutputStream stream,
  717. int data,
  718. String picture,
  719. CobolCharacteristics specs)
  720. throws IOException {
  721. // Legacy behaviour: when setting binary values
  722. // (which may have scale > 0) using long or int (which cannot store
  723. // information about scale > 0), treat the input not as an integral,
  724. // but as floating point value. This means applying scale info
  725. // of the item to the input after it is converted to a BigDecimal.
  726. //
  727. // A proposal to clean up this mess by removing int- and long-based
  728. // getters and setters for binary items has been rejected on grounds of
  729. // backward compatibility.
  730. BigDecimal decimal;
  731. decimal = new BigDecimal(Integer.toString(data));
  732. decimal.movePointLeft(specs.getDecimalPosition());
  733. encodeToBinary(stream, decimal, picture, specs);
  734. }
  735. /**
  736. * Write a value as a Cobol packed-decimal item. Use for internal decimal
  737. * items. Unlike the other variants of this method, this one can handle
  738. * values with non-zero decimal scaling.
  739. *
  740. * @param stream Outlet for data
  741. * @param data The value to write
  742. * @param picture Item picture
  743. * @param spec Characteristics of the item;
  744. * see {@link CobolCharacteristics#toString()}
  745. *
  746. * @throws IOException if an I/O error occurs in writing the value
  747. */
  748. public static void encodeToPacked(OutputStream stream,
  749. BigDecimal data,
  750. String picture,
  751. CobolCharacteristics specs)
  752. throws IOException {
  753. final StringBuffer value = new StringBuffer(data.unscaledValue().toString());
  754. final boolean signed = specs.isSigned();
  755. final int size = specs.getSize();
  756. final int scalePic = specs.getDecimalPosition();
  757. final int scalingPositions = specs.getDecimalScalingPositions();
  758. int digitsPic;
  759. int scale;
  760. // calc picture's digit requirements
  761. digitsPic = 0;
  762. for (int i = 0; i < picture.length(); i++) {
  763. if (picture.charAt(i) == '9') {
  764. digitsPic++;
  765. }
  766. }
  767. // Remove '-' for convenience
  768. if (data.signum() == -1) {
  769. value.delete(0, 1);
  770. }
  771. // Scale value to its picture
  772. scale = data.scale();
  773. scale = fitToNumericPicture(value,
  774. scale,
  775. digitsPic,
  776. scalePic,
  777. scalingPositions);
  778. // Packed decimal-specific truncation check
  779. int maxFitDigits = (size << 1) - 1; // reserve one for the
  780. //"sign" sign (neg, pos, unsigned)
  781. if (maxFitDigits < value.length()) {
  782. Message msg = MessageCatalog.getMessage("CCCR3004");
  783. String err = msg.formatText(new Object[]{
  784. data.toString(),
  785. String.valueOf((value.length() >> 1) + 1),
  786. String.valueOf(maxFitDigits)
  787. });
  788. cErrorMgr.log(ErrorManager.Severity.WARN, null, err);
  789. // truncate fraction
  790. if (scale > 0) {
  791. int truncsize = Math.max(0, scale - scalePic);
  792. value.delete(value.length() - truncsize, value.length());
  793. scale -= truncsize;
  794. }
  795. // truncate non-fraction
  796. if (maxFitDigits < value.length()) {
  797. int truncsize = Math.max(0, (value.length() - scale) - (digitsPic - scalePic));
  798. value.delete(0, truncsize);
  799. }
  800. }
  801. /*
  802. * if even number digits, need to add extra byte for sign:
  803. *
  804. * decimal = 12345
  805. * packed = 12|34|5s where s == sign nybble; extra byte not needed
  806. *
  807. * decimal = 1234
  808. * packed = 01|23|4s where s == sign nybble; extra byte needed
  809. */
  810. final boolean needPad = ((value.length() % 2) == 0);
  811. int current = 0;
  812. if (needPad) {
  813. byte pad = 0;
  814. byte digit =
  815. (byte) Character.digit(value.charAt(current++), 10);
  816. byte b = (byte) (pad | digit);
  817. stream.write(b);
  818. }
  819. for (int i = current; i < value.length(); i += 2) {
  820. byte digit1 = (byte) Character.digit(value.charAt(i), 10);
  821. byte digit2 = 0;
  822. if (i < (value.length() - 1)) { // if not last digit
  823. digit2 = (byte) Character.digit(value.charAt(i + 1), 10);
  824. } else if (!signed) {
  825. digit2 = UNSIGNED_PACK_SIGN;
  826. } else if ((new BigInteger(value.toString())).equals(
  827. BigInteger.ZERO)) {
  828. digit2 = POSITIVE_PACK_SIGN;
  829. } // else if ( Integer.valueOf( value.toString() ).intValue() == 0 ) {
  830. // digit2 = POSITIVE_PACK_SIGN;
  831. // }
  832. else {
  833. switch (data.signum()) {
  834. case -1:
  835. digit2 = NEGATIVE_PACK_SIGN;
  836. break;
  837. case 0:
  838. digit2 = POSITIVE_PACK_SIGN;
  839. break;
  840. case 1:
  841. digit2 = POSITIVE_PACK_SIGN;
  842. break;
  843. default:
  844. }
  845. }
  846. byte b = (byte) ((digit1 << 4) | digit2);
  847. stream.write(b);
  848. }
  849. }
  850. /**
  851. * Write a value as a Cobol packed-decimal item. Use for internal decimal
  852. * items.
  853. *
  854. * @param stream Outlet for data
  855. * @param data The value to write
  856. * @param picture Item picture
  857. * @param spec Characteristics of the item;
  858. * see {@link CobolCharacteristics#toString()}
  859. *
  860. * @throws IOException if an I/O error occurs in writing the value
  861. */
  862. public static void encodeToPacked(OutputStream stream,
  863. long data,
  864. String picture,
  865. CobolCharacteristics specs)
  866. throws IOException {
  867. // Legacy behaviour: when setting packed values
  868. // (which may have scale > 0) using long or int (which cannot store
  869. // information about scale > 0), treat the input not as an integral,
  870. // but as floating point value. This means applying scale info
  871. // of the item to the input after it is converted to a BigDecimal.
  872. //
  873. // A proposal to clean up this mess by removing int- and long-based
  874. // getters and setters for packed items has been rejected on grounds of
  875. // backward compatibility.
  876. BigDecimal decimal;
  877. decimal = new BigDecimal(Long.toString(data));
  878. decimal.movePointLeft(specs.getDecimalPosition());
  879. encodeToPacked(stream, decimal, picture, specs);
  880. }
  881. /**
  882. * Write a value as a Cobol packed-decimal item. Use for internal decimal
  883. * items.
  884. *
  885. * @param stream Outlet for data
  886. * @param data The value to write
  887. * @param picture Item picture
  888. * @param spec Characteristics of the item;
  889. * see {@link CobolCharacteristics#toString()}
  890. *
  891. * @throws IOException if an I/O error occurs in writing the value
  892. */
  893. public static void encodeToPacked(OutputStream stream,
  894. int data,
  895. String picture,
  896. CobolCharacteristics specs)
  897. throws IOException {
  898. // Legacy behaviour: when setting packed values
  899. // (which may have scale > 0) using long or int (which cannot store
  900. // information about scale > 0), treat the input not as an integral,
  901. // but as floating point value. This means applying scale info
  902. // of the item to the input after it is converted to a BigDecimal.
  903. //
  904. // A proposal to clean up this mess by removing int- and long-based
  905. // getters and setters for packed items has been rejected on grounds of
  906. // backward compatibility.
  907. BigDecimal decimal;
  908. decimal = new BigDecimal(Integer.toString(data));
  909. decimal.movePointLeft(specs.getDecimalPosition());
  910. encodeToPacked(stream, decimal, picture, specs);
  911. }
  912. /**
  913. * Write a value as a Cobol/EBCDIC index (4-byte) item.
  914. *
  915. * @param stream Outlet for data
  916. * @param data The value to write
  917. * @param spec Characteristics of the item;
  918. * see {@link CobolCharacteristics#toString()}
  919. *
  920. * @throws IOException if an I/O error occurs in writing the value
  921. */
  922. public static void encodeToIndex(OutputStream stream,
  923. int data,
  924. CobolCharacteristics specs)
  925. throws IOException {
  926. BigDecimal value = new BigDecimal(data);
  927. encodeToNativeBinary(stream, value, "999999999", specs);
  928. }
  929. /**
  930. * Convert the data from the input stream into to a Java integer (int)
  931. * value. Use for numeric items that can fit 4-byte signed storage.
  932. *
  933. * @param stream Data inlet as a byte stream
  934. * @param picture Cobol item picture
  935. * @param spec Characteristics of the item;
  936. * see {@link CobolCharacteristics#toString()}
  937. * @param enc Encoding to use to read character data
  938. *
  939. * @return Data as an int
  940. *
  941. * @throws IllegalArgumentException if an int value cannot be produced given
  942. * the data item information
  943. * @throws IOException if an I/O error occured in reading
  944. * input
  945. */
  946. public static int decodeToInt(InputStream stream,
  947. String picture,
  948. CobolCharacteristics specs,
  949. String enc)
  950. throws IOException {
  951. int result;
  952. int category = specs.getPicCategory();
  953. int usage = specs.getUsage();
  954. if (CobolCharacteristics.PIC_NUM == category) {
  955. switch (usage) {
  956. case CobolCharacteristics.USAGE_DISPLAY: {
  957. String value = readNumberDisplay(stream, specs, enc);
  958. result = Integer.parseInt(value);
  959. break;
  960. }
  961. case CobolCharacteristics.USAGE_BINARY:
  962. case CobolCharacteristics.USAGE_COMP:
  963. case CobolCharacteristics.USAGE_COMP4: {
  964. BigDecimal value = readNumberBinary(stream, specs);
  965. result = value.unscaledValue().intValue();
  966. break;
  967. }
  968. case CobolCharacteristics.USAGE_INDEX: {
  969. BigDecimal value = readNumberBinary(stream, specs);
  970. result = value.unscaledValue().intValue();
  971. break;
  972. }
  973. case CobolCharacteristics.USAGE_PACKED:
  974. case CobolCharacteristics.USAGE_COMP3: {
  975. BigDecimal value = readNumberPacked(stream, specs);
  976. result = value.unscaledValue().intValue();
  977. break;
  978. }
  979. case CobolCharacteristics.USAGE_COMP5: {
  980. BigDecimal value = readNumberBinary(stream, specs);
  981. result = value.unscaledValue().intValue();
  982. break;
  983. }
  984. default:
  985. Message msg = MessageCatalog.getMessage("CCCR4011");
  986. String err = msg.toString();
  987. cErrorMgr.log(ErrorManager.Severity.ERROR,
  988. null,
  989. err);
  990. throw new IllegalArgumentException(err);
  991. }
  992. } else {
  993. Message msg = MessageCatalog.getMessage("CCCR4013");
  994. String err = msg.formatText(new Object[]{compressedPic(picture)});
  995. cErrorMgr.log(ErrorManager.Severity.ERROR, null, err);
  996. throw new IllegalArgumentException(err);
  997. }
  998. return result;
  999. }
  1000. /**
  1001. * Convert the data from the input stream into a Java long integer (long)
  1002. * value. Use for numeric items exceeding 4-byte signed storage
  1003. * capability.
  1004. *
  1005. * @param stream Data inlet as a byte stream
  1006. * @param picture Cobol item picture
  1007. * @param spec Characteristics of the item;
  1008. * see {@link CobolCharacteristics#toString()}
  1009. * @param enc Encoding to use to read character data
  1010. *
  1011. * @return Data as an long
  1012. *
  1013. * @throws IllegalArgumentException if a long value cannot be produced given
  1014. * the data item information
  1015. * @throws IOException an I/O error occured in reading input
  1016. */
  1017. public static long decodeTolong(InputStream stream,
  1018. String picture,
  1019. CobolCharacteristics specs,
  1020. String enc)
  1021. throws IOException {
  1022. long result;
  1023. int category = specs.getPicCategory();
  1024. int usage = specs.getUsage();
  1025. if (CobolCharacteristics.PIC_NUM == category) {
  1026. switch (usage) {
  1027. case CobolCharacteristics.USAGE_DISPLAY: {
  1028. String value = readNumberDisplay(stream, specs, enc);
  1029. result = Long.parseLong(value);
  1030. break;
  1031. }
  1032. case CobolCharacteristics.USAGE_BINARY:
  1033. case CobolCharacteristics.USAGE_COMP:
  1034. case CobolCharacteristics.USAGE_COMP4: {
  1035. BigDecimal value = readNumberBinary(stream, specs);
  1036. result = value.unscaledValue().longValue();
  1037. break;
  1038. }
  1039. case CobolCharacteristics.USAGE_PACKED:
  1040. case CobolCharacteristics.USAGE_COMP3: {
  1041. BigDecimal value = readNumberPacked(stream, specs);
  1042. result = value.unscaledValue().longValue();
  1043. break;
  1044. }
  1045. case CobolCharacteristics.USAGE_COMP5: {
  1046. BigDecimal value = readNumberBinary(stream, specs);
  1047. result = value.unscaledValue().longValue();
  1048. break;
  1049. }
  1050. case CobolCharacteristics.USAGE_INDEX: {
  1051. BigDecimal value = readNumberBinary(stream, specs);
  1052. result = value.unscaledValue().longValue();
  1053. break;
  1054. }
  1055. default:
  1056. Message msg = MessageCatalog.getMessage("CCCR4012");
  1057. String err = msg.toString();
  1058. cErrorMgr.log(ErrorManager.Severity.ERROR,
  1059. null,
  1060. err);
  1061. throw new IllegalArgumentException(err);
  1062. }
  1063. } else {
  1064. Message msg = MessageCatalog.getMessage("CCCR4013");
  1065. String err = msg.formatText(new Object[]{compressedPic(picture)});
  1066. cErrorMgr.log(ErrorManager.Severity.ERROR, null, err);
  1067. throw new IllegalArgumentException(err);
  1068. }
  1069. return result;
  1070. }
  1071. /**
  1072. * Convert the data from the input stream into a Java float. Use for COMP-1
  1073. * items.
  1074. *
  1075. * @param stream Byte Data inlet
  1076. *
  1077. * @return Data as float
  1078. *
  1079. * @throws IOException if an I/O error occurs while reading the input,
  1080. * including having insufficient data
  1081. */
  1082. public static float decodeToFloat(InputStream stream)
  1083. throws IOException {
  1084. final int NEED = 4;
  1085. final byte[] bytebuf = new byte[NEED];
  1086. int got = stream.read(bytebuf);
  1087. if (got != NEED) {
  1088. Message msg = MessageCatalog.getMessage("CCCR4014");
  1089. String err = msg.formatText(new Object[]{
  1090. "COMP-1",
  1091. String.valueOf(NEED),
  1092. String.valueOf(Math.max(0, got))
  1093. });
  1094. cErrorMgr.log(ErrorManager.Severity.ERROR, null, err);
  1095. throw new IOException(err);
  1096. }
  1097. int intBits;
  1098. intBits = (((int) bytebuf[0]) << 24) & 0xFF000000;
  1099. intBits |= (((int) bytebuf[1]) << 16) & 0x00FF0000;
  1100. intBits |= (((int) bytebuf[2]) << 8) & 0x0000FF00;
  1101. intBits |= bytebuf[3] & 0x000000FF;
  1102. return Float.intBitsToFloat(intBits);
  1103. }
  1104. /**
  1105. * Convert the data from the input stream into a Java double. Use for COMP-2
  1106. * items.
  1107. *
  1108. * @param stream Byte Data inlet
  1109. *
  1110. * @return Data as double
  1111. *
  1112. * @throws IOException if an I/O error occurs while reading the input,
  1113. * including having insufficient data
  1114. */
  1115. public static double decodeToDouble(InputStream stream)
  1116. throws IOException {
  1117. final int NEED = 8;
  1118. final byte[] bytebuf = new byte[NEED];
  1119. int got = stream.read(bytebuf);
  1120. if (got != NEED) {
  1121. Message msg = MessageCatalog.getMessage("CCCR4014");
  1122. String err = msg.formatText(new Object[]{
  1123. "COMP-2",
  1124. String.valueOf(NEED),
  1125. String.valueOf(Math.max(0, got))
  1126. });
  1127. cErrorMgr.log(ErrorManager.Severity.ERROR, null, err);
  1128. throw new IOException(err);
  1129. }
  1130. long longBits;
  1131. longBits = (((long) bytebuf[0]) << 56) & 0xFF00000000000000L;
  1132. longBits |= (((long) bytebuf[1]) << 48) & 0x00FF000000000000L;
  1133. longBits |= (((long) bytebuf[2]) << 40) & 0x0000FF0000000000L;
  1134. longBits |= (((long) bytebuf[3]) << 32) & 0x000000FF00000000L;
  1135. longBits |= (((long) bytebuf[4]) << 24) & 0x00000000FF000000L;
  1136. longBits |= (((long) bytebuf[5]) << 16) & 0x0000000000FF0000L;
  1137. longBits |= (((long) bytebuf[6]) << 8) & 0x000000000000FF00L;
  1138. longBits |= bytebuf[7] & 0x00000000000000FFL;
  1139. return Double.longBitsToDouble(longBits);
  1140. }
  1141. /**
  1142. * Convert the data from the input stream into a Java byte array. Use for
  1143. * DBCS items.
  1144. *
  1145. * @param stream Data inlet as a byte stream
  1146. * @param picture Cobol item picture
  1147. * @param spec Characteristics of the item;
  1148. * see {@link CobolCharacteristics#toString()}
  1149. *
  1150. * @return Data as an array of bytes, with each element containing a half (a
  1151. * byte) of a double-byte character value
  1152. *
  1153. * @throws IOException if an I/O error occured in reading
  1154. * input
  1155. * @throws IllegalArgumentException if the Cobol item category specified is
  1156. * not DBCS, or a DBCS value cannot be read
  1157. * given the data item information
  1158. */
  1159. public static byte[] decodeTobytes(InputStream stream,
  1160. String picture,
  1161. CobolCharacteristics specs)
  1162. throws IOException {
  1163. byte[] result = null;
  1164. int category = specs.getPicCategory();
  1165. if (CobolCharacteristics.PIC_DBCS == category) {
  1166. result = readDBCS(stream, specs);
  1167. } else {
  1168. Message msg = MessageCatalog.getMessage("CCCR4015");
  1169. String err = msg.formatText(new Object[]{compressedPic(picture)});
  1170. cErrorMgr.log(ErrorManager.Severity.ERROR, null, err);
  1171. throw new IllegalArgumentException(err);
  1172. }
  1173. return result;
  1174. }
  1175. /**
  1176. * Convert the data from the input stream into a Java string value. Use for
  1177. * alphabetic, alphanumeric, alphanumeric-edited, and numeric-edited items.
  1178. *
  1179. * @param stream Data inlet as a byte stream
  1180. * @param reader Data inlet as a character reader
  1181. * @param picture Cobol item picture
  1182. * @param spec Characteristics of the item;
  1183. * see {@link CobolCharacteristics#toString()}
  1184. * @param enc Encoding to use to read character data
  1185. *
  1186. * @return Data as a string
  1187. *
  1188. * @throws IllegalArgumentException if a string value cannot be produced
  1189. * given the data item information
  1190. * @throws IOException an I/O error occured in reading input
  1191. */
  1192. public static String decodeToString(InputStream stream,
  1193. String picture,
  1194. CobolCharacteristics specs,
  1195. String enc)
  1196. throws IOException {
  1197. String result = null;
  1198. int category = specs.getPicCategory();
  1199. // Switch back to old implementation. Will improve it later
  1200. // if necessary.
  1201. //
  1202. // ESR 104580
  1203. // Profiling shows that creating a new InputStreamReader
  1204. // from InputStream is very expensive, in particular on
  1205. // HP/UX 11iV2. According to CocoCodeGen.java, the InputStreamReader
  1206. // argument, reader, is created from the InputStream argument,
  1207. // stream, using the encoding represented by the String argument,
  1208. // enc. Therefore there is really no need to create a new
  1209. // InputStreamReader from InputStream.
  1210. //
  1211. // Relevant code in CocoCodeGen.java is
  1212. //
  1213. // emitter.emit("mEncoding = \"cp037\"; // initial default");
  1214. // ...
  1215. // emitter.emit("mWriter =new OutputStreamWriter(mOutputStream, mEncoding);");
  1216. // emitter.emit("mReader = new InputStreamReader(mInputStream, mEncoding);");
  1217. // and
  1218. // emitter.emit( "mEncoding = enc.name();" );
  1219. // emitter.emit( …

Large files files are truncated, but you can click here to view the full file