19 package org.sleuthkit.autopsy.modules.interestingitems;
 
   22 import java.io.FileInputStream;
 
   23 import java.io.FileOutputStream;
 
   24 import java.io.IOException;
 
   25 import java.io.Serializable;
 
   26 import java.nio.file.Path;
 
   27 import java.nio.file.Paths;
 
   28 import java.util.Arrays;
 
   29 import java.util.Collection;
 
   30 import java.util.HashMap;
 
   31 import java.util.List;
 
   33 import java.util.logging.Level;
 
   34 import java.util.regex.Pattern;
 
   35 import java.util.regex.PatternSyntaxException;
 
   36 import javax.xml.parsers.DocumentBuilder;
 
   37 import javax.xml.parsers.DocumentBuilderFactory;
 
   38 import javax.xml.parsers.ParserConfigurationException;
 
   39 import org.apache.commons.lang.StringUtils;
 
   40 import static org.openide.util.NbBundle.Messages;
 
   41 import org.openide.util.io.NbObjectInputStream;
 
   42 import org.openide.util.io.NbObjectOutputStream;
 
   53 import org.w3c.dom.Document;
 
   54 import org.w3c.dom.Element;
 
   55 import org.w3c.dom.NodeList;
 
   56 import java.util.Comparator;
 
   57 import java.util.function.Function;
 
   58 import java.util.stream.Collectors;
 
   60 class InterestingItemsFilesSetSettings 
