java/alt2xml-in-fs/src/cz/frantovo/alt2xml/in/fs/Reader.java
author František Kučera <franta-hg@frantovo.cz>
Thu, 24 Oct 2019 21:56:03 +0200
changeset 111 e4900596abdb
parent 109 76df01fc4aa2
permissions -rw-r--r--
fix license version: GNU GPLv3
franta-hg@11
     1
/**
franta-hg@11
     2
 * Alt2XML
franta-hg@11
     3
 * Copyright © 2014 František Kučera (frantovo.cz)
franta-hg@11
     4
 *
franta-hg@11
     5
 * This program is free software: you can redistribute it and/or modify
franta-hg@11
     6
 * it under the terms of the GNU General Public License as published by
franta-hg@111
     7
 * the Free Software Foundation, version 3 of the License.
franta-hg@11
     8
 *
franta-hg@11
     9
 * This program is distributed in the hope that it will be useful,
franta-hg@11
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
franta-hg@11
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
franta-hg@11
    12
 * GNU General Public License for more details.
franta-hg@11
    13
 *
franta-hg@11
    14
 * You should have received a copy of the GNU General Public License
franta-hg@11
    15
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
franta-hg@11
    16
 */
franta-hg@103
    17
package cz.frantovo.alt2xml.in.fs;
franta-hg@2
    18
franta-hg@17
    19
import cz.frantovo.alt2xml.AbstractAlt2XmlReader;
franta-hg@103
    20
import java.io.File;
franta-hg@2
    21
import java.io.IOException;
franta-hg@103
    22
import java.net.URI;
franta-hg@103
    23
import java.net.URISyntaxException;
franta-hg@106
    24
import java.nio.ByteBuffer;
franta-hg@106
    25
import java.nio.file.Files;
franta-hg@106
    26
import java.nio.file.LinkOption;
franta-hg@106
    27
import java.nio.file.Path;
franta-hg@106
    28
import java.nio.file.attribute.PosixFilePermission;
franta-hg@106
    29
import java.nio.file.attribute.UserDefinedFileAttributeView;
franta-hg@106
    30
import java.nio.file.spi.FileSystemProvider;
franta-hg@106
    31
import java.util.List;
franta-hg@106
    32
import java.util.ArrayList;
franta-hg@106
    33
import java.util.Set;
franta-hg@77
    34
import java.util.logging.Logger;
franta-hg@103
    35
import org.xml.sax.Attributes;
franta-hg@2
    36
import org.xml.sax.InputSource;
franta-hg@2
    37
import org.xml.sax.SAXException;
franta-hg@92
    38
import org.xml.sax.helpers.AttributesImpl;
franta-hg@2
    39
franta-hg@2
    40
/**
franta-hg@103
    41
 * Reads filesystem – hierarchical structure of directories and files.
franta-hg@2
    42
 *
franta-hg@17
    43
 * @author Ing. František Kučera (frantovo.cz)
franta-hg@2
    44
 */
franta-hg@17
    45
