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