1 package net.sf.cobol2j;
2
3 import net.sf.cobol2j.FieldFormat;
4 import net.sf.cobol2j.FieldsGroup;
5 import net.sf.cobol2j.FieldsList;
6 import net.sf.cobol2j.FileFormat;
7 import net.sf.cobol2j.FileFormatException;
8 import net.sf.cobol2j.RecordFormat;
9 import net.sf.cobol2j.RecordSet;
10
11 import org.apache.commons.lang.mutable.MutableInt;
12 import org.apache.commons.logging.Log;
13 import org.apache.commons.logging.LogFactory;
14
15 import java.io.FileInputStream;
16 import java.io.FileNotFoundException;
17 import java.io.FileOutputStream;
18 import java.io.IOException;
19 import java.io.OutputStream;
20 import java.io.OutputStreamWriter;
21 import java.io.UnsupportedEncodingException;
22
23 import java.math.BigDecimal;
24 import java.math.BigInteger;
25
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Map;
30
31
32 public class RecordWriter {
33 private static Log log = LogFactory.getLog(RecordWriter.class);
34 OutputStream oS;
35 String charset;
36 Map recdefs;
37
38 public RecordWriter(OutputStream os, FileFormat ff)
39 throws UnsupportedEncodingException {
40 oS = os;
41 charset = ff.getConversionTable();
42 recdefs = new RecordsMap(ff);
43 }
44
45 public void writeRecord(List fields) throws Exception {
46 RecordFormat rF = (RecordFormat) recdefs.get("0");
47
48 if (recdefs.size() > 1) {
49 String first1 = fields.get(0).toString();
50 rF = (RecordFormat) recdefs.get(first1);
51 }
52
53 Iterator data = fields.listIterator();
54 createFields(data, rF);
55 }
56
57 private void createFields(Iterator data, FieldsList deflist)
58 throws Exception {
59 HashMap potentialDepOn = new HashMap();
60 Iterator def = deflist.getFieldFormatOrFieldsGroup().listIterator();
61
62 while (def.hasNext()) {
63 Object u = def.next();
64
65 if (u instanceof FieldFormat) {
66 int occurs = 1;
67 FieldFormat ff = (FieldFormat) u;
68 String dependingon = ff.getDependingOn();
69
70 if (dependingon.length() > 0) {
71 BigDecimal bd = (BigDecimal) potentialDepOn.get(dependingon);
72 occurs = bd.intValue();
73 } else {
74 occurs = ff.getOccurs().intValue();
75 }
76
77 while (occurs-- > 0) {
78 Object o = data.next();
79 writeField(o, ff, potentialDepOn);
80 }
81 } else if (u instanceof FieldsGroup) {
82 int occurs = 1;
83 FieldsGroup fG = (FieldsGroup) u;
84 String dependingon = fG.getDependingOn();
85
86 if (dependingon.length() > 0) {
87 BigDecimal bd = (BigDecimal) potentialDepOn.get(dependingon);
88 occurs = bd.intValue();
89 } else {
90 occurs = fG.getOccurs().intValue();
91 }
92
93 while (occurs-- > 0) {
94 createFields(data, fG);
95 }
96 }
97 }
98 }
99
100 private void writeField(Object o, FieldFormat format, HashMap potDepOn)
101 throws IOException, Exception {
102 char fType = format.getType().charAt(0);
103
104 switch (fType) {
105 case 'X':
106
107 if (o instanceof String) {
108 String value = (String) o;
109
110 if (value.length() != format.getSize().intValue()) {
111 throw new Exception(
112 "Value size must be equal to field length.");
113 }
114
115 oS.write(value.getBytes(charset));
116 } else {
117 throw new Exception("ValueTypeMismatch");
118 }
119
120 break;
121
122 case '9':
123
124 if (o instanceof BigDecimal) {
125 BigDecimal value = (BigDecimal) o;
126
127 if (format.getDecimal().intValue() != value.scale()) {
128 BigDecimal tmp = value.setScale(format.getDecimal()
129 .intValue(),
130 BigDecimal.ROUND_FLOOR);
131 value = tmp;
132 }
133
134 String str = value.toPlainString();
135 StringBuffer buf = new StringBuffer(str);
136
137
138 if (format.isSigned()) {
139 int lastidx = buf.length() - 1;
140 char lastbyte = buf.charAt(lastidx);
141 char repl;
142
143 if (value.signum() > 0) {
144 repl = "{ABCDEFGHI".charAt(Integer.parseInt(
145 String.valueOf(lastbyte)));
146 } else {
147 repl = "}JKLMNOPQR".charAt(Integer.parseInt(
148 String.valueOf(lastbyte)));
149 }
150
151 buf.setCharAt(lastidx, repl);
152
153
154 String tmp = buf.toString();
155 String tmp2 = tmp.replace("-", "");
156 buf = new StringBuffer(tmp2);
157 }
158
159
160 if (format.isImpliedDecimal()) {
161 String tmp = buf.toString();
162 String tmp2 = tmp.replace(".", "");
163 buf = new StringBuffer(tmp2);
164 }
165
166
167 while (format.getSize().intValue() > buf.length()) {
168 buf.insert(0, "0");
169 }
170
171 oS.write(buf.toString().getBytes(charset));
172 potDepOn.put(format.getName(), value);
173 } else {
174 throw new Exception("ValueTypeMismatch");
175 }
176
177 break;
178
179 case '3':
180
181 if (o instanceof BigDecimal) {
182 BigDecimal value = (BigDecimal) o;
183
184 if (format.getDecimal().intValue() != value.scale()) {
185 BigDecimal tmp = value.setScale(format.getDecimal()
186 .intValue(),
187 BigDecimal.ROUND_FLOOR);
188 value = tmp;
189 }
190
191 String str = value.toPlainString();
192 int len = str.length();
193 int fieldSize = getByteSize(format);
194 byte[] buf = new byte[fieldSize];
195 MutableInt k = new MutableInt(len);
196 byte even;
197 byte odd;
198
199 for (int i = fieldSize - 1; i >= 0; i--) {
200
201 if (i == (fieldSize - 1)) {
202 even = getNextByte(str, k);
203
204 if (format.isSigned()) {
205 if (value.signum() >= 0) {
206 odd = 0x0C;
207 } else {
208 odd = 0x0D;
209 }
210 } else {
211 odd = (byte) 0x0F;
212 }
213 } else {
214
215
216 odd = getNextByte(str, k);
217 even = getNextByte(str, k);
218 }
219
220 buf[i] = (byte) ((even << 4) | odd);
221 }
222
223
224 oS.write(buf);
225 } else {
226 throw new Exception("ValueTypeMismatch");
227 }
228
229 break;
230
231 case 'B':
232
233 if (o instanceof BigDecimal) {
234 BigDecimal value = (BigDecimal) o;
235
236 if (format.getDecimal().intValue() != value.scale()) {
237 BigDecimal tmp = value.setScale(format.getDecimal()
238 .intValue(),
239 BigDecimal.ROUND_FLOOR);
240 value = tmp;
241 }
242
243 BigInteger unscaled = value.unscaledValue();
244
245
246 oS.write(unscaled.toByteArray());
247 } else {
248 throw new Exception("ValueTypeMismatch");
249 }
250
251 break;
252
253 case 'T':
254
255 if (o instanceof byte[]) {
256 byte[] value = (byte[]) o;
257
258 if (value.length == format.getSize().intValue()) {
259 oS.write(value);
260 } else {
261 throw new Exception(
262 "Value size must be equal to field length.");
263 }
264 } else {
265 throw new Exception("ValueTypeMismatch");
266 }
267
268 break;
269
270 default:
271 throw new FileFormatException("Field type not supported: " + fType);
272 }
273 }
274
275 private int getByteSize(FieldFormat fieldF) {
276 int sz = fieldF.getSize().intValue();
277
278 if (fieldF.getType().equals("3")) {
279 if ((sz % 2) != 0) {
280 return (sz / 2) + 1;
281 } else {
282 return sz / 2;
283 }
284 } else {
285 return sz;
286 }
287 }
288
289 private byte getNextByte(String number, MutableInt recentlyReturned) {
290 MutableInt zero = new MutableInt(0);
291 recentlyReturned.decrement();
292
293 if (recentlyReturned.compareTo(zero) >= 0) {
294 while (!"0123456789".contains(String.valueOf(number.charAt(
295 recentlyReturned.intValue())))) {
296 recentlyReturned.decrement();
297
298 if (recentlyReturned.compareTo(zero) < 0) {
299 return 0;
300 }
301 }
302
303 return (byte) (Character.getNumericValue(number.charAt(
304 recentlyReturned.intValue())));
305 } else {
306 return 0;
307 }
308 }
309 }