public class Reader extends AbstractAlt2XmlReader {
franta-hg@13
    46
franta-hg@103
    47
	public static final String ROOT_ELEMENT = "fs";
franta-hg@103
    48
	public static final String DIR_ELEMENT = "dir";
franta-hg@103
    49
	public static final String FILE_ELEMENT = "file";
franta-hg@106
    50
	public static final String XATTR_ELEMENT = "xattr";
franta-hg@106
    51
	public static final String PERMISSIONS_ELEMENT = "mode";
franta-hg@106
    52
	public static final String PERMISSIONS_U_ELEMENT = "user";
franta-hg@106
    53
	public static final String PERMISSIONS_G_ELEMENT = "group";
franta-hg@106
    54
	public static final String PERMISSIONS_O_ELEMENT = "others";
franta-hg@103
    55
	public static final String NAME_ATTRIBUTE = "name";
franta-hg@106
    56
	public static final String ABSOLUTE_PATH_ATTRIBUTE = "path";
franta-hg@106
    57
	public static final String SIZE_ATTRIBUTE = "size";
franta-hg@77
    58
	private static final Logger log = Logger.getLogger(Reader.class.getName());
franta-hg@77
    59
franta-hg@106
    60
	/**
franta-hg@106
    61
	 * indentation level
franta-hg@106
    62
	 */
franta-hg@106
    63
	private int level = 0;
franta-hg@106
    64
franta-hg@2
    65
	@Override
franta-hg@6
    66
	public void parse(InputSource input) throws IOException, SAXException {
franta-hg@103
    67
		File dir = getFile(input.getSystemId());
franta-hg@77
    68
franta-hg@103
    69
		outputStart(dir);
franta-hg@103
    70
		outputDir(dir);
franta-hg@59
    71
		outputEnd();
franta-hg@59
    72
	}
franta-hg@59
    73
franta-hg@103
    74
	private File getFile(String systemId) throws IOException {
franta-hg@103
    75
		try {
franta-hg@103
    76
			return new File(new URI(systemId));
franta-hg@103
    77
		} catch (URISyntaxException e) {
franta-hg@103
    78
			throw new IOException("Invalid dir URI", e);
franta-hg@103
    79
		}
franta-hg@103
    80
	}
franta-hg@103
    81
franta-hg@106
    82
	private String getAbsolutePath(File file) throws IOException {
franta-hg@106
    83
		return file.getCanonicalFile().getAbsolutePath();
franta-hg@106
    84
	}
franta-hg@106
    85
franta-hg@106
    86
	private Attributes singleAttribute(String name, int value) {
franta-hg@106
    87
		AttributesImpl attributes = new AttributesImpl();
franta-hg@106
    88
		addAttribute(attributes, name, value);
franta-hg@106
    89
		return attributes;
franta-hg@106
    90
	}
franta-hg@109
    91
franta-hg@103
    92
	private Attributes singleAttribute(String name, String value) {
franta-hg@103
    93
		AttributesImpl attributes = new AttributesImpl();
franta-hg@106
    94
		addAttribute(attributes, name, value);
franta-hg@103
    95
		return attributes;
franta-hg@103
    96
	}
franta-hg@103
    97
franta-hg@106
    98
	private void addAttribute(AttributesImpl attributes, String name, int value) {
franta-hg@106
    99
		attributes.addAttribute(null, name, name, "xs:int", String.valueOf(value));
franta-hg@106
   100
	}
franta-hg@106
   101
franta-hg@106
   102
	private void addAttribute(AttributesImpl attributes, String name, long value) {
franta-hg@106
   103
		attributes.addAttribute(null, name, name, "xs:long", String.valueOf(value));
franta-hg@106
   104
	}
franta-hg@106
   105
franta-hg@106
   106
	private void addAttribute(AttributesImpl attributes, String name, String value) {
franta-hg@106
   107
		attributes.addAttribute(null, name, name, "xs:string", value);
franta-hg@106
   108
	}
franta-hg@106
   109
franta-hg@106
   110
	private void outputStart(File root) throws SAXException, IOException {
franta-hg@21
   111
		contentHandler.startDocument();
franta-hg@76
   112
		contentHandler.lineBreak();
franta-hg@106
   113
		contentHandler.startElement(null, null, ROOT_ELEMENT, singleAttribute(ABSOLUTE_PATH_ATTRIBUTE, getAbsolutePath(root)));
franta-hg@75
   114
		contentHandler.lineBreak();
franta-hg@59
   115
	}
franta-hg@59
   116
franta-hg@59
   117
	private void outputEnd() throws SAXException {
franta-hg@102
   118
		contentHandler.endElement(null, null, ROOT_ELEMENT);
franta-hg@75
   119
		contentHandler.lineBreak();
franta-hg@21
   120
		contentHandler.endDocument();
franta-hg@6
   121
	}
franta-hg@76
   122
franta-hg@106
   123
	private void outputFile(File file) throws SAXException, IOException {
franta-hg@106
   124
		level++;
franta-hg@106
   125
franta-hg@106
   126
		AttributesImpl attributes = new AttributesImpl();
franta-hg@106
   127
		addAttribute(attributes, NAME_ATTRIBUTE, file.getName());
franta-hg@106
   128
		addAttribute(attributes, ABSOLUTE_PATH_ATTRIBUTE, getAbsolutePath(file));
franta-hg@106
   129
		addAttribute(attributes, SIZE_ATTRIBUTE, file.length());
franta-hg@106
   130
franta-hg@106
   131
		contentHandler.indentation(level);
franta-hg@106
   132
		contentHandler.startElement(null, null, FILE_ELEMENT, attributes);
franta-hg@103
   133
		contentHandler.lineBreak();
franta-hg@77
   134
franta-hg@106
   135
		outputPermissions(file.toPath());
franta-hg@106
   136
		outputExtendedAttributes(file);
franta-hg@77
   137
franta-hg@106
   138
		contentHandler.indentation(level);
franta-hg@103
   139
		contentHandler.endElement(null, null, FILE_ELEMENT);
franta-hg@103
   140
		contentHandler.lineBreak();
franta-hg@106
   141
franta-hg@106
   142
		level--;
franta-hg@77
   143
	}
franta-hg@77
   144
franta-hg@106
   145
	private void outputDir(File dir) throws SAXException, IOException {
franta-hg@106
   146
		level++;
franta-hg@89
   147
franta-hg@106
   148
		final File[] children = dir.listFiles();
franta-hg@106
   149
franta-hg@106
   150
		AttributesImpl attributes = new AttributesImpl();
franta-hg@106
   151
		addAttribute(attributes, NAME_ATTRIBUTE, dir.getName());
franta-hg@106
   152
		addAttribute(attributes, ABSOLUTE_PATH_ATTRIBUTE, getAbsolutePath(dir));
franta-hg@106
   153
		addAttribute(attributes, SIZE_ATTRIBUTE, children.length);
franta-hg@106
   154
franta-hg@106
   155
		contentHandler.indentation(level);
franta-hg@106
   156
		contentHandler.startElement(null, null, DIR_ELEMENT, attributes);
franta-hg@103
   157
		contentHandler.lineBreak();
franta-hg@77
   158
franta-hg@106
   159
		outputPermissions(dir.toPath());
franta-hg@106
   160
		outputExtendedAttributes(dir);
franta-hg@106
   161
franta-hg@106
   162
		for (File file : children) {
franta-hg@103
   163
			if (file.isDirectory()) {
franta-hg@103
   164
				outputDir(file);
franta-hg@103
   165
			} else {
franta-hg@103
   166
				outputFile(file);
franta-hg@81
   167
			}
franta-hg@77
   168
		}
franta-hg@77
   169
franta-hg@106
   170
		contentHandler.indentation(level);
franta-hg@103
   171
		contentHandler.endElement(null, null, DIR_ELEMENT);
franta-hg@103
   172
		contentHandler.lineBreak();
franta-hg@106
   173
franta-hg@106
   174
		level--;
franta-hg@106
   175
	}
franta-hg@106
   176
franta-hg@106
   177
	private String encodeElementName(String originalName) {
franta-hg@106
   178
		/**
franta-hg@106
   179
		 * TODO: encode and/or skip invalid characters
franta-hg@106
   180
		 */
franta-hg@106
   181
		return originalName;
franta-hg@106
   182
	}
franta-hg@106
   183
franta-hg@106
   184
	private void outputPermissions(Path path) throws IOException, SAXException {
franta-hg@106
   185
		level++;
franta-hg@109
   186
		Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(path); // TODO: maybe symlinks: LinkOption.NOFOLLOW_LINKS
franta-hg@106
   187
franta-hg@106
   188
		contentHandler.indentation(level);
franta-hg@106
   189
		contentHandler.startElement(null, PERMISSIONS_ELEMENT, PERMISSIONS_ELEMENT, singleAttribute("octal", getOctal(permissions)));
franta-hg@106
   190
		contentHandler.lineBreak();
franta-hg@106
   191
franta-hg@106
   192
		level++;
franta-hg@106
   193
franta-hg@106
   194
		outputPermission("owner", permissions.contains(PosixFilePermission.OWNER_READ), permissions.contains(PosixFilePermission.OWNER_WRITE), permissions.contains(PosixFilePermission.OWNER_EXECUTE));
franta-hg@106
   195
		outputPermission("group", permissions.contains(PosixFilePermission.GROUP_READ), permissions.contains(PosixFilePermission.GROUP_WRITE), permissions.contains(PosixFilePermission.GROUP_EXECUTE));
franta-hg@106
   196
		outputPermission("others", permissions.contains(PosixFilePermission.OTHERS_READ), permissions.contains(PosixFilePermission.OTHERS_WRITE), permissions.contains(PosixFilePermission.OTHERS_EXECUTE));
franta-hg@106
   197
franta-hg@106
   198
		level--;
franta-hg@106
   199
franta-hg@106
   200
		contentHandler.indentation(level);
franta-hg@106
   201
		contentHandler.endElement(null, PERMISSIONS_ELEMENT, PERMISSIONS_ELEMENT);
franta-hg@106
   202
		contentHandler.lineBreak();
franta-hg@106
   203
franta-hg@106
   204
		level--;
franta-hg@106
   205
	}
franta-hg@106
   206
franta-hg@106
   207
	private int getOctal(Set<PosixFilePermission> permissions) {
franta-hg@106
   208
		int octal = 0;
franta-hg@109
   209
franta-hg@106
   210
		octal = octal + 100 * (permissions.contains(PosixFilePermission.OWNER_READ) ? 4 : 0);
franta-hg@106
   211
		octal = octal + 100 * (permissions.contains(PosixFilePermission.OWNER_WRITE) ? 2 : 0);
franta-hg@106
   212
		octal = octal + 100 * (permissions.contains(PosixFilePermission.OWNER_EXECUTE) ? 1 : 0);
franta-hg@109
   213
franta-hg@106
   214
		octal = octal + 10 * (permissions.contains(PosixFilePermission.GROUP_READ) ? 4 : 0);
franta-hg@106
   215
		octal = octal + 10 * (permissions.contains(PosixFilePermission.GROUP_WRITE) ? 2 : 0);
franta-hg@106
   216
		octal = octal + 10 * (permissions.contains(PosixFilePermission.GROUP_EXECUTE) ? 1 : 0);
franta-hg@109
   217
franta-hg@106
   218
		octal = octal + 1 * (permissions.contains(PosixFilePermission.OTHERS_READ) ? 4 : 0);
franta-hg@106
   219
		octal = octal + 1 * (permissions.contains(PosixFilePermission.OTHERS_WRITE) ? 2 : 0);
franta-hg@106
   220
		octal = octal + 1 * (permissions.contains(PosixFilePermission.OTHERS_EXECUTE) ? 1 : 0);
franta-hg@106
   221
franta-hg@106
   222
		return octal;
franta-hg@106
   223
	}
franta-hg@106
   224
franta-hg@106
   225
	private void outputPermission(String name, boolean read, boolean write, boolean execute) throws SAXException {
franta-hg@106
   226
		contentHandler.indentation(level);
franta-hg@106
   227
		AttributesImpl attributes = new AttributesImpl();
franta-hg@106
   228
		attributes.addAttribute(null, "read", "read", "xs:boolean", String.valueOf(read));
franta-hg@106
   229
		attributes.addAttribute(null, "write", "write", "xs:boolean", String.valueOf(write));
franta-hg@106
   230
		attributes.addAttribute(null, "execute", "execute", "xs:boolean", String.valueOf(execute));
franta-hg@106
   231
		contentHandler.startElement(null, name, name, attributes);
franta-hg@106
   232
		contentHandler.endElement(null, name, name);
franta-hg@106
   233
		contentHandler.lineBreak();
franta-hg@106
   234
	}
franta-hg@106
   235
franta-hg@106
   236
	private void outputExtendedAttributes(File file) throws IOException, SAXException {
franta-hg@106
   237
		level++;
franta-hg@106
   238
franta-hg@106
   239
		final List<ExtendedAttribute> extendedAttributes = getExtendedAttributes(file);
franta-hg@106
   240
franta-hg@106
   241
		if (!extendedAttributes.isEmpty()) {
franta-hg@106
   242
			contentHandler.indentation(level);
franta-hg@106
   243
			contentHandler.startElement(null, XATTR_ELEMENT, XATTR_ELEMENT, null);
franta-hg@106
   244
			contentHandler.lineBreak();
franta-hg@106
   245
			level++;
franta-hg@106
   246
			for (ExtendedAttribute ea : extendedAttributes) {
franta-hg@106
   247
				contentHandler.indentation(level);
franta-hg@106
   248
				String elementName = encodeElementName(ea.getKey());
franta-hg@106
   249
				contentHandler.textElement(ea.getValue(), null, elementName, elementName, null);
franta-hg@106
   250
				contentHandler.lineBreak();
franta-hg@106
   251
			}
franta-hg@106
   252
			level--;
franta-hg@106
   253
			contentHandler.indentation(level);
franta-hg@106
   254
			contentHandler.endElement(null, XATTR_ELEMENT, XATTR_ELEMENT);
franta-hg@106
   255
			contentHandler.lineBreak();
franta-hg@106
   256
		}
franta-hg@106
   257
franta-hg@106
   258
		level--;
franta-hg@106
   259
	}
franta-hg@106
   260
franta-hg@106
   261
	private List<ExtendedAttribute> getExtendedAttributes(File file) throws IOException {
franta-hg@106
   262
franta-hg@106
   263
		List<ExtendedAttribute> l = new ArrayList<>();
franta-hg@106
   264
franta-hg@106
   265
		Path path = file.toPath();
franta-hg@106
   266
		FileSystemProvider provider = path.getFileSystem().provider();
franta-hg@106
   267
		UserDefinedFileAttributeView attributes = provider.getFileAttributeView(path, UserDefinedFileAttributeView.class);
franta-hg@106
   268
franta-hg@106
   269
		for (String jménoAtributu : attributes.list()) {
franta-hg@106
   270
			ByteBuffer hodnotaAtributu = ByteBuffer.allocate(attributes.size(jménoAtributu));
franta-hg@106
   271
			attributes.read(jménoAtributu, hodnotaAtributu);
franta-hg@106
   272
			l.add(new ExtendedAttribute(jménoAtributu, hodnotaAtributu));
franta-hg@106
   273
		}
franta-hg@106
   274
franta-hg@106
   275
		return l;
franta-hg@106
   276
franta-hg@77
   277
	}
franta-hg@2
   278
}