implements Serializable {
 
   62     private static final long serialVersionUID = 1L;
 
   65     private static final String FILE_SETS_ROOT_TAG = 
"INTERESTING_FILE_SETS"; 
 
   66     private static final String DESC_ATTR = 
"description"; 
 
   67     private static final String IGNORE_KNOWN_FILES_ATTR = 
"ignoreKnown"; 
 
   68     private static final String PATH_REGEX_ATTR = 
"pathRegex"; 
 
   69     private static final String TYPE_FILTER_VALUE_ALL = 
"all";
 
   70     private static final String TYPE_FILTER_VALUE_FILES_AND_DIRS = 
"files_and_dirs"; 
 
   71     private static final String IGNORE_UNALLOCATED_SPACE = 
"ingoreUnallocated"; 
 
   72     private static final String PATH_FILTER_ATTR = 
"pathFilter"; 
 
   73     private static final String TYPE_FILTER_VALUE_DIRS = 
"dir"; 
 
   74     private static final String REGEX_ATTR = 
"regex"; 
 
   75     private static final List<String> illegalFileNameChars = FilesSetsManager.getIllegalFileNameChars();
 
   76     private static final String FILE_SET_TAG = 
"INTERESTING_FILE_SET"; 
 
   77     private static final String NAME_RULE_TAG = 
"NAME"; 
 
   78     private static final String NAME_ATTR = 
"name"; 
 
   79     private static final String DAYS_INCLUDED_ATTR = 
"daysIncluded";
 
   80     private static final String MIME_ATTR = 
"mimeType";
 
   81     private static final String FS_COMPARATOR_ATTR = 
"comparatorSymbol";
 
   82     private static final String FS_SIZE_ATTR = 
"sizeValue";
 
   83     private static final String FS_UNITS_ATTR = 
"sizeUnits";
 
   84     private static final String EXCLUSIVE_ATTR = 
"isExclusive";
 
   85     private static final String TYPE_FILTER_VALUE_FILES = 
"file"; 
 
   86     private static final String XML_ENCODING = 
"UTF-8"; 
 
   87     private static final Logger logger = Logger.getLogger(InterestingItemsFilesSetSettings.class.getName());
 
   88     private static final String TYPE_FILTER_ATTR = 
"typeFilter"; 
 
   89     private static final String EXTENSION_RULE_TAG = 
"EXTENSION"; 
 
   90     private static final String STANDARD_SET = 
"standardSet";
 
   91     private static final String VERSION_NUMBER = 
"versionNumber";
 
   93     private Map<String, FilesSet> filesSets;
 
   95     InterestingItemsFilesSetSettings(Map<String, FilesSet> filesSets) {
 
   96         this.filesSets = filesSets;
 
  102     Map<String, FilesSet> getFilesSets() {
 
  113     private static String readRuleName(Element elem) {
 
  115         String ruleName = elem.getAttribute(NAME_ATTR);
 
  129         "# {0} - filePathStr",
 
  130         "InterestingItemsFilesSetSettings.readSerializedDefinitions.failedReadSettings=Failed to read settings from ''{0}''" 
  132     private static Map<String, FilesSet> readSerializedDefinitions(String basePath, String serialFileName) 
throws FilesSetsManager.FilesSetsManagerException {
 
  133         Path filePath = Paths.get(basePath, serialFileName);
 
  134         File fileSetFile = filePath.toFile();
 
  135         String filePathStr = filePath.toString();
 
  136         if (fileSetFile.exists()) {
 
  138                 try (
final NbObjectInputStream in = 
new NbObjectInputStream(
new FileInputStream(filePathStr))) {
 
  139                     InterestingItemsFilesSetSettings filesSetsSettings = (InterestingItemsFilesSetSettings) in.readObject();
 
  140                     return filesSetsSettings.getFilesSets();
 
  142             } 
catch (IOException | ClassNotFoundException ex) {
 
  144                 throw new FilesSetsManager.FilesSetsManagerException(
 
  145                         Bundle.InterestingItemsFilesSetSettings_readSerializedDefinitions_failedReadSettings(filePathStr),
 
  149             return new HashMap<>();
 
  166         "InterestingItemsFilesSetSettings.readPathCondition.failedCompiledRegex=Error compiling ''{0}'' regex",
 
  168         "InterestingItemsFilesSetSettings.readPathCondition.pathConditionCreationError=Error creating path condition for rule ''{0}''" 
  170     private static ParentPathCondition readPathCondition(Element ruleElement) 
throws FilesSetsManager.FilesSetsManagerException {
 
  173         ParentPathCondition pathCondition = null;
 
  174         if (!ruleElement.getAttribute(PATH_FILTER_ATTR).isEmpty() || !ruleElement.getAttribute(PATH_REGEX_ATTR).isEmpty()) {
 
  175             String path = ruleElement.getAttribute(PATH_FILTER_ATTR);
 
  176             String pathRegex = ruleElement.getAttribute(PATH_REGEX_ATTR);
 
  177             if (!pathRegex.isEmpty() && path.isEmpty()) {
 
  179                     Pattern pattern = Pattern.compile(pathRegex);
 
  180                     pathCondition = 
new ParentPathCondition(pattern);
 
  181                 } 
catch (PatternSyntaxException ex) {
 
  182                     logger.log(Level.SEVERE, 
"Error compiling " + PATH_REGEX_ATTR + 
" regex, ignoring malformed path condition definition", ex); 
 
  183                     throw new FilesSetsManager.FilesSetsManagerException(
 
  184                             Bundle.InterestingItemsFilesSetSettings_readPathCondition_failedCompiledRegex(PATH_REGEX_ATTR),
 
  187             } 
else if (!path.isEmpty() && pathRegex.isEmpty()) {
 
  188                 pathCondition = 
new ParentPathCondition(path);
 
  190             if (pathCondition == null) {
 
  192                 throw new FilesSetsManager.FilesSetsManagerException(
 
  193                         Bundle.InterestingItemsFilesSetSettings_readPathCondition_pathConditionCreationError(readRuleName(ruleElement)));
 
  196         return pathCondition;
 
  212         "InterestingItemsFilesSetSettings.readDateCondition.failedCompiledRegex=Error determining ''{0}'' number",})
 
  213     private static DateCondition readDateCondition(Element ruleElement) 
throws FilesSetsManager.FilesSetsManagerException {
 
  216         DateCondition dateCondition = null;
 
  217         if (!ruleElement.getAttribute(DAYS_INCLUDED_ATTR).isEmpty()) {
 
  218             String daysIncluded = ruleElement.getAttribute(DAYS_INCLUDED_ATTR);
 
  219             if (!daysIncluded.isEmpty()) {
 
  221                     dateCondition = 
new DateCondition(Integer.parseInt(daysIncluded));
 
  222                 } 
catch (NumberFormatException ex) {
 
  223                     logger.log(Level.SEVERE, 
"Error creating condition for " + daysIncluded + 
", ignoring malformed date condition definition", ex); 
 
  225                     throw new FilesSetsManager.FilesSetsManagerException(
 
  226                             Bundle.InterestingItemsFilesSetSettings_readDateCondition_failedCompiledRegex(DAYS_INCLUDED_ATTR),
 
  231         return dateCondition;
 
  241     private static Pattern compileRegex(String regex) {
 
  243             return Pattern.compile(regex);
 
  244         } 
catch (PatternSyntaxException ex) {
 
  245             logger.log(Level.SEVERE, 
"Error compiling rule regex: " + ex.getMessage(), ex); 
 
  264         "InterestingItemsFilesSetSettings.readRule.missingNecessary=Invalid rule in files set, missing necessary conditions for ''{0}''",})
 
  265     private static FilesSet.Rule readRule(Element elem) 
throws FilesSetsManager.FilesSetsManagerException {
 
  266         String ruleName = readRuleName(elem);
 
  267         FileNameCondition nameCondition = readNameCondition(elem);
 
  268         MetaTypeCondition metaCondition = readMetaTypeCondition(elem);
 
  269         ParentPathCondition pathCondition = readPathCondition(elem);
 
  270         MimeTypeCondition mimeCondition = readMimeCondition(elem);
 
  271         FileSizeCondition sizeCondition = readSizeCondition(elem);
 
  272         DateCondition dateCondition = readDateCondition(elem); 
 
  273         Boolean isExclusive = readExclusive(elem);
 
  274         if (metaCondition == null || (nameCondition == null && pathCondition == null && mimeCondition == null && sizeCondition == null && dateCondition == null)) {
 
  275             logger.log(Level.WARNING, 
"Error Reading Rule, " + ruleName + 
" was either missing a meta condition or contained only a meta condition. No rule was imported."); 
 
  277             throw new FilesSetsManager.FilesSetsManagerException(
 
  278                     Bundle.InterestingItemsFilesSetSettings_readRule_missingNecessary(ruleName));
 
  280         return new FilesSet.Rule(ruleName, nameCondition, metaCondition, pathCondition, mimeCondition, sizeCondition, dateCondition, isExclusive);
 
  297         "InterestingItemsFilesSetSettings.readNameCondition.invalidTag=Name condition has invalid tag name of ''{0}'' for rule ''{1}''",
 
  300         "InterestingItemsFilesSetSettings.readNameCondition.errorCompilingRegex=Error compiling ''{0}'' regex in rule ''{1}''",
 
  303         "InterestingItemsFilesSetSettings.readNameCondition.illegalChar=File name has illegal character of ''{0}'' in rule ''{1}''",})
 
  304     private static FileNameCondition readNameCondition(Element elem) 
throws FilesSetsManager.FilesSetsManagerException {
 
  305         FileNameCondition nameCondition = null;
 
  306         String content = elem.getTextContent();
 
  307         String regex = elem.getAttribute(REGEX_ATTR);
 
  308         if (content != null && !content.isEmpty()) {  
 
  309             if ((!regex.isEmpty() && regex.equalsIgnoreCase(
"true")) || content.contains(
"*")) { 
 
  310                 Pattern pattern = compileRegex(content);
 
  311                 if (pattern != null) {
 
  312                     if (elem.getTagName().equals(NAME_RULE_TAG)) {
 
  313                         nameCondition = 
new FilesSet.Rule.FullNameCondition(pattern);
 
  314                     } 
else if (elem.getTagName().equals(EXTENSION_RULE_TAG)) {
 
  315                         nameCondition = 
new FilesSet.Rule.ExtensionCondition(pattern);
 
  317                         throw new FilesSetsManager.FilesSetsManagerException(
 
  318                                 Bundle.InterestingItemsFilesSetSettings_readNameCondition_invalidTag(elem.getTagName(), readRuleName(elem)));
 
  321                     logger.log(Level.SEVERE, 
"Error compiling " + elem.getTagName() + 
" regex, ignoring malformed ''{0}'' rule definition", readRuleName(elem)); 
 
  322                     throw new FilesSetsManager.FilesSetsManagerException(
 
  323                             Bundle.InterestingItemsFilesSetSettings_readNameCondition_errorCompilingRegex(REGEX_ATTR, readRuleName(elem)));
 
  326                 for (String illegalChar : illegalFileNameChars) {
 
  327                     if (content.contains(illegalChar)) {
 
  328                         logger.log(Level.SEVERE, elem.getTagName() + 
" content has illegal chars, ignoring malformed ''{0}'' rule definition", 
new Object[]{elem.getTagName(), readRuleName(elem)}); 
 
  330                         throw new FilesSetsManager.FilesSetsManagerException(
 
  331                                 Bundle.InterestingItemsFilesSetSettings_readNameCondition_illegalChar(illegalChar, readRuleName(elem)));
 
  334                 if (elem.getTagName().equals(NAME_RULE_TAG)) {
 
  335                     nameCondition = 
new FilesSet.Rule.FullNameCondition(content);
 
  336                 } 
else if (elem.getTagName().equals(EXTENSION_RULE_TAG)) {
 
  337                     nameCondition = 
new FilesSet.Rule.ExtensionCondition(Arrays.asList(content.split(
",")));
 
  341         return nameCondition;
 
  352     private static Boolean readExclusive(Element elem) {
 
  353         Boolean isExclusive = null;
 
  354         if (!elem.getAttribute(EXCLUSIVE_ATTR).isEmpty()) {
 
  355             isExclusive = Boolean.parseBoolean(elem.getAttribute(EXCLUSIVE_ATTR));
 
  368     private static MimeTypeCondition readMimeCondition(Element elem) {
 
  369         MimeTypeCondition mimeCondition = null;
 
  370         if (!elem.getAttribute(MIME_ATTR).isEmpty()) {
 
  371             mimeCondition = 
new MimeTypeCondition(elem.getAttribute(MIME_ATTR));
 
  376         return mimeCondition;
 
  392         "InterestingItemsFilesSetSettings.readSizeCondition.notIntegerValue=Non integer size in files set for rule ''{0}''",
 
  394         "InterestingItemsFilesSetSettings.readSizeCondition.invalidComparator=Invalid comparator or size unit in files set for rule ''{0}''",
 
  396         "InterestingItemsFilesSetSettings.readSizeCondition.malformedXml=Files set is malformed missing at least one 'fileSize' attribute for rule ''{0}''",})
 
  397     private static FileSizeCondition readSizeCondition(Element elem) 
throws FilesSetsManager.FilesSetsManagerException {
 
  398         FileSizeCondition sizeCondition = null;
 
  399         if (!elem.getAttribute(FS_COMPARATOR_ATTR).isEmpty() && !elem.getAttribute(FS_SIZE_ATTR).isEmpty() && !elem.getAttribute(FS_UNITS_ATTR).isEmpty()) {
 
  401                 FileSizeCondition.COMPARATOR comparator = FileSizeCondition.COMPARATOR.fromSymbol(elem.getAttribute(FS_COMPARATOR_ATTR));
 
  402                 FileSizeCondition.SIZE_UNIT sizeUnit = FileSizeCondition.SIZE_UNIT.fromName(elem.getAttribute(FS_UNITS_ATTR));
 
  403                 int size = Integer.parseInt(elem.getAttribute(FS_SIZE_ATTR));
 
  404                 sizeCondition = 
new FileSizeCondition(comparator, sizeUnit, size);
 
  405             } 
catch (NumberFormatException nfEx) {
 
  406                 logger.log(Level.SEVERE, 
"Value in file size attribute was not an integer, unable to create FileSizeCondition for rule: " + readRuleName(elem), nfEx);
 
  407                 throw new FilesSetsManager.FilesSetsManagerException(
 
  408                         Bundle.InterestingItemsFilesSetSettings_readSizeCondition_notIntegerValue(readRuleName(elem)),
 
  410             } 
catch (IllegalArgumentException iaEx) {
 
  411                 logger.log(Level.SEVERE, 
"Invalid Comparator symbol or Size Unit set in FilesSet xml, unable to create FileSizeCondition for rule: " + readRuleName(elem), iaEx);
 
  412                 throw new FilesSetsManager.FilesSetsManagerException(
 
  413                         Bundle.InterestingItemsFilesSetSettings_readSizeCondition_invalidComparator(readRuleName(elem)),
 
  417         else if (!elem.getAttribute(FS_COMPARATOR_ATTR).isEmpty() || !elem.getAttribute(FS_SIZE_ATTR).isEmpty() || !elem.getAttribute(FS_UNITS_ATTR).isEmpty()) {
 
  418             logger.log(Level.SEVERE, 
"Invalid Comparator symbol or Size Unit set in FilesSet xml, unable to create FileSizeCondition for rule: " + readRuleName(elem));
 
  419             throw new FilesSetsManager.FilesSetsManagerException(
 
  420                     Bundle.InterestingItemsFilesSetSettings_readSizeCondition_malformedXml(readRuleName(elem)));
 
  422         return sizeCondition;
 
  435     private static void readFilesSet(Element setElem, Map<String, FilesSet> filesSets, String filePath) 
throws FilesSetsManager.FilesSetsManagerException {
 
  437         String setName = setElem.getAttribute(NAME_ATTR);
 
  438         if (setName.isEmpty()) {
 
  439             logger.log(Level.SEVERE, 
"Found {0} element without required {1} attribute, ignoring malformed file set definition in FilesSet definition file at {2}", 
new Object[]{FILE_SET_TAG, NAME_ATTR, filePath}); 
 
  442         if (filesSets.containsKey(setName)) {
 
  443             logger.log(Level.SEVERE, 
"Found duplicate definition of set named {0} in FilesSet definition file at {1}, discarding duplicate set", 
new Object[]{setName, filePath}); 
 
  447         String description = setElem.getAttribute(DESC_ATTR);
 
  450         String ignoreKnown = setElem.getAttribute(IGNORE_KNOWN_FILES_ATTR);
 
  451         boolean ignoreKnownFiles = 
false;
 
  452         if (!ignoreKnown.isEmpty()) {
 
  453             ignoreKnownFiles = Boolean.parseBoolean(ignoreKnown);
 
  457         String ignoreUnallocated = setElem.getAttribute(IGNORE_UNALLOCATED_SPACE);
 
  458         boolean ignoreUnallocatedSpace = 
false;
 
  459         if (!ignoreUnallocated.isEmpty()) {
 
  460             ignoreUnallocatedSpace = Boolean.parseBoolean(ignoreUnallocated);
 
  463         String isStandardSetString = setElem.getAttribute(STANDARD_SET);
 
  464         boolean isStandardSet = 
false;
 
  465         if (StringUtils.isNotBlank(isStandardSetString)) {
 
  466             isStandardSet = Boolean.parseBoolean(isStandardSetString);
 
  469         String versionNumberString = setElem.getAttribute(VERSION_NUMBER);
 
  470         int versionNumber = 0;
 
  471         if (StringUtils.isNotBlank(versionNumberString)) {
 
  473                 versionNumber = Integer.parseInt(versionNumberString);
 
  474             } 
catch (NumberFormatException ex) {
 
  475                 logger.log(Level.WARNING,
 
  476                         String.format(
"Unable to parse version number for files set named: %s with provided input: '%s'", setName, versionNumberString),
 
  482         Map<String, FilesSet.Rule> rules = 
new HashMap<>();
 
  483         NodeList allRuleElems = setElem.getChildNodes();
 
  484         for (
int j = 0; j < allRuleElems.getLength(); ++j) {
 
  485             if (allRuleElems.item(j) instanceof Element) {  
 
  486                 Element elem = (Element) allRuleElems.item(j);
 
  487                 FilesSet.Rule rule = readRule(elem);
 
  489                     if (!rules.containsKey(rule.getUuid())) {
 
  490                         rules.put(rule.getUuid(), rule);
 
  492                         logger.log(Level.SEVERE, 
"Found duplicate rule {0} for set named {1} in FilesSet definition file at {2}, discarding malformed set", 
new Object[]{rule.getUuid(), setName, filePath}); 
 
  496                     logger.log(Level.SEVERE, 
"Found malformed rule for set named {0} in FilesSet definition file at {1}, discarding malformed set", 
new Object[]{setName, filePath}); 
 
  504         FilesSet set = 
new FilesSet(setName, description, ignoreKnownFiles, ignoreUnallocatedSpace, rules, isStandardSet, versionNumber);
 
  505         filesSets.put(set.getName(), set);
 
  523     static Map<String, FilesSet> readDefinitionsFile(String basePath, String fileName, String legacyFileName) 
throws FilesSetsManager.FilesSetsManagerException {
 
  524         Map<String, FilesSet> filesSets = readSerializedDefinitions(basePath, fileName);
 
  525         if (!filesSets.isEmpty()) {
 
  529         if (!legacyFileName.isEmpty()) {
 
  530             return readDefinitionsXML(Paths.get(basePath, legacyFileName).toFile());
 
  548     static Map<String, FilesSet> readDefinitionsXML(File xmlFile) 
throws FilesSetsManager.FilesSetsManagerException {
 
  549         if (!xmlFile.exists()) {
 
  550             return new HashMap<>();
 
  553         if (!xmlFile.canRead()) {
 
  554             logger.log(Level.SEVERE, 
"FilesSet definition file at {0} exists, but cannot be read", xmlFile.getPath()); 
 
  555             return new HashMap<>();
 
  558         Document doc = XMLUtil.loadDoc(InterestingItemsFilesSetSettings.class, xmlFile.getPath());
 
  559         return readDefinitionsXML(doc, xmlFile.getPath());
 
  575     static Map<String, FilesSet> readDefinitionsXML(Document doc, String resourceName) 
throws FilesSetsManager.FilesSetsManagerException {
 
  577         Map<String, FilesSet> filesSets = 
new HashMap<>();
 
  580             logger.log(Level.SEVERE, 
"FilesSet definition file at {0}", resourceName); 
 
  584         Element root = doc.getDocumentElement();
 
  586             logger.log(Level.SEVERE, 
"Failed to get root {0} element tag of FilesSet definition file at {1}",
 
  587                     new Object[]{FILE_SETS_ROOT_TAG, resourceName}); 
 
  591         NodeList setElems = root.getElementsByTagName(FILE_SET_TAG);
 
  592         for (
int i = 0; i < setElems.getLength(); ++i) {
 
  593             readFilesSet((Element) setElems.item(i), filesSets, resourceName);
 
  608     static boolean writeDefinitionsFile(String basePath, String fileName, Map<String, FilesSet> interestingFilesSets) 
throws FilesSetsManager.FilesSetsManagerException {
 
  609         File outputFile = Paths.get(basePath, fileName).toFile();
 
  610         outputFile.getParentFile().mkdirs();
 
  611         try (
final NbObjectOutputStream out = 
new NbObjectOutputStream(
new FileOutputStream(outputFile))) {
 
  612             out.writeObject(
new InterestingItemsFilesSetSettings(interestingFilesSets));
 
  613         } 
catch (IOException ex) {
 
  614             throw new FilesSetsManager.FilesSetsManagerException(String.format(
"Failed to write settings to %s", fileName), ex);
 
  626     private static <T> List<T> sortOnField(Collection<T> itemsToSort, 
final Function<T, String> getName) {
 
  627         Comparator<T> comparator = (a,b) -> {
 
  628             String aName = getName.apply(a);
 
  629             String bName = getName.apply(b);
 
  638             return aName.compareToIgnoreCase(bName);
 
  641         return itemsToSort.stream()
 
  643                 .collect(Collectors.toList());
 
  656     static boolean exportXmlDefinitionsFile(File xmlFile, List<FilesSet> interestingFilesSets) {
 
  657         DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
 
  660             DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
 
  661             Document doc = docBuilder.newDocument();
 
  662             Element rootElement = doc.createElement(FILE_SETS_ROOT_TAG);
 
  663             doc.appendChild(rootElement);
 
  666             List<FilesSet> sortedFilesSets = sortOnField(
 
  667                     interestingFilesSets, 
 
  668                     filesSet -> filesSet == null ? null : filesSet.getName());
 
  670             for (FilesSet set : sortedFilesSets) {
 
  672                 Element setElement = doc.createElement(FILE_SET_TAG);
 
  673                 setElement.setAttribute(NAME_ATTR, set.getName());
 
  674                 setElement.setAttribute(DESC_ATTR, set.getDescription());
 
  675                 setElement.setAttribute(IGNORE_KNOWN_FILES_ATTR, Boolean.toString(set.ignoresKnownFiles()));
 
  676                 setElement.setAttribute(STANDARD_SET, Boolean.toString(set.isStandardSet()));
 
  677                 setElement.setAttribute(VERSION_NUMBER, Integer.toString(set.getVersionNumber()));
 
  681                 List<FilesSet.Rule> sortedRules = sortOnField(
 
  682                         set.getRules().values(), 
 
  683                         rule -> rule == null ? null : rule.getName());
 
  685                 for (FilesSet.Rule rule : sortedRules) {
 
  690                     FileNameCondition nameCondition = rule.getFileNameCondition();
 
  695                     if (nameCondition instanceof FilesSet.Rule.FullNameCondition) {
 
  696                         ruleElement = doc.createElement(NAME_RULE_TAG);
 
  698                         ruleElement = doc.createElement(EXTENSION_RULE_TAG);
 
  701                     ruleElement.setAttribute(NAME_ATTR, rule.getName());
 
  702                     if (nameCondition != null) {
 
  704                         ruleElement.setAttribute(REGEX_ATTR, Boolean.toString(nameCondition.isRegex()));
 
  706                         ruleElement.setTextContent(nameCondition.getTextToMatch());
 
  709                     MetaTypeCondition typeCondition = rule.getMetaTypeCondition();
 
  710                     switch (typeCondition.getMetaType()) {
 
  712                             ruleElement.setAttribute(TYPE_FILTER_ATTR, TYPE_FILTER_VALUE_FILES);
 
  715                             ruleElement.setAttribute(TYPE_FILTER_ATTR, TYPE_FILTER_VALUE_DIRS);
 
  718                             ruleElement.setAttribute(TYPE_FILTER_ATTR, TYPE_FILTER_VALUE_ALL);
 
  722                     ParentPathCondition pathCondition = rule.getPathCondition();
 
  723                     if (pathCondition != null) {
 
  724                         if (pathCondition.isRegex()) {
 
  725                             ruleElement.setAttribute(PATH_REGEX_ATTR, pathCondition.getTextToMatch());
 
  727                             ruleElement.setAttribute(PATH_FILTER_ATTR, pathCondition.getTextToMatch());
 
  731                     MimeTypeCondition mimeCondition = rule.getMimeTypeCondition();
 
  732                     if (mimeCondition != null) {
 
  733                         ruleElement.setAttribute(MIME_ATTR, mimeCondition.getMimeType());
 
  736                     FileSizeCondition sizeCondition = rule.getFileSizeCondition();
 
  737                     if (sizeCondition != null) {
 
  738                         ruleElement.setAttribute(FS_COMPARATOR_ATTR, sizeCondition.getComparator().getSymbol());
 
  739                         ruleElement.setAttribute(FS_SIZE_ATTR, Integer.toString(sizeCondition.getSizeValue()));
 
  740                         ruleElement.setAttribute(FS_UNITS_ATTR, sizeCondition.getUnit().getName());
 
  744                     DateCondition dateCondition = rule.getDateCondition();
 
  745                     if (dateCondition != null) {
 
  746                         ruleElement.setAttribute(DAYS_INCLUDED_ATTR, Integer.toString(dateCondition.getDaysIncluded()));
 
  749                     ruleElement.setAttribute(EXCLUSIVE_ATTR, Boolean.toString(rule.isExclusive()));
 
  751                     setElement.appendChild(ruleElement);
 
  753                 rootElement.appendChild(setElement);
 
  757             return XMLUtil.saveDoc(InterestingItemsFilesSetSettings.class, xmlFile.getPath(), XML_ENCODING, doc);
 
  758         } 
catch (ParserConfigurationException ex) {
 
  759             logger.log(Level.SEVERE, 
"Error writing interesting files definition file to " + xmlFile.getPath(), ex); 
 
  778         "InterestingItemsFilesSetSettings.readMetaTypeCondition.malformedXml=Files set is malformed for metatype condition, ''{0}'', in rule ''{1}''" 
  780     private static MetaTypeCondition readMetaTypeCondition(Element ruleElement) 
throws FilesSetsManager.FilesSetsManagerException {
 
  781         MetaTypeCondition metaCondition = null;
 
  784         if (!ruleElement.getAttribute(TYPE_FILTER_ATTR).isEmpty()) {
 
  785             String conditionAttribute = ruleElement.getAttribute(TYPE_FILTER_ATTR);
 
  786             if (!conditionAttribute.isEmpty()) {
 
  787                 switch (conditionAttribute) {
 
  788                     case TYPE_FILTER_VALUE_FILES:
 
  789                         metaCondition = 
new MetaTypeCondition(MetaTypeCondition.Type.FILES);
 
  791                     case TYPE_FILTER_VALUE_DIRS:
 
  792                         metaCondition = 
new MetaTypeCondition(MetaTypeCondition.Type.DIRECTORIES);
 
  794                     case TYPE_FILTER_VALUE_ALL:
 
  795                     case TYPE_FILTER_VALUE_FILES_AND_DIRS:  
 
  796                         metaCondition = 
new MetaTypeCondition(MetaTypeCondition.Type.ALL);
 
  799                         logger.log(Level.SEVERE, 
"Found {0} " + TYPE_FILTER_ATTR + 
" attribute with unrecognized value ''{0}'', ignoring malformed rule definition", conditionAttribute); 
 
  802                         throw new FilesSetsManager.FilesSetsManagerException(
 
  803                                 Bundle.InterestingItemsFilesSetSettings_readMetaTypeCondition_malformedXml(
 
  804                                         conditionAttribute, readRuleName(ruleElement)));
 
  808         if (metaCondition == null) {
 
  811             metaCondition = 
new MetaTypeCondition(MetaTypeCondition.Type.FILES);
 
  813         return metaCondition;