Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

HeaderBlockReader.java 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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.storage;
  16. import static org.apache.poi.poifs.storage.HeaderBlockConstants._bat_array_offset;
  17. import static org.apache.poi.poifs.storage.HeaderBlockConstants._bat_count_offset;
  18. import static org.apache.poi.poifs.storage.HeaderBlockConstants._max_bats_in_header;
  19. import static org.apache.poi.poifs.storage.HeaderBlockConstants._property_start_offset;
  20. import static org.apache.poi.poifs.storage.HeaderBlockConstants._sbat_start_offset;
  21. import static org.apache.poi.poifs.storage.HeaderBlockConstants._sbat_block_count_offset;
  22. import static org.apache.poi.poifs.storage.HeaderBlockConstants._signature;
  23. import static org.apache.poi.poifs.storage.HeaderBlockConstants._signature_offset;
  24. import static org.apache.poi.poifs.storage.HeaderBlockConstants._xbat_count_offset;
  25. import static org.apache.poi.poifs.storage.HeaderBlockConstants._xbat_start_offset;
  26. import java.io.IOException;
  27. import java.io.InputStream;
  28. import org.apache.poi.poifs.common.POIFSConstants;
  29. import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
  30. import org.apache.poi.util.HexDump;
  31. import org.apache.poi.util.IOUtils;
  32. import org.apache.poi.util.LittleEndian;
  33. import org.apache.poi.util.LittleEndianConsts;
  34. /**
  35. * The block containing the archive header
  36. *
  37. * @author Marc Johnson (mjohnson at apache dot org)
  38. */
  39. public final class HeaderBlockReader {
  40. /**
  41. * What big block size the file uses. Most files
  42. * use 512 bytes, but a few use 4096
  43. */
  44. private final int bigBlockSize;
  45. /**
  46. * number of big block allocation table blocks (int).
  47. * (Number of FAT Sectors in Microsoft parlance)
  48. */
  49. private final int _bat_count;
  50. /**
  51. * Start of the property set block (int index of the property set
  52. * chain's first big block).
  53. */
  54. private final int _property_start;
  55. /**
  56. * start of the small block allocation table (int index of small
  57. * block allocation table's first big block)
  58. */
  59. private final int _sbat_start;
  60. /**
  61. * Number of small block allocation table blocks (int)
  62. * (Number of MiniFAT Sectors in Microsoft parlance)
  63. */
  64. private final int _sbat_count;
  65. /**
  66. * Big block index for extension to the big block allocation table
  67. */
  68. private final int _xbat_start;
  69. /**
  70. * Number of big block allocation table blocks (int)
  71. * (Number of DIFAT Sectors in Microsoft parlance)
  72. */
  73. private final int _xbat_count;
  74. private final byte[] _data;
  75. /**
  76. * create a new HeaderBlockReader from an InputStream
  77. *
  78. * @param stream the source InputStream
  79. *
  80. * @exception IOException on errors or bad data
  81. */
  82. public HeaderBlockReader(InputStream stream) throws IOException {
  83. // At this point, we don't know how big our
  84. // block sizes are
  85. // So, read the first 32 bytes to check, then
  86. // read the rest of the block
  87. byte[] blockStart = new byte[32];
  88. int bsCount = IOUtils.readFully(stream, blockStart);
  89. if(bsCount != 32) {
  90. throw alertShortRead(bsCount, 32);
  91. }
  92. // verify signature
  93. long signature = LittleEndian.getLong(blockStart, _signature_offset);
  94. if (signature != _signature) {
  95. // Is it one of the usual suspects?
  96. byte[] OOXML_FILE_HEADER = POIFSConstants.OOXML_FILE_HEADER;
  97. if(blockStart[0] == OOXML_FILE_HEADER[0] &&
  98. blockStart[1] == OOXML_FILE_HEADER[1] &&
  99. blockStart[2] == OOXML_FILE_HEADER[2] &&
  100. blockStart[3] == OOXML_FILE_HEADER[3]) {
  101. throw new OfficeXmlFileException("The supplied data appears to be in the Office 2007+ XML. You are calling the part of POI that deals with OLE2 Office Documents. You need to call a different part of POI to process this data (eg XSSF instead of HSSF)");
  102. }
  103. if ((signature & 0xFF8FFFFFFFFFFFFFL) == 0x0010000200040009L) {
  104. // BIFF2 raw stream starts with BOF (sid=0x0009, size=0x0004, data=0x00t0)
  105. throw new IllegalArgumentException("The supplied data appears to be in BIFF2 format. "
  106. + "POI only supports BIFF8 format");
  107. }
  108. // Give a generic error
  109. throw new IOException("Invalid header signature; read "
  110. + longToHex(signature) + ", expected "
  111. + longToHex(_signature));
  112. }
  113. // Figure out our block size
  114. switch (blockStart[30]) {
  115. case 12:
  116. bigBlockSize = POIFSConstants.LARGER_BIG_BLOCK_SIZE; break;
  117. case 9:
  118. bigBlockSize = POIFSConstants.BIG_BLOCK_SIZE; break;
  119. default:
  120. throw new IOException("Unsupported blocksize (2^"
  121. + blockStart[30] + "). Expected 2^9 or 2^12.");
  122. }
  123. _data = new byte[ bigBlockSize ];
  124. System.arraycopy(blockStart, 0, _data, 0, blockStart.length);
  125. // Now we can read the rest of our header
  126. int byte_count = IOUtils.readFully(stream, _data, blockStart.length, _data.length - blockStart.length);
  127. if (byte_count+bsCount != bigBlockSize) {
  128. throw alertShortRead(byte_count, bigBlockSize);
  129. }
  130. _bat_count = getInt(_bat_count_offset, _data);
  131. _property_start = getInt(_property_start_offset, _data);
  132. _sbat_start = getInt(_sbat_start_offset, _data);
  133. _sbat_count = getInt(_sbat_block_count_offset, _data);
  134. _xbat_start = getInt(_xbat_start_offset, _data);
  135. _xbat_count = getInt(_xbat_count_offset, _data);
  136. }
  137. private static int getInt(int offset, byte[] data) {
  138. return LittleEndian.getInt(data, offset);
  139. }
  140. private static String longToHex(long value) {
  141. return new String(HexDump.longToHex(value));
  142. }
  143. private static IOException alertShortRead(int pRead, int expectedReadSize) {
  144. int read;
  145. if (pRead < 0) {
  146. //Can't have -1 bytes read in the error message!
  147. read = 0;
  148. } else {
  149. read = pRead;
  150. }
  151. String type = " byte" + (read == 1 ? (""): ("s"));
  152. return new IOException("Unable to read entire header; "
  153. + read + type + " read; expected "
  154. + expectedReadSize + " bytes");
  155. }
  156. /**
  157. * get start of Property Table
  158. *
  159. * @return the index of the first block of the Property Table
  160. */
  161. public int getPropertyStart() {
  162. return _property_start;
  163. }
  164. /**
  165. * @return start of small block (MiniFAT) allocation table
  166. */
  167. public int getSBATStart() {
  168. return _sbat_start;
  169. }
  170. public int getSBATCount() {
  171. return _sbat_count;
  172. }
  173. /**
  174. * @return number of BAT blocks
  175. */
  176. public int getBATCount() {
  177. return _bat_count;
  178. }
  179. /**
  180. * Returns the offsets to the first (up to) 109
  181. * BAT sectors.
  182. * Any additional BAT sectors
  183. * @return BAT offset array
  184. */
  185. public int[] getBATArray() {
  186. int[] result = new int[ _max_bats_in_header ];
  187. int offset = _bat_array_offset;
  188. for (int j = 0; j < _max_bats_in_header; j++) {
  189. result[ j ] = LittleEndian.getInt(_data, offset);
  190. offset += LittleEndianConsts.INT_SIZE;
  191. }
  192. return result;
  193. }
  194. /**
  195. * @return XBAT (DIFAT) count
  196. */
  197. public int getXBATCount() {
  198. return _xbat_count;
  199. }
  200. /**
  201. * @return XBAT (DIFAT) index
  202. */
  203. public int getXBATIndex() {
  204. return _xbat_start;
  205. }
  206. /**
  207. * @return The Big Block size, normally 512 bytes, sometimes 4096 bytes
  208. */
  209. public int getBigBlockSize() {
  210. return bigBlockSize;
  211. }
  212. }