LibreOffice Module sw (master)  1
ww8scan.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <memory>
21 #include "ww8scan.hxx"
22 #include "ww8par.hxx"
23 
24 #include <cassert>
25 #include <cstddef>
26 #include <cstring>
27 #include <algorithm>
28 
29 #include <i18nlangtag/mslangid.hxx>
30 #include "sprmids.hxx"
31 #include <rtl/tencinfo.h>
32 #include <sal/macros.h>
33 #include <sal/log.hxx>
34 #include <osl/diagnose.h>
35 
36 #include <swerror.h>
37 
38 #include <comphelper/string.hxx>
40 #include <i18nlangtag/lang.h>
41 #include <o3tl/safeint.hxx>
42 #include <tools/stream.hxx>
43 
44 #include <vcl/settings.hxx>
45 #include <vcl/svapp.hxx>
46 
47 #ifdef DEBUGSPRMREADER
48 #include <stdio.h>
49 #endif
50 
51 using namespace ::com::sun::star::lang;
52 
53 namespace
54 {
63  bool TestBeltAndBraces(SvStream& rStrm)
64  {
65  bool bRet = false;
66  sal_uInt32 nOldPos = rStrm.Tell();
67  sal_uInt16 nBelt(0);
68  rStrm.ReadUInt16( nBelt );
69  nBelt *= sizeof(sal_Unicode);
70  if (rStrm.good() && (rStrm.remainingSize() >= (nBelt + sizeof(sal_Unicode))))
71  {
72  rStrm.SeekRel(nBelt);
73  if (rStrm.good())
74  {
75  sal_Unicode cBraces(0);
76  rStrm.ReadUtf16( cBraces );
77  if (rStrm.good() && cBraces == 0)
78  bRet = true;
79  }
80  }
81  rStrm.Seek(nOldPos);
82  return bRet;
83  }
84 }
85 
87 {
88  //double lock me
89  // WW2 Sprms
90  static const SprmInfoRow aSprms[] =
91  {
92  { 0, { 0, L_FIX} }, // "Default-sprm", will be skipped
93  { 2, { 1, L_FIX} }, // "sprmPIstd", pap.istd (style code)
94  { 3, { 0, L_VAR} }, // "sprmPIstdPermute pap.istd permutation
95  { 4, { 1, L_FIX} }, // "sprmPIncLv1" pap.istddifference
96  { 5, { 1, L_FIX} }, // "sprmPJc" pap.jc (justification)
97  { 6, { 1, L_FIX} }, // "sprmPFSideBySide" pap.fSideBySide
98  { 7, { 1, L_FIX} }, // "sprmPFKeep" pap.fKeep
99  { 8, { 1, L_FIX} }, // "sprmPFKeepFollow " pap.fKeepFollow
100  { 9, { 1, L_FIX} }, // "sprmPPageBreakBefore" pap.fPageBreakBefore
101  { 10, { 1, L_FIX} }, // "sprmPBrcl" pap.brcl
102  { 11, { 1, L_FIX} }, // "sprmPBrcp" pap.brcp
103  { 12, { 1, L_FIX} }, // "sprmPNfcSeqNumb" pap.nfcSeqNumb
104  { 13, { 1, L_FIX} }, // "sprmPNoSeqNumb" pap.nnSeqNumb
105  { 14, { 1, L_FIX} }, // "sprmPFNoLineNumb" pap.fNoLnn
106  { 15, { 0, L_VAR} }, // "?sprmPChgTabsPapx" pap.itbdMac, ...
107  { 16, { 2, L_FIX} }, // "sprmPDxaRight" pap.dxaRight
108  { 17, { 2, L_FIX} }, // "sprmPDxaLeft" pap.dxaLeft
109  { 18, { 2, L_FIX} }, // "sprmPNest" pap.dxaLeft
110  { 19, { 2, L_FIX} }, // "sprmPDxaLeft1" pap.dxaLeft1
111  { 20, { 2, L_FIX} }, // "sprmPDyaLine" pap.lspd an LSPD
112  { 21, { 2, L_FIX} }, // "sprmPDyaBefore" pap.dyaBefore
113  { 22, { 2, L_FIX} }, // "sprmPDyaAfter" pap.dyaAfter
114  { 23, { 0, L_VAR} }, // "?sprmPChgTabs" pap.itbdMac, pap.rgdxaTab, ...
115  { 24, { 1, L_FIX} }, // "sprmPFInTable" pap.fInTable
116  { 25, { 1, L_FIX} }, // "sprmPTtp" pap.fTtp
117  { 26, { 2, L_FIX} }, // "sprmPDxaAbs" pap.dxaAbs
118  { 27, { 2, L_FIX} }, // "sprmPDyaAbs" pap.dyaAbs
119  { 28, { 2, L_FIX} }, // "sprmPDxaWidth" pap.dxaWidth
120  { 29, { 1, L_FIX} }, // "sprmPPc" pap.pcHorz, pap.pcVert
121  { 30, { 2, L_FIX} }, // "sprmPBrcTop10" pap.brcTop BRC10
122  { 31, { 2, L_FIX} }, // "sprmPBrcLeft10" pap.brcLeft BRC10
123  { 32, { 2, L_FIX} }, // "sprmPBrcBottom10" pap.brcBottom BRC10
124  { 33, { 2, L_FIX} }, // "sprmPBrcRight10" pap.brcRight BRC10
125  { 34, { 2, L_FIX} }, // "sprmPBrcBetween10" pap.brcBetween BRC10
126  { 35, { 2, L_FIX} }, // "sprmPBrcBar10" pap.brcBar BRC10
127  { 36, { 2, L_FIX} }, // "sprmPFromText10" pap.dxaFromText dxa
128  { 37, { 1, L_FIX} }, // "sprmPWr" pap.wr wr
129  { 38, { 2, L_FIX} }, // "sprmPBrcTop" pap.brcTop BRC
130  { 39, { 2, L_FIX} }, // "sprmPBrcLeft" pap.brcLeft BRC
131  { 40, { 2, L_FIX} }, // "sprmPBrcBottom" pap.brcBottom BRC
132  { 41, { 2, L_FIX} }, // "sprmPBrcRight" pap.brcRight BRC
133  { 42, { 2, L_FIX} }, // "sprmPBrcBetween" pap.brcBetween BRC
134  { 43, { 2, L_FIX} }, // "sprmPBrcBar" pap.brcBar BRC word
135  { 44, { 1, L_FIX} }, // "sprmPFNoAutoHyph" pap.fNoAutoHyph
136  { 45, { 2, L_FIX} }, // "sprmPWHeightAbs" pap.wHeightAbs w
137  { 46, { 2, L_FIX} }, // "sprmPDcs" pap.dcs DCS
138  { 47, { 2, L_FIX} }, // "sprmPShd" pap.shd SHD
139  { 48, { 2, L_FIX} }, // "sprmPDyaFromText" pap.dyaFromText dya
140  { 49, { 2, L_FIX} }, // "sprmPDxaFromText" pap.dxaFromText dxa
141  { 50, { 1, L_FIX} }, // "sprmPFBiDi" pap.fBiDi 0 or 1 byte
142  { 51, { 1, L_FIX} }, // "sprmPFWidowControl" pap.fWidowControl 0 or 1 byte
143  { 52, { 0, L_FIX} }, // "?sprmPRuler 52"
144  { 53, { 1, L_FIX} }, // "sprmCFStrikeRM" chp.fRMarkDel 1 or 0 bit
145  { 54, { 1, L_FIX} }, // "sprmCFRMark" chp.fRMark 1 or 0 bit
146  { 55, { 1, L_FIX} }, // "sprmCFFieldVanish" chp.fFieldVanish 1 or 0 bit
147  { 57, { 0, L_VAR} }, // "sprmCDefault" whole CHP
148  { 58, { 0, L_FIX} }, // "sprmCPlain" whole CHP
149  { 60, { 1, L_FIX} }, // "sprmCFBold" chp.fBold 0,1, 128, or 129
150  { 61, { 1, L_FIX} }, // "sprmCFItalic" chp.fItalic 0,1, 128, or 129
151  { 62, { 1, L_FIX} }, // "sprmCFStrike" chp.fStrike 0,1, 128, or 129
152  { 63, { 1, L_FIX} }, // "sprmCFOutline" chp.fOutline 0,1, 128, or 129
153  { 64, { 1, L_FIX} }, // "sprmCFShadow" chp.fShadow 0,1, 128, or 129
154  { 65, { 1, L_FIX} }, // "sprmCFSmallCaps" chp.fSmallCaps 0,1, 128, or 129
155  { 66, { 1, L_FIX} }, // "sprmCFCaps" chp.fCaps 0,1, 128, or 129
156  { 67, { 1, L_FIX} }, // "sprmCFVanish" chp.fVanish 0,1, 128, or 129
157  { 68, { 2, L_FIX} }, // "sprmCFtc" chp.ftc ftc word
158  { 69, { 1, L_FIX} }, // "sprmCKul" chp.kul kul byte
159  { 70, { 3, L_FIX} }, // "sprmCSizePos" chp.hps, chp.hpsPos
160  { 71, { 2, L_FIX} }, // "sprmCDxaSpace" chp.dxaSpace dxa
161  { 72, { 2, L_FIX} }, // "sprmCLid" chp.lid LID
162  { 73, { 1, L_FIX} }, // "sprmCIco" chp.ico ico byte
163  { 74, { 1, L_FIX} }, // "sprmCHps" chp.hps hps !word!
164  { 75, { 1, L_FIX} }, // "sprmCHpsInc" chp.hps
165  { 76, { 1, L_FIX} }, // "sprmCHpsPos" chp.hpsPos hps !word!
166  { 77, { 1, L_FIX} }, // "sprmCHpsPosAdj" chp.hpsPos hps
167  { 78, { 0, L_VAR} }, // "?sprmCMajority" chp.fBold, chp.fItalic, ...
168  { 80, { 1, L_FIX} }, // "sprmCFBoldBi" chp.fBoldBi
169  { 81, { 1, L_FIX} }, // "sprmCFItalicBi" chp.fItalicBi
170  { 82, { 2, L_FIX} }, // "sprmCFtcBi" chp.ftcBi
171  { 83, { 2, L_FIX} }, // "sprmClidBi" chp.lidBi
172  { 84, { 1, L_FIX} }, // "sprmCIcoBi" chp.icoBi
173  { 85, { 1, L_FIX} }, // "sprmCHpsBi" chp.hpsBi
174  { 86, { 1, L_FIX} }, // "sprmCFBiDi" chp.fBiDi
175  { 87, { 1, L_FIX} }, // "sprmCFDiacColor" chp.fDiacUSico
176  { 94, { 1, L_FIX} }, // "sprmPicBrcl" pic.brcl brcl (see PIC definition)
177  { 95, {12, L_VAR} }, // "sprmPicScale" pic.mx, pic.my, pic.dxaCropleft,
178  { 96, { 2, L_FIX} }, // "sprmPicBrcTop" pic.brcTop BRC word
179  { 97, { 2, L_FIX} }, // "sprmPicBrcLeft" pic.brcLeft BRC word
180  { 98, { 2, L_FIX} }, // "sprmPicBrcBottom" pic.brcBottom BRC word
181  { 99, { 2, L_FIX} }, // "sprmPicBrcRight" pic.brcRight BRC word
182  {112, { 1, L_FIX} }, // "sprmSFRTLGutter", set to one if gutter is on
183  {114, { 1, L_FIX} }, // "sprmSFBiDi" ;;;
184  {115, { 2, L_FIX} }, // "sprmSDmBinFirst" sep.dmBinFirst word
185  {116, { 2, L_FIX} }, // "sprmSDmBinOther" sep.dmBinOther word
186  {117, { 1, L_FIX} }, // "sprmSBkc" sep.bkc bkc byte
187  {118, { 1, L_FIX} }, // "sprmSFTitlePage" sep.fTitlePage 0 or 1 byte
188  {119, { 2, L_FIX} }, // "sprmSCcolumns" sep.ccolM1 # of cols - 1 word
189  {120, { 2, L_FIX} }, // "sprmSDxaColumns" sep.dxaColumns dxa word
190  {121, { 1, L_FIX} }, // "sprmSFAutoPgn" sep.fAutoPgn obsolete byte
191  {122, { 1, L_FIX} }, // "sprmSNfcPgn" sep.nfcPgn nfc byte
192  {123, { 2, L_FIX} }, // "sprmSDyaPgn" sep.dyaPgn dya short
193  {124, { 2, L_FIX} }, // "sprmSDxaPgn" sep.dxaPgn dya short
194  {125, { 1, L_FIX} }, // "sprmSFPgnRestart" sep.fPgnRestart 0 or 1 byte
195  {126, { 1, L_FIX} }, // "sprmSFEndnote" sep.fEndnote 0 or 1 byte
196  {127, { 1, L_FIX} }, // "sprmSLnc" sep.lnc lnc byte
197  {128, { 1, L_FIX} }, // "sprmSGprfIhdt" sep.grpfIhdt grpfihdt
198  {129, { 2, L_FIX} }, // "sprmSNLnnMod" sep.nLnnMod non-neg int. word
199  {130, { 2, L_FIX} }, // "sprmSDxaLnn" sep.dxaLnn dxa word
200  {131, { 2, L_FIX} }, // "sprmSDyaHdrTop" sep.dyaHdrTop dya word
201  {132, { 2, L_FIX} }, // "sprmSDyaHdrBottom" sep.dyaHdrBottom dya word
202  {133, { 1, L_FIX} }, // "sprmSLBetween" sep.fLBetween 0 or 1 byte
203  {134, { 1, L_FIX} }, // "sprmSVjc" sep.vjc vjc byte
204  {135, { 2, L_FIX} }, // "sprmSLnnMin" sep.lnnMin lnn word
205  {136, { 2, L_FIX} }, // "sprmSPgnStart" sep.pgnStart pgn word
206  {137, { 1, L_FIX} }, // "sprmSBOrientation" sep.dmOrientPage dm byte
207  {138, { 1, L_FIX} }, // "sprmSFFacingCol" ;;;
208  {139, { 2, L_FIX} }, // "sprmSXaPage" sep.xaPage xa word
209  {140, { 2, L_FIX} }, // "sprmSYaPage" sep.yaPage ya word
210  {141, { 2, L_FIX} }, // "sprmSDxaLeft" sep.dxaLeft dxa word
211  {142, { 2, L_FIX} }, // "sprmSDxaRight" sep.dxaRight dxa word
212  {143, { 2, L_FIX} }, // "sprmSDyaTop" sep.dyaTop dya word
213  {144, { 2, L_FIX} }, // "sprmSDyaBottom" sep.dyaBottom dya word
214  {145, { 2, L_FIX} }, // "sprmSDzaGutter" sep.dzaGutter dza word
215  {146, { 2, L_FIX} }, // "sprmTJc" tap.jc jc (low order byte is significant)
216  {147, { 2, L_FIX} }, // "sprmTDxaLeft" tap.rgdxaCenter dxa word
217  {148, { 2, L_FIX} }, // "sprmTDxaGapHalf" tap.dxaGapHalf, tap.rgdxaCenter
218  {149, { 1, L_FIX} }, // "sprmTFBiDi" ;;;
219  {152, { 0, L_VAR} }, // "sprmTDefTable10" tap.rgdxaCenter, tap.rgtc complex
220  {153, { 2, L_FIX} }, // "sprmTDyaRowHeight" tap.dyaRowHeight dya word
221  {154, { 0, L_VAR2} },// "sprmTDefTable" tap.rgtc complex
222  {155, { 1, L_VAR} }, // "sprmTDefTableShd" tap.rgshd complex
223  {157, { 5, L_FIX} }, // "sprmTSetBrc" tap.rgtc[].rgbrc complex 5 bytes
224  {158, { 4, L_FIX} }, // "sprmTInsert" tap.rgdxaCenter,tap.rgtc complex
225  {159, { 2, L_FIX} }, // "sprmTDelete" tap.rgdxaCenter, tap.rgtc complex
226  {160, { 4, L_FIX} }, // "sprmTDxaCol" tap.rgdxaCenter complex
227  {161, { 2, L_FIX} }, // "sprmTMerge" tap.fFirstMerged, tap.fMerged complex
228  {162, { 2, L_FIX} }, // "sprmTSplit" tap.fFirstMerged, tap.fMerged complex
229  {163, { 5, L_FIX} }, // "sprmTSetBrc10" tap.rgtc[].rgbrc complex 5 bytes
230  {164, { 4, L_FIX} }, // "sprmTSetShd", tap.rgshd complex 4 bytes
231  };
232 
233  static wwSprmSearcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
234  return &aSprmSrch;
235 };
236 
238 {
239  //double lock me
240  // WW7- Sprms
241  static const SprmInfoRow aSprms[] =
242  {
243  { 0, { 0, L_FIX} }, // "Default-sprm", is skipped
244  {NS_sprm::v6::sprmPIstd, { 2, L_FIX} }, // pap.istd (style code)
245  {NS_sprm::v6::sprmPIstdPermute, { 3, L_VAR} }, // pap.istd permutation
246  {NS_sprm::v6::sprmPIncLv1, { 1, L_FIX} }, // pap.istddifference
247  {NS_sprm::v6::sprmPJc, { 1, L_FIX} }, // pap.jc (justification)
248  {NS_sprm::v6::sprmPFSideBySide, { 1, L_FIX} }, // pap.fSideBySide
249  {NS_sprm::v6::sprmPFKeep, { 1, L_FIX} }, // pap.fKeep
250  {NS_sprm::v6::sprmPFKeepFollow, { 1, L_FIX} }, // pap.fKeepFollow
251  {NS_sprm::v6::sprmPPageBreakBefore, { 1, L_FIX} }, // pap.fPageBreakBefore
252  {NS_sprm::v6::sprmPBrcl, { 1, L_FIX} }, // pap.brcl
253  {NS_sprm::v6::sprmPBrcp, { 1, L_FIX} }, // pap.brcp
254  {NS_sprm::v6::sprmPAnld, { 0, L_VAR} }, // pap.anld (ANLD structure)
255  {NS_sprm::v6::sprmPNLvlAnm, { 1, L_FIX} }, // pap.nLvlAnm nn
256  {NS_sprm::v6::sprmPFNoLineNumb, { 1, L_FIX} }, // pap.fNoLnn
257  {NS_sprm::v6::sprmPChgTabsPapx, { 0, L_VAR} }, // pap.itbdMac, ...
258  {NS_sprm::v6::sprmPDxaRight, { 2, L_FIX} }, // pap.dxaRight
259  {NS_sprm::v6::sprmPDxaLeft, { 2, L_FIX} }, // pap.dxaLeft
260  {NS_sprm::v6::sprmPNest, { 2, L_FIX} }, // pap.dxaLeft
261  {NS_sprm::v6::sprmPDxaLeft1, { 2, L_FIX} }, // pap.dxaLeft1
262  {NS_sprm::v6::sprmPDyaLine, { 4, L_FIX} }, // pap.lspd an LSPD
263  {NS_sprm::v6::sprmPDyaBefore, { 2, L_FIX} }, // pap.dyaBefore
264  {NS_sprm::v6::sprmPDyaAfter, { 2, L_FIX} }, // pap.dyaAfter
265  {NS_sprm::v6::sprmPChgTabs, { 0, L_VAR} }, // pap.itbdMac, pap.rgdxaTab, ...
266  {NS_sprm::v6::sprmPFInTable, { 1, L_FIX} }, // pap.fInTable
267  {NS_sprm::v6::sprmPTtp, { 1, L_FIX} }, // pap.fTtp
268  {NS_sprm::v6::sprmPDxaAbs, { 2, L_FIX} }, // pap.dxaAbs
269  {NS_sprm::v6::sprmPDyaAbs, { 2, L_FIX} }, // pap.dyaAbs
270  {NS_sprm::v6::sprmPDxaWidth, { 2, L_FIX} }, // pap.dxaWidth
271  {NS_sprm::v6::sprmPPc, { 1, L_FIX} }, // pap.pcHorz, pap.pcVert
272  {NS_sprm::v6::sprmPBrcTop10, { 2, L_FIX} }, // pap.brcTop BRC10
273  {NS_sprm::v6::sprmPBrcLeft10, { 2, L_FIX} }, // pap.brcLeft BRC10
274  {NS_sprm::v6::sprmPBrcBottom10, { 2, L_FIX} }, // pap.brcBottom BRC10
275  {NS_sprm::v6::sprmPBrcRight10, { 2, L_FIX} }, // pap.brcRight BRC10
276  {NS_sprm::v6::sprmPBrcBetween10, { 2, L_FIX} }, // pap.brcBetween BRC10
277  {NS_sprm::v6::sprmPBrcBar10, { 2, L_FIX} }, // pap.brcBar BRC10
278  {NS_sprm::v6::sprmPFromText10, { 2, L_FIX} }, // pap.dxaFromText dxa
279  {NS_sprm::v6::sprmPWr, { 1, L_FIX} }, // pap.wr wr
280  {NS_sprm::v6::sprmPBrcTop, { 2, L_FIX} }, // pap.brcTop BRC
281  {NS_sprm::v6::sprmPBrcLeft, { 2, L_FIX} }, // pap.brcLeft BRC
282  {NS_sprm::v6::sprmPBrcBottom, { 2, L_FIX} }, // pap.brcBottom BRC
283  {NS_sprm::v6::sprmPBrcRight, { 2, L_FIX} }, // pap.brcRight BRC
284  {NS_sprm::v6::sprmPBrcBetween, { 2, L_FIX} }, // pap.brcBetween BRC
285  {NS_sprm::v6::sprmPBrcBar, { 2, L_FIX} }, // pap.brcBar BRC word
286  {NS_sprm::v6::sprmPFNoAutoHyph, { 1, L_FIX} }, // pap.fNoAutoHyph
287  {NS_sprm::v6::sprmPWHeightAbs, { 2, L_FIX} }, // pap.wHeightAbs w
288  {NS_sprm::v6::sprmPDcs, { 2, L_FIX} }, // pap.dcs DCS
289  {NS_sprm::v6::sprmPShd, { 2, L_FIX} }, // pap.shd SHD
290  {NS_sprm::v6::sprmPDyaFromText, { 2, L_FIX} }, // pap.dyaFromText dya
291  {NS_sprm::v6::sprmPDxaFromText, { 2, L_FIX} }, // pap.dxaFromText dxa
292  {NS_sprm::v6::sprmPFLocked, { 1, L_FIX} }, // pap.fLocked 0 or 1 byte
293  {NS_sprm::v6::sprmPFWidowControl, { 1, L_FIX} }, // pap.fWidowControl 0 or 1 byte
294  {NS_sprm::v6::sprmPRuler, { 0, L_FIX} },
295  { 64, { 0, L_VAR} }, // rtl property ?
296  {NS_sprm::v6::sprmCFStrikeRM, { 1, L_FIX} }, // chp.fRMarkDel 1 or 0 bit
297  {NS_sprm::v6::sprmCFRMark, { 1, L_FIX} }, // chp.fRMark 1 or 0 bit
298  {NS_sprm::v6::sprmCFFldVanish, { 1, L_FIX} }, // chp.fFieldVanish 1 or 0 bit
299  {NS_sprm::v6::sprmCPicLocation, { 0, L_VAR} }, // chp.fcPic and chp.fSpec
300  {NS_sprm::v6::sprmCIbstRMark, { 2, L_FIX} }, // chp.ibstRMark index into sttbRMark
301  {NS_sprm::v6::sprmCDttmRMark, { 4, L_FIX} }, // chp.dttm DTTM long
302  {NS_sprm::v6::sprmCFData, { 1, L_FIX} }, // chp.fData 1 or 0 bit
303  {NS_sprm::v6::sprmCRMReason, { 2, L_FIX} }, // chp.idslRMReason an index to a table
304  {NS_sprm::v6::sprmCChse, { 3, L_FIX} }, // chp.fChsDiff and chp.chse
305  {NS_sprm::v6::sprmCSymbol, { 0, L_VAR} }, // chp.fSpec, chp.chSym and chp.ftcSym
306  {NS_sprm::v6::sprmCFOle2, { 1, L_FIX} }, // chp.fOle2 1 or 0 bit
307  { 77, { 0, L_VAR} }, // unknown
308  { 79, { 0, L_VAR} }, // unknown
309  {NS_sprm::v6::sprmCIstd, { 2, L_FIX} }, // chp.istd istd, see stylesheet definition
310  {NS_sprm::v6::sprmCIstdPermute, { 0, L_VAR} }, // chp.istd permutation vector
311  {NS_sprm::v6::sprmCDefault, { 0, L_VAR} }, // whole CHP
312  {NS_sprm::v6::sprmCPlain, { 0, L_FIX} }, // whole CHP
313  {NS_sprm::v6::sprmCFBold, { 1, L_FIX} }, // chp.fBold 0,1, 128, or 129
314  {NS_sprm::v6::sprmCFItalic, { 1, L_FIX} }, // chp.fItalic 0,1, 128, or 129
315  {NS_sprm::v6::sprmCFStrike, { 1, L_FIX} }, // chp.fStrike 0,1, 128, or 129
316  {NS_sprm::v6::sprmCFOutline, { 1, L_FIX} }, // chp.fOutline 0,1, 128, or 129
317  {NS_sprm::v6::sprmCFShadow, { 1, L_FIX} }, // chp.fShadow 0,1, 128, or 129
318  {NS_sprm::v6::sprmCFSmallCaps, { 1, L_FIX} }, // chp.fSmallCaps 0,1, 128, or 129
319  {NS_sprm::v6::sprmCFCaps, { 1, L_FIX} }, // chp.fCaps 0,1, 128, or 129
320  {NS_sprm::v6::sprmCFVanish, { 1, L_FIX} }, // chp.fVanish 0,1, 128, or 129
321  {NS_sprm::v6::sprmCFtc, { 2, L_FIX} }, // chp.ftc ftc word
322  {NS_sprm::v6::sprmCKul, { 1, L_FIX} }, // chp.kul kul byte
323  {NS_sprm::v6::sprmCSizePos, { 3, L_FIX} }, // chp.hps, chp.hpsPos
324  {NS_sprm::v6::sprmCDxaSpace, { 2, L_FIX} }, // chp.dxaSpace dxa
325  {NS_sprm::v6::sprmCLid, { 2, L_FIX} }, // chp.lid LID
326  {NS_sprm::v6::sprmCIco, { 1, L_FIX} }, // chp.ico ico byte
327  {NS_sprm::v6::sprmCHps, { 2, L_FIX} }, // chp.hps hps !word!
328  {NS_sprm::v6::sprmCHpsInc, { 1, L_FIX} }, // chp.hps
329  {NS_sprm::v6::sprmCHpsPos, { 2, L_FIX} }, // chp.hpsPos hps !word!
330  {NS_sprm::v6::sprmCHpsPosAdj, { 1, L_FIX} }, // chp.hpsPos hps
331  {NS_sprm::v6::sprmCMajority, { 0, L_VAR} }, // chp.fBold, chp.fItalic, ...
332  {NS_sprm::v6::sprmCIss, { 1, L_FIX} }, // chp.iss iss
333  {NS_sprm::v6::sprmCHpsNew50, { 0, L_VAR} }, // chp.hps hps variable width
334  {NS_sprm::v6::sprmCHpsInc1, { 0, L_VAR} }, // chp.hps complex
335  {NS_sprm::v6::sprmCHpsKern, { 2, L_FIX} }, // chp.hpsKern hps
336  {NS_sprm::v6::sprmCMajority50, { 0, L_VAR} }, // chp.fBold, chp.fItalic, ...
337  {NS_sprm::v6::sprmCHpsMul, { 2, L_FIX} }, // chp.hps percentage to grow hps
338  {NS_sprm::v6::sprmCCondHyhen, { 2, L_FIX} }, // chp.ysri ysri
339  {111, { 0, L_VAR} }, // sprmCFBoldBi or font code
340  {112, { 0, L_VAR} }, // sprmCFItalicBi or font code
341  {113, { 0, L_VAR} }, // ww7 rtl font
342  {114, { 0, L_VAR} }, // ww7 lid
343  {115, { 0, L_VAR} }, // ww7 CJK font
344  {116, { 0, L_VAR} }, // ww7 fontsize
345  {NS_sprm::v6::sprmCFSpec, { 1, L_FIX} }, // chp.fSpec 1 or 0 bit
346  {NS_sprm::v6::sprmCFObj, { 1, L_FIX} }, // chp.fObj 1 or 0 bit
347  {NS_sprm::v6::sprmPicBrcl, { 1, L_FIX} }, // pic.brcl brcl (see PIC definition)
348  {NS_sprm::v6::sprmPicScale, {12, L_VAR} }, // pic.mx, pic.my, pic.dxaCropleft,
349  {NS_sprm::v6::sprmPicBrcTop, { 2, L_FIX} }, // pic.brcTop BRC word
350  {NS_sprm::v6::sprmPicBrcLeft, { 2, L_FIX} }, // pic.brcLeft BRC word
351  {NS_sprm::v6::sprmPicBrcBottom, { 2, L_FIX} }, // pic.brcBottom BRC word
352  {NS_sprm::v6::sprmPicBrcRight, { 2, L_FIX} }, // pic.brcRight BRC word
353  {NS_sprm::v6::sprmSScnsPgn, { 1, L_FIX} }, // sep.cnsPgn cns byte
354  {NS_sprm::v6::sprmSiHeadingPgn, { 1, L_FIX} }, // sep.iHeadingPgn
355  {NS_sprm::v6::sprmSOlstAnm, { 0, L_VAR} }, // sep.olstAnm OLST variable length
356  {NS_sprm::v6::sprmSDxaColWidth, { 3, L_FIX} }, // sep.rgdxaColWidthSpacing complex
357  {NS_sprm::v6::sprmSDxaColSpacing, { 3, L_FIX} }, // sep.rgdxaColWidthSpacing
358  {NS_sprm::v6::sprmSFEvenlySpaced, { 1, L_FIX} }, // sep.fEvenlySpaced 1 or 0
359  {NS_sprm::v6::sprmSFProtected, { 1, L_FIX} }, // sep.fUnlocked 1 or 0 byte
360  {NS_sprm::v6::sprmSDmBinFirst, { 2, L_FIX} }, // sep.dmBinFirst word
361  {NS_sprm::v6::sprmSDmBinOther, { 2, L_FIX} }, // sep.dmBinOther word
362  {NS_sprm::v6::sprmSBkc, { 1, L_FIX} }, // sep.bkc bkc byte
363  {NS_sprm::v6::sprmSFTitlePage, { 1, L_FIX} }, // sep.fTitlePage 0 or 1 byte
364  {NS_sprm::v6::sprmSCcolumns, { 2, L_FIX} }, // sep.ccolM1 # of cols - 1 word
365  {NS_sprm::v6::sprmSDxaColumns, { 2, L_FIX} }, // sep.dxaColumns dxa word
366  {NS_sprm::v6::sprmSFAutoPgn, { 1, L_FIX} }, // sep.fAutoPgn obsolete byte
367  {NS_sprm::v6::sprmSNfcPgn, { 1, L_FIX} }, // sep.nfcPgn nfc byte
368  {NS_sprm::v6::sprmSDyaPgn, { 2, L_FIX} }, // sep.dyaPgn dya short
369  {NS_sprm::v6::sprmSDxaPgn, { 2, L_FIX} }, // sep.dxaPgn dya short
370  {NS_sprm::v6::sprmSFPgnRestart, { 1, L_FIX} }, // sep.fPgnRestart 0 or 1 byte
371  {NS_sprm::v6::sprmSFEndnote, { 1, L_FIX} }, // sep.fEndnote 0 or 1 byte
372  {NS_sprm::v6::sprmSLnc, { 1, L_FIX} }, // sep.lnc lnc byte
373  {NS_sprm::v6::sprmSGprfIhdt, { 1, L_FIX} }, // sep.grpfIhdt grpfihdt
374  {NS_sprm::v6::sprmSNLnnMod, { 2, L_FIX} }, // sep.nLnnMod non-neg int. word
375  {NS_sprm::v6::sprmSDxaLnn, { 2, L_FIX} }, // sep.dxaLnn dxa word
376  {NS_sprm::v6::sprmSDyaHdrTop, { 2, L_FIX} }, // sep.dyaHdrTop dya word
377  {NS_sprm::v6::sprmSDyaHdrBottom, { 2, L_FIX} }, // sep.dyaHdrBottom dya word
378  {NS_sprm::v6::sprmSLBetween, { 1, L_FIX} }, // sep.fLBetween 0 or 1 byte
379  {NS_sprm::v6::sprmSVjc, { 1, L_FIX} }, // sep.vjc vjc byte
380  {NS_sprm::v6::sprmSLnnMin, { 2, L_FIX} }, // sep.lnnMin lnn word
381  {NS_sprm::v6::sprmSPgnStart, { 2, L_FIX} }, // sep.pgnStart pgn word
382  {NS_sprm::v6::sprmSBOrientation, { 1, L_FIX} }, // sep.dmOrientPage dm byte
384  {NS_sprm::v6::sprmSXaPage, { 2, L_FIX} }, // sep.xaPage xa word
385  {NS_sprm::v6::sprmSYaPage, { 2, L_FIX} }, // sep.yaPage ya word
386  {NS_sprm::v6::sprmSDxaLeft, { 2, L_FIX} }, // sep.dxaLeft dxa word
387  {NS_sprm::v6::sprmSDxaRight, { 2, L_FIX} }, // sep.dxaRight dxa word
388  {NS_sprm::v6::sprmSDyaTop, { 2, L_FIX} }, // sep.dyaTop dya word
389  {NS_sprm::v6::sprmSDyaBottom, { 2, L_FIX} }, // sep.dyaBottom dya word
390  {NS_sprm::v6::sprmSDzaGutter, { 2, L_FIX} }, // sep.dzaGutter dza word
391  {NS_sprm::v6::sprmSDMPaperReq, { 2, L_FIX} }, // sep.dmPaperReq dm word
392  {179, { 0, L_VAR} }, // rtl property ?
393  {181, { 0, L_VAR} }, // rtl property ?
394  {NS_sprm::v6::sprmTJc, { 2, L_FIX} }, // tap.jc jc (low order byte is significant)
395  {NS_sprm::v6::sprmTDxaLeft, { 2, L_FIX} }, // tap.rgdxaCenter dxa word
396  {NS_sprm::v6::sprmTDxaGapHalf, { 2, L_FIX} }, // tap.dxaGapHalf, tap.rgdxaCenter
397  {NS_sprm::v6::sprmTFCantSplit, { 1, L_FIX} }, // tap.fCantSplit 1 or 0 byte
398  {NS_sprm::v6::sprmTTableHeader, { 1, L_FIX} }, // tap.fTableHeader 1 or 0 byte
399  {NS_sprm::v6::sprmTTableBorders, {12, L_FIX} }, // tap.rgbrcTable complex 12 bytes
400  {NS_sprm::v6::sprmTDefTable10, { 0, L_VAR} }, // tap.rgdxaCenter, tap.rgtc complex
401  {NS_sprm::v6::sprmTDyaRowHeight, { 2, L_FIX} }, // tap.dyaRowHeight dya word
402  {NS_sprm::v6::sprmTDefTable, { 0, L_VAR2} }, // tap.rgtc complex
403  {NS_sprm::v6::sprmTDefTableShd, { 1, L_VAR} }, // tap.rgshd complex
404  {NS_sprm::v6::sprmTTlp, { 4, L_FIX} }, // tap.tlp TLP 4 bytes
405  {NS_sprm::v6::sprmTSetBrc, { 5, L_FIX} }, // tap.rgtc[].rgbrc complex 5 bytes
406  {NS_sprm::v6::sprmTInsert, { 4, L_FIX} }, // tap.rgdxaCenter,tap.rgtc complex
407  {NS_sprm::v6::sprmTDelete, { 2, L_FIX} }, // tap.rgdxaCenter, tap.rgtc complex
408  {NS_sprm::v6::sprmTDxaCol, { 4, L_FIX} }, // tap.rgdxaCenter complex
409  {NS_sprm::v6::sprmTMerge, { 2, L_FIX} }, // tap.fFirstMerged, tap.fMerged complex
410  {NS_sprm::v6::sprmTSplit, { 2, L_FIX} }, // tap.fFirstMerged, tap.fMerged complex
411  {NS_sprm::v6::sprmTSetBrc10, { 5, L_FIX} }, // tap.rgtc[].rgbrc complex 5 bytes
412  {NS_sprm::v6::sprmTSetShd, { 4, L_FIX} }, // tap.rgshd complex 4 bytes
413  {207, { 0, L_VAR} } // rtl property ?
414  };
415 
416  if (rFib.m_wIdent >= 0xa697 && rFib.m_wIdent <= 0xa699)
417  {
418  //see Read_AmbiguousSPRM for this oddity
419  static wwSprmSearcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms), true);
420  return &aSprmSrch;
421  }
422 
423  static wwSprmSearcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
424  return &aSprmSrch;
425 };
426 
428 {
429  for (sal_uInt16 nId = 111; nId <= 113; ++nId)
430  {
431  SprmInfo& amb1 = map_[nId];
432  amb1.nLen = 2;
433  amb1.nVari = wwSprmParser::L_FIX;
434  }
435 }
436 
437 template <class Sprm> static constexpr SprmInfoRow InfoRow()
438 {
439  return { Sprm::val, { Sprm::len, Sprm::varlen ? wwSprmParser::L_VAR : wwSprmParser::L_FIX } };
440 }
441 
443 {
444  //double lock me
445  //WW8+ Sprms
446  static const SprmInfoRow aSprms[] =
447  {
448  { 0, { 0, L_FIX} }, // "Default-sprm"/ is skipped
449  InfoRow<NS_sprm::PIstd>(), // pap.istd;istd (style code);short;
450  InfoRow<NS_sprm::PIstdPermute>(), // pap.istd;permutation vector
451  InfoRow<NS_sprm::PIncLvl>(), // pap.istd, pap.lvl;difference
452  // between istd of base PAP and istd of PAP to be
453  // produced
454  InfoRow<NS_sprm::PJc80>(), // pap.jc;jc (justification);byte;
455  {NS_sprm::LN_PFSideBySide, { 1, L_FIX} }, // "sprmPFSideBySide" pap.fSideBySide;0 or 1;byte;
456  InfoRow<NS_sprm::PFKeep>(), // pap.fKeep;0 or 1;byte;
457  InfoRow<NS_sprm::PFKeepFollow>(), // pap.fKeepFollow;0 or 1;byte;
458  InfoRow<NS_sprm::PFPageBreakBefore>(), // pap.fPageBreakBefore;
459  // 0 or 1
460  {NS_sprm::LN_PBrcl, { 1, L_FIX} }, // "sprmPBrcl" pap.brcl;brcl;byte;
461  {NS_sprm::LN_PBrcp, { 1, L_FIX} }, // "sprmPBrcp" pap.brcp;brcp;byte;
462  InfoRow<NS_sprm::PIlvl>(), // pap.ilvl;ilvl;byte;
463  InfoRow<NS_sprm::PIlfo>(), // pap.ilfo;ilfo (list index) ;short;
464  InfoRow<NS_sprm::PFNoLineNumb>(), // pap.fNoLnn;0 or 1;byte;
465  InfoRow<NS_sprm::PChgTabsPapx>(), // pap.itbdMac, pap.rgdxaTab,
466  // pap.rgtbd;complex
467  InfoRow<NS_sprm::PDxaRight80>(), // pap.dxaRight;dxa;word;
468  InfoRow<NS_sprm::PDxaLeft80>(), // pap.dxaLeft;dxa;word;
469  InfoRow<NS_sprm::PNest80>(), // pap.dxaLeft;dxa
470  InfoRow<NS_sprm::PDxaLeft180>(), // pap.dxaLeft1;dxa;word;
471  InfoRow<NS_sprm::PDyaLine>(), // pap.lspd;an LSPD, a long word
472  // structure consisting of a short of dyaLine
473  // followed by a short of fMultLinespace
474  InfoRow<NS_sprm::PDyaBefore>(), // pap.dyaBefore;dya;word;
475  InfoRow<NS_sprm::PDyaAfter>(), // pap.dyaAfter;dya;word;
476  InfoRow<NS_sprm::PChgTabs>(), // pap.itbdMac, pap.rgdxaTab,
477  // pap.rgtbd;complex
478  InfoRow<NS_sprm::PFInTable>(), // pap.fInTable;0 or 1;byte;
479  InfoRow<NS_sprm::PFTtp>(), // pap.fTtp;0 or 1;byte;
480  InfoRow<NS_sprm::PDxaAbs>(), // pap.dxaAbs;dxa;word;
481  InfoRow<NS_sprm::PDyaAbs>(), // pap.dyaAbs;dya;word;
482  InfoRow<NS_sprm::PDxaWidth>(), // pap.dxaWidth;dxa;word;
483  InfoRow<NS_sprm::PPc>(), // pap.pcHorz, pap.pcVert;complex
484  {NS_sprm::LN_PBrcTop10, { 2, L_FIX} }, // "sprmPBrcTop10" pap.brcTop;BRC10;word;
485  {NS_sprm::LN_PBrcLeft10, { 2, L_FIX} }, // "sprmPBrcLeft10" pap.brcLeft;BRC10;word;
486  {NS_sprm::LN_PBrcBottom10, { 2, L_FIX} }, // "sprmPBrcBottom10" pap.brcBottom;BRC10;word;
487  {NS_sprm::LN_PBrcRight10, { 2, L_FIX} }, // "sprmPBrcRight10" pap.brcRight;BRC10;word;
488  {NS_sprm::LN_PBrcBetween10, { 2, L_FIX} }, // "sprmPBrcBetween10" pap.brcBetween;BRC10;word;
489  {NS_sprm::LN_PBrcBar10, { 2, L_FIX} }, // "sprmPBrcBar10" pap.brcBar;BRC10;word;
490  {NS_sprm::LN_PDxaFromText10, { 2, L_FIX} }, // "sprmPDxaFromText10" pap.dxaFromText;dxa;word;
491  InfoRow<NS_sprm::PWr>(), // pap.wr;wr
492  InfoRow<NS_sprm::PBrcTop80>(), // pap.brcTop;BRC;long;
493  InfoRow<NS_sprm::PBrcLeft80>(), // pap.brcLeft;BRC;long;
494  InfoRow<NS_sprm::PBrcBottom80>(), // pap.brcBottom;BRC;long;
495  InfoRow<NS_sprm::PBrcRight80>(), // pap.brcRight;BRC;long;
496  InfoRow<NS_sprm::PBrcBetween80>(), // pap.brcBetween;BRC;long;
497  InfoRow<NS_sprm::PBrcBar80>(), // pap.brcBar;BRC;long;
498  InfoRow<NS_sprm::PFNoAutoHyph>(), // pap.fNoAutoHyph;0 or 1;byte;
499  InfoRow<NS_sprm::PWHeightAbs>(), // pap.wHeightAbs;w;word;
500  InfoRow<NS_sprm::PDcs>(), // pap.dcs;DCS;short;
501  InfoRow<NS_sprm::PShd80>(), // pap.shd;SHD;word;
502  InfoRow<NS_sprm::PDyaFromText>(), // pap.dyaFromText;dya;word;
503  InfoRow<NS_sprm::PDxaFromText>(), // pap.dxaFromText;dxa;word;
504  InfoRow<NS_sprm::PFLocked>(), // pap.fLocked;0 or 1;byte;
505  InfoRow<NS_sprm::PFWidowControl>(), // pap.fWidowControl;0 or 1
506  {NS_sprm::LN_PRuler, { 0, L_VAR} }, // "sprmPRuler" ;;variable length;
507  InfoRow<NS_sprm::PFKinsoku>(), // pap.fKinsoku;0 or 1;byte;
508  InfoRow<NS_sprm::PFWordWrap>(), // pap.fWordWrap;0 or 1;byte;
509  InfoRow<NS_sprm::PFOverflowPunct>(), // pap.fOverflowPunct;0 or 1
510  InfoRow<NS_sprm::PFTopLinePunct>(), // pap.fTopLinePunct;0 or 1
511  InfoRow<NS_sprm::PFAutoSpaceDE>(), // pap.fAutoSpaceDE;0 or 1
512  InfoRow<NS_sprm::PFAutoSpaceDN>(), // pap.fAutoSpaceDN;0 or 1
513  InfoRow<NS_sprm::PWAlignFont>(), // pap.wAlignFont;iFa
514  InfoRow<NS_sprm::PFrameTextFlow>(), // pap.fVertical pap.fBackward
515  // pap.fRotateFont;complex
516  {NS_sprm::LN_PISnapBaseLine, { 1, L_FIX} }, // "sprmPISnapBaseLine" obsolete: not applicable in
517  // Word97 and later versions;
518  {NS_sprm::LN_PAnld, { 0, L_VAR} }, // "sprmPAnld" pap.anld;;variable length;
519  {NS_sprm::LN_PPropRMark, { 0, L_VAR} }, // "sprmPPropRMark" pap.fPropRMark;complex
520  InfoRow<NS_sprm::POutLvl>(), // pap.lvl;has no effect if pap.istd
521  // is < 1 or is > 9
522  InfoRow<NS_sprm::PFBiDi>(), // ;;byte;
523  InfoRow<NS_sprm::PFNumRMIns>(), // pap.fNumRMIns;1 or 0;bit;
524  {NS_sprm::LN_PCrLf, { 1, L_FIX} }, // "sprmPCrLf" ;;byte;
525  InfoRow<NS_sprm::PNumRM>(), // pap.numrm;;variable length;
526  {NS_sprm::LN_PHugePapx, { 4, L_FIX} }, // "sprmPHugePapx" fc in the data stream to locate
527  // the huge grpprl
528  InfoRow<NS_sprm::PHugePapx>(), // fc in the data stream to locate
529  // the huge grpprl
530  InfoRow<NS_sprm::PFUsePgsuSettings>(), // pap.fUsePgsuSettings;
531  // 1 or 0
532  InfoRow<NS_sprm::PFAdjustRight>(), // pap.fAdjustRight;1 or 0;byte;
533  InfoRow<NS_sprm::CFRMarkDel>(), // chp.fRMarkDel;1 or 0;bit;
534  InfoRow<NS_sprm::CFRMarkIns>(), // chp.fRMark;1 or 0;bit;
535  InfoRow<NS_sprm::CFFldVanish>(), // chp.fFieldVanish;1 or 0;bit;
536  InfoRow<NS_sprm::CPicLocation>(), // chp.fcPic and chp.fSpec;
537  InfoRow<NS_sprm::CIbstRMark>(), // chp.ibstRMark;index into
538  // sttbRMark
539  InfoRow<NS_sprm::CDttmRMark>(), // chp.dttmRMark;DTTM;long;
540  InfoRow<NS_sprm::CFData>(), // chp.fData;1 or 0;bit;
541  InfoRow<NS_sprm::CIdslRMark>(), // chp.idslRMReason;an index to a
542  // table of strings defined in Word 6.0
543  // executables;short;
544  {NS_sprm::LN_CChs, { 1, L_FIX} }, // "sprmCChs" chp.fChsDiff and chp.chse;
545  InfoRow<NS_sprm::CSymbol>(), // chp.fSpec, chp.xchSym and
546  // chp.ftcSym
547  InfoRow<NS_sprm::CFOle2>(), // chp.fOle2;1 or 0;bit;
548  {NS_sprm::LN_CIdCharType, { 0, L_FIX} }, // "sprmCIdCharType" obsolete: not applicable in
549  // Word97 and later versions;
550  InfoRow<NS_sprm::CHighlight>(), // chp.fHighlight,
551  // chp.icoHighlight;ico (fHighlight is set to 1 iff
552  // ico is not 0)
553  {NS_sprm::LN_CObjLocation, { 4, L_FIX} }, // "sprmCObjLocation" chp.fcObj;FC;long;
554  {NS_sprm::LN_CFFtcAsciSymb, { 0, L_FIX} }, // "sprmCFFtcAsciSymb" ;;;
555  InfoRow<NS_sprm::CIstd>(), // chp.istd;istd, see stylesheet def
556  InfoRow<NS_sprm::CIstdPermute>(), // chp.istd;permutation vector
557  {NS_sprm::LN_CDefault, { 0, L_VAR} }, // "sprmCDefault" whole CHP;none;variable length;
558  InfoRow<NS_sprm::CPlain>(), // whole CHP;none;0;
559  InfoRow<NS_sprm::CKcd>(), // ;;;
560  InfoRow<NS_sprm::CFBold>(), // chp.fBold;0,1, 128, or 129
561  InfoRow<NS_sprm::CFItalic>(), // chp.fItalic;0,1, 128, or 129
562  InfoRow<NS_sprm::CFStrike>(), // chp.fStrike;0,1, 128, or 129
563  InfoRow<NS_sprm::CFOutline>(), // chp.fOutline;0,1, 128, or 129
564  InfoRow<NS_sprm::CFShadow>(), // chp.fShadow;0,1, 128, or 129
565  InfoRow<NS_sprm::CFSmallCaps>(), // chp.fSmallCaps;0,1, 128, or 129
566  InfoRow<NS_sprm::CFCaps>(), // chp.fCaps;0,1, 128, or 129
567  InfoRow<NS_sprm::CFVanish>(), // chp.fVanish;0,1, 128, or 129
568  {NS_sprm::LN_CFtcDefault, { 2, L_FIX} }, // "sprmCFtcDefault" ;ftc, only used internally
569  InfoRow<NS_sprm::CKul>(), // chp.kul;kul;byte;
570  {NS_sprm::LN_CSizePos, { 3, L_FIX} }, // "sprmCSizePos" chp.hps, chp.hpsPos;3 bytes;
571  InfoRow<NS_sprm::CDxaSpace>(), // chp.dxaSpace;dxa;word;
572  {NS_sprm::LN_CLid, { 2, L_FIX} }, // "sprmCLid" ;only used internally never stored
573  InfoRow<NS_sprm::CIco>(), // chp.ico;ico;byte;
574  InfoRow<NS_sprm::CHps>(), // chp.hps;hps
575  {NS_sprm::LN_CHpsInc, { 1, L_FIX} }, // "sprmCHpsInc" chp.hps;
576  InfoRow<NS_sprm::CHpsPos>(), // chp.hpsPos;hps;short; (doc wrong)
577  {NS_sprm::LN_CHpsPosAdj, { 1, L_FIX} }, // "sprmCHpsPosAdj" chp.hpsPos;hps
578  InfoRow<NS_sprm::CMajority>(), // chp.fBold, chp.fItalic,
579  // chp.fSmallCaps, chp.fVanish, chp.fStrike,
580  // chp.fCaps, chp.rgftc, chp.hps, chp.hpsPos,
581  // chp.kul, chp.dxaSpace, chp.ico,
582  // chp.rglid;complex;variable length, length byte
583  // plus size of following grpprl;
584  InfoRow<NS_sprm::CIss>(), // chp.iss;iss;byte;
585  {NS_sprm::LN_CHpsNew50, { 0, L_VAR} }, // "sprmCHpsNew50" chp.hps;hps;variable width
586  {NS_sprm::LN_CHpsInc1, { 0, L_VAR} }, // "sprmCHpsInc1" chp.hps;complex
587  InfoRow<NS_sprm::CHpsKern>(), // chp.hpsKern;hps;short;
588  {NS_sprm::LN_CMajority50, { 2, L_FIX} }, // "sprmCMajority50" chp.fBold, chp.fItalic,
589  // chp.fSmallCaps, chp.fVanish, chp.fStrike,
590  // chp.fCaps, chp.ftc, chp.hps, chp.hpsPos, chp.kul,
591  // chp.dxaSpace, chp.ico,;complex
592  {NS_sprm::LN_CHpsMul, { 2, L_FIX} }, // "sprmCHpsMul" chp.hps;percentage to grow hps
593  InfoRow<NS_sprm::CHresi>(), // chp.ysri;ysri;short;
594  InfoRow<NS_sprm::CRgFtc0>(), // chp.rgftc[0];ftc for ASCII text
595  InfoRow<NS_sprm::CRgFtc1>(), // chp.rgftc[1];ftc for Far East text
596  InfoRow<NS_sprm::CRgFtc2>(), // chp.rgftc[2];ftc for non-FE text
597  InfoRow<NS_sprm::CCharScale>(),
598  InfoRow<NS_sprm::CFDStrike>(), // chp.fDStrike;;byte;
599  InfoRow<NS_sprm::CFImprint>(), // chp.fImprint;1 or 0;bit;
600  InfoRow<NS_sprm::CFSpec>(), // chp.fSpec ;1 or 0;bit;
601  InfoRow<NS_sprm::CFObj>(), // chp.fObj;1 or 0;bit;
602  InfoRow<NS_sprm::CPropRMark90>(), // chp.fPropRMark,
603  // chp.ibstPropRMark, chp.dttmPropRMark;Complex
604  InfoRow<NS_sprm::CFEmboss>(), // chp.fEmboss;1 or 0;bit;
605  InfoRow<NS_sprm::CSfxText>(), // chp.sfxtText;text animation;byte;
606  InfoRow<NS_sprm::CFBiDi>(), // ;;;
607  {NS_sprm::LN_CFDiacColor, { 1, L_FIX} }, // "sprmCFDiacColor" ;;;
608  InfoRow<NS_sprm::CFBoldBi>(), // ;;;
609  InfoRow<NS_sprm::CFItalicBi>(), // ;;;
610  InfoRow<NS_sprm::CFtcBi>(),
611  InfoRow<NS_sprm::CLidBi>(), // ;;;
612  InfoRow<NS_sprm::CIcoBi>(), // ;;;
613  InfoRow<NS_sprm::CHpsBi>(), // ;;;
614  InfoRow<NS_sprm::CDispFldRMark>(), // chp.fDispFieldRMark,
615  // chp.ibstDispFieldRMark, chp.dttmDispFieldRMark ;
616  InfoRow<NS_sprm::CIbstRMarkDel>(), // chp.ibstRMarkDel;index into
617  // sttbRMark;short;
618  InfoRow<NS_sprm::CDttmRMarkDel>(), // chp.dttmRMarkDel;DTTM;long;
619  InfoRow<NS_sprm::CBrc80>(), // chp.brc;BRC;long;
620  InfoRow<NS_sprm::CShd80>(), // chp.shd;SHD;short;
621  InfoRow<NS_sprm::CIdslRMarkDel>(), // chp.idslRMReasonDel;an index
622  // to a table of strings defined in Word 6.0
623  // executables;short;
624  InfoRow<NS_sprm::CFUsePgsuSettings>(),
625  // chp.fUsePgsuSettings;1 or 0
626  {NS_sprm::LN_CCpg, { 2, L_FIX} }, // "sprmCCpg" ;;word;
627  InfoRow<NS_sprm::CRgLid0_80>(), // chp.rglid[0];LID: for non-FE text
628  InfoRow<NS_sprm::CRgLid1_80>(), // chp.rglid[1];LID: for Far East text
629  InfoRow<NS_sprm::CIdctHint>(), // chp.idctHint;IDCT:
630  {NS_sprm::LN_PicBrcl, { 1, L_FIX} }, // "sprmPicBrcl" pic.brcl;brcl (see PIC definition)
631  {NS_sprm::LN_PicScale, { 0, L_VAR} }, // "sprmPicScale" pic.mx, pic.my, pic.dxaCropleft,
632  // pic.dyaCropTop pic.dxaCropRight,
633  // pic.dyaCropBottom;Complex
634  InfoRow<NS_sprm::PicBrcTop80>(), // pic.brcTop;BRC;long;
635  InfoRow<NS_sprm::PicBrcLeft80>(), // pic.brcLeft;BRC;long;
636  InfoRow<NS_sprm::PicBrcBottom80>(), // pic.brcBottom;BRC;long;
637  InfoRow<NS_sprm::PicBrcRight80>(), // pic.brcRight;BRC;long;
638  InfoRow<NS_sprm::ScnsPgn>(), // sep.cnsPgn;cns;byte;
639  InfoRow<NS_sprm::SiHeadingPgn>(), // sep.iHeadingPgn;heading number
640  // level;byte;
641  {NS_sprm::LN_SOlstAnm, { 0, L_VAR} }, // "sprmSOlstAnm" sep.olstAnm;OLST;variable length;
642  InfoRow<NS_sprm::SDxaColWidth>(), // sep.rgdxaColWidthSpacing;
643  InfoRow<NS_sprm::SDxaColSpacing>(), // sep.rgdxaColWidthSpacing;
644  // complex
645  InfoRow<NS_sprm::SFEvenlySpaced>(), // sep.fEvenlySpaced;1 or 0
646  InfoRow<NS_sprm::SFProtected>(), // sep.fUnlocked;1 or 0;byte;
647  InfoRow<NS_sprm::SDmBinFirst>(), // sep.dmBinFirst;;word;
648  InfoRow<NS_sprm::SDmBinOther>(), // sep.dmBinOther;;word;
649  InfoRow<NS_sprm::SBkc>(), // sep.bkc;bkc;byte;
650  InfoRow<NS_sprm::SFTitlePage>(), // sep.fTitlePage;0 or 1;byte;
651  InfoRow<NS_sprm::SCcolumns>(), // sep.ccolM1;# of cols - 1;word;
652  InfoRow<NS_sprm::SDxaColumns>(), // sep.dxaColumns;dxa;word;
653  {NS_sprm::LN_SFAutoPgn, { 1, L_FIX} }, // "sprmSFAutoPgn" sep.fAutoPgn;obsolete;byte;
654  InfoRow<NS_sprm::SNfcPgn>(), // sep.nfcPgn;nfc;byte;
655  {NS_sprm::LN_SDyaPgn, { 2, L_FIX} }, // "sprmSDyaPgn" sep.dyaPgn;dya;short;
656  {NS_sprm::LN_SDxaPgn, { 2, L_FIX} }, // "sprmSDxaPgn" sep.dxaPgn;dya;short;
657  InfoRow<NS_sprm::SFPgnRestart>(), // sep.fPgnRestart;0 or 1;byte;
658  InfoRow<NS_sprm::SFEndnote>(), // sep.fEndnote;0 or 1;byte;
659  InfoRow<NS_sprm::SLnc>(), // sep.lnc;lnc;byte;
660  {NS_sprm::LN_SGprfIhdt, { 1, L_FIX} }, // "sprmSGprfIhdt" sep.grpfIhdt;grpfihdt
661  InfoRow<NS_sprm::SNLnnMod>(), // sep.nLnnMod;non-neg int.;word;
662  InfoRow<NS_sprm::SDxaLnn>(), // sep.dxaLnn;dxa;word;
663  InfoRow<NS_sprm::SDyaHdrTop>(), // sep.dyaHdrTop;dya;word;
664  InfoRow<NS_sprm::SDyaHdrBottom>(), // sep.dyaHdrBottom;dya;word;
665  InfoRow<NS_sprm::SLBetween>(), // sep.fLBetween;0 or 1;byte;
666  InfoRow<NS_sprm::SVjc>(), // sep.vjc;vjc;byte;
667  InfoRow<NS_sprm::SLnnMin>(), // sep.lnnMin;lnn;word;
668  InfoRow<NS_sprm::SPgnStart97>(), // sep.pgnStart;pgn;word;
669  InfoRow<NS_sprm::SBOrientation>(), // sep.dmOrientPage;dm;byte;
670  {NS_sprm::LN_SBCustomize, { 1, L_FIX} }, // "sprmSBCustomize" ;;;
671  InfoRow<NS_sprm::SXaPage>(), // sep.xaPage;xa;word;
672  InfoRow<NS_sprm::SYaPage>(), // sep.yaPage;ya;word;
673  InfoRow<NS_sprm::SDxaLeft>(), // sep.dxaLeft;dxa;word;
674  InfoRow<NS_sprm::SDxaRight>(), // sep.dxaRight;dxa;word;
675  InfoRow<NS_sprm::SDyaTop>(), // sep.dyaTop;dya;word;
676  InfoRow<NS_sprm::SDyaBottom>(), // sep.dyaBottom;dya;word;
677  InfoRow<NS_sprm::SDzaGutter>(), // sep.dzaGutter;dza;word;
678  InfoRow<NS_sprm::SDmPaperReq>(), // sep.dmPaperReq;dm;word;
679  {NS_sprm::LN_SPropRMark, { 0, L_VAR} }, // "sprmSPropRMark" sep.fPropRMark,
680  // sep.ibstPropRMark, sep.dttmPropRMark ;complex
681  InfoRow<NS_sprm::SFBiDi>(), // ;;;
682  {NS_sprm::LN_SFFacingCol, { 1, L_FIX} }, // "sprmSFFacingCol" ;;;
683  InfoRow<NS_sprm::SFRTLGutter>(), //, set to one if gutter is on
684  // right
685  InfoRow<NS_sprm::SBrcTop80>(), // sep.brcTop;BRC;long;
686  InfoRow<NS_sprm::SBrcLeft80>(), // sep.brcLeft;BRC;long;
687  InfoRow<NS_sprm::SBrcBottom80>(), // sep.brcBottom;BRC;long;
688  InfoRow<NS_sprm::SBrcRight80>(), // sep.brcRight;BRC;long;
689  InfoRow<NS_sprm::SPgbProp>(), // sep.pgbProp;;word;
690  InfoRow<NS_sprm::SDxtCharSpace>(), // sep.dxtCharSpace;dxt;long;
691  InfoRow<NS_sprm::SDyaLinePitch>(),
692  // sep.dyaLinePitch;dya; WRONG:long; RIGHT:short; !
693  InfoRow<NS_sprm::SClm>(), // ;;;
694  InfoRow<NS_sprm::STextFlow>(), // sep.wTextFlow;complex
695  InfoRow<NS_sprm::TJc90>(), // tap.jc;jc;word (low order byte is
696  // significant);
697  InfoRow<NS_sprm::TDxaLeft>(), // tap.rgdxaCenter
698  InfoRow<NS_sprm::TDxaGapHalf>(), // tap.dxaGapHalf,
699  // tap.rgdxaCenter
700  InfoRow<NS_sprm::TFCantSplit90>(), // tap.fCantSplit90;1 or 0;byte;
701  InfoRow<NS_sprm::TTableHeader>(), // tap.fTableHeader;1 or 0;byte;
702  InfoRow<NS_sprm::TFCantSplit>(), // tap.fCantSplit;1 or 0;byte;
703  InfoRow<NS_sprm::TTableBorders80>(), // tap.rgbrcTable;complex
704  {NS_sprm::LN_TDefTable10, { 0, L_VAR} }, // "sprmTDefTable10" tap.rgdxaCenter,
705  // tap.rgtc;complex
706  InfoRow<NS_sprm::TDyaRowHeight>(), // tap.dyaRowHeight;dya;word;
707  InfoRow<NS_sprm::TDefTable>(), // tap.rgtc;complex
708  InfoRow<NS_sprm::TDefTableShd80>(), // tap.rgshd;complex
709  InfoRow<NS_sprm::TTlp>(), // tap.tlp;TLP;4 bytes;
710  InfoRow<NS_sprm::TFBiDi>(), // ;;;
711  {NS_sprm::LN_THTMLProps, { 1, L_FIX} }, // "sprmTHTMLProps" ;;;
712  InfoRow<NS_sprm::TSetBrc80>(), // tap.rgtc[].rgbrc;complex
713  InfoRow<NS_sprm::TInsert>(), // tap.rgdxaCenter, tap.rgtc;complex
714  InfoRow<NS_sprm::TDelete>(), // tap.rgdxaCenter, tap.rgtc;complex
715  InfoRow<NS_sprm::TDxaCol>(), // tap.rgdxaCenter;complex
716  InfoRow<NS_sprm::TMerge>(), // tap.fFirstMerged, tap.fMerged;
717  InfoRow<NS_sprm::TSplit>(), // tap.fFirstMerged, tap.fMerged;
718  {NS_sprm::LN_TSetBrc10, { 0, L_VAR} }, // "sprmTSetBrc10" tap.rgtc[].rgbrc;complex
719  {NS_sprm::LN_TSetShd80, { 0, L_VAR} }, // "sprmTSetShd80" tap.rgshd;complex
720  {NS_sprm::LN_TSetShdOdd80, { 0, L_VAR} }, // "sprmTSetShdOdd80" tap.rgshd;complex
721  InfoRow<NS_sprm::TTextFlow>(), // tap.rgtc[].fVerticaltap,
722  // rgtc[].fBackwardtap, rgtc[].fRotateFont;0 or 10
723  // or 10 or 1;word;
724  {NS_sprm::LN_TDiagLine, { 1, L_FIX} }, // "sprmTDiagLine" ;;;
725  InfoRow<NS_sprm::TVertMerge>(), // tap.rgtc[].vertMerge
726  InfoRow<NS_sprm::TVertAlign>(), // tap.rgtc[].vertAlign
727  InfoRow<NS_sprm::CFELayout>(),
728  InfoRow<NS_sprm::PItap>(), // undocumented
729  InfoRow<NS_sprm::TTableWidth>(), // undocumented
730  InfoRow<NS_sprm::TDefTableShd>(),
731  InfoRow<NS_sprm::TTableBorders>(),
732  InfoRow<NS_sprm::TBrcTopCv>(), // undocumented
733  InfoRow<NS_sprm::TBrcLeftCv>(), // undocumented
734  InfoRow<NS_sprm::TBrcBottomCv>(), // undocumented
735  InfoRow<NS_sprm::TBrcRightCv>(), // undocumented
736  InfoRow<NS_sprm::TCellPadding>(), // undocumented
737  InfoRow<NS_sprm::TCellPaddingDefault>(), // undocumented
738  {0xD238, { 0, L_VAR} }, // undocumented sep
739  InfoRow<NS_sprm::PBrcTop>(),
740  InfoRow<NS_sprm::PBrcLeft>(),
741  InfoRow<NS_sprm::PBrcBottom>(),
742  InfoRow<NS_sprm::PBrcRight>(),
743  InfoRow<NS_sprm::PBrcBetween>(),
744  InfoRow<NS_sprm::TWidthIndent>(), // undocumented
745  InfoRow<NS_sprm::CRgLid0>(), // chp.rglid[0];LID: for non-FE text
746  InfoRow<NS_sprm::CRgLid1>(), // chp.rglid[1];LID: for Far East text
747  {0x6463, { 4, L_FIX} }, // undocumented
748  InfoRow<NS_sprm::PJc>(), // undoc, must be asian version of "sprmPJc"
749  InfoRow<NS_sprm::PDxaRight>(), // undoc, must be asian version of "sprmPDxaRight"
750  InfoRow<NS_sprm::PDxaLeft>(), // undoc, must be asian version of "sprmPDxaLeft"
751  InfoRow<NS_sprm::PDxaLeft1>(), // undoc, must be asian version of "sprmPDxaLeft1"
752  InfoRow<NS_sprm::TFAutofit>(), // undocumented
753  InfoRow<NS_sprm::TPc>(), // undocumented
754  InfoRow<NS_sprm::SRsid>(), // undocumented, sep, perhaps related to textgrids ?
755  InfoRow<NS_sprm::SFpc>(), // undocumented, sep
756  InfoRow<NS_sprm::PFInnerTableCell>(), // undocumented, subtable "sprmPFInTable" equiv ?
757  InfoRow<NS_sprm::PFInnerTtp>(), // undocumented, subtable "sprmPFTtp" equiv ?
758  InfoRow<NS_sprm::TDxaAbs>(), // undocumented
759  InfoRow<NS_sprm::TDyaAbs>(), // undocumented
760  InfoRow<NS_sprm::TDxaFromText>(), // undocumented
761  InfoRow<NS_sprm::CRsidProp>(), // undocumented
762  InfoRow<NS_sprm::CRsidText>(), // undocumented
763  InfoRow<NS_sprm::CCv>(), // text colour
764  InfoRow<NS_sprm::PShd>(), // undocumented, para back colour
765  InfoRow<NS_sprm::PRsid>(), // undocumented
766  InfoRow<NS_sprm::PTableProps>(), // undocumented
767  InfoRow<NS_sprm::TWidthBefore>(), // undocumented
768  InfoRow<NS_sprm::TSetShdTable>(), // undocumented, something to do with colour.
769  InfoRow<NS_sprm::TDefTableShdRaw>(), // undocumented, something to do with colour.
770  InfoRow<NS_sprm::CShd>(), // text backcolour
771  InfoRow<NS_sprm::SRncFtn>(), // undocumented, sep
772  InfoRow<NS_sprm::PFDyaBeforeAuto>(), // undocumented, para autobefore
773  InfoRow<NS_sprm::PFDyaAfterAuto>(), // undocumented, para autoafter
774  // "sprmPFContextualSpacing", don't add space between para of the same style
775  InfoRow<NS_sprm::PFContextualSpacing>(),
776  };
777 
778  static wwSprmSearcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
779  return &aSprmSrch;
780 };
781 
783 {
784  OSL_ENSURE((meVersion >= ww::eWW1 && meVersion <= ww::eWW8),
785  "Impossible value for version");
786 
787  mnDelta = (ww::IsSevenMinus(meVersion)) ? 0 : 1;
788 
789  if (meVersion <= ww::eWW2)
791  else if (meVersion < ww::eWW8)
793  else
795 }
796 
797 SprmInfo wwSprmParser::GetSprmInfo(sal_uInt16 nId) const
798 {
799  const SprmInfo* pFound = mpKnownSprms->search(nId);
800  if (pFound != nullptr)
801  {
802  return *pFound;
803  }
804 
805  OSL_ENSURE(ww::IsEightPlus(meVersion),
806  "Unknown ww7- sprm, dangerous, report to development");
807 
808  //All the unknown ww7 sprms appear to be variable (which makes sense)
809  SprmInfo aSrch = { 0, L_VAR };
810  if (ww::IsEightPlus(meVersion)) //We can recover perfectly in this case
811  {
812  aSrch.nVari = L_FIX;
813  switch (nId >> 13)
814  {
815  case 0:
816  case 1:
817  aSrch.nLen = 1;
818  break;
819  case 2:
820  aSrch.nLen = 2;
821  break;
822  case 3:
823  aSrch.nLen = 4;
824  break;
825  case 4:
826  case 5:
827  aSrch.nLen = 2;
828  break;
829  case 6:
830  aSrch.nLen = 0;
831  aSrch.nVari = L_VAR;
832  break;
833  case 7:
834  default:
835  aSrch.nLen = 3;
836  break;
837  }
838  }
839  return aSrch;
840 }
841 
842 //-end
843 
845 {
846  sal_uInt8 n = *p;
847  p += 1;
848  return n;
849 }
850 
851 static sal_uInt16 Get_UShort( sal_uInt8 *& p )
852 {
853  const sal_uInt16 n = SVBT16ToUInt16( *reinterpret_cast<SVBT16*>(p) );
854  p += 2;
855  return n;
856 }
857 
858 static sal_Int16 Get_Short( sal_uInt8 *& p )
859 {
860  return Get_UShort(p);
861 }
862 
863 static sal_uInt32 Get_ULong( sal_uInt8 *& p )
864 {
865  sal_uInt32 n = SVBT32ToUInt32( *reinterpret_cast<SVBT32*>(p) );
866  p += 4;
867  return n;
868 }
869 
870 static sal_Int32 Get_Long( sal_uInt8 *& p )
871 {
872  return Get_ULong(p);
873 }
874 
875 WW8SprmIter::WW8SprmIter(const sal_uInt8* pSprms_, sal_Int32 nLen_,
876  const wwSprmParser &rParser)
877  : mrSprmParser(rParser), pSprms( pSprms_), nRemLen( nLen_)
878 {
879  UpdateMyMembers();
880 }
881 
882 void WW8SprmIter::SetSprms(const sal_uInt8* pSprms_, sal_Int32 nLen_)
883 {
884  pSprms = pSprms_;
885  nRemLen = nLen_;
886  UpdateMyMembers();
887 }
888 
890 {
891  if (nRemLen > 0 )
892  {
893  sal_uInt16 nSize = nCurrentSize;
894  if (nSize > nRemLen)
895  nSize = nRemLen;
896  pSprms += nSize;
897  nRemLen -= nSize;
898  UpdateMyMembers();
899  }
900 }
901 
903 {
904  bool bValid = (pSprms && nRemLen >= mrSprmParser.MinSprmLen());
905 
906  if (bValid)
907  {
911  bValid = nCurrentSize <= nRemLen;
912  SAL_WARN_IF(!bValid, "sw.ww8", "sprm longer than remaining bytes, doc or parser is wrong");
913  }
914 
915  if (!bValid)
916  {
917  nCurrentId = 0;
918  pCurrentParams = nullptr;
919  nCurrentSize = 0;
920  nRemLen = 0;
921  }
922 }
923 
924 SprmResult WW8SprmIter::FindSprm(sal_uInt16 nId, bool bFindFirst, const sal_uInt8* pNextByteMatch)
925 {
926  SprmResult aRet;
927 
928  while (GetSprms())
929  {
930  if (GetCurrentId() == nId)
931  {
932  sal_Int32 nFixedLen = mrSprmParser.DistanceToData(nId);
933  sal_Int32 nL = mrSprmParser.GetSprmSize(nId, GetSprms(), GetRemLen());
934  SprmResult aSprmResult(GetCurrentParams(), nL - nFixedLen);
935  // typically pNextByteMatch is nullptr and we just return the first match
936  // very occasionally we want one with a specific following byte
937  if ( !pNextByteMatch || (aSprmResult.nRemainingData >= 1 && *aSprmResult.pSprm == *pNextByteMatch) )
938  {
939  if ( bFindFirst )
940  return aSprmResult;
941  aRet = aSprmResult;
942  }
943  }
944  advance();
945  }
946 
947  return aRet;
948 }
949 
950 // temporary test
951 // WW8PLCFx_PCDAttrs cling to WW8PLCF_Pcd and therefore do not have their own iterators.
952 // All methods relating to iterators are therefore dummies.
954  WW8PLCFx_PCD* pPLCFx_PCD, const WW8ScannerBase* pBase)
955  : WW8PLCFx(rFib, true), pPcdI(pPLCFx_PCD->GetPLCFIter()),
956  pPcd(pPLCFx_PCD), mrGrpprls(pBase->m_aPieceGrpprls)
957 {
958 }
959 
960 sal_uInt32 WW8PLCFx_PCDAttrs::GetIdx() const
961 {
962  return 0;
963 }
964 
966 {
967 }
968 
970 {
971  return true;
972 }
973 
975 {
976 }
977 
979 {
980  return pPcd ? pPcd->Where() : WW8_CP_MAX;
981 }
982 
984 {
985  void* pData;
986 
987  p->bRealLineEnd = false;
988  if ( !pPcdI || !pPcdI->Get(p->nStartPos, p->nEndPos, pData) )
989  {
990  // PLCF fully processed
991  p->nStartPos = p->nEndPos = WW8_CP_MAX;
992  p->pMemPos = nullptr;
993  p->nSprmsLen = 0;
994  return;
995  }
996 
997  const sal_uInt16 nPrm = SVBT16ToUInt16( static_cast<WW8_PCD*>(pData)->prm );
998  if ( nPrm & 1 )
999  {
1000  // PRM Variant 2
1001  const sal_uInt16 nSprmIdx = nPrm >> 1;
1002 
1003  if( nSprmIdx >= mrGrpprls.size() )
1004  {
1005  // Invalid Index
1006  p->nStartPos = p->nEndPos = WW8_CP_MAX;
1007  p->pMemPos = nullptr;
1008  p->nSprmsLen = 0;
1009  return;
1010  }
1011  const sal_uInt8* pSprms = mrGrpprls[ nSprmIdx ].get();
1012 
1013  p->nSprmsLen = SVBT16ToUInt16( pSprms ); // Length
1014  pSprms += 2;
1015  p->pMemPos = pSprms; // Position
1016  }
1017  else
1018  {
1019  // SPRM is stored directly into members var
1020  /*
1021  These are the attr that are in the piece-table instead of in the text!
1022  */
1023 
1024  if (IsSevenMinus(GetFIBVersion()))
1025  {
1026  aShortSprm[0] = static_cast<sal_uInt8>( ( nPrm & 0xfe) >> 1 );
1027  aShortSprm[1] = static_cast<sal_uInt8>( nPrm >> 8 );
1028  p->nSprmsLen = nPrm ? 2 : 0; // length
1029 
1030  // store Position of internal mini storage in Data Pointer
1031  p->pMemPos = aShortSprm;
1032  }
1033  else
1034  {
1035  p->pMemPos = nullptr;
1036  p->nSprmsLen = 0;
1037  sal_uInt8 nSprmListIdx = static_cast<sal_uInt8>((nPrm & 0xfe) >> 1);
1038  if( nSprmListIdx )
1039  {
1040  // process Sprm Id Matching as explained in MS Documentation
1041 
1042  // ''Property Modifier(variant 1) (PRM)''
1043  // see file: s62f39.htm
1044 
1045  // Since Sprm is 7 bits, rgsprmPrm can hold 0x80 entries.
1046  static const sal_uInt16 aSprmId[0x80] =
1047  {
1048  // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1049  0x0000,0x0000,0x0000,0x0000,
1050  // sprmPIncLvl, sprmPJc, sprmPFSideBySide, sprmPFKeep
1051  0x2402,0x2403,NS_sprm::LN_PFSideBySide,0x2405,
1052  // sprmPFKeepFollow, sprmPFPageBreakBefore, sprmPBrcl,
1053  // sprmPBrcp
1054  0x2406,0x2407,NS_sprm::LN_PBrcl,NS_sprm::LN_PBrcp,
1055  // sprmPIlvl, sprmNoop, sprmPFNoLineNumb, sprmNoop
1056  0x260A,0x0000,0x240C,0x0000,
1057  // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1058  0x0000,0x0000,0x0000,0x0000,
1059  // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1060  0x0000,0x0000,0x0000,0x0000,
1061  // sprmPFInTable, sprmPFTtp, sprmNoop, sprmNoop
1062  0x2416,0x2417,0x0000,0x0000,
1063  // sprmNoop, sprmPPc, sprmNoop, sprmNoop
1064  0x0000,0x261B,0x0000,0x0000,
1065  // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1066  0x0000,0x0000,0x0000,0x0000,
1067  // sprmNoop, sprmPWr, sprmNoop, sprmNoop
1068  0x0000,0x2423,0x0000,0x0000,
1069  // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1070  0x0000,0x0000,0x0000,0x0000,
1071  // sprmPFNoAutoHyph, sprmNoop, sprmNoop, sprmNoop
1072  0x242A,0x0000,0x0000,0x0000,
1073  // sprmNoop, sprmNoop, sprmPFLocked, sprmPFWidowControl
1074  0x0000,0x0000,0x2430,0x2431,
1075  // sprmNoop, sprmPFKinsoku, sprmPFWordWrap,
1076  // sprmPFOverflowPunct
1077  0x0000,0x2433,0x2434,0x2435,
1078  // sprmPFTopLinePunct, sprmPFAutoSpaceDE,
1079  // sprmPFAutoSpaceDN, sprmNoop
1080  0x2436,0x2437,0x2438,0x0000,
1081  // sprmNoop, sprmPISnapBaseLine, sprmNoop, sprmNoop
1082  0x0000,NS_sprm::LN_PISnapBaseLine,0x000,0x0000,
1083  // sprmNoop, sprmCFStrikeRM, sprmCFRMark, sprmCFFieldVanish
1084  0x0000,0x0800,0x0801,0x0802,
1085  // sprmNoop, sprmNoop, sprmNoop, sprmCFData
1086  0x0000,0x0000,0x0000,0x0806,
1087  // sprmNoop, sprmNoop, sprmNoop, sprmCFOle2
1088  0x0000,0x0000,0x0000,0x080A,
1089  // sprmNoop, sprmCHighlight, sprmCFEmboss, sprmCSfxText
1090  0x0000,0x2A0C,0x0858,0x2859,
1091  // sprmNoop, sprmNoop, sprmNoop, sprmCPlain
1092  0x0000,0x0000,0x0000,0x2A33,
1093  // sprmNoop, sprmCFBold, sprmCFItalic, sprmCFStrike
1094  0x0000,0x0835,0x0836,0x0837,
1095  // sprmCFOutline, sprmCFShadow, sprmCFSmallCaps, sprmCFCaps,
1096  0x0838,0x0839,0x083a,0x083b,
1097  // sprmCFVanish, sprmNoop, sprmCKul, sprmNoop,
1098  0x083C,0x0000,0x2A3E,0x0000,
1099  // sprmNoop, sprmNoop, sprmCIco, sprmNoop,
1100  0x0000,0x0000,0x2A42,0x0000,
1101  // sprmCHpsInc, sprmNoop, sprmCHpsPosAdj, sprmNoop,
1103  // sprmCIss, sprmNoop, sprmNoop, sprmNoop,
1104  0x2A48,0x0000,0x0000,0x0000,
1105  // sprmNoop, sprmNoop, sprmNoop, sprmNoop,
1106  0x0000,0x0000,0x0000,0x0000,
1107  // sprmNoop, sprmNoop, sprmNoop, sprmCFDStrike,
1108  0x0000,0x0000,0x0000,0x2A53,
1109  // sprmCFImprint, sprmCFSpec, sprmCFObj, sprmPicBrcl,
1110  0x0854,0x0855,0x0856,NS_sprm::LN_PicBrcl,
1111  // sprmPOutLvl, sprmPFBiDi, sprmNoop, sprmNoop,
1112  0x2640,0x2441,0x0000,0x0000,
1113  // sprmNoop, sprmNoop, sprmPPnbrRMarkNot
1114  0x0000,0x0000,0x0000,0x0000
1115  };
1116 
1117  // find real Sprm Id:
1118  const sal_uInt16 nSprmId = aSprmId[ nSprmListIdx ];
1119 
1120  if( nSprmId )
1121  {
1122  // move Sprm Id and Sprm Param to internal mini storage:
1123  aShortSprm[0] = static_cast<sal_uInt8>( nSprmId & 0x00ff) ;
1124  aShortSprm[1] = static_cast<sal_uInt8>( ( nSprmId & 0xff00) >> 8 );
1125  aShortSprm[2] = static_cast<sal_uInt8>( nPrm >> 8 );
1126 
1127  // store Sprm Length in member:
1128  p->nSprmsLen = nPrm ? 3 : 0;
1129 
1130  // store Position of internal mini storage in Data Pointer
1131  p->pMemPos = aShortSprm;
1132  }
1133  }
1134  }
1135  }
1136 }
1137 
1139  WW8_CP nStartCp, bool bVer67P)
1140  : WW8PLCFx(rFib, false), nClipStart(-1)
1141 {
1142  // construct own iterator
1143  pPcdI.reset( new WW8PLCFpcd_Iter(*pPLCFpcd, nStartCp) );
1144  bVer67= bVer67P;
1145 }
1146 
1148 {
1149 }
1150 
1151 sal_uInt32 WW8PLCFx_PCD::GetIMax() const
1152 {
1153  return pPcdI ? pPcdI->GetIMax() : 0;
1154 }
1155 
1156 sal_uInt32 WW8PLCFx_PCD::GetIdx() const
1157 {
1158  return pPcdI ? pPcdI->GetIdx() : 0;
1159 }
1160 
1161 void WW8PLCFx_PCD::SetIdx(sal_uInt32 nIdx)
1162 {
1163  if (pPcdI)
1164  pPcdI->SetIdx( nIdx );
1165 }
1166 
1168 {
1169  return pPcdI && pPcdI->SeekPos( nCpPos );
1170 }
1171 
1173 {
1174  return pPcdI ? pPcdI->Where() : WW8_CP_MAX;
1175 }
1176 
1177 tools::Long WW8PLCFx_PCD::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
1178 {
1179  void* pData;
1180  rLen = 0;
1181 
1182  if ( !pPcdI || !pPcdI->Get(rStart, rEnd, pData) )
1183  {
1184  rStart = rEnd = WW8_CP_MAX;
1185  return -1;
1186  }
1187  return pPcdI->GetIdx();
1188 }
1189 
1191 {
1192  OSL_ENSURE(pPcdI , "missing pPcdI");
1193  if (pPcdI)
1194  pPcdI->advance();
1195 }
1196 
1198 {
1199  WW8_CP nCpStart, nCpEnd;
1200  void* pData;
1201 
1202  if ( !pPcdI->Get(nCpStart, nCpEnd, pData) )
1203  {
1204  OSL_ENSURE( false, "CurrentPieceStartCp2Fc() with false Cp found (1)" );
1205  return WW8_FC_MAX;
1206  }
1207 
1208  OSL_ENSURE( nCp >= nCpStart && nCp < nCpEnd,
1209  "AktPieceCp2Fc() with false Cp found (2)" );
1210 
1211  if( nCp < nCpStart )
1212  nCp = nCpStart;
1213  if( nCp >= nCpEnd )
1214  nCp = nCpEnd - 1;
1215 
1216  bool bIsUnicode = false;
1217  WW8_FC nFC = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
1218  if( !bVer67 )
1219  nFC = WW8PLCFx_PCD::TransformPieceAddress( nFC, bIsUnicode );
1220 
1221  WW8_CP nDistance;
1222  bool bFail = o3tl::checked_sub(nCp, nCpStart, nDistance);
1223  if (bFail)
1224  {
1225  SAL_WARN("sw.ww8", "broken offset, ignoring");
1226  return WW8_FC_MAX;
1227  }
1228 
1229  if (bIsUnicode)
1230  {
1231  bFail = o3tl::checked_multiply<WW8_CP>(nDistance, 2, nDistance);
1232  if (bFail)
1233  {
1234  SAL_WARN("sw.ww8", "broken offset, ignoring");
1235  return WW8_FC_MAX;
1236  }
1237  }
1238 
1239  WW8_FC nRet;
1240  bFail = o3tl::checked_add(nFC, nDistance, nRet);
1241  if (bFail)
1242  {
1243  SAL_WARN("sw.ww8", "broken offset, ignoring");
1244  return WW8_FC_MAX;
1245  }
1246 
1247  return nRet;
1248 }
1249 
1250 void WW8PLCFx_PCD::CurrentPieceFc2Cp( WW8_CP& rStartPos, WW8_CP& rEndPos,
1251  const WW8ScannerBase *pSBase )
1252 {
1253  //No point going anywhere with this
1254  if ((rStartPos == WW8_CP_MAX) && (rEndPos == WW8_CP_MAX))
1255  return;
1256 
1257  rStartPos = pSBase->WW8Fc2Cp( rStartPos );
1258  rEndPos = pSBase->WW8Fc2Cp( rEndPos );
1259 }
1260 
1262 {
1263  WW8_CP nCpStart, nCpEnd;
1264  void* pData;
1265  if ( !pPcdI->Get( nCpStart, nCpEnd, pData ) )
1266  {
1267  OSL_ENSURE( false, "CurrentPieceStartFc2Cp() - error" );
1268  return WW8_CP_MAX;
1269  }
1270  bool bIsUnicode = false;
1271  sal_Int32 nFcStart = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
1272  if( !bVer67 )
1273  nFcStart = WW8PLCFx_PCD::TransformPieceAddress( nFcStart, bIsUnicode );
1274 
1275  sal_Int32 nUnicodeFactor = bIsUnicode ? 2 : 1;
1276 
1277  if( nStartPos < nFcStart )
1278  nStartPos = nFcStart;
1279 
1280  WW8_CP nCpLen;
1281  bool bFail = o3tl::checked_sub(nCpEnd, nCpStart, nCpLen);
1282  if (bFail)
1283  {
1284  SAL_WARN("sw.ww8", "broken offset, ignoring");
1285  return WW8_CP_MAX;
1286  }
1287 
1288  WW8_CP nCpLenBytes;
1289  bFail = o3tl::checked_multiply(nCpLen, nUnicodeFactor, nCpLenBytes);
1290  if (bFail)
1291  {
1292  SAL_WARN("sw.ww8", "broken offset, ignoring");
1293  return WW8_CP_MAX;
1294  }
1295 
1296  WW8_FC nFcLen;
1297  bFail = o3tl::checked_add(nFcStart, nCpLenBytes, nFcLen);
1298  if (bFail)
1299  {
1300  SAL_WARN("sw.ww8", "broken offset, ignoring");
1301  return WW8_CP_MAX;
1302  }
1303 
1304  WW8_FC nFcEnd;
1305  bFail = o3tl::checked_add(nFcStart, nFcLen, nFcEnd);
1306  if (bFail)
1307  {
1308  SAL_WARN("sw.ww8", "broken offset, ignoring");
1309  return WW8_CP_MAX;
1310  }
1311 
1312 
1313  if (nStartPos >= nFcEnd)
1314  nStartPos = nFcEnd - (1 * nUnicodeFactor);
1315 
1316  WW8_FC nFcDiff = (nStartPos - nFcStart) / nUnicodeFactor;
1317 
1318  WW8_FC nCpRet;
1319  bFail = o3tl::checked_add(nCpStart, nFcDiff, nCpRet);
1320  if (bFail)
1321  {
1322  SAL_WARN("sw.ww8", "broken offset, ignoring");
1323  return WW8_CP_MAX;
1324  }
1325 
1326  return nCpRet;
1327 }
1328 
1329 // Helper routines for all
1330 
1331 // Convert BRC from WW6 to WW8 format
1333 {
1334  sal_uInt8 _dptLineWidth = brcVer6.dxpLineWidth(),
1335  _brcType = brcVer6.brcType();
1336 
1337  if (_dptLineWidth > 5) // this signifies dashed(6) or dotted(7) line
1338  {
1339  _brcType = _dptLineWidth;
1340  _dptLineWidth = 1;
1341  }
1342  _dptLineWidth *= 6; // convert units from 0.75pt to 1/8pt
1343 
1344  *this = WW8_BRC(_dptLineWidth, _brcType, brcVer6.ico(), brcVer6.dxpSpace(),
1345  brcVer6.fShadow(), false);
1346 }
1347 
1348 // Convert BRC from WW8 to WW9 format
1350 {
1351  if (brcVer8.isNil()) {
1352  UInt32ToSVBT32(0, aBits1);
1353  UInt32ToSVBT32(0xffffffff, aBits2);
1354  }
1355  else
1356  {
1357  sal_uInt32 _cv = brcVer8.ico() == 0 ? 0xff000000 // "auto" colour
1359  *this = WW8_BRCVer9(_cv, brcVer8.dptLineWidth(), brcVer8.brcType(),
1360  brcVer8.dptSpace(), brcVer8.fShadow(), brcVer8.fFrame());
1361  }
1362 }
1363 
1364 short WW8_BRC::DetermineBorderProperties(short *pSpace) const
1365 {
1366  WW8_BRCVer9 brcVer9(*this);
1367  return brcVer9.DetermineBorderProperties(pSpace);
1368 }
1369 
1370 short WW8_BRCVer9::DetermineBorderProperties(short *pSpace) const
1371 {
1372  /*
1373  Word does not factor the width of the border into the width/height
1374  stored in the information for graphic/table/object widths, so we need
1375  to figure out this extra width here and utilize the returned size in
1376  our calculations
1377  */
1378  short nMSTotalWidth;
1379 
1380  //Specification in 8ths of a point, 1 Point = 20 Twips, so by 2.5
1381  nMSTotalWidth = static_cast<short>(dptLineWidth()) * 20 / 8;
1382 
1383  //Figure out the real size of the border according to word
1384  switch (brcType())
1385  {
1386  //Note that codes over 25 are undocumented, and I can't create
1387  //these 4 here in the wild.
1388  case 2:
1389  case 4:
1390  case 5:
1391  case 22:
1392  OSL_FAIL("Can't create these from the menus, please report");
1393  break;
1394  default:
1395  case 23: //Only 3pt in the menus, but honours the size setting.
1396  break;
1397  case 10:
1398  /*
1399  triple line is five times the width of an ordinary line,
1400  except that the smallest 1/4 point size appears to have
1401  exactly the same total border width as a 3/4 point size
1402  ordinary line, i.e. three times the nominal line width. The
1403  second smallest 1/2 point size appears to have exactly the
1404  total border width as a 2 1/4 border, i.e 4.5 times the size.
1405  */
1406  if (nMSTotalWidth == 5)
1407  nMSTotalWidth*=3;
1408  else if (nMSTotalWidth == 10)
1409  nMSTotalWidth = nMSTotalWidth*9/2;
1410  else
1411  nMSTotalWidth*=5;
1412  break;
1413  case 20:
1414  /*
1415  wave, the dimensions appear to be created by the drawing of
1416  the wave, so we have only two possibilities in the menus, 3/4
1417  point is equal to solid 3 point. This calculation seems to
1418  match well to results.
1419  */
1420  nMSTotalWidth +=45;
1421  break;
1422  case 21:
1423  /*
1424  double wave, the dimensions appear to be created by the
1425  drawing of the wave, so we have only one possibilities in the
1426  menus, that of 3/4 point is equal to solid 3 point. This
1427  calculation seems to match well to results.
1428  */
1429  nMSTotalWidth += 45*2;
1430  break;
1431  }
1432 
1433  if (pSpace)
1434  *pSpace = static_cast<short>(dptSpace()) * 20; // convert from points to twips
1435  return nMSTotalWidth;
1436 }
1437 
1438 /*
1439  * WW8Cp2Fc is a good method, a CP always maps to a FC
1440  * WW8Fc2Cp on the other hand is more dubious, a random FC
1441  * may not map to a valid CP. Try and avoid WW8Fc2Cp where
1442  * possible
1443  */
1445 {
1446  WW8_CP nFallBackCpEnd = WW8_CP_MAX;
1447  if( nFcPos == WW8_FC_MAX )
1448  return nFallBackCpEnd;
1449 
1450  bool bIsUnicode;
1451  if (m_pWw8Fib->m_nVersion >= 8)
1452  bIsUnicode = false;
1453  else
1454  bIsUnicode = m_pWw8Fib->m_fExtChar;
1455 
1456  if( m_pPieceIter ) // Complex File ?
1457  {
1458  sal_uInt32 nOldPos = m_pPieceIter->GetIdx();
1459 
1460  for (m_pPieceIter->SetIdx(0);
1461  m_pPieceIter->GetIdx() < m_pPieceIter->GetIMax(); m_pPieceIter->advance())
1462  {
1463  WW8_CP nCpStart, nCpEnd;
1464  void* pData;
1465  if( !m_pPieceIter->Get( nCpStart, nCpEnd, pData ) )
1466  { // outside PLCFfpcd ?
1467  OSL_ENSURE( false, "PLCFpcd-WW8Fc2Cp() went wrong" );
1468  break;
1469  }
1470  sal_Int32 nFcStart = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
1471  if (m_pWw8Fib->m_nVersion >= 8)
1472  {
1473  nFcStart = WW8PLCFx_PCD::TransformPieceAddress( nFcStart,
1474  bIsUnicode );
1475  }
1476  else
1477  {
1478  bIsUnicode = m_pWw8Fib->m_fExtChar;
1479  }
1480 
1481  sal_Int32 nLen;
1482  if (o3tl::checked_sub(nCpEnd, nCpStart, nLen))
1483  {
1484  SAL_WARN("sw.ww8", "broken offset, ignoring");
1485  return WW8_CP_MAX;
1486  }
1487  if (bIsUnicode)
1488  {
1489  if (o3tl::checked_multiply<WW8_CP>(nLen, 2, nLen))
1490  {
1491  SAL_WARN("sw.ww8", "broken offset, ignoring");
1492  return WW8_CP_MAX;
1493  }
1494  }
1495 
1496  /*
1497  If this cp is inside this piece, or it's the last piece and we are
1498  on the very last cp of that piece
1499  */
1500  if (nFcPos >= nFcStart)
1501  {
1502  // found
1503  WW8_FC nFcDiff;
1504  if (o3tl::checked_sub(nFcPos, nFcStart, nFcDiff))
1505  {
1506  SAL_WARN("sw.ww8", "broken offset, ignoring");
1507  return WW8_CP_MAX;
1508  }
1509  if (bIsUnicode)
1510  nFcDiff /= 2;
1511  WW8_CP nTempCp;
1512  if (o3tl::checked_add(nCpStart, nFcDiff, nTempCp))
1513  {
1514  SAL_WARN("sw.ww8", "broken offset, ignoring");
1515  return WW8_CP_MAX;
1516  }
1517  WW8_FC nFcEnd;
1518  if (o3tl::checked_add(nFcStart, nLen, nFcEnd))
1519  {
1520  SAL_WARN("sw.ww8", "broken offset, ignoring");
1521  return WW8_CP_MAX;
1522  }
1523  if (nFcPos < nFcEnd)
1524  {
1525  m_pPieceIter->SetIdx( nOldPos );
1526  return nTempCp;
1527  }
1528  else if (nFcPos == nFcEnd)
1529  {
1530  //Keep this cp as its on a piece boundary because we might
1531  //need it if tests fail
1532  nFallBackCpEnd = nTempCp;
1533  }
1534  }
1535  }
1536  // not found
1537  m_pPieceIter->SetIdx( nOldPos ); // not found
1538  /*
1539  If it was not found, then this is because it has fallen between two
1540  stools, i.e. either it is the last cp/fc of the last piece, or it is
1541  the last cp/fc of a disjoint piece.
1542  */
1543  return nFallBackCpEnd;
1544  }
1545 
1546  WW8_FC nFcDiff;
1547  if (o3tl::checked_sub(nFcPos, m_pWw8Fib->m_fcMin, nFcDiff))
1548  {
1549  SAL_WARN("sw.ww8", "broken offset, ignoring");
1550  return WW8_CP_MAX;
1551  }
1552 
1553  // No complex file
1554  if (!bIsUnicode)
1555  nFallBackCpEnd = nFcDiff;
1556  else
1557  nFallBackCpEnd = (nFcDiff + 1) / 2;
1558 
1559  return nFallBackCpEnd;
1560 }
1561 
1562 // the fib of WinWord2 has a last entry of cpnBtePap of 2 byte sized type PN at
1563 // offset 324
1564 const int nSmallestPossibleFib = 326;
1565 
1566 WW8_FC WW8ScannerBase::WW8Cp2Fc(WW8_CP nCpPos, bool* pIsUnicode,
1567  WW8_CP* pNextPieceCp, bool* pTestFlag) const
1568 {
1569  if( pTestFlag )
1570  *pTestFlag = true;
1571  if( WW8_CP_MAX == nCpPos )
1572  return WW8_CP_MAX;
1573 
1574  bool bIsUnicode;
1575  if( !pIsUnicode )
1576  pIsUnicode = &bIsUnicode;
1577 
1578  if (m_pWw8Fib->m_nVersion >= 8)
1579  *pIsUnicode = false;
1580  else
1581  *pIsUnicode = m_pWw8Fib->m_fExtChar;
1582 
1583  WW8_FC nRet;
1584 
1585  if( m_pPieceIter )
1586  {
1587  // Complex File
1588  if( pNextPieceCp )
1589  *pNextPieceCp = WW8_CP_MAX;
1590 
1591  if( !m_pPieceIter->SeekPos( nCpPos ) )
1592  {
1593  if( pTestFlag )
1594  *pTestFlag = false;
1595  else {
1596  OSL_ENSURE( false, "Handed over wrong CP to WW8Cp2Fc()" );
1597  }
1598  return WW8_FC_MAX;
1599  }
1600  WW8_CP nCpStart, nCpEnd;
1601  void* pData;
1602  if( !m_pPieceIter->Get( nCpStart, nCpEnd, pData ) )
1603  {
1604  if( pTestFlag )
1605  *pTestFlag = false;
1606  else {
1607  OSL_ENSURE( false, "PLCFfpcd-Get went wrong" );
1608  }
1609  return WW8_FC_MAX;
1610  }
1611  if( pNextPieceCp )
1612  *pNextPieceCp = nCpEnd;
1613 
1614  nRet = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
1615  if (m_pWw8Fib->m_nVersion >= 8)
1616  nRet = WW8PLCFx_PCD::TransformPieceAddress( nRet, *pIsUnicode );
1617  else
1618  *pIsUnicode = m_pWw8Fib->m_fExtChar;
1619 
1620  WW8_CP nCpLen;
1621  bool bFail = o3tl::checked_sub(nCpPos, nCpStart, nCpLen);
1622  if (bFail)
1623  {
1624  SAL_WARN("sw.ww8", "broken offset, ignoring");
1625  return WW8_CP_MAX;
1626  }
1627 
1628  if (*pIsUnicode)
1629  {
1630  bFail = o3tl::checked_multiply<WW8_CP>(nCpLen, 2, nCpLen);
1631  if (bFail)
1632  {
1633  SAL_WARN("sw.ww8", "broken offset, ignoring");
1634  return WW8_CP_MAX;
1635  }
1636  }
1637 
1638  bFail = o3tl::checked_add(nRet, nCpLen, nRet);
1639  if (bFail)
1640  {
1641  SAL_WARN("sw.ww8", "broken offset, ignoring");
1642  return WW8_CP_MAX;
1643  }
1644 
1645  return nRet;
1646  }
1647 
1648  if (*pIsUnicode)
1649  {
1650  const bool bFail = o3tl::checked_multiply<WW8_CP>(nCpPos, 2, nCpPos);
1651  if (bFail)
1652  {
1653  SAL_WARN("sw.ww8", "broken offset, ignoring");
1654  return WW8_CP_MAX;
1655  }
1656  }
1657 
1658  // No complex file
1659  const bool bFail = o3tl::checked_add(m_pWw8Fib->m_fcMin, nCpPos, nRet);
1660  if (bFail)
1661  {
1662  SAL_WARN("sw.ww8", "broken offset, ignoring");
1663  return WW8_CP_MAX;
1664  }
1665 
1666  // the text and the fib share the same stream, if the text is inside the fib
1667  // then it's definitely a bad offset. The smallest FIB supported is that of
1668  // WW2 which is 326 bytes in size
1669  if (nRet < nSmallestPossibleFib)
1670  {
1671  SAL_WARN("sw.ww8", "broken offset, ignoring");
1672  return WW8_CP_MAX;
1673  }
1674 
1675  return nRet;
1676 }
1677 
1678 std::unique_ptr<WW8PLCFpcd> WW8ScannerBase::OpenPieceTable( SvStream* pStr, const WW8Fib* pWwF )
1679 {
1680  if ( ((8 > m_pWw8Fib->m_nVersion) && !pWwF->m_fComplex) || !pWwF->m_lcbClx )
1681  return nullptr;
1682 
1683  if (pWwF->m_lcbClx < 0)
1684  return nullptr;
1685 
1686  WW8_FC nClxPos = pWwF->m_fcClx;
1687 
1688  if (!checkSeek(*pStr, nClxPos))
1689  return nullptr;
1690 
1691  sal_Int32 nClxLen = pWwF->m_lcbClx;
1692  sal_Int32 nLeft = nClxLen;
1693 
1694  while (true)
1695  {
1696  sal_uInt8 clxt(2);
1697  pStr->ReadUChar( clxt );
1698  nLeft--;
1699  if( 2 == clxt) // PLCFfpcd ?
1700  break; // PLCFfpcd found
1701  sal_uInt16 nLen(0);
1702  pStr->ReadUInt16( nLen );
1703  nLeft -= 2 + nLen;
1704  if( nLeft < 0 )
1705  return nullptr; // gone wrong
1706  if( 1 == clxt ) // clxtGrpprl ?
1707  {
1708  if (m_aPieceGrpprls.size() == SHRT_MAX)
1709  return nullptr;
1710  if (nLen > pStr->remainingSize())
1711  return nullptr;
1712  std::unique_ptr<sal_uInt8[]> p(new sal_uInt8[nLen+2]); // allocate
1713  ShortToSVBT16(nLen, p.get()); // add length
1714  if (!checkRead(*pStr, p.get()+2, nLen)) // read grpprl
1715  {
1716  return nullptr;
1717  }
1718  m_aPieceGrpprls.push_back(std::move(p)); // add to array
1719  }
1720  else
1721  {
1722  nLen = std::min<sal_uInt64>(nLen, pStr->remainingSize());
1723  pStr->Seek(pStr->Tell() + nLen); // non-Grpprl left
1724  }
1725  }
1726 
1727  // read Piece Table PLCF
1728  sal_Int32 nPLCFfLen(0);
1729  if (pWwF->GetFIBVersion() <= ww::eWW2)
1730  {
1731  sal_Int16 nWordTwoLen(0);
1732  pStr->ReadInt16( nWordTwoLen );
1733  nPLCFfLen = nWordTwoLen;
1734  }
1735  else
1736  pStr->ReadInt32( nPLCFfLen );
1737  OSL_ENSURE( 65536 > nPLCFfLen, "PLCFfpcd above 64 k" );
1738  return std::make_unique<WW8PLCFpcd>( pStr, pStr->Tell(), nPLCFfLen, 8 );
1739 }
1740 
1742  SvStream* pDataSt, WW8Fib* pWwFib )
1743  : m_pWw8Fib(pWwFib)
1744 {
1745  m_pPiecePLCF = OpenPieceTable( pTableSt, m_pWw8Fib ); // Complex
1746  if( m_pPiecePLCF )
1747  {
1748  m_pPieceIter.reset(new WW8PLCFpcd_Iter( *m_pPiecePLCF ));
1749  m_pPLCFx_PCD.reset( new WW8PLCFx_PCD(*pWwFib, m_pPiecePLCF.get(), 0,
1751  m_pPLCFx_PCDAttrs.reset(new WW8PLCFx_PCDAttrs(*pWwFib,
1752  m_pPLCFx_PCD.get(), this));
1753  }
1754  else
1755  {
1756  m_pPieceIter = nullptr;
1757  m_pPLCFx_PCD = nullptr;
1758  m_pPLCFx_PCDAttrs = nullptr;
1759  }
1760 
1761  // pChpPLCF and pPapPLCF may NOT be created before pPLCFx_PCD !!
1762  m_pChpPLCF.reset(new WW8PLCFx_Cp_FKP( pSt, pTableSt, pDataSt, *this, CHP )); // CHPX
1763  m_pPapPLCF.reset(new WW8PLCFx_Cp_FKP( pSt, pTableSt, pDataSt, *this, PAP )); // PAPX
1764 
1765  m_pSepPLCF.reset(new WW8PLCFx_SEPX( pSt, pTableSt, *pWwFib, 0 )); // SEPX
1766 
1767  // Footnotes
1768  m_pFootnotePLCF.reset(new WW8PLCFx_SubDoc( pTableSt, *pWwFib, 0,
1769  pWwFib->m_fcPlcffndRef, pWwFib->m_lcbPlcffndRef, pWwFib->m_fcPlcffndText,
1770  pWwFib->m_lcbPlcffndText, 2 ));
1771  // Endnotes
1772  m_pEdnPLCF.reset(new WW8PLCFx_SubDoc( pTableSt, *pWwFib, 0,
1773  pWwFib->m_fcPlcfendRef, pWwFib->m_lcbPlcfendRef, pWwFib->m_fcPlcfendText,
1774  pWwFib->m_lcbPlcfendText, 2 ));
1775  // Comments
1776  m_pAndPLCF.reset(new WW8PLCFx_SubDoc( pTableSt, *pWwFib, 0,
1777  pWwFib->m_fcPlcfandRef, pWwFib->m_lcbPlcfandRef, pWwFib->m_fcPlcfandText,
1778  pWwFib->m_lcbPlcfandText, IsSevenMinus(pWwFib->GetFIBVersion()) ? 20 : 30));
1779 
1780  // Fields Main Text
1781  m_pFieldPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_MAINTEXT));
1782  // Fields Header / Footer
1783  m_pFieldHdFtPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_HDFT));
1784  // Fields Footnote
1785  m_pFieldFootnotePLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_FTN));
1786  // Fields Endnote
1787  m_pFieldEdnPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_EDN));
1788  // Fields Comments
1789  m_pFieldAndPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_AND));
1790  // Fields in Textboxes in Main Text
1791  m_pFieldTxbxPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_TXBX));
1792  // Fields in Textboxes in Header / Footer
1793  m_pFieldTxbxHdFtPLCF.reset(new WW8PLCFx_FLD(pTableSt,*pWwFib,MAN_TXBX_HDFT));
1794 
1795  // Note: 6 stands for "6 OR 7", 7 stands for "ONLY 7"
1796  switch( m_pWw8Fib->m_nVersion )
1797  {
1798  case 6:
1799  case 7:
1800  if( pWwFib->m_fcPlcfdoaMom && pWwFib->m_lcbPlcfdoaMom )
1801  {
1802  m_pMainFdoa.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfdoaMom,
1803  pWwFib->m_lcbPlcfdoaMom, 6 ));
1804  }
1805  if( pWwFib->m_fcPlcfdoaHdr && pWwFib->m_lcbPlcfdoaHdr )
1806  {
1807  m_pHdFtFdoa.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfdoaHdr,
1808  pWwFib->m_lcbPlcfdoaHdr, 6 ));
1809  }
1810  break;
1811  case 8:
1812  if( pWwFib->m_fcPlcfspaMom && pWwFib->m_lcbPlcfspaMom )
1813  {
1814  m_pMainFdoa.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfspaMom,
1815  pWwFib->m_lcbPlcfspaMom, 26 ));
1816  }
1817  if( pWwFib->m_fcPlcfspaHdr && pWwFib->m_lcbPlcfspaHdr )
1818  {
1819  m_pHdFtFdoa.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfspaHdr,
1820  pWwFib->m_lcbPlcfspaHdr, 26 ));
1821  }
1822  // PLCF for TextBox break-descriptors in the main text
1823  if( pWwFib->m_fcPlcftxbxBkd && pWwFib->m_lcbPlcftxbxBkd )
1824  {
1825  m_pMainTxbxBkd.reset(new WW8PLCFspecial( pTableSt,
1826  pWwFib->m_fcPlcftxbxBkd, pWwFib->m_lcbPlcftxbxBkd, 0));
1827  }
1828  // PLCF for TextBox break-descriptors in Header/Footer range
1829  if( pWwFib->m_fcPlcfHdrtxbxBkd && pWwFib->m_lcbPlcfHdrtxbxBkd )
1830  {
1831  m_pHdFtTxbxBkd.reset(new WW8PLCFspecial( pTableSt,
1832  pWwFib->m_fcPlcfHdrtxbxBkd, pWwFib->m_lcbPlcfHdrtxbxBkd, 0));
1833  }
1834  // Sub table cp positions
1835  if (pWwFib->m_fcPlcfTch && pWwFib->m_lcbPlcfTch)
1836  {
1837  m_pMagicTables.reset(new WW8PLCFspecial( pTableSt,
1838  pWwFib->m_fcPlcfTch, pWwFib->m_lcbPlcfTch, 4));
1839  }
1840  // Sub document cp positions
1841  if (pWwFib->m_fcPlcfwkb && pWwFib->m_lcbPlcfwkb)
1842  {
1843  m_pSubdocs.reset(new WW8PLCFspecial( pTableSt,
1844  pWwFib->m_fcPlcfwkb, pWwFib->m_lcbPlcfwkb, 12));
1845  }
1846  // Extended ATRD
1847  if (pWwFib->m_fcAtrdExtra && pWwFib->m_lcbAtrdExtra)
1848  {
1849  sal_uInt64 const nOldPos = pTableSt->Tell();
1850  if (checkSeek(*pTableSt, pWwFib->m_fcAtrdExtra) && (pTableSt->remainingSize() >= pWwFib->m_lcbAtrdExtra))
1851  {
1852  m_pExtendedAtrds.reset( new sal_uInt8[pWwFib->m_lcbAtrdExtra] );
1853  pWwFib->m_lcbAtrdExtra = pTableSt->ReadBytes(m_pExtendedAtrds.get(), pWwFib->m_lcbAtrdExtra);
1854  }
1855  else
1856  pWwFib->m_lcbAtrdExtra = 0;
1857  pTableSt->Seek(nOldPos);
1858  }
1859 
1860  break;
1861  default:
1862  OSL_ENSURE( false, "nVersion not implemented!" );
1863  break;
1864  }
1865 
1866  // PLCF for TextBox stories in main text
1867  sal_uInt32 nLenTxBxS = (8 > m_pWw8Fib->m_nVersion) ? 0 : 22;
1868  if( pWwFib->m_fcPlcftxbxText && pWwFib->m_lcbPlcftxbxText )
1869  {
1870  m_pMainTxbx.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcftxbxText,
1871  pWwFib->m_lcbPlcftxbxText, nLenTxBxS ));
1872  }
1873 
1874  // PLCF for TextBox stories in Header/Footer range
1875  if( pWwFib->m_fcPlcfHdrtxbxText && pWwFib->m_lcbPlcfHdrtxbxText )
1876  {
1877  m_pHdFtTxbx.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfHdrtxbxText,
1878  pWwFib->m_lcbPlcfHdrtxbxText, nLenTxBxS ));
1879  }
1880 
1881  m_pBook.reset(new WW8PLCFx_Book(pTableSt, *pWwFib));
1882  m_pAtnBook.reset(new WW8PLCFx_AtnBook(pTableSt, *pWwFib));
1883  m_pFactoidBook.reset(new WW8PLCFx_FactoidBook(pTableSt, *pWwFib));
1884 }
1885 
1887 {
1888  m_aPieceGrpprls.clear();
1889  m_pPLCFx_PCDAttrs.reset();
1890  m_pPLCFx_PCD.reset();
1891  m_pPieceIter.reset();
1892  m_pPiecePLCF.reset();
1893  m_pFactoidBook.reset();
1894  m_pAtnBook.reset();
1895  m_pBook.reset();
1896  m_pFieldEdnPLCF.reset();
1897  m_pFieldFootnotePLCF.reset();
1898  m_pFieldAndPLCF.reset();
1899  m_pFieldHdFtPLCF.reset();
1900  m_pFieldPLCF.reset();
1901  m_pFieldTxbxPLCF.reset();
1902  m_pFieldTxbxHdFtPLCF.reset();
1903  m_pEdnPLCF.reset();
1904  m_pFootnotePLCF.reset();
1905  m_pAndPLCF.reset();
1906  m_pSepPLCF.reset();
1907  m_pPapPLCF.reset();
1908  m_pChpPLCF.reset();
1909  m_pMainFdoa.reset();
1910  m_pHdFtFdoa.reset();
1911  m_pMainTxbx.reset();
1912  m_pMainTxbxBkd.reset();
1913  m_pHdFtTxbx.reset();
1914  m_pHdFtTxbxBkd.reset();
1915  m_pMagicTables.reset();
1916  m_pSubdocs.reset();
1917 }
1918 
1919 // Fields
1920 
1921 static bool WW8SkipField(WW8PLCFspecial& rPLCF)
1922 {
1923  void* pData;
1924  WW8_CP nP;
1925 
1926  if (!rPLCF.Get(nP, pData)) // End of PLCFspecial?
1927  return false;
1928 
1929  rPLCF.advance();
1930 
1931  if((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) != 0x13 ) // No beginning?
1932  return true; // Do not terminate on error
1933 
1934  if( !rPLCF.Get( nP, pData ) )
1935  return false;
1936 
1937  while((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x13 )
1938  {
1939  // still new (nested) beginnings ?
1940  WW8SkipField( rPLCF ); // nested Field in description
1941  if( !rPLCF.Get( nP, pData ) )
1942  return false;
1943  }
1944 
1945  if((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x14 )
1946  {
1947 
1948  // Field Separator ?
1949  rPLCF.advance();
1950 
1951  if( !rPLCF.Get( nP, pData ) )
1952  return false;
1953 
1954  while ((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x13)
1955  {
1956  // still new (nested) beginnings?
1957  WW8SkipField( rPLCF ); // nested Field in Results
1958  if( !rPLCF.Get( nP, pData ) )
1959  return false;
1960  }
1961  }
1962  rPLCF.advance();
1963 
1964  return true;
1965 }
1966 
1968 {
1969  void* pData;
1970  sal_uInt32 nOldIdx = rPLCF.GetIdx();
1971 
1972  rF.nLen = rF.nId = rF.nOpt = 0;
1973  rF.bCodeNest = rF.bResNest = false;
1974 
1975  if (!rPLCF.Get(rF.nSCode, pData) || rF.nSCode < 0) // end of PLCFspecial?
1976  goto Err;
1977 
1978  rPLCF.advance();
1979 
1980  if (!pData || (static_cast<sal_uInt8*>(pData)[0] & 0x1f) != 0x13) // No beginning?
1981  goto Err;
1982 
1983  rF.nId = static_cast<sal_uInt8*>(pData)[1];
1984 
1985  if( !rPLCF.Get( rF.nLCode, pData ) )
1986  goto Err;
1987 
1988  if (rF.nLCode < rF.nSCode)
1989  goto Err;
1990 
1991  rF.nSRes = rF.nLCode; // Default
1992  rF.nSCode++; // without markers
1993  rF.nLCode -= rF.nSCode; // Pos -> length
1994 
1995  while((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x13 )
1996  {
1997  // still new (nested) beginnings ?
1998  WW8SkipField( rPLCF ); // nested Field in description
1999  rF.bCodeNest = true;
2000  if (!rPLCF.Get(rF.nSRes, pData) || rF.nSRes < 0)
2001  goto Err;
2002  }
2003 
2004  if ((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x14 ) // Field Separator?
2005  {
2006  rPLCF.advance();
2007 
2008  if (!rPLCF.Get(rF.nLRes, pData) || rF.nLRes < 0)
2009  goto Err;
2010 
2011  while((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x13 )
2012  {
2013  // still new (nested) beginnings ?
2014  WW8SkipField( rPLCF ); // nested Field in results
2015  rF.bResNest = true;
2016  if (!rPLCF.Get(rF.nLRes, pData) || rF.nLRes < 0)
2017  goto Err;
2018  }
2019  WW8_CP nTmp;
2020  if (o3tl::checked_sub<WW8_CP>(rF.nLRes, rF.nSCode, nTmp))
2021  {
2022  rF.nLen = 0;
2023  goto Err;
2024  }
2025  if (o3tl::checked_add<WW8_CP>(nTmp, 2, rF.nLen)) // nLRes is still the final position
2026  {
2027  rF.nLen = 0;
2028  goto Err;
2029  }
2030  rF.nLRes -= rF.nSRes; // now: nLRes = length
2031  if (o3tl::checked_add<WW8_CP>(rF.nSRes, 1, rF.nSRes)) // Endpos including Markers
2032  {
2033  rF.nLen = 0;
2034  goto Err;
2035  }
2036  rF.nLRes--;
2037  }else{
2038  rF.nLRes = 0; // no result found
2039  WW8_CP nTmp;
2040  if (o3tl::checked_sub<WW8_CP>(rF.nSRes, rF.nSCode, nTmp))
2041  {
2042  rF.nLen = 0;
2043  goto Err;
2044  }
2045  if (o3tl::checked_add<WW8_CP>(nTmp, 2, rF.nLen)) // total length
2046  {
2047  rF.nLen = 0;
2048  goto Err;
2049  }
2050  }
2051 
2052  if (rF.nLen < 0)
2053  {
2054  rF.nLen = 0;
2055  goto Err;
2056  }
2057 
2058  rPLCF.advance();
2059  if((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x15 )
2060  {
2061  // Field end ?
2062  // INDEX-Field has set Bit7?
2063  rF.nOpt = static_cast<sal_uInt8*>(pData)[1]; // yes -> copy flags
2064  }else{
2065  rF.nId = 0; // no -> Field invalid
2066  }
2067 
2068  rPLCF.SetIdx( nOldIdx );
2069  return true;
2070 Err:
2071  rPLCF.SetIdx( nOldIdx );
2072  return false;
2073 }
2074 
2075 OUString read_uInt8_BeltAndBracesString(SvStream& rStrm, rtl_TextEncoding eEnc)
2076 {
2077  const OUString aRet = read_uInt8_lenPrefixed_uInt8s_ToOUString(rStrm, eEnc);
2078  rStrm.SeekRel(sizeof(sal_uInt8)); // skip null-byte at end
2079  return aRet;
2080 }
2081 
2083 {
2084  const OUString aRet = read_uInt16_PascalString(rStrm);
2085  rStrm.SeekRel(sizeof(sal_Unicode)); // skip null-byte at end
2086  return aRet;
2087 }
2088 
2089 sal_Int32 WW8ScannerBase::WW8ReadString( SvStream& rStrm, OUString& rStr,
2090  WW8_CP nCurrentStartCp, tools::Long nTotalLen, rtl_TextEncoding eEnc ) const
2091 {
2092  // Read in plain text, which can extend over several pieces
2093  rStr.clear();
2094 
2095  if (nCurrentStartCp < 0 || nTotalLen < 0)
2096  return 0;
2097 
2098  WW8_CP nBehindTextCp = nCurrentStartCp + nTotalLen;
2099  WW8_CP nNextPieceCp = nBehindTextCp; // Initialization, important for Ver6
2100  tools::Long nTotalRead = 0;
2101  do
2102  {
2103  bool bIsUnicode(false), bPosOk(false);
2104  WW8_FC fcAct = WW8Cp2Fc(nCurrentStartCp,&bIsUnicode,&nNextPieceCp,&bPosOk);
2105 
2106  // Probably aimed beyond file end, doesn't matter!
2107  if( !bPosOk )
2108  break;
2109 
2110  bool bValid = checkSeek(rStrm, fcAct);
2111  if (!bValid)
2112  break;
2113 
2114  WW8_CP nEnd = (nNextPieceCp < nBehindTextCp) ? nNextPieceCp
2115  : nBehindTextCp;
2116  WW8_CP nLen;
2117  const bool bFail = o3tl::checked_sub(nEnd, nCurrentStartCp, nLen);
2118  if (bFail)
2119  break;
2120 
2121  if( 0 >= nLen )
2122  break;
2123 
2124  rStr += bIsUnicode
2125  ? read_uInt16s_ToOUString(rStrm, nLen)
2126  : read_uInt8s_ToOUString(rStrm, nLen, eEnc);
2127 
2128  nTotalRead += nLen;
2129  nCurrentStartCp += nLen;
2130  if ( nTotalRead != rStr.getLength() )
2131  break;
2132  }
2133  while( nTotalRead < nTotalLen );
2134 
2135  return rStr.getLength();
2136 }
2137 
2138 WW8PLCFspecial::WW8PLCFspecial(SvStream* pSt, sal_uInt32 nFilePos,
2139  sal_uInt32 nPLCF, sal_uInt32 nStruct)
2140  : nIdx(0), nStru(nStruct)
2141 {
2142  const sal_uInt32 nValidMin=4;
2143 
2144  sal_uInt64 const nOldPos = pSt->Tell();
2145 
2146  bool bValid = checkSeek(*pSt, nFilePos);
2147  std::size_t nRemainingSize = pSt->remainingSize();
2148  if( nRemainingSize < nValidMin || nPLCF < nValidMin )
2149  bValid = false;
2150  nPLCF = bValid ? std::min(nRemainingSize, static_cast<std::size_t>(nPLCF)) : nValidMin;
2151 
2152  // Pointer to Pos- and Struct-array
2153  pPLCF_PosArray.reset( new sal_Int32[ ( nPLCF + 3 ) / 4 ] );
2154  pPLCF_PosArray[0] = 0;
2155 
2156  nPLCF = bValid ? pSt->ReadBytes(pPLCF_PosArray.get(), nPLCF) : nValidMin;
2157 
2158  nPLCF = std::max(nPLCF, nValidMin);
2159 
2160  nIMax = ( nPLCF - 4 ) / ( 4 + nStruct );
2161 #ifdef OSL_BIGENDIAN
2162  for( nIdx = 0; nIdx <= nIMax; nIdx++ )
2163  pPLCF_PosArray[nIdx] = OSL_SWAPDWORD( pPLCF_PosArray[nIdx] );
2164  nIdx = 0;
2165 #endif // OSL_BIGENDIAN
2166  if( nStruct ) // Pointer to content array
2167  pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&pPLCF_PosArray[nIMax + 1]);
2168  else
2169  pPLCF_Contents = nullptr; // no content
2170 
2171  pSt->Seek(nOldPos);
2172 }
2173 
2174 // WW8PLCFspecial::SeekPos() sets WW8PLCFspecial to position nPos, while also the entry is used
2175 // that begins before nPos and ends after nPos.
2176 // Suitable for normal attributes. However, the beginning of the attribute is not corrected onto
2177 // the position nPos.
2179 {
2180  if( nP < pPLCF_PosArray[0] )
2181  {
2182  nIdx = 0;
2183  return false; // Not found: nP less than smallest entry
2184  }
2185 
2186  // Search from beginning?
2187  if ((nIdx < 1) || (nP < pPLCF_PosArray[nIdx - 1]))
2188  nIdx = 1;
2189 
2190  tools::Long nI = nIdx;
2191  tools::Long nEnd = nIMax;
2192 
2193  for(int n = (1==nIdx ? 1 : 2); n; --n )
2194  {
2195  for( ; nI <=nEnd; ++nI)
2196  { // search with an index that is incremented by 1
2197  if( nP < pPLCF_PosArray[nI] )
2198  { // found position
2199  nIdx = nI - 1; // nI - 1 is the correct index
2200  return true; // done
2201  }
2202  }
2203  nI = 1;
2204  nEnd = nIdx-1;
2205  }
2206  nIdx = nIMax; // not found, greater than all entries
2207  return false;
2208 }
2209 
2210 // WW8PLCFspecial::SeekPosExact() like SeekPos(), but it is ensured that no attribute is cut,
2211 // i.e. the next given attribute begins at or after nPos.
2212 // Is used for fields and bookmarks.
2214 {
2215  if( nP < pPLCF_PosArray[0] )
2216  {
2217  nIdx = 0;
2218  return false; // Not found: nP less than smallest entry
2219  }
2220  // Search from beginning?
2221  if( nP <=pPLCF_PosArray[nIdx] )
2222  nIdx = 0;
2223 
2224  tools::Long nI = nIdx ? nIdx-1 : 0;
2225  tools::Long nEnd = nIMax;
2226 
2227  for(int n = (0==nIdx ? 1 : 2); n; --n )
2228  {
2229  for( ; nI < nEnd; ++nI)
2230  {
2231  if( nP <=pPLCF_PosArray[nI] )
2232  { // found position
2233  nIdx = nI; // nI is the correct index
2234  return true; // done
2235  }
2236  }
2237  nI = 0;
2238  nEnd = nIdx;
2239  }
2240  nIdx = nIMax; // Not found, greater than all entries
2241  return false;
2242 }
2243 
2244 bool WW8PLCFspecial::Get(WW8_CP& rPos, void*& rpValue) const
2245 {
2246  return GetData( nIdx, rPos, rpValue );
2247 }
2248 
2249 bool WW8PLCFspecial::GetData(tools::Long nInIdx, WW8_CP& rPos, void*& rpValue) const
2250 {
2251  if ( nInIdx >= nIMax )
2252  {
2253  rPos = WW8_CP_MAX;
2254  return false;
2255  }
2256  rPos = pPLCF_PosArray[nInIdx];
2257  rpValue = pPLCF_Contents ? static_cast<void*>(&pPLCF_Contents[nInIdx * nStru]) : nullptr;
2258  return true;
2259 }
2260 
2261 // WW8PLCF e.g. for SEPX
2262 // Ctor for *others* than Fkps
2263 // With nStartPos < 0, the first element of PLCFs will be taken
2264 WW8PLCF::WW8PLCF(SvStream& rSt, WW8_FC nFilePos, sal_Int32 nPLCF, int nStruct,
2265  WW8_CP nStartPos) : nIdx(0), nStru(nStruct)
2266 {
2267  if (nPLCF < 0)
2268  {
2269  SAL_WARN("sw.ww8", "broken WW8PLCF, ignoring");
2270  nPLCF = 0;
2271  }
2272  else
2273  nIMax = (nPLCF - 4) / (4 + nStruct);
2274 
2275  ReadPLCF(rSt, nFilePos, nPLCF);
2276 
2277  if( nStartPos >= 0 )
2278  SeekPos( nStartPos );
2279 }
2280 
2281 // Ctor *only* for Fkps
2282 // The last 2 parameters are needed for PLCF.Chpx and PLCF.Papx.
2283 // If ncpN != 0, then an incomplete PLCF will be completed. This is always required for WW6 with
2284 // lack of resources and for WordPad (W95).
2285 // With nStartPos < 0, the first element of the PLCFs is taken.
2286 WW8PLCF::WW8PLCF(SvStream& rSt, WW8_FC nFilePos, sal_Int32 nPLCF, int nStruct,
2287  WW8_CP nStartPos, sal_Int32 nPN, sal_Int32 ncpN): nIdx(0),
2288  nStru(nStruct)
2289 {
2290  if (nPLCF < 0)
2291  {
2292  SAL_WARN("sw.ww8", "broken WW8PLCF, ignoring");
2293  nIMax = SAL_MAX_INT32;
2294  }
2295  else
2296  nIMax = (nPLCF - 4) / (4 + nStruct);
2297 
2298  if( nIMax >= ncpN )
2299  ReadPLCF(rSt, nFilePos, nPLCF);
2300  else
2301  GeneratePLCF(rSt, nPN, ncpN);
2302 
2303  if( nStartPos >= 0 )
2304  SeekPos( nStartPos );
2305 }
2306 
2307 void WW8PLCF::ReadPLCF(SvStream& rSt, WW8_FC nFilePos, sal_uInt32 nPLCF)
2308 {
2309  sal_uInt64 const nOldPos = rSt.Tell();
2310  bool bValid = nPLCF != 0 && checkSeek(rSt, nFilePos)
2311  && (rSt.remainingSize() >= nPLCF);
2312 
2313  if (bValid)
2314  {
2315  // Pointer to Pos-array
2316  const size_t nEntries = (nPLCF + 3) / 4;
2317  pPLCF_PosArray.reset(new WW8_CP[nEntries]);
2318  bValid = checkRead(rSt, pPLCF_PosArray.get(), nPLCF);
2319  size_t nBytesAllocated = nEntries * sizeof(WW8_CP);
2320  if (bValid && nPLCF != nBytesAllocated)
2321  {
2322  sal_uInt8* pStartBlock = reinterpret_cast<sal_uInt8*>(pPLCF_PosArray.get());
2323  memset(pStartBlock + nPLCF, 0, nBytesAllocated - nPLCF);
2324  }
2325  }
2326 
2327  if (bValid)
2328  {
2329 #ifdef OSL_BIGENDIAN
2330  for( nIdx = 0; nIdx <= nIMax; nIdx++ )
2331  pPLCF_PosArray[nIdx] = OSL_SWAPDWORD( pPLCF_PosArray[nIdx] );
2332  nIdx = 0;
2333 #endif // OSL_BIGENDIAN
2334  // Pointer to content array
2335  pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&pPLCF_PosArray[nIMax + 1]);
2336 
2338  }
2339 
2340  OSL_ENSURE(bValid, "Document has corrupt PLCF, ignoring it");
2341 
2342  if (!bValid)
2343  MakeFailedPLCF();
2344 
2345  rSt.Seek(nOldPos);
2346 }
2347 
2349 {
2350  nIMax = 0;
2351  pPLCF_PosArray.reset( new WW8_CP[2] );
2353  pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&pPLCF_PosArray[nIMax + 1]);
2354 }
2355 
2356 namespace
2357 {
2358  sal_Int32 TruncToSortedRange(const sal_Int32* pPLCF_PosArray, sal_Int32 nIMax)
2359  {
2360  //Docs state that: ... all Plcs ... are sorted in ascending order.
2361  //So ensure that here for broken documents.
2362  for (auto nI = 0; nI < nIMax; ++nI)
2363  {
2364  if (pPLCF_PosArray[nI] > pPLCF_PosArray[nI+1])
2365  {
2366  SAL_WARN("sw.ww8", "Document has unsorted PLCF, truncated to sorted portion");
2367  nIMax = nI;
2368  break;
2369  }
2370  }
2371  return nIMax;
2372  }
2373 }
2374 
2376 {
2377  nIMax = ::TruncToSortedRange(pPLCF_PosArray.get(), nIMax);
2378 }
2379 
2381 {
2382  nIMax = ::TruncToSortedRange(pPLCF_PosArray.get(), nIMax);
2383 }
2384 
2385 void WW8PLCF::GeneratePLCF(SvStream& rSt, sal_Int32 nPN, sal_Int32 ncpN)
2386 {
2387  OSL_ENSURE( nIMax < ncpN, "Pcl.Fkp: Why is PLCF too big?" );
2388 
2389  bool failure = false;
2390  nIMax = ncpN;
2391 
2392  if ((nIMax < 1) || (nIMax > (WW8_CP_MAX - 4) / (4 + nStru)) || nPN < 0)
2393  failure = true;
2394 
2395  if (!failure)
2396  {
2397  // Check arguments to ShortToSVBT16 in loop below will all be valid:
2398  sal_Int32 nResult;
2399  failure = o3tl::checked_add(nPN, ncpN, nResult) || nResult > SAL_MAX_UINT16;
2400  }
2401 
2402  if (!failure)
2403  {
2404  size_t nSiz = (4 + nStru) * nIMax + 4;
2405  size_t nElems = ( nSiz + 3 ) / 4;
2406  pPLCF_PosArray.reset( new WW8_CP[ nElems ] ); // Pointer to Pos-array
2407 
2408  for (sal_Int32 i = 0; i < ncpN && !failure; ++i)
2409  {
2410  failure = true;
2411  // construct FC entries
2412  // first FC entry of each Fkp
2413  if (!checkSeek(rSt, (nPN + i) << 9))
2414  break;
2415 
2416  WW8_CP nFc(0);
2417  rSt.ReadInt32( nFc );
2418  pPLCF_PosArray[i] = nFc;
2419 
2420  failure = bool(rSt.GetError());
2421  }
2422  }
2423 
2424  if (!failure)
2425  {
2426  do
2427  {
2428  failure = true;
2429 
2430  std::size_t nLastFkpPos = nPN + nIMax - 1;
2431  nLastFkpPos = nLastFkpPos << 9;
2432  // number of FC entries of last Fkp
2433  if (!checkSeek(rSt, nLastFkpPos + 511))
2434  break;
2435 
2436  sal_uInt8 nb(0);
2437  rSt.ReadUChar( nb );
2438  // last FC entry of last Fkp
2439  if (!checkSeek(rSt, nLastFkpPos + nb * 4))
2440  break;
2441 
2442  WW8_CP nFc(0);
2443  rSt.ReadInt32( nFc );
2444  pPLCF_PosArray[nIMax] = nFc; // end of the last Fkp
2445 
2446  failure = bool(rSt.GetError());
2447  } while(false);
2448  }
2449 
2450  if (!failure)
2451  {
2452  // Pointer to content array
2453  pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&pPLCF_PosArray[nIMax + 1]);
2455 
2456  for (sal_Int32 i = 0; i < ncpN; ++i) // construct PNs
2457  {
2458  ShortToSVBT16(o3tl::narrowing<sal_uInt16>(nPN + i), p);
2459  p += nStru;
2460  }
2461  }
2462 
2463  SAL_WARN_IF(failure, "sw.ww8", "Document has corrupt PLCF, ignoring it");
2464 
2465  if (failure)
2466  MakeFailedPLCF();
2467 }
2468 
2470 {
2471  WW8_CP nP = nPos;
2472 
2473  if( nP < pPLCF_PosArray[0] )
2474  {
2475  nIdx = 0;
2476  // not found: nPos less than smallest entry
2477  return false;
2478  }
2479 
2480  // Search from beginning?
2481  if ((nIdx < 1) || (nP < pPLCF_PosArray[nIdx - 1]))
2482  nIdx = 1;
2483 
2484  sal_Int32 nI = nIdx;
2485  sal_Int32 nEnd = nIMax;
2486 
2487  for(int n = (1==nIdx ? 1 : 2); n; --n )
2488  {
2489  for( ; nI <=nEnd; ++nI) // search with an index that is incremented by 1
2490  {
2491  if( nP < pPLCF_PosArray[nI] ) // found position
2492  {
2493  nIdx = nI - 1; // nI - 1 is the correct index
2494  return true; // done
2495  }
2496  }
2497  nI = 1;
2498  nEnd = nIdx-1;
2499  }
2500 
2501  nIdx = nIMax; // not found, greater than all entries
2502  return false;
2503 }
2504 
2505 bool WW8PLCF::Get(WW8_CP& rStart, WW8_CP& rEnd, void*& rpValue) const
2506 {
2507  if ( nIdx >= nIMax )
2508  {
2509  rStart = rEnd = WW8_CP_MAX;
2510  return false;
2511  }
2512  rStart = pPLCF_PosArray[ nIdx ];
2513  rEnd = pPLCF_PosArray[ nIdx + 1 ];
2514  rpValue = static_cast<void*>(&pPLCF_Contents[nIdx * nStru]);
2515  return true;
2516 }
2517 
2519 {
2520  if ( nIdx >= nIMax )
2521  return WW8_CP_MAX;
2522 
2523  return pPLCF_PosArray[nIdx];
2524 }
2525 
2526 WW8PLCFpcd::WW8PLCFpcd(SvStream* pSt, sal_uInt32 nFilePos,
2527  sal_uInt32 nPLCF, sal_uInt32 nStruct)
2528  : nStru( nStruct )
2529 {
2530  const sal_uInt32 nValidMin=4;
2531 
2532  sal_uInt64 const nOldPos = pSt->Tell();
2533 
2534  bool bValid = checkSeek(*pSt, nFilePos);
2535  std::size_t nRemainingSize = pSt->remainingSize();
2536  if( nRemainingSize < nValidMin || nPLCF < nValidMin )
2537  bValid = false;
2538  nPLCF = bValid ? std::min(nRemainingSize, static_cast<std::size_t>(nPLCF)) : nValidMin;
2539 
2540  pPLCF_PosArray.reset( new WW8_CP[ ( nPLCF + 3 ) / 4 ] ); // Pointer to Pos-array
2541  pPLCF_PosArray[0] = 0;
2542 
2543  nPLCF = bValid ? pSt->ReadBytes(pPLCF_PosArray.get(), nPLCF) : nValidMin;
2544  nPLCF = std::max(nPLCF, nValidMin);
2545 
2546  nIMax = ( nPLCF - 4 ) / ( 4 + nStruct );
2547 #ifdef OSL_BIGENDIAN
2548  for( tools::Long nI = 0; nI <= nIMax; nI++ )
2549  pPLCF_PosArray[nI] = OSL_SWAPDWORD( pPLCF_PosArray[nI] );
2550 #endif // OSL_BIGENDIAN
2551 
2552  // Pointer to content array
2553  pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&pPLCF_PosArray[nIMax + 1]);
2555 
2556  pSt->Seek( nOldPos );
2557 }
2558 
2559 // If nStartPos < 0, the first element of PLCFs will be taken
2561  :rPLCF( rPLCFpcd ), nIdx( 0 )
2562 {
2563  if( nStartPos >= 0 )
2564  SeekPos( nStartPos );
2565 }
2566 
2568 {
2569  tools::Long nP = nPos;
2570 
2571  if( nP < rPLCF.pPLCF_PosArray[0] )
2572  {
2573  nIdx = 0;
2574  return false; // not found: nPos less than smallest entry
2575  }
2576  // Search from beginning?
2577  if ((nIdx < 1) || (nP < rPLCF.pPLCF_PosArray[nIdx - 1]))
2578  nIdx = 1;
2579 
2580  tools::Long nI = nIdx;
2581  tools::Long nEnd = rPLCF.nIMax;
2582 
2583  for(int n = (1==nIdx ? 1 : 2); n; --n )
2584  {
2585  for( ; nI <=nEnd; ++nI)
2586  { // search with an index that is incremented by 1
2587  if( nP < rPLCF.pPLCF_PosArray[nI] )
2588  { // found position
2589  nIdx = nI - 1; // nI - 1 is the correct index
2590  return true; // done
2591  }
2592  }
2593  nI = 1;
2594  nEnd = nIdx-1;
2595  }
2596  nIdx = rPLCF.nIMax; // not found, greater than all entries
2597  return false;
2598 }
2599 
2600 bool WW8PLCFpcd_Iter::Get(WW8_CP& rStart, WW8_CP& rEnd, void*& rpValue) const
2601 {
2602  if( nIdx >= rPLCF.nIMax )
2603  {
2604  rStart = rEnd = WW8_CP_MAX;
2605  return false;
2606  }
2607  rStart = rPLCF.pPLCF_PosArray[nIdx];
2608  rEnd = rPLCF.pPLCF_PosArray[nIdx + 1];
2609  rpValue = static_cast<void*>(&rPLCF.pPLCF_Contents[nIdx * rPLCF.nStru]);
2610  return true;
2611 }
2612 
2613 sal_Int32 WW8PLCFpcd_Iter::Where() const
2614 {
2615  if ( nIdx >= rPLCF.nIMax )
2616  return SAL_MAX_INT32;
2617 
2618  return rPLCF.pPLCF_PosArray[nIdx];
2619 }
2620 
2621 bool WW8PLCFx_Fc_FKP::WW8Fkp::Entry::operator<
2622  (const WW8PLCFx_Fc_FKP::WW8Fkp::Entry& rSecond) const
2623 {
2624  return (mnFC < rSecond.mnFC);
2625 }
2626 
2627 static bool IsReplaceAllSprm(sal_uInt16 nSpId)
2628 {
2629  return (NS_sprm::LN_PHugePapx == nSpId || 0x6646 == nSpId);
2630 }
2631 
2632 static bool IsExpandableSprm(sal_uInt16 nSpId)
2633 {
2634  return 0x646B == nSpId;
2635 }
2636 
2638  std::size_t nDataOffset, sal_uInt16 nLen)
2639 {
2640  bool bValidPos = (nDataOffset < sizeof(maRawData));
2641 
2642  OSL_ENSURE(bValidPos, "sprm sequence offset is out of range, ignoring");
2643 
2644  if (!bValidPos)
2645  {
2646  rEntry.mnLen = 0;
2647  return;
2648  }
2649 
2650  const sal_uInt16 nAvailableData = sizeof(maRawData)-nDataOffset;
2651  OSL_ENSURE(nLen <= nAvailableData, "srpm sequence len is out of range, clipping");
2652  rEntry.mnLen = std::min(nLen, nAvailableData);
2653  rEntry.mpData = maRawData + nDataOffset;
2654 }
2655 
2657  SvStream* pDataSt, tools::Long _nFilePos, tools::Long nItemSiz, ePLCFT ePl,
2658  WW8_FC nStartFc)
2659  : nItemSize(nItemSiz), nFilePos(_nFilePos), mnIdx(0), ePLCF(ePl)
2660  , mnMustRemainCached(0), maSprmParser(rFib)
2661 {
2662  memset(maRawData, 0, 512);
2663 
2664  const ww::WordVersion eVersion = rFib.GetFIBVersion();
2665 
2666  sal_uInt64 const nOldPos = pSt->Tell();
2667 
2668  bool bCouldSeek = checkSeek(*pSt, nFilePos);
2669  bool bCouldRead = bCouldSeek && checkRead(*pSt, maRawData, 512);
2670 
2671  mnIMax = bCouldRead ? maRawData[511] : 0;
2672 
2673  sal_uInt8 *pStart = maRawData;
2674  // Offset-Location in maRawData
2675  const size_t nRawDataStart = (mnIMax + 1) * 4;
2676 
2677  for (mnIdx = 0; mnIdx < mnIMax; ++mnIdx)
2678  {
2679  const size_t nRawDataOffset = nRawDataStart + mnIdx * nItemSize;
2680 
2681  //clip to available data, corrupt fkp
2682  if (nRawDataOffset >= 511)
2683  {
2684  mnIMax = mnIdx;
2685  break;
2686  }
2687 
2688  unsigned int nOfs = maRawData[nRawDataOffset] * 2;
2689  // nOfs in [0..0xff*2=510]
2690 
2691  Entry aEntry(Get_Long(pStart));
2692 
2693  if (nOfs)
2694  {
2695  switch (ePLCF)
2696  {
2697  case CHP:
2698  {
2699  aEntry.mnLen = maRawData[nOfs];
2700 
2701  //len byte
2702  std::size_t nDataOffset = nOfs + 1;
2703 
2704  FillEntry(aEntry, nDataOffset, aEntry.mnLen);
2705 
2706  if (aEntry.mnLen && eVersion <= ww::eWW2)
2707  {
2708  Word2CHPX aChpx = ReadWord2Chpx(*pSt, nFilePos + nOfs + 1, static_cast< sal_uInt8 >(aEntry.mnLen));
2709  std::vector<sal_uInt8> aSprms = ChpxToSprms(aChpx);
2710  aEntry.mnLen = static_cast< sal_uInt16 >(aSprms.size());
2711  if (aEntry.mnLen)
2712  {
2713  aEntry.mpData = new sal_uInt8[aEntry.mnLen];
2714  memcpy(aEntry.mpData, aSprms.data(), aEntry.mnLen);
2715  aEntry.mbMustDelete = true;
2716  }
2717  }
2718  break;
2719  }
2720  case PAP:
2721  {
2722  sal_uInt8 nDelta = 0;
2723 
2724  aEntry.mnLen = maRawData[nOfs];
2725  if (IsEightPlus(eVersion) && !aEntry.mnLen)
2726  {
2727  aEntry.mnLen = maRawData[nOfs+1];
2728  nDelta++;
2729  }
2730  aEntry.mnLen *= 2;
2731 
2732  //stylecode, std/istd
2733  if (eVersion <= ww::eWW2)
2734  {
2735  if (aEntry.mnLen >= 1)
2736  {
2737  aEntry.mnIStd = *(maRawData+nOfs+1+nDelta);
2738  aEntry.mnLen--; //style code
2739  if (aEntry.mnLen >= 6)
2740  {
2741  aEntry.mnLen-=6; //PHE
2742  //skip stc, len byte + 6 byte PHE
2743  unsigned int nOffset = nOfs + 8;
2744  if (nOffset >= 511) //Bad offset
2745  aEntry.mnLen=0;
2746  if (aEntry.mnLen) //start is ok
2747  {
2748  if (nOffset + aEntry.mnLen > 512) //Bad end, clip
2749  aEntry.mnLen = 512 - nOffset;
2750  aEntry.mpData = maRawData + nOffset;
2751  }
2752  }
2753  else
2754  aEntry.mnLen=0; //Too short
2755  }
2756  }
2757  else
2758  {
2759  if (aEntry.mnLen >= 2)
2760  {
2761  //len byte + optional extra len byte
2762  std::size_t nDataOffset = nOfs + 1 + nDelta;
2763  aEntry.mnIStd = nDataOffset <= sizeof(maRawData)-sizeof(aEntry.mnIStd) ?
2764  SVBT16ToUInt16(maRawData+nDataOffset) : 0;
2765  aEntry.mnLen-=2; //istd
2766  if (aEntry.mnLen)
2767  {
2768  //additional istd
2769  nDataOffset += sizeof(aEntry.mnIStd);
2770 
2771  FillEntry(aEntry, nDataOffset, aEntry.mnLen);
2772  }
2773  }
2774  else
2775  aEntry.mnLen=0; //Too short, ignore
2776  }
2777 
2778  const sal_uInt16 nSpId = aEntry.mnLen
2779  ? maSprmParser.GetSprmId(aEntry.mpData) : 0;
2780 
2781  /*
2782  If we replace then we throw away the old data, if we
2783  are expanding, then we tack the old data onto the end
2784  of the new data
2785  */
2786  const bool bExpand = IsExpandableSprm(nSpId);
2787  const sal_uInt8* pStartData
2788  = aEntry.mpData == nullptr ? nullptr : aEntry.mpData + 2;
2789  const sal_uInt8* pLastValidDataPos = maRawData + 512 - sizeof(sal_uInt32);
2790  if (pStartData != nullptr && pStartData > pLastValidDataPos)
2791  pStartData = nullptr;
2792  if ((IsReplaceAllSprm(nSpId) || bExpand) && pStartData)
2793  {
2794  sal_uInt32 nCurr = pDataSt->Tell();
2795  sal_uInt32 nPos = SVBT32ToUInt32(pStartData);
2796  sal_uInt16 nLen(0);
2797 
2798  bool bOk = checkSeek(*pDataSt, nPos);
2799  if (bOk)
2800  {
2801  pDataSt->ReadUInt16( nLen );
2802  bOk = nLen <= pDataSt->remainingSize();
2803  }
2804 
2805  if (bOk)
2806  {
2807  const sal_uInt16 nOrigLen = bExpand ? aEntry.mnLen : 0;
2808  sal_uInt8 *pOrigData = bExpand ? aEntry.mpData : nullptr;
2809 
2810  aEntry.mnLen = nLen;
2811  aEntry.mpData =
2812  new sal_uInt8[aEntry.mnLen + nOrigLen];
2813  aEntry.mbMustDelete = true;
2814  aEntry.mnLen =
2815  pDataSt->ReadBytes(aEntry.mpData, aEntry.mnLen);
2816 
2817  pDataSt->Seek( nCurr );
2818 
2819  if (pOrigData)
2820  {
2821  memcpy(aEntry.mpData + aEntry.mnLen,
2822  pOrigData, nOrigLen);
2823  aEntry.mnLen = aEntry.mnLen + nOrigLen;
2824  }
2825  }
2826  }
2827  }
2828  break;
2829  default:
2830  OSL_FAIL("sweet god, what have you done!");
2831  break;
2832  }
2833  }
2834 
2835  maEntries.push_back(aEntry);
2836 
2837 #ifdef DEBUGSPRMREADER
2838  {
2839  sal_Int32 nLen;
2840  sal_uInt8* pSprms = GetLenAndIStdAndSprms( nLen );
2841  WW8SprmIter aIter(pSprms, nLen, maSprmParser);
2842  while (aIter.GetSprms())
2843  {
2844  fprintf(stderr, "id is %x\n", aIter.GetCurrentId());
2845  aIter.advance();
2846  }
2847  }
2848 #endif
2849  }
2850 
2851  //one more FC than grrpl entries
2852  maEntries.emplace_back(Get_Long(pStart));
2853 
2854  //we expect them sorted, but it appears possible for them to arrive unsorted
2855  std::stable_sort(maEntries.begin(), maEntries.end());
2856 
2857  mnIdx = 0;
2858 
2859  if (nStartFc >= 0)
2860  SeekPos(nStartFc);
2861 
2862  pSt->Seek(nOldPos);
2863 }
2864 
2866  : mnFC(rEntry.mnFC), mnLen(rEntry.mnLen), mnIStd(rEntry.mnIStd),
2867  mbMustDelete(rEntry.mbMustDelete)
2868 {
2869  if (mbMustDelete)
2870  {
2871  mpData = new sal_uInt8[mnLen];
2872  memcpy(mpData, rEntry.mpData, mnLen);
2873  }
2874  else
2875  mpData = rEntry.mpData;
2876 }
2877 
2880 {
2881  if (this == &rEntry)
2882  return *this;
2883 
2884  if (mbMustDelete)
2885  delete[] mpData;
2886 
2887  mnFC = rEntry.mnFC;
2888  mnLen = rEntry.mnLen;
2889  mnIStd = rEntry.mnIStd;
2890  mbMustDelete = rEntry.mbMustDelete;
2891 
2892  if (rEntry.mbMustDelete)
2893  {
2894  mpData = new sal_uInt8[mnLen];
2895  memcpy(mpData, rEntry.mpData, mnLen);
2896  }
2897  else
2898  mpData = rEntry.mpData;
2899 
2900  return *this;
2901 }
2902 
2904 {
2905  if (mbMustDelete)
2906  delete[] mpData;
2907 }
2908 
2910 {
2911  SetIdx(0);
2912  if (nFc >= 0)
2913  SeekPos(nFc);
2914 }
2915 
2917 {
2918  if (nFc < maEntries[0].mnFC)
2919  {
2920  mnIdx = 0;
2921  return false; // not found: nPos less than smallest entry
2922  }
2923 
2924  // Search from beginning?
2925  if ((mnIdx < 1) || (nFc < maEntries[mnIdx - 1].mnFC))
2926  mnIdx = 1;
2927 
2928  sal_uInt8 nI = mnIdx;
2929  sal_uInt8 nEnd = mnIMax;
2930 
2931  for(sal_uInt8 n = (1==mnIdx ? 1 : 2); n; --n )
2932  {
2933  for( ; nI <=nEnd; ++nI)
2934  { // search with an index that is incremented by 1
2935  if (nFc < maEntries[nI].mnFC)
2936  { // found position
2937  mnIdx = nI - 1; // nI - 1 is the correct index
2938  return true; // done
2939  }
2940  }
2941  nI = 1;
2942  nEnd = mnIdx-1;
2943  }
2944  mnIdx = mnIMax; // not found, greater than all entries
2945  return false;
2946 }
2947 
2948 sal_uInt8* WW8PLCFx_Fc_FKP::WW8Fkp::Get(WW8_FC& rStart, WW8_FC& rEnd, sal_Int32& rLen)
2949  const
2950 {
2951  rLen = 0;
2952 
2953  if (mnIdx >= mnIMax)
2954  {
2955  rStart = WW8_FC_MAX;
2956  return nullptr;
2957  }
2958 
2959  rStart = maEntries[mnIdx].mnFC;
2960  rEnd = maEntries[mnIdx + 1].mnFC;
2961 
2962  sal_uInt8* pSprms = GetLenAndIStdAndSprms( rLen );
2963  return pSprms;
2964 }
2965 
2967 {
2968  if (nI < mnIMax)
2969  {
2970  mnIdx = nI;
2971  }
2972 }
2973 
2975 {
2976  rLen = maEntries[mnIdx].mnLen;
2977  return maEntries[mnIdx].mpData;
2978 }
2979 
2980 SprmResult WW8PLCFx_Fc_FKP::WW8Fkp::HasSprm( sal_uInt16 nId, bool bFindFirst )
2981 {
2982  if (mnIdx >= mnIMax)
2983  return SprmResult();
2984 
2985  sal_Int32 nLen;
2986  sal_uInt8* pSprms = GetLenAndIStdAndSprms( nLen );
2987 
2988  WW8SprmIter aIter(pSprms, nLen, maSprmParser);
2989  return aIter.FindSprm(nId, bFindFirst);
2990 }
2991 
2993  std::vector<SprmResult> &rResult)
2994 {
2995  if (mnIdx >= mnIMax)
2996  return;
2997 
2998  sal_Int32 nLen;
2999  sal_uInt8* pSprms = GetLenAndIStdAndSprms( nLen );
3000 
3001  WW8SprmIter aIter(pSprms, nLen, maSprmParser);
3002 
3003  while(aIter.GetSprms())
3004  {
3005  if (aIter.GetCurrentId() == nId)
3006  {
3007  sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId);
3008  sal_Int32 nL = maSprmParser.GetSprmSize(nId, aIter.GetSprms(), aIter.GetRemLen());
3009  rResult.emplace_back(aIter.GetCurrentParams(), nL - nFixedLen);
3010  }
3011  aIter.advance();
3012  };
3013 }
3014 
3016 {
3017  return mrFib.GetFIBVersion();
3018 }
3019 
3021 {
3022  OSL_ENSURE( false, "Called wrong GetSprms" );
3023  p->nStartPos = p->nEndPos = WW8_CP_MAX;
3024  p->pMemPos = nullptr;
3025  p->nSprmsLen = 0;
3026  p->bRealLineEnd = false;
3027 }
3028 
3029 tools::Long WW8PLCFx::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
3030 {
3031  OSL_ENSURE( false, "Called wrong GetNoSprms" );
3032  rStart = rEnd = WW8_CP_MAX;
3033  rLen = 0;
3034  return 0;
3035 }
3036 
3037 // ...Idx2: Default: ignore
3038 sal_uInt32 WW8PLCFx::GetIdx2() const
3039 {
3040  return 0;
3041 }
3042 
3043 void WW8PLCFx::SetIdx2(sal_uInt32)
3044 {
3045 }
3046 
3047 namespace {
3048 
3049 class SamePos
3050 {
3051 private:
3052  tools::Long mnPo;
3053 public:
3054  explicit SamePos(tools::Long nPo) : mnPo(nPo) {}
3055  bool operator()(const std::unique_ptr<WW8PLCFx_Fc_FKP::WW8Fkp>& pFkp)
3056  {return mnPo == pFkp->GetFilePos();}
3057 };
3058 
3059 }
3060 
3062 {
3063  WW8_CP nPLCFStart, nPLCFEnd;
3064  void* pPage;
3065 
3066  static const int WW8FkpSizeTabVer2[ PLCF_END ] =
3067  {
3068  1, 1, 0 /*, 0, 0, 0*/
3069  };
3070  static const int WW8FkpSizeTabVer6[ PLCF_END ] =
3071  {
3072  1, 7, 0 /*, 0, 0, 0*/
3073  };
3074  static const int WW8FkpSizeTabVer8[ PLCF_END ] =
3075  {
3076  1, 13, 0 /*, 0, 0, 0*/
3077  };
3078  const int* pFkpSizeTab;
3079 
3080  switch (GetFIBVersion())
3081  {
3082  case ww::eWW1:
3083  case ww::eWW2:
3084  pFkpSizeTab = WW8FkpSizeTabVer2;
3085  break;
3086  case ww::eWW6:
3087  case ww::eWW7:
3088  pFkpSizeTab = WW8FkpSizeTabVer6;
3089  break;
3090  case ww::eWW8:
3091  pFkpSizeTab = WW8FkpSizeTabVer8;
3092  break;
3093  default:
3094  // program error!
3095  OSL_ENSURE( false, "nVersion not implemented!" );
3096  return false;
3097  }
3098 
3099  if (!pPLCF->Get( nPLCFStart, nPLCFEnd, pPage ))
3100  {
3101  pFkp = nullptr;
3102  return false; // PLCF completely processed
3103  }
3104  pPLCF->advance();
3105  tools::Long nPo = SVBT16ToUInt16( static_cast<sal_uInt8 *>(pPage) );
3106  nPo <<= 9; // shift as LONG
3107 
3108  tools::Long nCurrentFkpFilePos = pFkp ? pFkp->GetFilePos() : -1;
3109  if (nCurrentFkpFilePos == nPo)
3110  pFkp->Reset(GetStartFc());
3111  else
3112  {
3113  auto aIter =
3114  std::find_if(maFkpCache.begin(), maFkpCache.end(), SamePos(nPo));
3115  if (aIter != maFkpCache.end())
3116  {
3117  pFkp = aIter->get();
3118  pFkp->Reset(GetStartFc());
3119  }
3120  else
3121  {
3122  pFkp = new WW8Fkp(GetFIB(), pFKPStrm, pDataStrm, nPo,
3123  pFkpSizeTab[ ePLCF ], ePLCF, GetStartFc());
3124  maFkpCache.push_back(std::unique_ptr<WW8Fkp>(pFkp));
3125 
3126  if (maFkpCache.size() > eMaxCache)
3127  {
3128  WW8Fkp* pCachedFkp = maFkpCache.front().get();
3129  if (!pCachedFkp->IsMustRemainCache())
3130  {
3131  maFkpCache.pop_front();
3132  }
3133  }
3134  }
3135  }
3136 
3137  SetStartFc( -1 ); // only the first time
3138  return true;
3139 }
3140 
3142  SvStream* pDataSt, const WW8Fib& rFib, ePLCFT ePl, WW8_FC nStartFcL)
3143  : WW8PLCFx(rFib, true), pFKPStrm(pSt), pDataStrm(pDataSt)
3144  , pFkp(nullptr), ePLCF(ePl)
3145 {
3146  SetStartFc(nStartFcL);
3147  tools::Long nLenStruct = (8 > rFib.m_nVersion) ? 2 : 4;
3148  if (ePl == CHP)
3149  {
3150  pPLCF.reset(new WW8PLCF(*pTableSt, rFib.m_fcPlcfbteChpx, rFib.m_lcbPlcfbteChpx,
3151  nLenStruct, GetStartFc(), rFib.m_pnChpFirst, rFib.m_cpnBteChp));
3152  }
3153  else
3154  {
3155  pPLCF.reset(new WW8PLCF(*pTableSt, rFib.m_fcPlcfbtePapx, rFib.m_lcbPlcfbtePapx,
3156  nLenStruct, GetStartFc(), rFib.m_pnPapFirst, rFib.m_cpnBtePap));
3157  }
3158 }
3159 
3161 {
3162  maFkpCache.clear();
3163  pPLCF.reset();
3164  pPCDAttrs.reset();
3165 }
3166 
3167 sal_uInt32 WW8PLCFx_Fc_FKP::GetIdx() const
3168 {
3169  sal_uInt32 u = pPLCF->GetIdx() << 8;
3170  if (pFkp)
3171  u |= pFkp->GetIdx();
3172  return u;
3173 }
3174 
3175 void WW8PLCFx_Fc_FKP::SetIdx(sal_uInt32 nIdx)
3176 {
3177  if( !( nIdx & 0xffffff00L ) )
3178  {
3179  pPLCF->SetIdx( nIdx >> 8 );
3180  pFkp = nullptr;
3181  }
3182  else
3183  { // there was a Fkp
3184  // Set PLCF one position back to retrieve the address of the Fkp
3185  pPLCF->SetIdx( ( nIdx >> 8 ) - 1 );
3186  if (NewFkp()) // read Fkp again
3187  {
3188  sal_uInt8 nFkpIdx = static_cast<sal_uInt8>(nIdx & 0xff);
3189  pFkp->SetIdx(nFkpIdx); // set Fkp-Pos again
3190  }
3191  }
3192 }
3193 
3195 {
3196  // StartPos for next Where()
3197  SetStartFc( nFcPos );
3198 
3199  // find StartPos for next pPLCF->Get()
3200  bool bRet = pPLCF->SeekPos(nFcPos);
3201 
3202  // make FKP invalid?
3203  WW8_CP nPLCFStart, nPLCFEnd;
3204  void* pPage;
3205  if( pFkp && pPLCF->Get( nPLCFStart, nPLCFEnd, pPage ) )
3206  {
3207  tools::Long nPo = SVBT16ToUInt16( static_cast<sal_uInt8 *>(pPage) );
3208  nPo <<= 9; // shift as LONG
3209  if (nPo != pFkp->GetFilePos())
3210  pFkp = nullptr;
3211  else
3212  pFkp->SeekPos( nFcPos );
3213  }
3214  return bRet;
3215 }
3216 
3218 {
3219  if( !pFkp && !NewFkp() )
3220  return WW8_FC_MAX;
3221  WW8_FC nP = pFkp ? pFkp->Where() : WW8_FC_MAX;
3222  if( nP != WW8_FC_MAX )
3223  return nP;
3224 
3225  pFkp = nullptr; // FKP finished -> get new
3226  return Where(); // easiest way: do it recursively
3227 }
3228 
3229 sal_uInt8* WW8PLCFx_Fc_FKP::GetSprmsAndPos(WW8_FC& rStart, WW8_FC& rEnd, sal_Int32& rLen)
3230 {
3231  rLen = 0; // Default
3232  rStart = rEnd = WW8_FC_MAX;
3233 
3234  if( !pFkp ) // Fkp not there ?
3235  {
3236  if( !NewFkp() )
3237  return nullptr;
3238  }
3239 
3240  sal_uInt8* pPos = pFkp ? pFkp->Get( rStart, rEnd, rLen ) : nullptr;
3241  if( rStart == WW8_FC_MAX ) //Not found
3242  return nullptr;
3243  return pPos;
3244 }
3245 
3247 {
3248  if( !pFkp && !NewFkp() )
3249  return;
3250 
3251  if (!pFkp)
3252  return;
3253 
3254  pFkp->advance();
3255  if( pFkp->Where() == WW8_FC_MAX )
3256  (void)NewFkp();
3257 }
3258 
3259 sal_uInt16 WW8PLCFx_Fc_FKP::GetIstd() const
3260 {
3261  return pFkp ? pFkp->GetIstd() : 0xFFFF;
3262 }
3263 
3265 {
3266  rDesc.pMemPos = nullptr;
3267  rDesc.nSprmsLen = 0;
3268  if( pPCDAttrs )
3269  {
3270  if( !pFkp )
3271  {
3272  OSL_FAIL("+Problem: GetPCDSprms: NewFkp necessary (not possible!)" );
3273  if( !NewFkp() )
3274  return;
3275  }
3276  pPCDAttrs->GetSprms(&rDesc);
3277  }
3278 }
3279 
3280 SprmResult WW8PLCFx_Fc_FKP::HasSprm(sal_uInt16 nId, bool bFindFirst)
3281 {
3282  // const would be nicer, but for that, NewFkp() would need to be replaced or eliminated
3283  if( !pFkp )
3284  {
3285  OSL_FAIL( "+Motz: HasSprm: NewFkp needed ( no const possible )" );
3286  // happens in BugDoc 31722
3287  if( !NewFkp() )
3288  return SprmResult();
3289  }
3290 
3291  if (!pFkp)
3292  return SprmResult();
3293 
3294  SprmResult aRes = pFkp->HasSprm(nId, bFindFirst);
3295 
3296  if (!aRes.pSprm)
3297  {
3298  WW8PLCFxDesc aDesc;
3299  GetPCDSprms( aDesc );
3300 
3301  if (aDesc.pMemPos)
3302  {
3303  WW8SprmIter aIter(aDesc.pMemPos, aDesc.nSprmsLen,
3304  pFkp->GetSprmParser());
3305  aRes = aIter.FindSprm(nId, bFindFirst);
3306  }
3307  }
3308 
3309  return aRes;
3310 }
3311 
3312 void WW8PLCFx_Fc_FKP::HasSprm(sal_uInt16 nId, std::vector<SprmResult> &rResult)
3313 {
3314  // const would be nicer, but for that, NewFkp() would need to be replaced or eliminated
3315  if (!pFkp)
3316  {
3317  OSL_FAIL( "+Motz: HasSprm: NewFkp needed ( no const possible )" );
3318  // happens in BugDoc 31722
3319  if( !NewFkp() )
3320  return;
3321  }
3322 
3323  if (!pFkp)
3324  return;
3325 
3326  pFkp->HasSprm(nId, rResult);
3327 
3328  WW8PLCFxDesc aDesc;
3329  GetPCDSprms( aDesc );
3330 
3331  if (!aDesc.pMemPos)
3332  return;
3333 
3334  const wwSprmParser &rSprmParser = pFkp->GetSprmParser();
3335  WW8SprmIter aIter(aDesc.pMemPos, aDesc.nSprmsLen, rSprmParser);
3336  while(aIter.GetSprms())
3337  {
3338  if (aIter.GetCurrentId() == nId)
3339  {
3340  sal_Int32 nFixedLen = rSprmParser.DistanceToData(nId);
3341  sal_Int32 nL = rSprmParser.GetSprmSize(nId, aIter.GetSprms(), aIter.GetRemLen());
3342  rResult.emplace_back(aIter.GetCurrentParams(), nL - nFixedLen);
3343  }
3344  aIter.advance();
3345  };
3346 }
3347 
3349  SvStream* pDataSt, const WW8ScannerBase& rBase, ePLCFT ePl )
3350  : WW8PLCFx_Fc_FKP(pSt, pTableSt, pDataSt, *rBase.m_pWw8Fib, ePl,
3351  rBase.WW8Cp2Fc(0)), rSBase(rBase), nAttrStart(-1), nAttrEnd(-1),
3352  bLineEnd(false),
3353  bComplex( (7 < rBase.m_pWw8Fib->m_nVersion) || rBase.m_pWw8Fib->m_fComplex )
3354 {
3356 
3357  if (rSBase.m_pPiecePLCF)
3358  pPcd.reset( new WW8PLCFx_PCD(GetFIB(), rBase.m_pPiecePLCF.get(), 0, IsSevenMinus(GetFIBVersion())) );
3359 
3360  /*
3361  Make a copy of the piece attributes for so that the calls to HasSprm on a
3362  Fc_FKP will be able to take into account the current piece attributes,
3363  despite the fact that such attributes can only be found through a cp based
3364  mechanism.
3365  */
3366  if (pPcd)
3367  {
3369  *rSBase.m_pWw8Fib, pPcd.get(), &rSBase) : nullptr);
3370  }
3371 
3372  pPieceIter = rSBase.m_pPieceIter.get();
3373 }
3374 
3376 {
3377 }
3378 
3380 {
3381  nAttrStart = -1;
3382  nAttrEnd = -1;
3383  bLineEnd = false;
3384 }
3385 
3386 sal_uInt32 WW8PLCFx_Cp_FKP::GetPCDIdx() const
3387 {
3388  return pPcd ? pPcd->GetIdx() : 0;
3389 }
3390 
3392 {
3393  if( pPcd ) // Complex
3394  {
3395  if( !pPcd->SeekPos( nCpPos ) ) // set piece
3396  return false;
3397  if (pPCDAttrs && !pPCDAttrs->GetIter()->SeekPos(nCpPos))
3398  return false;
3399  return WW8PLCFx_Fc_FKP::SeekPos(pPcd->CurrentPieceStartCp2Fc(nCpPos));
3400  }
3401  // NO piece table !!!
3402  return WW8PLCFx_Fc_FKP::SeekPos( rSBase.WW8Cp2Fc(nCpPos) );
3403 }
3404 
3406 {
3408  if( pPcd )
3409  return pPcd->CurrentPieceStartFc2Cp( nFc ); // identify piece
3410  return rSBase.WW8Fc2Cp( nFc ); // NO piece table !!!
3411 }
3412 
3414 {
3415  WW8_CP nOrigCp = p->nStartPos;
3416 
3417  if (!GetDirty()) //Normal case
3418  {
3420  p->nSprmsLen);
3421  }
3422  else
3423  {
3424  /*
3425  For the odd case where we have a location in a fastsaved file which
3426  does not have an entry in the FKP, perhaps its para end is in the next
3427  piece, or perhaps the cp just doesn't exist at all in this document.
3428  AdvSprm doesn't know so it sets the PLCF as dirty and we figure out
3429  in this method what the situation is
3430 
3431  It doesn't exist then the piece iterator will not be able to find it.
3432  Otherwise our cool fastsave algorithm can be brought to bear on the
3433  problem.
3434  */
3435  if( !pPieceIter )
3436  return;
3437  const sal_uInt32 nOldPos = pPieceIter->GetIdx();
3438  bool bOk = pPieceIter->SeekPos(nOrigCp);
3439  pPieceIter->SetIdx(nOldPos);
3440  if (!bOk)
3441  return;
3442  }
3443 
3444  if( pPcd ) // piece table available
3445  {
3446  // Init ( no ++ called, yet )
3447  if( (nAttrStart > nAttrEnd) || (nAttrStart == -1) )
3448  {
3449  p->bRealLineEnd = (ePLCF == PAP);
3450 
3451  if ( ((ePLCF == PAP ) || (ePLCF == CHP)) && (nOrigCp != WW8_CP_MAX) )
3452  {
3453  bool bIsUnicode=false;
3454  /*
3455  To find the end of a paragraph for a character in a
3456  complex format file.
3457 
3458  It is necessary to know the piece that contains the
3459  character and the FC assigned to the character.
3460  */
3461 
3462  //We set the piece iterator to the piece that contains the
3463  //character, now we have the correct piece for this character
3464  sal_uInt32 nOldPos = pPieceIter->GetIdx();
3465  p->nStartPos = nOrigCp;
3467 
3468  //This is the FC assigned to the character, but we already
3469  //have the result of the next stage, so we can skip this step
3470  //WW8_FC nStartFc = rSBase.WW8Cp2Fc(p->nStartPos, &bIsUnicode);
3471 
3472  /*
3473  Using the FC of the character, first search the FKP that
3474  describes the character to find the smallest FC in the rgfc
3475  that is larger than the character FC.
3476  */
3477  //But the search has already been done, the next largest FC is
3478  //p->nEndPos.
3479  WW8_FC nOldEndPos = p->nEndPos;
3480 
3481  /*
3482  If the FC found in the FKP is less than or equal to the limit
3483  FC of the piece, the end of the paragraph that contains the
3484  character is at the FKP FC minus 1.
3485  */
3486  WW8_CP nCpStart, nCpEnd;
3487  void* pData=nullptr;
3488  bool bOk = pPieceIter->Get(nCpStart, nCpEnd, pData);
3489 
3490  if (!bOk)
3491  {
3492  pPieceIter->SetIdx(nOldPos);
3493  return;
3494  }
3495 
3496  WW8_FC nLimitFC = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
3497  WW8_FC nBeginLimitFC = nLimitFC;
3498  if (IsEightPlus(GetFIBVersion()))
3499  {
3500  nBeginLimitFC =
3502  bIsUnicode);
3503  }
3504 
3505  WW8_CP nCpLen;
3506  bool bFail = o3tl::checked_sub(nCpEnd, nCpStart, nCpLen);
3507  if (bFail)
3508  {
3509  SAL_WARN("sw.ww8", "broken offset, ignoring");
3510  p->nStartPos = p->nEndPos = WW8_FC_MAX;
3511  pPieceIter->SetIdx(nOldPos);
3512  return;
3513  }
3514 
3515  if (bIsUnicode)
3516  {
3517  bFail = o3tl::checked_multiply<WW8_CP>(nCpLen, 2, nCpLen);
3518  if (bFail)
3519  {
3520  SAL_WARN("sw.ww8", "broken offset, ignoring");
3521  p->nStartPos = p->nEndPos = WW8_FC_MAX;
3522  pPieceIter->SetIdx(nOldPos);
3523  return;
3524  }
3525  }
3526 
3527  bFail = o3tl::checked_add(nBeginLimitFC, nCpLen, nLimitFC);
3528  if (bFail)
3529  {
3530  SAL_WARN("sw.ww8", "broken offset, ignoring");
3531  p->nStartPos = p->nEndPos = WW8_FC_MAX;
3532  pPieceIter->SetIdx(nOldPos);
3533  return;
3534  }
3535 
3536  if (nOldEndPos <= nLimitFC)
3537  {
3538  bFail = o3tl::checked_sub(nLimitFC, nOldEndPos, nCpLen);
3539  if (bFail)
3540  {
3541  SAL_WARN("sw.ww8", "broken offset, ignoring");
3542  p->nStartPos = p->nEndPos = WW8_FC_MAX;
3543  pPieceIter->SetIdx(nOldPos);
3544  return;
3545  }
3546 
3547  nCpLen /= (bIsUnicode ? 2 : 1);
3548 
3549  bFail = o3tl::checked_sub(nCpEnd, nCpLen, p->nEndPos);
3550  if (bFail)
3551  {
3552  SAL_WARN("sw.ww8", "broken offset, ignoring");
3553  p->nStartPos = p->nEndPos = WW8_FC_MAX;
3554  pPieceIter->SetIdx(nOldPos);
3555  return;
3556  }
3557  }
3558  else
3559  {
3560  if (ePLCF == CHP)
3561  p->nEndPos = nCpEnd;
3562  else
3563  {
3564  /*
3565  If the FKP FC that was found was greater than the FC
3566  of the end of the piece, scan piece by piece toward
3567  the end of the document until a piece is found that
3568  contains a paragraph end mark.
3569  */
3570 
3571  /*
3572  It's possible to check if a piece contains a paragraph
3573  mark by using the FC of the beginning of the piece to
3574  search in the FKPs for the smallest FC in the FKP rgfc
3575  that is greater than the FC of the beginning of the
3576  piece. If the FC found is less than or equal to the
3577  limit FC of the piece, then the character that ends
3578  the paragraph is the character immediately before the
3579  FKP fc
3580  */
3581 
3582  pPieceIter->advance();
3583 
3584  for (;pPieceIter->GetIdx() < pPieceIter->GetIMax();
3585  pPieceIter->advance())
3586  {
3587  if( !pPieceIter->Get( nCpStart, nCpEnd, pData ) )
3588  {
3589  OSL_ENSURE( false, "piece iter broken!" );
3590  break;
3591  }
3592  bIsUnicode = false;
3593  sal_Int32 nFcStart=SVBT32ToUInt32(static_cast<WW8_PCD*>(pData)->fc);
3594 
3595  if (IsEightPlus(GetFIBVersion()))
3596  {
3597  nFcStart =
3599  nFcStart,bIsUnicode );
3600  }
3601 
3602  bFail = o3tl::checked_sub(nCpEnd, nCpStart, nCpLen);
3603  if (bFail)
3604  {
3605  SAL_WARN("sw.ww8", "broken offset, ignoring");
3606  p->nStartPos = p->nEndPos = WW8_FC_MAX;
3607  continue;
3608  }
3609 
3610  if (bIsUnicode)
3611  {
3612  bFail = o3tl::checked_multiply<WW8_CP>(nCpLen, 2, nCpLen);
3613  if (bFail)
3614  {
3615  SAL_WARN("sw.ww8", "broken offset, ignoring");
3616  p->nStartPos = p->nEndPos = WW8_FC_MAX;
3617  continue;
3618  }
3619  }
3620 
3621  bFail = o3tl::checked_add(nFcStart, nCpLen, nLimitFC);
3622  if (bFail)
3623  {
3624  SAL_WARN("sw.ww8", "broken offset, ignoring");
3625  p->nStartPos = p->nEndPos = WW8_FC_MAX;
3626  continue;
3627  }
3628 
3629  //if it doesn't exist, skip it
3630  if (!SeekPos(nCpStart))
3631  continue;
3632 
3633  WW8_FC nOne,nSmallest;
3635  nSmallest, p->nSprmsLen);
3636 
3637  if (nSmallest <= nLimitFC)
3638  {
3639  WW8_CP nCpDiff;
3640  bFail = o3tl::checked_sub(nLimitFC, nSmallest, nCpDiff);
3641  if (bFail)
3642  {
3643  SAL_WARN("sw.ww8", "broken offset, ignoring");
3644  p->nStartPos = p->nEndPos = WW8_FC_MAX;
3645  continue;
3646  }
3647  if (bIsUnicode)
3648  nCpDiff /= 2;
3649 
3650  WW8_CP nEndPos;
3651  bFail = o3tl::checked_sub(nCpEnd, nCpDiff, nEndPos);
3652  if (bFail)
3653  {
3654  SAL_WARN("sw.ww8", "broken offset, ignoring");
3655  p->nStartPos = p->nEndPos = WW8_FC_MAX;
3656  continue;
3657  }
3658 
3659  OSL_ENSURE(nEndPos >= p->nStartPos, "EndPos before StartPos");
3660 
3661  if (nEndPos >= p->nStartPos)
3662  p->nEndPos = nEndPos;
3663 
3664  break;
3665  }
3666  }
3667  }
3668  }
3669  pPieceIter->SetIdx( nOldPos );
3670  }
3671  else
3673  }
3674  else
3675  {
3676  p->nStartPos = nAttrStart;
3677  p->nEndPos = nAttrEnd;
3678  p->bRealLineEnd = bLineEnd;
3679  }
3680  }
3681  else // NO piece table !!!
3682  {
3683  p->nStartPos = rSBase.WW8Fc2Cp( p->nStartPos );
3684  p->nEndPos = rSBase.WW8Fc2Cp( p->nEndPos );
3685  p->bRealLineEnd = ePLCF == PAP;
3686  }
3687 }
3688 
3690 {
3692  // !pPcd: emergency break
3693  if ( !bComplex || !pPcd )
3694  return;
3695 
3696  if( GetPCDIdx() >= pPcd->GetIMax() ) // End of PLCF
3697  {
3699  return;
3700  }
3701 
3702  sal_Int32 nFkpLen; // Fkp entry
3703  // get Fkp entry
3705 
3707  bLineEnd = (ePLCF == PAP);
3708 }
3709 
3711  const WW8Fib& rFib, WW8_CP nStartCp)
3712  : WW8PLCFx(rFib, true), maSprmParser(rFib),
3713  pStrm(pSt), nArrMax(256), nSprmSiz(0)
3714 {
3715  if (rFib.m_lcbPlcfsed)
3716  pPLCF.reset( new WW8PLCF(*pTableSt, rFib.m_fcPlcfsed, rFib.m_lcbPlcfsed,
3717  GetFIBVersion() <= ww::eWW2 ? 6 : 12, nStartCp) );
3718 
3719  pSprms.reset( new sal_uInt8[nArrMax] ); // maximum length
3720 }
3721 
3723 {
3724 }
3725 
3726 sal_uInt32 WW8PLCFx_SEPX::GetIdx() const
3727 {
3728  return pPLCF ? pPLCF->GetIdx() : 0;
3729 }
3730 
3731 void WW8PLCFx_SEPX::SetIdx(sal_uInt32 nIdx)
3732 {
3733  if( pPLCF ) pPLCF->SetIdx( nIdx );
3734 }
3735 
3737 {
3738  return pPLCF && pPLCF->SeekPos( nCpPos );
3739 }
3740 
3742 {
3743  return pPLCF ? pPLCF->Where() : 0;
3744 }
3745 
3747 {
3748  if( !pPLCF ) return;
3749 
3750  void* pData;
3751 
3752  p->bRealLineEnd = false;
3753  if (!pPLCF->Get( p->nStartPos, p->nEndPos, pData ))
3754  {
3755  p->nStartPos = p->nEndPos = WW8_CP_MAX; // PLCF completely processed
3756  p->pMemPos = nullptr;
3757  p->nSprmsLen = 0;
3758  }
3759  else
3760  {
3761  sal_uInt32 nPo = SVBT32ToUInt32( static_cast<sal_uInt8*>(pData)+2 );
3762  if (nPo == 0xFFFFFFFF || !checkSeek(*pStrm, nPo))
3763  {
3764  p->nStartPos = p->nEndPos = WW8_CP_MAX; // Sepx empty
3765  p->pMemPos = nullptr;
3766  p->nSprmsLen = 0;
3767  }
3768  else
3769  {
3770  // read len
3771  if (GetFIBVersion() <= ww::eWW2) // eWW6 ?, docs say yes, but...
3772  {
3773  sal_uInt8 nSiz(0);
3774  pStrm->ReadUChar( nSiz );
3775  nSprmSiz = nSiz;
3776  }
3777  else
3778  {
3780  }
3781 
3782  std::size_t nRemaining = pStrm->remainingSize();
3783  if (nSprmSiz > nRemaining)
3784  nSprmSiz = nRemaining;
3785 
3786  if( nSprmSiz > nArrMax )
3787  { // does not fit
3788  nArrMax = nSprmSiz; // Get more memory
3789  pSprms.reset( new sal_uInt8[nArrMax] );
3790  }
3791  nSprmSiz = pStrm->ReadBytes(pSprms.get(), nSprmSiz); // read Sprms
3792 
3793  p->nSprmsLen = nSprmSiz;
3794  p->pMemPos = pSprms.get(); // return Position
3795  }
3796  }
3797 }
3798 
3800 {
3801  if (pPLCF)
3802  pPLCF->advance();
3803 }
3804 
3805 SprmResult WW8PLCFx_SEPX::HasSprm(sal_uInt16 nId) const
3806 {
3807  return HasSprm(nId, pSprms.get(), nSprmSiz);
3808 }
3809 
3810 SprmResult WW8PLCFx_SEPX::HasSprm( sal_uInt16 nId, const sal_uInt8* pOtherSprms,
3811  tools::Long nOtherSprmSiz ) const
3812 {
3813  SprmResult aRet;
3814  if (pPLCF)
3815  {
3816  WW8SprmIter aIter(pOtherSprms, nOtherSprmSiz, maSprmParser);
3817  aRet = aIter.FindSprm(nId, /*bFindFirst=*/true);
3818  }
3819  return aRet;
3820 }
3821 
3822 bool WW8PLCFx_SEPX::Find4Sprms(sal_uInt16 nId1,sal_uInt16 nId2,sal_uInt16 nId3,sal_uInt16 nId4,
3823  SprmResult& r1, SprmResult& r2, SprmResult& r3, SprmResult& r4) const
3824 {
3825  if( !pPLCF )
3826  return false;
3827 
3828  bool bFound = false;
3829 
3830  sal_uInt8* pSp = pSprms.get();
3831  size_t i = 0;
3832  while (i + maSprmParser.MinSprmLen() <= nSprmSiz)
3833  {
3834  // Sprm found?
3835  const sal_uInt16 nCurrentId = maSprmParser.GetSprmId(pSp);
3836  sal_Int32 nRemLen = nSprmSiz - i;
3837  const sal_Int32 x = maSprmParser.GetSprmSize(nCurrentId, pSp, nRemLen);
3838  bool bValid = x <= nRemLen;
3839  if (!bValid)
3840  {
3841  SAL_WARN("sw.ww8", "sprm longer than remaining bytes, doc or parser is wrong");
3842  break;
3843  }
3844  bool bOk = true;
3845  if( nCurrentId == nId1 )
3846  {
3847  sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId1);
3848  r1 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3849  }
3850  else if( nCurrentId == nId2 )
3851  {
3852  sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId2);
3853  r2 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3854  }
3855  else if( nCurrentId == nId3 )
3856  {
3857  sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId3);
3858  r3 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3859  }
3860  else if( nCurrentId == nId4 )
3861  {
3862  sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId4);
3863  r4 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3864  }
3865  else
3866  bOk = false;
3867  bFound |= bOk;
3868  // increment pointer so that it points to next SPRM
3869  i += x;
3870  pSp += x;
3871  }
3872  return bFound;
3873 }
3874 
3875 SprmResult WW8PLCFx_SEPX::HasSprm( sal_uInt16 nId, sal_uInt8 n2nd ) const
3876 {
3877  SprmResult aRet;
3878  if (pPLCF)
3879  {
3880  WW8SprmIter aIter(pSprms.get(), nSprmSiz, maSprmParser);
3881  aRet = aIter.FindSprm(nId, /*bFindFirst=*/true, &n2nd);
3882  }
3883  return aRet;
3884 }
3885 
3887  WW8_CP nStartCp, tools::Long nFcRef, tools::Long nLenRef, tools::Long nFcText, tools::Long nLenText,
3888  tools::Long nStruct)
3889  : WW8PLCFx(rFib, true)
3890 {
3891  if( nLenRef && nLenText )
3892  {
3893  pRef.reset(new WW8PLCF(*pSt, nFcRef, nLenRef, nStruct, nStartCp));
3894  pText.reset(new WW8PLCF(*pSt, nFcText, nLenText, 0, nStartCp));
3895  }
3896 }
3897 
3899 {
3900  pRef.reset();
3901  pText.reset();
3902 }
3903 
3904 sal_uInt32 WW8PLCFx_SubDoc::GetIdx() const
3905 {
3906  // Probably pText ... no need for it
3907  if( pRef )
3908  return ( pRef->GetIdx() << 16 | pText->GetIdx() );
3909  return 0;
3910 }
3911 
3912 void WW8PLCFx_SubDoc::SetIdx(sal_uInt32 nIdx)
3913 {
3914  if( pRef )
3915  {
3916  pRef->SetIdx( nIdx >> 16 );
3917  // Probably pText ... no need for it
3918  pText->SetIdx( nIdx & 0xFFFF );
3919  }
3920 }
3921 
3923 {
3924  return pRef && pRef->SeekPos( nCpPos );
3925 }
3926 
3928 {
3929  return pRef ? pRef->Where() : WW8_CP_MAX;
3930 }
3931 
3933 {
3934  p->nStartPos = p->nEndPos = WW8_CP_MAX;
3935  p->pMemPos = nullptr;
3936  p->nSprmsLen = 0;
3937  p->bRealLineEnd = false;
3938 
3939  if (!pRef)
3940  return;
3941 
3942  sal_uInt32 nNr = pRef->GetIdx();
3943 
3944  void *pData;
3945  WW8_CP nFoo;
3946  if (!pRef->Get(p->nStartPos, nFoo, pData))
3947  {
3948  p->nEndPos = p->nStartPos = WW8_CP_MAX;
3949  return;
3950  }
3951 
3952  if (o3tl::checked_add<WW8_CP>(p->nStartPos, 1, p->nEndPos))
3953  {
3954  SAL_WARN("sw.ww8", "broken offset, ignoring");
3955  p->nEndPos = p->nStartPos = WW8_CP_MAX;
3956  return;
3957  }
3958 
3959  if (!pText)
3960  return;
3961 
3962  pText->SetIdx(nNr);
3963 
3964  if (!pText->Get(p->nCp2OrIdx, p->nSprmsLen, pData))
3965  {
3966  p->nEndPos = p->nStartPos = WW8_CP_MAX;
3967  p->nSprmsLen = 0;
3968  return;
3969  }
3970 
3971  if (p->nCp2OrIdx < 0 || p->nCp2OrIdx > p->nSprmsLen)
3972  {
3973  SAL_WARN("sw.ww8", "Document has invalid Cp or Idx, ignoring it");
3974  p->nEndPos = p->nStartPos = WW8_CP_MAX;
3975  p->nSprmsLen = 0;
3976  return;
3977  }
3978 
3979  p->nSprmsLen -= p->nCp2OrIdx;
3980 }
3981 
3983 {
3984  if (pRef && pText)
3985  {
3986  pRef->advance();
3987  pText->advance();
3988  }
3989 }
3990 
3991 // fields
3992 WW8PLCFx_FLD::WW8PLCFx_FLD( SvStream* pSt, const WW8Fib& rMyFib, short nType)
3993  : WW8PLCFx(rMyFib, true), rFib(rMyFib)
3994 {
3995  WW8_FC nFc;
3996  sal_Int32 nLen;
3997 
3998  switch( nType )
3999  {
4000  case MAN_HDFT:
4001  nFc = rFib.m_fcPlcffldHdr;
4002  nLen = rFib.m_lcbPlcffldHdr;
4003  break;
4004  case MAN_FTN:
4005  nFc = rFib.m_fcPlcffldFootnote;
4006  nLen = rFib.m_lcbPlcffldFootnote;
4007  break;
4008  case MAN_EDN:
4009  nFc = rFib.m_fcPlcffldEdn;
4010  nLen = rFib.m_lcbPlcffldEdn;
4011  break;
4012  case MAN_AND:
4013  nFc = rFib.m_fcPlcffldAtn;
4014  nLen = rFib.m_lcbPlcffldAtn;
4015  break;
4016  case MAN_TXBX:
4017  nFc = rFib.m_fcPlcffldTxbx;
4018  nLen = rFib.m_lcbPlcffldTxbx;
4019  break;
4020  case MAN_TXBX_HDFT:
4021  nFc = rFib.m_fcPlcffldHdrTxbx;
4022  nLen = rFib.m_lcbPlcffldHdrTxbx;
4023  break;
4024  default:
4025  nFc = rFib.m_fcPlcffldMom;
4026  nLen = rFib.m_lcbPlcffldMom;
4027  break;
4028  }
4029 
4030  if( nLen )
4031  pPLCF.reset( new WW8PLCFspecial( pSt, nFc, nLen, 2 ) );
4032 }
4033 
4035 {
4036 }
4037 
4038 sal_uInt32 WW8PLCFx_FLD::GetIdx() const
4039 {
4040  return pPLCF ? pPLCF->GetIdx() : 0;
4041 }
4042 
4043 void WW8PLCFx_FLD::SetIdx(sal_uInt32 nIdx)
4044 {
4045  if( pPLCF )
4046  pPLCF->SetIdx( nIdx );
4047 }
4048 
4050 {
4051  return pPLCF && pPLCF->SeekPosExact( nCpPos );
4052 }
4053 
4055 {
4056  return pPLCF ? pPLCF->Where() : WW8_CP_MAX;
4057 }
4058 
4060 {
4061  void* pData;
4062  sal_Int32 nTest;
4063  return pPLCF && pPLCF->Get(nTest, pData) && ((static_cast<sal_uInt8*>(pData)[0] & 0x1f) == 0x13);
4064 }
4065 
4067 {
4068  bool bRet = false;
4069 
4070  if (pPLCF)
4071  {
4072  tools::Long n = pPLCF->GetIdx();
4073 
4074  pPLCF->advance();
4075 
4076  void* pData;
4077  sal_Int32 nTest;
4078  if ( pPLCF->Get(nTest, pData) && ((static_cast<sal_uInt8*>(pData)[0] & 0x1f) == 0x15) )
4079  {
4080  nCP = nTest;
4081  bRet = true;
4082  }
4083 
4084  pPLCF->SetIdx(n);
4085  }
4086 
4087  return bRet;
4088 }
4089 
4091 {
4092  p->nStartPos = p->nEndPos = WW8_CP_MAX;
4093  p->pMemPos = nullptr;
4094  p->nSprmsLen = 0;
4095  p->bRealLineEnd = false;
4096 
4097  if (!pPLCF)
4098  {
4099  p->nStartPos = WW8_CP_MAX; // there are no fields
4100  return;
4101  }
4102 
4103  tools::Long n = pPLCF->GetIdx();
4104 
4105  sal_Int32 nP;
4106  void *pData;
4107  if (!pPLCF->Get(nP, pData)) // end of PLCFspecial?
4108  {
4109  p->nStartPos = WW8_CP_MAX; // PLCF completely processed
4110  return;
4111  }
4112 
4113  p->nStartPos = nP;
4114 
4115  pPLCF->advance();
4116  if (!pPLCF->Get(nP, pData)) // end of PLCFspecial?
4117  {
4118  p->nStartPos = WW8_CP_MAX; // PLCF completely processed
4119  return;
4120  }
4121 
4122  p->nEndPos = nP;
4123 
4124  pPLCF->SetIdx(n);
4125 
4126  p->nCp2OrIdx = pPLCF->GetIdx();
4127 }
4128 
4130 {
4131  SAL_WARN_IF(!pPLCF, "sw.ww8", "Call without PLCFspecial field");
4132  if( !pPLCF )
4133  return;
4134  pPLCF->advance();
4135 }
4136 
4138 {
4139  SAL_WARN_IF(!pPLCF, "sw.ww8", "Call without PLCFspecial field");
4140  if( !pPLCF )
4141  return false;
4142 
4143  tools::Long n = pPLCF->GetIdx();
4144  pPLCF->SetIdx(nIdx);
4145 
4146  bool bOk = WW8GetFieldPara(*pPLCF, rF);
4147 
4148  pPLCF->SetIdx(n);
4149  return bOk;
4150 }
4151 
4152 // WW8PLCF_Book
4153 void WW8ReadSTTBF(bool bVer8, SvStream& rStrm, sal_uInt32 nStart, sal_Int32 nLen,
4154  sal_uInt16 nExtraLen, rtl_TextEncoding eCS, std::vector<OUString> &rArray,
4155  std::vector<ww::bytes>* pExtraArray, std::vector<OUString>* pValueArray)
4156 {
4157  if (nLen==0) // Handle Empty STTBF
4158  return;
4159 
4160  sal_uInt64 const nOldPos = rStrm.Tell();
4161  if (checkSeek(rStrm, nStart))
4162  {
4163  sal_uInt16 nLen2(0);
4164  rStrm.ReadUInt16( nLen2 ); // bVer67: total length of structure
4165  // bVer8 : count of strings
4166 
4167  if( bVer8 )
4168  {
4169  sal_uInt16 nStrings(0);
4170  bool bUnicode = (0xFFFF == nLen2);
4171  if (bUnicode)
4172  rStrm.ReadUInt16( nStrings );
4173  else
4174  nStrings = nLen2;
4175 
4176  rStrm.ReadUInt16( nExtraLen );
4177 
4178  const size_t nMinStringLen = bUnicode ? sizeof(sal_uInt16) : sizeof(sal_uInt8);
4179  const size_t nMinRecordSize = nExtraLen + nMinStringLen;
4180  assert(nMinRecordSize != 0 && "impossible to be zero");
4181  const size_t nMaxPossibleStrings = rStrm.remainingSize() / nMinRecordSize;
4182  if (nStrings > nMaxPossibleStrings)
4183  {
4184  SAL_WARN("sw.ww8", "STTBF claims " << nStrings << " entries, but only " << nMaxPossibleStrings << " are possible");
4185  nStrings = nMaxPossibleStrings;
4186  }
4187 
4188  if (nExtraLen && nStrings)
4189  {
4190  const size_t nMaxExtraLen = (rStrm.remainingSize() - (nStrings * nMinStringLen)) / nStrings;
4191  if (nExtraLen > nMaxExtraLen)
4192  {
4193  SAL_WARN("sw.ww8", "STTBF claims " << nMaxExtraLen << " extra len, but only " << nMaxExtraLen << " are possible");
4194  nExtraLen = nMaxExtraLen;
4195  }
4196  }
4197 
4198  for (sal_uInt16 i=0; i < nStrings; ++i)
4199  {
4200  if (bUnicode)
4201  rArray.push_back(read_uInt16_PascalString(rStrm));
4202  else
4203  {
4204  OString aTmp = read_uInt8_lenPrefixed_uInt8s_ToOString(rStrm);
4205  rArray.push_back(OStringToOUString(aTmp, eCS));
4206  }
4207 
4208  // Skip the extra data
4209  if (nExtraLen)
4210  {
4211  if (pExtraArray)
4212  {
4213  ww::bytes extraData(nExtraLen);
4214  rStrm.ReadBytes(extraData.data(), nExtraLen);
4215  pExtraArray->push_back(extraData);
4216  }
4217  else
4218  rStrm.SeekRel( nExtraLen );
4219  }
4220  }
4221  // read the value of the document variables, if requested.
4222  if (pValueArray)
4223  {
4224  for (sal_uInt16 i=0; i < nStrings; ++i)
4225  {
4226  if( bUnicode )
4227  pValueArray->push_back(read_uInt16_PascalString(rStrm));
4228  else
4229  {
4230  OString aTmp = read_uInt8_lenPrefixed_uInt8s_ToOString(rStrm);
4231  pValueArray->push_back(OStringToOUString(aTmp, eCS));
4232  }
4233  }
4234  }
4235  }
4236  else
4237  {
4238  if( nLen2 != nLen )
4239  {
4240  OSL_ENSURE(nLen2 == nLen,
4241  "Fib length and read length are different");
4242  if (nLen > SAL_MAX_UINT16)
4243  nLen = SAL_MAX_UINT16;
4244  else if (nLen < 2 )
4245  nLen = 2;
4246  nLen2 = o3tl::narrowing<sal_uInt16>(nLen);
4247  }
4248  sal_uLong nRead = 0;
4249  for( nLen2 -= 2; nRead < nLen2; )
4250  {
4251  sal_uInt8 nBChar(0);
4252  rStrm.ReadUChar( nBChar );
4253  ++nRead;
4254  if (nBChar)
4255  {
4256  OString aTmp = read_uInt8s_ToOString(rStrm, nBChar);
4257  nRead += aTmp.getLength();
4258  rArray.push_back(OStringToOUString(aTmp, eCS));
4259  }
4260  else
4261  rArray.emplace_back();
4262 
4263  // Skip the extra data (for bVer67 versions this must come from
4264  // external knowledge)
4265  if (nExtraLen)
4266  {
4267  if (pExtraArray)
4268  {
4269  ww::bytes extraData(nExtraLen);
4270  rStrm.ReadBytes(extraData.data(), nExtraLen);
4271  pExtraArray->push_back(extraData);
4272  }
4273  else
4274  rStrm.SeekRel( nExtraLen );
4275  nRead+=nExtraLen;
4276  }
4277  }
4278  }
4279  }
4280  rStrm.Seek(nOldPos);
4281 }
4282 
4284  : WW8PLCFx(rFib, false), nIsEnd(0), nBookmarkId(1)
4285 {
4286  if( !rFib.m_fcPlcfbkf || !rFib.m_lcbPlcfbkf || !rFib.m_fcPlcfbkl ||
4287  !rFib.m_lcbPlcfbkl || !rFib.m_fcSttbfbkmk || !rFib.m_lcbSttbfbkmk )
4288  {
4289  nIMax = 0;
4290  }
4291  else
4292  {
4293  pBook[0].reset( new WW8PLCFspecial(pTableSt,rFib.m_fcPlcfbkf,rFib.m_lcbPlcfbkf,4) );
4294 
4295  pBook[1].reset( new WW8PLCFspecial(pTableSt,rFib.m_fcPlcfbkl,rFib.m_lcbPlcfbkl,0) );
4296 
4297  rtl_TextEncoding eStructChrSet = WW8Fib::GetFIBCharset(rFib.m_chseTables, rFib.m_lid);
4298 
4299  WW8ReadSTTBF( (7 < rFib.m_nVersion), *pTableSt, rFib.m_fcSttbfbkmk,
4300  rFib.m_lcbSttbfbkmk, 0, eStructChrSet, aBookNames );
4301 
4302  nIMax = aBookNames.size();
4303 
4304  if( pBook[0]->GetIMax() < nIMax ) // Count of Bookmarks
4305  nIMax = pBook[0]->GetIMax();
4306  if( pBook[1]->GetIMax() < nIMax )
4307  nIMax = pBook[1]->GetIMax();
4308  aStatus.resize(nIMax);
4309  }
4310 }
4311 
4313 {
4314 }
4315 
4316 sal_uInt32 WW8PLCFx_Book::GetIdx() const
4317 {
4318  return nIMax ? pBook[0]->GetIdx() : 0;
4319 }
4320 
4321 void WW8PLCFx_Book::SetIdx(sal_uInt32 nI)
4322 {
4323  if( nIMax )
4324  pBook[0]->SetIdx( nI );
4325 }
4326 
4327 sal_uInt32 WW8PLCFx_Book::GetIdx2() const
4328 {
4329  return nIMax ? ( pBook[1]->GetIdx() | ( nIsEnd ? 0x80000000 : 0 ) ) : 0;
4330 }
4331 
4332 void WW8PLCFx_Book::SetIdx2(sal_uInt32 nI)
4333 {
4334  if( nIMax )
4335  {
4336  pBook[1]->SetIdx( nI & 0x7fffffff );
4337  nIsEnd = o3tl::narrowing<sal_uInt16>( ( nI >> 31 ) & 1 ); // 0 or 1
4338  }
4339 }
4340 
4342 {
4343  if( !pBook[0] )
4344  return false;
4345 
4346  bool bOk = pBook[0]->SeekPosExact( nCpPos );
4347  bOk &= pBook[1]->SeekPosExact( nCpPos );
4348  nIsEnd = 0;
4349 
4350  return bOk;
4351 }
4352 
4354 {
4355  return pBook[nIsEnd]->Where();
4356 }
4357 
4358 tools::Long WW8PLCFx_Book::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
4359 {
4360  void* pData;
4361  rEnd = WW8_CP_MAX;
4362  rLen = 0;
4363 
4364  if (!pBook[0] || !pBook[1] || !nIMax || (pBook[nIsEnd]->GetIdx()) >= nIMax)
4365  {
4366  rStart = rEnd = WW8_CP_MAX;
4367  return -1;
4368  }
4369 
4370  (void)pBook[nIsEnd]->Get( rStart, pData ); // query position
4371  return pBook[nIsEnd]->GetIdx();
4372 }
4373 
4374 // The operator ++ has a pitfall: If 2 bookmarks adjoin each other,
4375 // we should first go to the end of the first one
4376 // and then to the beginning of the second one.
4377 // But if 2 bookmarks with the length of 0 lie on top of each other,
4378 // we *must* first find the start and end of each bookmark.
4379 // The case of: ][
4380 // [...]
4381 // ][
4382 // is not solved yet.
4383 // Because I must jump back and forth in the start- and end-indices then.
4384 // This would require one more index or bitfield to remember
4385 // the already processed bookmarks.
4386 
4388 {
4389  if( !(pBook[0] && pBook[1] && nIMax) )
4390  return;
4391 
4392  (*pBook[nIsEnd]).advance();
4393 
4394  sal_uLong l0 = pBook[0]->Where();
4395  sal_uLong l1 = pBook[1]->Where();
4396  if( l0 < l1 )
4397  nIsEnd = 0;
4398  else if( l1 < l0 )
4399  nIsEnd = 1;
4400  else
4401  {
4402  const void * p = pBook[0]->GetData(pBook[0]->GetIdx());
4403  tools::Long nPairFor = (p == nullptr) ? 0 : SVBT16ToUInt16(*static_cast<SVBT16 const *>(p));
4404  if (nPairFor == pBook[1]->GetIdx())
4405  nIsEnd = 0;
4406  else
4407  nIsEnd = nIsEnd ? 0 : 1;
4408  }
4409 }
4410 
4412 {
4413  if( nIsEnd )
4414  {
4415  OSL_ENSURE( false, "Incorrect call (1) of PLCF_Book::GetLen()" );
4416  return 0;
4417  }
4418  void * p;
4419  WW8_CP nStartPos;
4420  if( !pBook[0]->Get( nStartPos, p ) )
4421  {
4422  OSL_ENSURE( false, "Incorrect call (2) of PLCF_Book::GetLen()" );
4423  return 0;
4424  }
4425  const sal_uInt16 nEndIdx = SVBT16ToUInt16( *static_cast<SVBT16*>(p) );
4426  tools::Long nNum = pBook[1]->GetPos( nEndIdx );
4427  nNum -= nStartPos;
4428  return nNum;
4429 }
4430 
4431 void WW8PLCFx_Book::SetStatus(sal_uInt16 nIndex, eBookStatus eStat)
4432 {
4433  SAL_WARN_IF(nIndex >= nIMax, "sw.ww8",
4434  "bookmark index " << nIndex << " invalid");
4435  eBookStatus eStatus = aStatus.at(nIndex);
4436  aStatus[nIndex] = static_cast<eBookStatus>(eStatus | eStat);
4437 }
4438 
4440 {
4441  if (aStatus.empty())
4442  return BOOK_NORMAL;
4443  tools::Long nEndIdx = GetHandle();
4444  return ( nEndIdx < nIMax ) ? aStatus[nEndIdx] : BOOK_NORMAL;
4445 }
4446 
4448 {
4449  if( !pBook[0] || !pBook[1] )
4450  return LONG_MAX;
4451 
4452  if( nIsEnd )
4453  return pBook[1]->GetIdx();
4454  else
4455  {
4456  if (const void* p = pBook[0]->GetData(pBook[0]->GetIdx()))
4457  return SVBT16ToUInt16( *static_cast<SVBT16 const *>(p) );
4458  else
4459  return LONG_MAX;
4460  }
4461 }
4462 
4463 OUString WW8PLCFx_Book::GetBookmark(tools::Long nStart,tools::Long nEnd, sal_uInt16 &nIndex)
4464 {
4465  bool bFound = false;
4466  sal_uInt16 i = 0;
4467  if (pBook[0] && pBook[1])
4468  {
4469  WW8_CP nStartCurrent, nEndCurrent;
4470  while (sal::static_int_cast<decltype(aBookNames)::size_type>(i) < aBookNames.size())
4471  {
4472  void* p;
4473  sal_uInt16 nEndIdx;
4474 
4475  if( pBook[0]->GetData( i, nStartCurrent, p ) && p )
4476  nEndIdx = SVBT16ToUInt16( *static_cast<SVBT16*>(p) );
4477  else
4478  {
4479  OSL_ENSURE( false, "Bookmark-EndIdx not readable" );
4480  nEndIdx = i;
4481  }
4482 
4483  nEndCurrent = pBook[1]->GetPos( nEndIdx );
4484 
4485  if ((nStartCurrent >= nStart) && (nEndCurrent <= nEnd))
4486  {
4487  nIndex = i;
4488  bFound=true;
4489  break;
4490  }
4491  ++i;
4492  }
4493  }
4494  return bFound ? aBookNames[i] : OUString();
4495 }
4496 
4497 OUString WW8PLCFx_Book::GetUniqueBookmarkName(const OUString &rSuggestedName)
4498 {
4499  OUString aRet(rSuggestedName.isEmpty() ? OUString("Unnamed") : rSuggestedName);
4500  size_t i = 0;
4501  while (i < aBookNames.size())
4502  {
4503  if (aRet == aBookNames[i])
4504  {
4505  sal_Int32 len = aRet.getLength();
4506  sal_Int32 p = len - 1;
4507  while (p > 0 && aRet[p] >= '0' && aRet[p] <= '9')
4508  --p;
4509  aRet = aRet.subView(0, p+1) + OUString::number(nBookmarkId++);
4510  i = 0; // start search from beginning
4511  }
4512  else
4513  ++i;
4514  }
4515  return aRet;
4516 }
4517 
4518 void WW8PLCFx_Book::MapName(OUString& rName)
4519 {
4520  if( !pBook[0] || !pBook[1] )
4521  return;
4522 
4523  size_t i = 0;
4524  while (i < aBookNames.size())
4525  {
4526  if (rName.equalsIgnoreAsciiCase(aBookNames[i]))
4527  {
4528  rName = aBookNames[i];
4529  break;
4530  }
4531  ++i;
4532  }
4533 }
4534 
4535 const OUString* WW8PLCFx_Book::GetName() const
4536 {
4537  const OUString *pRet = nullptr;
4538  if (!nIsEnd && (pBook[0]->GetIdx() < nIMax))
4539  pRet = &(aBookNames[pBook[0]->GetIdx()]);
4540  return pRet;
4541 }
4542 
4544  : WW8PLCFx(rFib, /*bSprm=*/false),
4545  m_bIsEnd(false)
4546 {
4547  if (!rFib.m_fcPlcfAtnbkf || !rFib.m_lcbPlcfAtnbkf || !rFib.m_fcPlcfAtnbkl || !rFib.m_lcbPlcfAtnbkl)
4548  {
4549  nIMax = 0;
4550  }
4551  else
4552  {
4553  m_pBook[0].reset( new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfAtnbkf, rFib.m_lcbPlcfAtnbkf, 4) );
4554  m_pBook[1].reset( new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfAtnbkl, rFib.m_lcbPlcfAtnbkl, 0) );
4555 
4556  nIMax = m_pBook[0]->GetIMax();
4557  if (m_pBook[1]->GetIMax() < nIMax)
4558  nIMax = m_pBook[1]->GetIMax();
4559  }
4560 }
4561 
4563 {
4564 }
4565 
4566 sal_uInt32 WW8PLCFx_AtnBook::GetIdx() const
4567 {
4568  return nIMax ? m_pBook[0]->GetIdx() : 0;
4569 }
4570 
4571 void WW8PLCFx_AtnBook::SetIdx(sal_uInt32 nI)
4572 {
4573  if( nIMax )
4574  m_pBook[0]->SetIdx( nI );
4575 }
4576 
4577 sal_uInt32 WW8PLCFx_AtnBook::GetIdx2() const
4578 {
4579  if (nIMax)
4580  return m_pBook[1]->GetIdx() | ( m_bIsEnd ? 0x80000000 : 0 );
4581  else
4582  return 0;
4583 }
4584 
4585 void WW8PLCFx_AtnBook::SetIdx2(sal_uInt32 nI)
4586 {
4587  if( nIMax )
4588  {
4589  m_pBook[1]->SetIdx( nI & 0x7fffffff );
4590  m_bIsEnd = static_cast<bool>(( nI >> 31 ) & 1);
4591  }
4592 }
4593 
4595 {
4596  if (!m_pBook[0])
4597  return false;
4598 
4599  bool bOk = m_pBook[0]->SeekPosExact(nCpPos);
4600  bOk &= m_pBook[1]->SeekPosExact(nCpPos);
4601  m_bIsEnd = false;
4602 
4603  return bOk;
4604 }
4605 
4607 {
4608  return m_pBook[static_cast<int>(m_bIsEnd)]->Where();
4609 }
4610 
4611 tools::Long WW8PLCFx_AtnBook::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
4612 {
4613  void* pData;
4614  rEnd = WW8_CP_MAX;
4615  rLen = 0;
4616 
4617  if (!m_pBook[0] || !m_pBook[1] || !nIMax || (m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx()) >= nIMax)
4618  {
4619  rStart = rEnd = WW8_CP_MAX;
4620  return -1;
4621  }
4622 
4623  (void)m_pBook[static_cast<int>(m_bIsEnd)]->Get(rStart, pData);
4624  return m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx();
4625 }
4626 
4628 {
4629  if( !(m_pBook[0] && m_pBook[1] && nIMax) )
4630  return;
4631 
4632  (*m_pBook[static_cast<int>(m_bIsEnd)]).advance();
4633 
4634  sal_uLong l0 = m_pBook[0]->Where();
4635  sal_uLong l1 = m_pBook[1]->Where();
4636  if( l0 < l1 )
4637  m_bIsEnd = false;
4638  else if( l1 < l0 )
4639  m_bIsEnd = true;
4640  else
4641  {
4642  const void * p = m_pBook[0]->GetData(m_pBook[0]->GetIdx());
4643  tools::Long nPairFor = (p == nullptr) ? 0 : SVBT16ToUInt16(*static_cast<SVBT16 const *>(p));
4644  if (nPairFor == m_pBook[1]->GetIdx())
4645  m_bIsEnd = false;
4646  else
4647  m_bIsEnd = !m_bIsEnd;
4648  }
4649 }
4650 
4652 {
4653  if (!m_pBook[0] || !m_pBook[1])
4654  return LONG_MAX;
4655 
4656  if (m_bIsEnd)
4657  return m_pBook[1]->GetIdx();
4658  else
4659  {
4660  if (const void* p = m_pBook[0]->GetData(m_pBook[0]->GetIdx()))
4661  return SVBT16ToUInt16(*static_cast<const SVBT16*>(p));
4662  else
4663  return LONG_MAX;
4664  }
4665 }
4666 
4668 {
4669  return m_bIsEnd;
4670 }
4671 
4673  : WW8PLCFx(rFib, /*bSprm=*/false),
4674  m_bIsEnd(false)
4675 {
4677  {
4678  m_nIMax = 0;
4679  }
4680  else
4681  {
4682  m_pBook[0].reset(new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfBkfFactoid, rFib.m_lcbPlcfBkfFactoid, 6));
4683  m_pBook[1].reset(new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfBklFactoid, rFib.m_lcbPlcfBklFactoid, 4));
4684 
4685  m_nIMax = m_pBook[0]->GetIMax();
4686  if (m_pBook[1]->GetIMax() < m_nIMax)
4687  m_nIMax = m_pBook[1]->GetIMax();
4688  }
4689 }
4690 
4692 {
4693 }
4694 
4696 {
4697  return m_nIMax ? m_pBook[0]->GetIdx() : 0;
4698 }
4699 
4700 void WW8PLCFx_FactoidBook::SetIdx(sal_uInt32 nI)
4701 {
4702  if (m_nIMax)
4703  m_pBook[0]->SetIdx(nI);
4704 }
4705 
4707 {
4708  if (m_nIMax)
4709  return m_pBook[1]->GetIdx() | (m_bIsEnd ? 0x80000000 : 0);
4710  else
4711  return 0;
4712 }
4713 
4715 {
4716  if (m_nIMax)
4717  {
4718  m_pBook[1]->SetIdx(nI & 0x7fffffff);
4719  m_bIsEnd = static_cast<bool>((nI >> 31) & 1);
4720  }
4721 }
4722 
4724 {
4725  if (!m_pBook[0])
4726  return false;
4727 
4728  bool bOk = m_pBook[0]->SeekPosExact(nCpPos);
4729  bOk &= m_pBook[1]->SeekPosExact(nCpPos);
4730  m_bIsEnd = false;
4731 
4732  return bOk;
4733 }
4734 
4736 {
4737  return m_pBook[static_cast<int>(m_bIsEnd)]->Where();
4738 }
4739 
4741 {
4742  void* pData;
4743  rEnd = WW8_CP_MAX;
4744  rLen = 0;
4745 
4746  if (!m_pBook[0] || !m_pBook[1] || !m_nIMax || (m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx()) >= m_nIMax)
4747  {
4748  rStart = rEnd = WW8_CP_MAX;
4749  return -1;
4750  }
4751 
4752  (void)m_pBook[static_cast<int>(m_bIsEnd)]->Get(rStart, pData);
4753  return m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx();
4754 }
4755 
4757 {
4758  if (!(m_pBook[0] && m_pBook[1] && m_nIMax))
4759  return;
4760 
4761  (*m_pBook[static_cast<int>(m_bIsEnd)]).advance();
4762 
4763  sal_uLong l0 = m_pBook[0]->Where();
4764  sal_uLong l1 = m_pBook[1]->Where();
4765  if (l0 < l1)
4766  m_bIsEnd = false;
4767  else if (l1 < l0)
4768  m_bIsEnd = true;
4769  else
4770  {
4771  const void * p = m_pBook[0]->GetData(m_pBook[0]->GetIdx());
4772  tools::Long nPairFor = (p == nullptr) ? 0 : SVBT16ToUInt16(*static_cast<SVBT16 const *>(p));
4773  if (nPairFor == m_pBook[1]->GetIdx())
4774  m_bIsEnd = false;
4775  else
4776  m_bIsEnd = !m_bIsEnd;
4777  }
4778 }
4779 
4781 {
4782  if (!m_pBook[0] || !m_pBook[1])
4783  return LONG_MAX;
4784 
4785  if (m_bIsEnd)
4786  return m_pBook[1]->GetIdx();
4787  else
4788  {
4789  if (const void* p = m_pBook[0]->GetData(m_pBook[0]->GetIdx()))
4790  return SVBT16ToUInt16(*static_cast<const SVBT16*>(p));
4791  else
4792  return LONG_MAX;
4793  }
4794 }
4795 
4797 {
4798  return m_bIsEnd;
4799 }
4800 
4801 // In the end of a paragraph in WW6 the attribute extends after the <CR>.
4802 // This will be reset by one character to be used with SW,
4803 // if we don't expect trouble thereby.
4805 {
4806  // might be necessary to do this for pChp and/or pSep as well,
4807  // but its definitely the case for paragraphs that EndPos > StartPos
4808  // for a well formed paragraph as those always have a paragraph
4809  // <cr> in them
4810  if (&rDesc == m_pPap && rDesc.bRealLineEnd)
4811  {
4812  if (rDesc.nStartPos == rDesc.nEndPos && rDesc.nEndPos != WW8_CP_MAX)
4813  {
4814  SAL_WARN("sw.ww8", "WW8PLCFxDesc End same as Start, abandoning to avoid looping");
4815  rDesc.nEndPos = WW8_CP_MAX;
4816  }
4817  }
4818 
4819  //Store old end position for supercool new property finder that uses
4820  //cp instead of fc's as nature intended
4821  rDesc.nOrigEndPos = rDesc.nEndPos;
4822  rDesc.nOrigStartPos = rDesc.nStartPos;
4823 
4824  /*
4825  Normally given ^XXX{para end}^ we don't actually insert a para end
4826  character into the document, so we clip the para end property one to the
4827  left to make the para properties end when the paragraph text does. In a
4828  drawing textbox we actually do insert a para end character, so we don't
4829  clip it. Making the para end properties end after the para end char.
4830  */
4831  if (GetDoingDrawTextBox())
4832  return;
4833 
4834  if ( (&rDesc == m_pPap) && rDesc.bRealLineEnd )
4835  {
4836  if ( m_pPap->nEndPos != WW8_CP_MAX ) // Para adjust
4837  {
4838  m_nLineEnd = m_pPap->nEndPos;// nLineEnd points *after* the <CR>
4839  m_pPap->nEndPos--; // shorten paragraph end by one character
4840 
4841  // Is there already a sep end, which points to the current paragraph end?
4842  // Then we also must shorten by one character
4843  if( m_pSep->nEndPos == m_nLineEnd )
4844  m_pSep->nEndPos--;
4845  }
4846  }
4847  else if (&rDesc == m_pSep)
4848  {
4849  // Sep Adjust if end Char-Attr == paragraph end ...
4850  if( (rDesc.nEndPos == m_nLineEnd) && (rDesc.nEndPos > rDesc.nStartPos) )
4851  rDesc.nEndPos--; // ... then shorten by one character
4852  }
4853 }
4854 
4856 {
4857  SAL_WARN_IF(WW8_CP_MAX != nStartPos && nStartPos > nEndPos, "sw.ww8",
4858  "End " << nEndPos << " before Start " << nStartPos);
4859 
4860  if( nStartPos != WW8_CP_MAX )
4861  {
4862  /*
4863  ##516##,##517##
4864  Force the property change to happen at the beginning of this
4865  subdocument, same as in GetNewNoSprms, except that the target type is
4866  attributes attached to a piece that might span subdocument boundaries
4867  */
4868  if (nCpOfs > nStartPos)
4869  nStartPos = 0;
4870  else
4871  nStartPos -= nCpOfs;
4872  }
4873  if (nEndPos != WW8_CP_MAX)
4874  {
4875  if (nCpOfs > nEndPos)
4876  {
4877  SAL_WARN("sw.ww8", "broken subdocument piece entry");
4878  nEndPos = WW8_CP_MAX;
4879  }
4880  else
4881  nEndPos -= nCpOfs;
4882  }
4883 }
4884 
4886 {
4887  rDesc.pPLCFx->GetSprms(&rDesc);
4888  rDesc.ReduceByOffset();
4889 
4890  rDesc.bFirstSprm = true;
4891  AdjustEnds( rDesc );
4892  rDesc.nOrigSprmsLen = rDesc.nSprmsLen;
4893 }
4894 
4896 {
4897  rDesc.nCp2OrIdx = rDesc.pPLCFx->GetNoSprms(rDesc.nStartPos, rDesc.nEndPos,
4898  rDesc.nSprmsLen);
4899 
4900  SAL_WARN_IF(WW8_CP_MAX != rDesc.nStartPos && rDesc.nStartPos > rDesc.nEndPos, "sw.ww8",
4901  "End " << rDesc.nEndPos << " before Start " << rDesc.nStartPos);
4902 
4903  rDesc.ReduceByOffset();
4904 
4905  rDesc.bFirstSprm = true;
4906  rDesc.nOrigSprmsLen = rDesc.nSprmsLen;
4907 }
4908 
4909 sal_uInt16 WW8PLCFMan::GetId(const WW8PLCFxDesc* p) const
4910 {
4911  sal_uInt16 nId = 0; // Id = 0 for empty attributes
4912 
4913  if (p == m_pField)
4914  nId = eFLD;
4915  else if (p == m_pFootnote)
4916  nId = eFTN;
4917  else if (p == m_pEdn)
4918  nId = eEDN;
4919  else if (p == m_pAnd)
4920  nId = eAND;
4921  else if (p->nSprmsLen >= maSprmParser.MinSprmLen())
4922  nId = maSprmParser.GetSprmId(p->pMemPos);
4923 
4924  return nId;
4925 }
4926 
4928  bool bDoingDrawTextBox)
4929  : maSprmParser(*pBase->m_pWw8Fib),
4930  m_nLineEnd(WW8_CP_MAX),
4931  mbDoingDrawTextBox(bDoingDrawTextBox)
4932 {
4933  m_pWwFib = pBase->m_pWw8Fib;
4934 
4935  m_nManType = nType;
4936 
4937  if( MAN_MAINTEXT == nType )
4938  {
4939  // search order of the attributes
4941  m_pField = &m_aD[0];
4942  m_pBkm = &m_aD[1];
4943  m_pEdn = &m_aD[2];
4944  m_pFootnote = &m_aD[3];
4945  m_pAnd = &m_aD[4];
4946 
4947  m_pPcd = pBase->m_pPLCFx_PCD ? &m_aD[5] : nullptr;
4948  //pPcdA index == pPcd index + 1
4949  m_pPcdA = pBase->m_pPLCFx_PCDAttrs ? &m_aD[6] : nullptr;
4950 
4951  m_pChp = &m_aD[7];
4952  m_pPap = &m_aD[8];
4953  m_pSep = &m_aD[9];
4954  m_pAtnBkm = &m_aD[10];
4955  m_pFactoidBkm = &m_aD[11];
4956 
4957  m_pSep->pPLCFx = pBase->m_pSepPLCF.get();
4958  m_pFootnote->pPLCFx = pBase->m_pFootnotePLCF.get();
4959  m_pEdn->pPLCFx = pBase->m_pEdnPLCF.get();
4960  m_pBkm->pPLCFx = pBase->m_pBook.get();
4961  m_pAnd->pPLCFx = pBase->m_pAndPLCF.get();
4962  m_pAtnBkm->pPLCFx = pBase->m_pAtnBook.get();
4963  m_pFactoidBkm->pPLCFx = pBase->m_pFactoidBook.get();
4964 
4965  }
4966  else
4967  {
4968  // search order of the attributes
4969  m_nPLCF = 7;
4970  m_pField = &m_aD[0];
4971  m_pBkm = pBase->m_pBook ? &m_aD[1] : nullptr;
4972 
4973  m_pPcd = pBase->m_pPLCFx_PCD ? &m_aD[2] : nullptr;
4974  //pPcdA index == pPcd index + 1
4975  m_pPcdA= pBase->m_pPLCFx_PCDAttrs ? &m_aD[3] : nullptr;
4976 
4977  m_pChp = &m_aD[4];
4978  m_pPap = &m_aD[5];
4979  m_pSep = &m_aD[6]; // Dummy
4980 
4981  m_pAnd = m_pAtnBkm = m_pFactoidBkm = m_pFootnote = m_pEdn = nullptr; // not used at SpezText
4982  }
4983 
4984  m_pChp->pPLCFx = pBase->m_pChpPLCF.get();
4985  m_pPap->pPLCFx = pBase->m_pPapPLCF.get();
4986  if( m_pPcd )
4987  m_pPcd->pPLCFx = pBase->m_pPLCFx_PCD.get();
4988  if( m_pPcdA )
4989  m_pPcdA->pPLCFx= pBase->m_pPLCFx_PCDAttrs.get();
4990  if( m_pBkm )
4991  m_pBkm->pPLCFx = pBase->m_pBook.get();
4992 
4993  m_pMagicTables = pBase->m_pMagicTables.get();
4994  m_pSubdocs = pBase->m_pSubdocs.get();
4995  m_pExtendedAtrds = pBase->m_pExtendedAtrds.get();
4996 
4997  switch( nType ) // field initialization
4998  {
4999  case MAN_HDFT:
5000  m_pField->pPLCFx = pBase->m_pFieldHdFtPLCF.get();
5001  m_pFdoa = pBase->m_pHdFtFdoa.get();
5002  m_pTxbx = pBase->m_pHdFtTxbx.get();
5003  m_pTxbxBkd = pBase->m_pHdFtTxbxBkd.get();
5004  break;
5005  case MAN_FTN:
5006  m_pField->pPLCFx = pBase->m_pFieldFootnotePLCF.get();
5007  m_pFdoa = m_pTxbx = m_pTxbxBkd = nullptr;
5008  break;
5009  <