KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openlaszlo > xml > internal > DataCommon


1 /* ****************************************************************************
2  * DataCommon.java
3  *
4  * Compile XML directly to SWF bytecodes.
5  * ****************************************************************************/

6
7 /* J_LZ_COPYRIGHT_BEGIN *******************************************************
8 * Copyright 2001-2004 Laszlo Systems, Inc. All Rights Reserved. *
9 * Use is subject to license terms. *
10 * J_LZ_COPYRIGHT_END *********************************************************/

11
12 package org.openlaszlo.xml.internal;
13
14 import java.io.*;
15 import java.util.*;
16
17 import org.openlaszlo.iv.flash.util.*;
18 import org.openlaszlo.iv.flash.api.action.*;
19 import org.openlaszlo.iv.flash.api.*;
20 import org.openlaszlo.compiler.CompilationError;
21 import org.openlaszlo.utils.ChainedException;
22 import org.openlaszlo.utils.FileUtils;
23 import org.openlaszlo.utils.HashIntTable;
24
25 import org.apache.log4j.*;
26
27 /**
28  * Common data compiler routines between DataCompiler (XML compiler) and DataBuilder (Java API)
29  *
30  * @author Henry Minsky
31  * @version 1.0
32  */

33 public abstract class DataCommon {
34     /* Logger */
35     static public String JavaDoc ROOT_NODE_INSTANTIATOR_FN = "_rootndi";
36     static public String JavaDoc RESULTSET_NODE_INSTANTIATOR_FN = "_resultsetndi";
37     static public String JavaDoc BODY_NODE_INSTANTIATOR_FN = "_bodyndi";
38     static public String JavaDoc NODE_INSTANTIATOR_FN = "_m";
39     static public String JavaDoc TEXT_INSTANTIATOR_FN = "_t";
40     static public String JavaDoc ROOT_NODE_FINAL_FN = "_finishndi";
41
42     /**
43      * Push a reference to string data on stack. maybeInternString
44      * uses a heuristic to decide whether to add the string constant
45      * pool, so this may push a string literal or a dictionary ref.
46      */

47     static public final void pushStringData(String JavaDoc s, FlashBuffer body, DataContext dc) {
48         int idx = maybeInternString(s, dc);
49         if (idx != -1) {
50             //System.out.println("intern IDX '"+s+"'="+idx);
51
// PUSH idx
52
body.writeByte(Actions.PushData);
53             body.writeWord(2);
54             writeOffset(idx, body);
55         } else {
56             // System.out.println("intern LITERAL '"+s+"'");
57
// PUSH literal attrname
58
// {0x96, lenlo, lenhi, 0x00, char, char, char, ...0x00, }
59
body.writeByte(Actions.PushData);
60             body.writeWord(getByteLength(s, dc.encoding) + 2); // account for type code and zero terminator
61
body.writeByte(0); // type code 0 ; null terminated string type
62
body.writeStringZ(s, dc.encoding);
63         }
64     }
65
66     static public int getByteLength (String JavaDoc s, String JavaDoc encoding) {
67         try {
68             byte buf[] = s.getBytes(encoding);
69             return buf.length;
70         } catch (UnsupportedEncodingException e) {
71             throw new RuntimeException JavaDoc("Got UnsupportedEncodingException for charset "+encoding
72                                        +" on string '"+s+"': "+e.getMessage());
73         }
74     }
75
76
77     /**
78      * Push a reference to string data on stack. maybeInternString
79      * uses a heuristic to decide whether to add the string constant
80      * pool, so this may push a string literal or a dictionary ref.
81      *
82      * This version of the method uses the faster _writeXXX() methods,
83      * which do not do bounds checks on the FlashBuffer. So this should only be
84      * used in situations where we know the FlashBuffer is already allocated with
85      * enough space for any data we may push.
86      */

87     static public final void _pushStringData(String JavaDoc s, FlashBuffer body, DataContext dc) {
88         int idx = maybeInternString(s, dc);
89         if (idx != -1) {
90             //System.out.println("intern IDX '"+s+"'="+idx);
91
// PUSH idx
92
body._writeByte(Actions.PushData);
93             body._writeWord(2);
94             writeOffset(idx, body);
95         } else {
96             // System.out.println("intern LITERAL '"+s+"'");
97
// PUSH literal attrname
98
// {0x96, lenlo, lenhi, 0x00, char, char, char, ...0x00, }
99
body._writeByte(Actions.PushData);
100             body._writeWord(getByteLength(s, dc.encoding) + 2); // account for type code and zero terminator
101
body._writeByte(0); // type code 0 ; null terminated string type
102
body._writeStringZ(s, dc.encoding);
103         }
104     }
105
106     /**
107      * Push a reference to string data on stack. maybeInternString
108      * uses a heuristic to decide whether to add the string constant
109      * pool, so this may push a string literal or a dictionary ref.
110      *
111      *<p>
112      *
113      * This method is used when composing the arguments for a PUSH
114      * merges several args on the stack with a single PUSH
115      * instruction, and writes out only the data or constant-pool
116      * index reference, as opposed to the pushStringData() method
117      * which also writes out the PUSH instruction itsef.
118      *
119      */

120
121     static public final void pushMergedStringData(String JavaDoc s, FlashBuffer body, DataContext dc) {
122         int idx = maybeInternString(s, dc);
123         if (idx != -1) {
124             //System.out.println("intern IDX '"+s+"'="+idx);
125
writeOffset(idx, body);
126         } else {
127             // System.out.println("intern LITERAL '"+s+"'");
128
body.writeByte(0); // type code 0 ; null terminated
129
// string type
130
body.writeStringZ(s, dc.encoding);
131         }
132     }
133
134
135     /**
136      * Push a reference to string data on stack. maybeInternString
137      * uses a heuristic to decide whether to add the string constant
138      * pool, so this may push a string literal or a dictionary ref.
139      *
140      *<p>
141      *
142      *
143      * This version of the method uses the faster _writeXXX() methods,
144      * which do not do bounds checks on the FlashBuffer. So this should only be
145      * used in situations where we know the FlashBuffer is already allocated with
146      * enough space for any data we may push.
147      */

148
149     static public final void _pushMergedStringData(String JavaDoc s, FlashBuffer body, DataContext dc) {
150         int idx = maybeInternString(s, dc);
151         if (idx != -1) {
152             //System.out.println("intern IDX '"+s+"'="+idx);
153
_writeOffset(idx, body);
154         } else {
155             // System.out.println("intern LITERAL '"+s+"'");
156
body._writeByte(0); // type code 0 ; null terminated
157
// string type
158
body._writeStringZ(s, dc.encoding);
159         }
160     }
161
162     /**
163      * Push a reference to string data on stack. Always attempts to intern in the string
164      * pool, so this may push a string literal or a dictionary ref.
165      *
166      * <p>
167      *
168      * This method is designed to be called when pushing references to strings
169      * which we are pretty sure will occur again, such as tag names or attribute names.
170      * We try to put them into the string pool immediately, as opposed to using the
171      * heuristic of waiting until the string is seen again before interning it.
172      *
173      * @return number of bytes written to buffer
174      */

175     static public final void pushMergedStringDataSymbol(String JavaDoc s, FlashBuffer body, DataContext dc) {
176         int idx = internString(s, dc);
177         if (idx != -1) {
178             //System.out.println("intern IDX '"+s+"'="+idx);
179
writeOffset(idx, body);
180         } else {
181             // System.out.println("intern LITERAL '"+s+"'");
182
body.writeByte(0); // type code 0 ; null terminated
183
// string type
184
body.writeStringZ(s, dc.encoding);
185         }
186     }
187
188
189     /**
190      * Push a reference to string data on stack. Attempts to intern in the string pool
191      * pool, so this may push a string literal or a dictionary ref. This routine uses the _writeXXX routines,
192      * which bypass FlashBuffer's ensureCapacity(), so the FlashBuffer must have been allocated with enough
193      * space for these writes, or an ArrayBoundsException may happen.
194      *
195      * @return number of bytes written to buffer
196      */

197     static public final void _pushMergedStringDataSymbol(String JavaDoc s, FlashBuffer body, DataContext dc) {
198         int idx = internString(s, dc);
199         if (idx != -1) {
200             //System.out.println("intern IDX '"+s+"'="+idx);
201
writeOffset(idx, body);
202         } else {
203             // System.out.println("intern LITERAL '"+s+"'");
204
body._writeByte(0); // type code 0 ; null terminated
205
// string type
206
body._writeStringZ(s, dc.encoding);
207         }
208     }
209
210
211     /**
212      * Copy data from a a byte array into a FlashBuffer
213      */

214     static public final void writeFlashData(FlashBuffer body, byte[] data, int destPos) {
215         //arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
216
byte[] buf = body.getBuf();
217         System.arraycopy(data, 0, buf, destPos, data.length);
218         body.setPos(destPos + data.length);
219     }
220
221
222     /**
223      * Return byte array containing the strings from the constant pool, sorted and zero terminated.
224      */

225     final static public byte[] makeStringPool(DataContext dc) {
226         HashIntTable pool = dc.cpool;
227         // Array for sorting
228
int nstrings = pool.size();
229         //System.out.println("makeStringPool: nstrings = "+nstrings);
230
if (nstrings > (1<<16 - 1)) {
231             throw new RuntimeException JavaDoc("more than 64k strings in constant pool");
232         }
233         String JavaDoc[] sortArray = new String JavaDoc[nstrings];
234         Enumeration keys = pool.keys();
235         int poolsize = 0;
236         // Sort strings by numerical index
237
while ( keys.hasMoreElements() ) {
238             String JavaDoc key = (String JavaDoc) keys.nextElement();
239             int v = pool.get(key);
240             //System.out.println("sorting: key="+key+", index="+v);
241
sortArray[v] = key;
242             poolsize += (getByteLength(key, dc.encoding) + 1); // account for zero terminator
243
}
244
245         byte pooldata[] = new byte[poolsize];
246         int pos = 0;
247         for (int i = 0; i < nstrings; i++) {
248             String JavaDoc s = sortArray[i];
249             //System.out.println("s="+s);
250
// Convert to byte values in the desired charset encoding
251
byte chars[];
252             try {
253                 chars = s.getBytes(dc.encoding);
254             } catch (UnsupportedEncodingException e) {
255                 chars = s.getBytes();
256             }
257             int len = chars.length;
258             //arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
259
System.arraycopy(chars, 0, pooldata, pos, len);
260             pos += len;
261             pooldata[pos++] = 0; // null terminate the string
262
}
263         return pooldata;
264     }
265
266     /**
267      * Intern a string in the constant pool.
268      * @param s the string
269      * @param dc
270      * @return offset into string pool
271      */

272     static public final int addStringConstant(String JavaDoc s, DataContext dc) {
273         int size = dc.cpool.size();
274         dc.cpool.put(s, size);
275         dc.pool_data_length += (getByteLength(s, dc.encoding) + 1);
276         return size;
277     }
278
279     /**
280      * @return the index of the string in the constant pool.
281      */

282     static public final int getStringIndex(String JavaDoc s, DataContext dc) {
283         return dc.cpool.get(s);
284     }
285         
286     /**
287      * Intern a string in the constant pool, but only if it has been seen once before.
288      * @param s the string
289      * @param dc
290      * @return the offset into string pool, or -1 if we decided not to intern it yet
291      */

292     static public final int maybeInternString(String JavaDoc s, DataContext dc) {
293         int idx = dc.cpool.get(s);
294         if (idx >= 0) {
295             return idx;
296         }
297         if (dc.pool_data_length >= 65532) {
298             return -1;
299         }
300         boolean seen = dc.cpool_first.containsKey(s);
301         if (seen) {
302             int size = dc.cpool.size();
303             // We can only have 64k of data (including zero terminators on strings)
304
dc.pool_data_length += (getByteLength(s, dc.encoding) + 1);
305             // 65536 - 4 bytes for # strings
306
if (dc.pool_data_length >= 65532) {
307                 return -1;
308             }
309             dc.cpool.put(s, size);
310             return size;
311         } else {
312             dc.cpool_first.put(s, 1);
313             return(-1);
314         }
315     }
316
317     /**
318      * Intern a string in the constant pool
319      * @param s the string
320      * @param dc
321      * @return the offset into string pool, or -1 if the string pool is full
322      */

323     static public final int internString(String JavaDoc s, DataContext dc) {
324         int idx = dc.cpool.get(s);
325         if (idx >= 0) {
326             return idx;
327         }
328         if (dc.pool_data_length >= 65532) {
329             return -1;
330         }
331         int size = dc.cpool.size();
332         // We can only have 64k of data (including zero terminators on strings)
333
dc.pool_data_length += (getByteLength(s, dc.encoding) + 1);
334         // 65536 - 4 bytes for # strings
335
if (dc.pool_data_length >= 65532) {
336             return -1;
337         }
338         dc.cpool.put(s, size);
339         return size;
340     }
341
342     /**
343      * Writes a string offset from the constant pool to a flash buffer
344      *
345      * @param o dictionary string index to write to flash buffer
346      */

347     static public final void writeOffset(int o, FlashBuffer fb) {
348         if (o > 255) {
349             fb.writeByte(9);
350             fb.writeWord(o);
351         } else {
352             fb.writeByte(8);
353             fb.writeByte(o);
354         }
355     }
356     
357
358     /**
359      * Writes a string offset from the constant pool to a flash buffer. This uses _writeXXX
360      * which bypasses the FlashBuffer ensureCapacity() check (for speed) so you must make sure
361      * the FlashBuffer is large enough to write these bytes.
362      *
363      * @param o dictionary string index to write to flash buffer
364      */

365     static public final void _writeOffset(int o, FlashBuffer fb) {
366         if (o > 255) {
367             fb._writeByte(9);
368             fb._writeWord(o);
369         } else {
370             fb._writeByte(8);
371             fb._writeByte(o);
372         }
373     }
374     
375     /**
376      * For debugging, to print out a Program as hex values.
377     */

378     
379     static public void printProgram (Program program) {
380         //program.printContent(System.out, " ");
381
FlashBuffer body = program.body();
382         byte[] buf = body.getBuf();
383         System.out.print("char data[] = {\n ");
384         for (int i=0; i < body.getSize(); i++) {
385             if (i % 10 == 0) {
386                 System.out.print("\n ");
387             }
388             if (i < buf.length-1) {
389                 System.out.print("(byte) 0x"+Integer.toHexString((buf[i]>>4 ) & 0xf) + Integer.toHexString(buf[i] & 0xf) + ", ");
390             } else {
391                 System.out.print("(byte) 0x"+Integer.toHexString((buf[i]>>4 ) & 0xf) + Integer.toHexString(buf[i] & 0xf));
392             }
393         }
394                 System.out.println("\n};");
395     }
396 }
397
398
Popular Tags