1 | /**
|
---|
2 | *#########################################################################
|
---|
3 | *
|
---|
4 | * A component of the Gatherer application, part of the Greenstone digital
|
---|
5 | * library suite from the New Zealand Digital Library Project at the
|
---|
6 | * University of Waikato, New Zealand.
|
---|
7 | *
|
---|
8 | * <BR><BR>
|
---|
9 | *
|
---|
10 | * Author: John Thompson, Greenstone Digital Library, University of Waikato
|
---|
11 | *
|
---|
12 | * <BR><BR>
|
---|
13 | *
|
---|
14 | * Copyright (C) 1999 New Zealand Digital Library Project
|
---|
15 | *
|
---|
16 | * <BR><BR>
|
---|
17 | *
|
---|
18 | * This program is free software; you can redistribute it and/or modify
|
---|
19 | * it under the terms of the GNU General Public License as published by
|
---|
20 | * the Free Software Foundation; either version 2 of the License, or
|
---|
21 | * (at your option) any later version.
|
---|
22 | *
|
---|
23 | * <BR><BR>
|
---|
24 | *
|
---|
25 | * This program is distributed in the hope that it will be useful,
|
---|
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
28 | * GNU General Public License for more details.
|
---|
29 | *
|
---|
30 | * <BR><BR>
|
---|
31 | *
|
---|
32 | * You should have received a copy of the GNU General Public License
|
---|
33 | * along with this program; if not, write to the Free Software
|
---|
34 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
---|
35 | *########################################################################
|
---|
36 | */
|
---|
37 | package org.greenstone.gatherer.util;
|
---|
38 |
|
---|
39 | import java.awt.*;
|
---|
40 | import java.io.*;
|
---|
41 | import java.net.*;
|
---|
42 | import java.util.*;
|
---|
43 | import java.util.zip.*;
|
---|
44 | import javax.swing.*;
|
---|
45 | import javax.swing.tree.*;
|
---|
46 | import org.apache.xerces.parsers.*;
|
---|
47 | import org.apache.xml.serialize.*;
|
---|
48 | import org.greenstone.gatherer.Configuration;
|
---|
49 | import org.greenstone.gatherer.DebugStream;
|
---|
50 | import org.greenstone.gatherer.Dictionary;
|
---|
51 | // Don't even think about adding import org.greenstone.gatherer.Gatherer in here!
|
---|
52 | // The functions in this class should be independent of the Gatherer class. Put your function somewhere else buster!
|
---|
53 | import org.w3c.dom.*;
|
---|
54 | import org.xml.sax.*;
|
---|
55 |
|
---|
56 | /** To provide a library of common methods, in a static context, for use in the Gatherer.
|
---|
57 | * @author John Thompson, Greenstone Digital Library, University of Waikato
|
---|
58 | * @version 2.3b
|
---|
59 | */
|
---|
60 | public class Utility {
|
---|
61 | static final public Dimension MINIMUM_BUTTON_SIZE = new Dimension(100, 25);
|
---|
62 | // static final public Dimension DOUBLE_IMAGE_BUTTON_SIZE = new Dimension(190, 35);
|
---|
63 | static final public Dimension LABEL_SIZE = new Dimension(150, 25);
|
---|
64 | /** The default size of a gatherer progress bar, in either the download view or the build view. */
|
---|
65 | static final public Dimension PROGRESS_BAR_SIZE = new Dimension(580,65);
|
---|
66 | /** The number of kilobytes to use as a io buffer. */
|
---|
67 | static final public int FACTOR = 1;
|
---|
68 | /** The size of the io buffer, calculated as FACTOR * 1024. */
|
---|
69 | static final public int BUFFER_SIZE = FACTOR * 1024;
|
---|
70 | /** Definition of an important directory name, in this case the base dir, or the working directory of the Gatherer. */
|
---|
71 | static public String BASE_DIR = System.getProperty("user.dir") + File.separator;
|
---|
72 | static final public String BUILD_CFG_FILENAME = "build.cfg";
|
---|
73 | static final public String CFG_COLLECTIONMETA_COLLECTIONNAME = "collectionmeta\tcollectionname";
|
---|
74 | static final public String CFG_COLLECTIONMETA_COLLECTIONEXTRA = "collectionmeta\tcollectionextra";
|
---|
75 | static final public String CFG_COLLECTIONMETA_ICONCOLLECTION = "collectionmeta\ticoncollection";
|
---|
76 | static final public String CFG_CLASSIFY = "classify";
|
---|
77 | static final public String CFG_CLASSIFY_BUTTONNAME = "-buttonname";
|
---|
78 | static final public String CFG_CLASSIFY_HFILE = "-hfile";
|
---|
79 | static final public String CFG_CLASSIFY_METADATA = "-metadata";
|
---|
80 | static final public String CFG_CLASSIFY_SORT = "-sort";
|
---|
81 | static final public String CFG_CREATOR = "creator";
|
---|
82 | static final public String CFG_FORMAT = "format";
|
---|
83 | static final public String CFG_MAINTAINER = "maintainer";
|
---|
84 | /** Definition of an important directory name, in this case the parent directory of all the collections in the gsdl. */
|
---|
85 | static final public String COL_DIR = "collect" + File.separator;
|
---|
86 | static final public String COLLECTION_TREE = "Collection";
|
---|
87 | /** Definition of an important directory name, in this case the file the collection configuration is expect to be in. */
|
---|
88 | static final public String CONFIG_FILE = "etc" + File.separator + "collect.cfg";
|
---|
89 | static final public String EXTRACTED_METADATA_NAMESPACE = "ex";
|
---|
90 | /** The location of the default greenstone metadata file. */
|
---|
91 | static final public String GREENSTONEDIRECTORYMETADATA_TEMPLATE = "xml/metadata.xml";
|
---|
92 | static final public String GLI_ARCHIVE = "GLI.jar";
|
---|
93 | static final public String GLI_EXTENSION = ".col";
|
---|
94 | /** Definition of an important directory name, in this case the images directory for the collection. */
|
---|
95 | static final public String IMAGES_DIR = "images" + File.separator;
|
---|
96 | /** Definition of an important directory name, in this case the import directory for the collection. */
|
---|
97 | static final public String IMPORT_DIR = "import" + File.separator;
|
---|
98 | /** Definition of an important directory name, in this case the backup import directory for the collection. */
|
---|
99 | static final public String IMPORT_BAK_DIR = "import.bak" + File.separator;
|
---|
100 | /** Definition of an important directory name, in this case the log directory for the collection. */
|
---|
101 | static final public String LOG_DIR = "log" + File.separator;
|
---|
102 | /** Definition of an important directory name, in this case the macros directory for the collection. */
|
---|
103 | static final public String MACROS_DIR = "macros" + File.separator;
|
---|
104 | /** Definition of an important directory name, in this case the location of the expected collection metadata sets.. */
|
---|
105 | static final public String META_DIR = "metadata" + File.separator; // Col. Copy
|
---|
106 | /** Definition of an important directory name, in this case the location of the default metadata sets. */
|
---|
107 | static public String METADATA_DIR = BASE_DIR + "metadata" + File.separator;
|
---|
108 | /** Definition of an important zip file, in this case zipped up version of metadata file stored in JAR file */
|
---|
109 | static final public String METADATA_ZIP = "metadata.zip";
|
---|
110 | /** The location the gatherer expects to find metadata set information. */
|
---|
111 | static final public String METADATA_SET_TEMPLATE = "xml/template.mds";
|
---|
112 | static final public String METADATA_VALUE_TEMPLATE = "xml/template.mdv";
|
---|
113 | /** The default name of the perl executable under unix. */
|
---|
114 | static final public String PERL_EXECUTABLE_UNIX = "perl";
|
---|
115 | /** The default name of the perl executable under windows. */
|
---|
116 | static final public String PERL_EXECUTABLE_WINDOWS = "Perl.exe";
|
---|
117 | /** The name of the Gatherer. */
|
---|
118 | static final public String PROGRAM_NAME = "Greenstone Librarian Interface";
|
---|
119 | /** The current version of the Gatherer. */
|
---|
120 | static final public String PROGRAM_VERSION = "v2.52";
|
---|
121 | static final public String WORKSPACE_TREE = "Workspace";
|
---|
122 | static final public String XML_DIRECTORY = "xml" + File.separator;
|
---|
123 |
|
---|
124 | // These are out of alphabetic order to avoid forward reference error.
|
---|
125 | /** The default icon to produce a 'help-icon' sized blank space before a menu entry. */
|
---|
126 | static public Class base = null;
|
---|
127 | static public ImageIcon BLANK_ICON = null;
|
---|
128 | /** The default error icon image. */
|
---|
129 | static public ImageIcon ERROR_ICON = null;
|
---|
130 | static public ImageIcon HELP_ICON = null;
|
---|
131 |
|
---|
132 |
|
---|
133 | /** It turns out that in Java you have to make sure a directory is empty before you delete it (much like unix I suppose), and so just like unix I'll have to set up a recursive delete function.
|
---|
134 | * @param file The <strong>File</strong> you want to delete.
|
---|
135 | * @return A <i>boolean</i> which is <i>true</i> if the file specified was successfully deleted, <i>false</i> otherwise.
|
---|
136 | */
|
---|
137 | static public boolean delete(File file) {
|
---|
138 | boolean result = true;
|
---|
139 | // If file is a directory, delete the file's children.
|
---|
140 | if(file.isDirectory()) {
|
---|
141 | File files[] = file.listFiles();
|
---|
142 | for(int i = 0; files != null && result && i < files.length; i++) {
|
---|
143 | result = delete(files[i]);
|
---|
144 | }
|
---|
145 | }
|
---|
146 | if(result) {
|
---|
147 | // Delete file.
|
---|
148 | return file.delete();
|
---|
149 | }
|
---|
150 | return result;
|
---|
151 | }
|
---|
152 |
|
---|
153 | static public boolean delete(String filename) {
|
---|
154 | return delete(new File(filename));
|
---|
155 | }
|
---|
156 |
|
---|
157 |
|
---|
158 | /** Convert a long, detailing the length of a file in bytes, into a nice human readable string using b, kb, Mb and Gb. */
|
---|
159 | static final public String BYTE_SUFFIX = " b";
|
---|
160 | static final public long GIGABYTE = 1024000000l;
|
---|
161 | static final public String GIGABYTE_SUFFIX = " Gb";
|
---|
162 | static final public long KILOBYTE = 1024l;
|
---|
163 | static final public String KILOBYTE_SUFFIX = " kb";
|
---|
164 | static final public long MEGABYTE = 1024000l;
|
---|
165 | static final public String MEGABYTE_SUFFIX = " mb";
|
---|
166 | static final public String formatFileLength(long length) {
|
---|
167 | StringBuffer result = new StringBuffer("");
|
---|
168 | float number = 0f;
|
---|
169 | String suffix = null;
|
---|
170 | // Determine the floating point number and the suffix (radix) used.
|
---|
171 | if(length >= GIGABYTE) {
|
---|
172 | number = (float) length / (float) GIGABYTE;
|
---|
173 | suffix = GIGABYTE_SUFFIX;
|
---|
174 | }
|
---|
175 | else if(length >= MEGABYTE) {
|
---|
176 | number = (float) length / (float) MEGABYTE;
|
---|
177 | suffix = MEGABYTE_SUFFIX;
|
---|
178 | }
|
---|
179 | else if(length >= KILOBYTE) {
|
---|
180 | number = (float) length / (float) KILOBYTE;
|
---|
181 | suffix = KILOBYTE_SUFFIX;
|
---|
182 | }
|
---|
183 | else {
|
---|
184 | // Don't need to do anything fancy if the file is smaller than a kilobyte
|
---|
185 | return length + BYTE_SUFFIX;
|
---|
186 | }
|
---|
187 | // Create the formatted string remembering to round the number to 2.d.p. To do this copy everything in the number string from the start to the first occurance of '.' then copy two more digits. Finally search for and print anything that appears after (and including) the optional 'E' delimter.
|
---|
188 | String number_str = Float.toString(number);
|
---|
189 | char number_char[] = number_str.toCharArray();
|
---|
190 | int pos = 0;
|
---|
191 | // Print the characters up to the '.'
|
---|
192 | while(number_char != null && pos < number_char.length && number_char[pos] != '.') {
|
---|
193 | result.append(number_char[pos]);
|
---|
194 | pos++;
|
---|
195 | }
|
---|
196 | if(pos < number_char.length) {
|
---|
197 | // Print the '.' and at most two characters after it
|
---|
198 | result.append(number_char[pos]);
|
---|
199 | pos++;
|
---|
200 | for(int i = 0; i < 2 && pos < number_char.length; i++, pos++) {
|
---|
201 | result.append(number_char[pos]);
|
---|
202 | }
|
---|
203 | // Search through the remaining string for 'E'
|
---|
204 | while(pos < number_char.length && number_char[pos] != 'E') {
|
---|
205 | pos++;
|
---|
206 | }
|
---|
207 | // If we still have string then we found an E. Copy the remaining string.
|
---|
208 | while(pos < number_char.length) {
|
---|
209 | result.append(number_char[pos]);
|
---|
210 | pos++;
|
---|
211 | }
|
---|
212 | }
|
---|
213 | // Add suffix
|
---|
214 | result.append(suffix);
|
---|
215 | // Done
|
---|
216 | return result.toString();
|
---|
217 | }
|
---|
218 |
|
---|
219 | /** This method formats a given string, using HTML markup, so its width does not exceed the given width and its appearance if justified.
|
---|
220 | * @param text The <strong>String</strong> requiring formatting.
|
---|
221 | * @param width The maximum width per line as an <i>int</i>.
|
---|
222 | * @return A <strong>String</strong> formatted so as to have no line longer than the specified width.
|
---|
223 | * TODO Currently HTML formatting tags are simply removed from the text, as the effects of spreading HTML tags over a break are undetermined. To solve this we need to associate tags with a certain text token so if it gets broken on to the next line the tags go with it, or if the tags cover a sequence of words that are broken we need to close then reopen the tags. However all this is a major task and well beyond anything I have time to 'muck-round' on.
|
---|
224 | */
|
---|
225 | static public String formatHTMLWidth(String text, int width) {
|
---|
226 | if(text == null) {
|
---|
227 | return "Error";
|
---|
228 | }
|
---|
229 | HTMLStringTokenizer html = new HTMLStringTokenizer(text);
|
---|
230 | int current_width = 0;
|
---|
231 | int threshold = width / 2;
|
---|
232 | Stack lines = new Stack();
|
---|
233 | String line = "";
|
---|
234 | while(html.hasMoreTokens()) {
|
---|
235 | String token = html.nextToken();
|
---|
236 | while(token != null) {
|
---|
237 | if(html.isTag()) {
|
---|
238 | // Insert smart HTML tag code here.
|
---|
239 | token = null;
|
---|
240 | }
|
---|
241 | else {
|
---|
242 | // If the token is bigger than two thirds width, before we've even started break it down.
|
---|
243 | if(current_width + 1 + token.length() > width && token.length() > threshold) {
|
---|
244 | if(width == current_width) {
|
---|
245 | lines.push(line);
|
---|
246 | line = token;
|
---|
247 | current_width = token.length();
|
---|
248 | }
|
---|
249 | else {
|
---|
250 | String prefix = token.substring(0, width - 1 - current_width);
|
---|
251 | token = token.substring(prefix.length());
|
---|
252 | if(current_width == 0) {
|
---|
253 | line = line + prefix;
|
---|
254 | }
|
---|
255 | else {
|
---|
256 | line = line + " " + prefix;
|
---|
257 | }
|
---|
258 | lines.push(line);
|
---|
259 | line = "";
|
---|
260 | current_width = 0;
|
---|
261 | }
|
---|
262 | }
|
---|
263 | // If adding the next token would push us over the maximum line width.
|
---|
264 | else if(current_width + 1 + token.length() > width) {
|
---|
265 | lines.push(line);
|
---|
266 | line = token;
|
---|
267 | current_width = token.length();
|
---|
268 | token = null;
|
---|
269 | }
|
---|
270 | // Otherwise we should be able to just add the token, give or take.
|
---|
271 | else {
|
---|
272 | if(current_width == 0) {
|
---|
273 | line = line + token;
|
---|
274 | current_width = token.length();
|
---|
275 | }
|
---|
276 | else {
|
---|
277 | // Special case for standard punctuation which may exist after a tag like so:
|
---|
278 | // My name is <scratchy>Slim Shady</scratchy>. <-- Annoying punctuation.
|
---|
279 | if(token.equals(".") || token.equals(",") || token.equals("!") || token.equals("?")) {
|
---|
280 | line = line + token;
|
---|
281 | current_width = current_width + 1;
|
---|
282 | }
|
---|
283 | else {
|
---|
284 | line = line + " " + token;
|
---|
285 | current_width = current_width + 1 + token.length();
|
---|
286 | }
|
---|
287 | }
|
---|
288 | token = null;
|
---|
289 | }
|
---|
290 | }
|
---|
291 | }
|
---|
292 | }
|
---|
293 | String result = line;
|
---|
294 | while(!lines.empty()) {
|
---|
295 | result = (String)lines.pop() + "<BR>" + result;
|
---|
296 | }
|
---|
297 | // Replace ' ' with " "
|
---|
298 | boolean tag = false;
|
---|
299 | int pos = 0;
|
---|
300 | while(pos < result.length()) {
|
---|
301 | if(result.charAt(pos) == '<') {
|
---|
302 | tag = true;
|
---|
303 | }
|
---|
304 | else if(result.charAt(pos) == '>') {
|
---|
305 | tag = false;
|
---|
306 | }
|
---|
307 | else if(result.charAt(pos) == ' ' && !tag) {
|
---|
308 | String prefix = result.substring(0, pos);
|
---|
309 | String suffix = result.substring(pos + 1);
|
---|
310 | result = prefix + " " + suffix;
|
---|
311 | }
|
---|
312 | pos++;
|
---|
313 | }
|
---|
314 | result = "<HTML>" + result + "</HTML>";
|
---|
315 | return result;
|
---|
316 | }
|
---|
317 | /** Format the given filename path string so that it is no longer than the given width. If it is wider replace starting directories with ...
|
---|
318 | * @param key The key <strong>String</Strong> used to retrieve a phrase from the dictionary for this item.
|
---|
319 | * @param raw The raw filename path <strong>String</strong>.
|
---|
320 | * @param width The maximum width as an <i>int</i>.
|
---|
321 | * @return A path <strong>String</strong> no longer than width.
|
---|
322 | */
|
---|
323 | static public String formatPath(String key, String raw, int width) {
|
---|
324 | JLabel label = new JLabel(Dictionary.get(key, raw));
|
---|
325 | int position = -1;
|
---|
326 | while(label.getPreferredSize().width > width && (position = raw.indexOf(File.separator)) != -1) {
|
---|
327 | raw = "..." + raw.substring(position + 1);
|
---|
328 | label.setText(Dictionary.get(key, raw));
|
---|
329 | }
|
---|
330 | if(raw.indexOf(File.separator) == -1 && raw.startsWith("...")) {
|
---|
331 | raw = raw.substring(3);
|
---|
332 | }
|
---|
333 | return raw;
|
---|
334 | }
|
---|
335 |
|
---|
336 |
|
---|
337 | /** Builds the cache dir by appending the user path and 'cache'.
|
---|
338 | * @return a File representing the path to the private file cache within the current collection.
|
---|
339 | */
|
---|
340 | public static File getCacheDir() {
|
---|
341 | return new File(getGLIUserFolder(), StaticStrings.CACHE_FOLDER);
|
---|
342 | }
|
---|
343 | /** Method which constructs the collect directory for Greenstone.
|
---|
344 | * @param gsdl_path The location of the gsdl installation directory as a <strong>String</strong>.
|
---|
345 | * @return The location of the collection directory, also as a <strong>String</strong>.
|
---|
346 | */
|
---|
347 | public static String getCollectDir(String gsdl_path) {
|
---|
348 | return gsdl_path + COL_DIR;
|
---|
349 | }
|
---|
350 | static public String getCollectDir(String gsdl3_path, String site_name) {
|
---|
351 | return getSitesDir(gsdl3_path) + site_name + File.separator + COL_DIR;
|
---|
352 | }
|
---|
353 |
|
---|
354 |
|
---|
355 | /** Method which constructs a collection's top level directory
|
---|
356 | * @@param gsdl_path The location of the gsdl installation directory as a <strong>String</strong>.
|
---|
357 | * @param The name of the collection as a <strong>String</strong>.
|
---|
358 | * @return The location of the collection's base directory
|
---|
359 | */
|
---|
360 | public static String getCollectionDir(String gsdl_path, String coll_name) {
|
---|
361 | return getCollectDir(gsdl_path) + coll_name + File.separator;
|
---|
362 | }
|
---|
363 | public static String getCollectionDir(String gsdl3_path, String site_name, String coll_name) {
|
---|
364 | return getCollectDir(gsdl3_path, site_name) + coll_name + File.separator;
|
---|
365 | }
|
---|
366 |
|
---|
367 |
|
---|
368 | /** Method which constructs the configuration file given a certain collection.
|
---|
369 | * @param col_dir The location of the collection directory as a <strong>String</strong>.
|
---|
370 | * @return The location of the given collections configuration file, also as a <strong>String</strong>.
|
---|
371 | */
|
---|
372 | static public String getConfigFile(String col_dir) {
|
---|
373 | return col_dir + CONFIG_FILE;
|
---|
374 | }
|
---|
375 |
|
---|
376 | static public String getDateString() {
|
---|
377 | Calendar current = Calendar.getInstance();
|
---|
378 | String day_name = null;
|
---|
379 | switch(current.get(Calendar.DAY_OF_WEEK)) {
|
---|
380 | case Calendar.MONDAY: day_name = "Dates.Mon"; break;
|
---|
381 | case Calendar.TUESDAY: day_name = "Dates.Tue"; break;
|
---|
382 | case Calendar.WEDNESDAY: day_name = "Dates.Wed"; break;
|
---|
383 | case Calendar.THURSDAY: day_name = "Dates.Thu"; break;
|
---|
384 | case Calendar.FRIDAY: day_name = "Dates.Fri"; break;
|
---|
385 | case Calendar.SATURDAY: day_name = "Dates.Sat"; break;
|
---|
386 | case Calendar.SUNDAY: day_name = "Dates.Sun"; break;
|
---|
387 | default: day_name = "";
|
---|
388 | }
|
---|
389 | String month_name = null;
|
---|
390 | switch(current.get(Calendar.MONTH)) {
|
---|
391 | case Calendar.JANUARY: month_name = "Dates.Jan"; break;
|
---|
392 | case Calendar.FEBRUARY: month_name = "Dates.Feb"; break;
|
---|
393 | case Calendar.MARCH: month_name = "Dates.Mar"; break;
|
---|
394 | case Calendar.APRIL: month_name = "Dates.Apr"; break;
|
---|
395 | case Calendar.MAY: month_name = "Dates.May"; break;
|
---|
396 | case Calendar.JUNE: month_name = "Dates.Jun"; break;
|
---|
397 | case Calendar.JULY: month_name = "Dates.Jul"; break;
|
---|
398 | case Calendar.AUGUST: month_name = "Dates.Aug"; break;
|
---|
399 | case Calendar.SEPTEMBER: month_name = "Dates.Sep"; break;
|
---|
400 | case Calendar.OCTOBER: month_name = "Dates.Oct"; break;
|
---|
401 | case Calendar.NOVEMBER: month_name = "Dates.Nov"; break;
|
---|
402 | case Calendar.DECEMBER: month_name = "Dates.Dec"; break;
|
---|
403 | default: month_name = "";
|
---|
404 | }
|
---|
405 | int day = current.get(Calendar.DAY_OF_MONTH);
|
---|
406 | int hour = current.get(Calendar.HOUR_OF_DAY);
|
---|
407 | int minute = current.get(Calendar.MINUTE);
|
---|
408 | int second = current.get(Calendar.SECOND);
|
---|
409 | int year = current.get(Calendar.YEAR);
|
---|
410 |
|
---|
411 | return Dictionary.get(day_name) + " " + Dictionary.get(month_name) + " " + day + " " + year + " " + Utility.pad(String.valueOf(hour), 2, '0', true) + ":" + Utility.pad(String.valueOf(minute), 2, '0', true) + ":" + Utility.pad(String.valueOf(second), 2, '0', true);
|
---|
412 | }
|
---|
413 |
|
---|
414 |
|
---|
415 | static final private String APPLICATION_DATA_FOLDER = "Application Data";
|
---|
416 | static final private String UNIX_GLI_CONFIG_FOLDER = ".gli";
|
---|
417 | static final private String USER_HOME_PROPERTY = "user.home";
|
---|
418 | static final private String WIN_GLI_CONFIG_FOLDER = "Greenstone" + File.separator + "GLI";
|
---|
419 |
|
---|
420 | static public File getGLIUserFolder()
|
---|
421 | {
|
---|
422 | if (Utility.isWindows()) {
|
---|
423 | return new File(System.getProperty(USER_HOME_PROPERTY) + File.separator + APPLICATION_DATA_FOLDER + File.separator + WIN_GLI_CONFIG_FOLDER + File.separator);
|
---|
424 | }
|
---|
425 | else {
|
---|
426 | return new File(System.getProperty(USER_HOME_PROPERTY) + File.separator + UNIX_GLI_CONFIG_FOLDER + File.separator);
|
---|
427 | }
|
---|
428 | }
|
---|
429 |
|
---|
430 |
|
---|
431 | /** Retrieve the full file path to the help index xml file.
|
---|
432 | * @return the full path as a String
|
---|
433 | */
|
---|
434 | static public String getHelpFolder() {
|
---|
435 |
|
---|
436 | String help_folder = "help/" + Configuration.getLanguage() + "/";
|
---|
437 |
|
---|
438 | // Try in the JAR/classes directory first
|
---|
439 | URL help_folder_url = base.getResource("/" + help_folder);
|
---|
440 | if (help_folder_url != null) {
|
---|
441 | return help_folder;
|
---|
442 | }
|
---|
443 |
|
---|
444 | // Look in the base directory next
|
---|
445 | File help_folder_file = new File(help_folder);
|
---|
446 | if (help_folder_file.exists()) {
|
---|
447 | return help_folder;
|
---|
448 | }
|
---|
449 |
|
---|
450 | // Resort to English
|
---|
451 | return "help/" + StaticStrings.ENGLISH_LANGUAGE_STR + "/";
|
---|
452 | }
|
---|
453 |
|
---|
454 | /** Method to retrieve an image icon with the given filename found in classpath or the resouces directory.
|
---|
455 | * @return The specified <strong>ImageIcon</strong>, or an error image replacement if no such images exists.
|
---|
456 | */
|
---|
457 | static public ImageIcon getImage(String filename) {
|
---|
458 | return getImage(filename, false);
|
---|
459 | }
|
---|
460 |
|
---|
461 | static public ImageIcon getImage(String filename, boolean wait_until_complete) {
|
---|
462 | ImageIcon image = null;
|
---|
463 | try {
|
---|
464 | image = new ImageIcon(base.getResource("/images/" + Dictionary.get("Version") + "/" + filename));
|
---|
465 | }
|
---|
466 | catch(NullPointerException exception) {
|
---|
467 | image = new ImageIcon(base.getResource("/images/" + filename));
|
---|
468 | }
|
---|
469 | if(image == null) {
|
---|
470 | image = ERROR_ICON;
|
---|
471 | }
|
---|
472 |
|
---|
473 | if(wait_until_complete) {
|
---|
474 | int load_status;
|
---|
475 | do {
|
---|
476 | load_status = image.getImageLoadStatus();
|
---|
477 | }
|
---|
478 | while(load_status != MediaTracker.ABORTED && load_status != MediaTracker.ERRORED && load_status != MediaTracker.COMPLETE);
|
---|
479 | }
|
---|
480 | return image;
|
---|
481 | }
|
---|
482 |
|
---|
483 | /** Method which constructs the images directory given a certain collection.
|
---|
484 | * @param col_dir The location of the collection directory as a <strong>String</strong>.
|
---|
485 | * @return The location of the given collections images directory, also as a <strong>String</strong>.
|
---|
486 | */
|
---|
487 | public static String getImagesDir(String col_dir) {
|
---|
488 | return col_dir + IMAGES_DIR;
|
---|
489 | }
|
---|
490 | /** Method which constructs the import directory given a certain collection.
|
---|
491 | * @param col_dir The location of the collection directory as a <strong>String</strong>.
|
---|
492 | * @return The location of the given collections import directory, also as a <strong>String</strong>.
|
---|
493 | */
|
---|
494 | public static String getImportDir(String col_dir) {
|
---|
495 | return col_dir + IMPORT_DIR;
|
---|
496 | }
|
---|
497 |
|
---|
498 | /** Method which constructs the log directory given a certain collection.
|
---|
499 | * @param col_dir The location of the collection directory as a <strong>String</strong>.
|
---|
500 | * @return The location of the given collections log directory, also as a <strong>String</strong>.
|
---|
501 | */
|
---|
502 | public static String getLogDir(String col_dir) {
|
---|
503 | if(col_dir != null) {
|
---|
504 | return col_dir + LOG_DIR;
|
---|
505 | }
|
---|
506 | else {
|
---|
507 | return getGLIUserFolder().getAbsolutePath() + File.separator + LOG_DIR;
|
---|
508 | }
|
---|
509 | }
|
---|
510 | /** Determine this machines name.
|
---|
511 | * @return The name as a <strong>String</strong>.
|
---|
512 | */
|
---|
513 | static public String getMachineName() {
|
---|
514 | try {
|
---|
515 | return InetAddress.getLocalHost().getHostName();
|
---|
516 | }
|
---|
517 | catch(UnknownHostException ex) {
|
---|
518 | }
|
---|
519 | return "Unknown Machine";
|
---|
520 | }
|
---|
521 |
|
---|
522 |
|
---|
523 | static public void extractFromJar(String filename, String dst_dir, boolean must_be_present)
|
---|
524 | {
|
---|
525 | try {
|
---|
526 | // setup input stream for slurping out file
|
---|
527 | InputStream fis = base.getResourceAsStream("/"+filename);
|
---|
528 | BufferedInputStream fbis = new BufferedInputStream(fis);
|
---|
529 | DataInputStream fdbis = new DataInputStream(fbis);
|
---|
530 |
|
---|
531 | // set up output stream for writing to disk
|
---|
532 | String ofname = dst_dir + filename;
|
---|
533 | FileOutputStream fos = new FileOutputStream(ofname);
|
---|
534 | BufferedOutputStream bfos = new BufferedOutputStream(fos);
|
---|
535 |
|
---|
536 | byte[] buf = new byte[1024];
|
---|
537 | int len;
|
---|
538 | int total_bytes = 0;
|
---|
539 | while ((len = fdbis.read(buf)) >= 0) {
|
---|
540 | bfos.write(buf,0,len);
|
---|
541 | total_bytes += len;
|
---|
542 | }
|
---|
543 |
|
---|
544 | fdbis.close();
|
---|
545 | bfos.close();
|
---|
546 | }
|
---|
547 | catch (Exception error) {
|
---|
548 | if (must_be_present) {
|
---|
549 | error.printStackTrace();
|
---|
550 | }
|
---|
551 | }
|
---|
552 | }
|
---|
553 |
|
---|
554 |
|
---|
555 | /** Method which unzips a given metadata resoure
|
---|
556 | * @param zip_fname The name of the zip file as a <strong>String</strong>.
|
---|
557 | * @param dst_dir The destination directory for unzipping, also as a <strong>String</strong>.
|
---|
558 | * @param use_classloader Used to determine whether or not to look in resource bundle.
|
---|
559 | */
|
---|
560 | static public void unzipFromJar(String jar_zip_fname, String dst_dir) {
|
---|
561 |
|
---|
562 | File file = null;
|
---|
563 | if (!dst_dir.endsWith(File.separator)) {
|
---|
564 | dst_dir += File.separator;
|
---|
565 | }
|
---|
566 |
|
---|
567 | extractFromJar(jar_zip_fname,dst_dir,true);
|
---|
568 |
|
---|
569 | String zip_ofname = dst_dir + jar_zip_fname;
|
---|
570 | File zip_file = new File(zip_ofname);
|
---|
571 |
|
---|
572 | try {
|
---|
573 | ZipFile zipfile = new ZipFile(zip_file);
|
---|
574 |
|
---|
575 | Enumeration e = zipfile.entries();
|
---|
576 | while (e.hasMoreElements()) {
|
---|
577 | ZipEntry zipentry = (ZipEntry) e.nextElement();
|
---|
578 | String zentryname = dst_dir + zipentry.getName();
|
---|
579 | DebugStream.println(" Unzipping: " + zentryname);
|
---|
580 |
|
---|
581 | if (zipentry.isDirectory()) {
|
---|
582 | // Create named directory
|
---|
583 | boolean success = (new File(zentryname)).mkdir();
|
---|
584 | if (!success) {
|
---|
585 | System.err.println("Error: unable to create directory '"+zentryname+"'");
|
---|
586 | }
|
---|
587 | }
|
---|
588 | else {
|
---|
589 | // Write out file to disk
|
---|
590 |
|
---|
591 | // set up input stream
|
---|
592 | InputStream zis = zipfile.getInputStream(zipentry);
|
---|
593 | BufferedInputStream bzis = new BufferedInputStream(zis);
|
---|
594 | DataInputStream dbzis = new DataInputStream(bzis);
|
---|
595 |
|
---|
596 | // set up output stream
|
---|
597 | FileOutputStream fzos = new FileOutputStream(zentryname);
|
---|
598 | BufferedOutputStream bfzos = new BufferedOutputStream(fzos);
|
---|
599 |
|
---|
600 | byte[] buf = new byte[1024];
|
---|
601 | int len;
|
---|
602 | while ((len = dbzis.read(buf)) >= 0) {
|
---|
603 | bfzos.write(buf,0,len);
|
---|
604 | }
|
---|
605 |
|
---|
606 | dbzis.close();
|
---|
607 | bfzos.close();
|
---|
608 | }
|
---|
609 | }
|
---|
610 | }
|
---|
611 | catch (ZipException error) {
|
---|
612 | System.err.println("Error: Unable to open '"+zip_file.getAbsolutePath()+"'");
|
---|
613 | DebugStream.printStackTrace(error);
|
---|
614 | }
|
---|
615 |
|
---|
616 | catch (Exception error) {
|
---|
617 | error.printStackTrace();
|
---|
618 | }
|
---|
619 | }
|
---|
620 |
|
---|
621 |
|
---|
622 | static protected String unixStylePath(String path)
|
---|
623 | {
|
---|
624 | String unix_path = path.replace('\\','/');
|
---|
625 | return unix_path;
|
---|
626 | }
|
---|
627 |
|
---|
628 | static protected void zipFunc (ZipOutputStream zos, String file_path, int prefix_strip)
|
---|
629 | {
|
---|
630 | // Using try is required because of file io.
|
---|
631 | try {
|
---|
632 | // Create a Zip Entry and put it into the archive (no data yet).
|
---|
633 |
|
---|
634 | // Strip off col_dir prefix
|
---|
635 | String zip_path = file_path.substring(prefix_strip);
|
---|
636 | // Zip files use '/' for directory separator
|
---|
637 | String unix_style_path = unixStylePath(zip_path);
|
---|
638 | ZipEntry fileEntry = new ZipEntry(unix_style_path);
|
---|
639 | zos.putNextEntry(fileEntry);
|
---|
640 |
|
---|
641 | // Create a file input stream and a buffered input stream.
|
---|
642 | FileInputStream fis = new FileInputStream(file_path);
|
---|
643 | BufferedInputStream bis = new BufferedInputStream(fis);
|
---|
644 |
|
---|
645 | // Create a byte array object named data and declare byte count variable.
|
---|
646 | byte[] data = new byte[1024];
|
---|
647 | int byteCount;
|
---|
648 | // Create a loop that reads from the buffered input stream and writes
|
---|
649 | // to the zip output stream until the bis has been entirely read.
|
---|
650 | while ((byteCount = bis.read(data, 0, 1024)) > -1) {
|
---|
651 | zos.write(data, 0, byteCount);
|
---|
652 | }
|
---|
653 | }
|
---|
654 | catch (IOException e) {
|
---|
655 | e.printStackTrace();
|
---|
656 | }
|
---|
657 |
|
---|
658 | DebugStream.println(" Zipping up: " + file_path);
|
---|
659 | }
|
---|
660 |
|
---|
661 | static protected void dirFunc (ZipOutputStream zos, String dir_name, int prefix_strip)
|
---|
662 | {
|
---|
663 | File dirObj = new File(dir_name);
|
---|
664 |
|
---|
665 | if (dirObj.exists() == true) {
|
---|
666 | if (dirObj.isDirectory() == true) {
|
---|
667 | // Create an array of File objects, one for each file or directory in dirObj.
|
---|
668 | File [] fileList = dirObj.listFiles();
|
---|
669 |
|
---|
670 | // Loop through File array and display.
|
---|
671 | for (int i = 0; i < fileList.length; i++) {
|
---|
672 | File file = fileList[i];
|
---|
673 | if (file.isDirectory()) {
|
---|
674 | String dir_path = file.getPath();
|
---|
675 | String zip_path = dir_path.substring(prefix_strip);
|
---|
676 | // Zip files use '/' for directory separator
|
---|
677 | String unix_style_path
|
---|
678 | = unixStylePath(zip_path+File.separator);
|
---|
679 | ZipEntry dirEntry = new ZipEntry(unix_style_path);
|
---|
680 |
|
---|
681 | try {
|
---|
682 | zos.putNextEntry(dirEntry);
|
---|
683 | }
|
---|
684 | catch (IOException e) {
|
---|
685 | e.printStackTrace();
|
---|
686 | }
|
---|
687 |
|
---|
688 | dirFunc(zos,dir_path,prefix_strip);
|
---|
689 | } else if (file.isFile()) {
|
---|
690 | // Call the zipFunc function
|
---|
691 | String file_path = fileList[i].getPath();
|
---|
692 | zipFunc(zos,file_path,prefix_strip);
|
---|
693 | }
|
---|
694 | }
|
---|
695 | }
|
---|
696 | else {
|
---|
697 | System.err.println (dir_name+" is not a directory.");
|
---|
698 | }
|
---|
699 | }
|
---|
700 | else {
|
---|
701 | System.err.println ("Directory "+dir_name+" does not exist.");
|
---|
702 | }
|
---|
703 | }
|
---|
704 |
|
---|
705 |
|
---|
706 |
|
---|
707 | static public void zipup(String col_name, String dir_or_file)
|
---|
708 | {
|
---|
709 | String col_dir = Utility.getCollectDir(Configuration.gsdl_path);
|
---|
710 | int prefix_strip = col_dir.length();
|
---|
711 |
|
---|
712 | String zip_fname = col_dir + col_name + ".zip";
|
---|
713 | String zip_dir_or_file = col_dir + col_name + File.separator + dir_or_file;
|
---|
714 | File zip_dof = new File(zip_dir_or_file);
|
---|
715 |
|
---|
716 | try {
|
---|
717 | FileOutputStream fos = new FileOutputStream(zip_fname);
|
---|
718 | ZipOutputStream zos = new ZipOutputStream(fos);
|
---|
719 |
|
---|
720 | if (zip_dof.exists()) {
|
---|
721 | if (zip_dof.isDirectory()) {
|
---|
722 | String zip_dir = zip_dir_or_file;
|
---|
723 | dirFunc(zos,zip_dir,prefix_strip);
|
---|
724 | }
|
---|
725 | else {
|
---|
726 | String zip_full_file = zip_dir_or_file;
|
---|
727 |
|
---|
728 | String zip_path = zip_full_file.substring(prefix_strip);
|
---|
729 |
|
---|
730 | for (int i=1; i<zip_path.length(); i++) {
|
---|
731 | String ch = String.valueOf(zip_path.charAt(i));
|
---|
732 |
|
---|
733 | if (ch.equals(File.separator)) {
|
---|
734 | String dir_path = zip_path.substring(0,i);
|
---|
735 | // Zip files use '/' for directory separator
|
---|
736 | String unix_style_path
|
---|
737 | = unixStylePath(dir_path+File.separator);
|
---|
738 | ZipEntry dirEntry = new ZipEntry(unix_style_path);
|
---|
739 | zos.putNextEntry(dirEntry);
|
---|
740 | }
|
---|
741 | }
|
---|
742 | zipFunc(zos,zip_full_file,prefix_strip);
|
---|
743 | }
|
---|
744 | }
|
---|
745 | else {
|
---|
746 | System.err.println("Warning: " + zip_dir_or_file + " does not exist!");
|
---|
747 | }
|
---|
748 |
|
---|
749 | // Close the file output streams for both the file and the zip.
|
---|
750 | zos.flush();
|
---|
751 | zos.close();
|
---|
752 | fos.close();
|
---|
753 | }
|
---|
754 | catch (IOException e) {
|
---|
755 | e.printStackTrace();
|
---|
756 | }
|
---|
757 | }
|
---|
758 |
|
---|
759 |
|
---|
760 | static public void unzip(String col_name)
|
---|
761 | {
|
---|
762 | String col_dir = Utility.getCollectDir(Configuration.gsdl_path);
|
---|
763 | String zip_fname = col_dir + col_name + ".zip";
|
---|
764 | int zip_mode = ZipFile.OPEN_READ | ZipFile.OPEN_DELETE;
|
---|
765 |
|
---|
766 | try {
|
---|
767 | ZipFile zipfile = new ZipFile(new File(zip_fname), zip_mode);
|
---|
768 |
|
---|
769 | Enumeration e = zipfile.entries();
|
---|
770 | while (e.hasMoreElements()) {
|
---|
771 | ZipEntry zipentry = (ZipEntry) e.nextElement();
|
---|
772 | String zentryname = col_dir + zipentry.getName();
|
---|
773 | DebugStream.println(" Unzipping: " + zentryname);
|
---|
774 |
|
---|
775 | if (zipentry.isDirectory()) {
|
---|
776 | // Create named directory
|
---|
777 | boolean success = (new File(zentryname)).mkdir();
|
---|
778 | if (!success) {
|
---|
779 | System.err.println("Error: unable to create directory '"+zentryname+"'");
|
---|
780 | }
|
---|
781 | }
|
---|
782 | else {
|
---|
783 | // Write out file to disk
|
---|
784 |
|
---|
785 | // set up input stream
|
---|
786 | InputStream zis = zipfile.getInputStream(zipentry);
|
---|
787 | BufferedInputStream bzis = new BufferedInputStream(zis);
|
---|
788 | DataInputStream dbzis = new DataInputStream(bzis);
|
---|
789 |
|
---|
790 | // set up output stream
|
---|
791 | FileOutputStream fzos = new FileOutputStream(zentryname);
|
---|
792 | BufferedOutputStream bfzos = new BufferedOutputStream(fzos);
|
---|
793 |
|
---|
794 | byte[] buf = new byte[1024];
|
---|
795 | int len;
|
---|
796 | while ((len = dbzis.read(buf)) >= 0) {
|
---|
797 | bfzos.write(buf,0,len);
|
---|
798 | }
|
---|
799 |
|
---|
800 | dbzis.close();
|
---|
801 | bfzos.close();
|
---|
802 | }
|
---|
803 | }
|
---|
804 | }
|
---|
805 | catch (ZipException error) {
|
---|
806 | System.err.println("Error: Unable to open '"+zip_fname+"'");
|
---|
807 | DebugStream.printStackTrace(error);
|
---|
808 | }
|
---|
809 |
|
---|
810 | catch (Exception error) {
|
---|
811 | error.printStackTrace();
|
---|
812 | }
|
---|
813 | }
|
---|
814 |
|
---|
815 |
|
---|
816 | static public String getSitesDir(String gsdl3_path) {
|
---|
817 | return gsdl3_path + File.separator + "web"
|
---|
818 | + File.separator + "sites" + File.separator;
|
---|
819 |
|
---|
820 | }
|
---|
821 |
|
---|
822 |
|
---|
823 | /** returns the path to the greenstone version of wget */
|
---|
824 | static public String getWGetPath(String gsdl_path) {
|
---|
825 | if (isWindows()) {
|
---|
826 | return gsdl_path + "bin" + File.separator +
|
---|
827 | "windows" + File.separator +"wget.exe";
|
---|
828 | }
|
---|
829 | // is it the same for macs??
|
---|
830 | return gsdl_path + "bin" + File.separator +
|
---|
831 | "linux" + File.separator + "wget";
|
---|
832 | }
|
---|
833 |
|
---|
834 |
|
---|
835 | static public void initImages(Object base_object)
|
---|
836 | {
|
---|
837 | base = base_object.getClass();
|
---|
838 |
|
---|
839 | BLANK_ICON = new ImageIcon(base.getResource("/images/blank.gif"));
|
---|
840 | ERROR_ICON = new ImageIcon(base.getResource("/images/error.gif"));
|
---|
841 | HELP_ICON = new ImageIcon(base.getResource("/images/help.gif"));
|
---|
842 | }
|
---|
843 |
|
---|
844 |
|
---|
845 | /** Method to determine if the host system is MacOS based.
|
---|
846 | * @return a boolean which is true if the platform is MacOS, false otherwise
|
---|
847 | */
|
---|
848 | public static boolean isMac() {
|
---|
849 | Properties props = System.getProperties();
|
---|
850 | String os_name = props.getProperty("os.name","");
|
---|
851 | if(os_name.startsWith("Mac OS")) {
|
---|
852 | return true;
|
---|
853 | }
|
---|
854 | return false;
|
---|
855 | }
|
---|
856 |
|
---|
857 |
|
---|
858 | /** Method to determine if the host system is Microsoft Windows based.
|
---|
859 | * @return A <i>boolean</i> which is <i>true</i> if the platform is Windows, <i>false</i> otherwise.
|
---|
860 | */
|
---|
861 | public static boolean isWindows() {
|
---|
862 | Properties props = System.getProperties();
|
---|
863 | String os_name = props.getProperty("os.name","");
|
---|
864 | if(os_name.startsWith("Windows")) {
|
---|
865 | return true;
|
---|
866 | }
|
---|
867 | return false;
|
---|
868 | }
|
---|
869 |
|
---|
870 | public static boolean isWindows9x() {
|
---|
871 | Properties props = System.getProperties();
|
---|
872 | String os_name = props.getProperty("os.name","");
|
---|
873 | if(os_name.startsWith("Windows") && os_name.indexOf("9") != -1) {
|
---|
874 | return true;
|
---|
875 | }
|
---|
876 | return false;
|
---|
877 | }
|
---|
878 | /** Takes a string and a desired length and pads out the string to the length by adding spaces to the left.
|
---|
879 | * @param str The target <strong>String</strong> that needs to be padded.
|
---|
880 | * @param length The desired length of the string as an <i>int</i>.
|
---|
881 | * @return A <strong>String</strong> made from appending space characters with the string until it has a length equal to length.
|
---|
882 | */
|
---|
883 | public static String pad(String str_raw, int length, char fill, boolean end) {
|
---|
884 | StringBuffer str = new StringBuffer(str_raw);
|
---|
885 | while(str.length() < length) {
|
---|
886 | if(end) {
|
---|
887 | str.insert(0, fill);
|
---|
888 | }
|
---|
889 | else {
|
---|
890 | str.append(fill);
|
---|
891 | }
|
---|
892 | }
|
---|
893 | return str.toString();
|
---|
894 | }
|
---|
895 |
|
---|
896 |
|
---|
897 | /** Parse in a xml document from a given filename. Note that this filename may need to be resolved by the class loader, especially for template files within a jar. */
|
---|
898 | static public Document parse(String filename, boolean use_classloader)
|
---|
899 | {
|
---|
900 | // Try the class loader if desired (for the applet JAR file)
|
---|
901 | if (use_classloader) {
|
---|
902 | InputStream is = base.getResourceAsStream("/" + filename);
|
---|
903 | if (is != null) {
|
---|
904 | return XMLTools.parse(is, true);
|
---|
905 | }
|
---|
906 | }
|
---|
907 |
|
---|
908 | // Try the file outside the classes directory
|
---|
909 | return XMLTools.parse(new File(filename), true);
|
---|
910 | }
|
---|
911 |
|
---|
912 |
|
---|
913 | static public StringBuffer readXMLStream(InputStream input_stream)
|
---|
914 | {
|
---|
915 | StringBuffer xml = new StringBuffer("");
|
---|
916 |
|
---|
917 | try {
|
---|
918 | InputStreamReader isr = new InputStreamReader(input_stream, "UTF-8");
|
---|
919 | BufferedReader buffered_in = new BufferedReader(isr);
|
---|
920 |
|
---|
921 | String line = "";
|
---|
922 | boolean xml_content = false;
|
---|
923 | while((line = buffered_in.readLine()) != null) {
|
---|
924 | if(xml_content) {
|
---|
925 | xml.append(line);
|
---|
926 | xml.append("\n");
|
---|
927 | }
|
---|
928 | else if(line.trim().startsWith("<?xml")) {
|
---|
929 | xml_content = true;
|
---|
930 | xml.append(line);
|
---|
931 | xml.append("\n");
|
---|
932 | }
|
---|
933 | }
|
---|
934 | buffered_in = null;
|
---|
935 | }
|
---|
936 | catch (Exception error) {
|
---|
937 | System.err.println("Failed when trying to parse XML stream");
|
---|
938 | error.printStackTrace();
|
---|
939 | }
|
---|
940 |
|
---|
941 | return xml;
|
---|
942 | }
|
---|
943 |
|
---|
944 |
|
---|
945 | /** I think this works a bit better on Unicode strings. */
|
---|
946 | static public String stripNL(String raw_string)
|
---|
947 | {
|
---|
948 | String stripped_string = new String();
|
---|
949 | for (int i = 0; i < raw_string.length(); i++) {
|
---|
950 | char raw_character = raw_string.charAt(i);
|
---|
951 | if (raw_character != '\n' && raw_character != '\t') {
|
---|
952 | stripped_string = stripped_string + raw_character;
|
---|
953 | }
|
---|
954 | }
|
---|
955 | return stripped_string;
|
---|
956 | }
|
---|
957 | }
|
---|