• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /barrelfish-2018-10-04/usr/eclipseclp/JavaInterface/src/com/parctechnologies/eclipse/
1// BEGIN LICENSE BLOCK
2// Version: CMPL 1.1
3//
4// The contents of this file are subject to the Cisco-style Mozilla Public
5// License Version 1.1 (the "License"); you may not use this file except
6// in compliance with the License.  You may obtain a copy of the License
7// at www.eclipse-clp.org/license.
8//
9// Software distributed under the License is distributed on an "AS IS"
10// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
11// the License for the specific language governing rights and limitations
12// under the License.
13//
14// The Original Code is  The ECLiPSe Constraint Logic Programming System.
15// The Initial Developer of the Original Code is  Cisco Systems, Inc.
16// Portions created by the Initial Developer are
17// Copyright (C) 2000 - 2006 Cisco Systems, Inc.  All Rights Reserved.
18//
19// Contributor(s): Stefano Novello / Josh Singer, Parc Technologies
20//
21// END LICENSE BLOCK
22
23//Title:        Java/ECLiPSe interface
24//Version:      $Id: EXDRInputStream.java,v 1.1 2006/09/23 01:54:10 snovello Exp $
25//Author:       Stefano Novello / Josh Singer
26//Company:      Parc Technologies
27//Description:  InputStream which can parse ECLiPSe EXDR format.
28
29package com.parctechnologies.eclipse;
30import java.util.*;
31import java.io.*;
32
33
34
35/**
36 * A stream which can read EXDR format.
37 *
38 * An <i>EXDRInputStream</i> can be constructed from any
39 * instance of the <i>InputStream</i> class and extends it to be able to interpret
40 * incoming data which is in the EXDR (ECLiPSe eXternal Data Representation) format.
41 * <p>
42 * Use the method {@link EXDRInputStream#readTerm()} to convert from EXDR into
43 * Java <i>CompoundTerm</i> objects and instances of other relevant Java classes
44 * which represent ECLiPSe types.
45 * <p> Note that EXDRInputStream objects are often constructed using the
46 * {@link FromEclipseQueue} class.
47 * @see CompoundTerm
48 * @see FromEclipseQueue
49 *
50 */
51public class EXDRInputStream extends DataInputStream
52{
53    // note that throughout this class we use the methods of DataInputStream
54    // rather than those of the input stream in. This is because we want a
55    // blocking read (which blocks until it finishes, or raises an exception)
56    // The consequence of this is that this class' methods fulfill the same
57    // contract: they block until they are done, or they throw an exception.
58    // This is as it should be because this is a subclass of DataInputStream.
59
60    /**
61     * The following array list is used to map EXDR string references to their
62     * string value. For strings that occur repeatedly throughout the message,
63     * there is a single EXDR string representation. The remainder of the
64     * occurrences are all references to the first occurrence of the string.
65     * The array list is not synchronized. Multiple threads writing concurrently
66     * to the output stream is envisaged via the synchronized 'readTerm()'.
67     * Should this change, the array should become a Vector or wrapped:
68     * List list = Collections.synchronizedList(new ArrayList(...));
69     * An array list is used because string reference idenitifers start from 0,
70     * as a result there is not need for a map.
71     * Duplicate strings are allowed (EXDR version 2 permits reading but *not*
72     * writing of duplicates).
73     */
74    private ArrayList stringList = null;
75
76    /**
77     * Construct an <i>EXDRInputStream</i> using a given InputStream for
78     * incoming data.
79     */
80    public EXDRInputStream(InputStream in)
81    {
82        super(in);
83    }
84
85    /**
86     * Read a chunk (one term's worth) of EXDR from the incoming data and
87     * convert it into the corresponding object (an instance of CompoundTerm, Integer,
88     * etc.).
89     * This works as an atomic
90     * action so no other thread can read until the complete
91     * term has been read in.
92     */
93    synchronized public Object readTerm() throws IOException
94    {
95        // Read the first two bytes. These give the EXDR version number
96
97        int c1 = readByte();
98        int c2 = readByte();
99        if (c1 == 'V' && c2 < 3)
100        {
101            // Dispose of the hash map if it's hanging around
102            // (exception occurred etc)
103            stringList = null;
104            Object term = readSubTerm();
105            // Dispose of the hash map if created
106            stringList = null;
107
108            return term;
109        }
110        else // Throw an exception if the version bytes were incorrect
111        {
112          throw new IOException("EXDR protocol error: bad version " + c1 + " " + c2);
113        }
114    }
115
116    /**
117     * Read a term's worth of data and return a Java object of the corresponding
118     * type.
119     */
120    private Object readSubTerm() throws IOException
121    {
122        // Read the first byte, which is a capital letter that varies according
123        // to the class of data.
124        int c = readByte();
125        switch (c)
126        {
127        case 'C' : // Turn string compression on
128            stringList = new ArrayList();
129            return readSubTerm();
130        case 'B' : // for byte use method inherited from DataInputStream
131            return new Integer(readByte()); // Implicit widen
132        case 'I' : // for integers use method inherited from DataInputStream
133            return new Integer(readInt());
134        case 'J' : // for long use method inherited from DataInputStream
135            return new Long(readLong());
136        case 'D' : // for double use method inherited from DataInputStream
137            return new Double(readDouble());
138        case '_' : // for variables, return null (corresponding java representation)
139            return null;
140        case 'R' : // Retrieve the string from the string list
141            if (stringList == null) {
142                throw new IOException(
143                    "EXDR protocol error: String compression disabled, but reference found");
144            }
145            return stringList.get(readNat());
146        case 'S' : // use own method for strings
147            return readString();
148        case 'F' : // for compound terms
149            // read the arity as an integer
150          int arity = readNat();
151            // if arity is zero
152            if(arity == 0)
153            {
154              // read the next term (it will be a string), and
155              // construct and return an atom based on it.
156              return(new Atom((String) readSubTerm()));
157            }
158            // construct an array with space for the functor and subterms
159            Object res[] = new Object[arity+1];
160            // read in the functor and subterms and assign the array
161            // elements to the corresponding resulting Objects
162            for (int i = 0 ; i < arity+1 ; i++)
163                res[i] = readSubTerm();
164            // Return a CompoundTermImpl constructed from this array
165            return new CompoundTermImpl(res);
166        case '[' : // for NON-empty lists
167            // create an empty list
168            List list = new LinkedList();
169            // read and add the first element (there must be one)
170            list.add(readSubTerm());
171            while(true) // keep reading and adding elements until we reach a ']'
172            {
173                c = readByte();
174                if (c == ']') return list;
175                else if (c == '[') list.add(readSubTerm());
176                else
177                    throw new IOException("EXDR protocol error: unexpected list separator "+c);
178            }
179        case ']' : // for empty lists
180            return Collections.EMPTY_LIST;
181        default: // if no codes match, throw an exception
182            throw new IOException("EXDR protocol error: unrecognized EXDR code = "+c);
183        }
184    }
185
186    /**
187     * Read an 'XDR_nat'
188     */
189    private int readNat() throws IOException
190    {
191        // Read the first byte
192        byte a = readByte();
193
194        // If signed bit is one, the remaining 7 bits
195        // represent the value.
196        if ((a & 0x80) != 0) {
197          return (a & 0x7F);
198        }
199
200        // If signed bit is 0 it's really a
201        // four byte int, so read and construct the value
202
203        return (((a & 0xff) << 24) | ((readByte() & 0xff) << 16) |
204                ((readByte() & 0xff) << 8) | (readByte() & 0xff));
205    }
206
207    /**
208     * Read a string
209     */
210    private String readString() throws IOException
211    {
212        // create a byte buffer with length for the string
213        byte buff[] = new byte[readNat()];
214
215        // read in buff.length bytes into buff
216        readFully(buff);
217
218        // construct an intern'd String representation
219        // of 'buff'. By interning we save space for large terms
220        // with repeated strings and functors
221        String string = (new String(buff)).intern();
222
223        // Store the string in the array list for subsequent
224        // EXDR string reference resolution
225        if (stringList != null) stringList.add(string);
226
227        return string;
228    }
229}
230