View Javadoc

1   /*******************************************************************************
2    * Copyright (c) 2015 LegSem.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the GNU Lesser Public License v2.1
5    * which accompanies this distribution, and is available at
6    * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
7    * 
8    * Contributors:
9    *     LegSem - initial API and implementation
10   ******************************************************************************/
11  package com.legstar.coxb.convert.simple;
12  
13  import java.util.ArrayList;
14  import java.util.List;
15  
16  import com.legstar.coxb.CobolContext;
17  import com.legstar.coxb.ICobolArrayOctetStreamBinding;
18  import com.legstar.coxb.ICobolOctetStreamBinding;
19  import com.legstar.coxb.convert.ICobolOctetStreamConverter;
20  import com.legstar.coxb.convert.CobolConversionException;
21  import com.legstar.coxb.host.HostData;
22  import com.legstar.coxb.host.HostException;
23  
24  /**
25   * This is a concrete implementation of marshal/unmarshal operations of java
26   * byte arrays to cobol octet streams.
27   *
28   * @author Fady Moussallam
29   * 
30   */
31  public class CobolOctetStreamSimpleConverter extends CobolSimpleConverter
32  implements ICobolOctetStreamConverter {
33  
34      /**
35       * @param cobolContext the Cobol compiler parameters in effect
36       */
37      public CobolOctetStreamSimpleConverter(final CobolContext cobolContext) {
38          super(cobolContext);
39      }
40  
41      /** {@inheritDoc} */
42      public int toHost(
43              final ICobolOctetStreamBinding ce,
44              final byte[] hostTarget,
45              final int offset)
46      throws HostException {
47          int newOffset = 0;
48          try {
49              newOffset = toHostSingle(ce.getByteArrayValue(),
50                      ce.getByteLength(),
51                      hostTarget,
52                      offset);
53          } catch (CobolConversionException e) {
54              throwHostException(ce, e);
55          }
56          return newOffset;
57      }
58  
59      /** {@inheritDoc} */
60      public int toHost(
61              final ICobolArrayOctetStreamBinding ce,
62              final byte[] hostTarget,
63              final int offset,
64              final int currentOccurs)
65      throws HostException {
66          int newOffset = offset;
67          try {
68              for (byte[] javaSource : ce.getByteArrayList()) {
69                  newOffset = toHostSingle(javaSource,
70                          ce.getItemByteLength(),
71                          hostTarget,
72                          newOffset);
73              }
74              /* If necessary, fill in the array with missing items */
75              for (int i = ce.getByteArrayList().size();
76              i < currentOccurs; i++) {
77                  newOffset = toHostSingle(new byte[] { 0 },
78                          ce.getItemByteLength(),
79                          hostTarget,
80                          newOffset);
81              }
82          } catch (CobolConversionException e) {
83              throwHostException(ce, e);
84          }
85          return newOffset;
86      }
87  
88      /** {@inheritDoc} */
89      public int fromHost(
90              final ICobolOctetStreamBinding ce,
91              final byte[] hostSource,
92              final int offset)
93      throws HostException {
94          int newOffset = offset;
95          try {
96              byte[] javaBytes = fromHostSingle(ce.getByteLength(),
97                      hostSource,
98                      newOffset);
99              ce.setByteArrayValue(javaBytes);
100             newOffset += ce.getByteLength();
101         } catch (CobolConversionException e) {
102             throwHostException(ce, e);
103         }
104         return newOffset;
105     }
106 
107     /** {@inheritDoc} */
108     public int fromHost(
109             final ICobolArrayOctetStreamBinding ce,
110             final byte[] hostSource,
111             final int offset,
112             final int currentOccurs)
113     throws HostException {
114         List < byte[] > lArray = new ArrayList < byte[] >();
115         int newOffset = offset;
116         try {
117             for (int i = 0; i < currentOccurs; i++) {
118                 byte[] javaBytes = fromHostSingle(ce.getItemByteLength(),
119                         hostSource,
120                         newOffset);
121                 lArray.add(javaBytes);
122                 newOffset += ce.getItemByteLength();
123             }
124             ce.setByteArrayList(lArray);
125         } catch (CobolConversionException e) {
126             throwHostException(ce, e);
127         }
128         return newOffset;
129     }
130 
131     /**
132      *  Converts a Java byte array to a host octet stream.
133      * 
134      * @param javaBytes java byte array to convert
135      * @param cobolByteLength host byte length
136      * @param hostTarget target host buffer
137      * @param offset offset in target host buffer
138      * @return offset after host buffer is updated
139      * @throws CobolConversionException if conversion fails
140      */
141     public static final int toHostSingle(
142             final byte[] javaBytes,
143             final int cobolByteLength,
144             final byte[] hostTarget,
145             final int offset)
146     throws CobolConversionException {
147 
148         /* Check that we are still within the host target range */
149         int lastOffset = offset + cobolByteLength;
150         if (lastOffset > hostTarget.length) {
151             throw (new CobolConversionException(
152                     "Attempt to write past end of host source buffer",
153                     new HostData(hostTarget), offset, cobolByteLength));
154         }
155 
156         /* Provide a default if input is null */
157         byte[] localBytes = javaBytes;
158         if (localBytes == null) {
159             localBytes = new byte[cobolByteLength];
160         }
161         /**
162          * HostData is obtained by moving the java byte array content to the
163          * target host buffer. If there are more java bytes than space in the
164          * target buffer, data is truncated.
165          */
166         for (int i = 0; i < localBytes.length && i < cobolByteLength; i++) {
167             hostTarget[offset + i] = localBytes[i];
168         }
169         return lastOffset;
170     }
171 
172     /** Converts a host octet stream to a java byte array.
173      * 
174      * @param cobolByteLength host byte length
175      * @param hostSource source host buffer
176      * @param offset offset in source host buffer
177      * @return offset after host buffer is read
178      * @throws CobolConversionException if conversion fails
179      */
180     public static final byte[] fromHostSingle(
181             final int cobolByteLength,
182             final byte[] hostSource,
183             final int offset) throws CobolConversionException {
184 
185         /* Check that we are still within the host source range.
186          * If not, consider the host optimized its payload by truncating
187          * trailing nulls in which case, we just need to recover the
188          * partial data returned and then fill with nulls. */
189         int lastOffset = offset + cobolByteLength;
190         int fill = 0;
191         if (lastOffset > hostSource.length) {
192             if (offset >= hostSource.length) {
193                 fill = cobolByteLength;
194             } else {
195                 fill = hostSource.length - offset;
196             }
197         }
198 
199         /* The Java byte array is the exact byte by byte copy of the host octet
200          * stream. */
201         byte[] javaBytes = new byte[cobolByteLength];
202         for (int i = 0; i < cobolByteLength - fill; i++) {
203             javaBytes[i] = hostSource[offset + i];
204         }
205         for (int i = cobolByteLength - fill; i < cobolByteLength; i++) {
206             javaBytes[i] = 0x00;
207         }
208 
209         return javaBytes;
210     }
211 }