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