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.io.UnsupportedEncodingException;
14  import java.util.ArrayList;
15  import java.util.List;
16  
17  import com.legstar.coxb.CobolContext;
18  import com.legstar.coxb.ICobolArrayNationalBinding;
19  import com.legstar.coxb.ICobolNationalBinding;
20  import com.legstar.coxb.convert.ICobolNationalConverter;
21  import com.legstar.coxb.convert.CobolConversionException;
22  import com.legstar.coxb.host.HostData;
23  import com.legstar.coxb.host.HostException;
24  
25  /**
26   * This is a concrete implementation of marshal/unmarshal operations of java 
27   * strings to cobol national strings.
28   *
29   * @author Fady Moussallam
30   * 
31   */
32  public class CobolNationalSimpleConverter extends CobolSimpleConverter
33  implements ICobolNationalConverter {
34  
35      /** UTF-16 code point for space character. */
36      private static final byte[] SPACE_UTF_16 = {0x00, 0x20}; 
37  
38      /** Encoding used for national items. */
39      private static final String NATIONAL_CHARSET = "UTF-16BE";
40  
41      /**
42       * @param cobolContext the Cobol compiler parameters in effect
43       */
44      public CobolNationalSimpleConverter(final CobolContext cobolContext) {
45          super(cobolContext);
46      }
47  
48      /** {@inheritDoc} */
49      public int toHost(
50              final ICobolNationalBinding ce,
51              final byte[] hostTarget,
52              final int offset)
53      throws HostException {
54          int newOffset = 0;
55          try {
56              newOffset = toHostSingle(ce.getStringValue(),
57                      ce.getByteLength(),
58                      ce.isJustifiedRight(),
59                      hostTarget,
60                      offset);
61          } catch (CobolConversionException e) {
62              throwHostException(ce, e);
63          }
64          return newOffset;
65      }
66  
67      /** {@inheritDoc} */
68      public int toHost(
69              final ICobolArrayNationalBinding ce,
70              final byte[] hostTarget,
71              final int offset,
72              final int currentOccurs)
73      throws HostException {
74          int newOffset = offset;
75          try {
76              for (String javaSource : ce.getStringList()) {
77                  newOffset = toHostSingle(javaSource,
78                          ce.getItemByteLength(),
79                          ce.isJustifiedRight(),
80                          hostTarget,
81                          newOffset);
82              }
83              /* If necessary, fill in the array with missing items */
84              for (int i = ce.getStringList().size();
85              i < currentOccurs; i++) {
86                  newOffset = toHostSingle("",
87                          ce.getItemByteLength(),
88                          ce.isJustifiedRight(),
89                          hostTarget,
90                          newOffset);
91              }
92          } catch (CobolConversionException e) {
93              throwHostException(ce, e);
94          }
95          return newOffset;
96      }
97  
98      /** {@inheritDoc} */
99      public int fromHost(
100             final ICobolNationalBinding ce,
101             final byte[] hostSource,
102             final int offset)
103     throws HostException {
104         int newOffset = offset;
105         try {
106             String javaString = fromHostSingle(
107                     ce.getByteLength(),
108                     hostSource,
109                     newOffset);
110             ce.setStringValue(javaString);
111             newOffset += ce.getByteLength();
112         } catch (CobolConversionException e) {
113             throwHostException(ce, e);
114         }
115         return newOffset;
116     }
117 
118     /** {@inheritDoc} */
119     public int fromHost(
120             final ICobolArrayNationalBinding ce,
121             final byte[] hostSource,
122             final int offset,
123             final int currentOccurs)
124     throws HostException {
125         List < String > lArray = new ArrayList < String >();
126         int newOffset = offset;
127         try {
128             for (int i = 0; i < currentOccurs; i++) {
129                 String javaString = fromHostSingle(
130                         ce.getItemByteLength(),
131                         hostSource,
132                         newOffset);
133                 lArray.add(javaString);
134                 newOffset += ce.getItemByteLength();
135             }
136             ce.setStringList(lArray);
137         } catch (CobolConversionException e) {
138             throwHostException(ce, e);
139         }
140         return newOffset;
141     }
142 
143     /**
144      *  Converts a Java String to a host national element.
145      * 
146      * @param javaString java string to convert
147      * @param cobolByteLength host byte length
148      * @param isJustifiedRight is Cobol data right justified
149      * @param hostTarget target host buffer
150      * @param offset offset in target host buffer
151      * @return offset after host buffer is updated
152      * @throws CobolConversionException if conversion fails
153      */
154     public static final int toHostSingle(
155             final String javaString,
156             final int cobolByteLength,
157             final boolean isJustifiedRight,
158             final byte[] hostTarget,
159             final int offset)
160     throws CobolConversionException {
161 
162         /* Check that we are still within the host target range */
163         int lastOffset = offset + cobolByteLength;
164         if (lastOffset > hostTarget.length) {
165             throw (new CobolConversionException(
166                     "Attempt to write past end of host source buffer",
167                     new HostData(hostTarget), offset, cobolByteLength));
168         }
169 
170         /* HostData is obtained by converting the java String content to the 
171          * target host character set. */
172         byte[] hostSource;
173 
174         /* See how many host bytes would be needed to hold the converted
175          * string */
176         try {
177             if (javaString == null) {
178                 hostSource =
179                     "".getBytes(NATIONAL_CHARSET);
180             } else {
181                 hostSource =
182                     javaString.getBytes(NATIONAL_CHARSET);
183             }
184         } catch (UnsupportedEncodingException uee) {
185             throw new CobolConversionException(
186                     "UnsupportedEncodingException:" + uee.getMessage());
187         }
188 
189         int iSource = 0;
190         int hsl = hostSource.length;
191         /* The target host element might be larger than the converted java
192          * String and might have to be right or left justified. The padding
193          * code point is 0x0020 (space character). */
194         int iTarget = offset;
195         boolean flip = true;
196 
197         /* Pad with initial spaces if necessary */
198         if (isJustifiedRight) {
199             while (iTarget < (lastOffset - hsl)) {
200                 hostTarget[iTarget] = SPACE_UTF_16[(flip) ? 0 : 1];
201                 iTarget++;
202                 flip = !flip;
203             }
204         }
205 
206         /* Continue on with source content */
207         while (iSource < hostSource.length && iTarget < lastOffset) {
208             hostTarget[iTarget] = hostSource[iSource];
209             iSource++;
210             iTarget++;
211         }
212 
213         /* Pad with final spaces if necessary */
214         flip = true;
215         if (!isJustifiedRight) {
216             while (iTarget < lastOffset) {
217                 hostTarget[iTarget] = SPACE_UTF_16[(flip) ? 0 : 1];
218                 iTarget++;
219                 flip = !flip;
220             }
221         }
222 
223         return lastOffset;
224     }
225 
226     /** Converts a host national string into a Java string.
227      * 
228      * @param cobolByteLength host byte length
229      * @param hostSource source host buffer
230      * @param offset offset in source host buffer
231      * @return offset after host buffer is read
232      * @throws CobolConversionException if conversion fails
233      */
234     public static final String fromHostSingle(
235             final int cobolByteLength,
236             final byte[] hostSource,
237             final int offset)
238     throws CobolConversionException {
239 
240         String javaString = null;
241         int javaStringLength = cobolByteLength;
242 
243         /* Check that we are still within the host source range.
244          * If not, consider the host optimized its payload by truncating
245          * trailing nulls in which case, we just need to process the
246          * characters returned if any. */
247         int lastOffset = offset + cobolByteLength;
248         if (lastOffset > hostSource.length) {
249             if (offset >= hostSource.length) {
250                 return javaString;
251             } else {
252                 javaStringLength = hostSource.length - offset;
253             }
254         }
255 
256         /* The Java String is obtained by translating from the host code page
257          * to the local code page. */
258         try {
259             javaString = new String(
260                     hostSource, offset, javaStringLength,
261                     NATIONAL_CHARSET);
262             /* Some low-value characters may have slipped into the resulting
263              * string. */
264             if (javaString.indexOf("\0") != -1) {
265                 javaString = javaString.replace('\0', ' ');
266             }
267         } catch (UnsupportedEncodingException uee) {
268             throw new CobolConversionException(
269                     "UnsupportedEncodingException:" + uee.getMessage());
270         }
271 
272         return javaString;
273     }
274 }