PageRenderTime 42ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/ppt/scratchpad/src/org/apache/poi/hsmf/parsers/POIFSChunkParser.java

https://github.com/isdom/POI-Android
Java | 189 lines | 121 code | 19 blank | 49 comment | 28 complexity | 9c88a7698cc287ccc385a9389ab3678d MD5 | raw file
  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.hsmf.parsers;
  16. import java.io.IOException;
  17. import java.util.ArrayList;
  18. import org.apache.poi.hsmf.datatypes.AttachmentChunks;
  19. import org.apache.poi.hsmf.datatypes.ByteChunk;
  20. import org.apache.poi.hsmf.datatypes.Chunk;
  21. import org.apache.poi.hsmf.datatypes.ChunkGroup;
  22. import org.apache.poi.hsmf.datatypes.Chunks;
  23. import org.apache.poi.hsmf.datatypes.DirectoryChunk;
  24. import org.apache.poi.hsmf.datatypes.MAPIProperty;
  25. import org.apache.poi.hsmf.datatypes.MessageSubmissionChunk;
  26. import org.apache.poi.hsmf.datatypes.NameIdChunks;
  27. import org.apache.poi.hsmf.datatypes.RecipientChunks;
  28. import org.apache.poi.hsmf.datatypes.StringChunk;
  29. import org.apache.poi.hsmf.datatypes.Types;
  30. import org.apache.poi.poifs.filesystem.DirectoryNode;
  31. import org.apache.poi.poifs.filesystem.DocumentInputStream;
  32. import org.apache.poi.poifs.filesystem.DocumentNode;
  33. import org.apache.poi.poifs.filesystem.Entry;
  34. import org.apache.poi.poifs.filesystem.POIFSFileSystem;
  35. /**
  36. * Processes a POIFS of a .msg file into groups of Chunks, such as
  37. * core data, attachment #1 data, attachment #2 data, recipient
  38. * data and so on.
  39. */
  40. public final class POIFSChunkParser {
  41. public static ChunkGroup[] parse(POIFSFileSystem fs) throws IOException {
  42. return parse(fs.getRoot());
  43. }
  44. public static ChunkGroup[] parse(DirectoryNode node) throws IOException {
  45. Chunks mainChunks = new Chunks();
  46. ArrayList<ChunkGroup> groups = new ArrayList<ChunkGroup>();
  47. groups.add(mainChunks);
  48. // Find our top level children
  49. // Note - we don't handle children of children yet, as
  50. // there doesn't seem to be any use of that in Outlook
  51. for(Entry entry : node) {
  52. if(entry instanceof DirectoryNode) {
  53. DirectoryNode dir = (DirectoryNode)entry;
  54. ChunkGroup group = null;
  55. // Do we know what to do with it?
  56. if(dir.getName().startsWith(AttachmentChunks.PREFIX)) {
  57. group = new AttachmentChunks(dir.getName());
  58. }
  59. if(dir.getName().startsWith(NameIdChunks.PREFIX)) {
  60. group = new NameIdChunks();
  61. }
  62. if(dir.getName().startsWith(RecipientChunks.PREFIX)) {
  63. group = new RecipientChunks(dir.getName());
  64. }
  65. if(group != null) {
  66. processChunks(dir, group);
  67. groups.add(group);
  68. } else {
  69. // Unknown directory, skip silently
  70. }
  71. }
  72. }
  73. // Now do the top level chunks
  74. processChunks(node, mainChunks);
  75. // Finish
  76. return groups.toArray(new ChunkGroup[groups.size()]);
  77. }
  78. /**
  79. * Creates all the chunks for a given Directory, but
  80. * doesn't recurse or descend
  81. */
  82. protected static void processChunks(DirectoryNode node, ChunkGroup grouping) {
  83. for(Entry entry : node) {
  84. if(entry instanceof DocumentNode) {
  85. process(entry, grouping);
  86. } else if(entry instanceof DirectoryNode) {
  87. if(entry.getName().endsWith(Types.asFileEnding(Types.DIRECTORY))) {
  88. process(entry, grouping);
  89. }
  90. }
  91. }
  92. }
  93. /**
  94. * Creates a chunk, and gives it to its parent group
  95. */
  96. protected static void process(Entry entry, ChunkGroup grouping) {
  97. String entryName = entry.getName();
  98. if(entryName.length() < 9) {
  99. // Name in the wrong format
  100. return;
  101. }
  102. if(entryName.indexOf('_') == -1) {
  103. // Name in the wrong format
  104. return;
  105. }
  106. // Split it into its parts
  107. int splitAt = entryName.lastIndexOf('_');
  108. String namePrefix = entryName.substring(0, splitAt+1);
  109. String ids = entryName.substring(splitAt+1);
  110. // Make sure we got what we expected, should be of
  111. // the form __<name>_<id><type>
  112. if(namePrefix.equals("Olk10SideProps") ||
  113. namePrefix.equals("Olk10SideProps_")) {
  114. // This is some odd Outlook 2002 thing, skip
  115. return;
  116. } else if(splitAt <= entryName.length()-8) {
  117. // In the right form for a normal chunk
  118. // We'll process this further in a little bit
  119. } else {
  120. // Underscores not the right place, something's wrong
  121. throw new IllegalArgumentException("Invalid chunk name " + entryName);
  122. }
  123. // Now try to turn it into id + type
  124. try {
  125. int chunkId = Integer.parseInt(ids.substring(0, 4), 16);
  126. int type = Integer.parseInt(ids.substring(4, 8), 16);
  127. Chunk chunk = null;
  128. // Special cases based on the ID
  129. if(chunkId == MAPIProperty.MESSAGE_SUBMISSION_ID.id) {
  130. chunk = new MessageSubmissionChunk(namePrefix, chunkId, type);
  131. }
  132. else {
  133. // Nothing special about this ID
  134. // So, do the usual thing which is by type
  135. switch(type) {
  136. case Types.BINARY:
  137. chunk = new ByteChunk(namePrefix, chunkId, type);
  138. break;
  139. case Types.DIRECTORY:
  140. if(entry instanceof DirectoryNode) {
  141. chunk = new DirectoryChunk((DirectoryNode)entry, namePrefix, chunkId, type);
  142. }
  143. break;
  144. case Types.ASCII_STRING:
  145. case Types.UNICODE_STRING:
  146. chunk = new StringChunk(namePrefix, chunkId, type);
  147. break;
  148. }
  149. }
  150. if(chunk != null) {
  151. if(entry instanceof DocumentNode) {
  152. try {
  153. DocumentInputStream inp = new DocumentInputStream((DocumentNode)entry);
  154. chunk.readValue(inp);
  155. grouping.record(chunk);
  156. } catch(IOException e) {
  157. System.err.println("Error reading from part " + entry.getName() + " - " + e.toString());
  158. }
  159. } else {
  160. grouping.record(chunk);
  161. }
  162. }
  163. } catch(NumberFormatException e) {
  164. // Name in the wrong format
  165. return;
  166. }
  167. }
  168. }