1    
2    /* ====================================================================
3     * The Apache Software License, Version 1.1
4     *
5     * Copyright (c) 2002 The Apache Software Foundation.  All rights
6     * reserved.
7     *
8     * Redistribution and use in source and binary forms, with or without
9     * modification, are permitted provided that the following conditions
10    * are met:
11    *
12    * 1. Redistributions of source code must retain the above copyright
13    *    notice, this list of conditions and the following disclaimer.
14    *
15    * 2. Redistributions in binary form must reproduce the above copyright
16    *    notice, this list of conditions and the following disclaimer in
17    *    the documentation and/or other materials provided with the
18    *    distribution.
19    *
20    * 3. The end-user documentation included with the redistribution,
21    *    if any, must include the following acknowledgment:
22    *       "This product includes software developed by the
23    *        Apache Software Foundation (http://www.apache.org/)."
24    *    Alternately, this acknowledgment may appear in the software itself,
25    *    if and wherever such third-party acknowledgments normally appear.
26    *
27    * 4. The names "Apache" and "Apache Software Foundation" and
28    *    "Apache POI" must not be used to endorse or promote products
29    *    derived from this software without prior written permission. For
30    *    written permission, please contact apache@apache.org.
31    *
32    * 5. Products derived from this software may not be called "Apache",
33    *    "Apache POI", nor may "Apache" appear in their name, without
34    *    prior written permission of the Apache Software Foundation.
35    *
36    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37    * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38    * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39    * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40    * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41    * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43    * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47    * SUCH DAMAGE.
48    * ====================================================================
49    *
50    * This software consists of voluntary contributions made by many
51    * individuals on behalf of the Apache Software Foundation.  For more
52    * information on the Apache Software Foundation, please see
53    * <http://www.apache.org/>.
54    */
55   
56   package org.apache.poi.poifs.property;
57   
58   import java.util.*;
59   
60   import java.io.IOException;
61   
62   import org.apache.poi.poifs.storage.SmallDocumentBlock;
63   
64   /**
65    * Directory property
66    *
67    * @author Marc Johnson (mjohnson at apache dot org)
68    */
69   
70   public class DirectoryProperty
71       extends Property
72       implements Parent
73   {
74   
75       // List of Property instances
76       private List _children;
77   
78       // set of children's names
79       private Set  _children_names;
80   
81       /**
82        * Default constructor
83        *
84        * @param name the name of the directory
85        */
86   
87       public DirectoryProperty(String name)
88       {
89           super();
90           _children       = new ArrayList();
91           _children_names = new HashSet();
92           setName(name);
93           setSize(0);
94           setPropertyType(PropertyConstants.DIRECTORY_TYPE);
95           setStartBlock(0);
96           setNodeColor(_NODE_BLACK);   // simplification
97       }
98   
99       /**
100       * reader constructor
101       *
102       * @param index index number
103       * @param array byte data
104       * @param offset offset into byte data
105       */
106  
107      protected DirectoryProperty(final int index, final byte [] array,
108                                  final int offset)
109      {
110          super(index, array, offset);
111          _children       = new ArrayList();
112          _children_names = new HashSet();
113      }
114  
115      /**
116       * Change a Property's name
117       *
118       * @param property the Property whose name is being changed
119       * @param newName the new name for the Property
120       *
121       * @return true if the name change could be made, else false
122       */
123  
124      public boolean changeName(final Property property, final String newName)
125      {
126          boolean result;
127          String  oldName = property.getName();
128  
129          property.setName(newName);
130          String cleanNewName = property.getName();
131  
132          if (_children_names.contains(cleanNewName))
133          {
134  
135              // revert the change
136              property.setName(oldName);
137              result = false;
138          }
139          else
140          {
141              _children_names.add(cleanNewName);
142              _children_names.remove(oldName);
143              result = true;
144          }
145          return result;
146      }
147  
148      /**
149       * Delete a Property
150       *
151       * @param property the Property being deleted
152       *
153       * @return true if the Property could be deleted, else false
154       */
155  
156      public boolean deleteChild(final Property property)
157      {
158          boolean result = _children.remove(property);
159  
160          if (result)
161          {
162              _children_names.remove(property.getName());
163          }
164          return result;
165      }
166  
167      private class PropertyComparator
168          implements Comparator
169      {
170  
171          /**
172           * Object equality, implemented as object identity
173           *
174           * @param o Object we're being compared to
175           *
176           * @return true if identical, else false
177           */
178  
179          public boolean equals(Object o)
180          {
181              return this == o;
182          }
183  
184          /**
185           * compare method. Assumes both parameters are non-null
186           * instances of Property. One property is less than another if
187           * its name is shorter than the other property's name. If the
188           * names are the same length, the property whose name comes
189           * before the other property's name, alphabetically, is less
190           * than the other property.
191           *
192           * @param o1 first object to compare, better be a Property
193           * @param o2 second object to compare, better be a Property
194           *
195           * @return negative value if o1 <  o2,
196           *         zero           if o1 == o2,
197           *         positive value if o1 >  o2.
198           */
199  
200          public int compare(Object o1, Object o2)
201          {
202              String name1  = (( Property ) o1).getName();
203              String name2  = (( Property ) o2).getName();
204              int    result = name1.length() - name2.length();
205  
206              if (result == 0)
207              {
208                  result = name1.compareTo(name2);
209              }
210              return result;
211          }
212      }   // end private class PropertyComparator
213  
214      /* ********** START extension of Property ********** */
215  
216      /**
217       * @return true if a directory type Property
218       */
219  
220      public boolean isDirectory()
221      {
222          return true;
223      }
224  
225      /**
226       * Perform whatever activities need to be performed prior to
227       * writing
228       */
229  
230      protected void preWrite()
231      {
232          if (_children.size() > 0)
233          {
234              Property[] children =
235                  ( Property [] ) _children.toArray(new Property[ 0 ]);
236  
237              Arrays.sort(children, new PropertyComparator());
238              int midpoint = children.length / 2;
239  
240              setChildProperty(children[ midpoint ].getIndex());
241              children[ 0 ].setPreviousChild(null);
242              children[ 0 ].setNextChild(null);
243              for (int j = 1; j < midpoint; j++)
244              {
245                  children[ j ].setPreviousChild(children[ j - 1 ]);
246                  children[ j ].setNextChild(null);
247              }
248              if (midpoint != 0)
249              {
250                  childrensetPreviousChild                 .setPreviousChild(children[ midpoint - 1 ]);
251              }
252              if (midpoint != (children.length - 1))
253              {
254                  children[ midpoint ].setNextChild(children[ midpoint + 1 ]);
255                  for (int j = midpoint + 1; j < children.length - 1; j++)
256                  {
257                      children[ j ].setPreviousChild(null);
258                      children[ j ].setNextChild(children[ j + 1 ]);
259                  }
260                  children[ children.length - 1 ].setPreviousChild(null);
261                  children[ children.length - 1 ].setNextChild(null);
262              }
263              else
264              {
265                  children[ midpoint ].setNextChild(null);
266              }
267          }
268      }
269  
270      /* **********  END  extension of Property ********** */
271      /* ********** START implementation of Parent ********** */
272  
273      /**
274       * Get an iterator over the children of this Parent; all elements
275       * are instances of Property.
276       *
277       * @return Iterator of children; may refer to an empty collection
278       */
279  
280      public Iterator getChildren()
281      {
282          return _children.iterator();
283      }
284  
285      /**
286       * Add a new child to the collection of children
287       *
288       * @param property the new child to be added; must not be null
289       *
290       * @exception IOException if we already have a child with the same
291       *                        name
292       */
293  
294      public void addChild(final Property property)
295          throws IOException
296      {
297          String name = property.getName();
298  
299          if (_children_names.contains(name))
300          {
301              throw new IOException("Duplicate name \"" + name + "\"");
302          }
303          _children_names.add(name);
304          _children.add(property);
305      }
306  
307      /* **********  END  implementation of Parent ********** */
308  }   // end public class DirectoryProperty
309  
310  ???????????????????????????midpoint???????????????????????????????????????children?????????????????????????????????????????????????midpoint?????????????????midpoint??????????????????????????????children?????????????????children???????????????????????????midpoint??????????????????????????????????????setNextChild???????????????????????????????????????????????????children?????????????????????????????????????????????????????????????midpoint??????????????????????????????midpoint????????????????????????????????????????????j????????????????????????????????????????????????children?????????????????????????????????????????????????????????????????????j?????????????????????children???????????????????????????????j???????????????????????????????????setPreviousChild?????????????????????children???????????????????????????????j???????????????????????????????????setNextChild????????????????????????????????????????????????children??????????????????????????????????????????????????????????j?????????????????children???????????????????????????children?????????????????????????????????????????????????setPreviousChild?????????????????children???????????????????????????children?????????????????????????????????????????????????setNextChild?????????????????children???????????????????????????midpoint??????????????????????????????????????setNextChild?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????getChildren????????????????_children?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????addChild????????????????????????????????Property???????????????????????property????????????????????????????????getName?????????????_children_names??????????????????????????????????????name?????????????????????????????????????????????????????????name?????????_children_names?????????????????????????????name?????????_children???????????????????????property?????????????????????????????????????????????????????????????????????????????????????????????????????????