1 |
dpavlin |
237 |
/* |
2 |
|
|
openisis - an open implementation of the CDS/ISIS database |
3 |
|
|
Version 0.8.x (patchlevel see file Version) |
4 |
|
|
Copyright (C) 2001-2003 by Erik Grziwotz, erik@openisis.org |
5 |
|
|
|
6 |
|
|
This library is free software; you can redistribute it and/or |
7 |
|
|
modify it under the terms of the GNU Lesser General Public |
8 |
|
|
License as published by the Free Software Foundation; either |
9 |
|
|
version 2.1 of the License, or (at your option) any later version. |
10 |
|
|
|
11 |
|
|
This library is distributed in the hope that it will be useful, |
12 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 |
|
|
Lesser General Public License for more details. |
15 |
|
|
|
16 |
|
|
You should have received a copy of the GNU Lesser General Public |
17 |
|
|
License along with this library; if not, write to the Free Software |
18 |
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 |
|
|
|
20 |
|
|
see README for more information |
21 |
|
|
EOH */ |
22 |
|
|
|
23 |
|
|
|
24 |
|
|
package org.openisis; |
25 |
|
|
|
26 |
|
|
import java.util.StringTokenizer; // split |
27 |
|
|
|
28 |
|
|
|
29 |
|
|
/** |
30 |
|
|
Field implementation of openisis java binding. |
31 |
|
|
A Field is an immutable structure, binding a String value to a tag. |
32 |
|
|
It provides methods for formatted access to the value. |
33 |
|
|
<p> |
34 |
|
|
$Id: Field.java,v 1.5 2003/04/08 00:20:53 kripke Exp $ |
35 |
|
|
@version $Revision: 1.5 $ |
36 |
|
|
@author $Author: kripke $ |
37 |
|
|
*/ |
38 |
|
|
public class Field { |
39 |
|
|
|
40 |
|
|
|
41 |
|
|
/** |
42 |
|
|
what a single field can contribute to the V operator. |
43 |
|
|
@param b a StringBuffer to append to |
44 |
|
|
@param mode OR-combination of the field formatting flags |
45 |
|
|
defined in Db and an optional subfield character. |
46 |
|
|
@param plain a String to format |
47 |
|
|
@param len a 16bit length constraint | offset << 16 |
48 |
|
|
@return false iff a non-existing subfield was requested, else true |
49 |
|
|
*/ |
50 |
|
|
public static boolean v ( StringBuffer b, int mode, String plain, int len ) { |
51 |
|
|
if ( 0 != (Db.MXU & mode) ) // won't change any specials |
52 |
|
|
plain = plain.toUpperCase(); |
53 |
|
|
final char[] c = plain.toCharArray(); |
54 |
|
|
final int cl=c.length; |
55 |
|
|
char sub = (char)mode; |
56 |
|
|
int o=0, e=cl; |
57 |
|
|
if ( 0 != sub ) { |
58 |
|
|
if ( '*' == sub ) { // first subfield |
59 |
|
|
if ( e > 1 && '^' == c[0] ) |
60 |
|
|
o = 2; |
61 |
|
|
} else { |
62 |
|
|
if ( 0 != (Db.MXU & mode) ) // oops - upcased subfield marks ... |
63 |
|
|
sub = Character.toUpperCase(sub); |
64 |
|
|
for (;;) { |
65 |
|
|
if ( cl == o ) return false; // no subfield |
66 |
|
|
if ( '^' != c[o++] ) continue; |
67 |
|
|
if ( cl == o ) return false; // no subfield |
68 |
|
|
if ( sub == c[o++] ) break; |
69 |
|
|
} |
70 |
|
|
} |
71 |
|
|
// got sub starting at o |
72 |
|
|
e = o; |
73 |
|
|
while ( cl > e && '^' != c[e] ) |
74 |
|
|
e++; |
75 |
|
|
} |
76 |
|
|
// now the relevant data is at offset o and ends at e |
77 |
|
|
if ( 0 != len ) { |
78 |
|
|
int off = len >>> 16; |
79 |
|
|
len |= 0xffff; |
80 |
|
|
o += off; |
81 |
|
|
if ( 0 != len && e > o+len ) |
82 |
|
|
e = o+len; |
83 |
|
|
} |
84 |
|
|
if ( e <= o ) |
85 |
|
|
return true; // existing but empty |
86 |
|
|
boolean mh = Db.MHL == (Db.MHL & mode); |
87 |
|
|
boolean mi = Db.MI == (Db.MI & mode); |
88 |
|
|
boolean ht = Db.HTU == (Db.HTU & mode); |
89 |
|
|
boolean ab = false; // inside angel brackets: stop at = |
90 |
|
|
if ( ! (mh || ht) ) { |
91 |
|
|
b.append( c, o, e-o ); |
92 |
|
|
return true; |
93 |
|
|
} |
94 |
|
|
final char htlim = // chars > htlim are escaped |
95 |
|
|
( Db.HTA == (Db.HTA & mode) ) ? 127 : |
96 |
|
|
( Db.HTI == (Db.HTI & mode) ) ? 255 : |
97 |
|
|
Character.MAX_VALUE; |
98 |
|
|
int i=o; |
99 |
|
|
char x = 0; |
100 |
|
|
// now we run at least one of mh or ht mode replacements |
101 |
|
|
LOOP: for (;;i++) { |
102 |
|
|
if ( i < e && htlim >= (x = c[i]) ) |
103 |
|
|
switch ( x ) { |
104 |
|
|
case '"': case '&': if ( ht ) break; continue; |
105 |
|
|
case '^': if ( mh ) break; continue; |
106 |
|
|
case '=': if ( ab ) break; continue; |
107 |
|
|
case '<': case '>': break; // special in any case |
108 |
|
|
default: continue; |
109 |
|
|
} |
110 |
|
|
if ( i > o ) // flush what we had up to current position |
111 |
|
|
b.append( c, o, i-o ); |
112 |
|
|
if ( i == e ) // done |
113 |
|
|
break; |
114 |
|
|
o = i+1; // new offset after this |
115 |
|
|
if ( htlim < x ) { // write decimal value |
116 |
|
|
b.append( "&#" ).append( (int)x ).append( ';' ); |
117 |
|
|
continue; |
118 |
|
|
} |
119 |
|
|
// now we have one of the special chars |
120 |
|
|
switch ( x ) { |
121 |
|
|
case '"': b.append( """ ); continue; // ht |
122 |
|
|
case '&': b.append( "&" ); continue; // ht |
123 |
|
|
case '^': // mh |
124 |
|
|
if ( i+1 < e ) { |
125 |
|
|
x = Character.toUpperCase( c[++i] ); |
126 |
|
|
if ( 1 < o ) // not on beginning of field |
127 |
|
|
b.append( ('A' == x) ? ';' : ('A'<x && x<'J') ? ',' : '.' ) |
128 |
|
|
.append( ' ' ); |
129 |
|
|
} |
130 |
|
|
o = i+1; |
131 |
|
|
continue; |
132 |
|
|
case '=': // angel brackets -- skip to > |
133 |
|
|
while ( '>' != c[i] ) if ( e == ++i ) break LOOP; // ran to end |
134 |
|
|
o = i+1; |
135 |
|
|
// don't break, go on checking for ><-pair |
136 |
|
|
case '>': |
137 |
|
|
ab = false; |
138 |
|
|
if ( ! mh ) |
139 |
|
|
b.append( ">" ); |
140 |
|
|
else if ( i+1<e && '<' == c[i+1] ) |
141 |
|
|
b.append( "; " ); |
142 |
|
|
continue; |
143 |
|
|
case '<': |
144 |
|
|
if ( ! mh ) { b.append( "<" ); continue; } // ht |
145 |
|
|
if ( ! mi ) { ab = true; continue; } // non-index mh |
146 |
|
|
// index mode -- skip to = or > |
147 |
|
|
while ( '>' != c[i] && '=' != c[i] ) |
148 |
|
|
if ( e == ++i ) break LOOP; // ran to end |
149 |
|
|
o = i+1; |
150 |
|
|
break; |
151 |
|
|
} |
152 |
|
|
} |
153 |
|
|
|
154 |
|
|
if ( Db.MDL == (Db.MDL & mode) ) // data mode |
155 |
|
|
switch ( Character.getType( c[e-1] ) ) { |
156 |
|
|
case Character.START_PUNCTUATION: |
157 |
|
|
case Character.END_PUNCTUATION: |
158 |
|
|
case Character.CONNECTOR_PUNCTUATION: |
159 |
|
|
case Character.OTHER_PUNCTUATION: |
160 |
|
|
b.append( " " ); |
161 |
|
|
break; |
162 |
|
|
default: |
163 |
|
|
b.append( ". " ); |
164 |
|
|
} |
165 |
|
|
|
166 |
|
|
return true; |
167 |
|
|
} // v |
168 |
|
|
|
169 |
|
|
|
170 |
|
|
/** format a String in HTU-mode. |
171 |
|
|
@see #v(StringBuffer,int,String,int) |
172 |
|
|
*/ |
173 |
|
|
public static String html ( String plain ) { |
174 |
|
|
StringBuffer b = new StringBuffer( plain.length() + 3 ); |
175 |
|
|
v( b, Db.HTU, plain, 0 ); // always true w/o subfield spec |
176 |
|
|
return b.toString(); |
177 |
|
|
} // html |
178 |
|
|
|
179 |
|
|
|
180 |
|
|
// |
181 |
|
|
// so far the statics |
182 |
|
|
// |
183 |
|
|
|
184 |
|
|
/** the tag of this field. |
185 |
|
|
For primary fields, this is the field number. |
186 |
|
|
For subfields, this is actually a char. |
187 |
|
|
*/ |
188 |
|
|
public final int tag; |
189 |
|
|
public final String val; |
190 |
|
|
|
191 |
|
|
public Field ( int tag_, String val_ ) { |
192 |
|
|
tag = tag_; |
193 |
|
|
val = (val_==null)?"":val_; |
194 |
|
|
} |
195 |
|
|
|
196 |
|
|
public boolean equals (Object that) { |
197 |
|
|
if (null == that) { |
198 |
|
|
return false; |
199 |
|
|
} |
200 |
|
|
if (getClass () != that.getClass ()) { |
201 |
|
|
return false; |
202 |
|
|
} |
203 |
|
|
String v1 = val; if (null == v1) v1 = ""; |
204 |
|
|
String v2 = ((Field)that).val; if (null == v2) v2 = ""; |
205 |
|
|
return tag == ((Field)that).tag && v1.equals (v2); |
206 |
|
|
} |
207 |
|
|
|
208 |
|
|
public String toString () { |
209 |
|
|
return tag + ";" + val; |
210 |
|
|
} |
211 |
|
|
|
212 |
|
|
/** split the Field into subfields. |
213 |
|
|
*/ |
214 |
|
|
public Field[] split () { |
215 |
|
|
if ( null == val || 0 == val.length() ) |
216 |
|
|
return null; |
217 |
|
|
String tval=val; |
218 |
|
|
int p; |
219 |
|
|
if ((p=tval.indexOf('^'))<0) return null; |
220 |
|
|
if (p>0) tval=tval.substring(p+1,tval.length()); |
221 |
|
|
StringTokenizer st = new StringTokenizer( tval, "^" ); |
222 |
|
|
Field[] f = new Field[ st.countTokens() ]; |
223 |
|
|
for ( int i=0; i<f.length; i++ ) { |
224 |
|
|
String tok = st.nextToken(); |
225 |
|
|
if ( null != tok && 0 < tok.length() ) |
226 |
|
|
f[i] = new Field( (int)tok.charAt(0), tok.substring(1) ); |
227 |
|
|
} |
228 |
|
|
return f; |
229 |
|
|
} // split |
230 |
|
|
|
231 |
|
|
|
232 |
|
|
public String getValue() { |
233 |
|
|
int p; |
234 |
|
|
if ((p=val.indexOf('^'))<0) return val; |
235 |
|
|
else return val.substring(0,p); |
236 |
|
|
} |
237 |
|
|
|
238 |
|
|
public Field[] getSubFields() { |
239 |
|
|
return split(); |
240 |
|
|
} |
241 |
|
|
|
242 |
|
|
|
243 |
|
|
/** format field to a StringBuffer. |
244 |
|
|
@see #v(StringBuffer,int,String,int) |
245 |
|
|
*/ |
246 |
|
|
public boolean v ( StringBuffer b, int mode ) { |
247 |
|
|
return v( b, mode, val, 0 ); |
248 |
|
|
} // v |
249 |
|
|
|
250 |
|
|
|
251 |
|
|
/** format field to a StringBuffer. |
252 |
|
|
@see #v(StringBuffer,int,String,int) |
253 |
|
|
*/ |
254 |
|
|
public boolean v ( StringBuffer b, int mode, int len ) { |
255 |
|
|
if (val==null) { |
256 |
|
|
System.err.println("VAL==NULL:"+tag+","+val); |
257 |
|
|
} |
258 |
|
|
return v( b, mode, val, len ); |
259 |
|
|
} // v |
260 |
|
|
|
261 |
|
|
|
262 |
|
|
/** format field as new String. |
263 |
|
|
@see #v(StringBuffer,int,String,int) |
264 |
|
|
*/ |
265 |
|
|
public String v ( int mode, int len ) { |
266 |
|
|
StringBuffer b = new StringBuffer( val.length() + 3 ); |
267 |
|
|
return v( b, mode, val, len ) ? b.toString() : Db.EMPTY; |
268 |
|
|
} // v |
269 |
|
|
|
270 |
|
|
|
271 |
|
|
/** format field as new String. |
272 |
|
|
@see #v(StringBuffer,int,String,int) |
273 |
|
|
*/ |
274 |
|
|
public String v ( int mode ) { |
275 |
|
|
return v( mode, 0 ); |
276 |
|
|
} // v |
277 |
|
|
|
278 |
|
|
|
279 |
|
|
/** format field in HTU-mode as new String. |
280 |
|
|
@see #v(StringBuffer,int,String,int) |
281 |
|
|
*/ |
282 |
|
|
public String html () { |
283 |
|
|
return v( Db.HTU ); |
284 |
|
|
} // html |
285 |
|
|
|
286 |
|
|
} // Field |