1 | /*
|
---|
2 | * module: pip/java/packing -- Strategy objects for converting
|
---|
3 | * Java objects to and from stored data.
|
---|
4 | * class: QuotedVectorPacking -- Vectors of Strings packed in a Perl-
|
---|
5 | * style format
|
---|
6 | *
|
---|
7 | * Copyright (C) 1997 Pharos IP Pty Ltd
|
---|
8 | * $Id: QuotedVectorPacking.java 10737 2005-10-19 03:06:40Z kjdon $
|
---|
9 | *
|
---|
10 | * This program is free software; you can redistribute it and/or modify
|
---|
11 | * it under the terms of the GNU General Public License as published by
|
---|
12 | * the Free Software Foundation; either version 2 of the License, or
|
---|
13 | * (at your option) any later version.
|
---|
14 | *
|
---|
15 | * This program is distributed in the hope that it will be useful,
|
---|
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
18 | * GNU General Public License for more details.
|
---|
19 | *
|
---|
20 | * You should have received a copy of the GNU General Public License
|
---|
21 | * along with this program; if not, write to the Free Software
|
---|
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
---|
23 | */
|
---|
24 |
|
---|
25 | package au.com.pharos.packing;
|
---|
26 |
|
---|
27 | import java.util.Vector;
|
---|
28 |
|
---|
29 | // FIXME: Escape bad characters! -- mbp
|
---|
30 | // TODO: Write a more formal definition of the encoding system
|
---|
31 | // TODO: More documentation
|
---|
32 |
|
---|
33 | // XXX: Perhaps the strategy for encoding characters should be in a
|
---|
34 | // separate class used by this class? They would have to
|
---|
35 | // interact to make sure that separator chatacters were decoded
|
---|
36 | // properly. Probably not worth worrying about, as this class
|
---|
37 | // is only a compatibility measure in any case.
|
---|
38 |
|
---|
39 | /** Stores Vectors of strings, packed into a single string, as used by
|
---|
40 | * some Perl code. The encoding format is similar to that used in
|
---|
41 | * Unix databases like
|
---|
42 | * <A HREF="file:/etc/passwd/"><CODE>/etc/passwd</CODE></A>, except that
|
---|
43 | * it uses escape sequences to represent characters that would
|
---|
44 | * normally not be allowed.
|
---|
45 | *
|
---|
46 | * <P>The strings within the vector are separated by separator characters,
|
---|
47 | * which default to colons.
|
---|
48 | *
|
---|
49 | * <P>The resulting packed string is UTF encoded after escaping
|
---|
50 | * control-characters, so non-ASCII characters should be passed through
|
---|
51 | * unchanged.
|
---|
52 | *
|
---|
53 | * <P>Certain characters are escaped as quoted-printable strings.
|
---|
54 | * These characters include colon, equals, and escape characters. The
|
---|
55 | * encoding accepts and interprets any hex escape when reading data.
|
---|
56 | *
|
---|
57 | * <P>If any elements of the vector are null, they are stored as empty
|
---|
58 | * strings. On unpacking, empty strings are returned as such.
|
---|
59 | *
|
---|
60 | * <P>An example of a vector encoded in this manner is:
|
---|
61 | * <BLOCKQUOTE>
|
---|
62 | * <PRE>oC7okz059wGnQ:vf:Peter Barnes%2c Pharos Business Solutions</PRE>
|
---|
63 | * </BLOCKQUOTE>
|
---|
64 | *
|
---|
65 | * @author Martin Pool
|
---|
66 | * @version $Revision: 10737 $ $Date: 2005-10-19 03:06:40 +0000 (Wed, 19 Oct 2005) $
|
---|
67 | *
|
---|
68 | * @see java.util.Vector
|
---|
69 | **/
|
---|
70 | public class QuotedVectorPacking extends Packing
|
---|
71 | implements java.io.Serializable
|
---|
72 | {
|
---|
73 | private char hexEscape;
|
---|
74 | private char separator;
|
---|
75 |
|
---|
76 | /** Constructs a QuotedVectorPacking using the default separator
|
---|
77 | * character ':' and escape character '%'.
|
---|
78 | **/
|
---|
79 | public QuotedVectorPacking() {
|
---|
80 | this('%', ':');
|
---|
81 | }
|
---|
82 |
|
---|
83 |
|
---|
84 | /** Constructs a QuotedVectorPacking with specified separator and
|
---|
85 | * hex-escape characters.
|
---|
86 | *
|
---|
87 | * @param hexEscape the character used to begin a three-character
|
---|
88 | * hex escape
|
---|
89 | *
|
---|
90 | * @param separator the character used to separate elements in the
|
---|
91 | * vector.
|
---|
92 | **/
|
---|
93 | public QuotedVectorPacking(char hexEscape, char separator) {
|
---|
94 | if (hexEscape == separator)
|
---|
95 | throw new IllegalArgumentException
|
---|
96 | ("hexEscape and separator characters are the same");
|
---|
97 | this.hexEscape = hexEscape;
|
---|
98 | this.separator = separator;
|
---|
99 | }
|
---|
100 |
|
---|
101 |
|
---|
102 | /** Convert a Vector of Strings to a QuotedVector represented as an
|
---|
103 | * array of bytes.
|
---|
104 | *
|
---|
105 | * @param obj the Vector to encode; or null.
|
---|
106 | *
|
---|
107 | * @returns an array of bytes containing a packed representation of
|
---|
108 | * <EM>obj</EM>; or null if <EM>obj</EM> is null.
|
---|
109 | *
|
---|
110 | * @exception java.lang.ClassCastException if obj is not a Vector
|
---|
111 | * or null; or if any element of <EM>obj</EM> is not a String or
|
---|
112 | * null.
|
---|
113 | **/
|
---|
114 | public byte[] toBytes(Object obj)
|
---|
115 | {
|
---|
116 | if (obj == null)
|
---|
117 | return null;
|
---|
118 | Vector vec = (Vector) obj;
|
---|
119 | StringBuffer sb = new StringBuffer();
|
---|
120 | Object elem;
|
---|
121 | for (int i = 0; i < vec.size(); i++) {
|
---|
122 | if (i > 0)
|
---|
123 | sb.append(separator);
|
---|
124 | elem = vec.elementAt(i);
|
---|
125 | sb.append((elem == null) ? "" : encodeString((String) elem));
|
---|
126 | }
|
---|
127 | return sb.toString().getBytes();
|
---|
128 | }
|
---|
129 |
|
---|
130 |
|
---|
131 |
|
---|
132 | /** Perform hex-escapes on a string.
|
---|
133 | * @returns <EM>from</EM> encoded as a quoted-printable string
|
---|
134 | **/
|
---|
135 | private String encodeString(String from) {
|
---|
136 | StringBuffer buf = new StringBuffer(from.length());
|
---|
137 | char[] chars = from.toCharArray();
|
---|
138 | for (int i = 0; i < chars.length; i++) {
|
---|
139 | char ch = chars[i];
|
---|
140 | if (ch == separator
|
---|
141 | || ch == hexEscape
|
---|
142 | || Character.isISOControl(ch)
|
---|
143 | || (ch != ' ' && ch != '\t' && Character.isWhitespace(ch)))
|
---|
144 | {
|
---|
145 | buf.append(hexEscape);
|
---|
146 | // XXX: This will truncate high Unicode characters, but I
|
---|
147 | // don't know what else we can do with them. -- mbp
|
---|
148 | buf.append(Character.forDigit((ch>>4) & 0xf, 16));
|
---|
149 | buf.append(Character.forDigit(ch & 0xf, 16));
|
---|
150 | } else {
|
---|
151 | buf.append(ch);
|
---|
152 | }
|
---|
153 | }
|
---|
154 | return buf.toString();
|
---|
155 | }
|
---|
156 |
|
---|
157 |
|
---|
158 |
|
---|
159 | /** Interprets <em>raw</em> as a packed quoted Vector, and
|
---|
160 | * returns the unpacked Vector of strings. */
|
---|
161 | public Object fromBytes(byte[] raw)
|
---|
162 | {
|
---|
163 | if (raw == null)
|
---|
164 | return null;
|
---|
165 |
|
---|
166 | Vector result = new Vector();
|
---|
167 | StringBuffer sb = new StringBuffer();
|
---|
168 | for (int i = 0; i < raw.length; i++) {
|
---|
169 | char ch = (char) raw[i];
|
---|
170 | if (ch == separator) {
|
---|
171 | result.addElement(sb.toString());
|
---|
172 | sb.setLength(0);
|
---|
173 | } else if (ch == hexEscape && i < (raw.length - 2)) {
|
---|
174 | byte[] hexBytes = new byte[2];
|
---|
175 | hexBytes[0] = raw[++i];
|
---|
176 | hexBytes[1] = raw[++i];
|
---|
177 | String hex = new String(hexBytes);
|
---|
178 | ch = (char)Integer.parseInt(hex, 16);
|
---|
179 | sb.append(ch);
|
---|
180 | } else {
|
---|
181 | sb.append(ch);
|
---|
182 | }
|
---|
183 | }
|
---|
184 | result.addElement(sb.toString());
|
---|
185 | return result;
|
---|
186 | }
|
---|
187 | }
|
---|