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.

ParagraphSprmUncompressor.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  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.sprm;
  16. import java.util.ArrayList;
  17. import java.util.Collections;
  18. import java.util.HashMap;
  19. import java.util.List;
  20. import java.util.Map;
  21. import org.apache.poi.hwpf.model.TabDescriptor;
  22. import org.apache.poi.hwpf.model.types.TBDAbstractType;
  23. import org.apache.poi.hwpf.usermodel.BorderCode;
  24. import org.apache.poi.hwpf.usermodel.DateAndTime;
  25. import org.apache.poi.hwpf.usermodel.DropCapSpecifier;
  26. import org.apache.poi.hwpf.usermodel.LineSpacingDescriptor;
  27. import org.apache.poi.hwpf.usermodel.ParagraphProperties;
  28. import org.apache.poi.hwpf.usermodel.ShadingDescriptor;
  29. import org.apache.poi.hwpf.usermodel.ShadingDescriptor80;
  30. import org.apache.poi.util.Internal;
  31. import org.apache.poi.util.LittleEndian;
  32. import org.apache.poi.util.LittleEndianConsts;
  33. import org.apache.poi.util.POILogFactory;
  34. import org.apache.poi.util.POILogger;
  35. @Internal
  36. public final class ParagraphSprmUncompressor
  37. extends SprmUncompressor
  38. {
  39. private static final POILogger logger = POILogFactory
  40. .getLogger( ParagraphSprmUncompressor.class );
  41. public ParagraphSprmUncompressor()
  42. {
  43. }
  44. public static ParagraphProperties uncompressPAP(ParagraphProperties parent,
  45. byte[] grpprl,
  46. int offset)
  47. {
  48. ParagraphProperties newProperties = parent.copy();
  49. SprmIterator sprmIt = new SprmIterator(grpprl, offset);
  50. while (sprmIt.hasNext())
  51. {
  52. SprmOperation sprm = sprmIt.next();
  53. // PAPXs can contain table sprms if the paragraph marks the end of a
  54. // table row
  55. if (sprm.getType() == SprmOperation.TYPE_PAP)
  56. {
  57. try
  58. {
  59. unCompressPAPOperation( newProperties, sprm );
  60. }
  61. catch ( Exception exc )
  62. {
  63. logger.log(
  64. POILogger.ERROR,
  65. "Unable to apply SPRM operation '"
  66. + sprm.getOperation() + "': ", exc );
  67. }
  68. }
  69. }
  70. return newProperties;
  71. }
  72. /**
  73. * Performs an operation on a ParagraphProperties object. Used to uncompress
  74. * from a papx.
  75. *
  76. * @param newPAP The ParagraphProperties object to perform the operation on.
  77. * @param sprm sn SPRM operation.
  78. */
  79. static void unCompressPAPOperation (ParagraphProperties newPAP, SprmOperation sprm)
  80. {
  81. switch (sprm.getOperation())
  82. {
  83. case 0:
  84. newPAP.setIstd (sprm.getOperand());
  85. break;
  86. case 0x1:
  87. // Used only for piece table grpprl's not for PAPX
  88. // int istdFirst = LittleEndian.getShort (varParam, 2);
  89. // int istdLast = LittleEndian.getShort (varParam, 4);
  90. // if ((newPAP.getIstd () > istdFirst) || (newPAP.getIstd () <= istdLast))
  91. // {
  92. // permuteIstd (newPAP, varParam, opSize);
  93. // }
  94. break;
  95. case 0x2:
  96. if (newPAP.getIstd () <= 9 || newPAP.getIstd () >= 1)
  97. {
  98. byte paramTmp = (byte) sprm.getOperand();
  99. newPAP.setIstd (newPAP.getIstd () + paramTmp);
  100. newPAP.setLvl ((byte) (newPAP.getLvl () + paramTmp));
  101. if (((paramTmp >> 7) & 0x01) == 1)
  102. {
  103. newPAP.setIstd (Math.max (newPAP.getIstd (), 1));
  104. }
  105. else
  106. {
  107. newPAP.setIstd (Math.min (newPAP.getIstd (), 9));
  108. }
  109. }
  110. break;
  111. case 0x3:
  112. // Physical justification of the paragraph
  113. newPAP.setJc ((byte) sprm.getOperand());
  114. break;
  115. case 0x4:
  116. newPAP.setFSideBySide (sprm.getOperand() != 0);
  117. break;
  118. case 0x5:
  119. newPAP.setFKeep (sprm.getOperand() != 0);
  120. break;
  121. case 0x6:
  122. newPAP.setFKeepFollow (sprm.getOperand() != 0);
  123. break;
  124. case 0x7:
  125. newPAP.setFPageBreakBefore (sprm.getOperand() != 0);
  126. break;
  127. case 0x8:
  128. newPAP.setBrcl ((byte) sprm.getOperand());
  129. break;
  130. case 0x9:
  131. newPAP.setBrcp ((byte) sprm.getOperand());
  132. break;
  133. case 0xa:
  134. newPAP.setIlvl ((byte) sprm.getOperand());
  135. break;
  136. case 0xb:
  137. /* sprmPIlfo -- 0x460B */
  138. newPAP.setIlfo( sprm.getOperandShortSigned() );
  139. break;
  140. case 0xc:
  141. newPAP.setFNoLnn (sprm.getOperand() != 0);
  142. break;
  143. case 0xd:
  144. // handle tabs . variable parameter. seperate processing needed
  145. handleTabs(newPAP, sprm);
  146. break;
  147. case 0xe:
  148. newPAP.setDxaRight (sprm.getOperand());
  149. break;
  150. case 0xf:
  151. newPAP.setDxaLeft (sprm.getOperand());
  152. break;
  153. case 0x10:
  154. // sprmPNest is only stored in grpprls linked to a piece table.
  155. newPAP.setDxaLeft (newPAP.getDxaLeft () + sprm.getOperand());
  156. newPAP.setDxaLeft (Math.max (0, newPAP.getDxaLeft ()));
  157. break;
  158. case 0x11:
  159. newPAP.setDxaLeft1 (sprm.getOperand());
  160. break;
  161. case 0x12:
  162. newPAP.setLspd(new LineSpacingDescriptor(sprm.getGrpprl(), sprm.getGrpprlOffset()));
  163. break;
  164. case 0x13:
  165. newPAP.setDyaBefore (sprm.getOperand());
  166. break;
  167. case 0x14:
  168. newPAP.setDyaAfter (sprm.getOperand());
  169. break;
  170. case 0x15:
  171. // fast saved only
  172. //applySprmPChgTabs (newPAP, varParam, opSize);
  173. break;
  174. case 0x16:
  175. // sprmPFInTable -- 0x2416
  176. newPAP.setFInTable( sprm.getOperand() != 0);
  177. break;
  178. case 0x17:
  179. newPAP.setFTtp ( sprm.getOperand() != 0);
  180. break;
  181. case 0x18:
  182. newPAP.setDxaAbs (sprm.getOperand());
  183. break;
  184. case 0x19:
  185. newPAP.setDyaAbs (sprm.getOperand());
  186. break;
  187. case 0x1a:
  188. newPAP.setDxaWidth (sprm.getOperand());
  189. break;
  190. case 0x1b:
  191. byte param = (byte)sprm.getOperand();
  192. // TODO: handle paragraph postioning
  193. byte pcVert = (byte) ((param & 0x0c) >> 2);
  194. byte pcHorz = (byte) (param & 0x03);
  195. if (pcVert != 3)
  196. {
  197. newPAP.setPcVert (pcVert);
  198. }
  199. if (pcHorz != 3)
  200. {
  201. newPAP.setPcHorz (pcHorz);
  202. }
  203. break;
  204. // BrcXXX1 is older Version. Brc is used
  205. // case 0x1c:
  206. // newPAP.setBrcTop1((short)param);
  207. // break;
  208. // case 0x1d:
  209. // newPAP.setBrcLeft1((short)param);
  210. // break;
  211. // case 0x1e:
  212. // newPAP.setBrcBottom1((short)param);
  213. // break;
  214. // case 0x1f:
  215. // newPAP.setBrcRight1((short)param);
  216. // break;
  217. // case 0x20:
  218. // newPAP.setBrcBetween1((short)param);
  219. // break;
  220. // case 0x21:
  221. // newPAP.setBrcBar1((byte)param);
  222. // break;
  223. case 0x22:
  224. newPAP.setDxaFromText (sprm.getOperand());
  225. break;
  226. case 0x23:
  227. newPAP.setWr((byte)sprm.getOperand());
  228. break;
  229. case 0x24:
  230. newPAP.setBrcTop(new BorderCode(sprm.getGrpprl(), sprm.getGrpprlOffset()));
  231. break;
  232. case 0x25:
  233. newPAP.setBrcLeft(new BorderCode(sprm.getGrpprl(), sprm.getGrpprlOffset()));
  234. break;
  235. case 0x26:
  236. newPAP.setBrcBottom (new BorderCode(sprm.getGrpprl(), sprm.getGrpprlOffset()));
  237. break;
  238. case 0x27:
  239. newPAP.setBrcRight (new BorderCode(sprm.getGrpprl(), sprm.getGrpprlOffset()));
  240. break;
  241. case 0x28:
  242. newPAP.setBrcBetween (new BorderCode(sprm.getGrpprl(), sprm.getGrpprlOffset()));
  243. break;
  244. case 0x29:
  245. newPAP.setBrcBar (new BorderCode(sprm.getGrpprl(), sprm.getGrpprlOffset()));
  246. break;
  247. case 0x2a:
  248. newPAP.setFNoAutoHyph (sprm.getOperand() != 0);
  249. break;
  250. case 0x2b:
  251. newPAP.setDyaHeight (sprm.getOperand());
  252. break;
  253. case 0x2c:
  254. newPAP.setDcs (new DropCapSpecifier((short)sprm.getOperand()));
  255. break;
  256. case 0x2d:
  257. newPAP.setShd( new ShadingDescriptor80( (short) sprm.getOperand() )
  258. .toShadingDescriptor() );
  259. break;
  260. case 0x2e:
  261. newPAP.setDyaFromText (sprm.getOperand());
  262. break;
  263. case 0x2f:
  264. newPAP.setDxaFromText (sprm.getOperand());
  265. break;
  266. case 0x30:
  267. newPAP.setFLocked (sprm.getOperand() != 0);
  268. break;
  269. case 0x31:
  270. newPAP.setFWidowControl (sprm.getOperand() != 0);
  271. break;
  272. case 0x33:
  273. newPAP.setFKinsoku (sprm.getOperand() != 0);
  274. break;
  275. case 0x34:
  276. newPAP.setFWordWrap (sprm.getOperand() != 0);
  277. break;
  278. case 0x35:
  279. newPAP.setFOverflowPunct (sprm.getOperand() != 0);
  280. break;
  281. case 0x36:
  282. newPAP.setFTopLinePunct (sprm.getOperand() != 0);
  283. break;
  284. case 0x37:
  285. newPAP.setFAutoSpaceDE (sprm.getOperand() != 0);
  286. break;
  287. case 0x38:
  288. newPAP.setFAutoSpaceDN (sprm.getOperand() != 0);
  289. break;
  290. case 0x39:
  291. newPAP.setWAlignFont (sprm.getOperand());
  292. break;
  293. case 0x3a:
  294. newPAP.setFontAlign ((short) sprm.getOperand());
  295. break;
  296. case 0x3b:
  297. //obsolete
  298. break;
  299. case 0x3e:
  300. {
  301. byte[] buf = new byte[sprm.size() - 3];
  302. System.arraycopy(buf, 0, sprm.getGrpprl(), sprm.getGrpprlOffset(),
  303. buf.length);
  304. newPAP.setAnld(buf);
  305. break;
  306. }
  307. case 0x3f:
  308. //don't really need this. spec is confusing regarding this
  309. //sprm
  310. byte[] varParam = sprm.getGrpprl();
  311. int offset = sprm.getGrpprlOffset();
  312. newPAP.setFPropRMark (varParam[offset] != 0 );
  313. newPAP.setIbstPropRMark (LittleEndian.getShort (varParam, offset + 1));
  314. newPAP.setDttmPropRMark (new DateAndTime(varParam, offset + 3));
  315. break;
  316. case 0x40:
  317. // This condition commented out, as Word seems to set outline levels even for
  318. // paragraph with other styles than Heading 1..9, even though specification
  319. // does not say so. See bug 49820 for discussion.
  320. //if (newPAP.getIstd () < 1 && newPAP.getIstd () > 9)
  321. {
  322. newPAP.setLvl ((byte) sprm.getOperand());
  323. }
  324. break;
  325. case 0x41:
  326. // sprmPFBiDi
  327. newPAP.setFBiDi(sprm.getOperand() != 0);
  328. break;
  329. case 0x43:
  330. //pap.fNumRMIns
  331. newPAP.setFNumRMIns (sprm.getOperand() != 0);
  332. break;
  333. case 0x44:
  334. //undocumented
  335. break;
  336. case 0x45:
  337. if (sprm.getSizeCode() == 6)
  338. {
  339. byte[] buf = new byte[sprm.size() - 3];
  340. System.arraycopy(buf, 0, sprm.getGrpprl(), sprm.getGrpprlOffset(), buf.length);
  341. newPAP.setNumrm (buf);
  342. }
  343. else
  344. {
  345. /**@todo handle large PAPX from data stream*/
  346. }
  347. break;
  348. case 0x47:
  349. newPAP.setFUsePgsuSettings (sprm.getOperand() != 0);
  350. break;
  351. case 0x48:
  352. newPAP.setFAdjustRight (sprm.getOperand() != 0);
  353. break;
  354. case 0x49:
  355. // sprmPItap -- 0x6649
  356. newPAP.setItap( sprm.getOperand() );
  357. break;
  358. case 0x4a:
  359. // sprmPDtap -- 0x664a
  360. newPAP.setItap( (byte) ( newPAP.getItap() + sprm.getOperand() ) );
  361. break;
  362. case 0x4b:
  363. // sprmPFInnerTableCell -- 0x244b
  364. newPAP.setFInnerTableCell( sprm.getOperand() != 0);
  365. break;
  366. case 0x4c:
  367. // sprmPFInnerTtp -- 0x244c
  368. newPAP.setFTtpEmbedded( sprm.getOperand() != 0);
  369. break;
  370. case 0x4d:
  371. // sprmPShd -- 0xc64d
  372. ShadingDescriptor shadingDescriptor = new ShadingDescriptor(
  373. sprm.getGrpprl(), 3 );
  374. newPAP.setShading( shadingDescriptor );
  375. break;
  376. case 0x5d:
  377. // sprmPDxaRight -- 0x845d
  378. newPAP.setDxaRight( sprm.getOperand() );
  379. break;
  380. case 0x5e:
  381. // sprmPDxaLeft -- 0x845e
  382. newPAP.setDxaLeft( sprm.getOperand() );
  383. break;
  384. case 0x60:
  385. // sprmPDxaLeft1 -- 0x8460
  386. newPAP.setDxaLeft1( sprm.getOperand() );
  387. break;
  388. case 0x61:
  389. // sprmPJc
  390. newPAP.setJustificationLogical((byte) sprm.getOperand());
  391. break;
  392. case 0x67:
  393. // sprmPRsid -- 0x6467
  394. newPAP.setRsid( sprm.getOperand() );
  395. break;
  396. default:
  397. logger.log( POILogger.DEBUG, "Unknown PAP sprm ignored: " + sprm );
  398. break;
  399. }
  400. }
  401. private static void handleTabs(ParagraphProperties pap, SprmOperation sprm)
  402. {
  403. byte[] grpprl = sprm.getGrpprl();
  404. int offset = sprm.getGrpprlOffset();
  405. int delSize = grpprl[offset++];
  406. int[] tabPositions = pap.getRgdxaTab();
  407. TabDescriptor[] tabDescriptors = pap.getRgtbd();
  408. Map<Integer, TabDescriptor> tabMap = new HashMap<>();
  409. for (int x = 0; x < tabPositions.length; x++)
  410. {
  411. tabMap.put(tabPositions[x], tabDescriptors[x]);
  412. }
  413. for (int x = 0; x < delSize; x++)
  414. {
  415. tabMap.remove((int) LittleEndian.getShort(grpprl, offset));
  416. offset += LittleEndianConsts.SHORT_SIZE;
  417. }
  418. int addSize = grpprl[offset++];
  419. int start = offset;
  420. for (int x = 0; x < addSize; x++)
  421. {
  422. Integer key = (int) LittleEndian.getShort(grpprl, offset);
  423. TabDescriptor val = new TabDescriptor( grpprl, start + ((TBDAbstractType.getSize() * addSize) + x) );
  424. tabMap.put(key, val);
  425. offset += LittleEndianConsts.SHORT_SIZE;
  426. }
  427. tabPositions = new int[tabMap.size()];
  428. tabDescriptors = new TabDescriptor[tabPositions.length];
  429. List<Integer> list = new ArrayList<>(tabMap.keySet());
  430. Collections.sort(list);
  431. for (int x = 0; x < tabPositions.length; x++)
  432. {
  433. Integer key = list.get(x);
  434. tabPositions[x] = key;
  435. if (tabMap.containsKey( key ))
  436. tabDescriptors[x] = tabMap.get(key);
  437. else
  438. tabDescriptors[x] = new TabDescriptor();
  439. }
  440. pap.setRgdxaTab(tabPositions);
  441. pap.setRgtbd(tabDescriptors);
  442. }
  443. }