PageRenderTime 77ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 0ms

/components/forks/poi/src/loci/poi/poifs/storage/BlockAllocationTableReader.java

http://github.com/openmicroscopy/bioformats
Java | 312 lines | 147 code | 36 blank | 129 comment | 18 complexity | 10699ac97a28478662823933743971be MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, Apache-2.0, BSD-2-Clause, MPL-2.0-no-copyleft-exception
  1. /*
  2. * #%L
  3. * Fork of Apache Jakarta POI.
  4. * %%
  5. * Copyright (C) 2008 - 2013 Open Microscopy Environment:
  6. * - Board of Regents of the University of Wisconsin-Madison
  7. * - Glencoe Software, Inc.
  8. * - University of Dundee
  9. * %%
  10. * Licensed under the Apache License, Version 2.0 (the "License");
  11. * you may not use this file except in compliance with the License.
  12. * You may obtain a copy of the License at
  13. *
  14. * http://www.apache.org/licenses/LICENSE-2.0
  15. *
  16. * Unless required by applicable law or agreed to in writing, software
  17. * distributed under the License is distributed on an "AS IS" BASIS,
  18. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  19. * See the License for the specific language governing permissions and
  20. * limitations under the License.
  21. * #L%
  22. */
  23. /* ====================================================================
  24. Licensed to the Apache Software Foundation (ASF) under one or more
  25. contributor license agreements. See the NOTICE file distributed with
  26. this work for additional information regarding copyright ownership.
  27. The ASF licenses this file to You under the Apache License, Version 2.0
  28. (the "License"); you may not use this file except in compliance with
  29. the License. You may obtain a copy of the License at
  30. http://www.apache.org/licenses/LICENSE-2.0
  31. Unless required by applicable law or agreed to in writing, software
  32. distributed under the License is distributed on an "AS IS" BASIS,
  33. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  34. See the License for the specific language governing permissions and
  35. limitations under the License.
  36. ==================================================================== */
  37. package loci.poi.poifs.storage;
  38. import java.io.IOException;
  39. import java.util.*;
  40. import loci.poi.poifs.common.POIFSConstants;
  41. import loci.poi.util.IntList;
  42. import loci.poi.util.LittleEndian;
  43. import loci.poi.util.LittleEndianConsts;
  44. /**
  45. * This class manages and creates the Block Allocation Table, which is
  46. * basically a set of linked lists of block indices.
  47. * <P>
  48. * Each block of the filesystem has an index. The first block, the
  49. * header, is skipped; the first block after the header is index 0,
  50. * the next is index 1, and so on.
  51. * <P>
  52. * A block's index is also its index into the Block Allocation
  53. * Table. The entry that it finds in the Block Allocation Table is the
  54. * index of the next block in the linked list of blocks making up a
  55. * file, or it is set to -2: end of list.
  56. *
  57. * @author Marc Johnson (mjohnson at apache dot org)
  58. */
  59. public class BlockAllocationTableReader
  60. {
  61. private IntList _entries;
  62. /**
  63. * create a BlockAllocationTableReader for an existing filesystem. Side
  64. * effect: when this method finishes, the BAT blocks will have
  65. * been removed from the raw block list, and any blocks labeled as
  66. * 'unused' in the block allocation table will also have been
  67. * removed from the raw block list.
  68. *
  69. * @param block_count the number of BAT blocks making up the block
  70. * allocation table
  71. * @param block_array the array of BAT block indices from the
  72. * filesystem's header
  73. * @param xbat_count the number of XBAT blocks
  74. * @param xbat_index the index of the first XBAT block
  75. * @param raw_block_list the list of RawDataBlocks
  76. *
  77. * @exception IOException if, in trying to create the table, we
  78. * encounter logic errors
  79. */
  80. public BlockAllocationTableReader(final int block_count,
  81. final int [] block_array,
  82. final int xbat_count,
  83. final int xbat_index,
  84. final BlockList raw_block_list, int size)
  85. throws IOException
  86. {
  87. this();
  88. if (block_count <= 0)
  89. {
  90. throw new IOException(
  91. "Illegal block count; minimum count is 1, got " + block_count
  92. + " instead");
  93. }
  94. // acquire raw data blocks containing the BAT block data
  95. RawDataBlock blocks[] = new RawDataBlock[ block_count ];
  96. int limit = Math.min(block_count, block_array.length);
  97. int block_index;
  98. for (block_index = 0; block_index < limit; block_index++)
  99. {
  100. try {
  101. blocks[ block_index ] =
  102. ( RawDataBlock ) raw_block_list
  103. .remove(block_array[ block_index ]);
  104. }
  105. catch (IOException e) {
  106. break;
  107. }
  108. }
  109. if (block_index < block_count)
  110. {
  111. // must have extended blocks
  112. if (xbat_index < 0)
  113. {
  114. throw new IOException(
  115. "BAT count exceeds limit, yet XBAT index indicates no valid entries");
  116. }
  117. int chain_index = xbat_index;
  118. int max_entries_per_block = BATBlock.entriesPerXBATBlock(size);
  119. int chain_index_offset = BATBlock.getXBATChainOffset(size);
  120. for (int j = 0; j < xbat_count; j++)
  121. {
  122. limit = Math.min(block_count - block_index,
  123. max_entries_per_block);
  124. byte[] data = raw_block_list.remove(chain_index).getData();
  125. int offset = 0;
  126. for (int k = 0; k < limit; k++)
  127. {
  128. blocks[ block_index++ ] =
  129. ( RawDataBlock ) raw_block_list
  130. .remove(LittleEndian.getInt(data, offset));
  131. offset += LittleEndianConsts.INT_SIZE;
  132. }
  133. chain_index = LittleEndian.getInt(data, chain_index_offset);
  134. if (chain_index == POIFSConstants.END_OF_CHAIN)
  135. {
  136. break;
  137. }
  138. }
  139. }
  140. if (block_index != block_count)
  141. {
  142. throw new IOException("Could not find all blocks");
  143. }
  144. // now that we have all of the raw data blocks, go through and
  145. // create the indices
  146. setEntries(blocks, raw_block_list, size);
  147. }
  148. /**
  149. * create a BlockAllocationTableReader from an array of raw data blocks
  150. *
  151. * @param blocks the raw data
  152. * @param raw_block_list the list holding the managed blocks
  153. *
  154. * @exception IOException
  155. */
  156. BlockAllocationTableReader(final ListManagedBlock [] blocks,
  157. final BlockList raw_block_list, int size)
  158. throws IOException
  159. {
  160. this();
  161. setEntries(blocks, raw_block_list, size);
  162. }
  163. /**
  164. * Constructor BlockAllocationTableReader
  165. *
  166. *
  167. */
  168. BlockAllocationTableReader()
  169. {
  170. _entries = new IntList();
  171. }
  172. /**
  173. * walk the entries from a specified point and return the
  174. * associated blocks. The associated blocks are removed from the
  175. * block list
  176. *
  177. * @param startBlock the first block in the chain
  178. * @param blockList the raw data block list
  179. *
  180. * @return array of ListManagedBlocks, in their correct order
  181. *
  182. * @exception IOException if there is a problem acquiring the blocks
  183. */
  184. ListManagedBlock [] fetchBlocks(final int startBlock,
  185. final BlockList blockList)
  186. throws IOException
  187. {
  188. List blocks = new ArrayList();
  189. int currentBlock = startBlock;
  190. while (currentBlock != POIFSConstants.END_OF_CHAIN)
  191. {
  192. blocks.add(blockList.remove(currentBlock));
  193. currentBlock = _entries.get(currentBlock);
  194. }
  195. return ( ListManagedBlock [] ) blocks
  196. .toArray(new ListManagedBlock[ 0 ]);
  197. }
  198. // methods for debugging reader
  199. /**
  200. * determine whether the block specified by index is used or not
  201. *
  202. * @param index index of block in question
  203. *
  204. * @return true if the specific block is used, else false
  205. */
  206. boolean isUsed(final int index)
  207. {
  208. boolean rval = false;
  209. try
  210. {
  211. rval = _entries.get(index) != -1;
  212. }
  213. catch (IndexOutOfBoundsException ignored)
  214. {
  215. }
  216. return rval;
  217. }
  218. /**
  219. * return the next block index
  220. *
  221. * @param index of the current block
  222. *
  223. * @return index of the next block (may be
  224. * POIFSConstants.END_OF_CHAIN, indicating end of chain
  225. * (duh))
  226. *
  227. * @exception IOException if the current block is unused
  228. */
  229. int getNextBlockIndex(final int index)
  230. throws IOException
  231. {
  232. if (isUsed(index))
  233. {
  234. return _entries.get(index);
  235. }
  236. else
  237. {
  238. throw new IOException("index " + index + " is unused");
  239. }
  240. }
  241. /**
  242. * Convert an array of blocks into a set of integer indices
  243. *
  244. * @param blocks the array of blocks containing the indices
  245. * @param raw_blocks the list of blocks being managed. Unused
  246. * blocks will be eliminated from the list
  247. *
  248. * @exception IOException
  249. */
  250. private void setEntries(final ListManagedBlock [] blocks,
  251. final BlockList raw_blocks, int size)
  252. throws IOException
  253. {
  254. int limit = BATBlock.entriesPerBlock(size);
  255. for (int block_index = 0; block_index < blocks.length; block_index++)
  256. {
  257. byte[] data = blocks[ block_index ].getData();
  258. int offset = 0;
  259. for (int k = 0; k < limit; k++)
  260. {
  261. int entry = LittleEndian.getInt(data, offset);
  262. if (entry == POIFSConstants.UNUSED_BLOCK)
  263. {
  264. raw_blocks.zap(_entries.size());
  265. }
  266. _entries.add(entry);
  267. offset += LittleEndianConsts.INT_SIZE;
  268. }
  269. // discard block
  270. blocks[ block_index ] = null;
  271. }
  272. raw_blocks.setBAT(this);
  273. }
  274. } // end class BlockAllocationTableReader