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.

Sttb.java 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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.hwpf.model;
  16. import java.util.Arrays;
  17. import org.apache.poi.util.LittleEndian;
  18. import org.apache.poi.util.LittleEndianConsts;
  19. import org.apache.poi.util.POILogFactory;
  20. import org.apache.poi.util.POILogger;
  21. import org.apache.poi.util.StringUtil;
  22. /**
  23. * The STTB is a string table that is made up of a header that is followed by an
  24. * array of elements. The cData value specifies the number of elements that are
  25. * contained in the array.
  26. * <p>
  27. * Class and fields descriptions are quoted from [MS-DOC] -- v20121003 Word
  28. * (.doc) Binary File Format; Copyright (c) 2012 Microsoft Corporation; Release:
  29. * October 8, 2012
  30. * <p>
  31. * This class is internal. It content or properties may change without notice
  32. * due to changes in our knowledge of internal Microsoft Word binary structures.
  33. *
  34. * @author Sergey Vladimirov; according to [MS-DOC] -- v20121003 Word (.doc)
  35. * Binary File Format; Copyright (c) 2012 Microsoft Corporation;
  36. * Release: October 8, 2012
  37. */
  38. public class Sttb
  39. {
  40. private int _cbExtra;
  41. private final int _cDataLength;
  42. private String[] _data;
  43. private byte[][] _extraData;
  44. private final boolean _fExtend = true;
  45. public Sttb( byte[] buffer, int startOffset )
  46. {
  47. this( 2, buffer, startOffset );
  48. }
  49. public Sttb( int cDataLength, byte[] buffer, int startOffset )
  50. {
  51. this._cDataLength = cDataLength;
  52. fillFields( buffer, startOffset );
  53. }
  54. public Sttb( int cDataLength, String[] data )
  55. {
  56. this._cDataLength = cDataLength;
  57. this._data = Arrays.copyOf(data, data.length);
  58. this._cbExtra = 0;
  59. this._extraData = null;
  60. }
  61. public void fillFields( byte[] buffer, int startOffset )
  62. {
  63. short ffff = LittleEndian.getShort( buffer, startOffset );
  64. int offset = startOffset + LittleEndianConsts.SHORT_SIZE;
  65. if ( ffff != (short) 0xffff )
  66. {
  67. POILogFactory.getLogger(Sttb.class).log(
  68. POILogger.WARN,
  69. "Non-extended character Pascal strings are not supported right now. "
  70. + "Creating empty values in the RevisionMarkAuthorTable for now. " +
  71. "Please, contact POI developers for update.");
  72. //set data and extraData to empty values to avoid
  73. //downstream NPE in case someone calls getEntries on RevisionMarkAuthorTable
  74. _data = new String[0];
  75. _extraData = new byte[0][];
  76. return;
  77. }
  78. // strings are extended character strings
  79. int cData = _cDataLength == 2 ? LittleEndian.getUShort( buffer, offset )
  80. : LittleEndian.getInt( buffer, offset );
  81. offset += _cDataLength;
  82. this._cbExtra = LittleEndian.getUShort( buffer, offset );
  83. offset += 2;
  84. _data = new String[cData];
  85. _extraData = new byte[cData][];
  86. for ( int i = 0; i < cData; i++ )
  87. {
  88. int cchData = LittleEndian.getShort( buffer, offset );
  89. offset += 2;
  90. if ( cchData < 0 )
  91. continue;
  92. _data[i] = StringUtil.getFromUnicodeLE( buffer, offset, cchData );
  93. offset += cchData * 2;
  94. _extraData[i] = LittleEndian
  95. .getByteArray( buffer, offset, _cbExtra );
  96. offset += _cbExtra;
  97. }
  98. }
  99. /**
  100. * The definition of each STTB specifies the meaning of this field. If this
  101. * STTB uses extended characters, the size of this field is 2*cchData bytes
  102. * and it is a Unicode string unless otherwise specified by the STTB
  103. * definition. If this STTB does not use extended characters, then the size
  104. * of this field is cchData bytes and it is an ANSI string, unless otherwise
  105. * specified by the STTB definition.
  106. */
  107. public String[] getData()
  108. {
  109. return _data;
  110. }
  111. public int getSize()
  112. {
  113. // ffff
  114. int size = LittleEndianConsts.SHORT_SIZE;
  115. // cData
  116. size += _cDataLength;
  117. // cbExtra
  118. size += LittleEndianConsts.SHORT_SIZE;
  119. if ( this._fExtend )
  120. {
  121. for ( String data : _data )
  122. {
  123. // cchData
  124. size += LittleEndianConsts.SHORT_SIZE;
  125. // data
  126. size += 2 * data.length();
  127. }
  128. }
  129. else
  130. {
  131. for ( String data : _data )
  132. {
  133. // cchData
  134. size += LittleEndianConsts.BYTE_SIZE;
  135. // data
  136. size += data.length();
  137. }
  138. }
  139. // extraData
  140. if ( _extraData != null )
  141. {
  142. size += _cbExtra * _data.length;
  143. }
  144. return size;
  145. }
  146. public byte[] serialize()
  147. {
  148. final byte[] buffer = new byte[getSize()];
  149. LittleEndian.putShort( buffer, 0, (short) 0xffff );
  150. if ( _data == null || _data.length == 0 )
  151. {
  152. if ( _cDataLength == 4 )
  153. {
  154. LittleEndian.putInt( buffer, 2, 0 );
  155. LittleEndian.putUShort( buffer, 6, _cbExtra );
  156. return buffer;
  157. }
  158. LittleEndian.putUShort( buffer, 2, 0 );
  159. LittleEndian.putUShort( buffer, 4, _cbExtra );
  160. return buffer;
  161. }
  162. int offset;
  163. if ( _cDataLength == 4 )
  164. {
  165. LittleEndian.putInt( buffer, 2, _data.length );
  166. LittleEndian.putUShort( buffer, 6, _cbExtra );
  167. offset = 2 + LittleEndianConsts.INT_SIZE + LittleEndianConsts.SHORT_SIZE;
  168. }
  169. else
  170. {
  171. LittleEndian.putUShort( buffer, 2, _data.length );
  172. LittleEndian.putUShort( buffer, 4, _cbExtra );
  173. offset = 2 + LittleEndianConsts.SHORT_SIZE + LittleEndianConsts.SHORT_SIZE;
  174. }
  175. for ( int i = 0; i < _data.length; i++ )
  176. {
  177. String entry = _data[i];
  178. if ( entry == null )
  179. {
  180. // is it correct?
  181. buffer[offset] = -1;
  182. buffer[offset + 1] = 0;
  183. offset += 2;
  184. continue;
  185. }
  186. if ( _fExtend )
  187. {
  188. LittleEndian.putUShort( buffer, offset, entry.length() );
  189. offset += LittleEndianConsts.SHORT_SIZE;
  190. StringUtil.putUnicodeLE( entry, buffer, offset );
  191. offset += 2 * entry.length();
  192. }
  193. else
  194. {
  195. throw new UnsupportedOperationException(
  196. "ANSI STTB is not supported yet" );
  197. }
  198. if ( _cbExtra != 0 )
  199. {
  200. if ( _extraData[i] != null && _extraData[i].length != 0 )
  201. {
  202. System.arraycopy( _extraData[i], 0, buffer, offset,
  203. Math.min( _extraData[i].length, _cbExtra ) );
  204. }
  205. offset += _cbExtra;
  206. }
  207. }
  208. return buffer;
  209. }
  210. public int serialize( byte[] buffer, int offset )
  211. {
  212. byte[] bs = serialize();
  213. System.arraycopy( bs, 0, buffer, offset, bs.length );
  214. return bs.length;
  215. }
  216. }