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  pPLCF_PosArray.reset( new WW8_CP[ ( nPLCF + 3 ) / 4 ] );
2317  bValid = checkRead(rSt, pPLCF_PosArray.get(), nPLCF);
2318  }
2319 
2320  if (bValid)
2321  {
2322 #ifdef OSL_BIGENDIAN
2323  for( nIdx = 0; nIdx <= nIMax; nIdx++ )
2324  pPLCF_PosArray[nIdx] = OSL_SWAPDWORD( pPLCF_PosArray[nIdx] );
2325  nIdx = 0;
2326 #endif // OSL_BIGENDIAN
2327  // Pointer to content array
2328  pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&pPLCF_PosArray[nIMax + 1]);
2329 
2331  }
2332 
2333  OSL_ENSURE(bValid, "Document has corrupt PLCF, ignoring it");
2334 
2335  if (!bValid)
2336  MakeFailedPLCF();
2337 
2338  rSt.Seek(nOldPos);
2339 }
2340 
2342 {
2343  nIMax = 0;
2344  pPLCF_PosArray.reset( new WW8_CP[2] );
2346  pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&pPLCF_PosArray[nIMax + 1]);
2347 }
2348 
2349 namespace
2350 {
2351  sal_Int32 TruncToSortedRange(const sal_Int32* pPLCF_PosArray, sal_Int32 nIMax)
2352  {
2353  //Docs state that: ... all Plcs ... are sorted in ascending order.
2354  //So ensure that here for broken documents.
2355  for (auto nI = 0; nI < nIMax; ++nI)
2356  {
2357  if (pPLCF_PosArray[nI] > pPLCF_PosArray[nI+1])
2358  {
2359  SAL_WARN("sw.ww8", "Document has unsorted PLCF, truncated to sorted portion");
2360  nIMax = nI;
2361  break;
2362  }
2363  }
2364  return nIMax;
2365  }
2366 }
2367 
2369 {
2370  nIMax = ::TruncToSortedRange(pPLCF_PosArray.get(), nIMax);
2371 }
2372 
2374 {
2375  nIMax = ::TruncToSortedRange(pPLCF_PosArray.get(), nIMax);
2376 }
2377 
2378 void WW8PLCF::GeneratePLCF(SvStream& rSt, sal_Int32 nPN, sal_Int32 ncpN)
2379 {
2380  OSL_ENSURE( nIMax < ncpN, "Pcl.Fkp: Why is PLCF too big?" );
2381 
2382  bool failure = false;
2383  nIMax = ncpN;
2384 
2385  if ((nIMax < 1) || (nIMax > (WW8_CP_MAX - 4) / (4 + nStru)) || nPN < 0)
2386  failure = true;
2387 
2388  if (!failure)
2389  {
2390  // Check arguments to ShortToSVBT16 in loop below will all be valid:
2391  sal_Int32 nResult;
2392  failure = o3tl::checked_add(nPN, ncpN, nResult) || nResult > SAL_MAX_UINT16;
2393  }
2394 
2395  if (!failure)
2396  {
2397  size_t nSiz = (4 + nStru) * nIMax + 4;
2398  size_t nElems = ( nSiz + 3 ) / 4;
2399  pPLCF_PosArray.reset( new WW8_CP[ nElems ] ); // Pointer to Pos-array
2400 
2401  for (sal_Int32 i = 0; i < ncpN && !failure; ++i)
2402  {
2403  failure = true;
2404  // construct FC entries
2405  // first FC entry of each Fkp
2406  if (!checkSeek(rSt, (nPN + i) << 9))
2407  break;
2408 
2409  WW8_CP nFc(0);
2410  rSt.ReadInt32( nFc );
2411  pPLCF_PosArray[i] = nFc;
2412 
2413  failure = bool(rSt.GetError());
2414  }
2415  }
2416 
2417  if (!failure)
2418  {
2419  do
2420  {
2421  failure = true;
2422 
2423  std::size_t nLastFkpPos = nPN + nIMax - 1;
2424  nLastFkpPos = nLastFkpPos << 9;
2425  // number of FC entries of last Fkp
2426  if (!checkSeek(rSt, nLastFkpPos + 511))
2427  break;
2428 
2429  sal_uInt8 nb(0);
2430  rSt.ReadUChar( nb );
2431  // last FC entry of last Fkp
2432  if (!checkSeek(rSt, nLastFkpPos + nb * 4))
2433  break;
2434 
2435  WW8_CP nFc(0);
2436  rSt.ReadInt32( nFc );
2437  pPLCF_PosArray[nIMax] = nFc; // end of the last Fkp
2438 
2439  failure = bool(rSt.GetError());
2440  } while(false);
2441  }
2442 
2443  if (!failure)
2444  {
2445  // Pointer to content array
2446  pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&pPLCF_PosArray[nIMax + 1]);
2448 
2449  for (sal_Int32 i = 0; i < ncpN; ++i) // construct PNs
2450  {
2451  ShortToSVBT16(o3tl::narrowing<sal_uInt16>(nPN + i), p);
2452  p += nStru;
2453  }
2454  }
2455 
2456  SAL_WARN_IF(failure, "sw.ww8", "Document has corrupt PLCF, ignoring it");
2457 
2458  if (failure)
2459  MakeFailedPLCF();
2460 }
2461 
2463 {
2464  WW8_CP nP = nPos;
2465 
2466  if( nP < pPLCF_PosArray[0] )
2467  {
2468  nIdx = 0;
2469  // not found: nPos less than smallest entry
2470  return false;
2471  }
2472 
2473  // Search from beginning?
2474  if ((nIdx < 1) || (nP < pPLCF_PosArray[nIdx - 1]))
2475  nIdx = 1;
2476 
2477  sal_Int32 nI = nIdx;
2478  sal_Int32 nEnd = nIMax;
2479 
2480  for(int n = (1==nIdx ? 1 : 2); n; --n )
2481  {
2482  for( ; nI <=nEnd; ++nI) // search with an index that is incremented by 1
2483  {
2484  if( nP < pPLCF_PosArray[nI] ) // found position
2485  {
2486  nIdx = nI - 1; // nI - 1 is the correct index
2487  return true; // done
2488  }
2489  }
2490  nI = 1;
2491  nEnd = nIdx-1;
2492  }
2493 
2494  nIdx = nIMax; // not found, greater than all entries
2495  return false;
2496 }
2497 
2498 bool WW8PLCF::Get(WW8_CP& rStart, WW8_CP& rEnd, void*& rpValue) const
2499 {
2500  if ( nIdx >= nIMax )
2501  {
2502  rStart = rEnd = WW8_CP_MAX;
2503  return false;
2504  }
2505  rStart = pPLCF_PosArray[ nIdx ];
2506  rEnd = pPLCF_PosArray[ nIdx + 1 ];
2507  rpValue = static_cast<void*>(&pPLCF_Contents[nIdx * nStru]);
2508  return true;
2509 }
2510 
2512 {
2513  if ( nIdx >= nIMax )
2514  return WW8_CP_MAX;
2515 
2516  return pPLCF_PosArray[nIdx];
2517 }
2518 
2519 WW8PLCFpcd::WW8PLCFpcd(SvStream* pSt, sal_uInt32 nFilePos,
2520  sal_uInt32 nPLCF, sal_uInt32 nStruct)
2521  : nStru( nStruct )
2522 {
2523  const sal_uInt32 nValidMin=4;
2524 
2525  sal_uInt64 const nOldPos = pSt->Tell();
2526 
2527  bool bValid = checkSeek(*pSt, nFilePos);
2528  std::size_t nRemainingSize = pSt->remainingSize();
2529  if( nRemainingSize < nValidMin || nPLCF < nValidMin )
2530  bValid = false;
2531  nPLCF = bValid ? std::min(nRemainingSize, static_cast<std::size_t>(nPLCF)) : nValidMin;
2532 
2533  pPLCF_PosArray.reset( new WW8_CP[ ( nPLCF + 3 ) / 4 ] ); // Pointer to Pos-array
2534  pPLCF_PosArray[0] = 0;
2535 
2536  nPLCF = bValid ? pSt->ReadBytes(pPLCF_PosArray.get(), nPLCF) : nValidMin;
2537  nPLCF = std::max(nPLCF, nValidMin);
2538 
2539  nIMax = ( nPLCF - 4 ) / ( 4 + nStruct );
2540 #ifdef OSL_BIGENDIAN
2541  for( tools::Long nI = 0; nI <= nIMax; nI++ )
2542  pPLCF_PosArray[nI] = OSL_SWAPDWORD( pPLCF_PosArray[nI] );
2543 #endif // OSL_BIGENDIAN
2544 
2545  // Pointer to content array
2546  pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&pPLCF_PosArray[nIMax + 1]);
2548 
2549  pSt->Seek( nOldPos );
2550 }
2551 
2552 // If nStartPos < 0, the first element of PLCFs will be taken
2554  :rPLCF( rPLCFpcd ), nIdx( 0 )
2555 {
2556  if( nStartPos >= 0 )
2557  SeekPos( nStartPos );
2558 }
2559 
2561 {
2562  tools::Long nP = nPos;
2563 
2564  if( nP < rPLCF.pPLCF_PosArray[0] )
2565  {
2566  nIdx = 0;
2567  return false; // not found: nPos less than smallest entry
2568  }
2569  // Search from beginning?
2570  if ((nIdx < 1) || (nP < rPLCF.pPLCF_PosArray[nIdx - 1]))
2571  nIdx = 1;
2572 
2573  tools::Long nI = nIdx;
2574  tools::Long nEnd = rPLCF.nIMax;
2575 
2576  for(int n = (1==nIdx ? 1 : 2); n; --n )
2577  {
2578  for( ; nI <=nEnd; ++nI)
2579  { // search with an index that is incremented by 1
2580  if( nP < rPLCF.pPLCF_PosArray[nI] )
2581  { // found position
2582  nIdx = nI - 1; // nI - 1 is the correct index
2583  return true; // done
2584  }
2585  }
2586  nI = 1;
2587  nEnd = nIdx-1;
2588  }
2589  nIdx = rPLCF.nIMax; // not found, greater than all entries
2590  return false;
2591 }
2592 
2593 bool WW8PLCFpcd_Iter::Get(WW8_CP& rStart, WW8_CP& rEnd, void*& rpValue) const
2594 {
2595  if( nIdx >= rPLCF.nIMax )
2596  {
2597  rStart = rEnd = WW8_CP_MAX;
2598  return false;
2599  }
2600  rStart = rPLCF.pPLCF_PosArray[nIdx];
2601  rEnd = rPLCF.pPLCF_PosArray[nIdx + 1];
2602  rpValue = static_cast<void*>(&rPLCF.pPLCF_Contents[nIdx * rPLCF.nStru]);
2603  return true;
2604 }
2605 
2606 sal_Int32 WW8PLCFpcd_Iter::Where() const
2607 {
2608  if ( nIdx >= rPLCF.nIMax )
2609  return SAL_MAX_INT32;
2610 
2611  return rPLCF.pPLCF_PosArray[nIdx];
2612 }
2613 
2614 bool WW8PLCFx_Fc_FKP::WW8Fkp::Entry::operator<
2615  (const WW8PLCFx_Fc_FKP::WW8Fkp::Entry& rSecond) const
2616 {
2617  return (mnFC < rSecond.mnFC);
2618 }
2619 
2620 static bool IsReplaceAllSprm(sal_uInt16 nSpId)
2621 {
2622  return (NS_sprm::LN_PHugePapx == nSpId || 0x6646 == nSpId);
2623 }
2624 
2625 static bool IsExpandableSprm(sal_uInt16 nSpId)
2626 {
2627  return 0x646B == nSpId;
2628 }
2629 
2631  std::size_t nDataOffset, sal_uInt16 nLen)
2632 {
2633  bool bValidPos = (nDataOffset < sizeof(maRawData));
2634 
2635  OSL_ENSURE(bValidPos, "sprm sequence offset is out of range, ignoring");
2636 
2637  if (!bValidPos)
2638  {
2639  rEntry.mnLen = 0;
2640  return;
2641  }
2642 
2643  const sal_uInt16 nAvailableData = sizeof(maRawData)-nDataOffset;
2644  OSL_ENSURE(nLen <= nAvailableData, "srpm sequence len is out of range, clipping");
2645  rEntry.mnLen = std::min(nLen, nAvailableData);
2646  rEntry.mpData = maRawData + nDataOffset;
2647 }
2648 
2650  SvStream* pDataSt, tools::Long _nFilePos, tools::Long nItemSiz, ePLCFT ePl,
2651  WW8_FC nStartFc)
2652  : nItemSize(nItemSiz), nFilePos(_nFilePos), mnIdx(0), ePLCF(ePl)
2653  , mnMustRemainCached(0), maSprmParser(rFib)
2654 {
2655  memset(maRawData, 0, 512);
2656 
2657  const ww::WordVersion eVersion = rFib.GetFIBVersion();
2658 
2659  sal_uInt64 const nOldPos = pSt->Tell();
2660 
2661  bool bCouldSeek = checkSeek(*pSt, nFilePos);
2662  bool bCouldRead = bCouldSeek && checkRead(*pSt, maRawData, 512);
2663 
2664  mnIMax = bCouldRead ? maRawData[511] : 0;
2665 
2666  sal_uInt8 *pStart = maRawData;
2667  // Offset-Location in maRawData
2668  const size_t nRawDataStart = (mnIMax + 1) * 4;
2669 
2670  for (mnIdx = 0; mnIdx < mnIMax; ++mnIdx)
2671  {
2672  const size_t nRawDataOffset = nRawDataStart + mnIdx * nItemSize;
2673 
2674  //clip to available data, corrupt fkp
2675  if (nRawDataOffset >= 511)
2676  {
2677  mnIMax = mnIdx;
2678  break;
2679  }
2680 
2681  unsigned int nOfs = maRawData[nRawDataOffset] * 2;
2682  // nOfs in [0..0xff*2=510]
2683 
2684  Entry aEntry(Get_Long(pStart));
2685 
2686  if (nOfs)
2687  {
2688  switch (ePLCF)
2689  {
2690  case CHP:
2691  {
2692  aEntry.mnLen = maRawData[nOfs];
2693 
2694  //len byte
2695  std::size_t nDataOffset = nOfs + 1;
2696 
2697  FillEntry(aEntry, nDataOffset, aEntry.mnLen);
2698 
2699  if (aEntry.mnLen && eVersion <= ww::eWW2)
2700  {
2701  Word2CHPX aChpx = ReadWord2Chpx(*pSt, nFilePos + nOfs + 1, static_cast< sal_uInt8 >(aEntry.mnLen));
2702  std::vector<sal_uInt8> aSprms = ChpxToSprms(aChpx);
2703  aEntry.mnLen = static_cast< sal_uInt16 >(aSprms.size());
2704  if (aEntry.mnLen)
2705  {
2706  aEntry.mpData = new sal_uInt8[aEntry.mnLen];
2707  memcpy(aEntry.mpData, aSprms.data(), aEntry.mnLen);
2708  aEntry.mbMustDelete = true;
2709  }
2710  }
2711  break;
2712  }
2713  case PAP:
2714  {
2715  sal_uInt8 nDelta = 0;
2716 
2717  aEntry.mnLen = maRawData[nOfs];
2718  if (IsEightPlus(eVersion) && !aEntry.mnLen)
2719  {
2720  aEntry.mnLen = maRawData[nOfs+1];
2721  nDelta++;
2722  }
2723  aEntry.mnLen *= 2;
2724 
2725  //stylecode, std/istd
2726  if (eVersion <= ww::eWW2)
2727  {
2728  if (aEntry.mnLen >= 1)
2729  {
2730  aEntry.mnIStd = *(maRawData+nOfs+1+nDelta);
2731  aEntry.mnLen--; //style code
2732  if (aEntry.mnLen >= 6)
2733  {
2734  aEntry.mnLen-=6; //PHE
2735  //skip stc, len byte + 6 byte PHE
2736  unsigned int nOffset = nOfs + 8;
2737  if (nOffset >= 511) //Bad offset
2738  aEntry.mnLen=0;
2739  if (aEntry.mnLen) //start is ok
2740  {
2741  if (nOffset + aEntry.mnLen > 512) //Bad end, clip
2742  aEntry.mnLen = 512 - nOffset;
2743  aEntry.mpData = maRawData + nOffset;
2744  }
2745  }
2746  else
2747  aEntry.mnLen=0; //Too short
2748  }
2749  }
2750  else
2751  {
2752  if (aEntry.mnLen >= 2)
2753  {
2754  //len byte + optional extra len byte
2755  std::size_t nDataOffset = nOfs + 1 + nDelta;
2756  aEntry.mnIStd = nDataOffset <= sizeof(maRawData)-sizeof(aEntry.mnIStd) ?
2757  SVBT16ToUInt16(maRawData+nDataOffset) : 0;
2758  aEntry.mnLen-=2; //istd
2759  if (aEntry.mnLen)
2760  {
2761  //additional istd
2762  nDataOffset += sizeof(aEntry.mnIStd);
2763 
2764  FillEntry(aEntry, nDataOffset, aEntry.mnLen);
2765  }
2766  }
2767  else
2768  aEntry.mnLen=0; //Too short, ignore
2769  }
2770 
2771  const sal_uInt16 nSpId = aEntry.mnLen
2772  ? maSprmParser.GetSprmId(aEntry.mpData) : 0;
2773 
2774  /*
2775  If we replace then we throw away the old data, if we
2776  are expanding, then we tack the old data onto the end
2777  of the new data
2778  */
2779  const bool bExpand = IsExpandableSprm(nSpId);
2780  const sal_uInt8* pStartData
2781  = aEntry.mpData == nullptr ? nullptr : aEntry.mpData + 2;
2782  const sal_uInt8* pLastValidDataPos = maRawData + 512 - sizeof(sal_uInt32);
2783  if (pStartData != nullptr && pStartData > pLastValidDataPos)
2784  pStartData = nullptr;
2785  if ((IsReplaceAllSprm(nSpId) || bExpand) && pStartData)
2786  {
2787  sal_uInt32 nCurr = pDataSt->Tell();
2788  sal_uInt32 nPos = SVBT32ToUInt32(pStartData);
2789  sal_uInt16 nLen(0);
2790 
2791  bool bOk = checkSeek(*pDataSt, nPos);
2792  if (bOk)
2793  {
2794  pDataSt->ReadUInt16( nLen );
2795  bOk = nLen <= pDataSt->remainingSize();
2796  }
2797 
2798  if (bOk)
2799  {
2800  const sal_uInt16 nOrigLen = bExpand ? aEntry.mnLen : 0;
2801  sal_uInt8 *pOrigData = bExpand ? aEntry.mpData : nullptr;
2802 
2803  aEntry.mnLen = nLen;
2804  aEntry.mpData =
2805  new sal_uInt8[aEntry.mnLen + nOrigLen];
2806  aEntry.mbMustDelete = true;
2807  aEntry.mnLen =
2808  pDataSt->ReadBytes(aEntry.mpData, aEntry.mnLen);
2809 
2810  pDataSt->Seek( nCurr );
2811 
2812  if (pOrigData)
2813  {
2814  memcpy(aEntry.mpData + aEntry.mnLen,
2815  pOrigData, nOrigLen);
2816  aEntry.mnLen = aEntry.mnLen + nOrigLen;
2817  }
2818  }
2819  }
2820  }
2821  break;
2822  default:
2823  OSL_FAIL("sweet god, what have you done!");
2824  break;
2825  }
2826  }
2827 
2828  maEntries.push_back(aEntry);
2829 
2830 #ifdef DEBUGSPRMREADER
2831  {
2832  sal_Int32 nLen;
2833  sal_uInt8* pSprms = GetLenAndIStdAndSprms( nLen );
2834  WW8SprmIter aIter(pSprms, nLen, maSprmParser);
2835  while (aIter.GetSprms())
2836  {
2837  fprintf(stderr, "id is %x\n", aIter.GetCurrentId());
2838  aIter.advance();
2839  }
2840  }
2841 #endif
2842  }
2843 
2844  //one more FC than grrpl entries
2845  maEntries.emplace_back(Get_Long(pStart));
2846 
2847  //we expect them sorted, but it appears possible for them to arrive unsorted
2848  std::stable_sort(maEntries.begin(), maEntries.end());
2849 
2850  mnIdx = 0;
2851 
2852  if (nStartFc >= 0)
2853  SeekPos(nStartFc);
2854 
2855  pSt->Seek(nOldPos);
2856 }
2857 
2859  : mnFC(rEntry.mnFC), mnLen(rEntry.mnLen), mnIStd(rEntry.mnIStd),
2860  mbMustDelete(rEntry.mbMustDelete)
2861 {
2862  if (mbMustDelete)
2863  {
2864  mpData = new sal_uInt8[mnLen];
2865  memcpy(mpData, rEntry.mpData, mnLen);
2866  }
2867  else
2868  mpData = rEntry.mpData;
2869 }
2870 
2873 {
2874  if (this == &rEntry)
2875  return *this;
2876 
2877  if (mbMustDelete)
2878  delete[] mpData;
2879 
2880  mnFC = rEntry.mnFC;
2881  mnLen = rEntry.mnLen;
2882  mnIStd = rEntry.mnIStd;
2883  mbMustDelete = rEntry.mbMustDelete;
2884 
2885  if (rEntry.mbMustDelete)
2886  {
2887  mpData = new sal_uInt8[mnLen];
2888  memcpy(mpData, rEntry.mpData, mnLen);
2889  }
2890  else
2891  mpData = rEntry.mpData;
2892 
2893  return *this;
2894 }
2895 
2897 {
2898  if (mbMustDelete)
2899  delete[] mpData;
2900 }
2901 
2903 {
2904  SetIdx(0);
2905  if (nFc >= 0)
2906  SeekPos(nFc);
2907 }
2908 
2910 {
2911  if (nFc < maEntries[0].mnFC)
2912  {
2913  mnIdx = 0;
2914  return false; // not found: nPos less than smallest entry
2915  }
2916 
2917  // Search from beginning?
2918  if ((mnIdx < 1) || (nFc < maEntries[mnIdx - 1].mnFC))
2919  mnIdx = 1;
2920 
2921  sal_uInt8 nI = mnIdx;
2922  sal_uInt8 nEnd = mnIMax;
2923 
2924  for(sal_uInt8 n = (1==mnIdx ? 1 : 2); n; --n )
2925  {
2926  for( ; nI <=nEnd; ++nI)
2927  { // search with an index that is incremented by 1
2928  if (nFc < maEntries[nI].mnFC)
2929  { // found position
2930  mnIdx = nI - 1; // nI - 1 is the correct index
2931  return true; // done
2932  }
2933  }
2934  nI = 1;
2935  nEnd = mnIdx-1;
2936  }
2937  mnIdx = mnIMax; // not found, greater than all entries
2938  return false;
2939 }
2940 
2941 sal_uInt8* WW8PLCFx_Fc_FKP::WW8Fkp::Get(WW8_FC& rStart, WW8_FC& rEnd, sal_Int32& rLen)
2942  const
2943 {
2944  rLen = 0;
2945 
2946  if (mnIdx >= mnIMax)
2947  {
2948  rStart = WW8_FC_MAX;
2949  return nullptr;
2950  }
2951 
2952  rStart = maEntries[mnIdx].mnFC;
2953  rEnd = maEntries[mnIdx + 1].mnFC;
2954 
2955  sal_uInt8* pSprms = GetLenAndIStdAndSprms( rLen );
2956  return pSprms;
2957 }
2958 
2960 {
2961  if (nI < mnIMax)
2962  {
2963  mnIdx = nI;
2964  }
2965 }
2966 
2968 {
2969  rLen = maEntries[mnIdx].mnLen;
2970  return maEntries[mnIdx].mpData;
2971 }
2972 
2973 SprmResult WW8PLCFx_Fc_FKP::WW8Fkp::HasSprm( sal_uInt16 nId, bool bFindFirst )
2974 {
2975  if (mnIdx >= mnIMax)
2976  return SprmResult();
2977 
2978  sal_Int32 nLen;
2979  sal_uInt8* pSprms = GetLenAndIStdAndSprms( nLen );
2980 
2981  WW8SprmIter aIter(pSprms, nLen, maSprmParser);
2982  return aIter.FindSprm(nId, bFindFirst);
2983 }
2984 
2986  std::vector<SprmResult> &rResult)
2987 {
2988  if (mnIdx >= mnIMax)
2989  return;
2990 
2991  sal_Int32 nLen;
2992  sal_uInt8* pSprms = GetLenAndIStdAndSprms( nLen );
2993 
2994  WW8SprmIter aIter(pSprms, nLen, maSprmParser);
2995 
2996  while(aIter.GetSprms())
2997  {
2998  if (aIter.GetCurrentId() == nId)
2999  {
3000  sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId);
3001  sal_Int32 nL = maSprmParser.GetSprmSize(nId, aIter.GetSprms(), aIter.GetRemLen());
3002  rResult.emplace_back(aIter.GetCurrentParams(), nL - nFixedLen);
3003  }
3004  aIter.advance();
3005  };
3006 }
3007 
3009 {
3010  return mrFib.GetFIBVersion();
3011 }
3012 
3014 {
3015  OSL_ENSURE( false, "Called wrong GetSprms" );
3016  p->nStartPos = p->nEndPos = WW8_CP_MAX;
3017  p->pMemPos = nullptr;
3018  p->nSprmsLen = 0;
3019  p->bRealLineEnd = false;
3020 }
3021 
3022 tools::Long WW8PLCFx::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
3023 {
3024  OSL_ENSURE( false, "Called wrong GetNoSprms" );
3025  rStart = rEnd = WW8_CP_MAX;
3026  rLen = 0;
3027  return 0;
3028 }
3029 
3030 // ...Idx2: Default: ignore
3031 sal_uInt32 WW8PLCFx::GetIdx2() const
3032 {
3033  return 0;
3034 }
3035 
3036 void WW8PLCFx::SetIdx2(sal_uInt32)
3037 {
3038 }
3039 
3040 namespace {
3041 
3042 class SamePos
3043 {
3044 private:
3045  tools::Long mnPo;
3046 public:
3047  explicit SamePos(tools::Long nPo) : mnPo(nPo) {}
3048  bool operator()(const std::unique_ptr<WW8PLCFx_Fc_FKP::WW8Fkp>& pFkp)
3049  {return mnPo == pFkp->GetFilePos();}
3050 };
3051 
3052 }
3053 
3055 {
3056  WW8_CP nPLCFStart, nPLCFEnd;
3057  void* pPage;
3058 
3059  static const int WW8FkpSizeTabVer2[ PLCF_END ] =
3060  {
3061  1, 1, 0 /*, 0, 0, 0*/
3062  };
3063  static const int WW8FkpSizeTabVer6[ PLCF_END ] =
3064  {
3065  1, 7, 0 /*, 0, 0, 0*/
3066  };
3067  static const int WW8FkpSizeTabVer8[ PLCF_END ] =
3068  {
3069  1, 13, 0 /*, 0, 0, 0*/
3070  };
3071  const int* pFkpSizeTab;
3072 
3073  switch (GetFIBVersion())
3074  {
3075  case ww::eWW1:
3076  case ww::eWW2:
3077  pFkpSizeTab = WW8FkpSizeTabVer2;
3078  break;
3079  case ww::eWW6:
3080  case ww::eWW7:
3081  pFkpSizeTab = WW8FkpSizeTabVer6;
3082  break;
3083  case ww::eWW8:
3084  pFkpSizeTab = WW8FkpSizeTabVer8;
3085  break;
3086  default:
3087  // program error!
3088  OSL_ENSURE( false, "nVersion not implemented!" );
3089  return false;
3090  }
3091 
3092  if (!pPLCF->Get( nPLCFStart, nPLCFEnd, pPage ))
3093  {
3094  pFkp = nullptr;
3095  return false; // PLCF completely processed
3096  }
3097  pPLCF->advance();
3098  tools::Long nPo = SVBT16ToUInt16( static_cast<sal_uInt8 *>(pPage) );
3099  nPo <<= 9; // shift as LONG
3100 
3101  tools::Long nCurrentFkpFilePos = pFkp ? pFkp->GetFilePos() : -1;
3102  if (nCurrentFkpFilePos == nPo)
3103  pFkp->Reset(GetStartFc());
3104  else
3105  {
3106  auto aIter =
3107  std::find_if(maFkpCache.begin(), maFkpCache.end(), SamePos(nPo));
3108  if (aIter != maFkpCache.end())
3109  {
3110  pFkp = aIter->get();
3111  pFkp->Reset(GetStartFc());
3112  }
3113  else
3114  {
3115  pFkp = new WW8Fkp(GetFIB(), pFKPStrm, pDataStrm, nPo,
3116  pFkpSizeTab[ ePLCF ], ePLCF, GetStartFc());
3117  maFkpCache.push_back(std::unique_ptr<WW8Fkp>(pFkp));
3118 
3119  if (maFkpCache.size() > eMaxCache)
3120  {
3121  WW8Fkp* pCachedFkp = maFkpCache.front().get();
3122  if (!pCachedFkp->IsMustRemainCache())
3123  {
3124  maFkpCache.pop_front();
3125  }
3126  }
3127  }
3128  }
3129 
3130  SetStartFc( -1 ); // only the first time
3131  return true;
3132 }
3133 
3135  SvStream* pDataSt, const WW8Fib& rFib, ePLCFT ePl, WW8_FC nStartFcL)
3136  : WW8PLCFx(rFib, true), pFKPStrm(pSt), pDataStrm(pDataSt)
3137  , pFkp(nullptr), ePLCF(ePl)
3138 {
3139  SetStartFc(nStartFcL);
3140  tools::Long nLenStruct = (8 > rFib.m_nVersion) ? 2 : 4;
3141  if (ePl == CHP)
3142  {
3143  pPLCF.reset(new WW8PLCF(*pTableSt, rFib.m_fcPlcfbteChpx, rFib.m_lcbPlcfbteChpx,
3144  nLenStruct, GetStartFc(), rFib.m_pnChpFirst, rFib.m_cpnBteChp));
3145  }
3146  else
3147  {
3148  pPLCF.reset(new WW8PLCF(*pTableSt, rFib.m_fcPlcfbtePapx, rFib.m_lcbPlcfbtePapx,
3149  nLenStruct, GetStartFc(), rFib.m_pnPapFirst, rFib.m_cpnBtePap));
3150  }
3151 }
3152 
3154 {
3155  maFkpCache.clear();
3156  pPLCF.reset();
3157  pPCDAttrs.reset();
3158 }
3159 
3160 sal_uInt32 WW8PLCFx_Fc_FKP::GetIdx() const
3161 {
3162  sal_uInt32 u = pPLCF->GetIdx() << 8;
3163  if (pFkp)
3164  u |= pFkp->GetIdx();
3165  return u;
3166 }
3167 
3168 void WW8PLCFx_Fc_FKP::SetIdx(sal_uInt32 nIdx)
3169 {
3170  if( !( nIdx & 0xffffff00L ) )
3171  {
3172  pPLCF->SetIdx( nIdx >> 8 );
3173  pFkp = nullptr;
3174  }
3175  else
3176  { // there was a Fkp
3177  // Set PLCF one position back to retrieve the address of the Fkp
3178  pPLCF->SetIdx( ( nIdx >> 8 ) - 1 );
3179  if (NewFkp()) // read Fkp again
3180  {
3181  sal_uInt8 nFkpIdx = static_cast<sal_uInt8>(nIdx & 0xff);
3182  pFkp->SetIdx(nFkpIdx); // set Fkp-Pos again
3183  }
3184  }
3185 }
3186 
3188 {
3189  // StartPos for next Where()
3190  SetStartFc( nFcPos );
3191 
3192  // find StartPos for next pPLCF->Get()
3193  bool bRet = pPLCF->SeekPos(nFcPos);
3194 
3195  // make FKP invalid?
3196  WW8_CP nPLCFStart, nPLCFEnd;
3197  void* pPage;
3198  if( pFkp && pPLCF->Get( nPLCFStart, nPLCFEnd, pPage ) )
3199  {
3200  tools::Long nPo = SVBT16ToUInt16( static_cast<sal_uInt8 *>(pPage) );
3201  nPo <<= 9; // shift as LONG
3202  if (nPo != pFkp->GetFilePos())
3203  pFkp = nullptr;
3204  else
3205  pFkp->SeekPos( nFcPos );
3206  }
3207  return bRet;
3208 }
3209 
3211 {
3212  if( !pFkp && !NewFkp() )
3213  return WW8_FC_MAX;
3214  WW8_FC nP = pFkp ? pFkp->Where() : WW8_FC_MAX;
3215  if( nP != WW8_FC_MAX )
3216  return nP;
3217 
3218  pFkp = nullptr; // FKP finished -> get new
3219  return Where(); // easiest way: do it recursively
3220 }
3221 
3222 sal_uInt8* WW8PLCFx_Fc_FKP::GetSprmsAndPos(WW8_FC& rStart, WW8_FC& rEnd, sal_Int32& rLen)
3223 {
3224  rLen = 0; // Default
3225  rStart = rEnd = WW8_FC_MAX;
3226 
3227  if( !pFkp ) // Fkp not there ?
3228  {
3229  if( !NewFkp() )
3230  return nullptr;
3231  }
3232 
3233  sal_uInt8* pPos = pFkp ? pFkp->Get( rStart, rEnd, rLen ) : nullptr;
3234  if( rStart == WW8_FC_MAX ) //Not found
3235  return nullptr;
3236  return pPos;
3237 }
3238 
3240 {
3241  if( !pFkp && !NewFkp() )
3242  return;
3243 
3244  if (!pFkp)
3245  return;
3246 
3247  pFkp->advance();
3248  if( pFkp->Where() == WW8_FC_MAX )
3249  (void)NewFkp();
3250 }
3251 
3252 sal_uInt16 WW8PLCFx_Fc_FKP::GetIstd() const
3253 {
3254  return pFkp ? pFkp->GetIstd() : 0xFFFF;
3255 }
3256 
3258 {
3259  rDesc.pMemPos = nullptr;
3260  rDesc.nSprmsLen = 0;
3261  if( pPCDAttrs )
3262  {
3263  if( !pFkp )
3264  {
3265  OSL_FAIL("+Problem: GetPCDSprms: NewFkp necessary (not possible!)" );
3266  if( !NewFkp() )
3267  return;
3268  }
3269  pPCDAttrs->GetSprms(&rDesc);
3270  }
3271 }
3272 
3273 SprmResult WW8PLCFx_Fc_FKP::HasSprm(sal_uInt16 nId, bool bFindFirst)
3274 {
3275  // const would be nicer, but for that, NewFkp() would need to be replaced or eliminated
3276  if( !pFkp )
3277  {
3278  OSL_FAIL( "+Motz: HasSprm: NewFkp needed ( no const possible )" );
3279  // happens in BugDoc 31722
3280  if( !NewFkp() )
3281  return SprmResult();
3282  }
3283 
3284  if (!pFkp)
3285  return SprmResult();
3286 
3287  SprmResult aRes = pFkp->HasSprm(nId, bFindFirst);
3288 
3289  if (!aRes.pSprm)
3290  {
3291  WW8PLCFxDesc aDesc;
3292  GetPCDSprms( aDesc );
3293 
3294  if (aDesc.pMemPos)
3295  {
3296  WW8SprmIter aIter(aDesc.pMemPos, aDesc.nSprmsLen,
3297  pFkp->GetSprmParser());
3298  aRes = aIter.FindSprm(nId, bFindFirst);
3299  }
3300  }
3301 
3302  return aRes;
3303 }
3304 
3305 void WW8PLCFx_Fc_FKP::HasSprm(sal_uInt16 nId, std::vector<SprmResult> &rResult)
3306 {
3307  // const would be nicer, but for that, NewFkp() would need to be replaced or eliminated
3308  if (!pFkp)
3309  {
3310  OSL_FAIL( "+Motz: HasSprm: NewFkp needed ( no const possible )" );
3311  // happens in BugDoc 31722
3312  if( !NewFkp() )
3313  return;
3314  }
3315 
3316  if (!pFkp)
3317  return;
3318 
3319  pFkp->HasSprm(nId, rResult);
3320 
3321  WW8PLCFxDesc aDesc;
3322  GetPCDSprms( aDesc );
3323 
3324  if (!aDesc.pMemPos)
3325  return;
3326 
3327  const wwSprmParser &rSprmParser = pFkp->GetSprmParser();
3328  WW8SprmIter aIter(aDesc.pMemPos, aDesc.nSprmsLen, rSprmParser);
3329  while(aIter.GetSprms())
3330  {
3331  if (aIter.GetCurrentId() == nId)
3332  {
3333  sal_Int32 nFixedLen = rSprmParser.DistanceToData(nId);
3334  sal_Int32 nL = rSprmParser.GetSprmSize(nId, aIter.GetSprms(), aIter.GetRemLen());
3335  rResult.emplace_back(aIter.GetCurrentParams(), nL - nFixedLen);
3336  }
3337  aIter.advance();
3338  };
3339 }
3340 
3342  SvStream* pDataSt, const WW8ScannerBase& rBase, ePLCFT ePl )
3343  : WW8PLCFx_Fc_FKP(pSt, pTableSt, pDataSt, *rBase.m_pWw8Fib, ePl,
3344  rBase.WW8Cp2Fc(0)), rSBase(rBase), nAttrStart(-1), nAttrEnd(-1),
3345  bLineEnd(false),
3346  bComplex( (7 < rBase.m_pWw8Fib->m_nVersion) || rBase.m_pWw8Fib->m_fComplex )
3347 {
3349 
3350  if (rSBase.m_pPiecePLCF)
3351  pPcd.reset( new WW8PLCFx_PCD(GetFIB(), rBase.m_pPiecePLCF.get(), 0, IsSevenMinus(GetFIBVersion())) );
3352 
3353  /*
3354  Make a copy of the piece attributes for so that the calls to HasSprm on a
3355  Fc_FKP will be able to take into account the current piece attributes,
3356  despite the fact that such attributes can only be found through a cp based
3357  mechanism.
3358  */
3359  if (pPcd)
3360  {
3362  *rSBase.m_pWw8Fib, pPcd.get(), &rSBase) : nullptr);
3363  }
3364 
3365  pPieceIter = rSBase.m_pPieceIter.get();
3366 }
3367 
3369 {
3370 }
3371 
3373 {
3374  nAttrStart = -1;
3375  nAttrEnd = -1;
3376  bLineEnd = false;
3377 }
3378 
3379 sal_uInt32 WW8PLCFx_Cp_FKP::GetPCDIdx() const
3380 {
3381  return pPcd ? pPcd->GetIdx() : 0;
3382 }
3383 
3385 {
3386  if( pPcd ) // Complex
3387  {
3388  if( !pPcd->SeekPos( nCpPos ) ) // set piece
3389  return false;
3390  if (pPCDAttrs && !pPCDAttrs->GetIter()->SeekPos(nCpPos))
3391  return false;
3392  return WW8PLCFx_Fc_FKP::SeekPos(pPcd->CurrentPieceStartCp2Fc(nCpPos));
3393  }
3394  // NO piece table !!!
3395  return WW8PLCFx_Fc_FKP::SeekPos( rSBase.WW8Cp2Fc(nCpPos) );
3396 }
3397 
3399 {
3401  if( pPcd )
3402  return pPcd->CurrentPieceStartFc2Cp( nFc ); // identify piece
3403  return rSBase.WW8Fc2Cp( nFc ); // NO piece table !!!
3404 }
3405 
3407 {
3408  WW8_CP nOrigCp = p->nStartPos;
3409 
3410  if (!GetDirty()) //Normal case
3411  {
3413  p->nSprmsLen);
3414  }
3415  else
3416  {
3417  /*
3418  For the odd case where we have a location in a fastsaved file which
3419  does not have an entry in the FKP, perhaps its para end is in the next
3420  piece, or perhaps the cp just doesn't exist at all in this document.
3421  AdvSprm doesn't know so it sets the PLCF as dirty and we figure out
3422  in this method what the situation is
3423 
3424  It doesn't exist then the piece iterator will not be able to find it.
3425  Otherwise our cool fastsave algorithm can be brought to bear on the
3426  problem.
3427  */
3428  if( !pPieceIter )
3429  return;
3430  const sal_uInt32 nOldPos = pPieceIter->GetIdx();
3431  bool bOk = pPieceIter->SeekPos(nOrigCp);
3432  pPieceIter->SetIdx(nOldPos);
3433  if (!bOk)
3434  return;
3435  }
3436 
3437  if( pPcd ) // piece table available
3438  {
3439  // Init ( no ++ called, yet )
3440  if( (nAttrStart > nAttrEnd) || (nAttrStart == -1) )
3441  {
3442  p->bRealLineEnd = (ePLCF == PAP);
3443 
3444  if ( ((ePLCF == PAP ) || (ePLCF == CHP)) && (nOrigCp != WW8_CP_MAX) )
3445  {
3446  bool bIsUnicode=false;
3447  /*
3448  To find the end of a paragraph for a character in a
3449  complex format file.
3450 
3451  It is necessary to know the piece that contains the
3452  character and the FC assigned to the character.
3453  */
3454 
3455  //We set the piece iterator to the piece that contains the
3456  //character, now we have the correct piece for this character
3457  sal_uInt32 nOldPos = pPieceIter->GetIdx();
3458  p->nStartPos = nOrigCp;
3460 
3461  //This is the FC assigned to the character, but we already
3462  //have the result of the next stage, so we can skip this step
3463  //WW8_FC nStartFc = rSBase.WW8Cp2Fc(p->nStartPos, &bIsUnicode);
3464 
3465  /*
3466  Using the FC of the character, first search the FKP that
3467  describes the character to find the smallest FC in the rgfc
3468  that is larger than the character FC.
3469  */
3470  //But the search has already been done, the next largest FC is
3471  //p->nEndPos.
3472  WW8_FC nOldEndPos = p->nEndPos;
3473 
3474  /*
3475  If the FC found in the FKP is less than or equal to the limit
3476  FC of the piece, the end of the paragraph that contains the
3477  character is at the FKP FC minus 1.
3478  */
3479  WW8_CP nCpStart, nCpEnd;
3480  void* pData=nullptr;
3481  bool bOk = pPieceIter->Get(nCpStart, nCpEnd, pData);
3482 
3483  if (!bOk)
3484  {
3485  pPieceIter->SetIdx(nOldPos);
3486  return;
3487  }
3488 
3489  WW8_FC nLimitFC = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
3490  WW8_FC nBeginLimitFC = nLimitFC;
3491  if (IsEightPlus(GetFIBVersion()))
3492  {
3493  nBeginLimitFC =
3495  bIsUnicode);
3496  }
3497 
3498  WW8_CP nCpLen;
3499  bool bFail = o3tl::checked_sub(nCpEnd, nCpStart, nCpLen);
3500  if (bFail)
3501  {
3502  SAL_WARN("sw.ww8", "broken offset, ignoring");
3503  p->nStartPos = p->nEndPos = WW8_FC_MAX;
3504  pPieceIter->SetIdx(nOldPos);
3505  return;
3506  }
3507 
3508  if (bIsUnicode)
3509  {
3510  bFail = o3tl::checked_multiply<WW8_CP>(nCpLen, 2, nCpLen);
3511  if (bFail)
3512  {
3513  SAL_WARN("sw.ww8", "broken offset, ignoring");
3514  p->nStartPos = p->nEndPos = WW8_FC_MAX;
3515  pPieceIter->SetIdx(nOldPos);
3516  return;
3517  }
3518  }
3519 
3520  bFail = o3tl::checked_add(nBeginLimitFC, nCpLen, nLimitFC);
3521  if (bFail)
3522  {
3523  SAL_WARN("sw.ww8", "broken offset, ignoring");
3524  p->nStartPos = p->nEndPos = WW8_FC_MAX;
3525  pPieceIter->SetIdx(nOldPos);
3526  return;
3527  }
3528 
3529  if (nOldEndPos <= nLimitFC)
3530  {
3531  bFail = o3tl::checked_sub(nLimitFC, nOldEndPos, nCpLen);
3532  if (bFail)
3533  {
3534  SAL_WARN("sw.ww8", "broken offset, ignoring");
3535  p->nStartPos = p->nEndPos = WW8_FC_MAX;
3536  pPieceIter->SetIdx(nOldPos);
3537  return;
3538  }
3539 
3540  nCpLen /= (bIsUnicode ? 2 : 1);
3541 
3542  bFail = o3tl::checked_sub(nCpEnd, nCpLen, p->nEndPos);
3543  if (bFail)
3544  {
3545  SAL_WARN("sw.ww8", "broken offset, ignoring");
3546  p->nStartPos = p->nEndPos = WW8_FC_MAX;
3547  pPieceIter->SetIdx(nOldPos);
3548  return;
3549  }
3550  }
3551  else
3552  {
3553  if (ePLCF == CHP)
3554  p->nEndPos = nCpEnd;
3555  else
3556  {
3557  /*
3558  If the FKP FC that was found was greater than the FC
3559  of the end of the piece, scan piece by piece toward
3560  the end of the document until a piece is found that
3561  contains a paragraph end mark.
3562  */
3563 
3564  /*
3565  It's possible to check if a piece contains a paragraph
3566  mark by using the FC of the beginning of the piece to
3567  search in the FKPs for the smallest FC in the FKP rgfc
3568  that is greater than the FC of the beginning of the
3569  piece. If the FC found is less than or equal to the
3570  limit FC of the piece, then the character that ends
3571  the paragraph is the character immediately before the
3572  FKP fc
3573  */
3574 
3575  pPieceIter->advance();
3576 
3577  for (;pPieceIter->GetIdx() < pPieceIter->GetIMax();
3578  pPieceIter->advance())
3579  {
3580  if( !pPieceIter->Get( nCpStart, nCpEnd, pData ) )
3581  {
3582  OSL_ENSURE( false, "piece iter broken!" );
3583  break;
3584  }
3585  bIsUnicode = false;
3586  sal_Int32 nFcStart=SVBT32ToUInt32(static_cast<WW8_PCD*>(pData)->fc);
3587 
3588  if (IsEightPlus(GetFIBVersion()))
3589  {
3590  nFcStart =
3592  nFcStart,bIsUnicode );
3593  }
3594 
3595  bFail = o3tl::checked_sub(nCpEnd, nCpStart, nCpLen);
3596  if (bFail)
3597  {
3598  SAL_WARN("sw.ww8", "broken offset, ignoring");
3599  p->nStartPos = p->nEndPos = WW8_FC_MAX;
3600  continue;
3601  }
3602 
3603  if (bIsUnicode)
3604  {
3605  bFail = o3tl::checked_multiply<WW8_CP>(nCpLen, 2, nCpLen);
3606  if (bFail)
3607  {
3608  SAL_WARN("sw.ww8", "broken offset, ignoring");
3609  p->nStartPos = p->nEndPos = WW8_FC_MAX;
3610  continue;
3611  }
3612  }
3613 
3614  bFail = o3tl::checked_add(nFcStart, nCpLen, nLimitFC);
3615  if (bFail)
3616  {
3617  SAL_WARN("sw.ww8", "broken offset, ignoring");
3618  p->nStartPos = p->nEndPos = WW8_FC_MAX;
3619  continue;
3620  }
3621 
3622  //if it doesn't exist, skip it
3623  if (!SeekPos(nCpStart))
3624  continue;
3625 
3626  WW8_FC nOne,nSmallest;
3628  nSmallest, p->nSprmsLen);
3629 
3630  if (nSmallest <= nLimitFC)
3631  {
3632  WW8_CP nCpDiff;
3633  bFail = o3tl::checked_sub(nLimitFC, nSmallest, nCpDiff);
3634  if (bFail)
3635  {
3636  SAL_WARN("sw.ww8", "broken offset, ignoring");
3637  p->nStartPos = p->nEndPos = WW8_FC_MAX;
3638  continue;
3639  }
3640  if (bIsUnicode)
3641  nCpDiff /= 2;
3642 
3643  WW8_CP nEndPos;
3644  bFail = o3tl::checked_sub(nCpEnd, nCpDiff, nEndPos);
3645  if (bFail)
3646  {
3647  SAL_WARN("sw.ww8", "broken offset, ignoring");
3648  p->nStartPos = p->nEndPos = WW8_FC_MAX;
3649  continue;
3650  }
3651 
3652  OSL_ENSURE(nEndPos >= p->nStartPos, "EndPos before StartPos");
3653 
3654  if (nEndPos >= p->nStartPos)
3655  p->nEndPos = nEndPos;
3656 
3657  break;
3658  }
3659  }
3660  }
3661  }
3662  pPieceIter->SetIdx( nOldPos );
3663  }
3664  else
3666  }
3667  else
3668  {
3669  p->nStartPos = nAttrStart;
3670  p->nEndPos = nAttrEnd;
3671  p->bRealLineEnd = bLineEnd;
3672  }
3673  }
3674  else // NO piece table !!!
3675  {
3676  p->nStartPos = rSBase.WW8Fc2Cp( p->nStartPos );
3677  p->nEndPos = rSBase.WW8Fc2Cp( p->nEndPos );
3678  p->bRealLineEnd = ePLCF == PAP;
3679  }
3680 }
3681 
3683 {
3685  // !pPcd: emergency break
3686  if ( !bComplex || !pPcd )
3687  return;
3688 
3689  if( GetPCDIdx() >= pPcd->GetIMax() ) // End of PLCF
3690  {
3692  return;
3693  }
3694 
3695  sal_Int32 nFkpLen; // Fkp entry
3696  // get Fkp entry
3698 
3700  bLineEnd = (ePLCF == PAP);
3701 }
3702 
3704  const WW8Fib& rFib, WW8_CP nStartCp)
3705  : WW8PLCFx(rFib, true), maSprmParser(rFib),
3706  pStrm(pSt), nArrMax(256), nSprmSiz(0)
3707 {
3708  if (rFib.m_lcbPlcfsed)
3709  pPLCF.reset( new WW8PLCF(*pTableSt, rFib.m_fcPlcfsed, rFib.m_lcbPlcfsed,
3710  GetFIBVersion() <= ww::eWW2 ? 6 : 12, nStartCp) );
3711 
3712  pSprms.reset( new sal_uInt8[nArrMax] ); // maximum length
3713 }
3714 
3716 {
3717 }
3718 
3719 sal_uInt32 WW8PLCFx_SEPX::GetIdx() const
3720 {
3721  return pPLCF ? pPLCF->GetIdx() : 0;
3722 }
3723 
3724 void WW8PLCFx_SEPX::SetIdx(sal_uInt32 nIdx)
3725 {
3726  if( pPLCF ) pPLCF->SetIdx( nIdx );
3727 }
3728 
3730 {
3731  return pPLCF && pPLCF->SeekPos( nCpPos );
3732 }
3733 
3735 {
3736  return pPLCF ? pPLCF->Where() : 0;
3737 }
3738 
3740 {
3741  if( !pPLCF ) return;
3742 
3743  void* pData;
3744 
3745  p->bRealLineEnd = false;
3746  if (!pPLCF->Get( p->nStartPos, p->nEndPos, pData ))
3747  {
3748  p->nStartPos = p->nEndPos = WW8_CP_MAX; // PLCF completely processed
3749  p->pMemPos = nullptr;
3750  p->nSprmsLen = 0;
3751  }
3752  else
3753  {
3754  sal_uInt32 nPo = SVBT32ToUInt32( static_cast<sal_uInt8*>(pData)+2 );
3755  if (nPo == 0xFFFFFFFF || !checkSeek(*pStrm, nPo))
3756  {
3757  p->nStartPos = p->nEndPos = WW8_CP_MAX; // Sepx empty
3758  p->pMemPos = nullptr;
3759  p->nSprmsLen = 0;
3760  }
3761  else
3762  {
3763  // read len
3764  if (GetFIBVersion() <= ww::eWW2) // eWW6 ?, docs say yes, but...
3765  {
3766  sal_uInt8 nSiz(0);
3767  pStrm->ReadUChar( nSiz );
3768  nSprmSiz = nSiz;
3769  }
3770  else
3771  {
3773  }
3774 
3775  std::size_t nRemaining = pStrm->remainingSize();
3776  if (nSprmSiz > nRemaining)
3777  nSprmSiz = nRemaining;
3778 
3779  if( nSprmSiz > nArrMax )
3780  { // does not fit
3781  nArrMax = nSprmSiz; // Get more memory
3782  pSprms.reset( new sal_uInt8[nArrMax] );
3783  }
3784  nSprmSiz = pStrm->ReadBytes(pSprms.get(), nSprmSiz); // read Sprms
3785 
3786  p->nSprmsLen = nSprmSiz;
3787  p->pMemPos = pSprms.get(); // return Position
3788  }
3789  }
3790 }
3791 
3793 {
3794  if (pPLCF)
3795  pPLCF->advance();
3796 }
3797 
3798 SprmResult WW8PLCFx_SEPX::HasSprm(sal_uInt16 nId) const
3799 {
3800  return HasSprm(nId, pSprms.get(), nSprmSiz);
3801 }
3802 
3803 SprmResult WW8PLCFx_SEPX::HasSprm( sal_uInt16 nId, const sal_uInt8* pOtherSprms,
3804  tools::Long nOtherSprmSiz ) const
3805 {
3806  SprmResult aRet;
3807  if (pPLCF)
3808  {
3809  WW8SprmIter aIter(pOtherSprms, nOtherSprmSiz, maSprmParser);
3810  aRet = aIter.FindSprm(nId, /*bFindFirst=*/true);
3811  }
3812  return aRet;
3813 }
3814 
3815 bool WW8PLCFx_SEPX::Find4Sprms(sal_uInt16 nId1,sal_uInt16 nId2,sal_uInt16 nId3,sal_uInt16 nId4,
3816  SprmResult& r1, SprmResult& r2, SprmResult& r3, SprmResult& r4) const
3817 {
3818  if( !pPLCF )
3819  return false;
3820 
3821  bool bFound = false;
3822 
3823  sal_uInt8* pSp = pSprms.get();
3824  size_t i = 0;
3825  while (i + maSprmParser.MinSprmLen() <= nSprmSiz)
3826  {
3827  // Sprm found?
3828  const sal_uInt16 nCurrentId = maSprmParser.GetSprmId(pSp);
3829  sal_Int32 nRemLen = nSprmSiz - i;
3830  const sal_Int32 x = maSprmParser.GetSprmSize(nCurrentId, pSp, nRemLen);
3831  bool bValid = x <= nRemLen;
3832  if (!bValid)
3833  {
3834  SAL_WARN("sw.ww8", "sprm longer than remaining bytes, doc or parser is wrong");
3835  break;
3836  }
3837  bool bOk = true;
3838  if( nCurrentId == nId1 )
3839  {
3840  sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId1);
3841  r1 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3842  }
3843  else if( nCurrentId == nId2 )
3844  {
3845  sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId2);
3846  r2 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3847  }
3848  else if( nCurrentId == nId3 )
3849  {
3850  sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId3);
3851  r3 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3852  }
3853  else if( nCurrentId == nId4 )
3854  {
3855  sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId4);
3856  r4 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3857  }
3858  else
3859  bOk = false;
3860  bFound |= bOk;
3861  // increment pointer so that it points to next SPRM
3862  i += x;
3863  pSp += x;
3864  }
3865  return bFound;
3866 }
3867 
3868 SprmResult WW8PLCFx_SEPX::HasSprm( sal_uInt16 nId, sal_uInt8 n2nd ) const
3869 {
3870  SprmResult aRet;
3871  if (pPLCF)
3872  {
3873  WW8SprmIter aIter(pSprms.get(), nSprmSiz, maSprmParser);
3874  aRet = aIter.FindSprm(nId, /*bFindFirst=*/true, &n2nd);
3875  }
3876  return aRet;
3877 }
3878 
3880  WW8_CP nStartCp, tools::Long nFcRef, tools::Long nLenRef, tools::Long nFcText, tools::Long nLenText,
3881  tools::Long nStruct)
3882  : WW8PLCFx(rFib, true)
3883 {
3884  if( nLenRef && nLenText )
3885  {
3886  pRef.reset(new WW8PLCF(*pSt, nFcRef, nLenRef, nStruct, nStartCp));
3887  pText.reset(new WW8PLCF(*pSt, nFcText, nLenText, 0, nStartCp));
3888  }
3889 }
3890 
3892 {
3893  pRef.reset();
3894  pText.reset();
3895 }
3896 
3897 sal_uInt32 WW8PLCFx_SubDoc::GetIdx() const
3898 {
3899  // Probably pText ... no need for it
3900  if( pRef )
3901  return ( pRef->GetIdx() << 16 | pText->GetIdx() );
3902  return 0;
3903 }
3904 
3905 void WW8PLCFx_SubDoc::SetIdx(sal_uInt32 nIdx)
3906 {
3907  if( pRef )
3908  {
3909  pRef->SetIdx( nIdx >> 16 );
3910  // Probably pText ... no need for it
3911  pText->SetIdx( nIdx & 0xFFFF );
3912  }
3913 }
3914 
3916 {
3917  return pRef && pRef->SeekPos( nCpPos );
3918 }
3919 
3921 {
3922  return pRef ? pRef->Where() : WW8_CP_MAX;
3923 }
3924 
3926 {
3927  p->nStartPos = p->nEndPos = WW8_CP_MAX;
3928  p->pMemPos = nullptr;
3929  p->nSprmsLen = 0;
3930  p->bRealLineEnd = false;
3931 
3932  if (!pRef)
3933  return;
3934 
3935  sal_uInt32 nNr = pRef->GetIdx();
3936 
3937  void *pData;
3938  WW8_CP nFoo;
3939  if (!pRef->Get(p->nStartPos, nFoo, pData))
3940  {
3941  p->nEndPos = p->nStartPos = WW8_CP_MAX;
3942  return;
3943  }
3944 
3945  if (o3tl::checked_add<WW8_CP>(p->nStartPos, 1, p->nEndPos))
3946  {
3947  SAL_WARN("sw.ww8", "broken offset, ignoring");
3948  p->nEndPos = p->nStartPos = WW8_CP_MAX;
3949  return;
3950  }
3951 
3952  if (!pText)
3953  return;
3954 
3955  pText->SetIdx(nNr);
3956 
3957  if (!pText->Get(p->nCp2OrIdx, p->nSprmsLen, pData))
3958  {
3959  p->nEndPos = p->nStartPos = WW8_CP_MAX;
3960  p->nSprmsLen = 0;
3961  return;
3962  }
3963 
3964  if (p->nCp2OrIdx < 0 || p->nCp2OrIdx > p->nSprmsLen)
3965  {
3966  SAL_WARN("sw.ww8", "Document has invalid Cp or Idx, ignoring it");
3967  p->nEndPos = p->nStartPos = WW8_CP_MAX;
3968  p->nSprmsLen = 0;
3969  return;
3970  }
3971 
3972  p->nSprmsLen -= p->nCp2OrIdx;
3973 }
3974 
3976 {
3977  if (pRef && pText)
3978  {
3979  pRef->advance();
3980  pText->advance();
3981  }
3982 }
3983 
3984 // fields
3985 WW8PLCFx_FLD::WW8PLCFx_FLD( SvStream* pSt, const WW8Fib& rMyFib, short nType)
3986  : WW8PLCFx(rMyFib, true), rFib(rMyFib)
3987 {
3988  WW8_FC nFc;
3989  sal_Int32 nLen;
3990 
3991  switch( nType )
3992  {
3993  case MAN_HDFT:
3994  nFc = rFib.m_fcPlcffldHdr;
3995  nLen = rFib.m_lcbPlcffldHdr;
3996  break;
3997  case MAN_FTN:
3998  nFc = rFib.m_fcPlcffldFootnote;
3999  nLen = rFib.m_lcbPlcffldFootnote;
4000  break;
4001  case MAN_EDN:
4002  nFc = rFib.m_fcPlcffldEdn;
4003  nLen = rFib.m_lcbPlcffldEdn;
4004  break;
4005  case MAN_AND:
4006  nFc = rFib.m_fcPlcffldAtn;
4007  nLen = rFib.m_lcbPlcffldAtn;
4008  break;
4009  case MAN_TXBX:
4010  nFc = rFib.m_fcPlcffldTxbx;
4011  nLen = rFib.m_lcbPlcffldTxbx;
4012  break;
4013  case MAN_TXBX_HDFT:
4014  nFc = rFib.m_fcPlcffldHdrTxbx;
4015  nLen = rFib.m_lcbPlcffldHdrTxbx;
4016  break;
4017  default:
4018  nFc = rFib.m_fcPlcffldMom;
4019  nLen = rFib.m_lcbPlcffldMom;
4020  break;
4021  }
4022 
4023  if( nLen )
4024  pPLCF.reset( new WW8PLCFspecial( pSt, nFc, nLen, 2 ) );
4025 }
4026 
4028 {
4029 }
4030 
4031 sal_uInt32 WW8PLCFx_FLD::GetIdx() const
4032 {
4033  return pPLCF ? pPLCF->GetIdx() : 0;
4034 }
4035 
4036 void WW8PLCFx_FLD::SetIdx(sal_uInt32 nIdx)
4037 {
4038  if( pPLCF )
4039  pPLCF->SetIdx( nIdx );
4040 }
4041 
4043 {
4044  return pPLCF && pPLCF->SeekPosExact( nCpPos );
4045 }
4046 
4048 {
4049  return pPLCF ? pPLCF->Where() : WW8_CP_MAX;
4050 }
4051 
4053 {
4054  void* pData;
4055  sal_Int32 nTest;
4056  return pPLCF && pPLCF->Get(nTest, pData) && ((static_cast<sal_uInt8*>(pData)[0] & 0x1f) == 0x13);
4057 }
4058 
4060 {
4061  bool bRet = false;
4062 
4063  if (pPLCF)
4064  {
4065  tools::Long n = pPLCF->GetIdx();
4066 
4067  pPLCF->advance();
4068 
4069  void* pData;
4070  sal_Int32 nTest;
4071  if ( pPLCF->Get(nTest, pData) && ((static_cast<sal_uInt8*>(pData)[0] & 0x1f) == 0x15) )
4072  {
4073  nCP = nTest;
4074  bRet = true;
4075  }
4076 
4077  pPLCF->SetIdx(n);
4078  }
4079 
4080  return bRet;
4081 }
4082 
4084 {
4085  p->nStartPos = p->nEndPos = WW8_CP_MAX;
4086  p->pMemPos = nullptr;
4087  p->nSprmsLen = 0;
4088  p->bRealLineEnd = false;
4089 
4090  if (!pPLCF)
4091  {
4092  p->nStartPos = WW8_CP_MAX; // there are no fields
4093  return;
4094  }
4095 
4096  tools::Long n = pPLCF->GetIdx();
4097 
4098  sal_Int32 nP;
4099  void *pData;
4100  if (!pPLCF->Get(nP, pData)) // end of PLCFspecial?
4101  {
4102  p->nStartPos = WW8_CP_MAX; // PLCF completely processed
4103  return;
4104  }
4105 
4106  p->nStartPos = nP;
4107 
4108  pPLCF->advance();
4109  if (!pPLCF->Get(nP, pData)) // end of PLCFspecial?
4110  {
4111  p->nStartPos = WW8_CP_MAX; // PLCF completely processed
4112  return;
4113  }
4114 
4115  p->nEndPos = nP;
4116 
4117  pPLCF->SetIdx(n);
4118 
4119  p->nCp2OrIdx = pPLCF->GetIdx();
4120 }
4121 
4123 {
4124  SAL_WARN_IF(!pPLCF, "sw.ww8", "Call without PLCFspecial field");
4125  if( !pPLCF )
4126  return;
4127  pPLCF->advance();
4128 }
4129 
4131 {
4132  SAL_WARN_IF(!pPLCF, "sw.ww8", "Call without PLCFspecial field");
4133  if( !pPLCF )
4134  return false;
4135 
4136  tools::Long n = pPLCF->GetIdx();
4137  pPLCF->SetIdx(nIdx);
4138 
4139  bool bOk = WW8GetFieldPara(*pPLCF, rF);
4140 
4141  pPLCF->SetIdx(n);
4142  return bOk;
4143 }
4144 
4145 // WW8PLCF_Book
4146 void WW8ReadSTTBF(bool bVer8, SvStream& rStrm, sal_uInt32 nStart, sal_Int32 nLen,
4147  sal_uInt16 nExtraLen, rtl_TextEncoding eCS, std::vector<OUString> &rArray,
4148  std::vector<ww::bytes>* pExtraArray, std::vector<OUString>* pValueArray)
4149 {
4150  if (nLen==0) // Handle Empty STTBF
4151  return;
4152 
4153  sal_uInt64 const nOldPos = rStrm.Tell();
4154  if (checkSeek(rStrm, nStart))
4155  {
4156  sal_uInt16 nLen2(0);
4157  rStrm.ReadUInt16( nLen2 ); // bVer67: total length of structure
4158  // bVer8 : count of strings
4159 
4160  if( bVer8 )
4161  {
4162  sal_uInt16 nStrings(0);
4163  bool bUnicode = (0xFFFF == nLen2);
4164  if (bUnicode)
4165  rStrm.ReadUInt16( nStrings );
4166  else
4167  nStrings = nLen2;
4168 
4169  rStrm.ReadUInt16( nExtraLen );
4170 
4171  const size_t nMinStringLen = bUnicode ? sizeof(sal_uInt16) : sizeof(sal_uInt8);
4172  const size_t nMinRecordSize = nExtraLen + nMinStringLen;
4173  assert(nMinRecordSize != 0 && "impossible to be zero");
4174  const size_t nMaxPossibleStrings = rStrm.remainingSize() / nMinRecordSize;
4175  if (nStrings > nMaxPossibleStrings)
4176  {
4177  SAL_WARN("sw.ww8", "STTBF claims " << nStrings << " entries, but only " << nMaxPossibleStrings << " are possible");
4178  nStrings = nMaxPossibleStrings;
4179  }
4180 
4181  if (nExtraLen && nStrings)
4182  {
4183  const size_t nMaxExtraLen = (rStrm.remainingSize() - (nStrings * nMinStringLen)) / nStrings;
4184  if (nExtraLen > nMaxExtraLen)
4185  {
4186  SAL_WARN("sw.ww8", "STTBF claims " << nMaxExtraLen << " extra len, but only " << nMaxExtraLen << " are possible");
4187  nExtraLen = nMaxExtraLen;
4188  }
4189  }
4190 
4191  for (sal_uInt16 i=0; i < nStrings; ++i)
4192  {
4193  if (bUnicode)
4194  rArray.push_back(read_uInt16_PascalString(rStrm));
4195  else
4196  {
4197  OString aTmp = read_uInt8_lenPrefixed_uInt8s_ToOString(rStrm);
4198  rArray.push_back(OStringToOUString(aTmp, eCS));
4199  }
4200 
4201  // Skip the extra data
4202  if (nExtraLen)
4203  {
4204  if (pExtraArray)
4205  {
4206  ww::bytes extraData(nExtraLen);
4207  rStrm.ReadBytes(extraData.data(), nExtraLen);
4208  pExtraArray->push_back(extraData);
4209  }
4210  else
4211  rStrm.SeekRel( nExtraLen );
4212  }
4213  }
4214  // read the value of the document variables, if requested.
4215  if (pValueArray)
4216  {
4217  for (sal_uInt16 i=0; i < nStrings; ++i)
4218  {
4219  if( bUnicode )
4220  pValueArray->push_back(read_uInt16_PascalString(rStrm));
4221  else
4222  {
4223  OString aTmp = read_uInt8_lenPrefixed_uInt8s_ToOString(rStrm);
4224  pValueArray->push_back(OStringToOUString(aTmp, eCS));
4225  }
4226  }
4227  }
4228  }
4229  else
4230  {
4231  if( nLen2 != nLen )
4232  {
4233  OSL_ENSURE(nLen2 == nLen,
4234  "Fib length and read length are different");
4235  if (nLen > SAL_MAX_UINT16)
4236  nLen = SAL_MAX_UINT16;
4237  else if (nLen < 2 )
4238  nLen = 2;
4239  nLen2 = o3tl::narrowing<sal_uInt16>(nLen);
4240  }
4241  sal_uLong nRead = 0;
4242  for( nLen2 -= 2; nRead < nLen2; )
4243  {
4244  sal_uInt8 nBChar(0);
4245  rStrm.ReadUChar( nBChar );
4246  ++nRead;
4247  if (nBChar)
4248  {
4249  OString aTmp = read_uInt8s_ToOString(rStrm, nBChar);
4250  nRead += aTmp.getLength();
4251  rArray.push_back(OStringToOUString(aTmp, eCS));
4252  }
4253  else
4254  rArray.emplace_back();
4255 
4256  // Skip the extra data (for bVer67 versions this must come from
4257  // external knowledge)
4258  if (nExtraLen)
4259  {
4260  if (pExtraArray)
4261  {
4262  ww::bytes extraData(nExtraLen);
4263  rStrm.ReadBytes(extraData.data(), nExtraLen);
4264  pExtraArray->push_back(extraData);
4265  }
4266  else
4267  rStrm.SeekRel( nExtraLen );
4268  nRead+=nExtraLen;
4269  }
4270  }
4271  }
4272  }
4273  rStrm.Seek(nOldPos);
4274 }
4275 
4277  : WW8PLCFx(rFib, false), nIsEnd(0), nBookmarkId(1)
4278 {
4279  if( !rFib.m_fcPlcfbkf || !rFib.m_lcbPlcfbkf || !rFib.m_fcPlcfbkl ||
4280  !rFib.m_lcbPlcfbkl || !rFib.m_fcSttbfbkmk || !rFib.m_lcbSttbfbkmk )
4281  {
4282  nIMax = 0;
4283  }
4284  else
4285  {
4286  pBook[0].reset( new WW8PLCFspecial(pTableSt,rFib.m_fcPlcfbkf,rFib.m_lcbPlcfbkf,4) );
4287 
4288  pBook[1].reset( new WW8PLCFspecial(pTableSt,rFib.m_fcPlcfbkl,rFib.m_lcbPlcfbkl,0) );
4289 
4290  rtl_TextEncoding eStructChrSet = WW8Fib::GetFIBCharset(rFib.m_chseTables, rFib.m_lid);
4291 
4292  WW8ReadSTTBF( (7 < rFib.m_nVersion), *pTableSt, rFib.m_fcSttbfbkmk,
4293  rFib.m_lcbSttbfbkmk, 0, eStructChrSet, aBookNames );
4294 
4295  nIMax = aBookNames.size();
4296 
4297  if( pBook[0]->GetIMax() < nIMax ) // Count of Bookmarks
4298  nIMax = pBook[0]->GetIMax();
4299  if( pBook[1]->GetIMax() < nIMax )
4300  nIMax = pBook[1]->GetIMax();
4301  aStatus.resize(nIMax);
4302  }
4303 }
4304 
4306 {
4307 }
4308 
4309 sal_uInt32 WW8PLCFx_Book::GetIdx() const
4310 {
4311  return nIMax ? pBook[0]->GetIdx() : 0;
4312 }
4313 
4314 void WW8PLCFx_Book::SetIdx(sal_uInt32 nI)
4315 {
4316  if( nIMax )
4317  pBook[0]->SetIdx( nI );
4318 }
4319 
4320 sal_uInt32 WW8PLCFx_Book::GetIdx2() const
4321 {
4322  return nIMax ? ( pBook[1]->GetIdx() | ( nIsEnd ? 0x80000000 : 0 ) ) : 0;
4323 }
4324 
4325 void WW8PLCFx_Book::SetIdx2(sal_uInt32 nI)
4326 {
4327  if( nIMax )
4328  {
4329  pBook[1]->SetIdx( nI & 0x7fffffff );
4330  nIsEnd = o3tl::narrowing<sal_uInt16>( ( nI >> 31 ) & 1 ); // 0 or 1
4331  }
4332 }
4333 
4335 {
4336  if( !pBook[0] )
4337  return false;
4338 
4339  bool bOk = pBook[0]->SeekPosExact( nCpPos );
4340  bOk &= pBook[1]->SeekPosExact( nCpPos );
4341  nIsEnd = 0;
4342 
4343  return bOk;
4344 }
4345 
4347 {
4348  return pBook[nIsEnd]->Where();
4349 }
4350 
4351 tools::Long WW8PLCFx_Book::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
4352 {
4353  void* pData;
4354  rEnd = WW8_CP_MAX;
4355  rLen = 0;
4356 
4357  if (!pBook[0] || !pBook[1] || !nIMax || (pBook[nIsEnd]->GetIdx()) >= nIMax)
4358  {
4359  rStart = rEnd = WW8_CP_MAX;
4360  return -1;
4361  }
4362 
4363  (void)pBook[nIsEnd]->Get( rStart, pData ); // query position
4364  return pBook[nIsEnd]->GetIdx();
4365 }
4366 
4367 // The operator ++ has a pitfall: If 2 bookmarks adjoin each other,
4368 // we should first go to the end of the first one
4369 // and then to the beginning of the second one.
4370 // But if 2 bookmarks with the length of 0 lie on top of each other,
4371 // we *must* first find the start and end of each bookmark.
4372 // The case of: ][
4373 // [...]
4374 // ][
4375 // is not solved yet.
4376 // Because I must jump back and forth in the start- and end-indices then.
4377 // This would require one more index or bitfield to remember
4378 // the already processed bookmarks.
4379 
4381 {
4382  if( !(pBook[0] && pBook[1] && nIMax) )
4383  return;
4384 
4385  (*pBook[nIsEnd]).advance();
4386 
4387  sal_uLong l0 = pBook[0]->Where();
4388  sal_uLong l1 = pBook[1]->Where();
4389  if( l0 < l1 )
4390  nIsEnd = 0;
4391  else if( l1 < l0 )
4392  nIsEnd = 1;
4393  else
4394  {
4395  const void * p = pBook[0]->GetData(pBook[0]->GetIdx());
4396  tools::Long nPairFor = (p == nullptr) ? 0 : SVBT16ToUInt16(*static_cast<SVBT16 const *>(p));
4397  if (nPairFor == pBook[1]->GetIdx())
4398  nIsEnd = 0;
4399  else
4400  nIsEnd = nIsEnd ? 0 : 1;
4401  }
4402 }
4403 
4405 {
4406  if( nIsEnd )
4407  {
4408  OSL_ENSURE( false, "Incorrect call (1) of PLCF_Book::GetLen()" );
4409  return 0;
4410  }
4411  void * p;
4412  WW8_CP nStartPos;
4413  if( !pBook[0]->Get( nStartPos, p ) )
4414  {
4415  OSL_ENSURE( false, "Incorrect call (2) of PLCF_Book::GetLen()" );
4416  return 0;
4417  }
4418  const sal_uInt16 nEndIdx = SVBT16ToUInt16( *static_cast<SVBT16*>(p) );
4419  tools::Long nNum = pBook[1]->GetPos( nEndIdx );
4420  nNum -= nStartPos;
4421  return nNum;
4422 }
4423 
4424 void WW8PLCFx_Book::SetStatus(sal_uInt16 nIndex, eBookStatus eStat)
4425 {
4426  SAL_WARN_IF(nIndex >= nIMax, "sw.ww8",
4427  "bookmark index " << nIndex << " invalid");
4428  eBookStatus eStatus = aStatus.at(nIndex);
4429  aStatus[nIndex] = static_cast<eBookStatus>(eStatus | eStat);
4430 }
4431 
4433 {
4434  if (aStatus.empty())
4435  return BOOK_NORMAL;
4436  tools::Long nEndIdx = GetHandle();
4437  return ( nEndIdx < nIMax ) ? aStatus[nEndIdx] : BOOK_NORMAL;
4438 }
4439 
4441 {
4442  if( !pBook[0] || !pBook[1] )
4443  return LONG_MAX;
4444 
4445  if( nIsEnd )
4446  return pBook[1]->GetIdx();
4447  else
4448  {
4449  if (const void* p = pBook[0]->GetData(pBook[0]->GetIdx()))
4450  return SVBT16ToUInt16( *static_cast<SVBT16 const *>(p) );
4451  else
4452  return LONG_MAX;
4453  }
4454 }
4455 
4456 OUString WW8PLCFx_Book::GetBookmark(tools::Long nStart,tools::Long nEnd, sal_uInt16 &nIndex)
4457 {
4458  bool bFound = false;
4459  sal_uInt16 i = 0;
4460  if (pBook[0] && pBook[1])
4461  {
4462  WW8_CP nStartCurrent, nEndCurrent;
4463  while (sal::static_int_cast<decltype(aBookNames)::size_type>(i) < aBookNames.size())
4464  {
4465  void* p;
4466  sal_uInt16 nEndIdx;
4467 
4468  if( pBook[0]->GetData( i, nStartCurrent, p ) && p )
4469  nEndIdx = SVBT16ToUInt16( *static_cast<SVBT16*>(p) );
4470  else
4471  {
4472  OSL_ENSURE( false, "Bookmark-EndIdx not readable" );
4473  nEndIdx = i;
4474  }
4475 
4476  nEndCurrent = pBook[1]->GetPos( nEndIdx );
4477 
4478  if ((nStartCurrent >= nStart) && (nEndCurrent <= nEnd))
4479  {
4480  nIndex = i;
4481  bFound=true;
4482  break;
4483  }
4484  ++i;
4485  }
4486  }
4487  return bFound ? aBookNames[i] : OUString();
4488 }
4489 
4490 OUString WW8PLCFx_Book::GetUniqueBookmarkName(const OUString &rSuggestedName)
4491 {
4492  OUString aRet(rSuggestedName.isEmpty() ? OUString("Unnamed") : rSuggestedName);
4493  size_t i = 0;
4494  while (i < aBookNames.size())
4495  {
4496  if (aRet == aBookNames[i])
4497  {
4498  sal_Int32 len = aRet.getLength();
4499  sal_Int32 p = len - 1;
4500  while (p > 0 && aRet[p] >= '0' && aRet[p] <= '9')
4501  --p;
4502  aRet = aRet.subView(0, p+1) + OUString::number(nBookmarkId++);
4503  i = 0; // start search from beginning
4504  }
4505  else
4506  ++i;
4507  }
4508  return aRet;
4509 }
4510 
4511 void WW8PLCFx_Book::MapName(OUString& rName)
4512 {
4513  if( !pBook[0] || !pBook[1] )
4514  return;
4515 
4516  size_t i = 0;
4517  while (i < aBookNames.size())
4518  {
4519  if (rName.equalsIgnoreAsciiCase(aBookNames[i]))
4520  {
4521  rName = aBookNames[i];
4522  break;
4523  }
4524  ++i;
4525  }
4526 }
4527 
4528 const OUString* WW8PLCFx_Book::GetName() const
4529 {
4530  const OUString *pRet = nullptr;
4531  if (!nIsEnd && (pBook[0]->GetIdx() < nIMax))
4532  pRet = &(aBookNames[pBook[0]->GetIdx()]);
4533  return pRet;
4534 }
4535 
4537  : WW8PLCFx(rFib, /*bSprm=*/false),
4538  m_bIsEnd(false)
4539 {
4540  if (!rFib.m_fcPlcfAtnbkf || !rFib.m_lcbPlcfAtnbkf || !rFib.m_fcPlcfAtnbkl || !rFib.m_lcbPlcfAtnbkl)
4541  {
4542  nIMax = 0;
4543  }
4544  else
4545  {
4546  m_pBook[0].reset( new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfAtnbkf, rFib.m_lcbPlcfAtnbkf, 4) );
4547  m_pBook[1].reset( new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfAtnbkl, rFib.m_lcbPlcfAtnbkl, 0) );
4548 
4549  nIMax = m_pBook[0]->GetIMax();
4550  if (m_pBook[1]->GetIMax() < nIMax)
4551  nIMax = m_pBook[1]->GetIMax();
4552  }
4553 }
4554 
4556 {
4557 }
4558 
4559 sal_uInt32 WW8PLCFx_AtnBook::GetIdx() const
4560 {
4561  return nIMax ? m_pBook[0]->GetIdx() : 0;
4562 }
4563 
4564 void WW8PLCFx_AtnBook::SetIdx(sal_uInt32 nI)
4565 {
4566  if( nIMax )
4567  m_pBook[0]->SetIdx( nI );
4568 }
4569 
4570 sal_uInt32 WW8PLCFx_AtnBook::GetIdx2() const
4571 {
4572  if (nIMax)
4573  return m_pBook[1]->GetIdx() | ( m_bIsEnd ? 0x80000000 : 0 );
4574  else
4575  return 0;
4576 }
4577 
4578 void WW8PLCFx_AtnBook::SetIdx2(sal_uInt32 nI)
4579 {
4580  if( nIMax )
4581  {
4582  m_pBook[1]->SetIdx( nI & 0x7fffffff );
4583  m_bIsEnd = static_cast<bool>(( nI >> 31 ) & 1);
4584  }
4585 }
4586 
4588 {
4589  if (!m_pBook[0])
4590  return false;
4591 
4592  bool bOk = m_pBook[0]->SeekPosExact(nCpPos);
4593  bOk &= m_pBook[1]->SeekPosExact(nCpPos);
4594  m_bIsEnd = false;
4595 
4596  return bOk;
4597 }
4598 
4600 {
4601  return m_pBook[static_cast<int>(m_bIsEnd)]->Where();
4602 }
4603 
4604 tools::Long WW8PLCFx_AtnBook::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
4605 {
4606  void* pData;
4607  rEnd = WW8_CP_MAX;
4608  rLen = 0;
4609 
4610  if (!m_pBook[0] || !m_pBook[1] || !nIMax || (m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx()) >= nIMax)
4611  {
4612  rStart = rEnd = WW8_CP_MAX;
4613  return -1;
4614  }
4615 
4616  (void)m_pBook[static_cast<int>(m_bIsEnd)]->Get(rStart, pData);
4617  return m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx();
4618 }
4619 
4621 {
4622  if( !(m_pBook[0] && m_pBook[1] && nIMax) )
4623  return;
4624 
4625  (*m_pBook[static_cast<int>(m_bIsEnd)]).advance();
4626 
4627  sal_uLong l0 = m_pBook[0]->Where();
4628  sal_uLong l1 = m_pBook[1]->Where();
4629  if( l0 < l1 )
4630  m_bIsEnd = false;
4631  else if( l1 < l0 )
4632  m_bIsEnd = true;
4633  else
4634  {
4635  const void * p = m_pBook[0]->GetData(m_pBook[0]->GetIdx());
4636  tools::Long nPairFor = (p == nullptr) ? 0 : SVBT16ToUInt16(*static_cast<SVBT16 const *>(p));
4637  if (nPairFor == m_pBook[1]->GetIdx())
4638  m_bIsEnd = false;
4639  else
4640  m_bIsEnd = !m_bIsEnd;
4641  }
4642 }
4643 
4645 {
4646  if (!m_pBook[0] || !m_pBook[1])
4647  return LONG_MAX;
4648 
4649  if (m_bIsEnd)
4650  return m_pBook[1]->GetIdx();
4651  else
4652  {
4653  if (const void* p = m_pBook[0]->GetData(m_pBook[0]->GetIdx()))
4654  return SVBT16ToUInt16(*static_cast<const SVBT16*>(p));
4655  else
4656  return LONG_MAX;
4657  }
4658 }
4659 
4661 {
4662  return m_bIsEnd;
4663 }
4664 
4666  : WW8PLCFx(rFib, /*bSprm=*/false),
4667  m_bIsEnd(false)
4668 {
4670  {
4671  m_nIMax = 0;
4672  }
4673  else
4674  {
4675  m_pBook[0].reset(new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfBkfFactoid, rFib.m_lcbPlcfBkfFactoid, 6));
4676  m_pBook[1].reset(new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfBklFactoid, rFib.m_lcbPlcfBklFactoid, 4));
4677 
4678  m_nIMax = m_pBook[0]->GetIMax();
4679  if (m_pBook[1]->GetIMax() < m_nIMax)
4680  m_nIMax = m_pBook[1]->GetIMax();
4681  }
4682 }
4683 
4685 {
4686 }
4687 
4689 {
4690  return m_nIMax ? m_pBook[0]->GetIdx() : 0;
4691 }
4692 
4693 void WW8PLCFx_FactoidBook::SetIdx(sal_uInt32 nI)
4694 {
4695  if (m_nIMax)
4696  m_pBook[0]->SetIdx(nI);
4697 }
4698 
4700 {
4701  if (m_nIMax)
4702  return m_pBook[1]->GetIdx() | (m_bIsEnd ? 0x80000000 : 0);
4703  else
4704  return 0;
4705 }
4706 
4708 {
4709  if (m_nIMax)
4710  {
4711  m_pBook[1]->SetIdx(nI & 0x7fffffff);
4712  m_bIsEnd = static_cast<bool>((nI >> 31) & 1);
4713  }
4714 }
4715 
4717 {
4718  if (!m_pBook[0])
4719  return false;
4720 
4721  bool bOk = m_pBook[0]->SeekPosExact(nCpPos);
4722  bOk &= m_pBook[1]->SeekPosExact(nCpPos);
4723  m_bIsEnd = false;
4724 
4725  return bOk;
4726 }
4727 
4729 {
4730  return m_pBook[static_cast<int>(m_bIsEnd)]->Where();
4731 }
4732 
4734 {
4735  void* pData;
4736  rEnd = WW8_CP_MAX;
4737  rLen = 0;
4738 
4739  if (!m_pBook[0] || !m_pBook[1] || !m_nIMax || (m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx()) >= m_nIMax)
4740  {
4741  rStart = rEnd = WW8_CP_MAX;
4742  return -1;
4743  }
4744 
4745  (void)m_pBook[static_cast<int>(m_bIsEnd)]->Get(rStart, pData);
4746  return m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx();
4747 }
4748 
4750 {
4751  if (!(m_pBook[0] && m_pBook[1] && m_nIMax))
4752  return;
4753 
4754  (*m_pBook[static_cast<int>(m_bIsEnd)]).advance();
4755 
4756  sal_uLong l0 = m_pBook[0]->Where();
4757  sal_uLong l1 = m_pBook[1]->Where();
4758  if (l0 < l1)
4759  m_bIsEnd = false;
4760  else if (l1 < l0)
4761  m_bIsEnd = true;
4762  else
4763  {
4764  const void * p = m_pBook[0]->GetData(m_pBook[0]->GetIdx());
4765  tools::Long nPairFor = (p == nullptr) ? 0 : SVBT16ToUInt16(*static_cast<SVBT16 const *>(p));
4766  if (nPairFor == m_pBook[1]->GetIdx())
4767  m_bIsEnd = false;
4768  else
4769  m_bIsEnd = !m_bIsEnd;
4770  }
4771 }
4772 
4774 {
4775  if (!m_pBook[0] || !m_pBook[1])
4776  return LONG_MAX;
4777 
4778  if (m_bIsEnd)
4779  return m_pBook[1]->GetIdx();
4780  else
4781  {
4782  if (const void* p = m_pBook[0]->GetData(m_pBook[0]->GetIdx()))
4783  return SVBT16ToUInt16(*static_cast<const SVBT16*>(p));
4784  else
4785  return LONG_MAX;
4786  }
4787 }
4788 
4790 {
4791  return m_bIsEnd;
4792 }
4793 
4794 // In the end of a paragraph in WW6 the attribute extends after the <CR>.
4795 // This will be reset by one character to be used with SW,
4796 // if we don't expect trouble thereby.
4798 {
4799  // might be necessary to do this for pChp and/or pSep as well,
4800  // but its definitely the case for paragraphs that EndPos > StartPos
4801  // for a well formed paragraph as those always have a paragraph
4802  // <cr> in them
4803  if (&rDesc == m_pPap && rDesc.bRealLineEnd)
4804  {
4805  if (rDesc.nStartPos == rDesc.nEndPos && rDesc.nEndPos != WW8_CP_MAX)
4806  {
4807  SAL_WARN("sw.ww8", "WW8PLCFxDesc End same as Start, abandoning to avoid looping");
4808  rDesc.nEndPos = WW8_CP_MAX;
4809  }
4810  }
4811 
4812  //Store old end position for supercool new property finder that uses
4813  //cp instead of fc's as nature intended
4814  rDesc.nOrigEndPos = rDesc.nEndPos;
4815  rDesc.nOrigStartPos = rDesc.nStartPos;
4816 
4817  /*
4818  Normally given ^XXX{para end}^ we don't actually insert a para end
4819  character into the document, so we clip the para end property one to the
4820  left to make the para properties end when the paragraph text does. In a
4821  drawing textbox we actually do insert a para end character, so we don't
4822  clip it. Making the para end properties end after the para end char.
4823  */
4824  if (GetDoingDrawTextBox())
4825  return;
4826 
4827  if ( (&rDesc == m_pPap) && rDesc.bRealLineEnd )
4828  {
4829  if ( m_pPap->nEndPos != WW8_CP_MAX ) // Para adjust
4830  {
4831  m_nLineEnd = m_pPap->nEndPos;// nLineEnd points *after* the <CR>
4832  m_pPap->nEndPos--; // shorten paragraph end by one character
4833 
4834  // Is there already a sep end, which points to the current paragraph end?
4835  // Then we also must shorten by one character
4836  if( m_pSep->nEndPos == m_nLineEnd )
4837  m_pSep->nEndPos--;
4838  }
4839  }
4840  else if (&rDesc == m_pSep)
4841  {
4842  // Sep Adjust if end Char-Attr == paragraph end ...
4843  if( (rDesc.nEndPos == m_nLineEnd) && (rDesc.nEndPos > rDesc.nStartPos) )
4844  rDesc.nEndPos--; // ... then shorten by one character
4845  }
4846 }
4847 
4849 {
4850  SAL_WARN_IF(WW8_CP_MAX != nStartPos && nStartPos > nEndPos, "sw.ww8",
4851  "End " << nEndPos << " before Start " << nStartPos);
4852 
4853  if( nStartPos != WW8_CP_MAX )
4854  {
4855  /*
4856  ##516##,##517##
4857  Force the property change to happen at the beginning of this
4858  subdocument, same as in GetNewNoSprms, except that the target type is
4859  attributes attached to a piece that might span subdocument boundaries
4860  */
4861  if (nCpOfs > nStartPos)
4862  nStartPos = 0;
4863  else
4864  nStartPos -= nCpOfs;
4865  }
4866  if (nEndPos != WW8_CP_MAX)
4867  {
4868  if (nCpOfs > nEndPos)
4869  {
4870  SAL_WARN("sw.ww8", "broken subdocument piece entry");
4871  nEndPos = WW8_CP_MAX;
4872  }
4873  else
4874  nEndPos -= nCpOfs;
4875  }
4876 }
4877 
4879 {
4880  rDesc.pPLCFx->GetSprms(&rDesc);
4881  rDesc.ReduceByOffset();
4882 
4883  rDesc.bFirstSprm = true;
4884  AdjustEnds( rDesc );
4885  rDesc.nOrigSprmsLen = rDesc.nSprmsLen;
4886 }
4887 
4889 {
4890  rDesc.nCp2OrIdx = rDesc.pPLCFx->GetNoSprms(rDesc.nStartPos, rDesc.nEndPos,
4891  rDesc.nSprmsLen);
4892 
4893  SAL_WARN_IF(WW8_CP_MAX != rDesc.nStartPos && rDesc.nStartPos > rDesc.nEndPos, "sw.ww8",
4894  "End " << rDesc.nEndPos << " before Start " << rDesc.nStartPos);
4895 
4896  rDesc.ReduceByOffset();
4897 
4898  rDesc.bFirstSprm = true;
4899  rDesc.nOrigSprmsLen = rDesc.nSprmsLen;
4900 }
4901 
4902 sal_uInt16 WW8PLCFMan::GetId(const WW8PLCFxDesc* p) const
4903 {
4904  sal_uInt16 nId = 0; // Id = 0 for empty attributes
4905 
4906  if (p == m_pField)
4907  nId = eFLD;
4908  else if (p == m_pFootnote)
4909  nId = eFTN;
4910  else if (p == m_pEdn)
4911  nId = eEDN;
4912  else if (p == m_pAnd)
4913  nId = eAND;
4914  else if (p->nSprmsLen >= maSprmParser.MinSprmLen())
4915  nId = maSprmParser.GetSprmId(p->pMemPos);
4916 
4917  return nId;
4918 }
4919 
4921  bool bDoingDrawTextBox)
4922  : maSprmParser(*pBase->m_pWw8Fib),
4923  m_nLineEnd(WW8_CP_MAX),
4924  mbDoingDrawTextBox(bDoingDrawTextBox)
4925 {
4926  m_pWwFib = pBase->m_pWw8Fib;
4927 
4928  m_nManType = nType;
4929 
4930  if( MAN_MAINTEXT == nType )
4931  {
4932  // search order of the attributes
4934  m_pField = &m_aD[0];
4935  m_pBkm = &m_aD[1];
4936  m_pEdn = &m_aD[2];
4937  m_pFootnote = &m_aD[3];
4938  m_pAnd = &m_aD[4];
4939 
4940  m_pPcd = pBase->m_pPLCFx_PCD ? &m_aD[5] : nullptr;
4941  //pPcdA index == pPcd index + 1
4942  m_pPcdA = pBase->m_pPLCFx_PCDAttrs ? &m_aD[6] : nullptr;
4943 
4944  m_pChp = &m_aD[7];
4945  m_pPap = &m_aD[8];
4946  m_pSep = &m_aD[9];
4947  m_pAtnBkm = &m_aD[10];
4948  m_pFactoidBkm = &m_aD[11];
4949 
4950  m_pSep->pPLCFx = pBase->m_pSepPLCF.get();
4951  m_pFootnote->pPLCFx = pBase->m_pFootnotePLCF.get();
4952  m_pEdn->pPLCFx = pBase->m_pEdnPLCF.get();
4953  m_pBkm->pPLCFx = pBase->m_pBook.get();
4954  m_pAnd->pPLCFx = pBase->m_pAndPLCF.get();
4955  m_pAtnBkm->pPLCFx = pBase->m_pAtnBook.get();
4956  m_pFactoidBkm->pPLCFx = pBase->m_pFactoidBook.get();
4957 
4958  }
4959  else
4960  {
4961  // search order of the attributes
4962  m_nPLCF = 7;
4963  m_pField = &m_aD[0];
4964  m_pBkm = pBase->m_pBook ? &m_aD[1] : nullptr;
4965 
4966  m_pPcd = pBase->m_pPLCFx_PCD ? &m_aD[2] : nullptr;
4967  //pPcdA index == pPcd index + 1
4968  m_pPcdA= pBase->m_pPLCFx_PCDAttrs ? &m_aD[3] : nullptr;
4969 
4970  m_pChp = &m_aD[4];
4971  m_pPap = &m_aD[5];
4972  m_pSep = &m_aD[6]; // Dummy
4973 
4974  m_pAnd = m_pAtnBkm = m_pFactoidBkm = m_pFootnote = m_pEdn = nullptr; // not used at SpezText
4975  }
4976 
4977  m_pChp->pPLCFx = pBase->m_pChpPLCF.get();
4978  m_pPap->pPLCFx = pBase->m_pPapPLCF.get();
4979  if( m_pPcd )
4980  m_pPcd->pPLCFx = pBase->m_pPLCFx_PCD.get();
4981  if( m_pPcdA )
4982  m_pPcdA->pPLCFx= pBase->m_pPLCFx_PCDAttrs.get();
4983  if( m_pBkm )
4984  m_pBkm->pPLCFx = pBase->m_pBook.get();
4985 
4986  m_pMagicTables = pBase->m_pMagicTables.get();
4987  m_pSubdocs = pBase->m_pSubdocs.get();
4988  m_pExtendedAtrds = pBase->m_pExtendedAtrds.get();
4989 
4990  switch( nType ) // field initialization
4991  {
4992  case MAN_HDFT:
4993  m_pField->pPLCFx = pBase->m_pFieldHdFtPLCF.get();
4994  m_pFdoa = pBase->m_pHdFtFdoa.get();
4995  m_pTxbx = pBase->m_pHdFtTxbx.get();
4996  m_pTxbxBkd = pBase->m_pHdFtTxbxBkd.get();
4997  break;
4998  case MAN_FTN:
4999  m_pField->pPLCFx = pBase->m_pFieldFootnotePLCF.get();
5000  m_pFdoa = m_pTxbx = m_pTxbxBkd = nullptr;
5001  break;
5002  case MAN_EDN:
5003  m_pField->pPLCFx = pBase->m_pFieldEdnPLCF.get();
5004  m_pFdoa = m_pTxbx = m_pTxbxBkd = nullptr;
5005  break;
5006  case MAN_AND:
5007  m_pField->pPLCFx = pBase->