PageRenderTime 54ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/components/forks/poi/src/loci/poi/poifs/property/Property.java

http://github.com/openmicroscopy/bioformats
Java | 595 lines | 284 code | 84 blank | 227 comment | 10 complexity | 939a613f5cf5cec32bc2e605d05fed10 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.property;
  38. import java.io.*;
  39. import java.util.*;
  40. import loci.poi.hpsf.ClassID;
  41. import loci.poi.poifs.common.POIFSConstants;
  42. import loci.poi.poifs.dev.POIFSViewable;
  43. import loci.poi.util.ByteField;
  44. import loci.poi.util.IntegerField;
  45. import loci.poi.util.LittleEndianConsts;
  46. import loci.poi.util.ShortField;
  47. /**
  48. * This abstract base class is the ancestor of all classes
  49. * implementing POIFS Property behavior.
  50. *
  51. * @author Marc Johnson (mjohnson at apache dot org)
  52. */
  53. public abstract class Property
  54. implements Child, POIFSViewable
  55. {
  56. static final private byte _default_fill = ( byte ) 0x00;
  57. static final private int _name_size_offset = 0x40;
  58. static final private int _max_name_length =
  59. (_name_size_offset / LittleEndianConsts.SHORT_SIZE) - 1;
  60. static final protected int _NO_INDEX = -1;
  61. // useful offsets
  62. static final private int _node_color_offset = 0x43;
  63. static final private int _previous_property_offset = 0x44;
  64. static final private int _next_property_offset = 0x48;
  65. static final private int _child_property_offset = 0x4C;
  66. static final private int _storage_clsid_offset = 0x50;
  67. static final private int _user_flags_offset = 0x60;
  68. static final private int _seconds_1_offset = 0x64;
  69. static final private int _days_1_offset = 0x68;
  70. static final private int _seconds_2_offset = 0x6C;
  71. static final private int _days_2_offset = 0x70;
  72. static final private int _start_block_offset = 0x74;
  73. static final private int _size_offset = 0x78;
  74. // node colors
  75. static final protected byte _NODE_BLACK = 1;
  76. static final protected byte _NODE_RED = 0;
  77. // documents must be at least this size to be stored in big blocks
  78. static final private int _big_block_minimum_bytes = 4096;
  79. private String _name;
  80. private ShortField _name_size;
  81. private ByteField _property_type;
  82. private ByteField _node_color;
  83. private IntegerField _previous_property;
  84. private IntegerField _next_property;
  85. private IntegerField _child_property;
  86. private ClassID _storage_clsid;
  87. private IntegerField _user_flags;
  88. private IntegerField _seconds_1;
  89. private IntegerField _days_1;
  90. private IntegerField _seconds_2;
  91. private IntegerField _days_2;
  92. private IntegerField _start_block;
  93. private IntegerField _size;
  94. private byte[] _raw_data;
  95. private int _index;
  96. private Child _next_child;
  97. private Child _previous_child;
  98. /**
  99. * Default constructor
  100. */
  101. protected Property()
  102. {
  103. _raw_data = new byte[ POIFSConstants.PROPERTY_SIZE ];
  104. Arrays.fill(_raw_data, _default_fill);
  105. _name_size = new ShortField(_name_size_offset);
  106. _property_type =
  107. new ByteField(PropertyConstants.PROPERTY_TYPE_OFFSET);
  108. _node_color = new ByteField(_node_color_offset);
  109. _previous_property = new IntegerField(_previous_property_offset,
  110. _NO_INDEX, _raw_data);
  111. _next_property = new IntegerField(_next_property_offset,
  112. _NO_INDEX, _raw_data);
  113. _child_property = new IntegerField(_child_property_offset,
  114. _NO_INDEX, _raw_data);
  115. _storage_clsid = new ClassID(_raw_data,_storage_clsid_offset);
  116. _user_flags = new IntegerField(_user_flags_offset, 0, _raw_data);
  117. _seconds_1 = new IntegerField(_seconds_1_offset, 0,
  118. _raw_data);
  119. _days_1 = new IntegerField(_days_1_offset, 0, _raw_data);
  120. _seconds_2 = new IntegerField(_seconds_2_offset, 0,
  121. _raw_data);
  122. _days_2 = new IntegerField(_days_2_offset, 0, _raw_data);
  123. _start_block = new IntegerField(_start_block_offset);
  124. _size = new IntegerField(_size_offset, 0, _raw_data);
  125. _index = _NO_INDEX;
  126. setName("");
  127. setNextChild(null);
  128. setPreviousChild(null);
  129. }
  130. /**
  131. * Constructor from byte data
  132. *
  133. * @param index index number
  134. * @param array byte data
  135. * @param offset offset into byte data
  136. */
  137. protected Property(final int index, final byte [] array, final int offset)
  138. {
  139. _raw_data = new byte[ POIFSConstants.PROPERTY_SIZE ];
  140. System.arraycopy(array, offset, _raw_data, 0,
  141. POIFSConstants.PROPERTY_SIZE);
  142. _name_size = new ShortField(_name_size_offset, _raw_data);
  143. _property_type =
  144. new ByteField(PropertyConstants.PROPERTY_TYPE_OFFSET, _raw_data);
  145. _node_color = new ByteField(_node_color_offset, _raw_data);
  146. _previous_property = new IntegerField(_previous_property_offset,
  147. _raw_data);
  148. _next_property = new IntegerField(_next_property_offset,
  149. _raw_data);
  150. _child_property = new IntegerField(_child_property_offset,
  151. _raw_data);
  152. _storage_clsid = new ClassID(_raw_data,_storage_clsid_offset);
  153. _user_flags = new IntegerField(_user_flags_offset, 0, _raw_data);
  154. _seconds_1 = new IntegerField(_seconds_1_offset, _raw_data);
  155. _days_1 = new IntegerField(_days_1_offset, _raw_data);
  156. _seconds_2 = new IntegerField(_seconds_2_offset, _raw_data);
  157. _days_2 = new IntegerField(_days_2_offset, _raw_data);
  158. _start_block = new IntegerField(_start_block_offset, _raw_data);
  159. _size = new IntegerField(_size_offset, _raw_data);
  160. _index = index;
  161. int name_length = (_name_size.get() / LittleEndianConsts.SHORT_SIZE)
  162. - 1;
  163. if (name_length < 1)
  164. {
  165. _name = "";
  166. }
  167. else
  168. {
  169. char[] char_array = new char[ name_length ];
  170. int name_offset = 0;
  171. for (int j = 0; j < name_length; j++)
  172. {
  173. char_array[ j ] = ( char ) new ShortField(name_offset,
  174. _raw_data).get();
  175. name_offset += LittleEndianConsts.SHORT_SIZE;
  176. }
  177. _name = new String(char_array, 0, name_length);
  178. }
  179. _next_child = null;
  180. _previous_child = null;
  181. }
  182. /**
  183. * Write the raw data to an OutputStream.
  184. *
  185. * @param stream the OutputStream to which the data should be
  186. * written.
  187. *
  188. * @exception IOException on problems writing to the specified
  189. * stream.
  190. */
  191. public void writeData(final OutputStream stream)
  192. throws IOException
  193. {
  194. stream.write(_raw_data);
  195. }
  196. /**
  197. * Set the start block for the document referred to by this
  198. * Property.
  199. *
  200. * @param startBlock the start block index
  201. */
  202. public void setStartBlock(final int startBlock)
  203. {
  204. _start_block.set(startBlock, _raw_data);
  205. }
  206. /**
  207. * @return the start block
  208. */
  209. public int getStartBlock()
  210. {
  211. return _start_block.get();
  212. }
  213. /**
  214. * find out the document size
  215. *
  216. * @return size in bytes
  217. */
  218. public int getSize()
  219. {
  220. return _size.get();
  221. }
  222. /**
  223. * Based on the currently defined size, should this property use
  224. * small blocks?
  225. *
  226. * @return true if the size is less than _big_block_minimum_bytes
  227. */
  228. public boolean shouldUseSmallBlocks()
  229. {
  230. return Property.isSmall(_size.get());
  231. }
  232. /**
  233. * does the length indicate a small document?
  234. *
  235. * @param length length in bytes
  236. *
  237. * @return true if the length is less than
  238. * _big_block_minimum_bytes
  239. */
  240. public static boolean isSmall(final int length)
  241. {
  242. return length < _big_block_minimum_bytes;
  243. }
  244. /**
  245. * Get the name of this property
  246. *
  247. * @return property name as String
  248. */
  249. public String getName()
  250. {
  251. return _name;
  252. }
  253. /**
  254. * @return true if a directory type Property
  255. */
  256. abstract public boolean isDirectory();
  257. /**
  258. * Sets the storage clsid, which is the Class ID of a COM object which
  259. * reads and writes this stream
  260. * @return storage Class ID for this property stream
  261. */
  262. public ClassID getStorageClsid()
  263. {
  264. return _storage_clsid;
  265. }
  266. /**
  267. * Set the name; silently truncates the name if it's too long.
  268. *
  269. * @param name the new name
  270. */
  271. protected final void setName(final String name)
  272. {
  273. char[] char_array = name.toCharArray();
  274. int limit = Math.min(char_array.length, _max_name_length);
  275. _name = new String(char_array, 0, limit);
  276. short offset = 0;
  277. int j = 0;
  278. for (; j < limit; j++)
  279. {
  280. new ShortField(offset, ( short ) char_array[ j ], _raw_data);
  281. offset += LittleEndianConsts.SHORT_SIZE;
  282. }
  283. for (; j < _max_name_length + 1; j++)
  284. {
  285. new ShortField(offset, ( short ) 0, _raw_data);
  286. offset += LittleEndianConsts.SHORT_SIZE;
  287. }
  288. // double the count, and include the null at the end
  289. _name_size
  290. .set(( short ) ((limit + 1)
  291. * LittleEndianConsts.SHORT_SIZE), _raw_data);
  292. }
  293. /**
  294. * Sets the storage class ID for this property stream. This is the Class ID
  295. * of the COM object which can read and write this property stream
  296. * @param clsidStorage Storage Class ID
  297. */
  298. public void setStorageClsid( ClassID clsidStorage)
  299. {
  300. _storage_clsid = clsidStorage;
  301. if( clsidStorage == null) {
  302. Arrays.fill( _raw_data, _storage_clsid_offset, _storage_clsid_offset + ClassID.LENGTH, (byte) 0);
  303. } else {
  304. clsidStorage.write( _raw_data, _storage_clsid_offset);
  305. }
  306. }
  307. /**
  308. * Set the property type. Makes no attempt to validate the value.
  309. *
  310. * @param propertyType the property type (root, file, directory)
  311. */
  312. protected void setPropertyType(final byte propertyType)
  313. {
  314. _property_type.set(propertyType, _raw_data);
  315. }
  316. /**
  317. * Set the node color.
  318. *
  319. * @param nodeColor the node color (red or black)
  320. */
  321. protected void setNodeColor(final byte nodeColor)
  322. {
  323. _node_color.set(nodeColor, _raw_data);
  324. }
  325. /**
  326. * Set the child property.
  327. *
  328. * @param child the child property's index in the Property Table
  329. */
  330. protected void setChildProperty(final int child)
  331. {
  332. _child_property.set(child, _raw_data);
  333. }
  334. /**
  335. * Get the child property (its index in the Property Table)
  336. *
  337. * @return child property index
  338. */
  339. protected int getChildIndex()
  340. {
  341. return _child_property.get();
  342. }
  343. /**
  344. * Set the size of the document associated with this Property
  345. *
  346. * @param size the size of the document, in bytes
  347. */
  348. protected void setSize(final int size)
  349. {
  350. _size.set(size, _raw_data);
  351. }
  352. /**
  353. * Set the index for this Property
  354. *
  355. * @param index this Property's index within its containing
  356. * Property Table
  357. */
  358. protected void setIndex(final int index)
  359. {
  360. _index = index;
  361. }
  362. /**
  363. * get the index for this Property
  364. *
  365. * @return the index of this Property within its Property Table
  366. */
  367. protected int getIndex()
  368. {
  369. return _index;
  370. }
  371. /**
  372. * Perform whatever activities need to be performed prior to
  373. * writing
  374. */
  375. abstract protected void preWrite();
  376. /**
  377. * get the next sibling
  378. *
  379. * @return index of next sibling
  380. */
  381. int getNextChildIndex()
  382. {
  383. return _next_property.get();
  384. }
  385. /**
  386. * get the previous sibling
  387. *
  388. * @return index of previous sibling
  389. */
  390. int getPreviousChildIndex()
  391. {
  392. return _previous_property.get();
  393. }
  394. /**
  395. * determine whether the specified index is valid
  396. *
  397. * @param index value to be checked
  398. *
  399. * @return true if the index is valid
  400. */
  401. static boolean isValidIndex(int index)
  402. {
  403. return index != _NO_INDEX;
  404. }
  405. /* ********** START implementation of Child ********** */
  406. /**
  407. * Get the next Child, if any
  408. *
  409. * @return the next Child; may return null
  410. */
  411. public Child getNextChild()
  412. {
  413. return _next_child;
  414. }
  415. /**
  416. * Get the previous Child, if any
  417. *
  418. * @return the previous Child; may return null
  419. */
  420. public Child getPreviousChild()
  421. {
  422. return _previous_child;
  423. }
  424. /**
  425. * Set the next Child
  426. *
  427. * @param child the new 'next' child; may be null, which has the
  428. * effect of saying there is no 'next' child
  429. */
  430. public void setNextChild(final Child child)
  431. {
  432. _next_child = child;
  433. _next_property.set((child == null) ? _NO_INDEX
  434. : (( Property ) child)
  435. .getIndex(), _raw_data);
  436. }
  437. /**
  438. * Set the previous Child
  439. *
  440. * @param child the new 'previous' child; may be null, which has
  441. * the effect of saying there is no 'previous' child
  442. */
  443. public void setPreviousChild(final Child child)
  444. {
  445. _previous_child = child;
  446. _previous_property.set((child == null) ? _NO_INDEX
  447. : (( Property ) child)
  448. .getIndex(), _raw_data);
  449. }
  450. /* ********** END implementation of Child ********** */
  451. /* ********** START begin implementation of POIFSViewable ********** */
  452. /**
  453. * Get an array of objects, some of which may implement
  454. * POIFSViewable
  455. *
  456. * @return an array of Object; may not be null, but may be empty
  457. */
  458. public Object [] getViewableArray()
  459. {
  460. Object[] results = new Object[ 5 ];
  461. results[ 0 ] = "Name = \"" + getName() + "\"";
  462. results[ 1 ] = "Property Type = " + _property_type.get();
  463. results[ 2 ] = "Node Color = " + _node_color.get();
  464. long time = _days_1.get();
  465. time <<= 32;
  466. time += (( long ) _seconds_1.get()) & 0x0000FFFFL;
  467. results[ 3 ] = "Time 1 = " + time;
  468. time = _days_2.get();
  469. time <<= 32;
  470. time += (( long ) _seconds_2.get()) & 0x0000FFFFL;
  471. results[ 4 ] = "Time 2 = " + time;
  472. return results;
  473. }
  474. /**
  475. * Get an Iterator of objects, some of which may implement
  476. * POIFSViewable
  477. *
  478. * @return an Iterator; may not be null, but may have an empty
  479. * back end store
  480. */
  481. public Iterator getViewableIterator()
  482. {
  483. return Collections.EMPTY_LIST.iterator();
  484. }
  485. /**
  486. * Give viewers a hint as to whether to call getViewableArray or
  487. * getViewableIterator
  488. *
  489. * @return true if a viewer should call getViewableArray, false if
  490. * a viewer should call getViewableIterator
  491. */
  492. public boolean preferArray()
  493. {
  494. return true;
  495. }
  496. /**
  497. * Provides a short description of the object, to be used when a
  498. * POIFSViewable object has not provided its contents.
  499. *
  500. * @return short description
  501. */
  502. public String getShortDescription()
  503. {
  504. StringBuffer buffer = new StringBuffer();
  505. buffer.append("Property: \"").append(getName()).append("\"");
  506. return buffer.toString();
  507. }
  508. /* ********** END begin implementation of POIFSViewable ********** */
  509. } // end public abstract class Property