001: /**
002: *
003: * edtFTPj
004: *
005: * Copyright (C) 2000-2004 Enterprise Distributed Technologies Ltd
006: *
007: * www.enterprisedt.com
008: *
009: * This library is free software; you can redistribute it and/or
010: * modify it under the terms of the GNU Lesser General Public
011: * License as published by the Free Software Foundation; either
012: * version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: * Lesser General Public License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
022: *
023: * Bug fixes, suggestions and comments should be should posted on
024: * http://www.enterprisedt.com/forums/index.php
025: *
026: * Change Log:
027: *
028: *
029: */package com.enterprisedt.net.ftp;
030:
031: import java.text.ParseException;
032: import java.text.SimpleDateFormat;
033: import java.util.Date;
034: import java.util.Locale;
035:
036: /**
037: * Represents a remote OpenVMS file parser. Thanks to Jason Schultz for contributing
038: * significantly to this class
039: *
040: * @author Bruce Blackshaw
041: * @version $Revision: 1.5 $
042: */
043: public class VMSFileParser extends FTPFileParser {
044:
045: /**
046: * Revision control id
047: */
048: public static String cvsId = "@(#)$Id: VMSFileParser.java,v 1.5 2007-10-12 05:20:44 bruceb Exp $";
049:
050: /**
051: * Directory field
052: */
053: private final static String DIR = ".DIR";
054:
055: /**
056: * Directory line
057: */
058: private final static String HDR = "Directory";
059:
060: /**
061: * Total line
062: */
063: private final static String TOTAL = "Total";
064:
065: /**
066: * Blocksize for calculating file sizes
067: */
068: private final int DEFAULT_BLOCKSIZE = 512 * 1024;
069:
070: /**
071: * Number of expected fields
072: */
073: private final static int MIN_EXPECTED_FIELD_COUNT = 4;
074:
075: /**
076: * Date formatter
077: */
078: private SimpleDateFormat formatter1;
079:
080: /**
081: * Date formatter
082: */
083: private SimpleDateFormat formatter2;
084:
085: /**
086: * Is the version returned with the name?
087: */
088: private boolean versionInName = false;
089:
090: /**
091: * Block size used to calculate size
092: */
093: private int blocksize = DEFAULT_BLOCKSIZE;
094:
095: /**
096: * Constructor
097: */
098: public VMSFileParser() {
099: setLocale(Locale.getDefault());
100: }
101:
102: /**
103: * Get the VMS blocksize, used for calculating file
104: * sizes
105: *
106: * @return blocksize
107: */
108: public int getBlocksize() {
109: return blocksize;
110: }
111:
112: /**
113: * Set the VMS blocksize, used for calculating file
114: * sizes. This might need to be changed if unexpected file
115: * sizes are being returned for VMS files.
116: *
117: * @param blocksize new blocksize
118: */
119: public void setBlocksize(int blocksize) {
120: this .blocksize = blocksize;
121: }
122:
123: /**
124: * Get the property that controls whether or not the version
125: * number is returned as part of the filename, e.g. FILENAME.TXT;2
126: * would be returned as is if this property is true, or FILENAME.TXT
127: * if it is false.
128: *
129: * @return true if version to be returned as part of the filename
130: */
131: public boolean isVersionInName() {
132: return versionInName;
133: }
134:
135: /**
136: * Set the property that controls whether or not the version
137: * number is returned as part of the filename, e.g. FILENAME.TXT;2
138: * would be returned as is if this property is true, or FILENAME.TXT
139: * if it is false.
140: *
141: * @param versionInName true if version to be returned as part of the filename
142: */
143: public void setVersionInName(boolean versionInName) {
144: this .versionInName = versionInName;
145: }
146:
147: /**
148: * Parse server supplied string
149: *
150: * OUTPUT: <begin>
151: *
152: * Directory <dir>
153: *
154: * <filename>
155: * used/allocated dd-MMM-yyyy HH:mm:ss [unknown] (PERMS)
156: * <filename>
157: * used/allocated dd-MMM-yyyy HH:mm:ss [unknown] (PERMS)
158: * ...
159: *
160: * Total of <> files, <>/<> blocks
161: *
162: * @param raw raw string to parse
163: */
164: public FTPFile parse(String raw) throws ParseException {
165: String[] fields = split(raw);
166:
167: // skip blank lines
168: if (fields.length <= 0)
169: return null;
170: // skip line which lists Directory
171: if (fields.length >= 2 && fields[0].compareTo(HDR) == 0)
172: return null;
173: // skip line which lists Total
174: if (fields.length > 0 && fields[0].compareTo(TOTAL) == 0)
175: return null;
176: // probably the remainder of a listing on 2nd line
177: if (fields.length < MIN_EXPECTED_FIELD_COUNT)
178: return null;
179:
180: // first field is name
181: String name = fields[0];
182:
183: // make sure it is the name (ends with ';<INT>')
184: int semiPos = name.lastIndexOf(';');
185: // check for ;
186: if (semiPos <= 0) {
187: throw new ParseException(
188: "File version number not found in name '" + name
189: + "'", 0);
190: }
191:
192: String nameNoVersion = name.substring(0, semiPos);
193:
194: // check for version after ;
195: String afterSemi = name.substring(semiPos + 1);
196:
197: try {
198: Integer.parseInt(afterSemi);
199: // didn't throw exception yet, must be number
200: // we don't use it currently but we might in future
201: } catch (NumberFormatException ex) {
202: // don't worry about version number
203: }
204:
205: // test is dir
206: boolean isDir = false;
207: if (nameNoVersion.endsWith(DIR)) {
208: isDir = true;
209: name = nameNoVersion.substring(0, nameNoVersion.length()
210: - DIR.length());
211: }
212:
213: if (!versionInName && !isDir) {
214: name = nameNoVersion;
215: }
216:
217: // 2nd field is size USED/ALLOCATED format
218: int slashPos = fields[1].indexOf('/');
219: String sizeUsed = fields[1];
220: if (slashPos > 0)
221: sizeUsed = fields[1].substring(0, slashPos);
222: long size = Long.parseLong(sizeUsed) * blocksize;
223:
224: // 3 & 4 fields are date time
225: Date lastModified = null;
226: try {
227: lastModified = formatter1
228: .parse(fields[2] + " " + fields[3]);
229: } catch (ParseException ex) {
230: try {
231: lastModified = formatter2.parse(fields[2] + " "
232: + fields[3]);
233: } catch (ParseException ex1) {
234: if (!ignoreDateParseErrors)
235: throw ex;
236: }
237: }
238:
239: // 5th field is [group,owner]
240: String group = null;
241: String owner = null;
242: if (fields.length >= 5) {
243: if (fields[4].charAt(0) == '['
244: && fields[4].charAt(fields[4].length() - 1) == ']') {
245: int commaPos = fields[4].indexOf(',');
246: if (commaPos < 0) {
247: group = owner = fields[4]; // just make them the same, e.g. SYSTEM
248: } else {
249: group = fields[4].substring(1, commaPos);
250: owner = fields[4].substring(commaPos + 1, fields[4]
251: .length() - 1);
252: }
253: }
254: }
255:
256: // 6th field is permissions e.g. (RWED,RWED,RE,)
257: String permissions = null;
258: if (fields.length >= 6) {
259: if (fields[5].charAt(0) == '('
260: && fields[5].charAt(fields[5].length() - 1) == ')') {
261: permissions = fields[5].substring(1,
262: fields[5].length() - 2);
263: }
264: }
265:
266: FTPFile file = new FTPFile(raw, name, size, isDir, lastModified);
267: file.setGroup(group);
268: file.setOwner(owner);
269: file.setPermissions(permissions);
270: return file;
271: }
272:
273: /* (non-Javadoc)
274: * @see com.enterprisedt.net.ftp.FTPFileParser#setLocale(java.util.Locale)
275: */
276: public void setLocale(Locale locale) {
277: formatter1 = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss",
278: locale);
279: formatter2 = new SimpleDateFormat("dd-MMM-yyyy HH:mm", locale);
280: }
281:
282: }
|