You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PlfLfo.java 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. * ====================================================================
  3. * Licensed to the Apache Software Foundation (ASF) under one or more
  4. * contributor license agreements. See the NOTICE file distributed with
  5. * this work for additional information regarding copyright ownership.
  6. * The ASF licenses this file to You under the Apache License, Version 2.0
  7. * (the "License"); you may not use this file except in compliance with
  8. * the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. * ====================================================================
  18. */
  19. package org.apache.poi.hwpf.model;
  20. import java.io.ByteArrayOutputStream;
  21. import java.io.IOException;
  22. import java.util.Arrays;
  23. import java.util.NoSuchElementException;
  24. import org.apache.poi.hwpf.model.types.LFOAbstractType;
  25. import org.apache.poi.util.LittleEndian;
  26. import org.apache.poi.util.LittleEndianConsts;
  27. import org.apache.poi.util.POILogFactory;
  28. import org.apache.poi.util.POILogger;
  29. /**
  30. * The PlfLfo structure contains the list format override data for the document.
  31. * <p>
  32. * Documentation quoted from Page 424 of 621. [MS-DOC] -- v20110315 Word (.doc)
  33. * Binary File Format
  34. *
  35. * @author Sergey Vladimirov (vlsergey {at} gmail {dot} com)
  36. */
  37. public class PlfLfo
  38. {
  39. private final static POILogger log = POILogFactory.getLogger( PlfLfo.class );
  40. /**
  41. * An unsigned integer that specifies the count of elements in both the
  42. * rgLfo and rgLfoData arrays.
  43. */
  44. private int _lfoMac;
  45. private LFO[] _rgLfo;
  46. private LFOData[] _rgLfoData;
  47. PlfLfo( byte[] tableStream, int fcPlfLfo, int lcbPlfLfo )
  48. {
  49. /*
  50. * The PlfLfo structure contains the list format override data for the
  51. * document. -- Page 424 of 621. [MS-DOC] -- v20110315 Word (.doc)
  52. * Binary File Format
  53. */
  54. int offset = fcPlfLfo;
  55. /*
  56. * lfoMac (4 bytes): An unsigned integer that specifies the count of
  57. * elements in both the rgLfo and rgLfoData arrays. -- Page 424 of 621.
  58. * [MS-DOC] -- v20110315 Word (.doc) Binary File Format
  59. */
  60. long lfoMacLong = LittleEndian.getUInt( tableStream, offset );
  61. offset += LittleEndianConsts.INT_SIZE;
  62. if ( lfoMacLong > Integer.MAX_VALUE )
  63. {
  64. throw new UnsupportedOperationException(
  65. "Apache POI doesn't support rgLfo/rgLfoData size large than "
  66. + Integer.MAX_VALUE + " elements" );
  67. }
  68. this._lfoMac = (int) lfoMacLong;
  69. _rgLfo = new LFO[_lfoMac];
  70. _rgLfoData = new LFOData[_lfoMac];
  71. /*
  72. * An array of LFO structures. The number of elements in this array is
  73. * specified by lfoMac. -- Page 424 of 621. [MS-DOC] -- v20110315 Word
  74. * (.doc) Binary File Format
  75. */
  76. for ( int x = 0; x < _lfoMac; x++ )
  77. {
  78. LFO lfo = new LFO( tableStream, offset );
  79. offset += LFOAbstractType.getSize();
  80. _rgLfo[x] = lfo;
  81. }
  82. /*
  83. * An array of LFOData that is parallel to rgLfo. The number of elements
  84. * that are contained in this array is specified by lfoMac. -- Page 424
  85. * of 621. [MS-DOC] -- v20110315 Word (.doc) Binary File Format
  86. */
  87. for ( int x = 0; x < _lfoMac; x++ )
  88. {
  89. LFOData lfoData = new LFOData( tableStream, offset,
  90. _rgLfo[x].getClfolvl() );
  91. offset += lfoData.getSizeInBytes();
  92. _rgLfoData[x] = lfoData;
  93. }
  94. if ( ( offset - fcPlfLfo ) != lcbPlfLfo )
  95. {
  96. if (log.check(POILogger.WARN)) {
  97. log.log(POILogger.WARN, "Actual size of PlfLfo is "
  98. + (offset - fcPlfLfo) + " bytes, but expected "
  99. + lcbPlfLfo);
  100. }
  101. }
  102. }
  103. void add( LFO lfo, LFOData lfoData )
  104. {
  105. // _lfoMac is the size of the array
  106. _rgLfo = Arrays.copyOf(_rgLfo, _lfoMac + 1);
  107. _rgLfo[_lfoMac] = lfo;
  108. _rgLfoData = Arrays.copyOf(_rgLfoData, _lfoMac + 1);
  109. _rgLfoData[_lfoMac] = lfoData;
  110. _lfoMac = _lfoMac + 1;
  111. }
  112. @Override
  113. public boolean equals( Object obj ) {
  114. if (this == obj)
  115. return true;
  116. if (obj == null)
  117. return false;
  118. if (getClass() != obj.getClass())
  119. return false;
  120. PlfLfo other = (PlfLfo) obj;
  121. return _lfoMac == other._lfoMac &&
  122. Arrays.equals(_rgLfo, other._rgLfo) &&
  123. Arrays.equals(_rgLfoData, other._rgLfoData);
  124. }
  125. /**
  126. * An unsigned integer that specifies the count of elements in both the
  127. * rgLfo and rgLfoData arrays.
  128. */
  129. public int getLfoMac()
  130. {
  131. return _lfoMac;
  132. }
  133. public int getIlfoByLsid( int lsid )
  134. {
  135. for ( int i = 0; i < _lfoMac; i++ )
  136. {
  137. if ( _rgLfo[i].getLsid() == lsid )
  138. {
  139. return i + 1;
  140. }
  141. }
  142. throw new NoSuchElementException( "LFO with lsid " + lsid
  143. + " not found" );
  144. }
  145. /**
  146. * @param ilfo 1-based index
  147. * @return The {@link LFO} stored at the given index
  148. * @throws NoSuchElementException
  149. */
  150. public LFO getLfo( int ilfo ) throws NoSuchElementException
  151. {
  152. if ( ilfo <= 0 || ilfo > _lfoMac )
  153. {
  154. throw new NoSuchElementException( "LFO with ilfo " + ilfo
  155. + " not found. lfoMac is " + _lfoMac );
  156. }
  157. return _rgLfo[ilfo - 1];
  158. }
  159. /**
  160. * @param ilfo 1-based index
  161. * @return The {@link LFOData} stored at the given index
  162. * @throws NoSuchElementException
  163. */
  164. public LFOData getLfoData( int ilfo ) throws NoSuchElementException
  165. {
  166. if ( ilfo <= 0 || ilfo > _lfoMac )
  167. {
  168. throw new NoSuchElementException( "LFOData with ilfo " + ilfo
  169. + " not found. lfoMac is " + _lfoMac );
  170. }
  171. return _rgLfoData[ilfo - 1];
  172. }
  173. @Override
  174. public int hashCode() {
  175. return Arrays.deepHashCode(new Object[]{_lfoMac, _rgLfo, _rgLfoData});
  176. }
  177. void writeTo( FileInformationBlock fib, ByteArrayOutputStream outputStream )
  178. throws IOException
  179. {
  180. final int offset = outputStream.size();
  181. fib.setFcPlfLfo( offset );
  182. LittleEndian.putUInt( _lfoMac, outputStream );
  183. byte[] bs = new byte[LFOAbstractType.getSize() * _lfoMac];
  184. for ( int i = 0; i < _lfoMac; i++ )
  185. {
  186. _rgLfo[i].serialize( bs, i * LFOAbstractType.getSize() );
  187. }
  188. outputStream.write( bs, 0, LFOAbstractType.getSize() * _lfoMac );
  189. for ( int i = 0; i < _lfoMac; i++ )
  190. {
  191. _rgLfoData[i].writeTo( outputStream );
  192. }
  193. fib.setLcbPlfLfo( outputStream.size() - offset );
  194. }
  195. }