/* * plist - An open source library to parse and generate property lists * Copyright (C) 2011 Daniel Dreibrodt * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package com.dd.plist; import java.io.IOException; import java.util.*; /** * A set is an interface to an unordered collection of objects. * This implementation uses a <code>LinkedHashSet</code> or <code>TreeSet</code>as the underlying * data structure. * * @author Daniel Dreibrodt * @see LinkedHashSet */ public class NSSet extends NSObject { private Set<NSObject> set; private boolean ordered = false; /** * Creates an empty unordered set. * * @see java.util.LinkedHashSet */ public NSSet() { set = new LinkedHashSet<NSObject>(); } /** * Creates an empty set. * * @param ordered Indicates whether the created set should be ordered or unordered. * @see java.util.LinkedHashSet * @see java.util.TreeSet */ public NSSet(boolean ordered) { this.ordered = ordered; if (!ordered) set = new LinkedHashSet<NSObject>(); else set = new TreeSet<NSObject>(); } /** * Create a set and fill it with the given objects. * * @param objects The objects to populate the set. * @see java.util.LinkedHashSet */ public NSSet(NSObject... objects) { set = new LinkedHashSet<NSObject>(); set.addAll(Arrays.asList(objects)); } /** * Create a set and fill it with the given objects. * * @param ordered Indicates whether the created set should be ordered or unordered. * @param objects The objects to populate the set. * @see java.util.LinkedHashSet * @see java.util.TreeSet */ public NSSet(boolean ordered, NSObject... objects) { this.ordered = ordered; if (!ordered) set = new LinkedHashSet<NSObject>(); else set = new TreeSet<NSObject>(); set.addAll(Arrays.asList(objects)); } /** * Adds an object to the set. * * @param obj The object to add. */ public synchronized void addObject(NSObject obj) { set.add(obj); } /** * Removes an object from the set. * * @param obj The object to remove. */ public synchronized void removeObject(NSObject obj) { set.remove(obj); } /** * Returns all objects contained in the set. * * @return An array of all objects in the set. */ public synchronized NSObject[] allObjects() { return set.toArray(new NSObject[count()]); } /** * Returns one of the objects in the set, or <code>null</code> * if the set contains no objects. * * @return The first object in the set, or <code>null</code> if the set is empty. */ public synchronized NSObject anyObject() { if (set.isEmpty()) return null; else return set.iterator().next(); } /** * Finds out whether a given object is contained in the set. * * @param obj The object to look for. * @return <code>true</code>, when the object was found, <code>false</code> otherwise. */ public boolean containsObject(NSObject obj) { return set.contains(obj); } /** * Determines whether the set contains an object equal to a given object * and returns that object if it is present. * * @param obj The object to look for. * @return The object if it is present, <code>null</code> otherwise. */ public synchronized NSObject member(NSObject obj) { for (NSObject o : set) { if (o.equals(obj)) return o; } return null; } /** * Finds out whether at least one object is present in both sets. * * @param otherSet The other set. * @return <code>false</code> if the intersection of both sets is empty, <code>true</code> otherwise. */ public synchronized boolean intersectsSet(NSSet otherSet) { for (NSObject o : set) { if (otherSet.containsObject(o)) return true; } return false; } /** * Finds out if this set is a subset of the given set. * * @param otherSet The other set. * @return <code>true</code> if all elements in this set are also present in the other set, <code>false</code> otherwise. */ public synchronized boolean isSubsetOfSet(NSSet otherSet) { for (NSObject o : set) { if (!otherSet.containsObject(o)) return false; } return true; } /** * Returns an iterator object that lets you iterate over all elements of the set. * This is the equivalent to <code>objectEnumerator</code> in the Cocoa implementation * of NSSet. * * @return The iterator for the set. */ public synchronized Iterator<NSObject> objectIterator() { return set.iterator(); } /** * Gets the underlying data structure in which this NSSets stores its content. * @return A Set object. */ Set<NSObject> getSet() { return set; } @Override public int hashCode() { int hash = 7; hash = 29 * hash + (this.set != null ? this.set.hashCode() : 0); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final NSSet other = (NSSet) obj; return !(this.set != other.set && (this.set == null || !this.set.equals(other.set))); } /** * Gets the number of elements in the set. * * @return The number of elements in the set. * @see Set#size() */ public synchronized int count() { return set.size(); } /** * Returns the XML representantion for this set. * There is no official XML representation specified for sets. * In this implementation it is represented by an array. * * @param xml The XML StringBuilder * @param level The indentation level */ @Override void toXML(StringBuilder xml, int level) { indent(xml, level); xml.append("<array>"); xml.append(NSObject.NEWLINE); for (NSObject o : set) { o.toXML(xml, level + 1); xml.append(NSObject.NEWLINE); } indent(xml, level); xml.append("</array>"); } @Override void assignIDs(BinaryPropertyListWriter out) { super.assignIDs(out); for (NSObject obj : set) { obj.assignIDs(out); } } @Override void toBinary(BinaryPropertyListWriter out) throws IOException { if (ordered) { out.writeIntHeader(0xB, set.size()); } else { out.writeIntHeader(0xC, set.size()); } for (NSObject obj : set) { out.writeID(out.getID(obj)); } } /** * Returns the ASCII representation of this set. * There is no official ASCII representation for sets. * In this implementation sets are represented as arrays. * * @param ascii The ASCII file string builder * @param level The indentation level */ @Override protected void toASCII(StringBuilder ascii, int level) { indent(ascii, level); NSObject[] array = allObjects(); ascii.append(ASCIIPropertyListParser.ARRAY_BEGIN_TOKEN); int indexOfLastNewLine = ascii.lastIndexOf(NEWLINE); for (int i = 0; i < array.length; i++) { Class<?> objClass = array[i].getClass(); if ((objClass.equals(NSDictionary.class) || objClass.equals(NSArray.class) || objClass.equals(NSData.class)) && indexOfLastNewLine != ascii.length()) { ascii.append(NEWLINE); indexOfLastNewLine = ascii.length(); array[i].toASCII(ascii, level + 1); } else { if (i != 0) ascii.append(" "); array[i].toASCII(ascii, 0); } if (i != array.length - 1) ascii.append(ASCIIPropertyListParser.ARRAY_ITEM_DELIMITER_TOKEN); if (ascii.length() - indexOfLastNewLine > ASCII_LINE_LENGTH) { ascii.append(NEWLINE); indexOfLastNewLine = ascii.length(); } } ascii.append(ASCIIPropertyListParser.ARRAY_END_TOKEN); } /** * Returns the ASCII representation of this set according to the GnuStep format. * There is no official ASCII representation for sets. * In this implementation sets are represented as arrays. * * @param ascii The ASCII file string builder * @param level The indentation level */ @Override protected void toASCIIGnuStep(StringBuilder ascii, int level) { indent(ascii, level); NSObject[] array = allObjects(); ascii.append(ASCIIPropertyListParser.ARRAY_BEGIN_TOKEN); int indexOfLastNewLine = ascii.lastIndexOf(NEWLINE); for (int i = 0; i < array.length; i++) { Class<?> objClass = array[i].getClass(); if ((objClass.equals(NSDictionary.class) || objClass.equals(NSArray.class) || objClass.equals(NSData.class)) && indexOfLastNewLine != ascii.length()) { ascii.append(NEWLINE); indexOfLastNewLine = ascii.length(); array[i].toASCIIGnuStep(ascii, level + 1); } else { if (i != 0) ascii.append(" "); array[i].toASCIIGnuStep(ascii, 0); } if (i != array.length - 1) ascii.append(ASCIIPropertyListParser.ARRAY_ITEM_DELIMITER_TOKEN); if (ascii.length() - indexOfLastNewLine > ASCII_LINE_LENGTH) { ascii.append(NEWLINE); indexOfLastNewLine = ascii.length(); } } ascii.append(ASCIIPropertyListParser.ARRAY_END_TOKEN); } }