PageRenderTime 58ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/src/org/apache/poi/poifs/filesystem/EntryUtils.java

https://github.com/minstrelsy/SimpleAndroidDocView
Java | 269 lines | 156 code | 21 blank | 92 comment | 34 complexity | 3e82db13f1b60dbf552f1788134392b0 MD5 | raw file
Possible License(s): Apache-2.0
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.poifs.filesystem;
  16. import java.io.FileNotFoundException;
  17. import java.io.IOException;
  18. import java.util.HashMap;
  19. import java.util.Iterator;
  20. import java.util.List;
  21. import java.util.Map;
  22. import org.apache.poi.util.Internal;
  23. @Internal
  24. public class EntryUtils
  25. {
  26. /**
  27. * Copies an Entry into a target POIFS directory, recursively
  28. */
  29. @Internal
  30. public static void copyNodeRecursively( Entry entry, DirectoryEntry target )
  31. throws IOException
  32. {
  33. // logger.log( POILogger.ERROR, "copyNodeRecursively called with "+entry.getName()+
  34. // ","+target.getName());
  35. DirectoryEntry newTarget = null;
  36. if ( entry.isDirectoryEntry() )
  37. {
  38. newTarget = target.createDirectory( entry.getName() );
  39. Iterator<Entry> entries = ( (DirectoryEntry) entry ).getEntries();
  40. while ( entries.hasNext() )
  41. {
  42. copyNodeRecursively( entries.next(), newTarget );
  43. }
  44. }
  45. else
  46. {
  47. DocumentEntry dentry = (DocumentEntry) entry;
  48. DocumentInputStream dstream = new DocumentInputStream( dentry );
  49. target.createDocument( dentry.getName(), dstream );
  50. dstream.close();
  51. }
  52. }
  53. /**
  54. * Copies all the nodes from one POIFS Directory to another
  55. *
  56. * @param sourceRoot
  57. * is the source Directory to copy from
  58. * @param targetRoot
  59. * is the target Directory to copy to
  60. */
  61. public static void copyNodes(DirectoryEntry sourceRoot,
  62. DirectoryEntry targetRoot) throws IOException
  63. {
  64. for (Entry entry : sourceRoot) {
  65. copyNodeRecursively( entry, targetRoot );
  66. }
  67. }
  68. /**
  69. * Copies nodes from one Directory to the other minus the excepts
  70. *
  71. * @param filteredSource The filtering source Directory to copy from
  72. * @param filteredTarget The filtering target Directory to copy to
  73. */
  74. public static void copyNodes( FilteringDirectoryNode filteredSource,
  75. FilteringDirectoryNode filteredTarget ) throws IOException
  76. {
  77. // Nothing special here, just overloaded types to make the
  78. // recommended new way to handle this clearer
  79. copyNodes( (DirectoryEntry)filteredSource, (DirectoryEntry)filteredTarget );
  80. }
  81. /**
  82. * Copies nodes from one Directory to the other minus the excepts
  83. *
  84. * @param sourceRoot
  85. * is the source Directory to copy from
  86. * @param targetRoot
  87. * is the target Directory to copy to
  88. * @param excepts
  89. * is a list of Strings specifying what nodes NOT to copy
  90. * @deprecated use {@link FilteringDirectoryNode} instead
  91. */
  92. public static void copyNodes( DirectoryEntry sourceRoot,
  93. DirectoryEntry targetRoot, List<String> excepts )
  94. throws IOException
  95. {
  96. Iterator<Entry> entries = sourceRoot.getEntries();
  97. while ( entries.hasNext() )
  98. {
  99. Entry entry = entries.next();
  100. if ( !excepts.contains( entry.getName() ) )
  101. {
  102. copyNodeRecursively( entry, targetRoot );
  103. }
  104. }
  105. }
  106. /**
  107. * Copies all nodes from one POIFS to the other
  108. *
  109. * @param source
  110. * is the source POIFS to copy from
  111. * @param target
  112. * is the target POIFS to copy to
  113. */
  114. public static void copyNodes( POIFSFileSystem source,
  115. POIFSFileSystem target ) throws IOException
  116. {
  117. copyNodes( source.getRoot(), target.getRoot() );
  118. }
  119. /**
  120. * Copies nodes from one POIFS to the other, minus the excepts.
  121. * This delegates the filtering work to {@link FilteringDirectoryNode},
  122. * so excepts can be of the form "NodeToExclude" or
  123. * "FilteringDirectory/ExcludedChildNode"
  124. *
  125. * @param source is the source POIFS to copy from
  126. * @param target is the target POIFS to copy to
  127. * @param excepts is a list of Entry Names to be excluded from the copy
  128. */
  129. public static void copyNodes( POIFSFileSystem source,
  130. POIFSFileSystem target, List<String> excepts ) throws IOException
  131. {
  132. copyNodes(
  133. new FilteringDirectoryNode(source.getRoot(), excepts),
  134. new FilteringDirectoryNode(target.getRoot(), excepts)
  135. );
  136. }
  137. /**
  138. * Checks to see if the two Directories hold the same contents.
  139. * For this to be true, they must have entries with the same names,
  140. * no entries in one but not the other, and the size+contents
  141. * of each entry must match, and they must share names.
  142. * To exclude certain parts of the Directory from being checked,
  143. * use a {@link FilteringDirectoryNode}
  144. */
  145. public static boolean areDirectoriesIdentical(DirectoryEntry dirA, DirectoryEntry dirB) {
  146. // First, check names
  147. if (! dirA.getName().equals(dirB.getName())) {
  148. return false;
  149. }
  150. // Next up, check they have the same number of children
  151. if (dirA.getEntryCount() != dirB.getEntryCount()) {
  152. return false;
  153. }
  154. // Next, check entries and their types/sizes
  155. Map<String,Integer> aSizes = new HashMap<String, Integer>();
  156. final int isDirectory = -12345;
  157. for (Entry a : dirA) {
  158. String aName = a.getName();
  159. if (a.isDirectoryEntry()) {
  160. aSizes.put(aName, isDirectory);
  161. } else {
  162. aSizes.put(aName, ((DocumentNode)a).getSize());
  163. }
  164. }
  165. for (Entry b : dirB) {
  166. String bName = b.getName();
  167. if (! aSizes.containsKey(bName)) {
  168. // In B but not A
  169. return false;
  170. }
  171. int size;
  172. if (b.isDirectoryEntry()) {
  173. size = isDirectory;
  174. } else {
  175. size = ((DocumentNode)b).getSize();
  176. }
  177. if (size != aSizes.get(bName)) {
  178. // Either the wrong type, or they're different sizes
  179. return false;
  180. }
  181. // Track it as checked
  182. aSizes.remove(bName);
  183. }
  184. if (!aSizes.isEmpty()) {
  185. // Nodes were in A but not B
  186. return false;
  187. }
  188. // If that passed, check entry contents
  189. for (Entry a : dirA) {
  190. try {
  191. Entry b = dirB.getEntry(a.getName());
  192. boolean match;
  193. if (a.isDirectoryEntry()) {
  194. match = areDirectoriesIdentical(
  195. (DirectoryEntry)a, (DirectoryEntry)b);
  196. } else {
  197. match = areDocumentsIdentical(
  198. (DocumentEntry)a, (DocumentEntry)b);
  199. }
  200. if (!match) return false;
  201. } catch(FileNotFoundException e) {
  202. // Shouldn't really happen...
  203. return false;
  204. } catch(IOException e) {
  205. // Something's messed up with one document, not a match
  206. return false;
  207. }
  208. }
  209. // If we get here, they match!
  210. return true;
  211. }
  212. /**
  213. * Checks to see if two Documents have the same name
  214. * and the same contents. (Their parent directories are
  215. * not checked)
  216. */
  217. public static boolean areDocumentsIdentical(DocumentEntry docA, DocumentEntry docB) throws IOException {
  218. if (! docA.getName().equals(docB.getName())) {
  219. // Names don't match, not the same
  220. return false;
  221. }
  222. if (docA.getSize() != docB.getSize()) {
  223. // Wrong sizes, can't have the same contents
  224. return false;
  225. }
  226. boolean matches = true;
  227. DocumentInputStream inpA = null, inpB = null;
  228. try {
  229. inpA = new DocumentInputStream(docA);
  230. inpB = new DocumentInputStream(docB);
  231. int readA, readB;
  232. do {
  233. readA = inpA.read();
  234. readB = inpB.read();
  235. if (readA != readB) {
  236. matches = false;
  237. break;
  238. }
  239. } while(readA != -1 && readB != -1);
  240. } finally {
  241. if (inpA != null) inpA.close();
  242. if (inpB != null) inpB.close();
  243. }
  244. return matches;
  245. }
  246. }