From e3efaf2a9ad82deb1644ccab8c1469719a0c5b65 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Mon, 16 Jan 2012 02:31:34 +0000 Subject: Lots of documentation, an example program, and also some visibility cleanup. --- java/com/xagasoft/gats/GatsBoolean.java | 20 ++++- java/com/xagasoft/gats/GatsDictionary.java | 96 +++++++++++++++++++---- java/com/xagasoft/gats/GatsFloat.java | 8 +- java/com/xagasoft/gats/GatsInputStream.java | 110 ++++++--------------------- java/com/xagasoft/gats/GatsInteger.java | 17 ++++- java/com/xagasoft/gats/GatsList.java | 78 ++++++++++--------- java/com/xagasoft/gats/GatsObject.java | 30 +++++++- java/com/xagasoft/gats/GatsOutputStream.java | 32 ++++++++ java/com/xagasoft/gats/GatsString.java | 15 +++- java/com/xagasoft/package-info.java | 44 +++++++++++ 10 files changed, 302 insertions(+), 148 deletions(-) create mode 100644 java/com/xagasoft/package-info.java (limited to 'java/com/xagasoft') diff --git a/java/com/xagasoft/gats/GatsBoolean.java b/java/com/xagasoft/gats/GatsBoolean.java index 472db00..7e5d217 100644 --- a/java/com/xagasoft/gats/GatsBoolean.java +++ b/java/com/xagasoft/gats/GatsBoolean.java @@ -3,24 +3,40 @@ package com.xagasoft.gats; import java.io.InputStream; import java.io.OutputStream; +/** + * Represents a boolean value. This is probably the simplest of all Gats + * objects. It can be true or false. + */ public class GatsBoolean extends GatsObject { private boolean bValue = false; + /** + * Construct a new GatsBoolean, the default value is false. + */ public GatsBoolean() { } + /** + * Construct a new GatsBoolean, specify the value.; + */ public GatsBoolean( boolean bValue ) { this.bValue = bValue; } + /** + * Get the current value, either true or false. + */ public boolean getValue() { return bValue; } + /** + * Set the value. + */ public void setValue( boolean bValue ) { this.bValue = bValue; @@ -36,7 +52,7 @@ public class GatsBoolean extends GatsObject return "" + bValue; } - public void read( InputStream is, char cType ) throws java.io.IOException + void read( InputStream is, char cType ) throws java.io.IOException { if( cType == '0' ) bValue = false; @@ -44,7 +60,7 @@ public class GatsBoolean extends GatsObject bValue = true; } - public void write( OutputStream os ) throws java.io.IOException + void write( OutputStream os ) throws java.io.IOException { if( bValue ) os.write( (int)'1' ); diff --git a/java/com/xagasoft/gats/GatsDictionary.java b/java/com/xagasoft/gats/GatsDictionary.java index 0ad4c78..654dc6c 100644 --- a/java/com/xagasoft/gats/GatsDictionary.java +++ b/java/com/xagasoft/gats/GatsDictionary.java @@ -7,6 +7,21 @@ import java.util.Map; import java.util.Set; import java.util.Hashtable; +/** + * Gats dictionary, or hashtable. This stores any number of items, keyed with + * strings. The values can be any valid com.xagasoft.gats.GatsObject decendant + * object. This class is often used as the root of complex Gats structures. + *

+ * This class implements all standard java Map interface features but contains + * additional helper functions to make inserting and extracting values from the + * dictionary much easier, please see the extra get / put functions for more + * information. + *

+ * Keys are stored as GatsStrings in the end, but are plain Java strings until + * encoding occurs to make use easier. This means that using extended + * characters in the strings may be dangerous. In a future version, the keys + * may have to be encoded in UTF-8 which will solve this problem. + */ public class GatsDictionary extends GatsObject implements Map { private Hashtable hValue = @@ -21,7 +36,7 @@ public class GatsDictionary extends GatsObject implements Map return GatsObject.DICTIONARY; } - public void read( InputStream is, char cType ) throws java.io.IOException + void read( InputStream is, char cType ) throws java.io.IOException { for(;;) { @@ -34,7 +49,7 @@ public class GatsDictionary extends GatsObject implements Map } } - public void write( OutputStream os ) throws java.io.IOException + void write( OutputStream os ) throws java.io.IOException { os.write( (int)'d' ); for( String sKey : hValue.keySet() ) @@ -55,14 +70,14 @@ public class GatsDictionary extends GatsObject implements Map hValue.clear(); } - public boolean containsKey( Object arg0 ) + public boolean containsKey( Object key ) { - return hValue.containsKey( arg0 ); + return hValue.containsKey( key ); } - public boolean containsValue( Object arg0 ) + public boolean containsValue( Object value ) { - return hValue.containsValue( arg0 ); + return hValue.containsValue( value ); } public Set> entrySet() @@ -70,9 +85,9 @@ public class GatsDictionary extends GatsObject implements Map return hValue.entrySet(); } - public GatsObject get( Object arg0 ) + public GatsObject get( Object key ) { - return hValue.get( arg0 ); + return hValue.get( key ); } public boolean isEmpty() @@ -85,70 +100,121 @@ public class GatsDictionary extends GatsObject implements Map return hValue.keySet(); } - public GatsObject put( String arg0, GatsObject arg1 ) + public GatsObject put( String key, GatsObject value ) { - return hValue.put( arg0, arg1 ); + return hValue.put( key, value ); } + /** + * Helper function that inserts a new com.xagasoft.gats.GatsInteger with + * the value val. + */ public GatsObject put( String key, long val ) { return hValue.put( key, new GatsInteger( val ) ); } + /** + * Helper function that inserts a new com.xagasoft.gats.GatsFloat with the + * value val. + */ public GatsObject put( String key, double val ) { return hValue.put( key, new GatsFloat( val ) ); } + /** + * Helper function that inserts a new com.xagasoft.gats.GatsBoolean with the + * value val. + */ public GatsObject put( String key, boolean val ) { return hValue.put( key, new GatsBoolean( val ) ); } + /** + * Helper function that inserts a new com.xagasoft.gats.GatsString with the + * value val. + */ public GatsObject put( String key, String val ) { return hValue.put( key, new GatsString( val ) ); } + /** + * Helper function that gets the specified GatsObject, casts it to a + * com.xagasoft.gats.GatsInteger and extracts the value from it. If the + * key specified does not appear in the GatsDictionary or is not the correct + * type you will get the expected exception. + */ public long getInt( String key ) { return ((GatsInteger)hValue.get( key )).getValue(); } + /** + * Helper function that gets the specified GatsObject, casts it to a + * com.xagasoft.gats.GatsFloat and extracts the value from it. If the + * key specified does not appear in the GatsDictionary or is not the correct + * type you will get the expected exception. + */ public double getFloat( String key ) { return ((GatsFloat)hValue.get( key )).getValue(); } + /** + * Helper function that gets the specified GatsObject, casts it to a + * com.xagasoft.gats.GatsBool and extracts the value from it. If the + * key specified does not appear in the GatsDictionary or is not the correct + * type you will get the expected exception. + */ public boolean getBool( String key ) { return ((GatsBoolean)hValue.get( key )).getValue(); } + /** + * Helper function that gets the specified GatsObject, casts it to a + * com.xagasoft.gats.GatsString and extracts the value from it. If the + * key specified does not appear in the GatsDictionary or is not the correct + * type you will get the expected exception. + */ public byte[] getString( String key ) { return ((GatsString)hValue.get( key )).getValue(); } + /** + * Helper function that gets the specified GatsObject, casts it to a + * com.xagasoft.gats.GatsDictionary and returns it. If the + * key specified does not appear in the GatsDictionary or is not the correct + * type you will get the expected exception. + */ public GatsDictionary getDict( String key ) { return (GatsDictionary)hValue.get( key ); } + /** + * Helper function that gets the specified GatsObject, casts it to a + * com.xagasoft.gats.GatsList and returns it. If the + * key specified does not appear in the GatsDictionary or is not the correct + * type you will get the expected exception. + */ public GatsList getList( String key ) { return (GatsList)hValue.get( key ); } - - public void putAll( Map arg0 ) + public void putAll( Map src ) { - hValue.putAll( arg0 ); + hValue.putAll( src ); } - public GatsObject remove( Object arg0 ) + public GatsObject remove( Object key ) { - return hValue.remove( arg0 ); + return hValue.remove( key ); } public int size() diff --git a/java/com/xagasoft/gats/GatsFloat.java b/java/com/xagasoft/gats/GatsFloat.java index d70f910..3d7583e 100644 --- a/java/com/xagasoft/gats/GatsFloat.java +++ b/java/com/xagasoft/gats/GatsFloat.java @@ -7,6 +7,10 @@ import java.io.ByteArrayOutputStream; import java.lang.Math; +/** + * Represents a simple java double value. This does not represent an arbitrary + * precision floating point number, a class to handle that is forthcoming. + */ public class GatsFloat extends GatsObject { double dValue = 0.0; @@ -40,7 +44,7 @@ public class GatsFloat extends GatsObject return GatsObject.FLOAT; } - public void read( InputStream is, char cType ) throws java.io.IOException + void read( InputStream is, char cType ) throws java.io.IOException { if( cType == 'F' ) { @@ -83,7 +87,7 @@ public class GatsFloat extends GatsObject } } - public void write( OutputStream os ) throws java.io.IOException + void write( OutputStream os ) throws java.io.IOException { if( dValue == 0.0 ) { diff --git a/java/com/xagasoft/gats/GatsInputStream.java b/java/com/xagasoft/gats/GatsInputStream.java index 5cd830d..2417018 100644 --- a/java/com/xagasoft/gats/GatsInputStream.java +++ b/java/com/xagasoft/gats/GatsInputStream.java @@ -1,14 +1,32 @@ package com.xagasoft.gats; import java.io.InputStream; -import java.io.ByteArrayOutputStream; -import java.io.ByteArrayInputStream; import java.io.DataInputStream; +/** + * Facilitates reading GatsObjects from an InputStream. This doesn't really + * inherit from InputStream, so maybe it would make more sense to call it + * something else. Use the readObject function to read an entire object from + * the InputStream. + *

+ * At the moment this class will require all data to be available in continuous + * read operations from teh provided InputStream. This means that only complete + * packets can be read from files on the disk, or that if a socket is provided + * it is in blocking or synchronous I/O mode. In java, this should rarely be + * an issue. + *

+ * Each call to readObject returns a new GatsObject read from the InputStream or + * null if nothing else could be read. While reading, all zero bytes discovered + * in between packets will be considered padding and will be ignored. + *

+ * Like with the GatsOutputStream, there are generally many small reads + * performed during a single readObject operation, so it is a good idea to + * provide some sort of buffered input stream. + *@see com.xagasoft.gats.GatsOutputStream + */ public class GatsInputStream { private InputStream is; - private ByteArrayOutputStream baos = new ByteArrayOutputStream(); private int iVer = 0; private int iSize; @@ -17,6 +35,9 @@ public class GatsInputStream this.is = is; } + /** + * Reads an object from the input and returns it. + */ public GatsObject readObject() throws java.io.IOException { do @@ -34,88 +55,5 @@ public class GatsInputStream return null; } - - /* - public GatsObject readObject() throws java.io.IOException - { - do - { - if( baos.size() < 5 ) - { - byte aBuf[] = new byte[5-baos.size()]; - int iRead = is.read( aBuf ); - baos.write( aBuf, 0, iRead ); - - if( baos.size() < 5 ) - return null; - } - } while( !skipReadNulls() ); - - if( iVer == 0 ) - { - ByteArrayInputStream bais = new ByteArrayInputStream( - baos.toByteArray() - ); - DataInputStream dis = new DataInputStream( bais ); - iVer = dis.readUnsignedByte(); - iSize = dis.readInt(); - } - - byte aBuf[] = new byte[1500]; - while( baos.size() < iSize ) - { - int iGoal = iSize-baos.size(); - if( iGoal > 1500 ) - iGoal = 1500; - - int iRead = is.read( aBuf, 0, iGoal ); - baos.write( aBuf, 0, iRead ); - - if( iRead < iGoal ) - return null; - } - - if( baos.size() < iSize ) - return null; - - byte aTmp[] = baos.toByteArray(); - ByteArrayInputStream bais = new ByteArrayInputStream( - aTmp - ); - bais.skip( 5 ); - - GatsObject goRet = GatsObject.read( bais ); - - baos.reset(); - baos.write( aTmp, iSize, aTmp.length-iSize ); - - iVer = 0; - - return goRet; - } - - private boolean skipReadNulls() - { - if( baos.size() == 0 ) - return false; - - byte aBuf[] = baos.toByteArray(); - if( aBuf[0] != 0 ) - return true; - - for( int j = 1; j < aBuf.length; j++ ) - { - if( aBuf[j] != 0 ) - { - baos.reset(); - baos.write( aBuf, j, aBuf.length-j ); - return true; - } - } - - baos.reset(); - return true; - } - */ }; diff --git a/java/com/xagasoft/gats/GatsInteger.java b/java/com/xagasoft/gats/GatsInteger.java index 139e8ab..0ea5122 100644 --- a/java/com/xagasoft/gats/GatsInteger.java +++ b/java/com/xagasoft/gats/GatsInteger.java @@ -3,6 +3,10 @@ package com.xagasoft.gats; import java.io.OutputStream; import java.io.InputStream; +/** + * Represents a simple java long value. This does not handle arbitrary + * precision integer values, a class to handle that is forthcoming. + */ public class GatsInteger extends GatsObject { private long iValue = 0; @@ -36,19 +40,23 @@ public class GatsInteger extends GatsObject return GatsObject.INTEGER; }; - public void read( InputStream is, char cType ) throws java.io.IOException + void read( InputStream is, char cType ) throws java.io.IOException { iValue = readPackedInt( is ); } - public void write( OutputStream os ) throws java.io.IOException + void write( OutputStream os ) throws java.io.IOException { os.write( (int)'i' ); writePackedInt( os, iValue ); } /** + * This is a general helper function used by several parts of the Gats + * system. + * It reads a "packed integer" from the given input stream, and returns the + * value. * Possible TODO: have this return a Number, and construct either a Long * or BigInteger when appropriate. */ @@ -72,6 +80,11 @@ public class GatsInteger extends GatsObject return rOut; } + /** + * This is a general helper function used by several parts of the Gats + * system. + * It writes a "packed integer" to the given output stream. + */ public static void writePackedInt( OutputStream os, long iIn ) throws java.io.IOException { int b; diff --git a/java/com/xagasoft/gats/GatsList.java b/java/com/xagasoft/gats/GatsList.java index 35b2a4c..27c4c11 100644 --- a/java/com/xagasoft/gats/GatsList.java +++ b/java/com/xagasoft/gats/GatsList.java @@ -10,6 +10,12 @@ import java.util.List; import java.util.LinkedList; import java.util.ListIterator; +/** + * Represents an ordered list of Gats objects. The order of the objects in the + * list is always preserved, unlike the values in a + * com.xagasoft.gats.GatsDictionary. This class implements all java List + * interface features, and is implemented internally as a LinkedList. + */ public class GatsList extends GatsObject implements List { private LinkedList lValue = new LinkedList(); @@ -28,7 +34,7 @@ public class GatsList extends GatsObject implements List return GatsObject.LIST; } - public void read( InputStream is, char cType ) throws java.io.IOException + void read( InputStream is, char cType ) throws java.io.IOException { for(;;) { @@ -39,7 +45,7 @@ public class GatsList extends GatsObject implements List } } - public void write( OutputStream os ) throws java.io.IOException + void write( OutputStream os ) throws java.io.IOException { os.write( (int)'l' ); for( GatsObject obj : this ) @@ -54,24 +60,24 @@ public class GatsList extends GatsObject implements List return lValue.toString(); } - public boolean add( GatsObject arg0 ) + public boolean add( GatsObject value ) { - return lValue.add( arg0 ); + return lValue.add( value ); } - public void add( int arg0, GatsObject arg1 ) + public void add( int iPos, GatsObject value ) { - lValue.add( arg0, arg1 ); + lValue.add( iPos, value ); } - public boolean addAll( Collection arg0 ) + public boolean addAll( Collection src ) { - return lValue.addAll( arg0 ); + return lValue.addAll( src ); } - public boolean addAll( int arg0, Collection arg1 ) + public boolean addAll( int iPos, Collection src ) { - return lValue.addAll( arg0, arg1 ); + return lValue.addAll( iPos, src ); } public void clear() @@ -79,24 +85,24 @@ public class GatsList extends GatsObject implements List lValue.clear(); } - public boolean contains( Object arg0 ) + public boolean contains( Object value ) { - return lValue.contains( arg0 ); + return lValue.contains( value ); } - public boolean containsAll( Collection arg0 ) + public boolean containsAll( Collection src ) { - return lValue.containsAll( arg0 ); + return lValue.containsAll( src ); } - public GatsObject get( int arg0 ) + public GatsObject get( int iPos ) { - return lValue.get( arg0 ); + return lValue.get( iPos ); } - public int indexOf( Object arg0 ) + public int indexOf( Object value ) { - return lValue.indexOf( arg0 ); + return lValue.indexOf( value ); } public boolean isEmpty() @@ -109,9 +115,9 @@ public class GatsList extends GatsObject implements List return lValue.iterator(); } - public int lastIndexOf( Object arg0 ) + public int lastIndexOf( Object value ) { - return lValue.lastIndexOf( arg0 ); + return lValue.lastIndexOf( value ); } public ListIterator listIterator() @@ -119,34 +125,34 @@ public class GatsList extends GatsObject implements List return lValue.listIterator(); } - public ListIterator listIterator( int arg0 ) + public ListIterator listIterator( int iPos ) { - return lValue.listIterator( arg0 ); + return lValue.listIterator( iPos ); } - public GatsObject remove( int arg0 ) + public GatsObject remove( int iPos ) { - return lValue.remove( arg0 ); + return lValue.remove( iPos ); } - public boolean remove( Object arg0 ) + public boolean remove( Object value ) { - return lValue.remove( arg0 ); + return lValue.remove( value ); } - public boolean removeAll( Collection arg0 ) + public boolean removeAll( Collection src ) { - return lValue.removeAll( arg0 ); + return lValue.removeAll( src ); } - public boolean retainAll( Collection arg0 ) + public boolean retainAll( Collection src ) { - return lValue.retainAll( arg0 ); + return lValue.retainAll( src ); } - public GatsObject set( int arg0, GatsObject arg1 ) + public GatsObject set( int iPos, GatsObject src ) { - return lValue.set( arg0, arg1 ); + return lValue.set( iPos, src ); } public int size() @@ -154,9 +160,9 @@ public class GatsList extends GatsObject implements List return lValue.size(); } - public List subList( int arg0, int arg1 ) + public List subList( int iBegin, int iEnd ) { - return new GatsList( lValue.subList( arg0, arg1 ) ); + return new GatsList( lValue.subList( iBegin, iEnd ) ); } public Object[] toArray() @@ -164,9 +170,9 @@ public class GatsList extends GatsObject implements List return lValue.toArray(); } - public T[] toArray( T[] arg0 ) + public T[] toArray( T[] src ) { - return lValue.toArray( arg0 ); + return lValue.toArray( src ); } }; diff --git a/java/com/xagasoft/gats/GatsObject.java b/java/com/xagasoft/gats/GatsObject.java index 8c398e8..fc3fb5a 100644 --- a/java/com/xagasoft/gats/GatsObject.java +++ b/java/com/xagasoft/gats/GatsObject.java @@ -3,6 +3,13 @@ package com.xagasoft.gats; import java.io.InputStream; import java.io.OutputStream; +/** + * The abstract base class of all Gats storage classes. You probably don't + * need to worry about these functions at all, maybe getType. The IO functions + * in this class shouldn't really be used since they won't contain the proper + * packet header info. See com.xagasoft.gats.GatsOutputStream and + * com.xagasoft.gats.GatsInputStream for that. + */ public abstract class GatsObject { public final static int INTEGER = 1; @@ -12,12 +19,29 @@ public abstract class GatsObject public final static int DICTIONARY = 5; public final static int BOOLEAN = 6; + /** + * Gets the type of the current object, type can be one of INTEGER, FLOAT, + * STRING, LIST, DICTIONARY, or BOOLEAN. + */ public abstract int getType(); - public abstract void read( InputStream is, char cType ) throws java.io.IOException; - public abstract void write( OutputStream os ) throws java.io.IOException; + /** + * Read an object from the given input stream, with a particular type, this + * function is used internally. + */ + abstract void read( InputStream is, char cType ) throws java.io.IOException; - public static GatsObject read( InputStream is ) throws java.io.IOException + /** + * Write the current object to the output stream. + */ + abstract void write( OutputStream os ) throws java.io.IOException; + + /** + * Static function that returns a new object deserialized from an input + * stream. This still doesn't take advantage of packet data, so you + * probably shouldn't use this yourself. + */ + static GatsObject read( InputStream is ) throws java.io.IOException { char type = (char)is.read(); GatsObject goRet = null; diff --git a/java/com/xagasoft/gats/GatsOutputStream.java b/java/com/xagasoft/gats/GatsOutputStream.java index a0f4503..c67d345 100644 --- a/java/com/xagasoft/gats/GatsOutputStream.java +++ b/java/com/xagasoft/gats/GatsOutputStream.java @@ -4,6 +4,34 @@ import java.io.OutputStream; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; +/** + * Facilitates writing GatsObjects to an OutputStream. This doesn't really + * inherit from OutputStream, so maybe it would make more sense to call it + * something else, but this is how it is right now. Use the writeObject + * function to write any given GatsObject to the OutputStream. + *

+ * Each time you write an object with this class it actually writes a Gats + * Packet data structure which consists of a 5 byte header followed by the + * encoded GatsObject data. In the packet header is information about which + * version of gats is in use, which options are enabled, etc. This ensures + * that Gats is backward compatible. + *

+ * According to the GATS standard only fully formed gats packets may be written + * to files or sockets to ensure integrity and context. Since each packet can + * only contain one GatsObject that means that each writeObject call should + * write one fully formed message or data structure to ensure maximum + * efficiency. + *

+ * The OutputStream is written to frequently, and often in small increments, so + * it is highly advisable to pass in a BufferedOutputStream or similar structure + * to ensure maximum performance. + *

+ * The gats format stipulates that all zero bytes found in between packets are + * simply ignored, which allows you to pad streams of sequential gats objects + * if necesarry. This can be handy in some encoding/compression/encryption + * schemes. + *@see com.xagasoft.gats.GatsInputStream + */ public class GatsOutputStream { private OutputStream os; @@ -13,6 +41,10 @@ public class GatsOutputStream this.os = os; } + /** + * Write an object to the provided output stream. + *@return The total number of bytes written. + */ public int writeObject( GatsObject obj ) throws java.io.IOException { ByteArrayOutputStream bos1 = new ByteArrayOutputStream(); diff --git a/java/com/xagasoft/gats/GatsString.java b/java/com/xagasoft/gats/GatsString.java index e512ade..e119aec 100644 --- a/java/com/xagasoft/gats/GatsString.java +++ b/java/com/xagasoft/gats/GatsString.java @@ -3,6 +3,17 @@ package com.xagasoft.gats; import java.io.InputStream; import java.io.OutputStream; +/** + * Represents a Gats string, that is, a string of 8-bit bytes. Unlike the + * standard Java string, a Gats string is a string of 8-bit bytes, not 16-bit + * UCS characters. If you want to transmit textual data, we highly recommend + * encoding it into UTF-8. You can do this by constructing a GatsString from + * a java string thusly: new GatsString( myStr.getBytes("UTF8") ) + *

+ * If you pass a java string into a GatsString instead of an array of bytes it + * will simply call the getBytes function. This may not be what you want in + * many cases, but will work great for simple cases. + */ public class GatsString extends GatsObject { private byte[] aValue = null; @@ -46,14 +57,14 @@ public class GatsString extends GatsObject return GatsObject.STRING; } - public void read( InputStream is, char cType ) throws java.io.IOException + void read( InputStream is, char cType ) throws java.io.IOException { long lSize = GatsInteger.readPackedInt( is ); aValue = new byte[(int)lSize]; is.read( aValue ); } - public void write( OutputStream os ) throws java.io.IOException + void write( OutputStream os ) throws java.io.IOException { os.write( (int)'s' ); if( aValue == null ) diff --git a/java/com/xagasoft/package-info.java b/java/com/xagasoft/package-info.java new file mode 100644 index 0000000..bcc033d --- /dev/null +++ b/java/com/xagasoft/package-info.java @@ -0,0 +1,44 @@ +/** + * The Generalized Agile Transport System. + * + * This package contains interfaces for working with GATS. GATS is used to + * serialize data structures to and from storage as well as over the network. + *

+ * GATS has a number of advantages over other systems for doing serialization. + *

+ * + * GATS uses a structed, generalized data structure for storing data which + * supports the following datatypes: + * + * + * Please see {@link com.xagasoft.gats.GatsOutputStream} for more information + * about how GATS is encoded. + * + *@author Mike Buland + */ +package com.xagasoft.gats; -- cgit v1.2.3