xref: /core/sw/source/filter/ww8/ww8scan.cxx (revision 71ce1181)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <memory>
21 #include "ww8scan.hxx"
22 #include "ww8par.hxx"
23 
24 #include <cassert>
25 #include <cstddef>
26 #include <cstring>
27 #include <algorithm>
28 
29 #include <i18nlangtag/mslangid.hxx>
30 #include "sprmids.hxx"
31 #include <rtl/tencinfo.h>
32 #include <sal/macros.h>
33 #include <sal/log.hxx>
34 #include <osl/diagnose.h>
35 
36 #include <swerror.h>
37 
38 #include <comphelper/string.hxx>
39 #include <unotools/localedatawrapper.hxx>
40 #include <i18nlangtag/lang.h>
41 #include <o3tl/safeint.hxx>
42 #include <tools/stream.hxx>
43 
44 #include <vcl/settings.hxx>
45 #include <vcl/svapp.hxx>
46 
47 using namespace ::com::sun::star::lang;
48 
49 namespace
50 {
51     /**
52         winword strings are typically Belt and Braces strings preceded with a
53         pascal style count, and ending with a c style 0 terminator. 16bit chars
54         and count for ww8+ and 8bit chars and count for ww7-. The count and 0
55         can be checked for integrity to catch errors (e.g. lotus created
56         documents) where in error 8bit strings are used instead of 16bits
57         strings for style names.
58     */
TestBeltAndBraces(SvStream & rStrm)59     bool TestBeltAndBraces(SvStream& rStrm)
60     {
61         bool bRet = false;
62         sal_uInt64 nOldPos = rStrm.Tell();
63         sal_uInt16 nBelt(0);
64         rStrm.ReadUInt16( nBelt );
65         nBelt *= sizeof(sal_Unicode);
66         if (rStrm.good() && (rStrm.remainingSize() >= (nBelt + sizeof(sal_Unicode))))
67         {
68             rStrm.SeekRel(nBelt);
69             if (rStrm.good())
70             {
71                 sal_Unicode cBraces(0);
72                 rStrm.ReadUtf16( cBraces );
73                 if (rStrm.good() && cBraces == 0)
74                     bRet = true;
75             }
76         }
77         rStrm.Seek(nOldPos);
78         return bRet;
79     }
80 }
81 
GetWW2SprmSearcher()82 const wwSprmSearcher *wwSprmParser::GetWW2SprmSearcher()
83 {
84     //double lock me
85     // WW2 Sprms
86     static const SprmInfoRow aSprms[] =
87     {
88         {  0, { 0, L_FIX} }, // "Default-sprm", will be skipped
89         {  2, { 1, L_FIX} }, // "sprmPIstd",  pap.istd (style code)
90         {  3, { 0, L_VAR} }, // "sprmPIstdPermute pap.istd permutation
91         {  4, { 1, L_FIX} }, // "sprmPIncLv1" pap.istddifference
92         {  5, { 1, L_FIX} }, // "sprmPJc" pap.jc (justification)
93         {  6, { 1, L_FIX} }, // "sprmPFSideBySide" pap.fSideBySide
94         {  7, { 1, L_FIX} }, // "sprmPFKeep" pap.fKeep
95         {  8, { 1, L_FIX} }, // "sprmPFKeepFollow " pap.fKeepFollow
96         {  9, { 1, L_FIX} }, // "sprmPPageBreakBefore" pap.fPageBreakBefore
97         { 10, { 1, L_FIX} }, // "sprmPBrcl" pap.brcl
98         { 11, { 1, L_FIX} }, // "sprmPBrcp" pap.brcp
99         { 12, { 1, L_FIX} }, // "sprmPNfcSeqNumb" pap.nfcSeqNumb
100         { 13, { 1, L_FIX} }, // "sprmPNoSeqNumb" pap.nnSeqNumb
101         { 14, { 1, L_FIX} }, // "sprmPFNoLineNumb" pap.fNoLnn
102         { 15, { 0, L_VAR} }, // "?sprmPChgTabsPapx" pap.itbdMac, ...
103         { 16, { 2, L_FIX} }, // "sprmPDxaRight" pap.dxaRight
104         { 17, { 2, L_FIX} }, // "sprmPDxaLeft" pap.dxaLeft
105         { 18, { 2, L_FIX} }, // "sprmPNest" pap.dxaLeft
106         { 19, { 2, L_FIX} }, // "sprmPDxaLeft1" pap.dxaLeft1
107         { 20, { 2, L_FIX} }, // "sprmPDyaLine" pap.lspd an LSPD
108         { 21, { 2, L_FIX} }, // "sprmPDyaBefore" pap.dyaBefore
109         { 22, { 2, L_FIX} }, // "sprmPDyaAfter" pap.dyaAfter
110         { 23, { 0, L_VAR} }, // "?sprmPChgTabs" pap.itbdMac, pap.rgdxaTab, ...
111         { 24, { 1, L_FIX} }, // "sprmPFInTable" pap.fInTable
112         { 25, { 1, L_FIX} }, // "sprmPTtp" pap.fTtp
113         { 26, { 2, L_FIX} }, // "sprmPDxaAbs" pap.dxaAbs
114         { 27, { 2, L_FIX} }, // "sprmPDyaAbs" pap.dyaAbs
115         { 28, { 2, L_FIX} }, // "sprmPDxaWidth" pap.dxaWidth
116         { 29, { 1, L_FIX} }, // "sprmPPc" pap.pcHorz, pap.pcVert
117         { 30, { 2, L_FIX} }, // "sprmPBrcTop10" pap.brcTop BRC10
118         { 31, { 2, L_FIX} }, // "sprmPBrcLeft10" pap.brcLeft BRC10
119         { 32, { 2, L_FIX} }, // "sprmPBrcBottom10" pap.brcBottom BRC10
120         { 33, { 2, L_FIX} }, // "sprmPBrcRight10" pap.brcRight BRC10
121         { 34, { 2, L_FIX} }, // "sprmPBrcBetween10" pap.brcBetween BRC10
122         { 35, { 2, L_FIX} }, // "sprmPBrcBar10" pap.brcBar BRC10
123         { 36, { 2, L_FIX} }, // "sprmPFromText10" pap.dxaFromText dxa
124         { 37, { 1, L_FIX} }, // "sprmPWr" pap.wr wr
125         { 38, { 2, L_FIX} }, // "sprmPBrcTop" pap.brcTop BRC
126         { 39, { 2, L_FIX} }, // "sprmPBrcLeft" pap.brcLeft BRC
127         { 40, { 2, L_FIX} }, // "sprmPBrcBottom" pap.brcBottom BRC
128         { 41, { 2, L_FIX} }, // "sprmPBrcRight" pap.brcRight BRC
129         { 42, { 2, L_FIX} }, // "sprmPBrcBetween" pap.brcBetween BRC
130         { 43, { 2, L_FIX} }, // "sprmPBrcBar" pap.brcBar BRC word
131         { 44, { 1, L_FIX} }, // "sprmPFNoAutoHyph" pap.fNoAutoHyph
132         { 45, { 2, L_FIX} }, // "sprmPWHeightAbs" pap.wHeightAbs w
133         { 46, { 2, L_FIX} }, // "sprmPDcs" pap.dcs DCS
134         { 47, { 2, L_FIX} }, // "sprmPShd" pap.shd SHD
135         { 48, { 2, L_FIX} }, // "sprmPDyaFromText" pap.dyaFromText dya
136         { 49, { 2, L_FIX} }, // "sprmPDxaFromText" pap.dxaFromText dxa
137         { 50, { 1, L_FIX} }, // "sprmPFBiDi" pap.fBiDi 0 or 1 byte
138         { 51, { 1, L_FIX} }, // "sprmPFWidowControl" pap.fWidowControl 0 or 1 byte
139         { 52, { 0, L_FIX} }, // "?sprmPRuler 52"
140         { 53, { 1, L_FIX} }, // "sprmCFStrikeRM" chp.fRMarkDel 1 or 0 bit
141         { 54, { 1, L_FIX} }, // "sprmCFRMark" chp.fRMark 1 or 0 bit
142         { 55, { 1, L_FIX} }, // "sprmCFFieldVanish" chp.fFieldVanish 1 or 0 bit
143         { 57, { 0, L_VAR} }, // "sprmCDefault" whole CHP
144         { 58, { 0, L_FIX} }, // "sprmCPlain" whole CHP
145         { 60, { 1, L_FIX} }, // "sprmCFBold" chp.fBold 0,1, 128, or 129
146         { 61, { 1, L_FIX} }, // "sprmCFItalic" chp.fItalic 0,1, 128, or 129
147         { 62, { 1, L_FIX} }, // "sprmCFStrike" chp.fStrike 0,1, 128, or 129
148         { 63, { 1, L_FIX} }, // "sprmCFOutline" chp.fOutline 0,1, 128, or 129
149         { 64, { 1, L_FIX} }, // "sprmCFShadow" chp.fShadow 0,1, 128, or 129
150         { 65, { 1, L_FIX} }, // "sprmCFSmallCaps" chp.fSmallCaps 0,1, 128, or 129
151         { 66, { 1, L_FIX} }, // "sprmCFCaps" chp.fCaps 0,1, 128, or 129
152         { 67, { 1, L_FIX} }, // "sprmCFVanish" chp.fVanish 0,1, 128, or 129
153         { 68, { 2, L_FIX} }, // "sprmCFtc" chp.ftc ftc word
154         { 69, { 1, L_FIX} }, // "sprmCKul" chp.kul kul byte
155         { 70, { 3, L_FIX} }, // "sprmCSizePos" chp.hps, chp.hpsPos
156         { 71, { 2, L_FIX} }, // "sprmCDxaSpace" chp.dxaSpace dxa
157         { 72, { 2, L_FIX} }, // "sprmCLid" chp.lid LID
158         { 73, { 1, L_FIX} }, // "sprmCIco" chp.ico ico byte
159         { 74, { 1, L_FIX} }, // "sprmCHps" chp.hps hps !word!
160         { 75, { 1, L_FIX} }, // "sprmCHpsInc" chp.hps
161         { 76, { 1, L_FIX} }, // "sprmCHpsPos" chp.hpsPos hps !word!
162         { 77, { 1, L_FIX} }, // "sprmCHpsPosAdj" chp.hpsPos hps
163         { 78, { 0, L_VAR} }, // "?sprmCMajority" chp.fBold, chp.fItalic, ...
164         { 80, { 1, L_FIX} }, // "sprmCFBoldBi" chp.fBoldBi
165         { 81, { 1, L_FIX} }, // "sprmCFItalicBi" chp.fItalicBi
166         { 82, { 2, L_FIX} }, // "sprmCFtcBi" chp.ftcBi
167         { 83, { 2, L_FIX} }, // "sprmClidBi" chp.lidBi
168         { 84, { 1, L_FIX} }, // "sprmCIcoBi" chp.icoBi
169         { 85, { 1, L_FIX} }, // "sprmCHpsBi" chp.hpsBi
170         { 86, { 1, L_FIX} }, // "sprmCFBiDi" chp.fBiDi
171         { 87, { 1, L_FIX} }, // "sprmCFDiacColor" chp.fDiacUSico
172         { 94, { 1, L_FIX} }, // "sprmPicBrcl" pic.brcl brcl (see PIC definition)
173         { 95, {12, L_VAR} }, // "sprmPicScale" pic.mx, pic.my, pic.dxaCropleft,
174         { 96, { 2, L_FIX} }, // "sprmPicBrcTop" pic.brcTop BRC word
175         { 97, { 2, L_FIX} }, // "sprmPicBrcLeft" pic.brcLeft BRC word
176         { 98, { 2, L_FIX} }, // "sprmPicBrcBottom" pic.brcBottom BRC word
177         { 99, { 2, L_FIX} }, // "sprmPicBrcRight" pic.brcRight BRC word
178         {112, { 1, L_FIX} }, // "sprmSFRTLGutter", set to one if gutter is on
179         {114, { 1, L_FIX} }, // "sprmSFBiDi" ;;;
180         {115, { 2, L_FIX} }, // "sprmSDmBinFirst" sep.dmBinFirst  word
181         {116, { 2, L_FIX} }, // "sprmSDmBinOther" sep.dmBinOther  word
182         {117, { 1, L_FIX} }, // "sprmSBkc" sep.bkc bkc byte
183         {118, { 1, L_FIX} }, // "sprmSFTitlePage" sep.fTitlePage 0 or 1 byte
184         {119, { 2, L_FIX} }, // "sprmSCcolumns" sep.ccolM1 # of cols - 1 word
185         {120, { 2, L_FIX} }, // "sprmSDxaColumns" sep.dxaColumns dxa word
186         {121, { 1, L_FIX} }, // "sprmSFAutoPgn" sep.fAutoPgn obsolete byte
187         {122, { 1, L_FIX} }, // "sprmSNfcPgn" sep.nfcPgn nfc byte
188         {123, { 2, L_FIX} }, // "sprmSDyaPgn" sep.dyaPgn dya short
189         {124, { 2, L_FIX} }, // "sprmSDxaPgn" sep.dxaPgn dya short
190         {125, { 1, L_FIX} }, // "sprmSFPgnRestart" sep.fPgnRestart 0 or 1 byte
191         {126, { 1, L_FIX} }, // "sprmSFEndnote" sep.fEndnote 0 or 1 byte
192         {127, { 1, L_FIX} }, // "sprmSLnc" sep.lnc lnc byte
193         {128, { 1, L_FIX} }, // "sprmSGprfIhdt" sep.grpfIhdt grpfihdt
194         {129, { 2, L_FIX} }, // "sprmSNLnnMod" sep.nLnnMod non-neg int. word
195         {130, { 2, L_FIX} }, // "sprmSDxaLnn" sep.dxaLnn dxa word
196         {131, { 2, L_FIX} }, // "sprmSDyaHdrTop" sep.dyaHdrTop dya word
197         {132, { 2, L_FIX} }, // "sprmSDyaHdrBottom" sep.dyaHdrBottom dya word
198         {133, { 1, L_FIX} }, // "sprmSLBetween" sep.fLBetween 0 or 1 byte
199         {134, { 1, L_FIX} }, // "sprmSVjc" sep.vjc vjc byte
200         {135, { 2, L_FIX} }, // "sprmSLnnMin" sep.lnnMin lnn word
201         {136, { 2, L_FIX} }, // "sprmSPgnStart" sep.pgnStart pgn word
202         {137, { 1, L_FIX} }, // "sprmSBOrientation" sep.dmOrientPage dm byte
203         {138, { 1, L_FIX} }, // "sprmSFFacingCol" ;;;
204         {139, { 2, L_FIX} }, // "sprmSXaPage" sep.xaPage xa word
205         {140, { 2, L_FIX} }, // "sprmSYaPage" sep.yaPage ya word
206         {141, { 2, L_FIX} }, // "sprmSDxaLeft" sep.dxaLeft dxa word
207         {142, { 2, L_FIX} }, // "sprmSDxaRight" sep.dxaRight dxa word
208         {143, { 2, L_FIX} }, // "sprmSDyaTop" sep.dyaTop dya word
209         {144, { 2, L_FIX} }, // "sprmSDyaBottom" sep.dyaBottom dya word
210         {145, { 2, L_FIX} }, // "sprmSDzaGutter" sep.dzaGutter dza word
211         {146, { 2, L_FIX} }, // "sprmTJc" tap.jc jc (low order byte is significant)
212         {147, { 2, L_FIX} }, // "sprmTDxaLeft" tap.rgdxaCenter dxa word
213         {148, { 2, L_FIX} }, // "sprmTDxaGapHalf" tap.dxaGapHalf, tap.rgdxaCenter
214         {149, { 1, L_FIX} }, // "sprmTFBiDi" ;;;
215         {152, { 0, L_VAR2} },// "sprmTDefTable10" tap.rgdxaCenter, tap.rgtc complex
216         {153, { 2, L_FIX} }, // "sprmTDyaRowHeight" tap.dyaRowHeight dya word
217         {154, { 0, L_VAR2} },// "sprmTDefTable" tap.rgtc complex
218         {155, { 1, L_VAR} }, // "sprmTDefTableShd" tap.rgshd complex
219         {157, { 5, L_FIX} }, // "sprmTSetBrc" tap.rgtc[].rgbrc complex 5 bytes
220         {158, { 4, L_FIX} }, // "sprmTInsert" tap.rgdxaCenter,tap.rgtc complex
221         {159, { 2, L_FIX} }, // "sprmTDelete" tap.rgdxaCenter, tap.rgtc complex
222         {160, { 4, L_FIX} }, // "sprmTDxaCol" tap.rgdxaCenter complex
223         {161, { 2, L_FIX} }, // "sprmTMerge" tap.fFirstMerged, tap.fMerged complex
224         {162, { 2, L_FIX} }, // "sprmTSplit" tap.fFirstMerged, tap.fMerged complex
225         {163, { 5, L_FIX} }, // "sprmTSetBrc10" tap.rgtc[].rgbrc complex 5 bytes
226         {164, { 4, L_FIX} }, // "sprmTSetShd", tap.rgshd complex 4 bytes
227     };
228 
229     static wwSprmSearcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
230     return &aSprmSrch;
231 };
232 
GetWW6SprmSearcher(const WW8Fib & rFib)233 const wwSprmSearcher *wwSprmParser::GetWW6SprmSearcher(const WW8Fib& rFib)
234 {
235     //double lock me
236     // WW7- Sprms
237     static const SprmInfoRow aSprms[] =
238     {
239         {  0, { 0, L_FIX} }, // "Default-sprm", is skipped
240         {NS_sprm::v6::sprmPIstd, { 2, L_FIX} }, // pap.istd (style code)
241         {NS_sprm::v6::sprmPIstdPermute, { 3, L_VAR} }, // pap.istd permutation
242         {NS_sprm::v6::sprmPIncLv1, { 1, L_FIX} }, // pap.istddifference
243         {NS_sprm::v6::sprmPJc, { 1, L_FIX} }, // pap.jc (justification)
244         {NS_sprm::v6::sprmPFSideBySide, { 1, L_FIX} }, // pap.fSideBySide
245         {NS_sprm::v6::sprmPFKeep, { 1, L_FIX} }, // pap.fKeep
246         {NS_sprm::v6::sprmPFKeepFollow, { 1, L_FIX} }, // pap.fKeepFollow
247         {NS_sprm::v6::sprmPPageBreakBefore, { 1, L_FIX} }, // pap.fPageBreakBefore
248         {NS_sprm::v6::sprmPBrcl, { 1, L_FIX} }, // pap.brcl
249         {NS_sprm::v6::sprmPBrcp, { 1, L_FIX} }, // pap.brcp
250         {NS_sprm::v6::sprmPAnld, { 0, L_VAR} }, // pap.anld (ANLD structure)
251         {NS_sprm::v6::sprmPNLvlAnm, { 1, L_FIX} }, // pap.nLvlAnm nn
252         {NS_sprm::v6::sprmPFNoLineNumb, { 1, L_FIX} }, // pap.fNoLnn
253         {NS_sprm::v6::sprmPChgTabsPapx, { 0, L_VAR} }, // pap.itbdMac, ...
254         {NS_sprm::v6::sprmPDxaRight, { 2, L_FIX} }, // pap.dxaRight
255         {NS_sprm::v6::sprmPDxaLeft, { 2, L_FIX} }, // pap.dxaLeft
256         {NS_sprm::v6::sprmPNest, { 2, L_FIX} }, // pap.dxaLeft
257         {NS_sprm::v6::sprmPDxaLeft1, { 2, L_FIX} }, // pap.dxaLeft1
258         {NS_sprm::v6::sprmPDyaLine, { 4, L_FIX} }, // pap.lspd an LSPD
259         {NS_sprm::v6::sprmPDyaBefore, { 2, L_FIX} }, // pap.dyaBefore
260         {NS_sprm::v6::sprmPDyaAfter, { 2, L_FIX} }, // pap.dyaAfter
261         {NS_sprm::v6::sprmPChgTabs, { 0, L_VAR} }, // pap.itbdMac, pap.rgdxaTab, ...
262         {NS_sprm::v6::sprmPFInTable, { 1, L_FIX} }, // pap.fInTable
263         {NS_sprm::v6::sprmPTtp, { 1, L_FIX} }, // pap.fTtp
264         {NS_sprm::v6::sprmPDxaAbs, { 2, L_FIX} }, // pap.dxaAbs
265         {NS_sprm::v6::sprmPDyaAbs, { 2, L_FIX} }, // pap.dyaAbs
266         {NS_sprm::v6::sprmPDxaWidth, { 2, L_FIX} }, // pap.dxaWidth
267         {NS_sprm::v6::sprmPPc, { 1, L_FIX} }, // pap.pcHorz, pap.pcVert
268         {NS_sprm::v6::sprmPBrcTop10, { 2, L_FIX} }, // pap.brcTop BRC10
269         {NS_sprm::v6::sprmPBrcLeft10, { 2, L_FIX} }, // pap.brcLeft BRC10
270         {NS_sprm::v6::sprmPBrcBottom10, { 2, L_FIX} }, // pap.brcBottom BRC10
271         {NS_sprm::v6::sprmPBrcRight10, { 2, L_FIX} }, // pap.brcRight BRC10
272         {NS_sprm::v6::sprmPBrcBetween10, { 2, L_FIX} }, // pap.brcBetween BRC10
273         {NS_sprm::v6::sprmPBrcBar10, { 2, L_FIX} }, // pap.brcBar BRC10
274         {NS_sprm::v6::sprmPFromText10, { 2, L_FIX} }, // pap.dxaFromText dxa
275         {NS_sprm::v6::sprmPWr, { 1, L_FIX} }, // pap.wr wr
276         {NS_sprm::v6::sprmPBrcTop, { 2, L_FIX} }, // pap.brcTop BRC
277         {NS_sprm::v6::sprmPBrcLeft, { 2, L_FIX} }, // pap.brcLeft BRC
278         {NS_sprm::v6::sprmPBrcBottom, { 2, L_FIX} }, // pap.brcBottom BRC
279         {NS_sprm::v6::sprmPBrcRight, { 2, L_FIX} }, // pap.brcRight BRC
280         {NS_sprm::v6::sprmPBrcBetween, { 2, L_FIX} }, // pap.brcBetween BRC
281         {NS_sprm::v6::sprmPBrcBar, { 2, L_FIX} }, // pap.brcBar BRC word
282         {NS_sprm::v6::sprmPFNoAutoHyph, { 1, L_FIX} }, // pap.fNoAutoHyph
283         {NS_sprm::v6::sprmPWHeightAbs, { 2, L_FIX} }, // pap.wHeightAbs w
284         {NS_sprm::v6::sprmPDcs, { 2, L_FIX} }, // pap.dcs DCS
285         {NS_sprm::v6::sprmPShd, { 2, L_FIX} }, // pap.shd SHD
286         {NS_sprm::v6::sprmPDyaFromText, { 2, L_FIX} }, // pap.dyaFromText dya
287         {NS_sprm::v6::sprmPDxaFromText, { 2, L_FIX} }, // pap.dxaFromText dxa
288         {NS_sprm::v6::sprmPFLocked, { 1, L_FIX} }, // pap.fLocked 0 or 1 byte
289         {NS_sprm::v6::sprmPFWidowControl, { 1, L_FIX} }, // pap.fWidowControl 0 or 1 byte
290         {NS_sprm::v6::sprmPRuler, { 0, L_FIX} },
291         { 64, { 0, L_VAR} }, // rtl property ?
292         {NS_sprm::v6::sprmCFStrikeRM, { 1, L_FIX} }, // chp.fRMarkDel 1 or 0 bit
293         {NS_sprm::v6::sprmCFRMark, { 1, L_FIX} }, // chp.fRMark 1 or 0 bit
294         {NS_sprm::v6::sprmCFFldVanish, { 1, L_FIX} }, // chp.fFieldVanish 1 or 0 bit
295         {NS_sprm::v6::sprmCPicLocation, { 0, L_VAR} }, // chp.fcPic and chp.fSpec
296         {NS_sprm::v6::sprmCIbstRMark, { 2, L_FIX} }, // chp.ibstRMark index into sttbRMark
297         {NS_sprm::v6::sprmCDttmRMark, { 4, L_FIX} }, // chp.dttm DTTM long
298         {NS_sprm::v6::sprmCFData, { 1, L_FIX} }, // chp.fData 1 or 0 bit
299         {NS_sprm::v6::sprmCRMReason, { 2, L_FIX} }, // chp.idslRMReason an index to a table
300         {NS_sprm::v6::sprmCChse, { 3, L_FIX} }, // chp.fChsDiff and chp.chse
301         {NS_sprm::v6::sprmCSymbol, { 0, L_VAR} }, // chp.fSpec, chp.chSym and chp.ftcSym
302         {NS_sprm::v6::sprmCFOle2, { 1, L_FIX} }, // chp.fOle2 1 or 0   bit
303         { 77, { 0, L_VAR} }, // unknown
304         { 79, { 0, L_VAR} }, // unknown
305         {NS_sprm::v6::sprmCIstd, { 2, L_FIX} }, // chp.istd istd, see stylesheet definition
306         {NS_sprm::v6::sprmCIstdPermute, { 0, L_VAR} }, // chp.istd permutation vector
307         {NS_sprm::v6::sprmCDefault, { 0, L_VAR} }, // whole CHP
308         {NS_sprm::v6::sprmCPlain, { 0, L_FIX} }, // whole CHP
309         {NS_sprm::v6::sprmCFBold, { 1, L_FIX} }, // chp.fBold 0,1, 128, or 129
310         {NS_sprm::v6::sprmCFItalic, { 1, L_FIX} }, // chp.fItalic 0,1, 128, or 129
311         {NS_sprm::v6::sprmCFStrike, { 1, L_FIX} }, // chp.fStrike 0,1, 128, or 129
312         {NS_sprm::v6::sprmCFOutline, { 1, L_FIX} }, // chp.fOutline 0,1, 128, or 129
313         {NS_sprm::v6::sprmCFShadow, { 1, L_FIX} }, // chp.fShadow 0,1, 128, or 129
314         {NS_sprm::v6::sprmCFSmallCaps, { 1, L_FIX} }, // chp.fSmallCaps 0,1, 128, or 129
315         {NS_sprm::v6::sprmCFCaps, { 1, L_FIX} }, // chp.fCaps 0,1, 128, or 129
316         {NS_sprm::v6::sprmCFVanish, { 1, L_FIX} }, // chp.fVanish 0,1, 128, or 129
317         {NS_sprm::v6::sprmCFtc, { 2, L_FIX} }, // chp.ftc ftc word
318         {NS_sprm::v6::sprmCKul, { 1, L_FIX} }, // chp.kul kul byte
319         {NS_sprm::v6::sprmCSizePos, { 3, L_FIX} }, // chp.hps, chp.hpsPos
320         {NS_sprm::v6::sprmCDxaSpace, { 2, L_FIX} }, // chp.dxaSpace dxa
321         {NS_sprm::v6::sprmCLid, { 2, L_FIX} }, // chp.lid LID
322         {NS_sprm::v6::sprmCIco, { 1, L_FIX} }, // chp.ico ico byte
323         {NS_sprm::v6::sprmCHps, { 2, L_FIX} }, // chp.hps hps !word!
324         {NS_sprm::v6::sprmCHpsInc, { 1, L_FIX} }, // chp.hps
325         {NS_sprm::v6::sprmCHpsPos, { 2, L_FIX} }, // chp.hpsPos hps !word!
326         {NS_sprm::v6::sprmCHpsPosAdj, { 1, L_FIX} }, // chp.hpsPos hps
327         {NS_sprm::v6::sprmCMajority, { 0, L_VAR} }, // chp.fBold, chp.fItalic, ...
328         {NS_sprm::v6::sprmCIss, { 1, L_FIX} }, // chp.iss iss
329         {NS_sprm::v6::sprmCHpsNew50, { 0, L_VAR} }, // chp.hps hps variable width
330         {NS_sprm::v6::sprmCHpsInc1, { 0, L_VAR} }, // chp.hps complex
331         {NS_sprm::v6::sprmCHpsKern, { 2, L_FIX} }, // chp.hpsKern hps
332         {NS_sprm::v6::sprmCMajority50, { 0, L_VAR} }, // chp.fBold, chp.fItalic, ...
333         {NS_sprm::v6::sprmCHpsMul, { 2, L_FIX} }, // chp.hps percentage to grow hps
334         {NS_sprm::v6::sprmCCondHyhen, { 2, L_FIX} }, // chp.ysri ysri
335         {111, { 0, L_VAR} }, // sprmCFBoldBi or font code
336         {112, { 0, L_VAR} }, // sprmCFItalicBi or font code
337         {113, { 0, L_VAR} }, // ww7 rtl font
338         {114, { 0, L_VAR} }, // ww7 lid
339         {115, { 0, L_VAR} }, // ww7 CJK font
340         {116, { 0, L_VAR} }, // ww7 fontsize
341         {NS_sprm::v6::sprmCFSpec, { 1, L_FIX} }, // chp.fSpec  1 or 0 bit
342         {NS_sprm::v6::sprmCFObj, { 1, L_FIX} }, // chp.fObj 1 or 0 bit
343         {NS_sprm::v6::sprmPicBrcl, { 1, L_FIX} }, // pic.brcl brcl (see PIC definition)
344         {NS_sprm::v6::sprmPicScale, {12, L_VAR} }, // pic.mx, pic.my, pic.dxaCropleft,
345         {NS_sprm::v6::sprmPicBrcTop, { 2, L_FIX} }, // pic.brcTop BRC word
346         {NS_sprm::v6::sprmPicBrcLeft, { 2, L_FIX} }, // pic.brcLeft BRC word
347         {NS_sprm::v6::sprmPicBrcBottom, { 2, L_FIX} }, // pic.brcBottom BRC word
348         {NS_sprm::v6::sprmPicBrcRight, { 2, L_FIX} }, // pic.brcRight BRC word
349         {NS_sprm::v6::sprmSScnsPgn, { 1, L_FIX} }, // sep.cnsPgn cns byte
350         {NS_sprm::v6::sprmSiHeadingPgn, { 1, L_FIX} }, // sep.iHeadingPgn
351         {NS_sprm::v6::sprmSOlstAnm, { 0, L_VAR} }, // sep.olstAnm OLST variable length
352         {NS_sprm::v6::sprmSDxaColWidth, { 3, L_FIX} }, // sep.rgdxaColWidthSpacing complex
353         {NS_sprm::v6::sprmSDxaColSpacing, { 3, L_FIX} }, // sep.rgdxaColWidthSpacing
354         {NS_sprm::v6::sprmSFEvenlySpaced, { 1, L_FIX} }, // sep.fEvenlySpaced 1 or 0
355         {NS_sprm::v6::sprmSFProtected, { 1, L_FIX} }, // sep.fUnlocked 1 or 0 byte
356         {NS_sprm::v6::sprmSDmBinFirst, { 2, L_FIX} }, // sep.dmBinFirst  word
357         {NS_sprm::v6::sprmSDmBinOther, { 2, L_FIX} }, // sep.dmBinOther  word
358         {NS_sprm::v6::sprmSBkc, { 1, L_FIX} }, // sep.bkc bkc byte
359         {NS_sprm::v6::sprmSFTitlePage, { 1, L_FIX} }, // sep.fTitlePage 0 or 1 byte
360         {NS_sprm::v6::sprmSCcolumns, { 2, L_FIX} }, // sep.ccolM1 # of cols - 1 word
361         {NS_sprm::v6::sprmSDxaColumns, { 2, L_FIX} }, // sep.dxaColumns dxa word
362         {NS_sprm::v6::sprmSFAutoPgn, { 1, L_FIX} }, // sep.fAutoPgn obsolete byte
363         {NS_sprm::v6::sprmSNfcPgn, { 1, L_FIX} }, // sep.nfcPgn nfc byte
364         {NS_sprm::v6::sprmSDyaPgn, { 2, L_FIX} }, // sep.dyaPgn dya short
365         {NS_sprm::v6::sprmSDxaPgn, { 2, L_FIX} }, // sep.dxaPgn dya short
366         {NS_sprm::v6::sprmSFPgnRestart, { 1, L_FIX} }, // sep.fPgnRestart 0 or 1 byte
367         {NS_sprm::v6::sprmSFEndnote, { 1, L_FIX} }, // sep.fEndnote 0 or 1 byte
368         {NS_sprm::v6::sprmSLnc, { 1, L_FIX} }, // sep.lnc lnc byte
369         {NS_sprm::v6::sprmSGprfIhdt, { 1, L_FIX} }, // sep.grpfIhdt grpfihdt
370         {NS_sprm::v6::sprmSNLnnMod, { 2, L_FIX} }, // sep.nLnnMod non-neg int. word
371         {NS_sprm::v6::sprmSDxaLnn, { 2, L_FIX} }, // sep.dxaLnn dxa word
372         {NS_sprm::v6::sprmSDyaHdrTop, { 2, L_FIX} }, // sep.dyaHdrTop dya word
373         {NS_sprm::v6::sprmSDyaHdrBottom, { 2, L_FIX} }, // sep.dyaHdrBottom dya word
374         {NS_sprm::v6::sprmSLBetween, { 1, L_FIX} }, // sep.fLBetween 0 or 1 byte
375         {NS_sprm::v6::sprmSVjc, { 1, L_FIX} }, // sep.vjc vjc byte
376         {NS_sprm::v6::sprmSLnnMin, { 2, L_FIX} }, // sep.lnnMin lnn word
377         {NS_sprm::v6::sprmSPgnStart, { 2, L_FIX} }, // sep.pgnStart pgn word
378         {NS_sprm::v6::sprmSBOrientation, { 1, L_FIX} }, // sep.dmOrientPage dm byte
379         {NS_sprm::v6::sprmSBCustomize, { 0, L_FIX} },
380         {NS_sprm::v6::sprmSXaPage, { 2, L_FIX} }, // sep.xaPage xa word
381         {NS_sprm::v6::sprmSYaPage, { 2, L_FIX} }, // sep.yaPage ya word
382         {NS_sprm::v6::sprmSDxaLeft, { 2, L_FIX} }, // sep.dxaLeft dxa word
383         {NS_sprm::v6::sprmSDxaRight, { 2, L_FIX} }, // sep.dxaRight dxa word
384         {NS_sprm::v6::sprmSDyaTop, { 2, L_FIX} }, // sep.dyaTop dya word
385         {NS_sprm::v6::sprmSDyaBottom, { 2, L_FIX} }, // sep.dyaBottom dya word
386         {NS_sprm::v6::sprmSDzaGutter, { 2, L_FIX} }, // sep.dzaGutter dza word
387         {NS_sprm::v6::sprmSDMPaperReq, { 2, L_FIX} }, // sep.dmPaperReq dm word
388         {179, { 0, L_VAR} }, // rtl property ?
389         {181, { 0, L_VAR} }, // rtl property ?
390         {NS_sprm::v6::sprmTJc, { 2, L_FIX} }, // tap.jc jc (low order byte is significant)
391         {NS_sprm::v6::sprmTDxaLeft, { 2, L_FIX} }, // tap.rgdxaCenter dxa word
392         {NS_sprm::v6::sprmTDxaGapHalf, { 2, L_FIX} }, // tap.dxaGapHalf, tap.rgdxaCenter
393         {NS_sprm::v6::sprmTFCantSplit, { 1, L_FIX} }, // tap.fCantSplit 1 or 0 byte
394         {NS_sprm::v6::sprmTTableHeader, { 1, L_FIX} }, // tap.fTableHeader 1 or 0 byte
395         {NS_sprm::v6::sprmTTableBorders, {12, L_FIX} }, // tap.rgbrcTable complex 12 bytes
396         {NS_sprm::v6::sprmTDefTable10, { 0, L_VAR2} }, // tap.rgdxaCenter, tap.rgtc complex
397         {NS_sprm::v6::sprmTDyaRowHeight, { 2, L_FIX} }, // tap.dyaRowHeight dya word
398         {NS_sprm::v6::sprmTDefTable, { 0, L_VAR2} }, // tap.rgtc complex
399         {NS_sprm::v6::sprmTDefTableShd, { 1, L_VAR} }, // tap.rgshd complex
400         {NS_sprm::v6::sprmTTlp, { 4, L_FIX} }, // tap.tlp TLP 4 bytes
401         {NS_sprm::v6::sprmTSetBrc, { 5, L_FIX} }, // tap.rgtc[].rgbrc complex 5 bytes
402         {NS_sprm::v6::sprmTInsert, { 4, L_FIX} }, // tap.rgdxaCenter,tap.rgtc complex
403         {NS_sprm::v6::sprmTDelete, { 2, L_FIX} }, // tap.rgdxaCenter, tap.rgtc complex
404         {NS_sprm::v6::sprmTDxaCol, { 4, L_FIX} }, // tap.rgdxaCenter complex
405         {NS_sprm::v6::sprmTMerge, { 2, L_FIX} }, // tap.fFirstMerged, tap.fMerged complex
406         {NS_sprm::v6::sprmTSplit, { 2, L_FIX} }, // tap.fFirstMerged, tap.fMerged complex
407         {NS_sprm::v6::sprmTSetBrc10, { 5, L_FIX} }, // tap.rgtc[].rgbrc complex 5 bytes
408         {NS_sprm::v6::sprmTSetShd, { 4, L_FIX} }, // tap.rgshd complex 4 bytes
409         {207, { 0, L_VAR} }  // rtl property ?
410     };
411 
412     if (rFib.m_wIdent >= 0xa697 && rFib.m_wIdent <= 0xa699)
413     {
414         //see Read_AmbiguousSPRM for this oddity
415         static wwSprmSearcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms), true);
416         return &aSprmSrch;
417     }
418 
419     static wwSprmSearcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
420     return &aSprmSrch;
421 };
422 
patchCJKVariant()423 void wwSprmSearcher::patchCJKVariant()
424 {
425     for (sal_uInt16 nId = 111; nId <= 113; ++nId)
426     {
427         SprmInfo& amb1 = map_[nId];
428         amb1.nLen = 2;
429         amb1.nVari = wwSprmParser::L_FIX;
430     }
431 }
432 
InfoRow()433 template <class Sprm> static constexpr SprmInfoRow InfoRow()
434 {
435     return { Sprm::val, { Sprm::len, Sprm::varlen ? wwSprmParser::L_VAR : wwSprmParser::L_FIX } };
436 }
437 
GetWW8SprmSearcher()438 const wwSprmSearcher *wwSprmParser::GetWW8SprmSearcher()
439 {
440     //double lock me
441     //WW8+ Sprms
442     static const SprmInfoRow aSprms[] =
443     {
444         {     0, { 0, L_FIX} }, // "Default-sprm"/ is skipped
445         InfoRow<NS_sprm::PIstd>(), // pap.istd;istd (style code);short;
446         InfoRow<NS_sprm::PIstdPermute>(), // pap.istd;permutation vector
447         InfoRow<NS_sprm::PIncLvl>(), // pap.istd, pap.lvl;difference
448                             // between istd of base PAP and istd of PAP to be
449                             // produced
450         InfoRow<NS_sprm::PJc80>(), // pap.jc;jc (justification);byte;
451         {NS_sprm::LN_PFSideBySide, { 1, L_FIX} }, // "sprmPFSideBySide" pap.fSideBySide;0 or 1;byte;
452         InfoRow<NS_sprm::PFKeep>(), // pap.fKeep;0 or 1;byte;
453         InfoRow<NS_sprm::PFKeepFollow>(), // pap.fKeepFollow;0 or 1;byte;
454         InfoRow<NS_sprm::PFPageBreakBefore>(), // 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         InfoRow<NS_sprm::PIlvl>(), // pap.ilvl;ilvl;byte;
459         InfoRow<NS_sprm::PIlfo>(), // pap.ilfo;ilfo (list index) ;short;
460         InfoRow<NS_sprm::PFNoLineNumb>(), // pap.fNoLnn;0 or 1;byte;
461         InfoRow<NS_sprm::PChgTabsPapx>(), // pap.itbdMac, pap.rgdxaTab,
462                             // pap.rgtbd;complex
463         InfoRow<NS_sprm::PDxaRight80>(), // pap.dxaRight;dxa;word;
464         InfoRow<NS_sprm::PDxaLeft80>(), // pap.dxaLeft;dxa;word;
465         InfoRow<NS_sprm::PNest80>(), // pap.dxaLeft;dxa
466         InfoRow<NS_sprm::PDxaLeft180>(), // pap.dxaLeft1;dxa;word;
467         InfoRow<NS_sprm::PDyaLine>(), // pap.lspd;an LSPD, a long word
468                             // structure consisting of a short of dyaLine
469                             // followed by a short of fMultLinespace
470         InfoRow<NS_sprm::PDyaBefore>(), // pap.dyaBefore;dya;word;
471         InfoRow<NS_sprm::PDyaAfter>(), // pap.dyaAfter;dya;word;
472         InfoRow<NS_sprm::PChgTabs>(), // pap.itbdMac, pap.rgdxaTab,
473                             // pap.rgtbd;complex
474         InfoRow<NS_sprm::PFInTable>(), // pap.fInTable;0 or 1;byte;
475         InfoRow<NS_sprm::PFTtp>(), // pap.fTtp;0 or 1;byte;
476         InfoRow<NS_sprm::PDxaAbs>(), // pap.dxaAbs;dxa;word;
477         InfoRow<NS_sprm::PDyaAbs>(), // pap.dyaAbs;dya;word;
478         InfoRow<NS_sprm::PDxaWidth>(), // pap.dxaWidth;dxa;word;
479         InfoRow<NS_sprm::PPc>(), // 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         {NS_sprm::LN_PDxaFromText10, { 2, L_FIX} }, // "sprmPDxaFromText10" pap.dxaFromText;dxa;word;
487         InfoRow<NS_sprm::PWr>(), // pap.wr;wr
488         InfoRow<NS_sprm::PBrcTop80>(), // pap.brcTop;BRC;long;
489         InfoRow<NS_sprm::PBrcLeft80>(), // pap.brcLeft;BRC;long;
490         InfoRow<NS_sprm::PBrcBottom80>(), // pap.brcBottom;BRC;long;
491         InfoRow<NS_sprm::PBrcRight80>(), // pap.brcRight;BRC;long;
492         InfoRow<NS_sprm::PBrcBetween80>(), // pap.brcBetween;BRC;long;
493         InfoRow<NS_sprm::PBrcBar80>(), // pap.brcBar;BRC;long;
494         InfoRow<NS_sprm::PFNoAutoHyph>(), // pap.fNoAutoHyph;0 or 1;byte;
495         InfoRow<NS_sprm::PWHeightAbs>(), // pap.wHeightAbs;w;word;
496         InfoRow<NS_sprm::PDcs>(), // pap.dcs;DCS;short;
497         InfoRow<NS_sprm::PShd80>(), // pap.shd;SHD;word;
498         InfoRow<NS_sprm::PDyaFromText>(), // pap.dyaFromText;dya;word;
499         InfoRow<NS_sprm::PDxaFromText>(), // pap.dxaFromText;dxa;word;
500         InfoRow<NS_sprm::PFLocked>(), // pap.fLocked;0 or 1;byte;
501         InfoRow<NS_sprm::PFWidowControl>(), // pap.fWidowControl;0 or 1
502         {NS_sprm::LN_PRuler, { 0, L_VAR} }, // "sprmPRuler" ;;variable length;
503         InfoRow<NS_sprm::PFKinsoku>(), // pap.fKinsoku;0 or 1;byte;
504         InfoRow<NS_sprm::PFWordWrap>(), // pap.fWordWrap;0 or 1;byte;
505         InfoRow<NS_sprm::PFOverflowPunct>(), // pap.fOverflowPunct;0 or 1
506         InfoRow<NS_sprm::PFTopLinePunct>(), // pap.fTopLinePunct;0 or 1
507         InfoRow<NS_sprm::PFAutoSpaceDE>(), // pap.fAutoSpaceDE;0 or 1
508         InfoRow<NS_sprm::PFAutoSpaceDN>(), // pap.fAutoSpaceDN;0 or 1
509         InfoRow<NS_sprm::PWAlignFont>(), // pap.wAlignFont;iFa
510         InfoRow<NS_sprm::PFrameTextFlow>(), // 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         InfoRow<NS_sprm::POutLvl>(), // pap.lvl;has no effect if pap.istd
517                             // is < 1 or is > 9
518         InfoRow<NS_sprm::PFBiDi>(), // ;;byte;
519         InfoRow<NS_sprm::PFNumRMIns>(), // pap.fNumRMIns;1 or 0;bit;
520         {NS_sprm::LN_PCrLf, { 1, L_FIX} }, // "sprmPCrLf" ;;byte;
521         InfoRow<NS_sprm::PNumRM>(), // 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         InfoRow<NS_sprm::PHugePapx>(), // fc in the data stream to locate
525                             // the huge grpprl
526         InfoRow<NS_sprm::PFUsePgsuSettings>(), // pap.fUsePgsuSettings;
527                             // 1 or 0
528         InfoRow<NS_sprm::PFAdjustRight>(), // pap.fAdjustRight;1 or 0;byte;
529         InfoRow<NS_sprm::CFRMarkDel>(), // chp.fRMarkDel;1 or 0;bit;
530         InfoRow<NS_sprm::CFRMarkIns>(), // chp.fRMark;1 or 0;bit;
531         InfoRow<NS_sprm::CFFldVanish>(), // chp.fFieldVanish;1 or 0;bit;
532         InfoRow<NS_sprm::CPicLocation>(), // chp.fcPic and chp.fSpec;
533         InfoRow<NS_sprm::CIbstRMark>(), // chp.ibstRMark;index into
534                             // sttbRMark
535         InfoRow<NS_sprm::CDttmRMark>(), // chp.dttmRMark;DTTM;long;
536         InfoRow<NS_sprm::CFData>(), // chp.fData;1 or 0;bit;
537         InfoRow<NS_sprm::CIdslRMark>(), // 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         InfoRow<NS_sprm::CSymbol>(), // chp.fSpec, chp.xchSym and
542                             // chp.ftcSym
543         InfoRow<NS_sprm::CFOle2>(), // 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         InfoRow<NS_sprm::CHighlight>(), // 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         InfoRow<NS_sprm::CIstd>(), // chp.istd;istd, see stylesheet def
552         InfoRow<NS_sprm::CIstdPermute>(), // chp.istd;permutation vector
553         {NS_sprm::LN_CDefault, { 0, L_VAR} }, // "sprmCDefault" whole CHP;none;variable length;
554         InfoRow<NS_sprm::CPlain>(), // whole CHP;none;0;
555         InfoRow<NS_sprm::CKcd>(), // ;;;
556         InfoRow<NS_sprm::CFBold>(), // chp.fBold;0,1, 128, or 129
557         InfoRow<NS_sprm::CFItalic>(), // chp.fItalic;0,1, 128, or 129
558         InfoRow<NS_sprm::CFStrike>(), // chp.fStrike;0,1, 128, or 129
559         InfoRow<NS_sprm::CFOutline>(), // chp.fOutline;0,1, 128, or 129
560         InfoRow<NS_sprm::CFShadow>(), // chp.fShadow;0,1, 128, or 129
561         InfoRow<NS_sprm::CFSmallCaps>(), // chp.fSmallCaps;0,1, 128, or 129
562         InfoRow<NS_sprm::CFCaps>(), // chp.fCaps;0,1, 128, or 129
563         InfoRow<NS_sprm::CFVanish>(), // chp.fVanish;0,1, 128, or 129
564         {NS_sprm::LN_CFtcDefault, { 2, L_FIX} }, // "sprmCFtcDefault" ;ftc, only used internally
565         InfoRow<NS_sprm::CKul>(), // chp.kul;kul;byte;
566         {NS_sprm::LN_CSizePos, { 3, L_FIX} }, // "sprmCSizePos" chp.hps, chp.hpsPos;3 bytes;
567         InfoRow<NS_sprm::CDxaSpace>(), // chp.dxaSpace;dxa;word;
568         {NS_sprm::LN_CLid, { 2, L_FIX} }, // "sprmCLid" ;only used internally never stored
569         InfoRow<NS_sprm::CIco>(), // chp.ico;ico;byte;
570         InfoRow<NS_sprm::CHps>(), // chp.hps;hps
571         {NS_sprm::LN_CHpsInc, { 1, L_FIX} }, // "sprmCHpsInc" chp.hps;
572         InfoRow<NS_sprm::CHpsPos>(), // chp.hpsPos;hps;short; (doc wrong)
573         {NS_sprm::LN_CHpsPosAdj, { 1, L_FIX} }, // "sprmCHpsPosAdj" chp.hpsPos;hps
574         InfoRow<NS_sprm::CMajority>(), // 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         InfoRow<NS_sprm::CIss>(), // 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         InfoRow<NS_sprm::CHpsKern>(), // 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         InfoRow<NS_sprm::CHresi>(), // chp.ysri;ysri;short;
590         InfoRow<NS_sprm::CRgFtc0>(), // chp.rgftc[0];ftc for ASCII text
591         InfoRow<NS_sprm::CRgFtc1>(), // chp.rgftc[1];ftc for Far East text
592         InfoRow<NS_sprm::CRgFtc2>(), // chp.rgftc[2];ftc for non-FE text
593         InfoRow<NS_sprm::CCharScale>(),
594         InfoRow<NS_sprm::CFDStrike>(), // chp.fDStrike;;byte;
595         InfoRow<NS_sprm::CFImprint>(), // chp.fImprint;1 or 0;bit;
596         InfoRow<NS_sprm::CFSpec>(), // chp.fSpec ;1 or 0;bit;
597         InfoRow<NS_sprm::CFObj>(), // chp.fObj;1 or 0;bit;
598         InfoRow<NS_sprm::CPropRMark90>(), // chp.fPropRMark,
599                             // chp.ibstPropRMark, chp.dttmPropRMark;Complex
600         InfoRow<NS_sprm::CFEmboss>(), // chp.fEmboss;1 or 0;bit;
601         InfoRow<NS_sprm::CSfxText>(), // chp.sfxtText;text animation;byte;
602         InfoRow<NS_sprm::CFBiDi>(), // ;;;
603         {NS_sprm::LN_CFDiacColor, { 1, L_FIX} }, // "sprmCFDiacColor" ;;;
604         InfoRow<NS_sprm::CFBoldBi>(), // ;;;
605         InfoRow<NS_sprm::CFItalicBi>(), // ;;;
606         InfoRow<NS_sprm::CFtcBi>(),
607         InfoRow<NS_sprm::CLidBi>(), // ;;;
608         InfoRow<NS_sprm::CIcoBi>(), // ;;;
609         InfoRow<NS_sprm::CHpsBi>(), // ;;;
610         InfoRow<NS_sprm::CDispFldRMark>(), // chp.fDispFieldRMark,
611                             // chp.ibstDispFieldRMark, chp.dttmDispFieldRMark ;
612         InfoRow<NS_sprm::CIbstRMarkDel>(), // chp.ibstRMarkDel;index into
613                             // sttbRMark;short;
614         InfoRow<NS_sprm::CDttmRMarkDel>(), // chp.dttmRMarkDel;DTTM;long;
615         InfoRow<NS_sprm::CBrc80>(), // chp.brc;BRC;long;
616         InfoRow<NS_sprm::CShd80>(), // chp.shd;SHD;short;
617         InfoRow<NS_sprm::CIdslRMarkDel>(), // chp.idslRMReasonDel;an index
618                             // to a table of strings defined in Word 6.0
619                             // executables;short;
620         InfoRow<NS_sprm::CFUsePgsuSettings>(),
621                             // chp.fUsePgsuSettings;1 or 0
622         {NS_sprm::LN_CCpg, { 2, L_FIX} }, // "sprmCCpg" ;;word;
623         InfoRow<NS_sprm::CRgLid0_80>(), // chp.rglid[0];LID: for non-FE text
624         InfoRow<NS_sprm::CRgLid1_80>(), // chp.rglid[1];LID: for Far East text
625         InfoRow<NS_sprm::CIdctHint>(), // 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         InfoRow<NS_sprm::PicBrcTop80>(), // pic.brcTop;BRC;long;
631         InfoRow<NS_sprm::PicBrcLeft80>(), // pic.brcLeft;BRC;long;
632         InfoRow<NS_sprm::PicBrcBottom80>(), // pic.brcBottom;BRC;long;
633         InfoRow<NS_sprm::PicBrcRight80>(), // pic.brcRight;BRC;long;
634         InfoRow<NS_sprm::ScnsPgn>(), // sep.cnsPgn;cns;byte;
635         InfoRow<NS_sprm::SiHeadingPgn>(), // sep.iHeadingPgn;heading number
636                             // level;byte;
637         {NS_sprm::LN_SOlstAnm, { 0, L_VAR} }, // "sprmSOlstAnm" sep.olstAnm;OLST;variable length;
638         InfoRow<NS_sprm::SDxaColWidth>(), // sep.rgdxaColWidthSpacing;
639         InfoRow<NS_sprm::SDxaColSpacing>(), // sep.rgdxaColWidthSpacing;
640                             // complex
641         InfoRow<NS_sprm::SFEvenlySpaced>(), // sep.fEvenlySpaced;1 or 0
642         InfoRow<NS_sprm::SFProtected>(), // sep.fUnlocked;1 or 0;byte;
643         InfoRow<NS_sprm::SDmBinFirst>(), // sep.dmBinFirst;;word;
644         InfoRow<NS_sprm::SDmBinOther>(), // sep.dmBinOther;;word;
645         InfoRow<NS_sprm::SBkc>(), // sep.bkc;bkc;byte;
646         InfoRow<NS_sprm::SFTitlePage>(), // sep.fTitlePage;0 or 1;byte;
647         InfoRow<NS_sprm::SCcolumns>(), // sep.ccolM1;# of cols - 1;word;
648         InfoRow<NS_sprm::SDxaColumns>(), // sep.dxaColumns;dxa;word;
649         {NS_sprm::LN_SFAutoPgn, { 1, L_FIX} }, // "sprmSFAutoPgn" sep.fAutoPgn;obsolete;byte;
650         InfoRow<NS_sprm::SNfcPgn>(), // 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         InfoRow<NS_sprm::SFPgnRestart>(), // sep.fPgnRestart;0 or 1;byte;
654         InfoRow<NS_sprm::SFEndnote>(), // sep.fEndnote;0 or 1;byte;
655         InfoRow<NS_sprm::SLnc>(), // sep.lnc;lnc;byte;
656         {NS_sprm::LN_SGprfIhdt, { 1, L_FIX} }, // "sprmSGprfIhdt" sep.grpfIhdt;grpfihdt
657         InfoRow<NS_sprm::SNLnnMod>(), // sep.nLnnMod;non-neg int.;word;
658         InfoRow<NS_sprm::SDxaLnn>(), // sep.dxaLnn;dxa;word;
659         InfoRow<NS_sprm::SDyaHdrTop>(), // sep.dyaHdrTop;dya;word;
660         InfoRow<NS_sprm::SDyaHdrBottom>(), // sep.dyaHdrBottom;dya;word;
661         InfoRow<NS_sprm::SLBetween>(), // sep.fLBetween;0 or 1;byte;
662         InfoRow<NS_sprm::SVjc>(), // sep.vjc;vjc;byte;
663         InfoRow<NS_sprm::SLnnMin>(), // sep.lnnMin;lnn;word;
664         InfoRow<NS_sprm::SPgnStart97>(), // sep.pgnStart;pgn;word;
665         InfoRow<NS_sprm::SBOrientation>(), // sep.dmOrientPage;dm;byte;
666         {NS_sprm::LN_SBCustomize, { 1, L_FIX} }, // "sprmSBCustomize" ;;;
667         InfoRow<NS_sprm::SXaPage>(), // sep.xaPage;xa;word;
668         InfoRow<NS_sprm::SYaPage>(), // sep.yaPage;ya;word;
669         InfoRow<NS_sprm::SDxaLeft>(), // sep.dxaLeft;dxa;word;
670         InfoRow<NS_sprm::SDxaRight>(), // sep.dxaRight;dxa;word;
671         InfoRow<NS_sprm::SDyaTop>(), // sep.dyaTop;dya;word;
672         InfoRow<NS_sprm::SDyaBottom>(), // sep.dyaBottom;dya;word;
673         InfoRow<NS_sprm::SDzaGutter>(), // sep.dzaGutter;dza;word;
674         InfoRow<NS_sprm::SDmPaperReq>(), // sep.dmPaperReq;dm;word;
675         {NS_sprm::LN_SPropRMark, { 0, L_VAR} }, // "sprmSPropRMark" sep.fPropRMark,
676                             // sep.ibstPropRMark, sep.dttmPropRMark ;complex
677         InfoRow<NS_sprm::SFBiDi>(), // ;;;
678         {NS_sprm::LN_SFFacingCol, { 1, L_FIX} }, // "sprmSFFacingCol" ;;;
679         InfoRow<NS_sprm::SFRTLGutter>(), //, set to one if gutter is on
680                             // right
681         InfoRow<NS_sprm::SBrcTop80>(), // sep.brcTop;BRC;long;
682         InfoRow<NS_sprm::SBrcLeft80>(), // sep.brcLeft;BRC;long;
683         InfoRow<NS_sprm::SBrcBottom80>(), // sep.brcBottom;BRC;long;
684         InfoRow<NS_sprm::SBrcRight80>(), // sep.brcRight;BRC;long;
685         InfoRow<NS_sprm::SPgbProp>(), // sep.pgbProp;;word;
686         InfoRow<NS_sprm::SDxtCharSpace>(), // sep.dxtCharSpace;dxt;long;
687         InfoRow<NS_sprm::SDyaLinePitch>(),
688                             // sep.dyaLinePitch;dya; WRONG:long; RIGHT:short; !
689         InfoRow<NS_sprm::SClm>(), // ;;;
690         InfoRow<NS_sprm::STextFlow>(), // sep.wTextFlow;complex
691         InfoRow<NS_sprm::TJc90>(), // tap.jc;jc;word (low order byte is
692                             // significant);
693         InfoRow<NS_sprm::TDxaLeft>(), // tap.rgdxaCenter
694         InfoRow<NS_sprm::TDxaGapHalf>(), // tap.dxaGapHalf,
695                             // tap.rgdxaCenter
696         InfoRow<NS_sprm::TFCantSplit90>(), // tap.fCantSplit90;1 or 0;byte;
697         InfoRow<NS_sprm::TTableHeader>(), // tap.fTableHeader;1 or 0;byte;
698         InfoRow<NS_sprm::TFCantSplit>(), // tap.fCantSplit;1 or 0;byte;
699         InfoRow<NS_sprm::TTableBorders80>(), // tap.rgbrcTable;complex
700         {NS_sprm::LN_TDefTable10, { 0, L_VAR2} }, // "sprmTDefTable10" tap.rgdxaCenter,
701                             // tap.rgtc;complex
702         InfoRow<NS_sprm::TDyaRowHeight>(), // tap.dyaRowHeight;dya;word;
703         {NS_sprm::LN_TDefTable, { 0, L_VAR2} }, // "sprmTDefTable" tap.rgtc;complex
704         InfoRow<NS_sprm::TDefTableShd80>(), // tap.rgshd;complex
705         InfoRow<NS_sprm::TTlp>(), // tap.tlp;TLP;4 bytes;
706         InfoRow<NS_sprm::TFBiDi>(), // ;;;
707         {NS_sprm::LN_THTMLProps, { 1, L_FIX} }, // "sprmTHTMLProps" ;;;
708         InfoRow<NS_sprm::TSetBrc80>(), // tap.rgtc[].rgbrc;complex
709         InfoRow<NS_sprm::TInsert>(), // tap.rgdxaCenter, tap.rgtc;complex
710         InfoRow<NS_sprm::TDelete>(), // tap.rgdxaCenter, tap.rgtc;complex
711         InfoRow<NS_sprm::TDxaCol>(), // tap.rgdxaCenter;complex
712         InfoRow<NS_sprm::TMerge>(), // tap.fFirstMerged, tap.fMerged;
713         InfoRow<NS_sprm::TSplit>(), // 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         InfoRow<NS_sprm::TTextFlow>(), // 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         InfoRow<NS_sprm::TVertMerge>(), // tap.rgtc[].vertMerge
722         InfoRow<NS_sprm::TVertAlign>(), // tap.rgtc[].vertAlign
723         InfoRow<NS_sprm::CFELayout>(),
724         InfoRow<NS_sprm::PItap>(), // undocumented
725         InfoRow<NS_sprm::TTableWidth>(), // undocumented
726         InfoRow<NS_sprm::TDefTableShd>(),
727         InfoRow<NS_sprm::TTableBorders>(),
728         InfoRow<NS_sprm::TBrcTopCv>(), // undocumented
729         InfoRow<NS_sprm::TBrcLeftCv>(), // undocumented
730         InfoRow<NS_sprm::TBrcBottomCv>(), // undocumented
731         InfoRow<NS_sprm::TBrcRightCv>(), // undocumented
732         InfoRow<NS_sprm::TCellPadding>(), // undocumented
733         InfoRow<NS_sprm::TCellPaddingDefault>(), // undocumented
734         {0xD238, { 0, L_VAR} }, // undocumented sep
735         InfoRow<NS_sprm::PBrcTop>(),
736         InfoRow<NS_sprm::PBrcLeft>(),
737         InfoRow<NS_sprm::PBrcBottom>(),
738         InfoRow<NS_sprm::PBrcRight>(),
739         InfoRow<NS_sprm::PBrcBetween>(),
740         InfoRow<NS_sprm::TWidthIndent>(), // undocumented
741         InfoRow<NS_sprm::CRgLid0>(), // chp.rglid[0];LID: for non-FE text
742         InfoRow<NS_sprm::CRgLid1>(), // chp.rglid[1];LID: for Far East text
743         {0x6463, { 4, L_FIX} }, // undocumented
744         InfoRow<NS_sprm::PJc>(), // undoc, must be asian version of "sprmPJc"
745         InfoRow<NS_sprm::PDxaRight>(), // undoc, must be asian version of "sprmPDxaRight"
746         InfoRow<NS_sprm::PDxaLeft>(), // undoc, must be asian version of "sprmPDxaLeft"
747         InfoRow<NS_sprm::PDxaLeft1>(), // undoc, must be asian version of "sprmPDxaLeft1"
748         InfoRow<NS_sprm::TFAutofit>(), // undocumented
749         InfoRow<NS_sprm::TPc>(), // undocumented
750         InfoRow<NS_sprm::SRsid>(), // undocumented, sep, perhaps related to textgrids ?
751         InfoRow<NS_sprm::SFpc>(), // undocumented, sep
752         InfoRow<NS_sprm::PFInnerTableCell>(), // undocumented, subtable "sprmPFInTable" equiv ?
753         InfoRow<NS_sprm::PFInnerTtp>(), // undocumented, subtable "sprmPFTtp" equiv ?
754         InfoRow<NS_sprm::TDxaAbs>(), // undocumented
755         InfoRow<NS_sprm::TDyaAbs>(), // undocumented
756         InfoRow<NS_sprm::TDxaFromText>(), // undocumented
757         InfoRow<NS_sprm::CRsidProp>(), // undocumented
758         InfoRow<NS_sprm::CRsidText>(), // undocumented
759         InfoRow<NS_sprm::CCv>(), // text colour
760         InfoRow<NS_sprm::PShd>(), // undocumented, para back colour
761         InfoRow<NS_sprm::PRsid>(), // undocumented
762         InfoRow<NS_sprm::PTableProps>(), // undocumented
763         InfoRow<NS_sprm::TWidthBefore>(), // undocumented
764         InfoRow<NS_sprm::TSetShdTable>(), // undocumented, something to do with colour.
765         InfoRow<NS_sprm::TDefTableShdRaw>(), // undocumented, something to do with colour.
766         InfoRow<NS_sprm::CShd>(), // text backcolour
767         InfoRow<NS_sprm::SRncFtn>(), // undocumented, sep
768         InfoRow<NS_sprm::PFDyaBeforeAuto>(), // undocumented, para autobefore
769         InfoRow<NS_sprm::PFDyaAfterAuto>(), // undocumented, para autoafter
770         // "sprmPFContextualSpacing", don't add space between para of the same style
771         InfoRow<NS_sprm::PFContextualSpacing>(),
772     };
773 
774     static wwSprmSearcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
775     return &aSprmSrch;
776 };
777 
wwSprmParser(const WW8Fib & rFib)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)
786         mpKnownSprms = GetWW2SprmSearcher();
787     else if (meVersion < ww::eWW8)
788         mpKnownSprms = GetWW6SprmSearcher(rFib);
789     else
790         mpKnownSprms = GetWW8SprmSearcher();
791 }
792 
GetSprmInfo(sal_uInt16 nId) const793 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 
Get_Byte(sal_uInt8 * & p)840 static sal_uInt8 Get_Byte( sal_uInt8 *& p )
841 {
842     sal_uInt8 n = *p;
843     p += 1;
844     return n;
845 }
846 
Get_UShort(sal_uInt8 * & p)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 
Get_Short(sal_uInt8 * & p)854 static sal_Int16 Get_Short( sal_uInt8 *& p )
855 {
856     return Get_UShort(p);
857 }
858 
Get_ULong(sal_uInt8 * & p)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 
Get_Long(sal_uInt8 * & p)866 static sal_Int32 Get_Long( sal_uInt8 *& p )
867 {
868     return Get_ULong(p);
869 }
870 
WW8SprmIter(const sal_uInt8 * pSprms_,sal_Int32 nLen_,const wwSprmParser & rParser)871 WW8SprmIter::WW8SprmIter(const sal_uInt8* pSprms_, sal_Int32 nLen_,
872     const wwSprmParser &rParser)
873     :  mrSprmParser(rParser), m_pSprms( pSprms_), m_nRemLen( nLen_)
874 {
875     UpdateMyMembers();
876 }
877 
SetSprms(const sal_uInt8 * pSprms_,sal_Int32 nLen_)878 void WW8SprmIter::SetSprms(const sal_uInt8* pSprms_, sal_Int32 nLen_)
879 {
880     m_pSprms = pSprms_;
881     m_nRemLen = nLen_;
882     UpdateMyMembers();
883 }
884 
advance()885 void WW8SprmIter::advance()
886 {
887     if (m_nRemLen > 0 )
888     {
889         sal_uInt16 nSize = m_nCurrentSize;
890         if (nSize > m_nRemLen)
891             nSize = m_nRemLen;
892         m_pSprms += nSize;
893         m_nRemLen -= nSize;
894         UpdateMyMembers();
895     }
896 }
897 
UpdateMyMembers()898 void WW8SprmIter::UpdateMyMembers()
899 {
900     bool bValid = (m_pSprms && m_nRemLen >= mrSprmParser.MinSprmLen());
901 
902     if (bValid)
903     {
904         m_nCurrentId = mrSprmParser.GetSprmId(m_pSprms);
905         m_nCurrentSize = mrSprmParser.GetSprmSize(m_nCurrentId, m_pSprms, m_nRemLen);
906         m_pCurrentParams = m_pSprms + mrSprmParser.DistanceToData(m_nCurrentId);
907         bValid = m_nCurrentSize <= m_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         m_nCurrentId = 0;
914         m_pCurrentParams = nullptr;
915         m_nCurrentSize = 0;
916         m_nRemLen = 0;
917     }
918 }
919 
FindSprm(sal_uInt16 nId,bool bFindFirst,const sal_uInt8 * pNextByteMatch)920 SprmResult WW8SprmIter::FindSprm(sal_uInt16 nId, bool bFindFirst, const sal_uInt8* pNextByteMatch)
921 {
922     SprmResult aRet;
923 
924     while (GetSprms())
925     {
926         if (GetCurrentId() == nId)
927         {
928             sal_Int32 nFixedLen =  mrSprmParser.DistanceToData(nId);
929             sal_Int32 nL = mrSprmParser.GetSprmSize(nId, GetSprms(), GetRemLen());
930             SprmResult aSprmResult(GetCurrentParams(), nL - nFixedLen);
931             // typically pNextByteMatch is nullptr and we just return the first match
932             // very occasionally we want one with a specific following byte
933             if ( !pNextByteMatch || (aSprmResult.nRemainingData >= 1 && *aSprmResult.pSprm == *pNextByteMatch) )
934             {
935                 if ( bFindFirst )
936                     return aSprmResult;
937                 aRet = aSprmResult;
938             }
939         }
940         advance();
941     }
942 
943     return aRet;
944 }
945 
946 // temporary test
947 // WW8PLCFx_PCDAttrs cling to WW8PLCF_Pcd and therefore do not have their own iterators.
948 // All methods relating to iterators are therefore dummies.
WW8PLCFx_PCDAttrs(const WW8Fib & rFib,WW8PLCFx_PCD * pPLCFx_PCD,const WW8ScannerBase * pBase)949 WW8PLCFx_PCDAttrs::WW8PLCFx_PCDAttrs(const WW8Fib& rFib,
950     WW8PLCFx_PCD* pPLCFx_PCD, const WW8ScannerBase* pBase)
951     : WW8PLCFx(rFib, true), m_pPcdI(pPLCFx_PCD->GetPLCFIter()),
952     m_pPcd(pPLCFx_PCD), mrGrpprls(pBase->m_aPieceGrpprls)
953 {
954 }
955 
GetIdx() const956 sal_uInt32 WW8PLCFx_PCDAttrs::GetIdx() const
957 {
958     return 0;
959 }
960 
SetIdx(sal_uInt32)961 void WW8PLCFx_PCDAttrs::SetIdx(sal_uInt32)
962 {
963 }
964 
SeekPos(WW8_CP)965 bool WW8PLCFx_PCDAttrs::SeekPos(WW8_CP )
966 {
967     return true;
968 }
969 
advance()970 void WW8PLCFx_PCDAttrs::advance()
971 {
972 }
973 
Where()974 WW8_CP WW8PLCFx_PCDAttrs::Where()
975 {
976     return m_pPcd ? m_pPcd->Where() : WW8_CP_MAX;
977 }
978 
GetSprms(WW8PLCFxDesc * p)979 void WW8PLCFx_PCDAttrs::GetSprms(WW8PLCFxDesc* p)
980 {
981     void* pData;
982 
983     p->bRealLineEnd = false;
984     if ( !m_pPcdI || !m_pPcdI->Get(p->nStartPos, p->nEndPos, pData) )
985     {
986         // PLCF fully processed
987         p->nStartPos = p->nEndPos = WW8_CP_MAX;
988         p->pMemPos = nullptr;
989         p->nSprmsLen = 0;
990         return;
991     }
992 
993     const sal_uInt16 nPrm = SVBT16ToUInt16( static_cast<WW8_PCD*>(pData)->prm );
994     if ( nPrm & 1 )
995     {
996         // PRM Variant 2
997         const sal_uInt16 nSprmIdx = nPrm >> 1;
998 
999         if( nSprmIdx >= mrGrpprls.size() )
1000         {
1001             // Invalid Index
1002             p->nStartPos = p->nEndPos = WW8_CP_MAX;
1003             p->pMemPos = nullptr;
1004             p->nSprmsLen = 0;
1005             return;
1006         }
1007         const sal_uInt8* pSprms = mrGrpprls[ nSprmIdx ].get();
1008 
1009         p->nSprmsLen = SVBT16ToUInt16( pSprms ); // Length
1010         pSprms += 2;
1011         p->pMemPos = pSprms;                    // Position
1012     }
1013     else
1014     {
1015         // SPRM is stored directly into members var
1016         /*
1017             These are the attr that are in the piece-table instead of in the text!
1018         */
1019 
1020         if (IsSevenMinus(GetFIBVersion()))
1021         {
1022             m_aShortSprm[0] = static_cast<sal_uInt8>( ( nPrm & 0xfe) >> 1 );
1023             m_aShortSprm[1] = static_cast<sal_uInt8>(   nPrm         >> 8 );
1024             p->nSprmsLen = nPrm ? 2 : 0;        // length
1025 
1026             // store Position of internal mini storage in Data Pointer
1027             p->pMemPos = m_aShortSprm;
1028         }
1029         else
1030         {
1031             p->pMemPos = nullptr;
1032             p->nSprmsLen = 0;
1033             sal_uInt8 nSprmListIdx = static_cast<sal_uInt8>((nPrm & 0xfe) >> 1);
1034             if( nSprmListIdx )
1035             {
1036                 // process Sprm Id Matching as explained in MS Documentation
1037 
1038                 // ''Property Modifier(variant 1) (PRM)''
1039                 // see file: s62f39.htm
1040 
1041                 // Since Sprm is 7 bits, rgsprmPrm can hold 0x80 entries.
1042                 static const sal_uInt16 aSprmId[0x80] =
1043                 {
1044                     // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1045                     0x0000,0x0000,0x0000,0x0000,
1046                     // sprmPIncLvl, sprmPJc, sprmPFSideBySide, sprmPFKeep
1047                     0x2402,0x2403,NS_sprm::LN_PFSideBySide,0x2405,
1048                     // sprmPFKeepFollow, sprmPFPageBreakBefore, sprmPBrcl,
1049                     // sprmPBrcp
1050                     0x2406,0x2407,NS_sprm::LN_PBrcl,NS_sprm::LN_PBrcp,
1051                     // sprmPIlvl, sprmNoop, sprmPFNoLineNumb, sprmNoop
1052                     0x260A,0x0000,0x240C,0x0000,
1053                     // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1054                     0x0000,0x0000,0x0000,0x0000,
1055                     // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1056                     0x0000,0x0000,0x0000,0x0000,
1057                     // sprmPFInTable, sprmPFTtp, sprmNoop, sprmNoop
1058                     0x2416,0x2417,0x0000,0x0000,
1059                     // sprmNoop, sprmPPc,  sprmNoop, sprmNoop
1060                     0x0000,0x261B,0x0000,0x0000,
1061                     // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1062                     0x0000,0x0000,0x0000,0x0000,
1063                     // sprmNoop, sprmPWr,  sprmNoop, sprmNoop
1064                     0x0000,0x2423,0x0000,0x0000,
1065                     // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1066                     0x0000,0x0000,0x0000,0x0000,
1067                     // sprmPFNoAutoHyph, sprmNoop, sprmNoop, sprmNoop
1068                     0x242A,0x0000,0x0000,0x0000,
1069                     // sprmNoop, sprmNoop, sprmPFLocked, sprmPFWidowControl
1070                     0x0000,0x0000,0x2430,0x2431,
1071                     // sprmNoop, sprmPFKinsoku, sprmPFWordWrap,
1072                     // sprmPFOverflowPunct
1073                     0x0000,0x2433,0x2434,0x2435,
1074                     // sprmPFTopLinePunct, sprmPFAutoSpaceDE,
1075                     // sprmPFAutoSpaceDN, sprmNoop
1076                     0x2436,0x2437,0x2438,0x0000,
1077                     // sprmNoop, sprmPISnapBaseLine, sprmNoop, sprmNoop
1078                     0x0000,NS_sprm::LN_PISnapBaseLine,0x000,0x0000,
1079                     // sprmNoop, sprmCFStrikeRM, sprmCFRMark, sprmCFFieldVanish
1080                     0x0000,0x0800,0x0801,0x0802,
1081                     // sprmNoop, sprmNoop, sprmNoop, sprmCFData
1082                     0x0000,0x0000,0x0000,0x0806,
1083                     // sprmNoop, sprmNoop, sprmNoop, sprmCFOle2
1084                     0x0000,0x0000,0x0000,0x080A,
1085                     // sprmNoop, sprmCHighlight, sprmCFEmboss, sprmCSfxText
1086                     0x0000,0x2A0C,0x0858,0x2859,
1087                     // sprmNoop, sprmNoop, sprmNoop, sprmCPlain
1088                     0x0000,0x0000,0x0000,0x2A33,
1089                     // sprmNoop, sprmCFBold, sprmCFItalic, sprmCFStrike
1090                     0x0000,0x0835,0x0836,0x0837,
1091                     // sprmCFOutline, sprmCFShadow, sprmCFSmallCaps, sprmCFCaps,
1092                     0x0838,0x0839,0x083a,0x083b,
1093                     // sprmCFVanish, sprmNoop, sprmCKul, sprmNoop,
1094                     0x083C,0x0000,0x2A3E,0x0000,
1095                     // sprmNoop, sprmNoop, sprmCIco, sprmNoop,
1096                     0x0000,0x0000,0x2A42,0x0000,
1097                     // sprmCHpsInc, sprmNoop, sprmCHpsPosAdj, sprmNoop,
1098                     NS_sprm::LN_CHpsInc,0x0000,NS_sprm::LN_CHpsPosAdj,0x0000,
1099                     // sprmCIss, sprmNoop, sprmNoop, sprmNoop,
1100                     0x2A48,0x0000,0x0000,0x0000,
1101                     // sprmNoop, sprmNoop, sprmNoop, sprmNoop,
1102                     0x0000,0x0000,0x0000,0x0000,
1103                     // sprmNoop, sprmNoop, sprmNoop, sprmCFDStrike,
1104                     0x0000,0x0000,0x0000,0x2A53,
1105                     // sprmCFImprint, sprmCFSpec, sprmCFObj, sprmPicBrcl,
1106                     0x0854,0x0855,0x0856,NS_sprm::LN_PicBrcl,
1107                     // sprmPOutLvl, sprmPFBiDi, sprmNoop, sprmNoop,
1108                     0x2640,0x2441,0x0000,0x0000,
1109                     // sprmNoop, sprmNoop, sprmPPnbrRMarkNot
1110                     0x0000,0x0000,0x0000,0x0000
1111                 };
1112 
1113                 // find real Sprm Id:
1114                 const sal_uInt16 nSprmId = aSprmId[ nSprmListIdx ];
1115 
1116                 if( nSprmId )
1117                 {
1118                     // move Sprm Id and Sprm Param to internal mini storage:
1119                     m_aShortSprm[0] = static_cast<sal_uInt8>( nSprmId & 0x00ff)       ;
1120                     m_aShortSprm[1] = static_cast<sal_uInt8>( ( nSprmId & 0xff00) >> 8 );
1121                     m_aShortSprm[2] = static_cast<sal_uInt8>( nPrm >> 8 );
1122 
1123                     // store Sprm Length in member:
1124                     p->nSprmsLen = nPrm ? 3 : 0;
1125 
1126                     // store Position of internal mini storage in Data Pointer
1127                     p->pMemPos = m_aShortSprm;
1128                 }
1129             }
1130         }
1131     }
1132 }
1133 
WW8PLCFx_PCD(const WW8Fib & rFib,WW8PLCFpcd * pPLCFpcd,WW8_CP nStartCp,bool bVer67P)1134 WW8PLCFx_PCD::WW8PLCFx_PCD(const WW8Fib& rFib, WW8PLCFpcd* pPLCFpcd,
1135     WW8_CP nStartCp, bool bVer67P)
1136     : WW8PLCFx(rFib, false), m_nClipStart(-1)
1137 {
1138     // construct own iterator
1139     m_pPcdI.reset( new WW8PLCFpcd_Iter(*pPLCFpcd, nStartCp) );
1140     m_bVer67= bVer67P;
1141 }
1142 
~WW8PLCFx_PCD()1143 WW8PLCFx_PCD::~WW8PLCFx_PCD()
1144 {
1145 }
1146 
GetIMax() const1147 sal_uInt32 WW8PLCFx_PCD::GetIMax() const
1148 {
1149     return m_pPcdI ? m_pPcdI->GetIMax() : 0;
1150 }
1151 
GetIdx() const1152 sal_uInt32 WW8PLCFx_PCD::GetIdx() const
1153 {
1154     return m_pPcdI ? m_pPcdI->GetIdx() : 0;
1155 }
1156 
SetIdx(sal_uInt32 nIdx)1157 void WW8PLCFx_PCD::SetIdx(sal_uInt32 nIdx)
1158 {
1159     if (m_pPcdI)
1160         m_pPcdI->SetIdx( nIdx );
1161 }
1162 
SeekPos(WW8_CP nCpPos)1163 bool WW8PLCFx_PCD::SeekPos(WW8_CP nCpPos)
1164 {
1165     return m_pPcdI && m_pPcdI->SeekPos( nCpPos );
1166 }
1167 
Where()1168 WW8_CP WW8PLCFx_PCD::Where()
1169 {
1170     return m_pPcdI ? m_pPcdI->Where() : WW8_CP_MAX;
1171 }
1172 
GetNoSprms(WW8_CP & rStart,WW8_CP & rEnd,sal_Int32 & rLen)1173 tools::Long WW8PLCFx_PCD::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
1174 {
1175     void* pData;
1176     rLen = 0;
1177 
1178     if ( !m_pPcdI || !m_pPcdI->Get(rStart, rEnd, pData) )
1179     {
1180         rStart = rEnd = WW8_CP_MAX;
1181         return -1;
1182     }
1183     return m_pPcdI->GetIdx();
1184 }
1185 
advance()1186 void WW8PLCFx_PCD::advance()
1187 {
1188     OSL_ENSURE(m_pPcdI , "missing pPcdI");
1189     if (m_pPcdI)
1190         m_pPcdI->advance();
1191 }
1192 
CurrentPieceStartCp2Fc(WW8_CP nCp)1193 WW8_FC WW8PLCFx_PCD::CurrentPieceStartCp2Fc( WW8_CP nCp )
1194 {
1195     WW8_CP nCpStart, nCpEnd;
1196     void* pData;
1197 
1198     if ( !m_pPcdI->Get(nCpStart, nCpEnd, pData) )
1199     {
1200         OSL_ENSURE( false, "CurrentPieceStartCp2Fc() with false Cp found (1)" );
1201         return WW8_FC_MAX;
1202     }
1203 
1204     OSL_ENSURE( nCp >= nCpStart && nCp < nCpEnd,
1205         "AktPieceCp2Fc() with false Cp found (2)" );
1206 
1207     if( nCp < nCpStart )
1208         nCp = nCpStart;
1209     if( nCp >= nCpEnd )
1210         nCp = nCpEnd - 1;
1211 
1212     bool bIsUnicode = false;
1213     WW8_FC nFC = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
1214     if( !m_bVer67 )
1215         nFC = WW8PLCFx_PCD::TransformPieceAddress( nFC, bIsUnicode );
1216 
1217     WW8_CP nDistance;
1218     bool bFail = o3tl::checked_sub(nCp, nCpStart, nDistance);
1219     if (bFail)
1220     {
1221         SAL_WARN("sw.ww8", "broken offset, ignoring");
1222         return WW8_FC_MAX;
1223     }
1224 
1225     if (bIsUnicode)
1226     {
1227         bFail = o3tl::checked_multiply<WW8_CP>(nDistance, 2, nDistance);
1228         if (bFail)
1229         {
1230             SAL_WARN("sw.ww8", "broken offset, ignoring");
1231             return WW8_FC_MAX;
1232         }
1233     }
1234 
1235     WW8_FC nRet;
1236     bFail = o3tl::checked_add(nFC, nDistance, nRet);
1237     if (bFail)
1238     {
1239         SAL_WARN("sw.ww8", "broken offset, ignoring");
1240         return WW8_FC_MAX;
1241     }
1242 
1243     return nRet;
1244 }
1245 
CurrentPieceFc2Cp(WW8_CP & rStartPos,WW8_CP & rEndPos,const WW8ScannerBase * pSBase)1246 void WW8PLCFx_PCD::CurrentPieceFc2Cp( WW8_CP& rStartPos, WW8_CP& rEndPos,
1247     const WW8ScannerBase *pSBase )
1248 {
1249     //No point going anywhere with this
1250     if ((rStartPos == WW8_CP_MAX) && (rEndPos == WW8_CP_MAX))
1251         return;
1252 
1253     rStartPos = pSBase->WW8Fc2Cp( rStartPos );
1254     rEndPos = pSBase->WW8Fc2Cp( rEndPos );
1255 }
1256 
CurrentPieceStartFc2Cp(WW8_FC nStartPos)1257 WW8_CP WW8PLCFx_PCD::CurrentPieceStartFc2Cp( WW8_FC nStartPos )
1258 {
1259     WW8_CP nCpStart, nCpEnd;
1260     void* pData;
1261     if ( !m_pPcdI->Get( nCpStart, nCpEnd, pData ) )
1262     {
1263         OSL_ENSURE( false, "CurrentPieceStartFc2Cp() - error" );
1264         return WW8_CP_MAX;
1265     }
1266     bool bIsUnicode = false;
1267     sal_Int32 nFcStart  = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
1268     if( !m_bVer67 )
1269         nFcStart = WW8PLCFx_PCD::TransformPieceAddress( nFcStart, bIsUnicode );
1270 
1271     sal_Int32 nUnicodeFactor = bIsUnicode ? 2 : 1;
1272 
1273     if( nStartPos < nFcStart )
1274         nStartPos = nFcStart;
1275 
1276     WW8_CP nCpLen;
1277     bool bFail = o3tl::checked_sub(nCpEnd, nCpStart, nCpLen);
1278     if (bFail)
1279     {
1280         SAL_WARN("sw.ww8", "broken offset, ignoring");
1281         return WW8_CP_MAX;
1282     }
1283 
1284     WW8_CP nCpLenBytes;
1285     bFail = o3tl::checked_multiply(nCpLen, nUnicodeFactor, nCpLenBytes);
1286     if (bFail)
1287     {
1288         SAL_WARN("sw.ww8", "broken offset, ignoring");
1289         return WW8_CP_MAX;
1290     }
1291 
1292     WW8_FC nFcLen;
1293     bFail = o3tl::checked_add(nFcStart, nCpLenBytes, nFcLen);
1294     if (bFail)
1295     {
1296         SAL_WARN("sw.ww8", "broken offset, ignoring");
1297         return WW8_CP_MAX;
1298     }
1299 
1300     WW8_FC nFcEnd;
1301     bFail = o3tl::checked_add(nFcStart, nFcLen, nFcEnd);
1302     if (bFail)
1303     {
1304         SAL_WARN("sw.ww8", "broken offset, ignoring");
1305         return WW8_CP_MAX;
1306     }
1307 
1308 
1309     if (nStartPos >= nFcEnd)
1310         nStartPos = nFcEnd - (1 * nUnicodeFactor);
1311 
1312     WW8_FC nFcDiff = (nStartPos - nFcStart) / nUnicodeFactor;
1313 
1314     WW8_FC nCpRet;
1315     bFail = o3tl::checked_add(nCpStart, nFcDiff, nCpRet);
1316     if (bFail)
1317     {
1318         SAL_WARN("sw.ww8", "broken offset, ignoring");
1319         return WW8_CP_MAX;
1320     }
1321 
1322     return nCpRet;
1323 }
1324 
1325 //      Helper routines for all
1326 
1327 // Convert BRC from WW6 to WW8 format
WW8_BRC(const WW8_BRCVer6 & brcVer6)1328 WW8_BRC::WW8_BRC(const WW8_BRCVer6& brcVer6)
1329 {
1330     sal_uInt8 _dptLineWidth = brcVer6.dxpLineWidth(),
1331               _brcType = brcVer6.brcType();
1332 
1333     if (_dptLineWidth > 5) // this signifies dashed(6) or dotted(7) line
1334     {
1335         _brcType = _dptLineWidth;
1336         _dptLineWidth = 1;
1337     }
1338     _dptLineWidth *= 6; // convert units from 0.75pt to 1/8pt
1339 
1340     *this = WW8_BRC(_dptLineWidth, _brcType, brcVer6.ico(), brcVer6.dxpSpace(),
1341         brcVer6.fShadow(), false);
1342 }
1343 
1344 // Convert BRC from WW8 to WW9 format
WW8_BRCVer9(const WW8_BRC & brcVer8)1345 WW8_BRCVer9::WW8_BRCVer9(const WW8_BRC& brcVer8)
1346 {
1347     if (brcVer8.isNil()) {
1348         UInt32ToSVBT32(0, aBits1);
1349         UInt32ToSVBT32(0xffffffff, aBits2);
1350     }
1351     else
1352     {
1353         sal_uInt32 _cv = brcVer8.ico() == 0 ? 0xff000000 // "auto" colour
1354             : wwUtility::RGBToBGR(SwWW8ImplReader::GetCol(brcVer8.ico()));
1355         *this = WW8_BRCVer9(_cv, brcVer8.dptLineWidth(), brcVer8.brcType(),
1356             brcVer8.dptSpace(), brcVer8.fShadow(), brcVer8.fFrame());
1357     }
1358 }
1359 
DetermineBorderProperties(short * pSpace) const1360 short WW8_BRC::DetermineBorderProperties(short *pSpace) const
1361 {
1362     WW8_BRCVer9 brcVer9(*this);
1363     return brcVer9.DetermineBorderProperties(pSpace);
1364 }
1365 
DetermineBorderProperties(short * pSpace) const1366 short WW8_BRCVer9::DetermineBorderProperties(short *pSpace) const
1367 {
1368     /*
1369         Word does not factor the width of the border into the width/height
1370         stored in the information for graphic/table/object widths, so we need
1371         to figure out this extra width here and utilize the returned size in
1372         our calculations
1373     */
1374     short nMSTotalWidth;
1375 
1376     //Specification in 8ths of a point, 1 Point = 20 Twips, so by 2.5
1377     nMSTotalWidth  = static_cast<short>(dptLineWidth()) * 20 / 8;
1378 
1379     //Figure out the real size of the border according to word
1380     switch (brcType())
1381     {
1382         //Note that codes over 25 are undocumented, and I can't create
1383         //these 4 here in the wild.
1384         case 2:
1385         case 4:
1386         case 5:
1387         case 22:
1388             OSL_FAIL("Can't create these from the menus, please report");
1389             break;
1390         default:
1391         case 23:    //Only 3pt in the menus, but honours the size setting.
1392             break;
1393         case 10:
1394             /*
1395             triple line is five times the width of an ordinary line,
1396             except that the smallest 1/4 point size appears to have
1397             exactly the same total border width as a 3/4 point size
1398             ordinary line, i.e. three times the nominal line width.  The
1399             second smallest 1/2 point size appears to have exactly the
1400             total border width as a 2 1/4 border, i.e 4.5 times the size.
1401             */
1402             if (nMSTotalWidth == 5)
1403                 nMSTotalWidth*=3;
1404             else if (nMSTotalWidth == 10)
1405                 nMSTotalWidth = nMSTotalWidth*9/2;
1406             else
1407                 nMSTotalWidth*=5;
1408             break;
1409         case 20:
1410             /*
1411             wave, the dimensions appear to be created by the drawing of
1412             the wave, so we have only two possibilities in the menus, 3/4
1413             point is equal to solid 3 point. This calculation seems to
1414             match well to results.
1415             */
1416             nMSTotalWidth +=45;
1417             break;
1418         case 21:
1419             /*
1420             double wave, the dimensions appear to be created by the
1421             drawing of the wave, so we have only one possibilities in the
1422             menus, that of 3/4 point is equal to solid 3 point. This
1423             calculation seems to match well to results.
1424             */
1425             nMSTotalWidth += 45*2;
1426             break;
1427     }
1428 
1429     if (pSpace)
1430         *pSpace = static_cast<short>(dptSpace()) * 20; // convert from points to twips
1431     return nMSTotalWidth;
1432 }
1433 
1434 /*
1435  * WW8Cp2Fc is a good method, a CP always maps to a FC
1436  * WW8Fc2Cp on the other hand is more dubious, a random FC
1437  * may not map to a valid CP. Try and avoid WW8Fc2Cp where
1438  * possible
1439  */
WW8Fc2Cp(WW8_FC nFcPos) const1440 WW8_CP WW8ScannerBase::WW8Fc2Cp( WW8_FC nFcPos ) const
1441 {
1442     WW8_CP nFallBackCpEnd = WW8_CP_MAX;
1443     if( nFcPos == WW8_FC_MAX )
1444         return nFallBackCpEnd;
1445 
1446     bool bIsUnicode;
1447     if (m_pWw8Fib->m_nVersion >= 8)
1448         bIsUnicode = false;
1449     else
1450         bIsUnicode = m_pWw8Fib->m_fExtChar;
1451 
1452     if( m_pPieceIter )    // Complex File ?
1453     {
1454         sal_uInt32 nOldPos = m_pPieceIter->GetIdx();
1455 
1456         for (m_pPieceIter->SetIdx(0);
1457             m_pPieceIter->GetIdx() < m_pPieceIter->GetIMax(); m_pPieceIter->advance())
1458         {
1459             WW8_CP nCpStart, nCpEnd;
1460             void* pData;
1461             if( !m_pPieceIter->Get( nCpStart, nCpEnd, pData ) )
1462             {   // outside PLCFfpcd ?
1463                 OSL_ENSURE( false, "PLCFpcd-WW8Fc2Cp() went wrong" );
1464                 break;
1465             }
1466             sal_Int32 nFcStart  = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
1467             if (m_pWw8Fib->m_nVersion >= 8)
1468             {
1469                 nFcStart = WW8PLCFx_PCD::TransformPieceAddress( nFcStart,
1470                                                                 bIsUnicode );
1471             }
1472             else
1473             {
1474                 bIsUnicode = m_pWw8Fib->m_fExtChar;
1475             }
1476 
1477             sal_Int32 nLen;
1478             if (o3tl::checked_sub(nCpEnd, nCpStart, nLen))
1479             {
1480                 SAL_WARN("sw.ww8", "broken offset, ignoring");
1481                 return WW8_CP_MAX;
1482             }
1483             if (bIsUnicode)
1484             {
1485                 if (o3tl::checked_multiply<WW8_CP>(nLen, 2, nLen))
1486                 {
1487                     SAL_WARN("sw.ww8", "broken offset, ignoring");
1488                     return WW8_CP_MAX;
1489                 }
1490             }
1491 
1492             /*
1493             If this cp is inside this piece, or it's the last piece and we are
1494             on the very last cp of that piece
1495             */
1496             if (nFcPos >= nFcStart)
1497             {
1498                 // found
1499                 WW8_FC nFcDiff;
1500                 if (o3tl::checked_sub(nFcPos, nFcStart, nFcDiff))
1501                 {
1502                     SAL_WARN("sw.ww8", "broken offset, ignoring");
1503                     return WW8_CP_MAX;
1504                 }
1505                 if (bIsUnicode)
1506                     nFcDiff /= 2;
1507                 WW8_CP nTempCp;
1508                 if (o3tl::checked_add(nCpStart, nFcDiff, nTempCp))
1509                 {
1510                     SAL_WARN("sw.ww8", "broken offset, ignoring");
1511                     return WW8_CP_MAX;
1512                 }
1513                 WW8_FC nFcEnd;
1514                 if (o3tl::checked_add(nFcStart, nLen, nFcEnd))
1515                 {
1516                     SAL_WARN("sw.ww8", "broken offset, ignoring");
1517                     return WW8_CP_MAX;
1518                 }
1519                 if (nFcPos < nFcEnd)
1520                 {
1521                     m_pPieceIter->SetIdx( nOldPos );
1522                     return nTempCp;
1523                 }
1524                 else if (nFcPos == nFcEnd)
1525                 {
1526                     //Keep this cp as its on a piece boundary because we might
1527                     //need it if tests fail
1528                     nFallBackCpEnd = nTempCp;
1529                 }
1530             }
1531         }
1532         // not found
1533         m_pPieceIter->SetIdx( nOldPos );      // not found
1534         /*
1535         If it was not found, then this is because it has fallen between two
1536         stools, i.e. either it is the last cp/fc of the last piece, or it is
1537         the last cp/fc of a disjoint piece.
1538         */
1539         return nFallBackCpEnd;
1540     }
1541 
1542     WW8_FC nFcDiff;
1543     if (o3tl::checked_sub(nFcPos, m_pWw8Fib->m_fcMin, nFcDiff))
1544     {
1545         SAL_WARN("sw.ww8", "broken offset, ignoring");
1546         return WW8_CP_MAX;
1547     }
1548 
1549     // No complex file
1550     if (!bIsUnicode)
1551         nFallBackCpEnd = nFcDiff;
1552     else
1553         nFallBackCpEnd = (nFcDiff + 1) / 2;
1554 
1555     return nFallBackCpEnd;
1556 }
1557 
1558 // the fib of WinWord2 has a last entry of cpnBtePap of 2 byte sized type PN at
1559 // offset 324
1560 const int nSmallestPossibleFib = 326;
1561 
WW8Cp2Fc(WW8_CP nCpPos,bool * pIsUnicode,WW8_CP * pNextPieceCp,bool * pTestFlag) const1562 WW8_FC WW8ScannerBase::WW8Cp2Fc(WW8_CP nCpPos, bool* pIsUnicode,
1563     WW8_CP* pNextPieceCp, bool* pTestFlag) const
1564 {
1565     if( pTestFlag )
1566         *pTestFlag = true;
1567     if( WW8_CP_MAX == nCpPos )
1568         return WW8_CP_MAX;
1569 
1570     bool bIsUnicode;
1571     if( !pIsUnicode )
1572         pIsUnicode = &bIsUnicode;
1573 
1574     if (m_pWw8Fib->m_nVersion >= 8)
1575         *pIsUnicode = false;
1576     else
1577         *pIsUnicode = m_pWw8Fib->m_fExtChar;
1578 
1579     WW8_FC nRet;
1580 
1581     if( m_pPieceIter )
1582     {
1583         // Complex File
1584         if( pNextPieceCp )
1585             *pNextPieceCp = WW8_CP_MAX;
1586 
1587         if( !m_pPieceIter->SeekPos( nCpPos ) )
1588         {
1589             if( pTestFlag )
1590                 *pTestFlag = false;
1591             else {
1592                 OSL_ENSURE( false, "Handed over wrong CP to WW8Cp2Fc()" );
1593             }
1594             return WW8_FC_MAX;
1595         }
1596         WW8_CP nCpStart, nCpEnd;
1597         void* pData;
1598         if( !m_pPieceIter->Get( nCpStart, nCpEnd, pData ) )
1599         {
1600             if( pTestFlag )
1601                 *pTestFlag = false;
1602             else {
1603                 OSL_ENSURE( false, "PLCFfpcd-Get went wrong" );
1604             }
1605             return WW8_FC_MAX;
1606         }
1607         if( pNextPieceCp )
1608             *pNextPieceCp = nCpEnd;
1609 
1610         nRet = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
1611         if (m_pWw8Fib->m_nVersion >= 8)
1612             nRet = WW8PLCFx_PCD::TransformPieceAddress( nRet, *pIsUnicode );
1613         else
1614             *pIsUnicode = m_pWw8Fib->m_fExtChar;
1615 
1616         WW8_CP nCpLen;
1617         bool bFail = o3tl::checked_sub(nCpPos, nCpStart, nCpLen);
1618         if (bFail)
1619         {
1620             SAL_WARN("sw.ww8", "broken offset, ignoring");
1621             return WW8_CP_MAX;
1622         }
1623 
1624         if (*pIsUnicode)
1625         {
1626             bFail = o3tl::checked_multiply<WW8_CP>(nCpLen, 2, nCpLen);
1627             if (bFail)
1628             {
1629                 SAL_WARN("sw.ww8", "broken offset, ignoring");
1630                 return WW8_CP_MAX;
1631             }
1632         }
1633 
1634         bFail = o3tl::checked_add(nRet, nCpLen, nRet);
1635         if (bFail)
1636         {
1637             SAL_WARN("sw.ww8", "broken offset, ignoring");
1638             return WW8_CP_MAX;
1639         }
1640 
1641         return nRet;
1642     }
1643 
1644     if (*pIsUnicode)
1645     {
1646         const bool bFail = o3tl::checked_multiply<WW8_CP>(nCpPos, 2, nCpPos);
1647         if (bFail)
1648         {
1649             SAL_WARN("sw.ww8", "broken offset, ignoring");
1650             return WW8_CP_MAX;
1651         }
1652     }
1653 
1654     // No complex file
1655     const bool bFail = o3tl::checked_add(m_pWw8Fib->m_fcMin, nCpPos, nRet);
1656     if (bFail)
1657     {
1658         SAL_WARN("sw.ww8", "broken offset, ignoring");
1659         return WW8_CP_MAX;
1660     }
1661 
1662     // the text and the fib share the same stream, if the text is inside the fib
1663     // then it's definitely a bad offset. The smallest FIB supported is that of
1664     // WW2 which is 326 bytes in size
1665     if (nRet < nSmallestPossibleFib)
1666     {
1667         SAL_WARN("sw.ww8", "broken offset, ignoring");
1668         return WW8_CP_MAX;
1669     }
1670 
1671     return nRet;
1672 }
1673 
OpenPieceTable(SvStream * pStr,const WW8Fib * pWwF)1674 std::unique_ptr<WW8PLCFpcd> WW8ScannerBase::OpenPieceTable( SvStream* pStr, const WW8Fib* pWwF )
1675 {
1676     if ( ((8 > m_pWw8Fib->m_nVersion) && !pWwF->m_fComplex) || !pWwF->m_lcbClx )
1677         return nullptr;
1678 
1679     if (pWwF->m_lcbClx < 0)
1680         return nullptr;
1681 
1682     WW8_FC nClxPos = pWwF->m_fcClx;
1683 
1684     if (!checkSeek(*pStr, nClxPos))
1685         return nullptr;
1686 
1687     sal_Int32 nClxLen = pWwF->m_lcbClx;
1688     sal_Int32 nLeft = nClxLen;
1689 
1690     while (true)
1691     {
1692         sal_uInt8 clxt(2);
1693         pStr->ReadUChar( clxt );
1694         nLeft--;
1695         if( 2 == clxt)                          // PLCFfpcd ?
1696             break;                              // PLCFfpcd found
1697         sal_uInt16 nLen(0);
1698         pStr->ReadUInt16( nLen );
1699         nLeft -= 2 + nLen;
1700         if( nLeft < 0 )
1701             return nullptr;                        // gone wrong
1702         if( 1 == clxt )                         // clxtGrpprl ?
1703         {
1704             if (m_aPieceGrpprls.size() == SHRT_MAX)
1705                 return nullptr;
1706             if (nLen > pStr->remainingSize())
1707                 return nullptr;
1708             std::unique_ptr<sal_uInt8[]> p(new sal_uInt8[nLen+2]);         // allocate
1709             ShortToSVBT16(nLen, p.get());             // add length
1710             if (!checkRead(*pStr, p.get()+2, nLen))   // read grpprl
1711             {
1712                 return nullptr;
1713             }
1714             m_aPieceGrpprls.push_back(std::move(p));    // add to array
1715         }
1716         else
1717         {
1718             nLen = std::min<sal_uInt64>(nLen, pStr->remainingSize());
1719             pStr->Seek(pStr->Tell() + nLen);         // non-Grpprl left
1720         }
1721     }
1722 
1723     // read Piece Table PLCF
1724     sal_Int32 nPLCFfLen(0);
1725     if (pWwF->GetFIBVersion() <= ww::eWW2)
1726     {
1727         sal_Int16 nWordTwoLen(0);
1728         pStr->ReadInt16( nWordTwoLen );
1729         nPLCFfLen = nWordTwoLen;
1730     }
1731     else
1732         pStr->ReadInt32( nPLCFfLen );
1733     OSL_ENSURE( 65536 > nPLCFfLen, "PLCFfpcd above 64 k" );
1734     return std::make_unique<WW8PLCFpcd>( pStr, pStr->Tell(), nPLCFfLen, 8 );
1735 }
1736 
WW8ScannerBase(SvStream * pSt,SvStream * pTableSt,SvStream * pDataSt,WW8Fib * pWwFib)1737 WW8ScannerBase::WW8ScannerBase( SvStream* pSt, SvStream* pTableSt,
1738     SvStream* pDataSt, WW8Fib* pWwFib )
1739     : m_pWw8Fib(pWwFib)
1740 {
1741     m_pPiecePLCF = OpenPieceTable( pTableSt, m_pWw8Fib );             // Complex
1742     if( m_pPiecePLCF )
1743     {
1744         m_pPieceIter.reset(new WW8PLCFpcd_Iter( *m_pPiecePLCF ));
1745         m_pPLCFx_PCD.reset( new WW8PLCFx_PCD(*pWwFib, m_pPiecePLCF.get(), 0,
1746             IsSevenMinus(m_pWw8Fib->GetFIBVersion())));
1747         m_pPLCFx_PCDAttrs.reset(new WW8PLCFx_PCDAttrs(*pWwFib,
1748             m_pPLCFx_PCD.get(), this));
1749     }
1750     else
1751     {
1752         m_pPieceIter = nullptr;
1753         m_pPLCFx_PCD = nullptr;
1754         m_pPLCFx_PCDAttrs = nullptr;
1755     }
1756 
1757     // pChpPLCF and pPapPLCF may NOT be created before pPLCFx_PCD !!
1758     m_pChpPLCF.reset(new WW8PLCFx_Cp_FKP( pSt, pTableSt, pDataSt, *this, CHP )); // CHPX
1759     m_pPapPLCF.reset(new WW8PLCFx_Cp_FKP( pSt, pTableSt, pDataSt, *this, PAP )); // PAPX
1760 
1761     m_pSepPLCF.reset(new WW8PLCFx_SEPX(   pSt, pTableSt, *pWwFib, 0 ));          // SEPX
1762 
1763     // Footnotes
1764     m_pFootnotePLCF.reset(new WW8PLCFx_SubDoc( pTableSt, *pWwFib, 0,
1765         pWwFib->m_fcPlcffndRef, pWwFib->m_lcbPlcffndRef, pWwFib->m_fcPlcffndText,
1766         pWwFib->m_lcbPlcffndText, 2 ));
1767     // Endnotes
1768     m_pEdnPLCF.reset(new WW8PLCFx_SubDoc( pTableSt, *pWwFib, 0,
1769         pWwFib->m_fcPlcfendRef, pWwFib->m_lcbPlcfendRef, pWwFib->m_fcPlcfendText,
1770         pWwFib->m_lcbPlcfendText, 2 ));
1771     // Comments
1772     m_pAndPLCF.reset(new WW8PLCFx_SubDoc( pTableSt, *pWwFib, 0,
1773         pWwFib->m_fcPlcfandRef, pWwFib->m_lcbPlcfandRef, pWwFib->m_fcPlcfandText,
1774         pWwFib->m_lcbPlcfandText, IsSevenMinus(pWwFib->GetFIBVersion()) ? 20 : 30));
1775 
1776     // Fields Main Text
1777     m_pFieldPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_MAINTEXT));
1778     // Fields Header / Footer
1779     m_pFieldHdFtPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_HDFT));
1780     // Fields Footnote
1781     m_pFieldFootnotePLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_FTN));
1782     // Fields Endnote
1783     m_pFieldEdnPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_EDN));
1784     // Fields Comments
1785     m_pFieldAndPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_AND));
1786     // Fields in Textboxes in Main Text
1787     m_pFieldTxbxPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_TXBX));
1788     // Fields in Textboxes in Header / Footer
1789     m_pFieldTxbxHdFtPLCF.reset(new WW8PLCFx_FLD(pTableSt,*pWwFib,MAN_TXBX_HDFT));
1790 
1791     // Note: 6 stands for "6 OR 7",  7 stands for "ONLY 7"
1792     switch( m_pWw8Fib->m_nVersion )
1793     {
1794         case 6:
1795         case 7:
1796             if( pWwFib->m_fcPlcfdoaMom && pWwFib->m_lcbPlcfdoaMom )
1797             {
1798                 m_pMainFdoa.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfdoaMom,
1799                     pWwFib->m_lcbPlcfdoaMom, 6 ));
1800             }
1801             if( pWwFib->m_fcPlcfdoaHdr && pWwFib->m_lcbPlcfdoaHdr )
1802             {
1803                 m_pHdFtFdoa.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfdoaHdr,
1804                 pWwFib->m_lcbPlcfdoaHdr, 6 ));
1805             }
1806             break;
1807         case 8:
1808             if( pWwFib->m_fcPlcfspaMom && pWwFib->m_lcbPlcfspaMom )
1809             {
1810                 m_pMainFdoa.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfspaMom,
1811                     pWwFib->m_lcbPlcfspaMom, 26 ));
1812             }
1813             if( pWwFib->m_fcPlcfspaHdr && pWwFib->m_lcbPlcfspaHdr )
1814             {
1815                 m_pHdFtFdoa.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfspaHdr,
1816                     pWwFib->m_lcbPlcfspaHdr, 26 ));
1817             }
1818             // PLCF for TextBox break-descriptors in the main text
1819             if( pWwFib->m_fcPlcftxbxBkd && pWwFib->m_lcbPlcftxbxBkd )
1820             {
1821                 m_pMainTxbxBkd.reset(new WW8PLCFspecial( pTableSt,
1822                     pWwFib->m_fcPlcftxbxBkd, pWwFib->m_lcbPlcftxbxBkd, 0));
1823             }
1824             // PLCF for TextBox break-descriptors in Header/Footer range
1825             if( pWwFib->m_fcPlcfHdrtxbxBkd && pWwFib->m_lcbPlcfHdrtxbxBkd )
1826             {
1827                 m_pHdFtTxbxBkd.reset(new WW8PLCFspecial( pTableSt,
1828                     pWwFib->m_fcPlcfHdrtxbxBkd, pWwFib->m_lcbPlcfHdrtxbxBkd, 0));
1829             }
1830             // Sub table cp positions
1831             if (pWwFib->m_fcPlcfTch && pWwFib->m_lcbPlcfTch)
1832             {
1833                 m_pMagicTables.reset(new WW8PLCFspecial( pTableSt,
1834                     pWwFib->m_fcPlcfTch, pWwFib->m_lcbPlcfTch, 4));
1835             }
1836             // Sub document cp positions
1837             if (pWwFib->m_fcPlcfwkb && pWwFib->m_lcbPlcfwkb)
1838             {
1839                 m_pSubdocs.reset(new WW8PLCFspecial( pTableSt,
1840                     pWwFib->m_fcPlcfwkb, pWwFib->m_lcbPlcfwkb, 12));
1841             }
1842             // Extended ATRD
1843             if (pWwFib->m_fcAtrdExtra && pWwFib->m_lcbAtrdExtra)
1844             {
1845                 sal_uInt64 const nOldPos = pTableSt->Tell();
1846                 if (checkSeek(*pTableSt, pWwFib->m_fcAtrdExtra) && (pTableSt->remainingSize() >= pWwFib->m_lcbAtrdExtra))
1847                 {
1848                     m_pExtendedAtrds.reset( new sal_uInt8[pWwFib->m_lcbAtrdExtra] );
1849                     pWwFib->m_lcbAtrdExtra = pTableSt->ReadBytes(m_pExtendedAtrds.get(), pWwFib->m_lcbAtrdExtra);
1850                 }
1851                 else
1852                     pWwFib->m_lcbAtrdExtra = 0;
1853                 pTableSt->Seek(nOldPos);
1854             }
1855 
1856             break;
1857         default:
1858             OSL_ENSURE( false, "nVersion not implemented!" );
1859             break;
1860     }
1861 
1862     // PLCF for TextBox stories in main text
1863     sal_uInt32 nLenTxBxS = (8 > m_pWw8Fib->m_nVersion) ? 0 : 22;
1864     if( pWwFib->m_fcPlcftxbxText && pWwFib->m_lcbPlcftxbxText )
1865     {
1866         m_pMainTxbx.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcftxbxText,
1867             pWwFib->m_lcbPlcftxbxText, nLenTxBxS ));
1868     }
1869 
1870     // PLCF for TextBox stories in Header/Footer range
1871     if( pWwFib->m_fcPlcfHdrtxbxText && pWwFib->m_lcbPlcfHdrtxbxText )
1872     {
1873         m_pHdFtTxbx.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfHdrtxbxText,
1874             pWwFib->m_lcbPlcfHdrtxbxText, nLenTxBxS ));
1875     }
1876 
1877     m_pBook.reset(new WW8PLCFx_Book(pTableSt, *pWwFib));
1878     m_pAtnBook.reset(new WW8PLCFx_AtnBook(pTableSt, *pWwFib));
1879     m_pFactoidBook.reset(new WW8PLCFx_FactoidBook(pTableSt, *pWwFib));
1880 }
1881 
~WW8ScannerBase()1882 WW8ScannerBase::~WW8ScannerBase()
1883 {
1884     m_aPieceGrpprls.clear();
1885     m_pPLCFx_PCDAttrs.reset();
1886     m_pPLCFx_PCD.reset();
1887     m_pPieceIter.reset();
1888     m_pPiecePLCF.reset();
1889     m_pFactoidBook.reset();
1890     m_pAtnBook.reset();
1891     m_pBook.reset();
1892     m_pFieldEdnPLCF.reset();
1893     m_pFieldFootnotePLCF.reset();
1894     m_pFieldAndPLCF.reset();
1895     m_pFieldHdFtPLCF.reset();
1896     m_pFieldPLCF.reset();
1897     m_pFieldTxbxPLCF.reset();
1898     m_pFieldTxbxHdFtPLCF.reset();
1899     m_pEdnPLCF.reset();
1900     m_pFootnotePLCF.reset();
1901     m_pAndPLCF.reset();
1902     m_pSepPLCF.reset();
1903     m_pPapPLCF.reset();
1904     m_pChpPLCF.reset();
1905     m_pMainFdoa.reset();
1906     m_pHdFtFdoa.reset();
1907     m_pMainTxbx.reset();
1908     m_pMainTxbxBkd.reset();
1909     m_pHdFtTxbx.reset();
1910     m_pHdFtTxbxBkd.reset();
1911     m_pMagicTables.reset();
1912     m_pSubdocs.reset();
1913 }
1914 
1915 // Fields
1916 
WW8SkipField(WW8PLCFspecial & rPLCF)1917 static bool WW8SkipField(WW8PLCFspecial& rPLCF)
1918 {
1919     void* pData;
1920     WW8_CP nP;
1921 
1922     if (!rPLCF.Get(nP, pData))              // End of PLCFspecial?
1923         return false;
1924 
1925     rPLCF.advance();
1926 
1927     if((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) != 0x13 )    // No beginning?
1928         return true;                            // Do not terminate on error
1929 
1930     if( !rPLCF.Get( nP, pData ) )
1931         return false;
1932 
1933     while((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x13 )
1934     {
1935         // still new (nested) beginnings ?
1936         WW8SkipField( rPLCF );              // nested Field in description
1937         if( !rPLCF.Get( nP, pData ) )
1938             return false;
1939     }
1940 
1941     if((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x14 )
1942     {
1943 
1944         // Field Separator ?
1945         rPLCF.advance();
1946 
1947         if( !rPLCF.Get( nP, pData ) )
1948             return false;
1949 
1950         while ((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x13)
1951         {
1952             // still new (nested) beginnings?
1953             WW8SkipField( rPLCF );          // nested Field in Results
1954             if( !rPLCF.Get( nP, pData ) )
1955                 return false;
1956         }
1957     }
1958     rPLCF.advance();
1959 
1960     return true;
1961 }
1962 
WW8GetFieldPara(WW8PLCFspecial & rPLCF,WW8FieldDesc & rF)1963 static bool WW8GetFieldPara(WW8PLCFspecial& rPLCF, WW8FieldDesc& rF)
1964 {
1965     void* pData;
1966     sal_uInt32 nOldIdx = rPLCF.GetIdx();
1967 
1968     rF.nLen = rF.nId = rF.nOpt = 0;
1969     rF.bCodeNest = rF.bResNest = false;
1970 
1971     if (!rPLCF.Get(rF.nSCode, pData) || rF.nSCode < 0)             // end of PLCFspecial?
1972         goto Err;
1973 
1974     rPLCF.advance();
1975 
1976     if (!pData || (static_cast<sal_uInt8*>(pData)[0] & 0x1f) != 0x13)        // No beginning?
1977         goto Err;
1978 
1979     rF.nId = static_cast<sal_uInt8*>(pData)[1];
1980 
1981     if( !rPLCF.Get( rF.nLCode, pData ) )
1982         goto Err;
1983 
1984     if (rF.nLCode < rF.nSCode)
1985         goto Err;
1986 
1987     rF.nSRes = rF.nLCode;                           // Default
1988     rF.nSCode++;                                    // without markers
1989     rF.nLCode -= rF.nSCode;                         // Pos -> length
1990 
1991     while((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x13 )
1992     {
1993         // still new (nested) beginnings ?
1994         WW8SkipField( rPLCF );              // nested Field in description
1995         rF.bCodeNest = true;
1996         if (!rPLCF.Get(rF.nSRes, pData) || rF.nSRes < 0)
1997             goto Err;
1998     }
1999 
2000     if ((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x14 )       // Field Separator?
2001     {
2002         rPLCF.advance();
2003 
2004         if (!rPLCF.Get(rF.nLRes, pData) || rF.nLRes < 0)
2005             goto Err;
2006 
2007         while((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x13 )
2008         {
2009             // still new (nested) beginnings ?
2010             WW8SkipField( rPLCF );              // nested Field in results
2011             rF.bResNest = true;
2012             if (!rPLCF.Get(rF.nLRes, pData) || rF.nLRes < 0)
2013                 goto Err;
2014         }
2015         WW8_CP nTmp;
2016         if (o3tl::checked_sub<WW8_CP>(rF.nLRes, rF.nSCode, nTmp))
2017         {
2018             rF.nLen = 0;
2019             goto Err;
2020         }
2021         if (o3tl::checked_add<WW8_CP>(nTmp, 2, rF.nLen)) // nLRes is still the final position
2022         {
2023             rF.nLen = 0;
2024             goto Err;
2025         }
2026         rF.nLRes -= rF.nSRes;                       // now: nLRes = length
2027         if (o3tl::checked_add<WW8_CP>(rF.nSRes, 1, rF.nSRes)) // Endpos including Markers
2028         {
2029             rF.nLen = 0;
2030             goto Err;
2031         }
2032         rF.nLRes--;
2033     }else{
2034         rF.nLRes = 0;                               // no result found
2035         WW8_CP nTmp;
2036         if (o3tl::checked_sub<WW8_CP>(rF.nSRes, rF.nSCode, nTmp))
2037         {
2038             rF.nLen = 0;
2039             goto Err;
2040         }
2041         if (o3tl::checked_add<WW8_CP>(nTmp, 2, rF.nLen)) // total length
2042         {
2043             rF.nLen = 0;
2044             goto Err;
2045         }
2046     }
2047 
2048     if (rF.nLen < 0)
2049     {
2050         rF.nLen = 0;
2051         goto Err;
2052     }
2053 
2054     rPLCF.advance();
2055     if((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x15 )
2056     {
2057         // Field end ?
2058         // INDEX-Field has set Bit7?
2059         rF.nOpt = static_cast<sal_uInt8*>(pData)[1];                // yes -> copy flags
2060     }else{
2061         rF.nId = 0;                                      // no -> Field invalid
2062     }
2063 
2064     rPLCF.SetIdx( nOldIdx );
2065     return true;
2066 Err:
2067     rPLCF.SetIdx( nOldIdx );
2068     return false;
2069 }
2070 
read_uInt8_BeltAndBracesString(SvStream & rStrm,rtl_TextEncoding eEnc)2071 OUString read_uInt8_BeltAndBracesString(SvStream& rStrm, rtl_TextEncoding eEnc)
2072 {
2073     const OUString aRet = read_uInt8_lenPrefixed_uInt8s_ToOUString(rStrm, eEnc);
2074     rStrm.SeekRel(sizeof(sal_uInt8)); // skip null-byte at end
2075     return aRet;
2076 }
2077 
read_uInt16_BeltAndBracesString(SvStream & rStrm)2078 OUString read_uInt16_BeltAndBracesString(SvStream& rStrm)
2079 {
2080     const OUString aRet = read_uInt16_PascalString(rStrm);
2081     rStrm.SeekRel(sizeof(sal_Unicode)); // skip null-byte at end
2082     return aRet;
2083 }
2084 
WW8ReadString(SvStream & rStrm,OUString & rStr,WW8_CP nCurrentStartCp,tools::Long nTotalLen,rtl_TextEncoding eEnc) const2085 sal_Int32 WW8ScannerBase::WW8ReadString( SvStream& rStrm, OUString& rStr,
2086     WW8_CP nCurrentStartCp, tools::Long nTotalLen, rtl_TextEncoding eEnc ) const
2087 {
2088     // Read in plain text, which can extend over several pieces
2089     rStr.clear();
2090 
2091     if (nCurrentStartCp < 0 || nTotalLen < 0)
2092         return 0;
2093 
2094     WW8_CP nBehindTextCp = nCurrentStartCp + nTotalLen;
2095     WW8_CP nNextPieceCp  = nBehindTextCp; // Initialization, important for Ver6
2096     tools::Long nTotalRead = 0;
2097     do
2098     {
2099         bool bIsUnicode(false), bPosOk(false);
2100         WW8_FC fcAct = WW8Cp2Fc(nCurrentStartCp,&bIsUnicode,&nNextPieceCp,&bPosOk);
2101 
2102         // Probably aimed beyond file end, doesn't matter!
2103         if( !bPosOk )
2104             break;
2105 
2106         bool bValid = checkSeek(rStrm, fcAct);
2107         if (!bValid)
2108             break;
2109 
2110         WW8_CP nEnd = (nNextPieceCp < nBehindTextCp) ? nNextPieceCp
2111             : nBehindTextCp;
2112         WW8_CP nLen;
2113         const bool bFail = o3tl::checked_sub(nEnd, nCurrentStartCp, nLen);
2114         if (bFail)
2115             break;
2116 
2117         if( 0 >= nLen )
2118             break;
2119 
2120         rStr += bIsUnicode
2121              ? read_uInt16s_ToOUString(rStrm, nLen)
2122              : read_uInt8s_ToOUString(rStrm, nLen, eEnc);
2123 
2124         nTotalRead  += nLen;
2125         nCurrentStartCp += nLen;
2126         if ( nTotalRead != rStr.getLength() )
2127             break;
2128     }
2129     while( nTotalRead < nTotalLen );
2130 
2131     return rStr.getLength();
2132 }
2133 
WW8PLCFspecial(SvStream * pSt,sal_uInt32 nFilePos,sal_uInt32 nPLCF,sal_uInt32 nStruct)2134 WW8PLCFspecial::WW8PLCFspecial(SvStream* pSt, sal_uInt32 nFilePos,
2135     sal_uInt32 nPLCF, sal_uInt32 nStruct)
2136     : m_nIdx(0), m_nStru(nStruct)
2137 {
2138     const sal_uInt32 nValidMin=4;
2139 
2140     sal_uInt64 const nOldPos = pSt->Tell();
2141 
2142     bool bValid = checkSeek(*pSt, nFilePos);
2143     std::size_t nRemainingSize = pSt->remainingSize();
2144     if( nRemainingSize < nValidMin || nPLCF < nValidMin )
2145         bValid = false;
2146     nPLCF = bValid ? std::min(nRemainingSize, static_cast<std::size_t>(nPLCF)) : nValidMin;
2147 
2148     // Pointer to Pos- and Struct-array
2149     m_pPLCF_PosArray.reset( new sal_Int32[ ( nPLCF + 3 ) / 4 ] );
2150     m_pPLCF_PosArray[0] = 0;
2151 
2152     nPLCF = bValid ? pSt->ReadBytes(m_pPLCF_PosArray.get(), nPLCF) : nValidMin;
2153 
2154     nPLCF = std::max(nPLCF, nValidMin);
2155 
2156     m_nIMax = ( nPLCF - 4 ) / ( 4 + nStruct );
2157 #ifdef OSL_BIGENDIAN
2158     for( m_nIdx = 0; m_nIdx <= m_nIMax; m_nIdx++ )
2159         m_pPLCF_PosArray[m_nIdx] = OSL_SWAPDWORD( m_pPLCF_PosArray[m_nIdx] );
2160     m_nIdx = 0;
2161 #endif // OSL_BIGENDIAN
2162     if( nStruct ) // Pointer to content array
2163         m_pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&m_pPLCF_PosArray[m_nIMax + 1]);
2164     else
2165         m_pPLCF_Contents = nullptr;                         // no content
2166 
2167     pSt->Seek(nOldPos);
2168 }
2169 
2170 // WW8PLCFspecial::SeekPos() sets WW8PLCFspecial to position nPos, while also the entry is used
2171 // that begins before nPos and ends after nPos.
2172 // Suitable for normal attributes. However, the beginning of the attribute is not corrected onto
2173 // the position nPos.
SeekPos(tools::Long nP)2174 bool WW8PLCFspecial::SeekPos(tools::Long nP)
2175 {
2176     if( nP < m_pPLCF_PosArray[0] )
2177     {
2178         m_nIdx = 0;
2179         return false;   // Not found: nP less than smallest entry
2180     }
2181 
2182     // Search from beginning?
2183     if ((m_nIdx < 1) || (nP < m_pPLCF_PosArray[m_nIdx - 1]))
2184         m_nIdx = 1;
2185 
2186     tools::Long nI   = m_nIdx;
2187     tools::Long nEnd = m_nIMax;
2188 
2189     for(int n = (1==m_nIdx ? 1 : 2); n; --n )
2190     {
2191         for( ; nI <=nEnd; ++nI)
2192         {                                   // search with an index that is incremented by 1
2193             if( nP < m_pPLCF_PosArray[nI] )
2194             {                               // found position
2195                 m_nIdx = nI - 1;              // nI - 1 is the correct index
2196                 return true;                // done
2197             }
2198         }
2199         nI   = 1;
2200         nEnd = m_nIdx-1;
2201     }
2202     m_nIdx = m_nIMax;               // not found, greater than all entries
2203     return false;
2204 }
2205 
2206 // WW8PLCFspecial::SeekPosExact() like SeekPos(), but it is ensured that no attribute is cut,
2207 // i.e. the next given attribute begins at or after nPos.
2208 // Is used for fields and bookmarks.
SeekPosExact(tools::Long nP)2209 bool WW8PLCFspecial::SeekPosExact(tools::Long nP)
2210 {
2211     if( nP < m_pPLCF_PosArray[0] )
2212     {
2213         m_nIdx = 0;
2214         return false;       // Not found: nP less than smallest entry
2215     }
2216     // Search from beginning?
2217     if( nP <=m_pPLCF_PosArray[m_nIdx] )
2218         m_nIdx = 0;
2219 
2220     tools::Long nI   = m_nIdx ? m_nIdx-1 : 0;
2221     tools::Long nEnd = m_nIMax;
2222 
2223     for(int n = (0==m_nIdx ? 1 : 2); n; --n )
2224     {
2225         for( ; nI < nEnd; ++nI)
2226         {
2227             if( nP <=m_pPLCF_PosArray[nI] )
2228             {                           // found position
2229                 m_nIdx = nI;              // nI is the correct index
2230                 return true;            // done
2231             }
2232         }
2233         nI   = 0;
2234         nEnd = m_nIdx;
2235     }
2236     m_nIdx = m_nIMax;               // Not found, greater than all entries
2237     return false;
2238 }
2239 
Get(WW8_CP & rPos,void * & rpValue) const2240 bool WW8PLCFspecial::Get(WW8_CP& rPos, void*& rpValue) const
2241 {
2242     return GetData( m_nIdx, rPos, rpValue );
2243 }
2244 
GetData(tools::Long nInIdx,WW8_CP & rPos,void * & rpValue) const2245 bool WW8PLCFspecial::GetData(tools::Long nInIdx, WW8_CP& rPos, void*& rpValue) const
2246 {
2247     if ( nInIdx >= m_nIMax )
2248     {
2249         rPos = WW8_CP_MAX;
2250         return false;
2251     }
2252     rPos = m_pPLCF_PosArray[nInIdx];
2253     rpValue = m_pPLCF_Contents ? static_cast<void*>(&m_pPLCF_Contents[nInIdx * m_nStru]) : nullptr;
2254     return true;
2255 }
2256 
2257 // WW8PLCF e.g. for SEPX
2258 // Ctor for *others* than Fkps
2259 // With nStartPos < 0, the first element of PLCFs will be taken
WW8PLCF(SvStream & rSt,WW8_FC nFilePos,sal_Int32 nPLCF,int nStruct,WW8_CP nStartPos)2260 WW8PLCF::WW8PLCF(SvStream& rSt, WW8_FC nFilePos, sal_Int32 nPLCF, int nStruct,
2261     WW8_CP nStartPos) : m_nIdx(0), m_nStru(nStruct)
2262 {
2263     if (nPLCF < 0)
2264     {
2265         SAL_WARN("sw.ww8", "broken WW8PLCF, ignoring");
2266         nPLCF = 0;
2267     }
2268     else
2269         m_nIMax = (nPLCF - 4) / (4 + nStruct);
2270 
2271     ReadPLCF(rSt, nFilePos, nPLCF);
2272 
2273     if( nStartPos >= 0 )
2274         SeekPos( nStartPos );
2275 }
2276 
2277 // Ctor *only* for Fkps
2278 // The last 2 parameters are needed for PLCF.Chpx and PLCF.Papx.
2279 // If ncpN != 0, then an incomplete PLCF will be completed. This is always required for WW6 with
2280 // lack of resources and for WordPad (W95).
2281 // With nStartPos < 0, the first element of the PLCFs is taken.
WW8PLCF(SvStream & rSt,WW8_FC nFilePos,sal_Int32 nPLCF,int nStruct,WW8_CP nStartPos,sal_Int32 nPN,sal_Int32 ncpN)2282 WW8PLCF::WW8PLCF(SvStream& rSt, WW8_FC nFilePos, sal_Int32 nPLCF, int nStruct,
2283     WW8_CP nStartPos, sal_Int32 nPN, sal_Int32 ncpN): m_nIdx(0),
2284     m_nStru(nStruct)
2285 {
2286     if (nPLCF < 0)
2287     {
2288         SAL_WARN("sw.ww8", "broken WW8PLCF, ignoring");
2289         m_nIMax = SAL_MAX_INT32;
2290     }
2291     else
2292         m_nIMax = (nPLCF - 4) / (4 + nStruct);
2293 
2294     if( m_nIMax >= ncpN )
2295         ReadPLCF(rSt, nFilePos, nPLCF);
2296     else
2297         GeneratePLCF(rSt, nPN, ncpN);
2298 
2299     if( nStartPos >= 0 )
2300         SeekPos( nStartPos );
2301 }
2302 
ReadPLCF(SvStream & rSt,WW8_FC nFilePos,sal_uInt32 nPLCF)2303 void WW8PLCF::ReadPLCF(SvStream& rSt, WW8_FC nFilePos, sal_uInt32 nPLCF)
2304 {
2305     sal_uInt64 const nOldPos = rSt.Tell();
2306     bool bValid = nPLCF != 0 && checkSeek(rSt, nFilePos)
2307         && (rSt.remainingSize() >= nPLCF);
2308 
2309     if (bValid)
2310     {
2311         // Pointer to Pos-array
2312         const size_t nEntries = (nPLCF + 3) / 4;
2313         m_pPLCF_PosArray.reset(new WW8_CP[nEntries]);
2314         bValid = checkRead(rSt, m_pPLCF_PosArray.get(), nPLCF);
2315         size_t nBytesAllocated = nEntries * sizeof(WW8_CP);
2316         if (bValid && nPLCF != nBytesAllocated)
2317         {
2318             sal_uInt8* pStartBlock = reinterpret_cast<sal_uInt8*>(m_pPLCF_PosArray.get());
2319             memset(pStartBlock + nPLCF, 0, nBytesAllocated - nPLCF);
2320         }
2321     }
2322 
2323     if (bValid)
2324     {
2325 #ifdef OSL_BIGENDIAN
2326         for( m_nIdx = 0; m_nIdx <= m_nIMax; m_nIdx++ )
2327             m_pPLCF_PosArray[m_nIdx] = OSL_SWAPDWORD( m_pPLCF_PosArray[m_nIdx] );
2328         m_nIdx = 0;
2329 #endif // OSL_BIGENDIAN
2330         // Pointer to content array
2331         m_pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&m_pPLCF_PosArray[m_nIMax + 1]);
2332 
2333         TruncToSortedRange();
2334     }
2335 
2336     OSL_ENSURE(bValid, "Document has corrupt PLCF, ignoring it");
2337 
2338     if (!bValid)
2339         MakeFailedPLCF();
2340 
2341     rSt.Seek(nOldPos);
2342 }
2343 
MakeFailedPLCF()2344 void WW8PLCF::MakeFailedPLCF()
2345 {
2346     m_nIMax = 0;
2347     m_pPLCF_PosArray.reset( new WW8_CP[2] );
2348     m_pPLCF_PosArray[0] = m_pPLCF_PosArray[1] = WW8_CP_MAX;
2349     m_pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&m_pPLCF_PosArray[m_nIMax + 1]);
2350 }
2351 
2352 namespace
2353 {
TruncToSortedRange(const sal_Int32 * pPLCF_PosArray,sal_Int32 nIMax)2354     sal_Int32 TruncToSortedRange(const sal_Int32* pPLCF_PosArray, sal_Int32 nIMax)
2355     {
2356         //Docs state that: ... all Plcs ... are sorted in ascending order.
2357         //So ensure that here for broken documents.
2358         for (auto nI = 0; nI < nIMax; ++nI)
2359         {
2360             if (pPLCF_PosArray[nI] > pPLCF_PosArray[nI+1])
2361             {
2362                 SAL_WARN("sw.ww8", "Document has unsorted PLCF, truncated to sorted portion");
2363                 nIMax = nI;
2364                 break;
2365             }
2366         }
2367         return nIMax;
2368     }
2369 }
2370 
TruncToSortedRange()2371 void WW8PLCFpcd::TruncToSortedRange()
2372 {
2373     m_nIMax = ::TruncToSortedRange(m_pPLCF_PosArray.get(), m_nIMax);
2374 }
2375 
TruncToSortedRange()2376 void WW8PLCF::TruncToSortedRange()
2377 {
2378     m_nIMax = ::TruncToSortedRange(m_pPLCF_PosArray.get(), m_nIMax);
2379 }
2380 
GeneratePLCF(SvStream & rSt,sal_Int32 nPN,sal_Int32 ncpN)2381 void WW8PLCF::GeneratePLCF(SvStream& rSt, sal_Int32 nPN, sal_Int32 ncpN)
2382 {
2383     OSL_ENSURE( m_nIMax < ncpN, "Pcl.Fkp: Why is PLCF too big?" );
2384 
2385     bool failure = false;
2386     m_nIMax = ncpN;
2387 
2388     if ((m_nIMax < 1) || (m_nIMax > (WW8_CP_MAX - 4) / (4 + m_nStru)) || nPN < 0)
2389         failure = true;
2390 
2391     if (!failure)
2392     {
2393         // Check arguments to ShortToSVBT16 in loop below will all be valid:
2394         sal_Int32 nResult;
2395         failure = o3tl::checked_add(nPN, ncpN, nResult) || nResult > SAL_MAX_UINT16;
2396     }
2397 
2398     if (!failure)
2399     {
2400         size_t nSiz = (4 + m_nStru) * m_nIMax + 4;
2401         size_t nElems = ( nSiz + 3 ) / 4;
2402         m_pPLCF_PosArray.reset( new WW8_CP[ nElems ] ); // Pointer to Pos-array
2403 
2404         for (sal_Int32 i = 0; i < ncpN && !failure; ++i)
2405         {
2406             failure = true;
2407             // construct FC entries
2408             // first FC entry of each Fkp
2409             if (!checkSeek(rSt, (nPN + i) << 9))
2410                 break;
2411 
2412             WW8_CP nFc(0);
2413             rSt.ReadInt32( nFc );
2414             m_pPLCF_PosArray[i] = nFc;
2415 
2416             failure = bool(rSt.GetError());
2417         }
2418     }
2419 
2420     if (!failure)
2421     {
2422         do
2423         {
2424             failure = true;
2425 
2426             std::size_t nLastFkpPos = nPN + m_nIMax - 1;
2427             nLastFkpPos = nLastFkpPos << 9;
2428             // number of FC entries of last Fkp
2429             if (!checkSeek(rSt, nLastFkpPos + 511))
2430                 break;
2431 
2432             sal_uInt8 nb(0);
2433             rSt.ReadUChar( nb );
2434             // last FC entry of last Fkp
2435             if (!checkSeek(rSt, nLastFkpPos + nb * 4))
2436                 break;
2437 
2438             WW8_CP nFc(0);
2439             rSt.ReadInt32( nFc );
2440             m_pPLCF_PosArray[m_nIMax] = nFc;        // end of the last Fkp
2441 
2442             failure = bool(rSt.GetError());
2443         } while(false);
2444     }
2445 
2446     if (!failure)
2447     {
2448         // Pointer to content array
2449         m_pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&m_pPLCF_PosArray[m_nIMax + 1]);
2450         sal_uInt8* p = m_pPLCF_Contents;
2451 
2452         for (sal_Int32 i = 0; i < ncpN; ++i)         // construct PNs
2453         {
2454             ShortToSVBT16(o3tl::narrowing<sal_uInt16>(nPN + i), p);
2455             p += m_nStru;
2456         }
2457     }
2458 
2459     SAL_WARN_IF(failure, "sw.ww8", "Document has corrupt PLCF, ignoring it");
2460 
2461     if (failure)
2462         MakeFailedPLCF();
2463 }
2464 
SeekPos(WW8_CP nPos)2465 bool WW8PLCF::SeekPos(WW8_CP nPos)
2466 {
2467     WW8_CP nP = nPos;
2468 
2469     if( nP < m_pPLCF_PosArray[0] )
2470     {
2471         m_nIdx = 0;
2472         // not found: nPos less than smallest entry
2473         return false;
2474     }
2475 
2476     // Search from beginning?
2477     if ((m_nIdx < 1) || (nP < m_pPLCF_PosArray[m_nIdx - 1]))
2478         m_nIdx = 1;
2479 
2480     sal_Int32 nI   = m_nIdx;
2481     sal_Int32 nEnd = m_nIMax;
2482 
2483     for(int n = (1==m_nIdx ? 1 : 2); n; --n )
2484     {
2485         for( ; nI <=nEnd; ++nI)             // search with an index that is incremented by 1
2486         {
2487             if( nP < m_pPLCF_PosArray[nI] )   // found position
2488             {
2489                 m_nIdx = nI - 1;              // nI - 1 is the correct index
2490                 return true;                // done
2491             }
2492         }
2493         nI   = 1;
2494         nEnd = m_nIdx-1;
2495     }
2496 
2497     m_nIdx = m_nIMax;               // not found, greater than all entries
2498     return false;
2499 }
2500 
Get(WW8_CP & rStart,WW8_CP & rEnd,void * & rpValue) const2501 bool WW8PLCF::Get(WW8_CP& rStart, WW8_CP& rEnd, void*& rpValue) const
2502 {
2503     if ( m_nIdx >= m_nIMax )
2504     {
2505         rStart = rEnd = WW8_CP_MAX;
2506         return false;
2507     }
2508     rStart = m_pPLCF_PosArray[ m_nIdx ];
2509     rEnd   = m_pPLCF_PosArray[ m_nIdx + 1 ];
2510     rpValue = static_cast<void*>(&m_pPLCF_Contents[m_nIdx * m_nStru]);
2511     return true;
2512 }
2513 
Where() const2514 WW8_CP WW8PLCF::Where() const
2515 {
2516     if ( m_nIdx >= m_nIMax )
2517         return WW8_CP_MAX;
2518 
2519     return m_pPLCF_PosArray[m_nIdx];
2520 }
2521 
WW8PLCFpcd(SvStream * pSt,sal_uInt32 nFilePos,sal_uInt32 nPLCF,sal_uInt32 nStruct)2522 WW8PLCFpcd::WW8PLCFpcd(SvStream* pSt, sal_uInt32 nFilePos,
2523     sal_uInt32 nPLCF, sal_uInt32 nStruct)
2524     : m_nStru( nStruct )
2525 {
2526     const sal_uInt32 nValidMin=4;
2527 
2528     sal_uInt64 const nOldPos = pSt->Tell();
2529 
2530     bool bValid = checkSeek(*pSt, nFilePos);
2531     std::size_t nRemainingSize = pSt->remainingSize();
2532     if( nRemainingSize < nValidMin || nPLCF < nValidMin )
2533         bValid = false;
2534     nPLCF = bValid ? std::min(nRemainingSize, static_cast<std::size_t>(nPLCF)) : nValidMin;
2535 
2536     m_pPLCF_PosArray.reset( new WW8_CP[ ( nPLCF + 3 ) / 4 ] );    // Pointer to Pos-array
2537     m_pPLCF_PosArray[0] = 0;
2538 
2539     nPLCF = bValid ? pSt->ReadBytes(m_pPLCF_PosArray.get(), nPLCF) : nValidMin;
2540     nPLCF = std::max(nPLCF, nValidMin);
2541 
2542     m_nIMax = ( nPLCF - 4 ) / ( 4 + nStruct );
2543 #ifdef OSL_BIGENDIAN
2544     for( tools::Long nI = 0; nI <= m_nIMax; nI++ )
2545       m_pPLCF_PosArray[nI] = OSL_SWAPDWORD( m_pPLCF_PosArray[nI] );
2546 #endif // OSL_BIGENDIAN
2547 
2548     // Pointer to content array
2549     m_pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&m_pPLCF_PosArray[m_nIMax + 1]);
2550     TruncToSortedRange();
2551 
2552     pSt->Seek( nOldPos );
2553 }
2554 
2555 // If nStartPos < 0, the first element of PLCFs will be taken
WW8PLCFpcd_Iter(WW8PLCFpcd & rPLCFpcd,tools::Long nStartPos)2556 WW8PLCFpcd_Iter::WW8PLCFpcd_Iter( WW8PLCFpcd& rPLCFpcd, tools::Long nStartPos )
2557     :m_rPLCF( rPLCFpcd ), m_nIdx( 0 )
2558 {
2559     if( nStartPos >= 0 )
2560         SeekPos( nStartPos );
2561 }
2562 
SeekPos(tools::Long nPos)2563 bool WW8PLCFpcd_Iter::SeekPos(tools::Long nPos)
2564 {
2565     tools::Long nP = nPos;
2566 
2567     if( nP < m_rPLCF.m_pPLCF_PosArray[0] )
2568     {
2569         m_nIdx = 0;
2570         return false;       // not found: nPos less than smallest entry
2571     }
2572     // Search from beginning?
2573     if ((m_nIdx < 1) || (nP < m_rPLCF.m_pPLCF_PosArray[m_nIdx - 1]))
2574         m_nIdx = 1;
2575 
2576     tools::Long nI   = m_nIdx;
2577     tools::Long nEnd = m_rPLCF.m_nIMax;
2578 
2579     for(int n = (1==m_nIdx ? 1 : 2); n; --n )
2580     {
2581         for( ; nI <=nEnd; ++nI)
2582         {                               // search with an index that is incremented by 1
2583             if( nP < m_rPLCF.m_pPLCF_PosArray[nI] )
2584             {                           // found position
2585                 m_nIdx = nI - 1;          // nI - 1 is the correct index
2586                 return true;            // done
2587             }
2588         }
2589         nI   = 1;
2590         nEnd = m_nIdx-1;
2591     }
2592     m_nIdx = m_rPLCF.m_nIMax;         // not found, greater than all entries
2593     return false;
2594 }
2595 
Get(WW8_CP & rStart,WW8_CP & rEnd,void * & rpValue) const2596 bool WW8PLCFpcd_Iter::Get(WW8_CP& rStart, WW8_CP& rEnd, void*& rpValue) const
2597 {
2598     if( m_nIdx >= m_rPLCF.m_nIMax )
2599     {
2600         rStart = rEnd = WW8_CP_MAX;
2601         return false;
2602     }
2603     rStart = m_rPLCF.m_pPLCF_PosArray[m_nIdx];
2604     rEnd = m_rPLCF.m_pPLCF_PosArray[m_nIdx + 1];
2605     rpValue = static_cast<void*>(&m_rPLCF.m_pPLCF_Contents[m_nIdx * m_rPLCF.m_nStru]);
2606     return true;
2607 }
2608 
Where() const2609 sal_Int32 WW8PLCFpcd_Iter::Where() const
2610 {
2611     if ( m_nIdx >= m_rPLCF.m_nIMax )
2612         return SAL_MAX_INT32;
2613 
2614     return m_rPLCF.m_pPLCF_PosArray[m_nIdx];
2615 }
2616 
operator <(const WW8PLCFx_Fc_FKP::WW8Fkp::Entry & rSecond) const2617 bool WW8PLCFx_Fc_FKP::WW8Fkp::Entry::operator<
2618     (const WW8PLCFx_Fc_FKP::WW8Fkp::Entry& rSecond) const
2619 {
2620     return (mnFC < rSecond.mnFC);
2621 }
2622 
IsReplaceAllSprm(sal_uInt16 nSpId)2623 static bool IsReplaceAllSprm(sal_uInt16 nSpId)
2624 {
2625     return (NS_sprm::LN_PHugePapx == nSpId || 0x6646 == nSpId);
2626 }
2627 
IsExpandableSprm(sal_uInt16 nSpId)2628 static bool IsExpandableSprm(sal_uInt16 nSpId)
2629 {
2630     return 0x646B == nSpId;
2631 }
2632 
FillEntry(WW8PLCFx_Fc_FKP::WW8Fkp::Entry & rEntry,std::size_t nDataOffset,sal_uInt16 nLen)2633 void WW8PLCFx_Fc_FKP::WW8Fkp::FillEntry(WW8PLCFx_Fc_FKP::WW8Fkp::Entry &rEntry,
2634     std::size_t nDataOffset, sal_uInt16 nLen)
2635 {
2636     bool bValidPos = (nDataOffset < sizeof(maRawData));
2637 
2638     OSL_ENSURE(bValidPos, "sprm sequence offset is out of range, ignoring");
2639 
2640     if (!bValidPos)
2641     {
2642         rEntry.mnLen = 0;
2643         return;
2644     }
2645 
2646     const sal_uInt16 nAvailableData = sizeof(maRawData)-nDataOffset;
2647     OSL_ENSURE(nLen <= nAvailableData, "sprm sequence len is out of range, clipping");
2648     rEntry.mnLen = std::min(nLen, nAvailableData);
2649     rEntry.mpData = maRawData + nDataOffset;
2650 }
2651 
WW8Fkp(const WW8Fib & rFib,SvStream * pSt,SvStream * pDataSt,tools::Long _nFilePos,tools::Long nItemSiz,ePLCFT ePl,WW8_FC nStartFc)2652 WW8PLCFx_Fc_FKP::WW8Fkp::WW8Fkp(const WW8Fib& rFib, SvStream* pSt,
2653     SvStream* pDataSt, tools::Long _nFilePos, tools::Long nItemSiz, ePLCFT ePl,
2654     WW8_FC nStartFc)
2655     : m_nItemSize(nItemSiz), m_nFilePos(_nFilePos), mnIdx(0), m_ePLCF(ePl)
2656     , mnMustRemainCached(0), maSprmParser(rFib)
2657 {
2658     memset(maRawData, 0, 512);
2659 
2660     const ww::WordVersion eVersion = rFib.GetFIBVersion();
2661 
2662     sal_uInt64 const nOldPos = pSt->Tell();
2663 
2664     bool bCouldSeek = checkSeek(*pSt, m_nFilePos);
2665     bool bCouldRead = bCouldSeek && checkRead(*pSt, maRawData, 512);
2666 
2667     mnIMax = bCouldRead ? maRawData[511] : 0;
2668 
2669     sal_uInt8 *pStart = maRawData;
2670     // Offset-Location in maRawData
2671     const size_t nRawDataStart = (mnIMax + 1) * 4;
2672 
2673     for (mnIdx = 0; mnIdx < mnIMax; ++mnIdx)
2674     {
2675         const size_t nRawDataOffset = nRawDataStart + mnIdx * m_nItemSize;
2676 
2677         //clip to available data, corrupt fkp
2678         if (nRawDataOffset >= 511)
2679         {
2680             mnIMax = mnIdx;
2681             break;
2682         }
2683 
2684         unsigned int nOfs = maRawData[nRawDataOffset] * 2;
2685         // nOfs in [0..0xff*2=510]
2686 
2687         Entry aEntry(Get_Long(pStart));
2688 
2689         if (nOfs)
2690         {
2691             switch (m_ePLCF)
2692             {
2693                 case CHP:
2694                 {
2695                     aEntry.mnLen = maRawData[nOfs];
2696 
2697                     //len byte
2698                     std::size_t nDataOffset = nOfs + 1;
2699 
2700                     FillEntry(aEntry, nDataOffset, aEntry.mnLen);
2701 
2702                     if (aEntry.mnLen && eVersion <= ww::eWW2)
2703                     {
2704                         Word2CHPX aChpx = ReadWord2Chpx(*pSt, m_nFilePos + nOfs + 1, static_cast< sal_uInt8 >(aEntry.mnLen));
2705                         std::vector<sal_uInt8> aSprms = ChpxToSprms(aChpx);
2706                         aEntry.mnLen = static_cast< sal_uInt16 >(aSprms.size());
2707                         if (aEntry.mnLen)
2708                         {
2709                             aEntry.mpData = new sal_uInt8[aEntry.mnLen];
2710                             memcpy(aEntry.mpData, aSprms.data(), aEntry.mnLen);
2711                             aEntry.mbMustDelete = true;
2712                         }
2713                     }
2714                     break;
2715                 }
2716                 case PAP:
2717                     {
2718                         sal_uInt8 nDelta = 0;
2719 
2720                         aEntry.mnLen = maRawData[nOfs];
2721                         if (IsEightPlus(eVersion) && !aEntry.mnLen)
2722                         {
2723                             aEntry.mnLen = maRawData[nOfs+1];
2724                             nDelta++;
2725                         }
2726                         aEntry.mnLen *= 2;
2727 
2728                         //stylecode, std/istd
2729                         if (eVersion <= ww::eWW2)
2730                         {
2731                             if (aEntry.mnLen >= 1)
2732                             {
2733                                 aEntry.mnIStd = *(maRawData+nOfs+1+nDelta);
2734                                 aEntry.mnLen--;  //style code
2735                                 if (aEntry.mnLen >= 6)
2736                                 {
2737                                     aEntry.mnLen-=6; //PHE
2738                                     //skip stc, len byte + 6 byte PHE
2739                                     unsigned int nOffset = nOfs + 8;
2740                                     if (nOffset >= 511) //Bad offset
2741                                         aEntry.mnLen=0;
2742                                     if (aEntry.mnLen)   //start is ok
2743                                     {
2744                                         if (nOffset + aEntry.mnLen > 512)   //Bad end, clip
2745                                             aEntry.mnLen = 512 - nOffset;
2746                                         aEntry.mpData = maRawData + nOffset;
2747                                     }
2748                                 }
2749                                 else
2750                                     aEntry.mnLen=0; //Too short
2751                             }
2752                         }
2753                         else
2754                         {
2755                             if (aEntry.mnLen >= 2)
2756                             {
2757                                 //len byte + optional extra len byte
2758                                 std::size_t nDataOffset = nOfs + 1 + nDelta;
2759                                 aEntry.mnIStd = nDataOffset <= sizeof(maRawData)-sizeof(aEntry.mnIStd) ?
2760                                     SVBT16ToUInt16(maRawData+nDataOffset) : 0;
2761                                 aEntry.mnLen-=2; //istd
2762                                 if (aEntry.mnLen)
2763                                 {
2764                                     //additional istd
2765                                     nDataOffset += sizeof(aEntry.mnIStd);
2766 
2767                                     FillEntry(aEntry, nDataOffset, aEntry.mnLen);
2768                                 }
2769                             }
2770                             else
2771                                 aEntry.mnLen=0; //Too short, ignore
2772                         }
2773 
2774                         const sal_uInt16 nSpId = aEntry.mnLen
2775                             ? maSprmParser.GetSprmId(aEntry.mpData) : 0;
2776 
2777                         /*
2778                          If we replace then we throw away the old data, if we
2779                          are expanding, then we tack the old data onto the end
2780                          of the new data
2781                         */
2782                         const bool bExpand = IsExpandableSprm(nSpId);
2783                         const sal_uInt8* pStartData
2784                             = aEntry.mpData == nullptr ? nullptr : aEntry.mpData + 2;
2785                         const sal_uInt8* pLastValidDataPos = maRawData + 512 - sizeof(sal_uInt32);
2786                         if (pStartData != nullptr && pStartData > pLastValidDataPos)
2787                             pStartData = nullptr;
2788                         if ((IsReplaceAllSprm(nSpId) || bExpand) && pStartData)
2789                         {
2790                             sal_uInt64 nCurr = pDataSt->Tell();
2791                             sal_uInt32 nPos = SVBT32ToUInt32(pStartData);
2792                             sal_uInt16 nLen(0);
2793 
2794                             bool bOk = checkSeek(*pDataSt, nPos);
2795                             if (bOk)
2796                             {
2797                                 pDataSt->ReadUInt16( nLen );
2798                                 bOk = nLen <= pDataSt->remainingSize();
2799                             }
2800 
2801                             if (bOk)
2802                             {
2803                                 const sal_uInt16 nOrigLen = bExpand ? aEntry.mnLen : 0;
2804                                 sal_uInt8 *pOrigData = bExpand ? aEntry.mpData : nullptr;
2805 
2806                                 aEntry.mnLen = nLen;
2807                                 aEntry.mpData =
2808                                     new sal_uInt8[aEntry.mnLen + nOrigLen];
2809                                 aEntry.mbMustDelete = true;
2810                                 aEntry.mnLen =
2811                                     pDataSt->ReadBytes(aEntry.mpData, aEntry.mnLen);
2812 
2813                                 pDataSt->Seek( nCurr );
2814 
2815                                 if (pOrigData)
2816                                 {
2817                                     memcpy(aEntry.mpData + aEntry.mnLen,
2818                                         pOrigData, nOrigLen);
2819                                     aEntry.mnLen = aEntry.mnLen + nOrigLen;
2820                                 }
2821                             }
2822                         }
2823                     }
2824                     break;
2825                 default:
2826                     OSL_FAIL("sweet god, what have you done!");
2827                     break;
2828             }
2829         }
2830 
2831         maEntries.push_back(aEntry);
2832     }
2833 
2834     //one more FC than grrpl entries
2835     maEntries.emplace_back(Get_Long(pStart));
2836 
2837     //we expect them sorted, but it appears possible for them to arrive unsorted
2838     std::stable_sort(maEntries.begin(), maEntries.end());
2839 
2840     mnIdx = 0;
2841 
2842     if (nStartFc >= 0)
2843         SeekPos(nStartFc);
2844 
2845     pSt->Seek(nOldPos);
2846 }
2847 
Entry(const Entry & rEntry)2848 WW8PLCFx_Fc_FKP::WW8Fkp::Entry::Entry(const Entry &rEntry)
2849     : mnFC(rEntry.mnFC), mnLen(rEntry.mnLen), mnIStd(rEntry.mnIStd),
2850     mbMustDelete(rEntry.mbMustDelete)
2851 {
2852     if (mbMustDelete)
2853     {
2854         mpData = new sal_uInt8[mnLen];
2855         memcpy(mpData, rEntry.mpData, mnLen);
2856     }
2857     else
2858         mpData = rEntry.mpData;
2859 }
2860 
2861 WW8PLCFx_Fc_FKP::WW8Fkp::Entry&
operator =(const Entry & rEntry)2862     WW8PLCFx_Fc_FKP::WW8Fkp::Entry::operator=(const Entry &rEntry)
2863 {
2864     if (this == &rEntry)
2865         return *this;
2866 
2867     if (mbMustDelete)
2868         delete[] mpData;
2869 
2870     mnFC = rEntry.mnFC;
2871     mnLen = rEntry.mnLen;
2872     mnIStd = rEntry.mnIStd;
2873     mbMustDelete = rEntry.mbMustDelete;
2874 
2875     if (rEntry.mbMustDelete)
2876     {
2877         mpData = new sal_uInt8[mnLen];
2878         memcpy(mpData, rEntry.mpData, mnLen);
2879     }
2880     else
2881         mpData = rEntry.mpData;
2882 
2883     return *this;
2884 }
2885 
~Entry()2886 WW8PLCFx_Fc_FKP::WW8Fkp::Entry::~Entry()
2887 {
2888     if (mbMustDelete)
2889         delete[] mpData;
2890 }
2891 
Reset(WW8_FC nFc)2892 void WW8PLCFx_Fc_FKP::WW8Fkp::Reset(WW8_FC nFc)
2893 {
2894     SetIdx(0);
2895     if (nFc >= 0)
2896         SeekPos(nFc);
2897 }
2898 
SeekPos(WW8_FC nFc)2899 bool WW8PLCFx_Fc_FKP::WW8Fkp::SeekPos(WW8_FC nFc)
2900 {
2901     if (nFc < maEntries[0].mnFC)
2902     {
2903         mnIdx = 0;
2904         return false;       // not found: nPos less than smallest entry
2905     }
2906 
2907     // Search from beginning?
2908     if ((mnIdx < 1) || (nFc < maEntries[mnIdx - 1].mnFC))
2909         mnIdx = 1;
2910 
2911     sal_uInt8 nI   = mnIdx;
2912     sal_uInt8 nEnd = mnIMax;
2913 
2914     for(sal_uInt8 n = (1==mnIdx ? 1 : 2); n; --n )
2915     {
2916         for( ; nI <=nEnd; ++nI)
2917         {                               // search with an index that is incremented by 1
2918             if (nFc < maEntries[nI].mnFC)
2919             {                           // found position
2920                 mnIdx = nI - 1;          // nI - 1 is the correct index
2921                 return true;            // done
2922             }
2923         }
2924         nI = 1;
2925         nEnd = mnIdx-1;
2926     }
2927     mnIdx = mnIMax;               // not found, greater than all entries
2928     return false;
2929 }
2930 
Get(WW8_FC & rStart,WW8_FC & rEnd,sal_Int32 & rLen) const2931 sal_uInt8* WW8PLCFx_Fc_FKP::WW8Fkp::Get(WW8_FC& rStart, WW8_FC& rEnd, sal_Int32& rLen)
2932     const
2933 {
2934     rLen = 0;
2935 
2936     if (mnIdx >= mnIMax)
2937     {
2938         rStart = WW8_FC_MAX;
2939         return nullptr;
2940     }
2941 
2942     rStart = maEntries[mnIdx].mnFC;
2943     rEnd   = maEntries[mnIdx + 1].mnFC;
2944 
2945     sal_uInt8* pSprms = GetLenAndIStdAndSprms( rLen );
2946     return pSprms;
2947 }
2948 
SetIdx(sal_uInt8 nI)2949 void WW8PLCFx_Fc_FKP::WW8Fkp::SetIdx(sal_uInt8 nI)
2950 {
2951     if (nI < mnIMax)
2952     {
2953         mnIdx = nI;
2954     }
2955 }
2956 
GetLenAndIStdAndSprms(sal_Int32 & rLen) const2957 sal_uInt8* WW8PLCFx_Fc_FKP::WW8Fkp::GetLenAndIStdAndSprms(sal_Int32& rLen) const
2958 {
2959     rLen = maEntries[mnIdx].mnLen;
2960     return maEntries[mnIdx].mpData;
2961 }
2962 
HasSprm(sal_uInt16 nId,bool bFindFirst)2963 SprmResult WW8PLCFx_Fc_FKP::WW8Fkp::HasSprm( sal_uInt16 nId, bool bFindFirst )
2964 {
2965     if (mnIdx >= mnIMax)
2966         return SprmResult();
2967 
2968     sal_Int32 nLen;
2969     sal_uInt8* pSprms = GetLenAndIStdAndSprms( nLen );
2970 
2971     WW8SprmIter aIter(pSprms, nLen, maSprmParser);
2972     return aIter.FindSprm(nId, bFindFirst);
2973 }
2974 
HasSprm(sal_uInt16 nId,std::vector<SprmResult> & rResult)2975 void WW8PLCFx_Fc_FKP::WW8Fkp::HasSprm(sal_uInt16 nId,
2976     std::vector<SprmResult> &rResult)
2977 {
2978     if (mnIdx >= mnIMax)
2979        return;
2980 
2981     sal_Int32 nLen;
2982     sal_uInt8* pSprms = GetLenAndIStdAndSprms( nLen );
2983 
2984     WW8SprmIter aIter(pSprms, nLen, maSprmParser);
2985 
2986     while(aIter.GetSprms())
2987     {
2988         if (aIter.GetCurrentId() == nId)
2989         {
2990             sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId);
2991             sal_Int32 nL = maSprmParser.GetSprmSize(nId, aIter.GetSprms(), aIter.GetRemLen());
2992             rResult.emplace_back(aIter.GetCurrentParams(), nL - nFixedLen);
2993         }
2994         aIter.advance();
2995     };
2996 }
2997 
GetFIBVersion() const2998 ww::WordVersion WW8PLCFx::GetFIBVersion() const
2999 {
3000     return mrFib.GetFIBVersion();
3001 }
3002 
GetSprms(WW8PLCFxDesc * p)3003 void WW8PLCFx::GetSprms( WW8PLCFxDesc* p )
3004 {
3005     OSL_ENSURE( false, "Called wrong GetSprms" );
3006     p->nStartPos = p->nEndPos = WW8_CP_MAX;
3007     p->pMemPos = nullptr;
3008     p->nSprmsLen = 0;
3009     p->bRealLineEnd = false;
3010 }
3011 
GetNoSprms(WW8_CP & rStart,WW8_CP & rEnd,sal_Int32 & rLen)3012 tools::Long WW8PLCFx::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
3013 {
3014     OSL_ENSURE( false, "Called wrong GetNoSprms" );
3015     rStart = rEnd = WW8_CP_MAX;
3016     rLen = 0;
3017     return 0;
3018 }
3019 
3020 // ...Idx2: Default: ignore
GetIdx2() const3021 sal_uInt32 WW8PLCFx::GetIdx2() const
3022 {
3023     return 0;
3024 }
3025 
SetIdx2(sal_uInt32)3026 void WW8PLCFx::SetIdx2(sal_uInt32)
3027 {
3028 }
3029 
3030 namespace {
3031 
3032 class SamePos
3033 {
3034 private:
3035     tools::Long mnPo;
3036 public:
SamePos(tools::Long nPo)3037     explicit SamePos(tools::Long nPo) : mnPo(nPo) {}
operator ()(const std::unique_ptr<WW8PLCFx_Fc_FKP::WW8Fkp> & pFkp)3038     bool operator()(const std::unique_ptr<WW8PLCFx_Fc_FKP::WW8Fkp>& pFkp)
3039         {return mnPo == pFkp->GetFilePos();}
3040 };
3041 
3042 }
3043 
NewFkp()3044 bool WW8PLCFx_Fc_FKP::NewFkp()
3045 {
3046     WW8_CP nPLCFStart, nPLCFEnd;
3047     void* pPage;
3048 
3049     static const int WW8FkpSizeTabVer2[ PLCF_END ] =
3050     {
3051         1,  1, 0 /*, 0, 0, 0*/
3052     };
3053     static const int WW8FkpSizeTabVer6[ PLCF_END ] =
3054     {
3055         1,  7, 0 /*, 0, 0, 0*/
3056     };
3057     static const int WW8FkpSizeTabVer8[ PLCF_END ] =
3058     {
3059         1, 13, 0 /*, 0, 0, 0*/
3060     };
3061     const int* pFkpSizeTab;
3062 
3063     switch (GetFIBVersion())
3064     {
3065         case ww::eWW1:
3066         case ww::eWW2:
3067             pFkpSizeTab = WW8FkpSizeTabVer2;
3068             break;
3069         case ww::eWW6:
3070         case ww::eWW7:
3071             pFkpSizeTab = WW8FkpSizeTabVer6;
3072             break;
3073         case ww::eWW8:
3074             pFkpSizeTab = WW8FkpSizeTabVer8;
3075             break;
3076         default:
3077             // program error!
3078             OSL_ENSURE( false, "nVersion not implemented!" );
3079             return false;
3080     }
3081 
3082     if (!m_pPLCF->Get( nPLCFStart, nPLCFEnd, pPage ))
3083     {
3084         m_pFkp = nullptr;
3085         return false;                           // PLCF completely processed
3086     }
3087     m_pPLCF->advance();
3088     tools::Long nPo = SVBT16ToUInt16( static_cast<sal_uInt8 *>(pPage) );
3089     nPo <<= 9;                                  // shift as LONG
3090 
3091     tools::Long nCurrentFkpFilePos = m_pFkp ? m_pFkp->GetFilePos() : -1;
3092     if (nCurrentFkpFilePos == nPo)
3093         m_pFkp->Reset(GetStartFc());
3094     else
3095     {
3096         auto aIter =
3097             std::find_if(maFkpCache.begin(), maFkpCache.end(), SamePos(nPo));
3098         if (aIter != maFkpCache.end())
3099         {
3100             m_pFkp = aIter->get();
3101             m_pFkp->Reset(GetStartFc());
3102         }
3103         else
3104         {
3105             m_pFkp = new WW8Fkp(GetFIB(), m_pFKPStrm, m_pDataStrm, nPo,
3106                 pFkpSizeTab[ m_ePLCF ], m_ePLCF, GetStartFc());
3107             maFkpCache.push_back(std::unique_ptr<WW8Fkp>(m_pFkp));
3108 
3109             if (maFkpCache.size() > eMaxCache)
3110             {
3111                 WW8Fkp* pCachedFkp = maFkpCache.front().get();
3112                 if (!pCachedFkp->IsMustRemainCache())
3113                 {
3114                     maFkpCache.pop_front();
3115                 }
3116             }
3117         }
3118     }
3119 
3120     SetStartFc( -1 );                                   // only the first time
3121     return true;
3122 }
3123 
WW8PLCFx_Fc_FKP(SvStream * pSt,SvStream * pTableSt,SvStream * pDataSt,const WW8Fib & rFib,ePLCFT ePl,WW8_FC nStartFcL)3124 WW8PLCFx_Fc_FKP::WW8PLCFx_Fc_FKP(SvStream* pSt, SvStream* pTableSt,
3125     SvStream* pDataSt, const WW8Fib& rFib, ePLCFT ePl, WW8_FC nStartFcL)
3126     : WW8PLCFx(rFib, true), m_pFKPStrm(pSt), m_pDataStrm(pDataSt)
3127     , m_pFkp(nullptr), m_ePLCF(ePl)
3128 {
3129     SetStartFc(nStartFcL);
3130     tools::Long nLenStruct = (8 > rFib.m_nVersion) ? 2 : 4;
3131     if (ePl == CHP)
3132     {
3133         m_pPLCF.reset(new WW8PLCF(*pTableSt, rFib.m_fcPlcfbteChpx, rFib.m_lcbPlcfbteChpx,
3134             nLenStruct, GetStartFc(), rFib.m_pnChpFirst, rFib.m_cpnBteChp));
3135     }
3136     else
3137     {
3138         m_pPLCF.reset(new WW8PLCF(*pTableSt, rFib.m_fcPlcfbtePapx, rFib.m_lcbPlcfbtePapx,
3139             nLenStruct, GetStartFc(), rFib.m_pnPapFirst, rFib.m_cpnBtePap));
3140     }
3141 }
3142 
~WW8PLCFx_Fc_FKP()3143 WW8PLCFx_Fc_FKP::~WW8PLCFx_Fc_FKP()
3144 {
3145     maFkpCache.clear();
3146     m_pPLCF.reset();
3147     m_pPCDAttrs.reset();
3148 }
3149 
GetIdx() const3150 sal_uInt32 WW8PLCFx_Fc_FKP::GetIdx() const
3151 {
3152     sal_uInt32 u = m_pPLCF->GetIdx() << 8;
3153     if (m_pFkp)
3154         u |= m_pFkp->GetIdx();
3155     return u;
3156 }
3157 
SetIdx(sal_uInt32 nIdx)3158 void WW8PLCFx_Fc_FKP::SetIdx(sal_uInt32 nIdx)
3159 {
3160     if( !( nIdx & 0xffffff00L ) )
3161     {
3162         m_pPLCF->SetIdx( nIdx >> 8 );
3163         m_pFkp = nullptr;
3164     }
3165     else
3166     {                                   // there was a Fkp
3167         // Set PLCF one position back to retrieve the address of the Fkp
3168         m_pPLCF->SetIdx( ( nIdx >> 8 ) - 1 );
3169         if (NewFkp())                       // read Fkp again
3170         {
3171             sal_uInt8 nFkpIdx = static_cast<sal_uInt8>(nIdx & 0xff);
3172             m_pFkp->SetIdx(nFkpIdx);          // set Fkp-Pos again
3173         }
3174     }
3175 }
3176 
SeekPos(WW8_FC nFcPos)3177 bool WW8PLCFx_Fc_FKP::SeekPos(WW8_FC nFcPos)
3178 {
3179     // StartPos for next Where()
3180     SetStartFc( nFcPos );
3181 
3182     // find StartPos for next pPLCF->Get()
3183     bool bRet = m_pPLCF->SeekPos(nFcPos);
3184 
3185     // make FKP invalid?
3186     WW8_CP nPLCFStart, nPLCFEnd;
3187     void* pPage;
3188     if( m_pFkp && m_pPLCF->Get( nPLCFStart, nPLCFEnd, pPage ) )
3189     {
3190         tools::Long nPo = SVBT16ToUInt16( static_cast<sal_uInt8 *>(pPage) );
3191         nPo <<= 9;                                          // shift as LONG
3192         if (nPo != m_pFkp->GetFilePos())
3193             m_pFkp = nullptr;
3194         else
3195             m_pFkp->SeekPos( nFcPos );
3196     }
3197     return bRet;
3198 }
3199 
Where()3200 WW8_FC WW8PLCFx_Fc_FKP::Where()
3201 {
3202     if( !m_pFkp && !NewFkp() )
3203         return WW8_FC_MAX;
3204     WW8_FC nP = m_pFkp ? m_pFkp->Where() : WW8_FC_MAX;
3205     if( nP != WW8_FC_MAX )
3206         return nP;
3207 
3208     m_pFkp = nullptr;                   // FKP finished -> get new
3209     return Where();                     // easiest way: do it recursively
3210 }
3211 
GetSprmsAndPos(WW8_FC & rStart,WW8_FC & rEnd,sal_Int32 & rLen)3212 sal_uInt8* WW8PLCFx_Fc_FKP::GetSprmsAndPos(WW8_FC& rStart, WW8_FC& rEnd, sal_Int32& rLen)
3213 {
3214     rLen = 0;                               // Default
3215     rStart = rEnd = WW8_FC_MAX;
3216 
3217     if( !m_pFkp )     // Fkp not there ?
3218     {
3219         if( !NewFkp() )
3220             return nullptr;
3221     }
3222 
3223     sal_uInt8* pPos = m_pFkp ? m_pFkp->Get( rStart, rEnd, rLen ) : nullptr;
3224     if( rStart == WW8_FC_MAX )    //Not found
3225         return nullptr;
3226     return pPos;
3227 }
3228 
advance()3229 void WW8PLCFx_Fc_FKP::advance()
3230 {
3231     if( !m_pFkp && !NewFkp() )
3232         return;
3233 
3234     if (!m_pFkp)
3235         return;
3236 
3237     m_pFkp->advance();
3238     if( m_pFkp->Where() == WW8_FC_MAX )
3239         (void)NewFkp();
3240 }
3241 
GetIstd() const3242 sal_uInt16 WW8PLCFx_Fc_FKP::GetIstd() const
3243 {
3244     return m_pFkp ? m_pFkp->GetIstd() : 0xFFFF;
3245 }
3246 
GetPCDSprms(WW8PLCFxDesc & rDesc)3247 void WW8PLCFx_Fc_FKP::GetPCDSprms( WW8PLCFxDesc& rDesc )
3248 {
3249     rDesc.pMemPos   = nullptr;
3250     rDesc.nSprmsLen = 0;
3251     if( m_pPCDAttrs )
3252     {
3253         if( !m_pFkp )
3254         {
3255             OSL_FAIL("+Problem: GetPCDSprms: NewFkp necessary (not possible!)" );
3256             if( !NewFkp() )
3257                 return;
3258         }
3259         m_pPCDAttrs->GetSprms(&rDesc);
3260     }
3261 }
3262 
HasSprm(sal_uInt16 nId,bool bFindFirst)3263 SprmResult WW8PLCFx_Fc_FKP::HasSprm(sal_uInt16 nId, bool bFindFirst)
3264 {
3265     // const would be nicer, but for that, NewFkp() would need to be replaced or eliminated
3266     if( !m_pFkp )
3267     {
3268         OSL_FAIL( "+Motz: HasSprm: NewFkp needed ( no const possible )" );
3269         // happens in BugDoc 31722
3270         if( !NewFkp() )
3271             return SprmResult();
3272     }
3273 
3274     if (!m_pFkp)
3275         return SprmResult();
3276 
3277     SprmResult aRes = m_pFkp->HasSprm(nId, bFindFirst);
3278 
3279     if (!aRes.pSprm)
3280     {
3281         WW8PLCFxDesc aDesc;
3282         GetPCDSprms( aDesc );
3283 
3284         if (aDesc.pMemPos)
3285         {
3286             WW8SprmIter aIter(aDesc.pMemPos, aDesc.nSprmsLen,
3287                 m_pFkp->GetSprmParser());
3288             aRes = aIter.FindSprm(nId, bFindFirst);
3289         }
3290     }
3291 
3292     return aRes;
3293 }
3294 
HasSprm(sal_uInt16 nId,std::vector<SprmResult> & rResult)3295 void WW8PLCFx_Fc_FKP::HasSprm(sal_uInt16 nId, std::vector<SprmResult> &rResult)
3296 {
3297     // const would be nicer, but for that, NewFkp() would need to be replaced or eliminated
3298     if (!m_pFkp)
3299     {
3300        OSL_FAIL( "+Motz: HasSprm: NewFkp needed ( no const possible )" );
3301        // happens in BugDoc 31722
3302        if( !NewFkp() )
3303            return;
3304     }
3305 
3306     if (!m_pFkp)
3307         return;
3308 
3309     m_pFkp->HasSprm(nId, rResult);
3310 
3311     WW8PLCFxDesc aDesc;
3312     GetPCDSprms( aDesc );
3313 
3314     if (!aDesc.pMemPos)
3315         return;
3316 
3317     const wwSprmParser &rSprmParser = m_pFkp->GetSprmParser();
3318     WW8SprmIter aIter(aDesc.pMemPos, aDesc.nSprmsLen, rSprmParser);
3319     while(aIter.GetSprms())
3320     {
3321         if (aIter.GetCurrentId() == nId)
3322         {
3323             sal_Int32 nFixedLen = rSprmParser.DistanceToData(nId);
3324             sal_Int32 nL = rSprmParser.GetSprmSize(nId, aIter.GetSprms(), aIter.GetRemLen());
3325             rResult.emplace_back(aIter.GetCurrentParams(), nL - nFixedLen);
3326         }
3327         aIter.advance();
3328     };
3329 }
3330 
WW8PLCFx_Cp_FKP(SvStream * pSt,SvStream * pTableSt,SvStream * pDataSt,const WW8ScannerBase & rBase,ePLCFT ePl)3331 WW8PLCFx_Cp_FKP::WW8PLCFx_Cp_FKP( SvStream* pSt, SvStream* pTableSt,
3332     SvStream* pDataSt, const WW8ScannerBase& rBase, ePLCFT ePl )
3333     : WW8PLCFx_Fc_FKP(pSt, pTableSt, pDataSt, *rBase.m_pWw8Fib, ePl,
3334     rBase.WW8Cp2Fc(0)), m_rSBase(rBase), m_nAttrStart(-1), m_nAttrEnd(-1),
3335     m_bLineEnd(false),
3336     m_bComplex( (7 < rBase.m_pWw8Fib->m_nVersion) || rBase.m_pWw8Fib->m_fComplex )
3337 {
3338     ResetAttrStartEnd();
3339 
3340     if (m_rSBase.m_pPiecePLCF)
3341         m_pPcd.reset( new WW8PLCFx_PCD(GetFIB(), rBase.m_pPiecePLCF.get(), 0, IsSevenMinus(GetFIBVersion())) );
3342 
3343     /*
3344     Make a copy of the piece attributes for so that the calls to HasSprm on a
3345     Fc_FKP will be able to take into account the current piece attributes,
3346     despite the fact that such attributes can only be found through a cp based
3347     mechanism.
3348     */
3349     if (m_pPcd)
3350     {
3351         m_pPCDAttrs.reset( m_rSBase.m_pPLCFx_PCDAttrs ? new WW8PLCFx_PCDAttrs(
3352             *m_rSBase.m_pWw8Fib, m_pPcd.get(), &m_rSBase) : nullptr);
3353     }
3354 
3355     m_pPieceIter = m_rSBase.m_pPieceIter.get();
3356 }
3357 
~WW8PLCFx_Cp_FKP()3358 WW8PLCFx_Cp_FKP::~WW8PLCFx_Cp_FKP()
3359 {
3360 }
3361 
ResetAttrStartEnd()3362 void WW8PLCFx_Cp_FKP::ResetAttrStartEnd()
3363 {
3364     m_nAttrStart = -1;
3365     m_nAttrEnd   = -1;
3366     m_bLineEnd   = false;
3367 }
3368 
GetPCDIdx() const3369 sal_uInt32 WW8PLCFx_Cp_FKP::GetPCDIdx() const
3370 {
3371     return m_pPcd ? m_pPcd->GetIdx() : 0;
3372 }
3373 
SeekPos(WW8_CP nCpPos)3374 bool WW8PLCFx_Cp_FKP::SeekPos(WW8_CP nCpPos)
3375 {
3376     if( m_pPcd )  // Complex
3377     {
3378         if( !m_pPcd->SeekPos( nCpPos ) )  // set piece
3379             return false;
3380         if (m_pPCDAttrs && !m_pPCDAttrs->GetIter()->SeekPos(nCpPos))
3381             return false;
3382         return WW8PLCFx_Fc_FKP::SeekPos(m_pPcd->CurrentPieceStartCp2Fc(nCpPos));
3383     }
3384                                     // NO piece table !!!
3385     return WW8PLCFx_Fc_FKP::SeekPos( m_rSBase.WW8Cp2Fc(nCpPos) );
3386 }
3387 
Where()3388 WW8_CP WW8PLCFx_Cp_FKP::Where()
3389 {
3390     WW8_FC nFc = WW8PLCFx_Fc_FKP::Where();
3391     if( m_pPcd )
3392         return m_pPcd->CurrentPieceStartFc2Cp( nFc ); // identify piece
3393     return m_rSBase.WW8Fc2Cp( nFc );      // NO piece table !!!
3394 }
3395 
GetSprms(WW8PLCFxDesc * p)3396 void WW8PLCFx_Cp_FKP::GetSprms(WW8PLCFxDesc* p)
3397 {
3398     WW8_CP nOrigCp = p->nStartPos;
3399 
3400     if (!GetDirty())        //Normal case
3401     {
3402         p->pMemPos = WW8PLCFx_Fc_FKP::GetSprmsAndPos(p->nStartPos, p->nEndPos,
3403             p->nSprmsLen);
3404     }
3405     else
3406     {
3407         /*
3408         For the odd case where we have a location in a fastsaved file which
3409         does not have an entry in the FKP, perhaps its para end is in the next
3410         piece, or perhaps the cp just doesn't exist at all in this document.
3411         AdvSprm doesn't know so it sets the PLCF as dirty and we figure out
3412         in this method what the situation is
3413 
3414         It doesn't exist then the piece iterator will not be able to find it.
3415         Otherwise our cool fastsave algorithm can be brought to bear on the
3416         problem.
3417         */
3418         if( !m_pPieceIter )
3419             return;
3420         const sal_uInt32 nOldPos = m_pPieceIter->GetIdx();
3421         bool bOk = m_pPieceIter->SeekPos(nOrigCp);
3422         m_pPieceIter->SetIdx(nOldPos);
3423         if (!bOk)
3424             return;
3425     }
3426 
3427     if( m_pPcd )  // piece table available
3428     {
3429         // Init ( no ++ called, yet )
3430         if( (m_nAttrStart >  m_nAttrEnd) || (m_nAttrStart == -1) )
3431         {
3432             p->bRealLineEnd = (m_ePLCF == PAP);
3433 
3434             if ( ((m_ePLCF == PAP ) || (m_ePLCF == CHP)) && (nOrigCp != WW8_CP_MAX) )
3435             {
3436                 bool bIsUnicode=false;
3437                 /*
3438                 To find the end of a paragraph for a character in a
3439                 complex format file.
3440 
3441                 It is necessary to know the piece that contains the
3442                 character and the FC assigned to the character.
3443                 */
3444 
3445                 //We set the piece iterator to the piece that contains the
3446                 //character, now we have the correct piece for this character
3447                 sal_uInt32 nOldPos = m_pPieceIter->GetIdx();
3448                 p->nStartPos = nOrigCp;
3449                 m_pPieceIter->SeekPos( p->nStartPos);
3450 
3451                 //This is the FC assigned to the character, but we already
3452                 //have the result of the next stage, so we can skip this step
3453                 //WW8_FC nStartFc = rSBase.WW8Cp2Fc(p->nStartPos, &bIsUnicode);
3454 
3455                 /*
3456                 Using the FC of the character, first search the FKP that
3457                 describes the character to find the smallest FC in the rgfc
3458                 that is larger than the character FC.
3459                 */
3460                 //But the search has already been done, the next largest FC is
3461                 //p->nEndPos.
3462                 WW8_FC nOldEndPos = p->nEndPos;
3463 
3464                 /*
3465                 If the FC found in the FKP is less than or equal to the limit
3466                 FC of the piece, the end of the paragraph that contains the
3467                 character is at the FKP FC minus 1.
3468                 */
3469                 WW8_CP nCpStart, nCpEnd;
3470                 void* pData=nullptr;
3471                 bool bOk = m_pPieceIter->Get(nCpStart, nCpEnd, pData);
3472 
3473                 if (!bOk)
3474                 {
3475                     m_pPieceIter->SetIdx(nOldPos);
3476                     return;
3477                 }
3478 
3479                 WW8_FC nLimitFC = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
3480                 WW8_FC nBeginLimitFC = nLimitFC;
3481                 if (IsEightPlus(GetFIBVersion()))
3482                 {
3483                     nBeginLimitFC =
3484                         WW8PLCFx_PCD::TransformPieceAddress(nLimitFC,
3485                         bIsUnicode);
3486                 }
3487 
3488                 WW8_CP nCpLen;
3489                 bool bFail = o3tl::checked_sub(nCpEnd, nCpStart, nCpLen);
3490                 if (bFail)
3491                 {
3492                     SAL_WARN("sw.ww8", "broken offset, ignoring");
3493                     p->nStartPos = p->nEndPos = WW8_FC_MAX;
3494                     m_pPieceIter->SetIdx(nOldPos);
3495                     return;
3496                 }
3497 
3498                 if (bIsUnicode)
3499                 {
3500                     bFail = o3tl::checked_multiply<WW8_CP>(nCpLen, 2, nCpLen);
3501                     if (bFail)
3502                     {
3503                         SAL_WARN("sw.ww8", "broken offset, ignoring");
3504                         p->nStartPos = p->nEndPos = WW8_FC_MAX;
3505                         m_pPieceIter->SetIdx(nOldPos);
3506                         return;
3507                     }
3508                 }
3509 
3510                 bFail = o3tl::checked_add(nBeginLimitFC, nCpLen, nLimitFC);
3511                 if (bFail)
3512                 {
3513                     SAL_WARN("sw.ww8", "broken offset, ignoring");
3514                     p->nStartPos = p->nEndPos = WW8_FC_MAX;
3515                     m_pPieceIter->SetIdx(nOldPos);
3516                     return;
3517                 }
3518 
3519                 if (nOldEndPos <= nLimitFC)
3520                 {
3521                     bFail = o3tl::checked_sub(nLimitFC, nOldEndPos, nCpLen);
3522                     if (bFail)
3523                     {
3524                         SAL_WARN("sw.ww8", "broken offset, ignoring");
3525                         p->nStartPos = p->nEndPos = WW8_FC_MAX;
3526                         m_pPieceIter->SetIdx(nOldPos);
3527                         return;
3528                     }
3529 
3530                     nCpLen /= (bIsUnicode ? 2 : 1);
3531 
3532                     bFail = o3tl::checked_sub(nCpEnd, nCpLen, p->nEndPos);
3533                     if (bFail)
3534                     {
3535                         SAL_WARN("sw.ww8", "broken offset, ignoring");
3536                         p->nStartPos = p->nEndPos = WW8_FC_MAX;
3537                         m_pPieceIter->SetIdx(nOldPos);
3538                         return;
3539                     }
3540                 }
3541                 else
3542                 {
3543                     p->nEndPos = nCpEnd;
3544                     if (m_ePLCF != CHP)
3545                     {
3546                         /*
3547                         If the FKP FC that was found was greater than the FC
3548                         of the end of the piece, scan piece by piece toward
3549                         the end of the document until a piece is found that
3550                         contains a  paragraph end mark.
3551                         */
3552 
3553                         /*
3554                         It's possible to check if a piece contains a paragraph
3555                         mark by using the FC of the beginning of the piece to
3556                         search in the FKPs for the smallest FC in the FKP rgfc
3557                         that is greater than the FC of the beginning of the
3558                         piece. If the FC found is less than or equal to the
3559                         limit FC of the piece, then the character that ends
3560                         the paragraph is the character immediately before the
3561                         FKP fc
3562                         */
3563 
3564                         m_pPieceIter->advance();
3565 
3566                         for (;m_pPieceIter->GetIdx() < m_pPieceIter->GetIMax();
3567                             m_pPieceIter->advance())
3568                         {
3569                             if( !m_pPieceIter->Get( nCpStart, nCpEnd, pData ) )
3570                             {
3571                                 OSL_ENSURE( false, "piece iter broken!" );
3572                                 break;
3573                             }
3574                             bIsUnicode = false;
3575                             sal_Int32 nFcStart=SVBT32ToUInt32(static_cast<WW8_PCD*>(pData)->fc);
3576 
3577                             if (IsEightPlus(GetFIBVersion()))
3578                             {
3579                                 nFcStart =
3580                                     WW8PLCFx_PCD::TransformPieceAddress(
3581                                     nFcStart,bIsUnicode );
3582                             }
3583 
3584                             bFail = o3tl::checked_sub(nCpEnd, nCpStart, nCpLen);
3585                             if (bFail)
3586                             {
3587                                 SAL_WARN("sw.ww8", "broken offset, ignoring");
3588                                 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3589                                 continue;
3590                             }
3591 
3592                             if (bIsUnicode)
3593                             {
3594                                 bFail = o3tl::checked_multiply<WW8_CP>(nCpLen, 2, nCpLen);
3595                                 if (bFail)
3596                                 {
3597                                     SAL_WARN("sw.ww8", "broken offset, ignoring");
3598                                     p->nStartPos = p->nEndPos = WW8_FC_MAX;
3599                                     continue;
3600                                 }
3601                             }
3602 
3603                             bFail = o3tl::checked_add(nFcStart, nCpLen, nLimitFC);
3604                             if (bFail)
3605                             {
3606                                 SAL_WARN("sw.ww8", "broken offset, ignoring");
3607                                 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3608                                 continue;
3609                             }
3610 
3611                             //if it doesn't exist, skip it
3612                             if (!SeekPos(nCpStart))
3613                                 continue;
3614 
3615                             WW8_FC nOne,nSmallest;
3616                             p->pMemPos = WW8PLCFx_Fc_FKP::GetSprmsAndPos(nOne,
3617                                 nSmallest, p->nSprmsLen);
3618 
3619                             if (nSmallest <= nLimitFC)
3620                             {
3621                                 WW8_CP nCpDiff;
3622                                 bFail = o3tl::checked_sub(nLimitFC, nSmallest, nCpDiff);
3623                                 if (bFail)
3624                                 {
3625                                     SAL_WARN("sw.ww8", "broken offset, ignoring");
3626                                     p->nStartPos = p->nEndPos = WW8_FC_MAX;
3627                                     continue;
3628                                 }
3629                                 if (bIsUnicode)
3630                                     nCpDiff /= 2;
3631 
3632                                 WW8_CP nEndPos;
3633                                 bFail = o3tl::checked_sub(nCpEnd, nCpDiff, nEndPos);
3634                                 if (bFail)
3635                                 {
3636                                     SAL_WARN("sw.ww8", "broken offset, ignoring");
3637                                     p->nStartPos = p->nEndPos = WW8_FC_MAX;
3638                                     continue;
3639                                 }
3640 
3641                                 OSL_ENSURE(nEndPos >= p->nStartPos, "EndPos before StartPos");
3642 
3643                                 if (nEndPos >= p->nStartPos)
3644                                     p->nEndPos = nEndPos;
3645 
3646                                 break;
3647                             }
3648                         }
3649                     }
3650                 }
3651                 m_pPieceIter->SetIdx( nOldPos );
3652             }
3653             else
3654                 WW8PLCFx_PCD::CurrentPieceFc2Cp( p->nStartPos, p->nEndPos,&m_rSBase );
3655         }
3656         else
3657         {
3658             p->nStartPos = m_nAttrStart;
3659             p->nEndPos = m_nAttrEnd;
3660             p->bRealLineEnd = m_bLineEnd;
3661         }
3662     }
3663     else        // NO piece table !!!
3664     {
3665         p->nStartPos = m_rSBase.WW8Fc2Cp( p->nStartPos );
3666         p->nEndPos   = m_rSBase.WW8Fc2Cp( p->nEndPos );
3667         p->bRealLineEnd = m_ePLCF == PAP;
3668     }
3669 }
3670 
advance()3671 void WW8PLCFx_Cp_FKP::advance()
3672 {
3673     WW8PLCFx_Fc_FKP::advance();
3674     // !pPcd: emergency break
3675     if ( !m_bComplex || !m_pPcd )
3676         return;
3677 
3678     if( GetPCDIdx() >= m_pPcd->GetIMax() )           // End of PLCF
3679     {
3680         m_nAttrStart = m_nAttrEnd = WW8_CP_MAX;
3681         return;
3682     }
3683 
3684     sal_Int32 nFkpLen;                               // Fkp entry
3685     // get Fkp entry
3686     WW8PLCFx_Fc_FKP::GetSprmsAndPos(m_nAttrStart, m_nAttrEnd, nFkpLen);
3687 
3688     WW8PLCFx_PCD::CurrentPieceFc2Cp( m_nAttrStart, m_nAttrEnd, &m_rSBase );
3689     m_bLineEnd = (m_ePLCF == PAP);
3690 }
3691 
WW8PLCFx_SEPX(SvStream * pSt,SvStream * pTableSt,const WW8Fib & rFib,WW8_CP nStartCp)3692 WW8PLCFx_SEPX::WW8PLCFx_SEPX(SvStream* pSt, SvStream* pTableSt,
3693     const WW8Fib& rFib, WW8_CP nStartCp)
3694     : WW8PLCFx(rFib, true), maSprmParser(rFib),
3695     m_pStrm(pSt), m_nArrMax(256), m_nSprmSiz(0)
3696 {
3697     if (rFib.m_lcbPlcfsed)
3698         m_pPLCF.reset( new WW8PLCF(*pTableSt, rFib.m_fcPlcfsed, rFib.m_lcbPlcfsed,
3699                                  GetFIBVersion() <= ww::eWW2 ? 6 : 12, nStartCp) );
3700 
3701     m_pSprms.reset( new sal_uInt8[m_nArrMax] );     // maximum length
3702 }
3703 
~WW8PLCFx_SEPX()3704 WW8PLCFx_SEPX::~WW8PLCFx_SEPX()
3705 {
3706 }
3707 
GetIdx() const3708 sal_uInt32 WW8PLCFx_SEPX::GetIdx() const
3709 {
3710     return m_pPLCF ? m_pPLCF->GetIdx() : 0;
3711 }
3712 
SetIdx(sal_uInt32 nIdx)3713 void WW8PLCFx_SEPX::SetIdx(sal_uInt32 nIdx)
3714 {
3715     if( m_pPLCF ) m_pPLCF->SetIdx( nIdx );
3716 }
3717 
SeekPos(WW8_CP nCpPos)3718 bool WW8PLCFx_SEPX::SeekPos(WW8_CP nCpPos)
3719 {
3720     return m_pPLCF && m_pPLCF->SeekPos( nCpPos );
3721 }
3722 
Where()3723 WW8_CP WW8PLCFx_SEPX::Where()
3724 {
3725     return m_pPLCF ? m_pPLCF->Where() : 0;
3726 }
3727 
GetSprms(WW8PLCFxDesc * p)3728 void WW8PLCFx_SEPX::GetSprms(WW8PLCFxDesc* p)
3729 {
3730     if( !m_pPLCF ) return;
3731 
3732     void* pData;
3733 
3734     p->bRealLineEnd = false;
3735     if (!m_pPLCF->Get( p->nStartPos, p->nEndPos, pData ))
3736     {
3737         p->nStartPos = p->nEndPos = WW8_CP_MAX;       // PLCF completely processed
3738         p->pMemPos = nullptr;
3739         p->nSprmsLen = 0;
3740     }
3741     else
3742     {
3743         sal_uInt32 nPo =  SVBT32ToUInt32( static_cast<sal_uInt8*>(pData)+2 );
3744         if (nPo == 0xFFFFFFFF || !checkSeek(*m_pStrm, nPo))
3745         {
3746             p->nStartPos = p->nEndPos = WW8_CP_MAX;   // Sepx empty
3747             p->pMemPos = nullptr;
3748             p->nSprmsLen = 0;
3749         }
3750         else
3751         {
3752             // read len
3753             if (GetFIBVersion() <= ww::eWW2)    // eWW6 ?, docs say yes, but...
3754             {
3755                 sal_uInt8 nSiz(0);
3756                 m_pStrm->ReadUChar( nSiz );
3757                 m_nSprmSiz = nSiz;
3758             }
3759             else
3760             {
3761                 m_pStrm->ReadUInt16( m_nSprmSiz );
3762             }
3763 
3764             std::size_t nRemaining = m_pStrm->remainingSize();
3765             if (m_nSprmSiz > nRemaining)
3766                 m_nSprmSiz = nRemaining;
3767 
3768             if( m_nSprmSiz > m_nArrMax )
3769             {               // does not fit
3770                 m_nArrMax = m_nSprmSiz;                 // Get more memory
3771                 m_pSprms.reset( new sal_uInt8[m_nArrMax] );
3772             }
3773             m_nSprmSiz = m_pStrm->ReadBytes(m_pSprms.get(), m_nSprmSiz); // read Sprms
3774 
3775             p->nSprmsLen = m_nSprmSiz;
3776             p->pMemPos = m_pSprms.get();                    // return Position
3777         }
3778     }
3779 }
3780 
advance()3781 void WW8PLCFx_SEPX::advance()
3782 {
3783     if (m_pPLCF)
3784         m_pPLCF->advance();
3785 }
3786 
HasSprm(sal_uInt16 nId) const3787 SprmResult WW8PLCFx_SEPX::HasSprm(sal_uInt16 nId) const
3788 {
3789     return HasSprm(nId, m_pSprms.get(), m_nSprmSiz);
3790 }
3791 
HasSprm(sal_uInt16 nId,const sal_uInt8 * pOtherSprms,tools::Long nOtherSprmSiz) const3792 SprmResult WW8PLCFx_SEPX::HasSprm( sal_uInt16 nId, const sal_uInt8*  pOtherSprms,
3793     tools::Long nOtherSprmSiz ) const
3794 {
3795     SprmResult aRet;
3796     if (m_pPLCF)
3797     {
3798         WW8SprmIter aIter(pOtherSprms, nOtherSprmSiz, maSprmParser);
3799         aRet = aIter.FindSprm(nId, /*bFindFirst=*/true);
3800     }
3801     return aRet;
3802 }
3803 
Find4Sprms(sal_uInt16 nId1,sal_uInt16 nId2,sal_uInt16 nId3,sal_uInt16 nId4,SprmResult & r1,SprmResult & r2,SprmResult & r3,SprmResult & r4) const3804 bool WW8PLCFx_SEPX::Find4Sprms(sal_uInt16 nId1,sal_uInt16 nId2,sal_uInt16 nId3,sal_uInt16 nId4,
3805     SprmResult& r1, SprmResult& r2, SprmResult& r3, SprmResult& r4) const
3806 {
3807     if( !m_pPLCF )
3808         return false;
3809 
3810     bool bFound = false;
3811 
3812     sal_uInt8* pSp = m_pSprms.get();
3813     size_t i = 0;
3814     while (i + maSprmParser.MinSprmLen() <= m_nSprmSiz)
3815     {
3816         // Sprm found?
3817         const sal_uInt16 nCurrentId = maSprmParser.GetSprmId(pSp);
3818         sal_Int32 nRemLen = m_nSprmSiz - i;
3819         const sal_Int32 x = maSprmParser.GetSprmSize(nCurrentId, pSp, nRemLen);
3820         bool bValid = x <= nRemLen;
3821         if (!bValid)
3822         {
3823             SAL_WARN("sw.ww8", "sprm longer than remaining bytes, doc or parser is wrong");
3824             break;
3825         }
3826         bool bOk = true;
3827         if( nCurrentId  == nId1 )
3828         {
3829             sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId1);
3830             r1 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3831         }
3832         else if( nCurrentId  == nId2 )
3833         {
3834             sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId2);
3835             r2 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3836         }
3837         else if( nCurrentId  == nId3 )
3838         {
3839             sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId3);
3840             r3 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3841         }
3842         else if( nCurrentId  == nId4 )
3843         {
3844             sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId4);
3845             r4 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3846         }
3847         else
3848             bOk = false;
3849         bFound |= bOk;
3850         // increment pointer so that it points to next SPRM
3851         i += x;
3852         pSp += x;
3853     }
3854     return bFound;
3855 }
3856 
HasSprm(sal_uInt16 nId,sal_uInt8 n2nd) const3857 SprmResult WW8PLCFx_SEPX::HasSprm( sal_uInt16 nId, sal_uInt8 n2nd ) const
3858 {
3859     SprmResult aRet;
3860     if (m_pPLCF)
3861     {
3862         WW8SprmIter aIter(m_pSprms.get(), m_nSprmSiz, maSprmParser);
3863         aRet = aIter.FindSprm(nId, /*bFindFirst=*/true, &n2nd);
3864     }
3865     return aRet;
3866 }
3867 
WW8PLCFx_SubDoc(SvStream * pSt,const WW8Fib & rFib,WW8_CP nStartCp,tools::Long nFcRef,tools::Long nLenRef,tools::Long nFcText,tools::Long nLenText,tools::Long nStruct)3868 WW8PLCFx_SubDoc::WW8PLCFx_SubDoc(SvStream* pSt, const WW8Fib& rFib,
3869     WW8_CP nStartCp, tools::Long nFcRef, tools::Long nLenRef, tools::Long nFcText, tools::Long nLenText,
3870     tools::Long nStruct)
3871     : WW8PLCFx(rFib, true)
3872 {
3873     if( nLenRef && nLenText )
3874     {
3875         m_pRef.reset(new WW8PLCF(*pSt, nFcRef, nLenRef, nStruct, nStartCp));
3876         m_pText.reset(new WW8PLCF(*pSt, nFcText, nLenText, 0, nStartCp));
3877     }
3878 }
3879 
~WW8PLCFx_SubDoc()3880 WW8PLCFx_SubDoc::~WW8PLCFx_SubDoc()
3881 {
3882     m_pRef.reset();
3883     m_pText.reset();
3884 }
3885 
GetIdx() const3886 sal_uInt32 WW8PLCFx_SubDoc::GetIdx() const
3887 {
3888     // Probably pText ... no need for it
3889     if( m_pRef )
3890         return ( m_pRef->GetIdx() << 16 | m_pText->GetIdx() );
3891     return 0;
3892 }
3893 
SetIdx(sal_uInt32 nIdx)3894 void WW8PLCFx_SubDoc::SetIdx(sal_uInt32 nIdx)
3895 {
3896     if( m_pRef )
3897     {
3898         m_pRef->SetIdx( nIdx >> 16 );
3899         // Probably pText ... no need for it
3900         m_pText->SetIdx( nIdx & 0xFFFF );
3901     }
3902 }
3903 
SeekPos(WW8_CP nCpPos)3904 bool WW8PLCFx_SubDoc::SeekPos( WW8_CP nCpPos )
3905 {
3906     return m_pRef && m_pRef->SeekPos( nCpPos );
3907 }
3908 
Where()3909 WW8_CP WW8PLCFx_SubDoc::Where()
3910 {
3911     return m_pRef ? m_pRef->Where() : WW8_CP_MAX;
3912 }
3913 
GetSprms(WW8PLCFxDesc * p)3914 void WW8PLCFx_SubDoc::GetSprms(WW8PLCFxDesc* p)
3915 {
3916     p->nStartPos = p->nEndPos = WW8_CP_MAX;
3917     p->pMemPos = nullptr;
3918     p->nSprmsLen = 0;
3919     p->bRealLineEnd = false;
3920 
3921     if (!m_pRef)
3922         return;
3923 
3924     sal_uInt32 nNr = m_pRef->GetIdx();
3925 
3926     void *pData;
3927     WW8_CP nFoo;
3928     if (!m_pRef->Get(p->nStartPos, nFoo, pData))
3929     {
3930         p->nEndPos = p->nStartPos = WW8_CP_MAX;
3931         return;
3932     }
3933 
3934     if (o3tl::checked_add<WW8_CP>(p->nStartPos, 1, p->nEndPos))
3935     {
3936         SAL_WARN("sw.ww8", "broken offset, ignoring");
3937         p->nEndPos = p->nStartPos = WW8_CP_MAX;
3938         return;
3939     }
3940 
3941     if (!m_pText)
3942         return;
3943 
3944     m_pText->SetIdx(nNr);
3945 
3946     if (!m_pText->Get(p->nCp2OrIdx, p->nSprmsLen, pData))
3947     {
3948         p->nEndPos = p->nStartPos = WW8_CP_MAX;
3949         p->nSprmsLen = 0;
3950         return;
3951     }
3952 
3953     if (p->nCp2OrIdx < 0 || p->nCp2OrIdx > p->nSprmsLen)
3954     {
3955         SAL_WARN("sw.ww8", "Document has invalid Cp or Idx, ignoring it");
3956         p->nEndPos = p->nStartPos = WW8_CP_MAX;
3957         p->nSprmsLen = 0;
3958         return;
3959     }
3960 
3961     p->nSprmsLen -= p->nCp2OrIdx;
3962 }
3963 
advance()3964 void WW8PLCFx_SubDoc::advance()
3965 {
3966     if (m_pRef && m_pText)
3967     {
3968         m_pRef->advance();
3969         m_pText->advance();
3970     }
3971 }
3972 
3973 // fields
WW8PLCFx_FLD(SvStream * pSt,const WW8Fib & rMyFib,short nType)3974 WW8PLCFx_FLD::WW8PLCFx_FLD( SvStream* pSt, const WW8Fib& rMyFib, short nType)
3975     : WW8PLCFx(rMyFib, true), m_rFib(rMyFib)
3976 {
3977     WW8_FC nFc;
3978     sal_Int32 nLen;
3979 
3980     switch( nType )
3981     {
3982     case MAN_HDFT:
3983         nFc = m_rFib.m_fcPlcffldHdr;
3984         nLen = m_rFib.m_lcbPlcffldHdr;
3985         break;
3986     case MAN_FTN:
3987         nFc = m_rFib.m_fcPlcffldFootnote;
3988         nLen = m_rFib.m_lcbPlcffldFootnote;
3989         break;
3990     case MAN_EDN:
3991         nFc = m_rFib.m_fcPlcffldEdn;
3992         nLen = m_rFib.m_lcbPlcffldEdn;
3993         break;
3994     case MAN_AND:
3995         nFc = m_rFib.m_fcPlcffldAtn;
3996         nLen = m_rFib.m_lcbPlcffldAtn;
3997         break;
3998     case MAN_TXBX:
3999         nFc = m_rFib.m_fcPlcffldTxbx;
4000         nLen = m_rFib.m_lcbPlcffldTxbx;
4001         break;
4002     case MAN_TXBX_HDFT:
4003         nFc = m_rFib.m_fcPlcffldHdrTxbx;
4004         nLen = m_rFib.m_lcbPlcffldHdrTxbx;
4005         break;
4006     default:
4007         nFc = m_rFib.m_fcPlcffldMom;
4008         nLen = m_rFib.m_lcbPlcffldMom;
4009         break;
4010     }
4011 
4012     if( nLen )
4013         m_pPLCF.reset( new WW8PLCFspecial( pSt, nFc, nLen, 2 ) );
4014 }
4015 
~WW8PLCFx_FLD()4016 WW8PLCFx_FLD::~WW8PLCFx_FLD()
4017 {
4018 }
4019 
GetIdx() const4020 sal_uInt32 WW8PLCFx_FLD::GetIdx() const
4021 {
4022     return m_pPLCF ? m_pPLCF->GetIdx() : 0;
4023 }
4024 
SetIdx(sal_uInt32 nIdx)4025 void WW8PLCFx_FLD::SetIdx(sal_uInt32 nIdx)
4026 {
4027     if( m_pPLCF )
4028         m_pPLCF->SetIdx( nIdx );
4029 }
4030 
SeekPos(WW8_CP nCpPos)4031 bool WW8PLCFx_FLD::SeekPos(WW8_CP nCpPos)
4032 {
4033     return m_pPLCF && m_pPLCF->SeekPosExact( nCpPos );
4034 }
4035 
Where()4036 WW8_CP WW8PLCFx_FLD::Where()
4037 {
4038     return m_pPLCF ? m_pPLCF->Where() : WW8_CP_MAX;
4039 }
4040 
StartPosIsFieldStart()4041 bool WW8PLCFx_FLD::StartPosIsFieldStart()
4042 {
4043     void* pData;
4044     sal_Int32 nTest;
4045     return m_pPLCF && m_pPLCF->Get(nTest, pData) && ((static_cast<sal_uInt8*>(pData)[0] & 0x1f) == 0x13);
4046 }
4047 
EndPosIsFieldEnd(WW8_CP & nCP)4048 bool WW8PLCFx_FLD::EndPosIsFieldEnd(WW8_CP& nCP)
4049 {
4050     bool bRet = false;
4051 
4052     if (m_pPLCF)
4053     {
4054         tools::Long n = m_pPLCF->GetIdx();
4055 
4056         m_pPLCF->advance();
4057 
4058         void* pData;
4059         sal_Int32 nTest;
4060         if ( m_pPLCF->Get(nTest, pData) && ((static_cast<sal_uInt8*>(pData)[0] & 0x1f) == 0x15) )
4061         {
4062             nCP = nTest;
4063             bRet = true;
4064         }
4065 
4066         m_pPLCF->SetIdx(n);
4067     }
4068 
4069     return bRet;
4070 }
4071 
GetSprms(WW8PLCFxDesc * p)4072 void WW8PLCFx_FLD::GetSprms(WW8PLCFxDesc* p)
4073 {
4074     p->nStartPos = p->nEndPos = WW8_CP_MAX;
4075     p->pMemPos = nullptr;
4076     p->nSprmsLen = 0;
4077     p->bRealLineEnd = false;
4078 
4079     if (!m_pPLCF)
4080     {
4081         p->nStartPos = WW8_CP_MAX;                    // there are no fields
4082         return;
4083     }
4084 
4085     tools::Long n = m_pPLCF->GetIdx();
4086 
4087     sal_Int32 nP;
4088     void *pData;
4089     if (!m_pPLCF->Get(nP, pData))             // end of PLCFspecial?
4090     {
4091         p->nStartPos = WW8_CP_MAX;            // PLCF completely processed
4092         return;
4093     }
4094 
4095     p->nStartPos = nP;
4096 
4097     m_pPLCF->advance();
4098     if (!m_pPLCF->Get(nP, pData))             // end of PLCFspecial?
4099     {
4100         p->nStartPos = WW8_CP_MAX;            // PLCF completely processed
4101         return;
4102     }
4103 
4104     p->nEndPos = nP;
4105 
4106     m_pPLCF->SetIdx(n);
4107 
4108     p->nCp2OrIdx = m_pPLCF->GetIdx();
4109 }
4110 
advance()4111 void WW8PLCFx_FLD::advance()
4112 {
4113     SAL_WARN_IF(!m_pPLCF, "sw.ww8", "Call without PLCFspecial field");
4114     if( !m_pPLCF )
4115         return;
4116     m_pPLCF->advance();
4117 }
4118 
GetPara(tools::Long nIdx,WW8FieldDesc & rF)4119 bool WW8PLCFx_FLD::GetPara(tools::Long nIdx, WW8FieldDesc& rF)
4120 {
4121     SAL_WARN_IF(!m_pPLCF, "sw.ww8", "Call without PLCFspecial field");
4122     if( !m_pPLCF )
4123         return false;
4124 
4125     tools::Long n = m_pPLCF->GetIdx();
4126     m_pPLCF->SetIdx(nIdx);
4127 
4128     bool bOk = WW8GetFieldPara(*m_pPLCF, rF);
4129 
4130     m_pPLCF->SetIdx(n);
4131     return bOk;
4132 }
4133 
4134 // WW8PLCF_Book
WW8ReadSTTBF(bool bVer8,SvStream & rStrm,sal_uInt32 nStart,sal_Int32 nLen,sal_uInt16 nExtraLen,rtl_TextEncoding eCS,std::vector<OUString> & rArray,std::vector<ww::bytes> * pExtraArray,std::vector<OUString> * pValueArray)4135 void WW8ReadSTTBF(bool bVer8, SvStream& rStrm, sal_uInt32 nStart, sal_Int32 nLen,
4136     sal_uInt16 nExtraLen, rtl_TextEncoding eCS, std::vector<OUString> &rArray,
4137     std::vector<ww::bytes>* pExtraArray, std::vector<OUString>* pValueArray)
4138 {
4139     if (nLen==0)     // Handle Empty STTBF
4140         return;
4141 
4142     sal_uInt64 const nOldPos = rStrm.Tell();
4143     if (checkSeek(rStrm, nStart))
4144     {
4145         sal_uInt16 nLen2(0);
4146         rStrm.ReadUInt16( nLen2 ); // bVer67: total length of structure
4147                         // bVer8 : count of strings
4148 
4149         if( bVer8 )
4150         {
4151             sal_uInt16 nStrings(0);
4152             bool bUnicode = (0xFFFF == nLen2);
4153             if (bUnicode)
4154                 rStrm.ReadUInt16( nStrings );
4155             else
4156                 nStrings = nLen2;
4157 
4158             rStrm.ReadUInt16( nExtraLen );
4159 
4160             const size_t nMinStringLen = bUnicode ? sizeof(sal_uInt16) : sizeof(sal_uInt8);
4161             const size_t nMinRecordSize = nExtraLen + nMinStringLen;
4162             assert(nMinRecordSize != 0 && "impossible to be zero");
4163             const size_t nMaxPossibleStrings = rStrm.remainingSize() / nMinRecordSize;
4164             if (nStrings > nMaxPossibleStrings)
4165             {
4166                 SAL_WARN("sw.ww8", "STTBF claims " << nStrings << " entries, but only " << nMaxPossibleStrings << " are possible");
4167                 nStrings = nMaxPossibleStrings;
4168             }
4169 
4170             if (nExtraLen && nStrings)
4171             {
4172                 const size_t nMaxExtraLen = (rStrm.remainingSize() - (nStrings * nMinStringLen)) / nStrings;
4173                 if (nExtraLen > nMaxExtraLen)
4174                 {
4175                     SAL_WARN("sw.ww8", "STTBF claims " << nMaxExtraLen << " extra len, but only " << nMaxExtraLen << " are possible");
4176                     nExtraLen = nMaxExtraLen;
4177                 }
4178             }
4179 
4180             for (sal_uInt16 i=0; i < nStrings; ++i)
4181             {
4182                 if (bUnicode)
4183                     rArray.push_back(read_uInt16_PascalString(rStrm));
4184                 else
4185                 {
4186                     OString aTmp = read_uInt8_lenPrefixed_uInt8s_ToOString(rStrm);
4187                     rArray.push_back(OStringToOUString(aTmp, eCS));
4188                 }
4189 
4190                 // Skip the extra data
4191                 if (nExtraLen)
4192                 {
4193                     if (pExtraArray)
4194                     {
4195                         ww::bytes extraData(nExtraLen);
4196                         rStrm.ReadBytes(extraData.data(), nExtraLen);
4197                         pExtraArray->push_back(extraData);
4198                     }
4199                     else
4200                         rStrm.SeekRel( nExtraLen );
4201                 }
4202             }
4203             // read the value of the document variables, if requested.
4204             if (pValueArray)
4205             {
4206                 for (sal_uInt16 i=0; i < nStrings; ++i)
4207                 {
4208                     if( bUnicode )
4209                         pValueArray->push_back(read_uInt16_PascalString(rStrm));
4210                     else
4211                     {
4212                         OString aTmp = read_uInt8_lenPrefixed_uInt8s_ToOString(rStrm);
4213                         pValueArray->push_back(OStringToOUString(aTmp, eCS));
4214                     }
4215                 }
4216             }
4217         }
4218         else
4219         {
4220             if( nLen2 != nLen )
4221             {
4222                 OSL_ENSURE(nLen2 == nLen,
4223                     "Fib length and read length are different");
4224                 if (nLen > SAL_MAX_UINT16)
4225                     nLen = SAL_MAX_UINT16;
4226                 else if (nLen < 2 )
4227                     nLen = 2;
4228                 nLen2 = o3tl::narrowing<sal_uInt16>(nLen);
4229             }
4230             sal_uLong nRead = 0;
4231             for( nLen2 -= 2; nRead < nLen2;  )
4232             {
4233                 sal_uInt8 nBChar(0);
4234                 rStrm.ReadUChar( nBChar );
4235                 ++nRead;
4236                 if (nBChar)
4237                 {
4238                     OString aTmp = read_uInt8s_ToOString(rStrm, nBChar);
4239                     nRead += aTmp.getLength();
4240                     rArray.push_back(OStringToOUString(aTmp, eCS));
4241                 }
4242                 else
4243                     rArray.emplace_back();
4244 
4245                 // Skip the extra data (for bVer67 versions this must come from
4246                 // external knowledge)
4247                 if (nExtraLen)
4248                 {
4249                     if (pExtraArray)
4250                     {
4251                         ww::bytes extraData(nExtraLen);
4252                         rStrm.ReadBytes(extraData.data(), nExtraLen);
4253                         pExtraArray->push_back(extraData);
4254                     }
4255                     else
4256                         rStrm.SeekRel( nExtraLen );
4257                     nRead+=nExtraLen;
4258                 }
4259             }
4260         }
4261     }
4262     rStrm.Seek(nOldPos);
4263 }
4264 
WW8PLCFx_Book(SvStream * pTableSt,const WW8Fib & rFib)4265 WW8PLCFx_Book::WW8PLCFx_Book(SvStream* pTableSt, const WW8Fib& rFib)
4266     : WW8PLCFx(rFib, false), m_nIsEnd(0), m_nBookmarkId(1)
4267 {
4268     if( !rFib.m_fcPlcfbkf || !rFib.m_lcbPlcfbkf || !rFib.m_fcPlcfbkl ||
4269         !rFib.m_lcbPlcfbkl || !rFib.m_fcSttbfbkmk || !rFib.m_lcbSttbfbkmk )
4270     {
4271         m_nIMax = 0;
4272     }
4273     else
4274     {
4275         m_pBook[0].reset( new WW8PLCFspecial(pTableSt,rFib.m_fcPlcfbkf,rFib.m_lcbPlcfbkf,4) );
4276 
4277         m_pBook[1].reset( new WW8PLCFspecial(pTableSt,rFib.m_fcPlcfbkl,rFib.m_lcbPlcfbkl,0) );
4278 
4279         rtl_TextEncoding eStructChrSet = WW8Fib::GetFIBCharset(rFib.m_chseTables, rFib.m_lid);
4280 
4281         WW8ReadSTTBF( (7 < rFib.m_nVersion), *pTableSt, rFib.m_fcSttbfbkmk,
4282             rFib.m_lcbSttbfbkmk, 0, eStructChrSet, m_aBookNames );
4283 
4284         m_nIMax = m_aBookNames.size();
4285 
4286         if( m_pBook[0]->GetIMax() < m_nIMax )   // Count of Bookmarks
4287             m_nIMax = m_pBook[0]->GetIMax();
4288         if( m_pBook[1]->GetIMax() < m_nIMax )
4289             m_nIMax = m_pBook[1]->GetIMax();
4290         m_aStatus.resize(m_nIMax);
4291     }
4292 }
4293 
~WW8PLCFx_Book()4294 WW8PLCFx_Book::~WW8PLCFx_Book()
4295 {
4296 }
4297 
GetIdx() const4298 sal_uInt32 WW8PLCFx_Book::GetIdx() const
4299 {
4300     return m_nIMax ? m_pBook[0]->GetIdx() : 0;
4301 }
4302 
SetIdx(sal_uInt32 nI)4303 void WW8PLCFx_Book::SetIdx(sal_uInt32 nI)
4304 {
4305     if( m_nIMax )
4306         m_pBook[0]->SetIdx( nI );
4307 }
4308 
GetIdx2() const4309 sal_uInt32 WW8PLCFx_Book::GetIdx2() const
4310 {
4311     return m_nIMax ? ( m_pBook[1]->GetIdx() | ( m_nIsEnd ? 0x80000000 : 0 ) ) : 0;
4312 }
4313 
SetIdx2(sal_uInt32 nI)4314 void WW8PLCFx_Book::SetIdx2(sal_uInt32 nI)
4315 {
4316     if( m_nIMax )
4317     {
4318         m_pBook[1]->SetIdx( nI & 0x7fffffff );
4319         m_nIsEnd = o3tl::narrowing<sal_uInt16>( ( nI >> 31 ) & 1 );  // 0 or 1
4320     }
4321 }
4322 
SeekPos(WW8_CP nCpPos)4323 bool WW8PLCFx_Book::SeekPos(WW8_CP nCpPos)
4324 {
4325     if( !m_pBook[0] )
4326         return false;
4327 
4328     bool bOk = m_pBook[0]->SeekPosExact( nCpPos );
4329     bOk &= m_pBook[1]->SeekPosExact( nCpPos );
4330     m_nIsEnd = 0;
4331 
4332     return bOk;
4333 }
4334 
Where()4335 WW8_CP WW8PLCFx_Book::Where()
4336 {
4337     return m_pBook[m_nIsEnd]->Where();
4338 }
4339 
GetNoSprms(WW8_CP & rStart,WW8_CP & rEnd,sal_Int32 & rLen)4340 tools::Long WW8PLCFx_Book::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
4341 {
4342     void* pData;
4343     rEnd = WW8_CP_MAX;
4344     rLen = 0;
4345 
4346     if (!m_pBook[0] || !m_pBook[1] || !m_nIMax || (m_pBook[m_nIsEnd]->GetIdx()) >= m_nIMax)
4347     {
4348         rStart = rEnd = WW8_CP_MAX;
4349         return -1;
4350     }
4351 
4352     (void)m_pBook[m_nIsEnd]->Get( rStart, pData );    // query position
4353     return m_pBook[m_nIsEnd]->GetIdx();
4354 }
4355 
4356 // The operator ++ has a pitfall: If 2 bookmarks adjoin each other,
4357 // we should first go to the end of the first one
4358 // and then to the beginning of the second one.
4359 // But if 2 bookmarks with the length of 0 lie on top of each other,
4360 // we *must* first find the start and end of each bookmark.
4361 // The case of: ][
4362 //               [...]
4363 //              ][
4364 // is not solved yet.
4365 // Because I must jump back and forth in the start- and end-indices then.
4366 // This would require one more index or bitfield to remember
4367 // the already processed bookmarks.
4368 
advance()4369 void WW8PLCFx_Book::advance()
4370 {
4371     if( !(m_pBook[0] && m_pBook[1] && m_nIMax) )
4372         return;
4373 
4374     (*m_pBook[m_nIsEnd]).advance();
4375 
4376     sal_uLong l0 = m_pBook[0]->Where();
4377     sal_uLong l1 = m_pBook[1]->Where();
4378     if( l0 < l1 )
4379         m_nIsEnd = 0;
4380     else if( l1 < l0 )
4381         m_nIsEnd = 1;
4382     else
4383     {
4384         const void * p = m_pBook[0]->GetData(m_pBook[0]->GetIdx());
4385         tools::Long nPairFor = (p == nullptr) ? 0 : SVBT16ToUInt16(*static_cast<SVBT16 const *>(p));
4386         if (nPairFor == m_pBook[1]->GetIdx())
4387             m_nIsEnd = 0;
4388         else
4389             m_nIsEnd = m_nIsEnd ? 0 : 1;
4390     }
4391 }
4392 
GetLen() const4393 tools::Long WW8PLCFx_Book::GetLen() const
4394 {
4395     if( m_nIsEnd )
4396     {
4397         OSL_ENSURE( false, "Incorrect call (1) of PLCF_Book::GetLen()" );
4398         return 0;
4399     }
4400     void * p;
4401     WW8_CP nStartPos;
4402     if( !m_pBook[0]->Get( nStartPos, p ) )
4403     {
4404         OSL_ENSURE( false, "Incorrect call (2) of PLCF_Book::GetLen()" );
4405         return 0;
4406     }
4407     const sal_uInt16 nEndIdx = SVBT16ToUInt16( *static_cast<SVBT16*>(p) );
4408     tools::Long nNum = m_pBook[1]->GetPos( nEndIdx );
4409     nNum -= nStartPos;
4410     return nNum;
4411 }
4412 
SetStatus(sal_uInt16 nIndex,eBookStatus eStat)4413 void WW8PLCFx_Book::SetStatus(sal_uInt16 nIndex, eBookStatus eStat)
4414 {
4415     SAL_WARN_IF(nIndex >= m_nIMax, "sw.ww8",
4416                 "bookmark index " << nIndex << " invalid");
4417     eBookStatus eStatus = m_aStatus.at(nIndex);
4418     m_aStatus[nIndex] = static_cast<eBookStatus>(eStatus | eStat);
4419 }
4420 
GetStatus() const4421 eBookStatus WW8PLCFx_Book::GetStatus() const
4422 {
4423     if (m_aStatus.empty())
4424         return BOOK_NORMAL;
4425     tools::Long nEndIdx = GetHandle();
4426     return ( nEndIdx < m_nIMax ) ? m_aStatus[nEndIdx] : BOOK_NORMAL;
4427 }
4428 
GetHandle() const4429 tools::Long WW8PLCFx_Book::GetHandle() const
4430 {
4431     if( !m_pBook[0] || !m_pBook[1] )
4432         return LONG_MAX;
4433 
4434     if( m_nIsEnd )
4435         return m_pBook[1]->GetIdx();
4436     else
4437     {
4438         if (const void* p = m_pBook[0]->GetData(m_pBook[0]->GetIdx()))
4439             return SVBT16ToUInt16( *static_cast<SVBT16 const *>(p) );
4440         else
4441             return LONG_MAX;
4442     }
4443 }
4444 
GetBookmark(tools::Long nStart,tools::Long nEnd,sal_uInt16 & nIndex)4445 OUString WW8PLCFx_Book::GetBookmark(tools::Long nStart,tools::Long nEnd, sal_uInt16 &nIndex)
4446 {
4447     bool bFound = false;
4448     sal_uInt16 i = 0;
4449     if (m_pBook[0] && m_pBook[1])
4450     {
4451         WW8_CP nStartCurrent, nEndCurrent;
4452         while (sal::static_int_cast<decltype(m_aBookNames)::size_type>(i) < m_aBookNames.size())
4453         {
4454             void* p;
4455             sal_uInt16 nEndIdx;
4456 
4457             if( m_pBook[0]->GetData( i, nStartCurrent, p ) && p )
4458                 nEndIdx = SVBT16ToUInt16( *static_cast<SVBT16*>(p) );
4459             else
4460             {
4461                 OSL_ENSURE( false, "Bookmark-EndIdx not readable" );
4462                 nEndIdx = i;
4463             }
4464 
4465             nEndCurrent = m_pBook[1]->GetPos( nEndIdx );
4466 
4467             if ((nStartCurrent >= nStart) && (nEndCurrent <= nEnd))
4468             {
4469                 nIndex = i;
4470                 bFound=true;
4471                 break;
4472             }
4473             ++i;
4474         }
4475     }
4476     return bFound ? m_aBookNames[i] : OUString();
4477 }
4478 
GetUniqueBookmarkName(const OUString & rSuggestedName)4479 OUString WW8PLCFx_Book::GetUniqueBookmarkName(const OUString &rSuggestedName)
4480 {
4481     OUString aRet(rSuggestedName.isEmpty() ? u"Unnamed"_ustr : rSuggestedName);
4482     size_t i = 0;
4483     while (i < m_aBookNames.size())
4484     {
4485         if (aRet == m_aBookNames[i])
4486         {
4487             sal_Int32 len = aRet.getLength();
4488             sal_Int32 p = len - 1;
4489             while (p > 0 && aRet[p] >= '0' && aRet[p] <= '9')
4490                 --p;
4491             aRet = aRet.subView(0, p+1) + OUString::number(m_nBookmarkId++);
4492             i = 0; // start search from beginning
4493         }
4494         else
4495             ++i;
4496     }
4497     return aRet;
4498 }
4499 
MapName(OUString & rName)4500 void WW8PLCFx_Book::MapName(OUString& rName)
4501 {
4502     if( !m_pBook[0] || !m_pBook[1] )
4503         return;
4504 
4505     size_t i = 0;
4506     while (i < m_aBookNames.size())
4507     {
4508         if (rName.equalsIgnoreAsciiCase(m_aBookNames[i]))
4509         {
4510             rName = m_aBookNames[i];
4511             break;
4512         }
4513         ++i;
4514     }
4515 }
4516 
GetName() const4517 const OUString* WW8PLCFx_Book::GetName() const
4518 {
4519     const OUString *pRet = nullptr;
4520     if (!m_nIsEnd && (m_pBook[0]->GetIdx() < m_nIMax))
4521         pRet = &(m_aBookNames[m_pBook[0]->GetIdx()]);
4522     return pRet;
4523 }
4524 
WW8PLCFx_AtnBook(SvStream * pTableSt,const WW8Fib & rFib)4525 WW8PLCFx_AtnBook::WW8PLCFx_AtnBook(SvStream* pTableSt, const WW8Fib& rFib)
4526     : WW8PLCFx(rFib, /*bSprm=*/false),
4527     m_bIsEnd(false)
4528 {
4529     if (!rFib.m_fcPlcfAtnbkf || !rFib.m_lcbPlcfAtnbkf || !rFib.m_fcPlcfAtnbkl || !rFib.m_lcbPlcfAtnbkl)
4530     {
4531         m_nIMax = 0;
4532     }
4533     else
4534     {
4535         m_pBook[0].reset( new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfAtnbkf, rFib.m_lcbPlcfAtnbkf, 4) );
4536         m_pBook[1].reset( new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfAtnbkl, rFib.m_lcbPlcfAtnbkl, 0) );
4537 
4538         m_nIMax = m_pBook[0]->GetIMax();
4539         if (m_pBook[1]->GetIMax() < m_nIMax)
4540             m_nIMax = m_pBook[1]->GetIMax();
4541     }
4542 }
4543 
~WW8PLCFx_AtnBook()4544 WW8PLCFx_AtnBook::~WW8PLCFx_AtnBook()
4545 {
4546 }
4547 
GetIdx() const4548 sal_uInt32 WW8PLCFx_AtnBook::GetIdx() const
4549 {
4550     return m_nIMax ? m_pBook[0]->GetIdx() : 0;
4551 }
4552 
SetIdx(sal_uInt32 nI)4553 void WW8PLCFx_AtnBook::SetIdx(sal_uInt32 nI)
4554 {
4555     if( m_nIMax )
4556         m_pBook[0]->SetIdx( nI );
4557 }
4558 
GetIdx2() const4559 sal_uInt32 WW8PLCFx_AtnBook::GetIdx2() const
4560 {
4561     if (m_nIMax)
4562         return m_pBook[1]->GetIdx() | ( m_bIsEnd ? 0x80000000 : 0 );
4563     else
4564         return 0;
4565 }
4566 
SetIdx2(sal_uInt32 nI)4567 void WW8PLCFx_AtnBook::SetIdx2(sal_uInt32 nI)
4568 {
4569     if( m_nIMax )
4570     {
4571         m_pBook[1]->SetIdx( nI & 0x7fffffff );
4572         m_bIsEnd = static_cast<bool>(( nI >> 31 ) & 1);
4573     }
4574 }
4575 
SeekPos(WW8_CP nCpPos)4576 bool WW8PLCFx_AtnBook::SeekPos(WW8_CP nCpPos)
4577 {
4578     if (!m_pBook[0])
4579         return false;
4580 
4581     bool bOk = m_pBook[0]->SeekPosExact(nCpPos);
4582     bOk &= m_pBook[1]->SeekPosExact(nCpPos);
4583     m_bIsEnd = false;
4584 
4585     return bOk;
4586 }
4587 
Where()4588 WW8_CP WW8PLCFx_AtnBook::Where()
4589 {
4590     return m_pBook[static_cast<int>(m_bIsEnd)]->Where();
4591 }
4592 
GetNoSprms(WW8_CP & rStart,WW8_CP & rEnd,sal_Int32 & rLen)4593 tools::Long WW8PLCFx_AtnBook::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
4594 {
4595     void* pData;
4596     rEnd = WW8_CP_MAX;
4597     rLen = 0;
4598 
4599     if (!m_pBook[0] || !m_pBook[1] || !m_nIMax || (m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx()) >= m_nIMax)
4600     {
4601         rStart = rEnd = WW8_CP_MAX;
4602         return -1;
4603     }
4604 
4605     (void)m_pBook[static_cast<int>(m_bIsEnd)]->Get(rStart, pData);
4606     return m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx();
4607 }
4608 
advance()4609 void WW8PLCFx_AtnBook::advance()
4610 {
4611     if( !(m_pBook[0] && m_pBook[1] && m_nIMax) )
4612         return;
4613 
4614     (*m_pBook[static_cast<int>(m_bIsEnd)]).advance();
4615 
4616     sal_uLong l0 = m_pBook[0]->Where();
4617     sal_uLong l1 = m_pBook[1]->Where();
4618     if( l0 < l1 )
4619         m_bIsEnd = false;
4620     else if( l1 < l0 )
4621         m_bIsEnd = true;
4622     else
4623     {
4624         const void * p = m_pBook[0]->GetData(m_pBook[0]->GetIdx());
4625         tools::Long nPairFor = (p == nullptr) ? 0 : SVBT16ToUInt16(*static_cast<SVBT16 const *>(p));
4626         if (nPairFor == m_pBook[1]->GetIdx())
4627             m_bIsEnd = false;
4628         else
4629             m_bIsEnd = !m_bIsEnd;
4630     }
4631 }
4632 
getHandle() const4633 tools::Long WW8PLCFx_AtnBook::getHandle() const
4634 {
4635     if (!m_pBook[0] || !m_pBook[1])
4636         return LONG_MAX;
4637 
4638     if (m_bIsEnd)
4639         return m_pBook[1]->GetIdx();
4640     else
4641     {
4642         if (const void* p = m_pBook[0]->GetData(m_pBook[0]->GetIdx()))
4643             return SVBT16ToUInt16(*static_cast<const SVBT16*>(p));
4644         else
4645             return LONG_MAX;
4646     }
4647 }
4648 
getIsEnd() const4649 bool WW8PLCFx_AtnBook::getIsEnd() const
4650 {
4651     return m_bIsEnd;
4652 }
4653 
WW8PLCFx_FactoidBook(SvStream * pTableSt,const WW8Fib & rFib)4654 WW8PLCFx_FactoidBook::WW8PLCFx_FactoidBook(SvStream* pTableSt, const WW8Fib& rFib)
4655     : WW8PLCFx(rFib, /*bSprm=*/false),
4656     m_bIsEnd(false)
4657 {
4658     if (!rFib.m_fcPlcfBkfFactoid || !rFib.m_lcbPlcfBkfFactoid || !rFib.m_fcPlcfBklFactoid || !rFib.m_lcbPlcfBklFactoid)
4659     {
4660         m_nIMax = 0;
4661     }
4662     else
4663     {
4664         m_pBook[0].reset(new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfBkfFactoid, rFib.m_lcbPlcfBkfFactoid, 6));
4665         m_pBook[1].reset(new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfBklFactoid, rFib.m_lcbPlcfBklFactoid, 4));
4666 
4667         m_nIMax = m_pBook[0]->GetIMax();
4668         if (m_pBook[1]->GetIMax() < m_nIMax)
4669             m_nIMax = m_pBook[1]->GetIMax();
4670     }
4671 }
4672 
~WW8PLCFx_FactoidBook()4673 WW8PLCFx_FactoidBook::~WW8PLCFx_FactoidBook()
4674 {
4675 }
4676 
GetIdx() const4677 sal_uInt32 WW8PLCFx_FactoidBook::GetIdx() const
4678 {
4679     return m_nIMax ? m_pBook[0]->GetIdx() : 0;
4680 }
4681 
SetIdx(sal_uInt32 nI)4682 void WW8PLCFx_FactoidBook::SetIdx(sal_uInt32 nI)
4683 {
4684     if (m_nIMax)
4685         m_pBook[0]->SetIdx(nI);
4686 }
4687 
GetIdx2() const4688 sal_uInt32 WW8PLCFx_FactoidBook::GetIdx2() const
4689 {
4690     if (m_nIMax)
4691         return m_pBook[1]->GetIdx() | (m_bIsEnd ? 0x80000000 : 0);
4692     else
4693         return 0;
4694 }
4695 
SetIdx2(sal_uInt32 nI)4696 void WW8PLCFx_FactoidBook::SetIdx2(sal_uInt32 nI)
4697 {
4698     if (m_nIMax)
4699     {
4700         m_pBook[1]->SetIdx(nI & 0x7fffffff);
4701         m_bIsEnd = static_cast<bool>((nI >> 31) & 1);
4702     }
4703 }
4704 
SeekPos(WW8_CP nCpPos)4705 bool WW8PLCFx_FactoidBook::SeekPos(WW8_CP nCpPos)
4706 {
4707     if (!m_pBook[0])
4708         return false;
4709 
4710     bool bOk = m_pBook[0]->SeekPosExact(nCpPos);
4711     bOk &= m_pBook[1]->SeekPosExact(nCpPos);
4712     m_bIsEnd = false;
4713 
4714     return bOk;
4715 }
4716 
Where()4717 WW8_CP WW8PLCFx_FactoidBook::Where()
4718 {
4719     return m_pBook[static_cast<int>(m_bIsEnd)]->Where();
4720 }
4721 
GetNoSprms(WW8_CP & rStart,WW8_CP & rEnd,sal_Int32 & rLen)4722 tools::Long WW8PLCFx_FactoidBook::GetNoSprms(WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen)
4723 {
4724     void* pData;
4725     rEnd = WW8_CP_MAX;
4726     rLen = 0;
4727 
4728     if (!m_pBook[0] || !m_pBook[1] || !m_nIMax || (m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx()) >= m_nIMax)
4729     {
4730         rStart = rEnd = WW8_CP_MAX;
4731         return -1;
4732     }
4733 
4734     (void)m_pBook[static_cast<int>(m_bIsEnd)]->Get(rStart, pData);
4735     return m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx();
4736 }
4737 
advance()4738 void WW8PLCFx_FactoidBook::advance()
4739 {
4740     if (!(m_pBook[0] && m_pBook[1] && m_nIMax))
4741         return;
4742 
4743     (*m_pBook[static_cast<int>(m_bIsEnd)]).advance();
4744 
4745     sal_uLong l0 = m_pBook[0]->Where();
4746     sal_uLong l1 = m_pBook[1]->Where();
4747     if (l0 < l1)
4748         m_bIsEnd = false;
4749     else if (l1 < l0)
4750         m_bIsEnd = true;
4751     else
4752     {
4753         const void * p = m_pBook[0]->GetData(m_pBook[0]->GetIdx());
4754         tools::Long nPairFor = (p == nullptr) ? 0 : SVBT16ToUInt16(*static_cast<SVBT16 const *>(p));
4755         if (nPairFor == m_pBook[1]->GetIdx())
4756             m_bIsEnd = false;
4757         else
4758             m_bIsEnd = !m_bIsEnd;
4759     }
4760 }
4761 
getHandle() const4762 tools::Long WW8PLCFx_FactoidBook::getHandle() const
4763 {
4764     if (!m_pBook[0] || !m_pBook[1])
4765         return LONG_MAX;
4766 
4767     if (m_bIsEnd)
4768         return m_pBook[1]->GetIdx();
4769     else
4770     {
4771         if (const void* p = m_pBook[0]->GetData(m_pBook[0]->GetIdx()))
4772             return SVBT16ToUInt16(*static_cast<const SVBT16*>(p));
4773         else
4774             return LONG_MAX;
4775     }
4776 }
4777 
getIsEnd() const4778 bool WW8PLCFx_FactoidBook::getIsEnd() const
4779 {
4780     return m_bIsEnd;
4781 }
4782 
4783 // In the end of a paragraph in WW6 the attribute extends after the <CR>.
4784 // This will be reset by one character to be used with SW,
4785 // if we don't expect trouble thereby.
AdjustEnds(WW8PLCFxDesc & rDesc)4786 void WW8PLCFMan::AdjustEnds( WW8PLCFxDesc& rDesc )
4787 {
4788     // might be necessary to do this for pChp and/or pSep as well,
4789     // but its definitely the case for paragraphs that EndPos > StartPos
4790     // for a well formed paragraph as those always have a paragraph
4791     // <cr> in them
4792     if (&rDesc == m_pPap && rDesc.bRealLineEnd)
4793     {
4794         if (rDesc.nStartPos == rDesc.nEndPos && rDesc.nEndPos != WW8_CP_MAX)
4795         {
4796             SAL_WARN("sw.ww8", "WW8PLCFxDesc End same as Start, abandoning to avoid looping");
4797             rDesc.nEndPos = WW8_CP_MAX;
4798         }
4799     }
4800 
4801     //Store old end position for supercool new property finder that uses
4802     //cp instead of fc's as nature intended
4803     rDesc.nOrigEndPos = rDesc.nEndPos;
4804     rDesc.nOrigStartPos = rDesc.nStartPos;
4805 
4806     /*
4807      Normally given ^XXX{para end}^ we don't actually insert a para end
4808      character into the document, so we clip the para end property one to the
4809      left to make the para properties end when the paragraph text does. In a
4810      drawing textbox we actually do insert a para end character, so we don't
4811      clip it. Making the para end properties end after the para end char.
4812     */
4813     if (GetDoingDrawTextBox())
4814         return;
4815 
4816     if ( (&rDesc == m_pPap) && rDesc.bRealLineEnd )
4817     {
4818         if ( m_pPap->nEndPos != WW8_CP_MAX )    // Para adjust
4819         {
4820             m_nLineEnd = m_pPap->nEndPos;// nLineEnd points *after* the <CR>
4821             m_pPap->nEndPos--;        // shorten paragraph end by one character
4822 
4823             // Is there already a sep end, which points to the current paragraph end?
4824             // Then we also must shorten by one character
4825             if( m_pSep->nEndPos == m_nLineEnd )
4826                 m_pSep->nEndPos--;
4827         }
4828     }
4829     else if (&rDesc == m_pSep)
4830     {
4831         // Sep Adjust if end Char-Attr == paragraph end ...
4832         if( (rDesc.nEndPos == m_nLineEnd) && (rDesc.nEndPos > rDesc.nStartPos) )
4833             rDesc.nEndPos--;            // ... then shorten by one character
4834     }
4835 }
4836 
ReduceByOffset()4837 void WW8PLCFxDesc::ReduceByOffset()
4838 {
4839     SAL_WARN_IF(WW8_CP_MAX != nStartPos && nStartPos > nEndPos, "sw.ww8",
4840                 "End " << nEndPos << " before Start " << nStartPos);
4841 
4842     if( nStartPos != WW8_CP_MAX )
4843     {
4844         /*
4845         ##516##,##517##
4846         Force the property change to happen at the beginning of this
4847         subdocument, same as in GetNewNoSprms, except that the target type is
4848         attributes attached to a piece that might span subdocument boundaries
4849         */
4850         if (nCpOfs > nStartPos)
4851             nStartPos = 0;
4852         else
4853             nStartPos -= nCpOfs;
4854     }
4855     if (nEndPos != WW8_CP_MAX)
4856     {
4857         if (nCpOfs > nEndPos)
4858         {
4859             SAL_WARN("sw.ww8", "broken subdocument piece entry");
4860             nEndPos = WW8_CP_MAX;
4861         }
4862         else
4863             nEndPos -= nCpOfs;
4864     }
4865 }
4866 
GetNewSprms(WW8PLCFxDesc & rDesc)4867 void WW8PLCFMan::GetNewSprms( WW8PLCFxDesc& rDesc )
4868 {
4869     rDesc.pPLCFx->GetSprms(&rDesc);
4870     rDesc.ReduceByOffset();
4871 
4872     rDesc.bFirstSprm = true;
4873     AdjustEnds( rDesc );
4874     rDesc.nOrigSprmsLen = rDesc.nSprmsLen;
4875 }
4876 
GetNewNoSprms(WW8PLCFxDesc & rDesc)4877 void WW8PLCFMan::GetNewNoSprms( WW8PLCFxDesc& rDesc )
4878 {
4879     rDesc.nCp2OrIdx = rDesc.pPLCFx->GetNoSprms(rDesc.nStartPos, rDesc.nEndPos,
4880         rDesc.nSprmsLen);
4881 
4882     SAL_WARN_IF(WW8_CP_MAX != rDesc.nStartPos && rDesc.nStartPos > rDesc.nEndPos, "sw.ww8",
4883                 "End " << rDesc.nEndPos << " before Start " << rDesc.nStartPos);
4884 
4885     rDesc.ReduceByOffset();
4886 
4887     rDesc.bFirstSprm = true;
4888     rDesc.nOrigSprmsLen = rDesc.nSprmsLen;
4889 }
4890 
GetId(const WW8PLCFxDesc * p) const4891 sal_uInt16 WW8PLCFMan::GetId(const WW8PLCFxDesc* p) const
4892 {
4893     sal_uInt16 nId = 0;        // Id = 0 for empty attributes
4894 
4895     if (p == m_pField)
4896         nId = eFLD;
4897     else if (p == m_pFootnote)
4898         nId = eFTN;
4899     else if (p == m_pEdn)
4900         nId = eEDN;
4901     else if (p == m_pAnd)
4902         nId = eAND;
4903     else if (p->nSprmsLen >= maSprmParser.MinSprmLen())
4904         nId = maSprmParser.GetSprmId(p->pMemPos);
4905 
4906     return nId;
4907 }
4908 
WW8PLCFMan(const WW8ScannerBase * pBase,ManTypes nType,tools::Long nStartCp,bool bDoingDrawTextBox)4909 WW8PLCFMan::WW8PLCFMan(const WW8ScannerBase* pBase, ManTypes nType, tools::Long nStartCp,
4910     bool bDoingDrawTextBox)
4911     : maSprmParser(*pBase->m_pWw8Fib),
4912     m_nLineEnd(WW8_CP_MAX),
4913     mbDoingDrawTextBox(bDoingDrawTextBox)
4914 {
4915     m_pWwFib = pBase->m_pWw8Fib;
4916 
4917     m_nManType = nType;
4918 
4919     if( MAN_MAINTEXT == nType )
4920     {
4921         // search order of the attributes
4922         m_nPLCF = MAN_PLCF_COUNT;
4923         m_pField = &m_aD[0];
4924         m_pBkm = &m_aD[1];
4925         m_pEdn = &m_aD[2];
4926         m_pFootnote = &m_aD[3];
4927         m_pAnd = &m_aD[4];
4928 
4929         m_pPcd = pBase->m_pPLCFx_PCD ? &m_aD[5] : nullptr;
4930         //pPcdA index == pPcd index + 1
4931         m_pPcdA = pBase->m_pPLCFx_PCDAttrs ? &m_aD[6] : nullptr;
4932 
4933         m_pChp = &m_aD[7];
4934         m_pPap = &m_aD[8];
4935         m_pSep = &m_aD[9];
4936         m_pAtnBkm = &m_aD[10];
4937         m_pFactoidBkm = &m_aD[11];
4938 
4939         m_pSep->pPLCFx = pBase->m_pSepPLCF.get();
4940         m_pFootnote->pPLCFx = pBase->m_pFootnotePLCF.get();
4941         m_pEdn->pPLCFx = pBase->m_pEdnPLCF.get();
4942         m_pBkm->pPLCFx = pBase->m_pBook.get();
4943         m_pAnd->pPLCFx = pBase->m_pAndPLCF.get();
4944         m_pAtnBkm->pPLCFx = pBase->m_pAtnBook.get();
4945         m_pFactoidBkm->pPLCFx = pBase->m_pFactoidBook.get();
4946 
4947     }
4948     else
4949     {
4950         // search order of the attributes
4951         m_nPLCF = 7;
4952         m_pField = &m_aD[0];
4953         m_pBkm = pBase->m_pBook ? &m_aD[1] : nullptr;
4954 
4955         m_pPcd = pBase->m_pPLCFx_PCD ? &m_aD[2] : nullptr;
4956         //pPcdA index == pPcd index + 1
4957         m_pPcdA= pBase->m_pPLCFx_PCDAttrs ? &m_aD[3] : nullptr;
4958 
4959         m_pChp = &m_aD[4];
4960         m_pPap = &m_aD[5];
4961         m_pSep = &m_aD[6]; // Dummy
4962 
4963         m_pAnd = m_pAtnBkm = m_pFactoidBkm = m_pFootnote = m_pEdn = nullptr;     // not used at SpezText
4964     }
4965 
4966     m_pChp->pPLCFx = pBase->m_pChpPLCF.get();
4967     m_pPap->pPLCFx = pBase->m_pPapPLCF.get();
4968     if( m_pPcd )
4969         m_pPcd->pPLCFx = pBase->m_pPLCFx_PCD.get();
4970     if( m_pPcdA )
4971         m_pPcdA->pPLCFx= pBase->m_pPLCFx_PCDAttrs.get();
4972     if( m_pBkm )
4973         m_pBkm->pPLCFx = pBase->m_pBook.get();
4974 
4975     m_pMagicTables = pBase->m_pMagicTables.get();
4976     m_pSubdocs = pBase->m_pSubdocs.get();
4977     m_pExtendedAtrds = pBase->m_pExtendedAtrds.get();
4978 
4979     switch( nType )                 // field initialization
4980     {
4981         case MAN_HDFT:
4982             m_pField->pPLCFx = pBase->m_pFieldHdFtPLCF.get();
4983             m_pFdoa = pBase->m_pHdFtFdoa.get();
4984             m_pTxbx = pBase->m_pHdFtTxbx.get();
4985             m_pTxbxBkd = pBase->m_pHdFtTxbxBkd.get();
4986             break;
4987         case MAN_FTN:
4988             m_pField->pPLCFx = pBase->m_pFieldFootnotePLCF.get();
4989             m_pFdoa = m_pTxbx = m_pTxbxBkd = nullptr;
4990             break;
4991         case MAN_EDN:
4992             m_pField->pPLCFx = pBase->m_pFieldEdnPLCF.get();
4993             m_pFdoa = m_pTxbx = m_pTxbxBkd = nullptr;
4994             break;
4995         case MAN_AND:
4996             m_pField->pPLCFx = pBase->m_pFieldAndPLCF.get();
4997             m_pFdoa = m_pTxbx = m_pTxbxBkd = nullptr;
4998             break;
4999         case MAN_TXBX:
5000             m_pField->pPLCFx = pBase->m_pFieldTxbxPLCF.get();
5001             m_pTxbx = pBase->m_pMainTxbx.get();
5002             m_pTxbxBkd = pBase->m_pMainTxbxBkd.get();
5003             m_pFdoa = nullptr;
5004             break;
5005         case MAN_TXBX_HDFT:
5006             m_pField->pPLCFx = pBase->m_pFieldTxbxHdFtPLCF.get();
5007             m_pTxbx = pBase->m_pHdFtTxbx.get();
5008             m_pTxbxBkd = pBase->m_pHdFtTxbxBkd.get();
5009             m_pFdoa = nullptr;
5010             break;
5011         default:
5012             m_pField->pPLCFx = pBase->m_pFieldPLCF.get();
5013             m_pFdoa = pBase->m_pMainFdoa.get();
5014             m_pTxbx = pBase->m_pMainTxbx.get();
5015             m_pTxbxBkd = pBase->m_pMainTxbxBkd.get();
5016             break;
5017     }
5018 
5019     WW8_CP cp = 0;
5020     m_pWwFib->GetBaseCp(nType, &cp); //TODO: check return value
5021     m_nCpO = cp;
5022 
5023     if( nStartCp || m_nCpO )
5024         SeekPos( nStartCp );    // adjust PLCFe at text StartPos
5025 
5026     // initialization to the member vars Low-Level
5027     GetChpPLCF()->ResetAttrStartEnd();
5028     GetPapPLCF()->ResetAttrStartEnd();
5029     for( sal_uInt16 i=0; i < m_nPLCF; ++i)
5030     {
5031         WW8PLCFxDesc* p = &m_aD[i];
5032 
5033         /*
5034         ##516##,##517##
5035         For subdocuments we modify the cp of properties to be relative to
5036         the beginning of subdocuments, we should also do the same for
5037         piecetable changes, and piecetable properties, otherwise a piece
5038         change that happens in a subdocument is lost.
5039         */
5040         p->nCpOfs = ( p == m_pChp || p == m_pPap || p == m_pBkm || p == m_pPcd ||
5041             p == m_pPcdA ) ? m_nCpO : 0;
5042 
5043         p->nCp2OrIdx = 0;
5044         p->bFirstSprm = false;
5045         p->xIdStack.reset();
5046 
5047         if ((p == m_pChp) || (p == m_pPap))
5048             p->nStartPos = p->nEndPos = nStartCp;
5049         else
5050             p->nStartPos = p->nEndPos = WW8_CP_MAX;
5051     }
5052 
5053     // initialization to the member vars High-Level
5054     for( sal_uInt16 i=0; i<m_nPLCF; ++i){
5055         WW8PLCFxDesc* p = &m_aD[i];
5056 
5057         if( !p->pPLCFx )
5058         {
5059             p->nStartPos = p->nEndPos = WW8_CP_MAX;
5060             continue;
5061         }
5062 
5063         if( p->pPLCFx->IsSprm() )
5064         {
5065             // Careful: nEndPos must be
5066             p->xIdStack.emplace();
5067             if ((p == m_pChp) || (p == m_pPap))
5068             {
5069                 WW8_CP nTemp = p->nEndPos+p->nCpOfs;
5070                 p->pMemPos = nullptr;
5071                 p->nSprmsLen = 0;
5072                 p->nStartPos = nTemp;
5073                 if (!(*p->pPLCFx).SeekPos(p->nStartPos))
5074                     p->nEndPos = p->nStartPos = WW8_CP_MAX;
5075                 else
5076                     GetNewSprms( *p );
5077             }
5078             else
5079                 GetNewSprms( *p );      // initialized at all PLCFs
5080         }
5081         else if( p->pPLCFx )
5082             GetNewNoSprms( *p );
5083     }
5084 }
5085 
~WW8PLCFMan()5086 WW8PLCFMan::~WW8PLCFMan()
5087 {
5088     for( sal_uInt16 i=0; i<m_nPLCF; i++)
5089         m_aD[i].xIdStack.reset();
5090 }
5091 
5092 // 0. which attr class,
5093 // 1. if it's an attr start,
5094 // 2. CP, where is next attr change
WhereIdx(bool * const pbStart,WW8_CP * const pPos) const5095 sal_uInt16 WW8PLCFMan::WhereIdx(bool *const pbStart, WW8_CP *const pPos) const
5096 {
5097     OSL_ENSURE(m_nPLCF,"What the hell");
5098     WW8_CP nNext = WW8_CP_MAX;  // search order:
5099     sal_uInt16 nNextIdx = m_nPLCF;// first ending found ( CHP, PAP, ( SEP ) ),
5100     bool bStart = true;     // now find beginnings ( ( SEP ), PAP, CHP )
5101     const WW8PLCFxDesc* pD;
5102     for (sal_uInt16 i=0; i < m_nPLCF; ++i)
5103     {
5104         pD = &m_aD[i];
5105         if (pD != m_pPcdA)
5106         {
5107             if( (pD->nEndPos < nNext) && (pD->nStartPos == WW8_CP_MAX) )
5108             {
5109                 // otherwise start = end
5110                 nNext = pD->nEndPos;
5111                 nNextIdx = i;
5112                 bStart = false;
5113             }
5114         }
5115     }
5116     for (sal_uInt16 i=m_nPLCF; i > 0; --i)
5117     {
5118         pD = &m_aD[i-1];
5119         if (pD != m_pPcdA && pD->nStartPos < nNext )
5120         {
5121             nNext = pD->nStartPos;
5122             nNextIdx = i-1;
5123             bStart = true;
5124         }
5125     }
5126     if( pPos )
5127         *pPos = nNext;
5128     if( pbStart )
5129         *pbStart = bStart;
5130     return nNextIdx;
5131 }
5132 
5133 // gives the CP pos of the next attr change
Where() const5134 WW8_CP WW8PLCFMan::Where() const
5135 {
5136     WW8_CP l;
5137     WhereIdx(nullptr, &l);
5138     return l;
5139 }
5140 
SeekPos(tools::Long nNewCp)5141 void WW8PLCFMan::SeekPos( tools::Long nNewCp )
5142 {
5143     m_pChp->pPLCFx->SeekPos( nNewCp + m_nCpO ); // create new attr
5144     m_pPap->pPLCFx->SeekPos( nNewCp + m_nCpO );
5145     m_pField->pPLCFx->SeekPos( nNewCp );
5146     if( m_pPcd )
5147         m_pPcd->pPLCFx->SeekPos( nNewCp + m_nCpO );
5148     if( m_pBkm )
5149         m_pBkm->pPLCFx->SeekPos( nNewCp + m_nCpO );
5150 }
5151 
SaveAllPLCFx(WW8PLCFxSaveAll & rSave) const5152 void WW8PLCFMan::SaveAllPLCFx( WW8PLCFxSaveAll& rSave ) const
5153 {
5154     sal_uInt16 n=0;
5155     if( m_pPcd )
5156         m_pPcd->Save(  rSave.aS[n++] );
5157     if( m_pPcdA )
5158         m_pPcdA->Save( rSave.aS[n++] );
5159 
5160     for(sal_uInt16 i=0; i<m_nPLCF; ++i)
5161         if( m_pPcd != &m_aD[i] && m_pPcdA != &m_aD[i] )
5162             m_aD[i].Save( rSave.aS[n++] );
5163 }
5164 
RestoreAllPLCFx(const WW8PLCFxSaveAll & rSave)5165 void WW8PLCFMan::RestoreAllPLCFx( const WW8PLCFxSaveAll& rSave )
5166 {
5167     sal_uInt16 n=0;
5168     if( m_pPcd )
5169         m_pPcd->Restore(  rSave.aS[n++] );
5170     if( m_pPcdA )
5171         m_pPcdA->Restore( rSave.aS[n++] );
5172 
5173     for(sal_uInt16 i=0; i<m_nPLCF; ++i)
5174         if( m_pPcd != &m_aD[i] && m_pPcdA != &m_aD[i] )
5175             m_aD[i].Restore( rSave.aS[n++] );
5176 }
5177 
5178 namespace
5179 {
IsSizeLegal(tools::Long nSprmLen,sal_Int32 nSprmsLen)5180     bool IsSizeLegal(tools::Long nSprmLen, sal_Int32 nSprmsLen)
5181     {
5182         if (nSprmLen > nSprmsLen)
5183         {
5184             SAL_WARN("sw.ww8", "Short sprm, len " << nSprmLen << " claimed, max possible is " << nSprmsLen);
5185             return false;
5186         }
5187         return true;
5188     }
5189 }
5190 
IsSprmLegalForCategory(sal_uInt16 nSprmId,short nIdx) const5191 bool WW8PLCFMan::IsSprmLegalForCategory(sal_uInt16 nSprmId, short nIdx) const
5192 {
5193     const WW8PLCFxDesc* p = &m_aD[nIdx];
5194     if (p != m_pSep) // just check sep for now
5195         return true;
5196 
5197     bool bRet;
5198     ww::WordVersion eVersion = maSprmParser.GetFIBVersion();
5199     if (eVersion <= ww::eWW2)
5200         bRet = nSprmId >= 112 && nSprmId <= 145;
5201     else if (eVersion < ww::eWW8)
5202         bRet = nSprmId >= NS_sprm::v6::sprmSScnsPgn && nSprmId <= NS_sprm::v6::sprmSDMPaperReq;
5203     else
5204     {
5205         /*
5206           Sprm bits: 10-12  sgc   sprm group; type of sprm (PAP, CHP, etc)
5207 
5208           sgc value type of sprm
5209           1         PAP
5210           2         CHP
5211           3         PIC
5212           4         SEP
5213           5         TAP
5214         */
5215         auto nSGC = ((nSprmId & 0x1C00) >> 10);
5216         bRet = nSGC == 4;
5217     }
5218     if (!bRet)
5219         SAL_INFO("sw.ww8", "sprm, id " << nSprmId << " wrong category for section properties");
5220     return bRet;
5221 }
5222 
GetSprmStart(short nIdx,WW8PLCFManResult * pRes) const5223 void WW8PLCFMan::GetSprmStart( short nIdx, WW8PLCFManResult* pRes ) const
5224 {
5225     memset( pRes, 0, sizeof( WW8PLCFManResult ) );
5226 
5227     // verifying !!!
5228 
5229     pRes->nMemLen = 0;
5230 
5231     const WW8PLCFxDesc* p = &m_aD[nIdx];
5232 
5233     // first Sprm in a Group
5234     if( p->bFirstSprm )
5235     {
5236         if( p == m_pPap )
5237             pRes->nFlags |= MAN_MASK_NEW_PAP;
5238         else if( p == m_pSep )
5239             pRes->nFlags |= MAN_MASK_NEW_SEP;
5240     }
5241     pRes->pMemPos = p->pMemPos;
5242     pRes->nSprmId = GetId(p);
5243     pRes->nCp2OrIdx = p->nCp2OrIdx;
5244     if ((p == m_pFootnote) || (p == m_pEdn) || (p == m_pAnd))
5245         pRes->nMemLen = p->nSprmsLen;
5246     else if (p->nSprmsLen >= maSprmParser.MinSprmLen()) //normal
5247     {
5248         // Length of actual sprm
5249         pRes->nMemLen = maSprmParser.GetSprmSize(pRes->nSprmId, pRes->pMemPos, p->nSprmsLen);
5250         if (!IsSizeLegal(pRes->nMemLen, p->nSprmsLen) || !IsSprmLegalForCategory(pRes->nSprmId, nIdx))
5251         {
5252             pRes->nSprmId = 0;
5253         }
5254     }
5255 }
5256 
GetSprmEnd(short nIdx,WW8PLCFManResult * pRes) const5257 void WW8PLCFMan::GetSprmEnd( short nIdx, WW8PLCFManResult* pRes ) const
5258 {
5259     memset( pRes, 0, sizeof( WW8PLCFManResult ) );
5260 
5261     const WW8PLCFxDesc* p = &m_aD[nIdx];
5262 
5263     if (!(p->xIdStack->empty()))
5264         pRes->nSprmId = p->xIdStack->top();       // get end position
5265     else
5266     {
5267         OSL_ENSURE( false, "No Id on the Stack" );
5268         pRes->nSprmId = 0;
5269     }
5270 }
5271 
GetNoSprmStart(short nIdx,WW8PLCFManResult * pRes) const5272 void WW8PLCFMan::GetNoSprmStart( short nIdx, WW8PLCFManResult* pRes ) const
5273 {
5274     const WW8PLCFxDesc* p = &m_aD[nIdx];
5275 
5276     pRes->nCpPos = p->nStartPos;
5277     pRes->nMemLen = p->nSprmsLen;
5278     pRes->nCp2OrIdx = p->nCp2OrIdx;
5279 
5280     if( p == m_pField )
5281         pRes->nSprmId = eFLD;
5282     else if( p == m_pFootnote )
5283         pRes->nSprmId = eFTN;
5284     else if( p == m_pEdn )
5285         pRes->nSprmId = eEDN;
5286     else if( p == m_pBkm )
5287         pRes->nSprmId = eBKN;
5288     else if (p == m_pAtnBkm)
5289         pRes->nSprmId = eATNBKN;
5290     else if (p == m_pFactoidBkm)
5291         pRes->nSprmId = eFACTOIDBKN;
5292     else if( p == m_pAnd )
5293         pRes->nSprmId = eAND;
5294     else if( p == m_pPcd )
5295     {
5296         //We slave the piece table attributes to the piece table, the piece
5297         //table attribute iterator contains the sprms for this piece.
5298         GetSprmStart( nIdx+1, pRes );
5299     }
5300     else
5301         pRes->nSprmId = 0;          // default: not found
5302 }
5303 
GetNoSprmEnd(short nIdx,WW8PLCFManResult * pRes) const5304 void WW8PLCFMan::GetNoSprmEnd( short nIdx, WW8PLCFManResult* pRes ) const
5305 {
5306     pRes->nMemLen = -1;     // end tag
5307 
5308     if( &m_aD[nIdx] == m_pBkm )
5309         pRes->nSprmId = eBKN;
5310     else if (&m_aD[nIdx] == m_pAtnBkm)
5311         pRes->nSprmId = eATNBKN;
5312     else if (&m_aD[nIdx] == m_pFactoidBkm)
5313         pRes->nSprmId = eFACTOIDBKN;
5314     else if( &m_aD[nIdx] == m_pPcd )
5315     {
5316         //We slave the piece table attributes to the piece table, the piece
5317         //table attribute iterator contains the sprms for this piece.
5318         GetSprmEnd( nIdx+1, pRes );
5319     }
5320     else
5321         pRes->nSprmId = 0;
5322 }
5323 
TransferOpenSprms(std::stack<sal_uInt16> & rStack)5324 void WW8PLCFMan::TransferOpenSprms(std::stack<sal_uInt16> &rStack)
5325 {
5326     for (sal_uInt16 i = 0; i < m_nPLCF; ++i)
5327     {
5328         WW8PLCFxDesc* p = &m_aD[i];
5329         if (!p || !p->xIdStack)
5330             continue;
5331         while (!p->xIdStack->empty())
5332         {
5333             rStack.push(p->xIdStack->top());
5334             p->xIdStack->pop();
5335         }
5336     }
5337 }
5338 
AdvSprm(short nIdx,bool bStart)5339 void WW8PLCFMan::AdvSprm(short nIdx, bool bStart)
5340 {
5341     WW8PLCFxDesc* p = &m_aD[nIdx];    // determine sprm class(!)
5342 
5343     p->bFirstSprm = false;
5344     if( bStart )
5345     {
5346         const sal_uInt16 nLastId = GetId(p);
5347 
5348         const sal_uInt16 nLastAttribStarted = IsSprmLegalForCategory(nLastId, nIdx) ? nLastId : 0;
5349 
5350         p->xIdStack->push(nLastAttribStarted);   // remember Id for attribute end
5351 
5352         if( p->nSprmsLen )
5353         {   /*
5354                 Check, if we have to process more sprm(s).
5355             */
5356             if( p->pMemPos )
5357             {
5358                 // Length of last sprm
5359                 const sal_Int32 nSprmL = maSprmParser.GetSprmSize(nLastId, p->pMemPos, p->nSprmsLen);
5360 
5361                 // Reduce length of all sprms by length of last sprm
5362                 p->nSprmsLen -= nSprmL;
5363 
5364                 // pos of next possible sprm
5365                 if (p->nSprmsLen < maSprmParser.MinSprmLen())
5366                 {
5367                     // preventively set to 0, because the end follows!
5368                     p->pMemPos = nullptr;
5369                     p->nSprmsLen = 0;
5370                 }
5371                 else
5372                     p->pMemPos += nSprmL;
5373             }
5374             else
5375                 p->nSprmsLen = 0;
5376         }
5377         if (p->nSprmsLen < maSprmParser.MinSprmLen())
5378             p->nStartPos = WW8_CP_MAX;    // the ending follows
5379     }
5380     else
5381     {
5382         if (!(p->xIdStack->empty()))
5383             p->xIdStack->pop();
5384         if (p->xIdStack->empty())
5385         {
5386             if ( (p == m_pChp) || (p == m_pPap) )
5387             {
5388                 p->pMemPos = nullptr;
5389                 p->nSprmsLen = 0;
5390                 p->nStartPos = p->nOrigEndPos+p->nCpOfs;
5391 
5392                 /*
5393                 On failed seek we have run out of sprms, probably. But if it's
5394                 a fastsaved file (has pPcd) then we may be just in a sprm free
5395                 gap between pieces that have them, so set dirty flag in sprm
5396                 finder to consider than.
5397                 */
5398                 if (!(*p->pPLCFx).SeekPos(p->nStartPos))
5399                 {
5400                     p->nEndPos = WW8_CP_MAX;
5401                     p->pPLCFx->SetDirty(true);
5402                 }
5403                 if (!p->pPLCFx->GetDirty() || m_pPcd)
5404                     GetNewSprms( *p );
5405                 p->pPLCFx->SetDirty(false);
5406 
5407                 /*
5408                 #i2325#
5409                 To get the character and paragraph properties you first get
5410                 the pap and chp and then apply the fastsaved pPcd properties
5411                 to the range. If a pap or chp starts inside the pPcd range
5412                 then we must bring the current pPcd range to a halt so as to
5413                 end those sprms, then the pap/chp will be processed, and then
5414                 we must force a restart of the pPcd on that pap/chp starting
5415                 boundary. Doing that effectively means that the pPcd sprms will
5416                 be applied to the new range. Not doing it means that the pPcd
5417                 sprms will only be applied to the first pap/chp set of
5418                 properties contained in the pap/chp range.
5419 
5420                 So we bring the pPcd to a halt on this location here, by
5421                 settings its end to the current start, then store the starting
5422                 position of the current range to clipstart. The pPcd sprms
5423                 will end as normal (albeit earlier than originally expected),
5424                 and the existence of a clipstart will force the pPcd iterator
5425                 to reread the current set of sprms instead of advancing to its
5426                 next set. Then the clipstart will be set as the starting
5427                 position which will force them to be applied directly after
5428                 the pap and chps.
5429                 */
5430                 if (m_pPcd && ((p->nStartPos > m_pPcd->nStartPos) ||
5431                     (m_pPcd->nStartPos == WW8_CP_MAX)) &&
5432                     (m_pPcd->nEndPos != p->nStartPos))
5433                 {
5434                     m_pPcd->nEndPos = p->nStartPos;
5435                     static_cast<WW8PLCFx_PCD *>(m_pPcd->pPLCFx)->SetClipStart(
5436                         p->nStartPos);
5437                 }
5438 
5439             }
5440             else
5441             {
5442                 p->pPLCFx->advance(); // next Group of Sprms
5443                 p->pMemPos = nullptr;       // !!!
5444                 p->nSprmsLen = 0;
5445                 GetNewSprms( *p );
5446             }
5447             SAL_WARN_IF(p->nStartPos > p->nEndPos, "sw.ww8",
5448                         "End " << p->nEndPos << " before Start " << p->nStartPos);
5449         }
5450     }
5451 }
5452 
AdvNoSprm(short nIdx,bool bStart)5453 void WW8PLCFMan::AdvNoSprm(short nIdx, bool bStart)
5454 {
5455     /*
5456     For the case of a piece table we slave the piece table attribute iterator
5457     to the piece table and access it through that only. They are two separate
5458     structures, but act together as one logical one. The attributes only go
5459     to the next entry when the piece changes
5460     */
5461     WW8PLCFxDesc* p = &m_aD[nIdx];
5462 
5463     if( p == m_pPcd )
5464     {
5465         AdvSprm(nIdx+1,bStart);
5466         if( bStart )
5467             p->nStartPos = m_aD[nIdx+1].nStartPos;
5468         else
5469         {
5470             if (m_aD[nIdx+1].xIdStack->empty())
5471             {
5472                 WW8PLCFx_PCD *pTemp = static_cast<WW8PLCFx_PCD*>(m_pPcd->pPLCFx);
5473                 /*
5474                 #i2325#
5475                 As per normal, go on to the next set of properties, i.e. we
5476                 have traversed over to the next piece.  With a clipstart set
5477                 we are being told to reread the current piece sprms so as to
5478                 reapply them to a new chp or pap range.
5479                 */
5480                 if (pTemp->GetClipStart() == -1)
5481                     p->pPLCFx->advance();
5482                 p->pMemPos = nullptr;
5483                 p->nSprmsLen = 0;
5484                 GetNewSprms( m_aD[nIdx+1] );
5485                 GetNewNoSprms( *p );
5486                 if (pTemp->GetClipStart() != -1)
5487                 {
5488                     /*
5489                     #i2325#, now we will force our starting position to the
5490                     clipping start so as to force the application of these
5491                     sprms after the current pap/chp sprms so as to apply the
5492                     fastsave sprms to the current range.
5493                     */
5494                     p->nStartPos = pTemp->GetClipStart();
5495                     pTemp->SetClipStart(-1);
5496                 }
5497             }
5498         }
5499     }
5500     else
5501     {                                  // NoSprm without end
5502         p->pPLCFx->advance();
5503         p->pMemPos = nullptr;                     // MemPos invalid
5504         p->nSprmsLen = 0;
5505         GetNewNoSprms( *p );
5506     }
5507 }
5508 
advance()5509 void WW8PLCFMan::advance()
5510 {
5511     bool bStart;
5512     const sal_uInt16 nIdx = WhereIdx(&bStart);
5513     if (nIdx < m_nPLCF)
5514     {
5515         WW8PLCFxDesc* p = &m_aD[nIdx];
5516 
5517         p->bFirstSprm = true;                       // Default
5518 
5519         if( p->pPLCFx->IsSprm() )
5520             AdvSprm( nIdx, bStart );
5521         else                                        // NoSprm
5522             AdvNoSprm( nIdx, bStart );
5523     }
5524 }
5525 
5526 // return true for the beginning of an attribute or error,
5527 //           false for the end of an attribute
5528 // remaining return values are delivered to the caller from WW8PclxManResults.
Get(WW8PLCFManResult * pRes) const5529 bool WW8PLCFMan::Get(WW8PLCFManResult* pRes) const
5530 {
5531     memset( pRes, 0, sizeof( WW8PLCFManResult ) );
5532     bool bStart;
5533     const sal_uInt16 nIdx = WhereIdx(&bStart);
5534 
5535     if( nIdx >= m_nPLCF )
5536     {
5537         OSL_ENSURE( false, "Position not found" );
5538         return true;
5539     }
5540 
5541     if( m_aD[nIdx].pPLCFx->IsSprm() )
5542     {
5543         if( bStart )
5544         {
5545             GetSprmStart( nIdx, pRes );
5546             return true;
5547         }
5548         else
5549         {
5550             GetSprmEnd( nIdx, pRes );
5551             return false;
5552         }
5553     }
5554     else
5555     {
5556         if( bStart )
5557         {
5558             GetNoSprmStart( nIdx, pRes );
5559             return true;
5560         }
5561         else
5562         {
5563             GetNoSprmEnd( nIdx, pRes );
5564             return false;
5565         }
5566     }
5567 }
5568 
GetColl() const5569 sal_uInt16 WW8PLCFMan::GetColl() const
5570 {
5571     if( m_pPap->pPLCFx )
5572         return  m_pPap->pPLCFx->GetIstd();
5573     else
5574     {
5575         OSL_ENSURE( false, "GetColl without PLCF_Pap" );
5576         return 0;
5577     }
5578 }
5579 
GetField() const5580 WW8PLCFx_FLD* WW8PLCFMan::GetField() const
5581 {
5582     return static_cast<WW8PLCFx_FLD*>(m_pField->pPLCFx);
5583 }
5584 
HasParaSprm(sal_uInt16 nId) const5585 SprmResult WW8PLCFMan::HasParaSprm( sal_uInt16 nId ) const
5586 {
5587     return static_cast<WW8PLCFx_Cp_FKP*>(m_pPap->pPLCFx)->HasSprm( nId );
5588 }
5589 
HasCharSprm(sal_uInt16 nId) const5590 SprmResult WW8PLCFMan::HasCharSprm( sal_uInt16 nId ) const
5591 {
5592     return static_cast<WW8PLCFx_Cp_FKP*>(m_pChp->pPLCFx)->HasSprm( nId );
5593 }
5594 
HasCharSprm(sal_uInt16 nId,std::vector<SprmResult> & rResult) const5595 void WW8PLCFMan::HasCharSprm(sal_uInt16 nId,
5596     std::vector<SprmResult> &rResult) const
5597 {
5598     static_cast<WW8PLCFx_Cp_FKP*>(m_pChp->pPLCFx)->HasSprm(nId, rResult);
5599 }
5600 
Save(WW8PLCFxSave1 & rSave) const5601 void WW8PLCFx::Save( WW8PLCFxSave1& rSave ) const
5602 {
5603     rSave.nPLCFxPos    = GetIdx();
5604     rSave.nPLCFxPos2   = GetIdx2();
5605     rSave.nPLCFxMemOfs = 0;
5606     rSave.nStartFC     = GetStartFc();
5607 }
5608 
Restore(const WW8PLCFxSave1 & rSave)5609 void WW8PLCFx::Restore( const WW8PLCFxSave1& rSave )
5610 {
5611     SetIdx(     rSave.nPLCFxPos  );
5612     SetIdx2(    rSave.nPLCFxPos2 );
5613     SetStartFc( rSave.nStartFC   );
5614 }
5615 
GetIdx2() const5616 sal_uInt32 WW8PLCFx_Cp_FKP::GetIdx2() const
5617 {
5618     return GetPCDIdx();
5619 }
5620 
SetIdx2(sal_uInt32 nIdx)5621 void WW8PLCFx_Cp_FKP::SetIdx2(sal_uInt32 nIdx)
5622 {
5623     if( m_pPcd )
5624         m_pPcd->SetIdx( nIdx );
5625 }
5626 
Save(WW8PLCFxSave1 & rSave) const5627 void WW8PLCFx_Cp_FKP::Save( WW8PLCFxSave1& rSave ) const
5628 {
5629     if (m_pFkp)
5630         m_pFkp->IncMustRemainCache();
5631     WW8PLCFx::Save( rSave );
5632 
5633     rSave.nAttrStart = m_nAttrStart;
5634     rSave.nAttrEnd   = m_nAttrEnd;
5635     rSave.bLineEnd   = m_bLineEnd;
5636 }
5637 
Restore(const WW8PLCFxSave1 & rSave)5638 void WW8PLCFx_Cp_FKP::Restore( const WW8PLCFxSave1& rSave )
5639 {
5640     WW8PLCFx::Restore( rSave );
5641 
5642     m_nAttrStart = rSave.nAttrStart;
5643     m_nAttrEnd   = rSave.nAttrEnd;
5644     m_bLineEnd   = rSave.bLineEnd;
5645 
5646     if (m_pFkp)
5647         m_pFkp->DecMustRemainCache();
5648 }
5649 
Save(WW8PLCFxSave1 & rSave) const5650 void WW8PLCFxDesc::Save( WW8PLCFxSave1& rSave ) const
5651 {
5652     if( !pPLCFx )
5653         return;
5654 
5655     pPLCFx->Save( rSave );
5656     if( !pPLCFx->IsSprm() )
5657         return;
5658 
5659     WW8PLCFxDesc aD;
5660     aD.nStartPos = nOrigStartPos+nCpOfs;
5661     aD.nCpOfs = rSave.nCpOfs = nCpOfs;
5662     if (!(pPLCFx->SeekPos(aD.nStartPos)))
5663     {
5664         aD.nEndPos = WW8_CP_MAX;
5665         pPLCFx->SetDirty(true);
5666     }
5667     pPLCFx->GetSprms(&aD);
5668     pPLCFx->SetDirty(false);
5669     aD.ReduceByOffset();
5670     rSave.nStartCp = aD.nStartPos;
5671     rSave.nPLCFxMemOfs = nOrigSprmsLen - nSprmsLen;
5672 }
5673 
Restore(const WW8PLCFxSave1 & rSave)5674 void WW8PLCFxDesc::Restore( const WW8PLCFxSave1& rSave )
5675 {
5676     if( !pPLCFx )
5677         return;
5678 
5679     pPLCFx->Restore( rSave );
5680     if( !pPLCFx->IsSprm() )
5681         return;
5682 
5683     WW8PLCFxDesc aD;
5684     aD.nStartPos = rSave.nStartCp+rSave.nCpOfs;
5685     nCpOfs = aD.nCpOfs = rSave.nCpOfs;
5686     if (!(pPLCFx->SeekPos(aD.nStartPos)))
5687     {
5688         aD.nEndPos = WW8_CP_MAX;
5689         pPLCFx->SetDirty(true);
5690     }
5691     pPLCFx->GetSprms(&aD);
5692     pPLCFx->SetDirty(false);
5693     aD.ReduceByOffset();
5694 
5695     if (nOrigSprmsLen > aD.nSprmsLen)
5696     {
5697         //two entries exist for the same offset, cut and run
5698         SAL_WARN("sw.ww8", "restored properties don't match saved properties, bailing out");
5699         nSprmsLen = 0;
5700         pMemPos = nullptr;
5701     }
5702     else
5703     {
5704         nSprmsLen = nOrigSprmsLen - rSave.nPLCFxMemOfs;
5705         pMemPos = aD.pMemPos == nullptr ? nullptr : aD.pMemPos + rSave.nPLCFxMemOfs;
5706     }
5707 }
5708 
5709 namespace
5710 {
Readcb(SvStream & rSt,ww::WordVersion eVer)5711     sal_uInt32 Readcb(SvStream& rSt, ww::WordVersion eVer)
5712     {
5713         if (eVer <= ww::eWW2)
5714         {
5715             sal_uInt16 nShort(0);
5716             rSt.ReadUInt16(nShort);
5717             return nShort;
5718         }
5719         else
5720         {
5721             sal_uInt32 nLong(0);
5722             rSt.ReadUInt32(nLong);
5723             return nLong;
5724         }
5725     }
5726 }
5727 
GetBaseCp(ManTypes nType,WW8_CP * cp) const5728 bool WW8Fib::GetBaseCp(ManTypes nType, WW8_CP * cp) const
5729 {
5730     assert(cp != nullptr);
5731     WW8_CP nOffset = 0;
5732 
5733     switch (nType)
5734     {
5735         case MAN_TXBX_HDFT:
5736             if (m_ccpTxbx < 0) {
5737                 return false;
5738             }
5739             nOffset = m_ccpTxbx;
5740             [[fallthrough]];
5741         case MAN_TXBX:
5742             if (m_ccpEdn < 0 || m_ccpEdn > std::numeric_limits<WW8_CP>::max() - nOffset) {
5743                 return false;
5744             }
5745             nOffset += m_ccpEdn;
5746             [[fallthrough]];
5747         case MAN_EDN:
5748             if (m_ccpAtn < 0 || m_ccpAtn > std::numeric_limits<WW8_CP>::max() - nOffset) {
5749                 return false;
5750             }
5751             nOffset += m_ccpAtn;
5752             [[fallthrough]];
5753         case MAN_AND:
5754             if (m_ccpMcr < 0 || m_ccpMcr > std::numeric_limits<WW8_CP>::max() - nOffset) {
5755                 return false;
5756             }
5757             nOffset += m_ccpMcr;
5758         /*
5759             // fall through
5760 
5761          A subdocument of this kind (MAN_MACRO) probably exists in some defunct
5762          version of MSWord, but now ccpMcr is always 0. If some example that
5763          uses this comes to light, this is the likely calculation required
5764 
5765         case MAN_MACRO:
5766         */
5767             if (m_ccpHdr < 0 || m_ccpHdr > std::numeric_limits<WW8_CP>::max() - nOffset) {
5768                 return false;
5769             }
5770             nOffset += m_ccpHdr;
5771             [[fallthrough]];
5772         case MAN_HDFT:
5773             if (m_ccpFootnote < 0 || m_ccpFootnote > std::numeric_limits<WW8_CP>::max() - nOffset) {
5774                 return false;
5775             }
5776             nOffset += m_ccpFootnote;
5777             [[fallthrough]];
5778         case MAN_FTN:
5779             if (m_ccpText < 0 || m_ccpText > std::numeric_limits<WW8_CP>::max() - nOffset) {
5780                 return false;
5781             }
5782             nOffset += m_ccpText;
5783             [[fallthrough]];
5784         case MAN_MAINTEXT:
5785             break;
5786     }
5787     *cp = nOffset;
5788     return true;
5789 }
5790 
GetFIBVersion() const5791 ww::WordVersion WW8Fib::GetFIBVersion() const
5792 {
5793     ww::WordVersion eVer = ww::eWW8;
5794     /*
5795      * Word for Windows 2 I think (1.X might work too if anyone has an example.
5796      *
5797      * 0xA59B for Word 1 for Windows
5798      * 0xA59C for Word 1 for OS/2 "PM Word"
5799      *
5800      * Various pages claim that the fileformats of Word 1 and 2 for Windows are
5801      * equivalent to Word for Macintosh 4 and 5. On the other hand
5802      *
5803      * wIdents for Word for Mac versions...
5804      * 0xFE32 for Word 1
5805      * 0xFE34 for Word 3
5806      * 0xFE37 for Word 4 et 5.
5807      *
5808      * and this document
5809      * http://cmsdoc.cern.ch/documents/docformat/CMS_CERN_LetterHead.word is
5810      * claimed to be "Word 5 for Mac" by Office etc and has that wIdent, but
5811      * its format isn't the same as that of Word 2 for windows. Nor is it
5812      * the same as that of Word for DOS/PCWord 5
5813      */
5814     if (m_wIdent == 0xa59b || m_wIdent == 0xa59c)
5815         eVer = ww::eWW1;
5816     else if (m_wIdent == 0xa5db)
5817         eVer = ww::eWW2;
5818     else
5819     {
5820         switch (m_nVersion)
5821         {
5822             case 6:
5823                 eVer = ww::eWW6;
5824                 break;
5825             case 7:
5826                 eVer = ww::eWW7;
5827                 break;
5828             case 8:
5829                 eVer = ww::eWW8;
5830                 break;
5831         }
5832     }
5833     return eVer;
5834 }
5835 
WW8Fib(SvStream & rSt,sal_uInt8 nWantedVersion,sal_uInt32 nOffset)5836 WW8Fib::WW8Fib(SvStream& rSt, sal_uInt8 nWantedVersion, sal_uInt32 nOffset):
5837     m_fDot(false), m_fGlsy(false), m_fComplex(false), m_fHasPic(false), m_cQuickSaves(0),
5838     m_fEncrypted(false), m_fWhichTableStm(false), m_fReadOnlyRecommended(false),
5839     m_fWriteReservation(false), m_fExtChar(false), m_fFarEast(false), m_fObfuscated(false),
5840     m_fMac(false), m_fEmptySpecial(false), m_fLoadOverridePage(false), m_fFuturesavedUndo(false),
5841     m_fWord97Saved(false), m_fWord2000Saved(false)
5842         // in C++20 with P06831R1 "Default member initializers for bit-fields (revision 1)", the
5843         // above bit-field member initializations can be moved to the class definition
5844 {
5845     // See [MS-DOC] 2.5.15 "How to read the FIB".
5846     rSt.Seek( nOffset );
5847     /*
5848         note desired number, identify file version number
5849         and check against desired number!
5850     */
5851     m_nVersion = nWantedVersion;
5852     rSt.ReadUInt16( m_wIdent );
5853     rSt.ReadUInt16( m_nFib );
5854     rSt.ReadUInt16( m_nProduct );
5855     if( ERRCODE_NONE != rSt.GetError() )
5856     {
5857         sal_Int16 nFibMin;
5858         sal_Int16 nFibMax;
5859         // note: 6 stands for "6 OR 7",  7 stands for "ONLY 7"
5860         switch( m_nVersion )
5861         {
5862             case 6:
5863                 nFibMin = 0x0065;   // from 101 WinWord 6.0
5864                                     //     102    "
5865                                     // and 103 WinWord 6.0 for Macintosh
5866                                     //     104    "
5867                 nFibMax = 0x0069;   // to 105 WinWord 95
5868                 break;
5869             case 7:
5870                 nFibMin = 0x0069;   // from 105 WinWord 95
5871                 nFibMax = 0x0069;   // to 105 WinWord 95
5872                 break;
5873             case 8:
5874                 nFibMin = 0x006A;   // from 106 WinWord 97
5875                 nFibMax = 0x00c1;   // to 193 WinWord 97 (?)
5876                 break;
5877             default:
5878                 nFibMin = 0;            // program error!
5879                 nFibMax = 0;
5880                 m_nFib    = 1;
5881                 OSL_ENSURE( false, "nVersion not implemented!" );
5882                 break;
5883         }
5884         if ( (m_nFib < nFibMin) || (m_nFib > nFibMax) )
5885         {
5886             m_nFibError = ERR_SWG_READ_ERROR; // report error
5887             return;
5888         }
5889     }
5890 
5891     ww::WordVersion eVer = GetFIBVersion();
5892 
5893     // helper vars for Ver67:
5894     sal_Int16 pnChpFirst_Ver67=0;
5895     sal_Int16 pnPapFirst_Ver67=0;
5896     sal_Int16 cpnBteChp_Ver67=0;
5897     sal_Int16 cpnBtePap_Ver67=0;
5898 
5899     // read FIB
5900     sal_uInt16 nTmpLid = 0;
5901     rSt.ReadUInt16(nTmpLid);
5902     m_lid = LanguageType(nTmpLid);
5903     rSt.ReadInt16( m_pnNext );
5904     sal_uInt8 aBits1(0);
5905     rSt.ReadUChar( aBits1 );
5906     sal_uInt8 aBits2(0);
5907     rSt.ReadUChar( aBits2 );
5908     rSt.ReadUInt16( m_nFibBack );
5909     rSt.ReadUInt16( m_nHash );
5910     rSt.ReadUInt16( m_nKey );
5911     rSt.ReadUChar( m_envr );
5912     sal_uInt8 aVer8Bits1(0);     // only used starting with WinWord 8
5913     rSt.ReadUChar( aVer8Bits1 ); // only have an empty reserve field under Ver67
5914                             // content from aVer8Bits1
5915 
5916                             // sal_uInt8 fMac              :1;
5917                             // sal_uInt8 fEmptySpecial     :1;
5918                             // sal_uInt8 fLoadOverridePage :1;
5919                             // sal_uInt8 fFuturesavedUndo  :1;
5920                             // sal_uInt8 fWord97Saved      :1;
5921                             // sal_uInt8 :3;
5922     rSt.ReadUInt16( m_chse );
5923     rSt.ReadUInt16( m_chseTables );
5924     rSt.ReadInt32( m_fcMin );
5925     rSt.ReadInt32( m_fcMac );
5926 
5927 // insertion for WW8
5928     if (IsEightPlus(eVer))
5929     {
5930         rSt.ReadUInt16( m_csw );
5931 
5932         // Marke: "rgsw"  Beginning of the array of shorts
5933         rSt.ReadUInt16( m_wMagicCreated );
5934         rSt.ReadUInt16( m_wMagicRevised );
5935         rSt.ReadUInt16( m_wMagicCreatedPrivate );
5936         rSt.ReadUInt16( m_wMagicRevisedPrivate );
5937         rSt.SeekRel( 9 * sizeof( sal_Int16 ) );
5938 
5939         /*
5940         // these are the 9 unused fields:
5941         && (bVer67 || WW8ReadINT16(  rSt, pnFbpChpFirst_W6          ))  // 1
5942         && (bVer67 || WW8ReadINT16(  rSt, pnChpFirst_W6                 ))  // 2
5943         && (bVer67 || WW8ReadINT16(  rSt, cpnBteChp_W6                  ))  // 3
5944         && (bVer67 || WW8ReadINT16(  rSt, pnFbpPapFirst_W6          ))  // 4
5945         && (bVer67 || WW8ReadINT16(  rSt, pnPapFirst_W6                 ))  // 5
5946         && (bVer67 || WW8ReadINT16(  rSt, cpnBtePap_W6                  ))  // 6
5947         && (bVer67 || WW8ReadINT16(  rSt, pnFbpLvcFirst_W6          ))  // 7
5948         && (bVer67 || WW8ReadINT16(  rSt, pnLvcFirst_W6                 ))  // 8
5949         && (bVer67 || WW8ReadINT16(  rSt, cpnBteLvc_W6                  ))  // 9
5950         */
5951         sal_uInt16 nTmpFE = 0;
5952         rSt.ReadUInt16(nTmpFE);
5953         m_lidFE = LanguageType(nTmpFE);
5954         rSt.ReadUInt16( m_clw );
5955     }
5956 
5957 // end of the insertion for WW8
5958 
5959         // Marke: "rglw"  Beginning of the array of longs
5960     rSt.ReadInt32( m_cbMac );
5961 
5962         // ignore 2 longs, because they are unimportant
5963     rSt.SeekRel( 2 * sizeof( sal_Int32) );
5964 
5965         // skipping 2 more longs only at Ver67
5966     if (IsSevenMinus(eVer))
5967         rSt.SeekRel( 2 * sizeof( sal_Int32) );
5968 
5969     rSt.ReadInt32( m_ccpText );
5970     rSt.ReadInt32( m_ccpFootnote );
5971     rSt.ReadInt32( m_ccpHdr );
5972     rSt.ReadInt32( m_ccpMcr );
5973     rSt.ReadInt32( m_ccpAtn );
5974     rSt.ReadInt32( m_ccpEdn );
5975     rSt.ReadInt32( m_ccpTxbx );
5976     rSt.ReadInt32( m_ccpHdrTxbx );
5977 
5978         // only skip one more long at Ver67
5979     if (IsSevenMinus(eVer))
5980         rSt.SeekRel( 1 * sizeof( sal_Int32) );
5981     else
5982     {
5983 // insertion for WW8
5984         rSt.ReadInt32( m_pnFbpChpFirst );
5985         rSt.ReadInt32( m_pnChpFirst );
5986         rSt.ReadInt32( m_cpnBteChp );
5987         rSt.ReadInt32( m_pnFbpPapFirst );
5988         rSt.ReadInt32( m_pnPapFirst );
5989         rSt.ReadInt32( m_cpnBtePap );
5990         rSt.ReadInt32( m_pnFbpLvcFirst );
5991         rSt.ReadInt32( m_pnLvcFirst );
5992         rSt.ReadInt32( m_cpnBteLvc );
5993         rSt.ReadInt32( m_fcIslandFirst );
5994         rSt.ReadInt32( m_fcIslandLim );
5995         rSt.ReadUInt16( m_cfclcb );
5996 
5997         // Read cswNew to find out if nFib should be ignored.
5998         sal_uInt64 nPos = rSt.Tell();
5999         rSt.SeekRel(m_cfclcb * 8);
6000         if (rSt.good() && rSt.remainingSize() >= 2)
6001         {
6002             rSt.ReadUInt16(m_cswNew);
6003         }
6004         rSt.Seek(nPos);
6005     }
6006 
6007 // end of the insertion for WW8
6008 
6009     // Marke: "rgfclcb" Beginning of array of FC/LCB pairs.
6010     rSt.ReadInt32( m_fcStshfOrig );
6011     m_lcbStshfOrig = Readcb(rSt, eVer);
6012     rSt.ReadInt32( m_fcStshf );
6013     m_lcbStshf = Readcb(rSt, eVer);
6014     rSt.ReadInt32( m_fcPlcffndRef );
6015     m_lcbPlcffndRef = Readcb(rSt, eVer);
6016     rSt.ReadInt32( m_fcPlcffndText );
6017     m_lcbPlcffndText = Readcb(rSt, eVer);
6018     rSt.ReadInt32( m_fcPlcfandRef );
6019     m_lcbPlcfandRef = Readcb(rSt, eVer);
6020     rSt.ReadInt32( m_fcPlcfandText );
6021     m_lcbPlcfandText = Readcb(rSt, eVer);
6022     rSt.ReadInt32( m_fcPlcfsed );
6023     m_lcbPlcfsed = Readcb(rSt, eVer);
6024     rSt.ReadInt32( m_fcPlcfpad );
6025     m_lcbPlcfpad = Readcb(rSt, eVer);
6026     rSt.ReadInt32( m_fcPlcfphe );
6027     m_lcbPlcfphe = Readcb(rSt, eVer);
6028     rSt.ReadInt32( m_fcSttbfglsy );
6029     m_lcbSttbfglsy = Readcb(rSt, eVer);
6030     rSt.ReadInt32( m_fcPlcfglsy );
6031     m_lcbPlcfglsy = Readcb(rSt, eVer);
6032     rSt.ReadInt32( m_fcPlcfhdd );
6033     m_lcbPlcfhdd = Readcb(rSt, eVer);
6034     rSt.ReadInt32( m_fcPlcfbteChpx );
6035     m_lcbPlcfbteChpx = Readcb(rSt, eVer);
6036     rSt.ReadInt32( m_fcPlcfbtePapx );
6037     m_lcbPlcfbtePapx = Readcb(rSt, eVer);
6038     rSt.ReadInt32( m_fcPlcfsea );
6039     m_lcbPlcfsea = Readcb(rSt, eVer);
6040     rSt.ReadInt32( m_fcSttbfffn );
6041     m_lcbSttbfffn = Readcb(rSt, eVer);
6042     rSt.ReadInt32( m_fcPlcffldMom );
6043     m_lcbPlcffldMom = Readcb(rSt, eVer);
6044     rSt.ReadInt32( m_fcPlcffldHdr );
6045     m_lcbPlcffldHdr = Readcb(rSt, eVer);
6046     rSt.ReadInt32( m_fcPlcffldFootnote );
6047     m_lcbPlcffldFootnote = Readcb(rSt, eVer);
6048     rSt.ReadInt32( m_fcPlcffldAtn );
6049     m_lcbPlcffldAtn = Readcb(rSt, eVer);
6050     rSt.ReadInt32( m_fcPlcffldMcr );
6051     m_lcbPlcffldMcr = Readcb(rSt, eVer);
6052     rSt.ReadInt32( m_fcSttbfbkmk );
6053     m_lcbSttbfbkmk = Readcb(rSt, eVer);
6054     rSt.ReadInt32( m_fcPlcfbkf );
6055     m_lcbPlcfbkf = Readcb(rSt, eVer);
6056     rSt.ReadInt32( m_fcPlcfbkl );
6057     m_lcbPlcfbkl = Readcb(rSt, eVer);
6058     rSt.ReadInt32( m_fcCmds );
6059     m_lcbCmds = Readcb(rSt, eVer);
6060     rSt.ReadInt32( m_fcPlcfmcr );
6061     m_lcbPlcfmcr = Readcb(rSt, eVer);
6062     rSt.ReadInt32( m_fcSttbfmcr );
6063     m_lcbSttbfmcr = Readcb(rSt, eVer);
6064     if (eVer >= ww::eWW2)
6065     {
6066         rSt.ReadInt32( m_fcPrDrvr );
6067         m_lcbPrDrvr = Readcb(rSt, eVer);
6068         rSt.ReadInt32( m_fcPrEnvPort );
6069         m_lcbPrEnvPort = Readcb(rSt, eVer);
6070         rSt.ReadInt32( m_fcPrEnvLand );
6071         m_lcbPrEnvLand = Readcb(rSt, eVer);
6072     }
6073     else
6074     {
6075         rSt.ReadInt32( m_fcPrEnvPort );
6076         m_lcbPrEnvPort = Readcb(rSt, eVer);
6077     }
6078     rSt.ReadInt32( m_fcWss );
6079     m_lcbWss = Readcb(rSt, eVer);
6080     rSt.ReadInt32( m_fcDop );
6081     m_lcbDop = Readcb(rSt, eVer);
6082     rSt.ReadInt32( m_fcSttbfAssoc );
6083     m_lcbSttbfAssoc = Readcb(rSt, eVer);
6084     rSt.ReadInt32( m_fcClx );
6085     m_lcbClx = Readcb(rSt, eVer);
6086     rSt.ReadInt32( m_fcPlcfpgdFootnote );
6087     m_lcbPlcfpgdFootnote = Readcb(rSt, eVer);
6088     rSt.ReadInt32( m_fcAutosaveSource );
6089     m_lcbAutosaveSource = Readcb(rSt, eVer);
6090     rSt.ReadInt32( m_fcGrpStAtnOwners );
6091     m_lcbGrpStAtnOwners = Readcb(rSt, eVer);
6092     rSt.ReadInt32( m_fcSttbfAtnbkmk );
6093     m_lcbSttbfAtnbkmk = Readcb(rSt, eVer);
6094 
6095     // only skip more shot at Ver67
6096     if (IsSevenMinus(eVer))
6097     {
6098         if (eVer == ww::eWW1)
6099             rSt.SeekRel(1*sizeof(sal_Int32));
6100         rSt.SeekRel(1*sizeof(sal_Int16));
6101 
6102         if (eVer >= ww::eWW2)
6103         {
6104             rSt.ReadInt16(pnChpFirst_Ver67);
6105             rSt.ReadInt16(pnPapFirst_Ver67);
6106         }
6107         rSt.ReadInt16(cpnBteChp_Ver67);
6108         rSt.ReadInt16(cpnBtePap_Ver67);
6109     }
6110 
6111     if (eVer > ww::eWW2)
6112     {
6113         rSt.ReadInt32( m_fcPlcfdoaMom );
6114         rSt.ReadInt32( m_lcbPlcfdoaMom );
6115         rSt.ReadInt32( m_fcPlcfdoaHdr );
6116         rSt.ReadInt32( m_lcbPlcfdoaHdr );
6117         rSt.ReadInt32( m_fcPlcfspaMom );
6118         rSt.ReadInt32( m_lcbPlcfspaMom );
6119         rSt.ReadInt32( m_fcPlcfspaHdr );
6120         rSt.ReadInt32( m_lcbPlcfspaHdr );
6121 
6122         rSt.ReadInt32( m_fcPlcfAtnbkf );
6123         rSt.ReadInt32( m_lcbPlcfAtnbkf );
6124         rSt.ReadInt32( m_fcPlcfAtnbkl );
6125         rSt.ReadInt32( m_lcbPlcfAtnbkl );
6126         rSt.ReadInt32( m_fcPms );
6127         rSt.ReadInt32( m_lcbPMS );
6128         rSt.ReadInt32( m_fcFormFieldSttbf );
6129         rSt.ReadInt32( m_lcbFormFieldSttbf );
6130         rSt.ReadInt32( m_fcPlcfendRef );
6131         rSt.ReadInt32( m_lcbPlcfendRef );
6132         rSt.ReadInt32( m_fcPlcfendText );
6133         rSt.ReadInt32( m_lcbPlcfendText );
6134         rSt.ReadInt32( m_fcPlcffldEdn );
6135         rSt.ReadInt32( m_lcbPlcffldEdn );
6136         rSt.ReadInt32( m_fcPlcfpgdEdn );
6137         rSt.ReadInt32( m_lcbPlcfpgdEdn );
6138         rSt.ReadInt32( m_fcDggInfo );
6139         rSt.ReadInt32( m_lcbDggInfo );
6140         rSt.ReadInt32( m_fcSttbfRMark );
6141         rSt.ReadInt32( m_lcbSttbfRMark );
6142         rSt.ReadInt32( m_fcSttbfCaption );
6143         rSt.ReadInt32( m_lcbSttbfCaption );
6144         rSt.ReadInt32( m_fcSttbAutoCaption );
6145         rSt.ReadInt32( m_lcbSttbAutoCaption );
6146         rSt.ReadInt32( m_fcPlcfwkb );
6147         rSt.ReadInt32( m_lcbPlcfwkb );
6148         rSt.ReadInt32( m_fcPlcfspl );
6149         rSt.ReadInt32( m_lcbPlcfspl );
6150         rSt.ReadInt32( m_fcPlcftxbxText );
6151         rSt.ReadInt32( m_lcbPlcftxbxText );
6152         rSt.ReadInt32( m_fcPlcffldTxbx );
6153         rSt.ReadInt32( m_lcbPlcffldTxbx );
6154         rSt.ReadInt32( m_fcPlcfHdrtxbxText );
6155         rSt.ReadInt32( m_lcbPlcfHdrtxbxText );
6156         rSt.ReadInt32( m_fcPlcffldHdrTxbx );
6157         rSt.ReadInt32( m_lcbPlcffldHdrTxbx );
6158         rSt.ReadInt32( m_fcStwUser );
6159         rSt.ReadUInt32( m_lcbStwUser );
6160         rSt.ReadInt32( m_fcSttbttmbd );
6161         rSt.ReadUInt32( m_lcbSttbttmbd );
6162     }
6163 
6164     if( ERRCODE_NONE == rSt.GetError() )
6165     {
6166         // set bit flag
6167         m_fDot        =   aBits1 & 0x01       ;
6168         m_fGlsy       = ( aBits1 & 0x02 ) >> 1;
6169         m_fComplex    = ( aBits1 & 0x04 ) >> 2;
6170         m_fHasPic     = ( aBits1 & 0x08 ) >> 3;
6171         m_cQuickSaves = ( aBits1 & 0xf0 ) >> 4;
6172         m_fEncrypted  =   aBits2 & 0x01       ;
6173         m_fWhichTableStm= ( aBits2 & 0x02 ) >> 1;
6174         m_fReadOnlyRecommended = (aBits2 & 0x4) >> 2;
6175         m_fWriteReservation = (aBits2 & 0x8) >> 3;
6176         m_fExtChar    = ( aBits2 & 0x10 ) >> 4;
6177         // dummy    = ( aBits2 & 0x20 ) >> 5;
6178         m_fFarEast    = ( aBits2 & 0x40 ) >> 6; // #i90932#
6179         // dummy    = ( aBits2 & 0x80 ) >> 7;
6180 
6181         /*
6182             p.r.n. fill targeted variable with xxx_Ver67
6183             or set flags
6184         */
6185         if (IsSevenMinus(eVer))
6186         {
6187             m_pnChpFirst = pnChpFirst_Ver67;
6188             m_pnPapFirst = pnPapFirst_Ver67;
6189             m_cpnBteChp = cpnBteChp_Ver67;
6190             m_cpnBtePap = cpnBtePap_Ver67;
6191         }
6192         else if (IsEightPlus(eVer))
6193         {
6194             m_fMac              =   aVer8Bits1  & 0x01           ;
6195             m_fEmptySpecial     = ( aVer8Bits1  & 0x02 ) >> 1;
6196             m_fLoadOverridePage = ( aVer8Bits1  & 0x04 ) >> 2;
6197             m_fFuturesavedUndo  = ( aVer8Bits1  & 0x08 ) >> 3;
6198             m_fWord97Saved      = ( aVer8Bits1  & 0x10 ) >> 4;
6199             m_fWord2000Saved    = ( aVer8Bits1  & 0x20 ) >> 5;
6200 
6201             /*
6202                 especially for WW8:
6203                 identify the values for PLCF and PLF LFO
6204                 and PLCF for the textbox break descriptors
6205             */
6206             sal_uInt64 nOldPos = rSt.Tell();
6207 
6208             rSt.Seek( 0x02da );
6209             rSt.ReadInt32( m_fcSttbFnm );
6210             rSt.ReadInt32( m_lcbSttbFnm );
6211             rSt.ReadInt32( m_fcPlcfLst );
6212             rSt.ReadInt32( m_lcbPlcfLst );
6213             rSt.ReadInt32( m_fcPlfLfo );
6214             rSt.ReadInt32( m_lcbPlfLfo );
6215             rSt.ReadInt32( m_fcPlcftxbxBkd );
6216             rSt.ReadInt32( m_lcbPlcftxbxBkd );
6217             rSt.ReadInt32( m_fcPlcfHdrtxbxBkd );
6218             rSt.ReadInt32( m_lcbPlcfHdrtxbxBkd );
6219             if( ERRCODE_NONE != rSt.GetError() )
6220             {
6221                 m_nFibError = ERR_SWG_READ_ERROR;
6222             }
6223 
6224             rSt.Seek( 0x372 );          // fcSttbListNames
6225             rSt.ReadInt32( m_fcSttbListNames );
6226             rSt.ReadInt32( m_lcbSttbListNames );
6227 
6228             if (m_cfclcb > 93)
6229             {
6230                 rSt.Seek( 0x382 );          // MagicTables
6231                 rSt.ReadInt32( m_fcPlcfTch );
6232                 rSt.ReadInt32( m_lcbPlcfTch );
6233             }
6234 
6235             if (m_cfclcb > 113)
6236             {
6237                 rSt.Seek( 0x41A );          // new ATRD
6238                 rSt.ReadInt32( m_fcAtrdExtra );
6239                 rSt.ReadUInt32( m_lcbAtrdExtra );
6240             }
6241 
6242             // Factoid bookmarks
6243             if (m_cfclcb > 134)
6244             {
6245                 rSt.Seek(0x432);
6246                 rSt.ReadInt32(m_fcPlcfBkfFactoid);
6247                 rSt.ReadUInt32(m_lcbPlcfBkfFactoid);
6248 
6249                 rSt.Seek(0x442);
6250                 rSt.ReadInt32(m_fcPlcfBklFactoid);
6251                 rSt.ReadUInt32(m_lcbPlcfBklFactoid);
6252 
6253                 rSt.Seek(0x44a);
6254                 rSt.ReadInt32(m_fcFactoidData);
6255                 rSt.ReadUInt32(m_lcbFactoidData);
6256             }
6257 
6258             if( ERRCODE_NONE != rSt.GetError() )
6259                 m_nFibError = ERR_SWG_READ_ERROR;
6260 
6261             rSt.Seek( 0x5bc );          // Actual nFib introduced in Word 2003
6262             rSt.ReadUInt16( m_nFib_actual );
6263 
6264             rSt.Seek( nOldPos );
6265         }
6266     }
6267     else
6268     {
6269         m_nFibError = ERR_SWG_READ_ERROR;     // report error
6270     }
6271 }
6272 
WW8Fib(sal_uInt8 nVer,bool bDot)6273 WW8Fib::WW8Fib(sal_uInt8 nVer, bool bDot):
6274     m_nVersion(nVer), m_fDot(false), m_fGlsy(false), m_fComplex(false), m_fHasPic(false), m_cQuickSaves(0),
6275     m_fEncrypted(false), m_fWhichTableStm(false), m_fReadOnlyRecommended(false),
6276     m_fWriteReservation(false), m_fExtChar(false), m_fFarEast(false), m_fObfuscated(false),
6277     m_fMac(false), m_fEmptySpecial(false), m_fLoadOverridePage(false), m_fFuturesavedUndo(false),
6278     m_fWord97Saved(false), m_fWord2000Saved(false)
6279         // in C++20 with P06831R1 "Default member initializers for bit-fields (revision 1)", the
6280         // above bit-field member initializations can be moved to the class definition
6281 {
6282     if (8 == nVer)
6283     {
6284         m_fcMin = 0x800;
6285         m_wIdent = 0xa5ec;
6286         m_nFib = 0x0101;
6287         m_nFibBack = 0xbf;
6288         m_nProduct = 0x204D;
6289         m_fDot = bDot;
6290 
6291         m_csw = 0x0e;     // Is this really necessary???
6292         m_cfclcb = 0x88;  //      -""-
6293         m_clw = 0x16;     //      -""-
6294         m_pnFbpChpFirst = m_pnFbpPapFirst = m_pnFbpLvcFirst = 0x000fffff;
6295         m_fExtChar = true;
6296         m_fWord97Saved = m_fWord2000Saved = true;
6297 
6298         // Just a fancy way to write 'Caolan80'.
6299         m_wMagicCreated = 0x6143;
6300         m_wMagicRevised = 0x6C6F;
6301         m_wMagicCreatedPrivate = 0x6E61;
6302         m_wMagicRevisedPrivate = 0x3038;
6303     }
6304     else
6305     {
6306         m_fcMin = 0x300;
6307         m_wIdent = 0xa5dc;
6308         m_nFib = m_nFibBack = 0x65;
6309         m_nProduct = 0xc02d;
6310     }
6311 
6312     //If nFib is 0x00D9 or greater, then cQuickSaves MUST be 0xF
6313     m_cQuickSaves = m_nFib >= 0x00D9 ? 0xF : 0;
6314 
6315     // --> #i90932#
6316     m_lid = LanguageType(0x409); // LANGUAGE_ENGLISH_US
6317 
6318     LanguageType nLang = Application::GetSettings().GetLanguageTag().getLanguageType();
6319     m_fFarEast = MsLangId::isCJK(nLang);
6320     if (m_fFarEast)
6321         m_lidFE = nLang;
6322     else
6323         m_lidFE = m_lid;
6324 
6325     LanguageTag aLanguageTag( m_lid );
6326     LocaleDataWrapper aLocaleWrapper( std::move(aLanguageTag) );
6327     m_nNumDecimalSep = aLocaleWrapper.getNumDecimalSep()[0];
6328 }
6329 
6330 
WriteHeader(SvStream & rStrm)6331 void WW8Fib::WriteHeader(SvStream& rStrm)
6332 {
6333     bool bVer8 = 8 == m_nVersion;
6334 
6335     size_t nUnencryptedHdr = bVer8 ? 0x44 : 0x24;
6336     std::unique_ptr<sal_uInt8[]> pDataPtr( new sal_uInt8[ nUnencryptedHdr ] );
6337     sal_uInt8 *pData = pDataPtr.get();
6338     memset( pData, 0, nUnencryptedHdr );
6339 
6340     m_cbMac = rStrm.TellEnd();
6341 
6342     Set_UInt16( pData, m_wIdent );
6343     Set_UInt16( pData, m_nFib );
6344     Set_UInt16( pData, m_nProduct );
6345     Set_UInt16( pData, static_cast<sal_uInt16>(m_lid) );
6346     Set_UInt16( pData, m_pnNext );
6347 
6348     sal_uInt16 nBits16 = 0;
6349     if( m_fDot )          nBits16 |= 0x0001;
6350     if( m_fGlsy)          nBits16 |= 0x0002;
6351     if( m_fComplex )      nBits16 |= 0x0004;
6352     if( m_fHasPic )       nBits16 |= 0x0008;
6353     nBits16 |= (0xf0 & ( m_cQuickSaves << 4 ));
6354     if( m_fEncrypted )    nBits16 |= 0x0100;
6355     if( m_fWhichTableStm )  nBits16 |= 0x0200;
6356 
6357     if (m_fReadOnlyRecommended)
6358         nBits16 |= 0x0400;
6359     if (m_fWriteReservation)
6360         nBits16 |= 0x0800;
6361 
6362     if( m_fExtChar )      nBits16 |= 0x1000;
6363     if( m_fFarEast )      nBits16 |= 0x4000;  // #i90932#
6364     if( m_fObfuscated )   nBits16 |= 0x8000;
6365     Set_UInt16( pData, nBits16 );
6366 
6367     Set_UInt16( pData, m_nFibBack );
6368     Set_UInt16( pData, m_nHash );
6369     Set_UInt16( pData, m_nKey );
6370     Set_UInt8( pData, m_envr );
6371 
6372     sal_uInt8 nBits8 = 0;
6373     if( bVer8 )
6374     {
6375         if( m_fMac )                  nBits8 |= 0x0001;
6376         if( m_fEmptySpecial )         nBits8 |= 0x0002;
6377         if( m_fLoadOverridePage )     nBits8 |= 0x0004;
6378         if( m_fFuturesavedUndo )      nBits8 |= 0x0008;
6379         if( m_fWord97Saved )          nBits8 |= 0x0010;
6380         if( m_fWord2000Saved )        nBits8 |= 0x0020;
6381     }
6382     // under Ver67 these are only reserved
6383     Set_UInt8( pData, nBits8  );
6384 
6385     Set_UInt16( pData, m_chse );
6386     Set_UInt16( pData, m_chseTables );
6387     Set_UInt32( pData, m_fcMin );
6388     Set_UInt32( pData, m_fcMac );
6389 
6390 // insertion for WW8
6391 
6392     // Marke: "rgsw"  Beginning of the array of shorts
6393     if( bVer8 )
6394     {
6395         Set_UInt16( pData, m_csw );
6396         Set_UInt16( pData, m_wMagicCreated );
6397         Set_UInt16( pData, m_wMagicRevised );
6398         Set_UInt16( pData, m_wMagicCreatedPrivate );
6399         Set_UInt16( pData, m_wMagicRevisedPrivate );
6400         pData += 9 * sizeof( sal_Int16 );
6401         Set_UInt16( pData, static_cast<sal_uInt16>(m_lidFE) );
6402         Set_UInt16( pData, m_clw );
6403     }
6404 
6405 // end of the insertion for WW8
6406 
6407     // Marke: "rglw"  Beginning of the array of longs
6408     Set_UInt32( pData, m_cbMac );
6409 
6410     rStrm.WriteBytes(pDataPtr.get(), nUnencryptedHdr);
6411 }
6412 
Write(SvStream & rStrm)6413 void WW8Fib::Write(SvStream& rStrm)
6414 {
6415     bool bVer8 = 8 == m_nVersion;
6416 
6417     WriteHeader( rStrm );
6418 
6419     size_t nUnencryptedHdr = bVer8 ? 0x44 : 0x24;
6420 
6421     std::unique_ptr<sal_uInt8[]> pDataPtr( new sal_uInt8[ m_fcMin - nUnencryptedHdr ] );
6422     sal_uInt8 *pData = pDataPtr.get();
6423     memset( pData, 0, m_fcMin - nUnencryptedHdr );
6424 
6425     m_cbMac = rStrm.TellEnd();
6426 
6427     // ignore 2 longs, because they are unimportant
6428     pData += 2 * sizeof( sal_Int32);
6429 
6430     // skipping 2 more longs only at Ver67
6431     if( !bVer8 )
6432         pData += 2 * sizeof( sal_Int32);
6433 
6434     Set_UInt32( pData, m_ccpText );
6435     Set_UInt32( pData, m_ccpFootnote );
6436     Set_UInt32( pData, m_ccpHdr );
6437     Set_UInt32( pData, m_ccpMcr );
6438     Set_UInt32( pData, m_ccpAtn );
6439     Set_UInt32( pData, m_ccpEdn );
6440     Set_UInt32( pData, m_ccpTxbx );
6441     Set_UInt32( pData, m_ccpHdrTxbx );
6442 
6443         // only skip one more long at Ver67
6444     if( !bVer8 )
6445         pData += 1 * sizeof( sal_Int32);
6446 
6447 // insertion for WW8
6448     if( bVer8 )
6449     {
6450         Set_UInt32( pData, m_pnFbpChpFirst );
6451         Set_UInt32( pData, m_pnChpFirst );
6452         Set_UInt32( pData, m_cpnBteChp );
6453         Set_UInt32( pData, m_pnFbpPapFirst );
6454         Set_UInt32( pData, m_pnPapFirst );
6455         Set_UInt32( pData, m_cpnBtePap );
6456         Set_UInt32( pData, m_pnFbpLvcFirst );
6457         Set_UInt32( pData, m_pnLvcFirst );
6458         Set_UInt32( pData, m_cpnBteLvc );
6459         Set_UInt32( pData, m_fcIslandFirst );
6460         Set_UInt32( pData, m_fcIslandLim );
6461         Set_UInt16( pData, m_cfclcb );
6462     }
6463 // end of the insertion for WW8
6464 
6465     // Marke: "rgfclcb" Beginning of array of FC/LCB pairs.
6466     Set_UInt32( pData, m_fcStshfOrig );
6467     Set_UInt32( pData, m_lcbStshfOrig );
6468     Set_UInt32( pData, m_fcStshf );
6469     Set_UInt32( pData, m_lcbStshf );
6470     Set_UInt32( pData, m_fcPlcffndRef );
6471     Set_UInt32( pData, m_lcbPlcffndRef );
6472     Set_UInt32( pData, m_fcPlcffndText );
6473     Set_UInt32( pData, m_lcbPlcffndText );
6474     Set_UInt32( pData, m_fcPlcfandRef );
6475     Set_UInt32( pData, m_lcbPlcfandRef );
6476     Set_UInt32( pData, m_fcPlcfandText );
6477     Set_UInt32( pData, m_lcbPlcfandText );
6478     Set_UInt32( pData, m_fcPlcfsed );
6479     Set_UInt32( pData, m_lcbPlcfsed );
6480     Set_UInt32( pData, m_fcPlcfpad );
6481     Set_UInt32( pData, m_lcbPlcfpad );
6482     Set_UInt32( pData, m_fcPlcfphe );
6483     Set_UInt32( pData, m_lcbPlcfphe );
6484     Set_UInt32( pData, m_fcSttbfglsy );
6485     Set_UInt32( pData, m_lcbSttbfglsy );
6486     Set_UInt32( pData, m_fcPlcfglsy );
6487     Set_UInt32( pData, m_lcbPlcfglsy );
6488     Set_UInt32( pData, m_fcPlcfhdd );
6489     Set_UInt32( pData, m_lcbPlcfhdd );
6490     Set_UInt32( pData, m_fcPlcfbteChpx );
6491     Set_UInt32( pData, m_lcbPlcfbteChpx );
6492     Set_UInt32( pData, m_fcPlcfbtePapx );
6493     Set_UInt32( pData, m_lcbPlcfbtePapx );
6494     Set_UInt32( pData, m_fcPlcfsea );
6495     Set_UInt32( pData, m_lcbPlcfsea );
6496     Set_UInt32( pData, m_fcSttbfffn );
6497     Set_UInt32( pData, m_lcbSttbfffn );
6498     Set_UInt32( pData, m_fcPlcffldMom );
6499     Set_UInt32( pData, m_lcbPlcffldMom );
6500     Set_UInt32( pData, m_fcPlcffldHdr );
6501     Set_UInt32( pData, m_lcbPlcffldHdr );
6502     Set_UInt32( pData, m_fcPlcffldFootnote );
6503     Set_UInt32( pData, m_lcbPlcffldFootnote );
6504     Set_UInt32( pData, m_fcPlcffldAtn );
6505     Set_UInt32( pData, m_lcbPlcffldAtn );
6506     Set_UInt32( pData, m_fcPlcffldMcr );
6507     Set_UInt32( pData, m_lcbPlcffldMcr );
6508     Set_UInt32( pData, m_fcSttbfbkmk );
6509     Set_UInt32( pData, m_lcbSttbfbkmk );
6510     Set_UInt32( pData, m_fcPlcfbkf );
6511     Set_UInt32( pData, m_lcbPlcfbkf );
6512     Set_UInt32( pData, m_fcPlcfbkl );
6513     Set_UInt32( pData, m_lcbPlcfbkl );
6514     Set_UInt32( pData, m_fcCmds );
6515     Set_UInt32( pData, m_lcbCmds );
6516     Set_UInt32( pData, m_fcPlcfmcr );
6517     Set_UInt32( pData, m_lcbPlcfmcr );
6518     Set_UInt32( pData, m_fcSttbfmcr );
6519     Set_UInt32( pData, m_lcbSttbfmcr );
6520     Set_UInt32( pData, m_fcPrDrvr );
6521     Set_UInt32( pData, m_lcbPrDrvr );
6522     Set_UInt32( pData, m_fcPrEnvPort );
6523     Set_UInt32( pData, m_lcbPrEnvPort );
6524     Set_UInt32( pData, m_fcPrEnvLand );
6525     Set_UInt32( pData, m_lcbPrEnvLand );
6526     Set_UInt32( pData, m_fcWss );
6527     Set_UInt32( pData, m_lcbWss );
6528     Set_UInt32( pData, m_fcDop );
6529     Set_UInt32( pData, m_lcbDop );
6530     Set_UInt32( pData, m_fcSttbfAssoc );
6531     Set_UInt32( pData, m_lcbSttbfAssoc );
6532     Set_UInt32( pData, m_fcClx );
6533     Set_UInt32( pData, m_lcbClx );
6534     Set_UInt32( pData, m_fcPlcfpgdFootnote );
6535     Set_UInt32( pData, m_lcbPlcfpgdFootnote );
6536     Set_UInt32( pData, m_fcAutosaveSource );
6537     Set_UInt32( pData, m_lcbAutosaveSource );
6538     Set_UInt32( pData, m_fcGrpStAtnOwners );
6539     Set_UInt32( pData, m_lcbGrpStAtnOwners );
6540     Set_UInt32( pData, m_fcSttbfAtnbkmk );
6541     Set_UInt32( pData, m_lcbSttbfAtnbkmk );
6542 
6543     // only skip one more short at Ver67
6544     if( !bVer8 )
6545     {
6546         pData += 1*sizeof( sal_Int16);
6547         Set_UInt16( pData, o3tl::narrowing<sal_uInt16>(m_pnChpFirst) );
6548         Set_UInt16( pData, o3tl::narrowing<sal_uInt16>(m_pnPapFirst) );
6549         Set_UInt16( pData, o3tl::narrowing<sal_uInt16>(m_cpnBteChp) );
6550         Set_UInt16( pData, o3tl::narrowing<sal_uInt16>(m_cpnBtePap) );
6551     }
6552 
6553     Set_UInt32( pData, m_fcPlcfdoaMom ); // only at Ver67, in Ver8 unused
6554     Set_UInt32( pData, m_lcbPlcfdoaMom ); // only at Ver67, in Ver8 unused
6555     Set_UInt32( pData, m_fcPlcfdoaHdr ); // only at Ver67, in Ver8 unused
6556     Set_UInt32( pData, m_lcbPlcfdoaHdr ); // only at Ver67, in Ver8 unused
6557 
6558     Set_UInt32( pData, m_fcPlcfspaMom ); // in Ver67 empty reserve
6559     Set_UInt32( pData, m_lcbPlcfspaMom ); // in Ver67 empty reserve
6560     Set_UInt32( pData, m_fcPlcfspaHdr ); // in Ver67 empty reserve
6561     Set_UInt32( pData, m_lcbPlcfspaHdr ); // in Ver67 empty reserve
6562 
6563     Set_UInt32( pData, m_fcPlcfAtnbkf );
6564     Set_UInt32( pData, m_lcbPlcfAtnbkf );
6565     Set_UInt32( pData, m_fcPlcfAtnbkl );
6566     Set_UInt32( pData, m_lcbPlcfAtnbkl );
6567     Set_UInt32( pData, m_fcPms );
6568     Set_UInt32( pData, m_lcbPMS );
6569     Set_UInt32( pData, m_fcFormFieldSttbf );
6570     Set_UInt32( pData, m_lcbFormFieldSttbf );
6571     Set_UInt32( pData, m_fcPlcfendRef );
6572     Set_UInt32( pData, m_lcbPlcfendRef );
6573     Set_UInt32( pData, m_fcPlcfendText );
6574     Set_UInt32( pData, m_lcbPlcfendText );
6575     Set_UInt32( pData, m_fcPlcffldEdn );
6576     Set_UInt32( pData, m_lcbPlcffldEdn );
6577     Set_UInt32( pData, m_fcPlcfpgdEdn );
6578     Set_UInt32( pData, m_lcbPlcfpgdEdn );
6579     Set_UInt32( pData, m_fcDggInfo ); // in Ver67 empty reserve
6580     Set_UInt32( pData, m_lcbDggInfo ); // in Ver67 empty reserve
6581     Set_UInt32( pData, m_fcSttbfRMark );
6582     Set_UInt32( pData, m_lcbSttbfRMark );
6583     Set_UInt32( pData, m_fcSttbfCaption );
6584     Set_UInt32( pData, m_lcbSttbfCaption );
6585     Set_UInt32( pData, m_fcSttbAutoCaption );
6586     Set_UInt32( pData, m_lcbSttbAutoCaption );
6587     Set_UInt32( pData, m_fcPlcfwkb );
6588     Set_UInt32( pData, m_lcbPlcfwkb );
6589     Set_UInt32( pData, m_fcPlcfspl ); // in Ver67 empty reserve
6590     Set_UInt32( pData, m_lcbPlcfspl ); // in Ver67 empty reserve
6591     Set_UInt32( pData, m_fcPlcftxbxText );
6592     Set_UInt32( pData, m_lcbPlcftxbxText );
6593     Set_UInt32( pData, m_fcPlcffldTxbx );
6594     Set_UInt32( pData, m_lcbPlcffldTxbx );
6595     Set_UInt32( pData, m_fcPlcfHdrtxbxText );
6596     Set_UInt32( pData, m_lcbPlcfHdrtxbxText );
6597     Set_UInt32( pData, m_fcPlcffldHdrTxbx );
6598     Set_UInt32( pData, m_lcbPlcffldHdrTxbx );
6599 
6600     if( bVer8 )
6601     {
6602         pData += 0x2da - 0x27a;         // Pos + Offset (fcPlcfLst - fcStwUser)
6603         Set_UInt32( pData, m_fcSttbFnm);
6604         Set_UInt32( pData, m_lcbSttbFnm);
6605         Set_UInt32( pData, m_fcPlcfLst );
6606         Set_UInt32( pData, m_lcbPlcfLst );
6607         Set_UInt32( pData, m_fcPlfLfo );
6608         Set_UInt32( pData, m_lcbPlfLfo );
6609         Set_UInt32( pData, m_fcPlcftxbxBkd );
6610         Set_UInt32( pData, m_lcbPlcftxbxBkd );
6611         Set_UInt32( pData, m_fcPlcfHdrtxbxBkd );
6612         Set_UInt32( pData, m_lcbPlcfHdrtxbxBkd );
6613 
6614         pData += 0x372 - 0x302; // Pos + Offset (fcSttbListNames - fcDocUndo)
6615         Set_UInt32( pData, m_fcSttbListNames );
6616         Set_UInt32( pData, m_lcbSttbListNames );
6617 
6618         pData += 0x382 - 0x37A;
6619         Set_UInt32( pData, m_fcPlcfTch );
6620         Set_UInt32( pData, m_lcbPlcfTch );
6621 
6622         pData += 0x3FA - 0x38A;
6623         Set_UInt16( pData, sal_uInt16(0x0002));
6624         Set_UInt16( pData, sal_uInt16(0x00D9));
6625 
6626         pData += 0x41A - 0x3FE;
6627         Set_UInt32( pData, m_fcAtrdExtra );
6628         Set_UInt32( pData, m_lcbAtrdExtra );
6629 
6630         pData += 0x42a - 0x422;
6631         Set_UInt32(pData, m_fcSttbfBkmkFactoid);
6632         Set_UInt32(pData, m_lcbSttbfBkmkFactoid);
6633         Set_UInt32(pData, m_fcPlcfBkfFactoid);
6634         Set_UInt32(pData, m_lcbPlcfBkfFactoid);
6635 
6636         pData += 0x442 - 0x43A;
6637         Set_UInt32(pData, m_fcPlcfBklFactoid);
6638         Set_UInt32(pData, m_lcbPlcfBklFactoid);
6639         Set_UInt32(pData, m_fcFactoidData);
6640         Set_UInt32(pData, m_lcbFactoidData);
6641 
6642         pData += 0x4BA - 0x452;
6643         Set_UInt32(pData, m_fcPlcffactoid);
6644         Set_UInt32(pData, m_lcbPlcffactoid);
6645 
6646         pData += 0x4DA - 0x4c2;
6647         Set_UInt32( pData, m_fcHplxsdr );
6648         Set_UInt32( pData, 0);
6649     }
6650 
6651     rStrm.WriteBytes(pDataPtr.get(), m_fcMin - nUnencryptedHdr);
6652 }
6653 
GetFIBCharset(sal_uInt16 chs,LanguageType nLidLocale)6654 rtl_TextEncoding WW8Fib::GetFIBCharset(sal_uInt16 chs, LanguageType nLidLocale)
6655 {
6656     OSL_ENSURE(chs <= 0x100, "overflowed winword charset set");
6657     if (chs == 0x0100)
6658         return RTL_TEXTENCODING_APPLE_ROMAN;
6659     if (chs == 0 && static_cast<sal_uInt16>(nLidLocale) >= 999)
6660     {
6661         /*
6662          nLidLocale:
6663             language stamp -- localized version In pre-WinWord 2.0 files this
6664             value was the nLocale. If value is < 999, then it is the nLocale,
6665             otherwise it is the lid.
6666         */
6667         css::lang::Locale aLocale(LanguageTag::convertToLocale(nLidLocale));
6668         return msfilter::util::getBestTextEncodingFromLocale(aLocale);
6669     }
6670     return rtl_getTextEncodingFromWindowsCharset(static_cast<sal_uInt8>(chs));
6671 }
6672 
MSOFactoidType()6673 MSOFactoidType::MSOFactoidType()
6674     : m_nId(0)
6675 {
6676 }
6677 
6678 namespace MSOPBString
6679 {
Read(SvStream & rStream)6680 static OUString Read(SvStream& rStream)
6681 {
6682     OUString aRet;
6683 
6684     sal_uInt16 nBuf(0);
6685     rStream.ReadUInt16(nBuf);
6686     sal_uInt16 nCch = nBuf & 0x7fff; // Bits 1..15.
6687     bool bAnsiString = (nBuf & (1 << 15)) >> 15; // 16th bit.
6688     if (bAnsiString)
6689         aRet = OStringToOUString(read_uInt8s_ToOString(rStream, nCch), RTL_TEXTENCODING_ASCII_US);
6690     else
6691         aRet = read_uInt16s_ToOUString(rStream, nCch);
6692 
6693     return aRet;
6694 }
6695 
Write(std::u16string_view aString,SvStream & rStream)6696 static void Write(std::u16string_view aString, SvStream& rStream)
6697 {
6698     sal_uInt16 nBuf = 0;
6699     nBuf |= sal_Int32(aString.size()); // cch, 0..14th bits.
6700     nBuf |= 0x8000; // fAnsiString, 15th bit.
6701     rStream.WriteUInt16(nBuf);
6702     SwWW8Writer::WriteString8(rStream, aString, false, RTL_TEXTENCODING_ASCII_US);
6703 }
6704 };
6705 
Read(SvStream & rStream)6706 void MSOFactoidType::Read(SvStream& rStream)
6707 {
6708     sal_uInt32 cbFactoid(0);
6709     rStream.ReadUInt32(cbFactoid);
6710     rStream.ReadUInt32(m_nId);
6711     m_aUri = MSOPBString::Read(rStream);
6712     m_aTag = MSOPBString::Read(rStream);
6713     MSOPBString::Read(rStream); // rgbDownloadURL
6714 }
6715 
Write(WW8Export & rExport)6716 void MSOFactoidType::Write(WW8Export& rExport)
6717 {
6718     SvStream& rStream = *rExport.m_pTableStrm;
6719 
6720     SvMemoryStream aStream;
6721     aStream.WriteUInt32(m_nId); // id
6722     MSOPBString::Write(m_aUri, aStream);
6723     MSOPBString::Write(m_aTag, aStream);
6724     MSOPBString::Write(u"", aStream); // rgbDownloadURL
6725     rStream.WriteUInt32(aStream.Tell());
6726     aStream.Seek(0);
6727     rStream.WriteStream(aStream);
6728 }
6729 
Read(SvStream & rStream)6730 void MSOPropertyBagStore::Read(SvStream& rStream)
6731 {
6732     sal_uInt32 cFactoidType(0);
6733     rStream.ReadUInt32(cFactoidType);
6734     for (sal_uInt32 i = 0; i < cFactoidType && rStream.good(); ++i)
6735     {
6736         MSOFactoidType aFactoidType;
6737         aFactoidType.Read(rStream);
6738         m_aFactoidTypes.push_back(aFactoidType);
6739     }
6740     sal_uInt16 cbHdr(0);
6741     rStream.ReadUInt16(cbHdr);
6742     SAL_WARN_IF(cbHdr != 0xc, "sw.ww8", "MSOPropertyBagStore::Read: unexpected cbHdr");
6743     sal_uInt16 nVer(0);
6744     rStream.ReadUInt16(nVer);
6745     SAL_WARN_IF(nVer != 0x0100, "sw.ww8", "MSOPropertyBagStore::Read: unexpected nVer");
6746     rStream.SeekRel(4); // cfactoid
6747     sal_uInt32 nCste(0);
6748     rStream.ReadUInt32(nCste);
6749 
6750     //each string has a 2 byte len record at the start
6751     const size_t nMaxPossibleRecords = rStream.remainingSize() / sizeof(sal_uInt16);
6752     if (nCste > nMaxPossibleRecords)
6753     {
6754         SAL_WARN("sw.ww8", nCste << " records claimed, but max possible is " << nMaxPossibleRecords);
6755         nCste = nMaxPossibleRecords;
6756     }
6757 
6758     for (sal_uInt32 i = 0; i < nCste; ++i)
6759     {
6760         OUString aString = MSOPBString::Read(rStream);
6761         m_aStringTable.push_back(aString);
6762     }
6763 }
6764 
Write(WW8Export & rExport)6765 void MSOPropertyBagStore::Write(WW8Export& rExport)
6766 {
6767     SvStream& rStream = *rExport.m_pTableStrm;
6768     rStream.WriteUInt32(m_aFactoidTypes.size()); // cFactoidType
6769     for (MSOFactoidType& rType : m_aFactoidTypes)
6770         rType.Write(rExport);
6771     rStream.WriteUInt16(0xc); // cbHdr
6772     rStream.WriteUInt16(0x0100); // sVer
6773     rStream.WriteUInt32(0); // cfactoid
6774     rStream.WriteUInt32(m_aStringTable.size()); // cste
6775     for (const OUString& rString : m_aStringTable)
6776         MSOPBString::Write(rString, rStream);
6777 }
6778 
MSOProperty()6779 MSOProperty::MSOProperty()
6780     : m_nKey(0)
6781     , m_nValue(0)
6782 {
6783 }
6784 
Read(SvStream & rStream)6785 void MSOProperty::Read(SvStream& rStream)
6786 {
6787     rStream.ReadUInt32(m_nKey);
6788     rStream.ReadUInt32(m_nValue);
6789 }
6790 
Write(SvStream & rStream)6791 void MSOProperty::Write(SvStream& rStream)
6792 {
6793     rStream.WriteUInt32(m_nKey);
6794     rStream.WriteUInt32(m_nValue);
6795 }
6796 
MSOPropertyBag()6797 MSOPropertyBag::MSOPropertyBag()
6798     : m_nId(0)
6799 {
6800 }
6801 
Read(SvStream & rStream)6802 bool MSOPropertyBag::Read(SvStream& rStream)
6803 {
6804     rStream.ReadUInt16(m_nId);
6805     sal_uInt16 cProp(0);
6806     rStream.ReadUInt16(cProp);
6807     if (!rStream.good())
6808         return false;
6809     rStream.SeekRel(2); // cbUnknown
6810     //each MSOProperty is 8 bytes in size
6811     const size_t nMaxPossibleRecords = rStream.remainingSize() / 8;
6812     if (cProp > nMaxPossibleRecords)
6813     {
6814         SAL_WARN("sw.ww8", cProp << " records claimed, but max possible is " << nMaxPossibleRecords);
6815         cProp = nMaxPossibleRecords;
6816     }
6817     for (sal_uInt16 i = 0; i < cProp && rStream.good(); ++i)
6818     {
6819         MSOProperty aProperty;
6820         aProperty.Read(rStream);
6821         m_aProperties.push_back(aProperty);
6822     }
6823     return rStream.good();
6824 }
6825 
Write(WW8Export & rExport)6826 void MSOPropertyBag::Write(WW8Export& rExport)
6827 {
6828     SvStream& rStream = *rExport.m_pTableStrm;
6829     rStream.WriteUInt16(m_nId);
6830     rStream.WriteUInt16(m_aProperties.size());
6831     rStream.WriteUInt16(0); // cbUnknown
6832     for (MSOProperty& rProperty : m_aProperties)
6833         rProperty.Write(rStream);
6834 }
6835 
Read(SvStream & rStream,WW8_FC fcFactoidData,sal_uInt32 lcbFactoidData)6836 void WW8SmartTagData::Read(SvStream& rStream, WW8_FC fcFactoidData, sal_uInt32 lcbFactoidData)
6837 {
6838     sal_uInt64 nOldPosition = rStream.Tell();
6839     if (!checkSeek(rStream, fcFactoidData))
6840         return;
6841 
6842     m_aPropBagStore.Read(rStream);
6843     while (rStream.good() && rStream.Tell() < fcFactoidData + lcbFactoidData)
6844     {
6845         MSOPropertyBag aPropertyBag;
6846         if (!aPropertyBag.Read(rStream))
6847             break;
6848         m_aPropBags.push_back(aPropertyBag);
6849     }
6850 
6851     rStream.Seek(nOldPosition);
6852 }
6853 
Write(WW8Export & rExport)6854 void WW8SmartTagData::Write(WW8Export& rExport)
6855 {
6856     m_aPropBagStore.Write(rExport);
6857     for (MSOPropertyBag& rPropertyBag : m_aPropBags)
6858         rPropertyBag.Write(rExport);
6859 }
6860 
WW8Style(SvStream & rStream,WW8Fib & rFibPara)6861 WW8Style::WW8Style(SvStream& rStream, WW8Fib& rFibPara)
6862     : m_rFib(rFibPara), m_rStream(rStream), m_cstd(0), m_cbSTDBaseInFile(0), m_fStdStylenamesWritten(0)
6863     , m_stiMaxWhenSaved(0), m_istdMaxFixedWhenSaved(0), m_nVerBuiltInNamesWhenSaved(0)
6864     , m_ftcAsci(0), m_ftcFE(0), m_ftcOther(0), m_ftcBi(0)
6865 {
6866     if (!checkSeek(m_rStream, m_rFib.m_fcStshf))
6867         return;
6868 
6869     sal_uInt16 cbStshi = 0; //  2 bytes size of the following STSHI structure
6870     sal_uInt32 nRemaining = m_rFib.m_lcbStshf;
6871     const sal_uInt32 nMinValidStshi = 4;
6872 
6873     if (m_rFib.GetFIBVersion() <= ww::eWW2)
6874     {
6875         cbStshi = 0;
6876         m_cstd = 256;
6877     }
6878     else
6879     {
6880         if (m_rFib.m_nFib < 67) // old Version ? (need to find this again to fix)
6881             cbStshi = nMinValidStshi;
6882         else    // new version
6883         {
6884             if (nRemaining < sizeof(cbStshi))
6885                 return;
6886             // reads the length of the structure in the file
6887             m_rStream.ReadUInt16( cbStshi );
6888             nRemaining-=2;
6889         }
6890     }
6891 
6892     cbStshi = std::min(static_cast<sal_uInt32>(cbStshi), nRemaining);
6893     if (cbStshi < nMinValidStshi)
6894         return;
6895 
6896     const sal_uInt16 nRead = cbStshi;
6897     do
6898     {
6899         m_rStream.ReadUInt16( m_cstd );
6900 
6901         m_rStream.ReadUInt16( m_cbSTDBaseInFile );
6902 
6903         if(  6 > nRead ) break;
6904 
6905         sal_uInt16 a16Bit;
6906         m_rStream.ReadUInt16( a16Bit );
6907         m_fStdStylenamesWritten = a16Bit & 0x0001;
6908 
6909         if(  8 > nRead ) break;
6910         m_rStream.ReadUInt16( m_stiMaxWhenSaved );
6911 
6912         if( 10 > nRead ) break;
6913         m_rStream.ReadUInt16( m_istdMaxFixedWhenSaved );
6914 
6915         if( 12 > nRead ) break;
6916         m_rStream.ReadUInt16( m_nVerBuiltInNamesWhenSaved );
6917 
6918         if( 14 > nRead ) break;
6919         m_rStream.ReadUInt16( m_ftcAsci );
6920 
6921         if( 16 > nRead ) break;
6922         m_rStream.ReadUInt16( m_ftcFE );
6923 
6924         if ( 18 > nRead ) break;
6925         m_rStream.ReadUInt16( m_ftcOther );
6926 
6927         m_ftcBi = m_ftcOther;
6928 
6929         if ( 20 > nRead ) break;
6930         m_rStream.ReadUInt16( m_ftcBi );
6931 
6932         // p.r.n. ignore the rest
6933         if( 20 < nRead )
6934             m_rStream.SeekRel( nRead-20 );
6935     }
6936     while( false ); // trick: the block above will be passed through exactly one time
6937                 //            and that's why we can early exit with "break".
6938 
6939     nRemaining -= cbStshi;
6940 
6941     //There will be stshi.cstd (cbSTD, STD) pairs in the file following the
6942     //STSHI. Note that styles can be empty, i.e. cbSTD == 0
6943     const sal_uInt32 nMinRecordSize = sizeof(sal_uInt16);
6944     const sal_uInt16 nMaxPossibleRecords = nRemaining/nMinRecordSize;
6945 
6946     OSL_ENSURE(m_cstd <= nMaxPossibleRecords,
6947         "allegedly more styles that available data");
6948     m_cstd = o3tl::sanitizing_min(m_cstd, nMaxPossibleRecords);
6949 }
6950 
6951 // Read1STDFixed() reads a style. If the style is completely existent,
6952 // so it has no empty slot, we should allocate memory and a pointer should
6953 // reference to STD (perhaps filled with 0). If the slot is empty,
6954 // it will return a null pointer.
Read1STDFixed(sal_uInt16 & rSkip)6955 std::unique_ptr<WW8_STD> WW8Style::Read1STDFixed(sal_uInt16& rSkip)
6956 {
6957     if (m_rStream.remainingSize() < 2)
6958     {
6959         rSkip = 0;
6960         return nullptr;
6961     }
6962 
6963     std::unique_ptr<WW8_STD> pStd;
6964 
6965     sal_uInt16 cbStd(0);
6966     m_rStream.ReadUInt16(cbStd);   // read length
6967 
6968     const sal_uInt16 nRead = m_cbSTDBaseInFile;
6969     if( cbStd >= m_cbSTDBaseInFile )
6970     {
6971         // Fixed part completely available
6972 
6973         // read fixed part of STD
6974         pStd.reset(new WW8_STD);
6975         memset( pStd.get(), 0, sizeof( *pStd ) );
6976 
6977         do
6978         {
6979             if( 2 > nRead ) break;
6980 
6981             sal_uInt16 a16Bit = 0;
6982             m_rStream.ReadUInt16( a16Bit );
6983             pStd->sti          =        a16Bit & 0x0fff  ;
6984             pStd->fScratch     = sal_uInt16(0 != ( a16Bit & 0x1000 ));
6985             pStd->fInvalHeight = sal_uInt16(0 != ( a16Bit & 0x2000 ));
6986             pStd->fHasUpe      = sal_uInt16(0 != ( a16Bit & 0x4000 ));
6987             pStd->fMassCopy    = sal_uInt16(0 != ( a16Bit & 0x8000 ));
6988 
6989             if( 4 > nRead ) break;
6990             a16Bit = 0;
6991             m_rStream.ReadUInt16( a16Bit );
6992             pStd->sgc      =   a16Bit & 0x000f       ;
6993             pStd->istdBase = ( a16Bit & 0xfff0 ) >> 4;
6994 
6995             if( 6 > nRead ) break;
6996             a16Bit = 0;
6997             m_rStream.ReadUInt16( a16Bit );
6998             pStd->cupx     =   a16Bit & 0x000f       ;
6999             pStd->istdNext = ( a16Bit & 0xfff0 ) >> 4;
7000 
7001             if( 8 > nRead ) break;
7002             m_rStream.ReadUInt16( pStd->bchUpe );
7003 
7004             // from Ver8 this two fields should be added:
7005             if(10 > nRead ) break;
7006             a16Bit = 0;
7007             m_rStream.ReadUInt16( a16Bit );
7008             pStd->fAutoRedef =   a16Bit & 0x0001       ;
7009             pStd->fHidden    = ( a16Bit & 0x0002 ) >> 1;
7010             // You never know: cautionary skipped
7011             if (nRead > 10)
7012             {
7013                 auto nSkip = std::min<sal_uInt64>(nRead - 10, m_rStream.remainingSize());
7014                 m_rStream.Seek(m_rStream.Tell() + nSkip);
7015             }
7016         }
7017         while( false ); // trick: the block above will passed through exactly one time
7018                     //   and can be left early with a "break"
7019 
7020         if (!m_rStream.good() || !nRead)
7021         {
7022             pStd.reset(); // report error with NULL
7023         }
7024 
7025         rSkip = cbStd - m_cbSTDBaseInFile;
7026     }
7027     else
7028     {           // Fixed part too short
7029         if( cbStd )
7030             m_rStream.SeekRel( cbStd );           // skip leftovers
7031         rSkip = 0;
7032     }
7033     return pStd;
7034 }
7035 
Read1Style(sal_uInt16 & rSkip,OUString * pString)7036 std::unique_ptr<WW8_STD> WW8Style::Read1Style(sal_uInt16& rSkip, OUString* pString)
7037 {
7038     // Attention: MacWord-Documents have their Stylenames
7039     // always in ANSI, even if eStructCharSet == CHARSET_MAC !!
7040 
7041     std::unique_ptr<WW8_STD> pStd = Read1STDFixed(rSkip);         // read STD
7042 
7043     // string desired?
7044     if( pString )
7045     {   // real style?
7046         if ( pStd )
7047         {
7048             sal_Int32 nLenStringBytes = 0;
7049             switch( m_rFib.m_nVersion )
7050             {
7051                 case 6:
7052                 case 7:
7053                     // read pascal string
7054                     *pString = read_uInt8_BeltAndBracesString(m_rStream, RTL_TEXTENCODING_MS_1252);
7055                     // leading len and trailing zero --> 2
7056                     nLenStringBytes = pString->getLength() + 2;
7057                     break;
7058                 case 8:
7059                     // handle Unicode-String with leading length short and
7060                     // trailing zero
7061                     if (TestBeltAndBraces(m_rStream))
7062                     {
7063                         *pString = read_uInt16_BeltAndBracesString(m_rStream);
7064                         nLenStringBytes = (pString->getLength() + 2) * 2;
7065                     }
7066                     else
7067                     {
7068                         /*
7069                         #i8114#
7070                         This is supposed to be impossible, it's just supposed
7071                         to be 16 bit count followed by the string and ending
7072                         in a 0 short. But "Lotus SmartSuite Product: Word Pro"
7073                         is creating invalid style names in ww7- format. So we
7074                         use the belt and braces of the ms strings to see if
7075                         they are not corrupt. If they are then we try them as
7076                         8bit ones
7077                         */
7078                         *pString = read_uInt8_BeltAndBracesString(m_rStream,RTL_TEXTENCODING_MS_1252);
7079                         // leading len and trailing zero --> 2
7080                         nLenStringBytes = pString->getLength() + 2;
7081                     }
7082                     break;
7083                 default:
7084                     OSL_ENSURE(false, "It was forgotten to code nVersion!");
7085                     break;
7086             }
7087             if (nLenStringBytes > rSkip)
7088             {
7089                 SAL_WARN("sw.ww8", "WW8Style structure corrupt");
7090                 nLenStringBytes = rSkip;
7091             }
7092             rSkip -= nLenStringBytes;
7093         }
7094         else
7095             pString->clear();   // can not return a name
7096     }
7097     return pStd;
7098 }
7099 
7100 namespace {
7101 const sal_uInt16 maxStrSize = 65;
7102 
7103 struct WW8_FFN_Ver6
7104 {
7105     WW8_FFN_BASE base;
7106     // from Ver6
7107     char szFfn[maxStrSize]; // 0x6 or 0x40 from Ver8 on zero terminated string that
7108                         // records name of font.
7109                         // Maximal size of szFfn is 65 characters.
7110                         // Attention: This array can also be smaller!!!
7111                         // Possibly followed by a second sz which records the
7112                         // name of an alternate font to use if the first named
7113                         // font does not exist on this system.
7114 };
7115 
7116 }
7117 
7118 // #i43762# check font name for illegal characters
lcl_checkFontname(OUString & sString)7119 static void lcl_checkFontname( OUString& sString )
7120 {
7121     // for efficiency, we'd like to use String methods as far as possible.
7122     // Hence, we will:
7123     // 1) convert all invalid chars to \u0001
7124     // 2) then erase all \u0001 chars (if anywhere found), and
7125     // 3) erase leading/trailing ';', in case a font name was
7126     //    completely removed
7127 
7128     // convert all invalid chars to \u0001
7129     OUStringBuffer aBuf(sString);
7130     const sal_Int32 nLen = aBuf.getLength();
7131     bool bFound = false;
7132     for ( sal_Int32 n = 0; n < nLen; ++n )
7133     {
7134         if ( aBuf[n] < 0x20 )
7135         {
7136             aBuf[n] = 1;
7137             bFound = true;
7138         }
7139     }
7140     sString = aBuf.makeStringAndClear();
7141 
7142     // if anything was found, remove \u0001 + leading/trailing ';'
7143     if( bFound )
7144     {
7145         sString = comphelper::string::strip(sString.replaceAll("\001", ""), ';');
7146     }
7147 }
7148 
7149 namespace
7150 {
calcMaxFonts(sal_uInt8 * p,sal_Int32 nFFn)7151     sal_uInt16 calcMaxFonts(sal_uInt8 *p, sal_Int32 nFFn)
7152     {
7153         // Figure out the max number of fonts defined here
7154         sal_uInt16 nMax = 0;
7155         sal_Int32 nRemaining = nFFn;
7156         while (nRemaining)
7157         {
7158             //p[0] is cbFfnM1, the alleged total length of FFN - 1.
7159             //i.e. length after cbFfnM1
7160             const sal_uInt16 cbFfnM1 = *p++;
7161             --nRemaining;
7162 
7163             if (cbFfnM1 > nRemaining)
7164                 break;
7165 
7166             nMax++;
7167             nRemaining -= cbFfnM1;
7168             p += cbFfnM1;
7169         }
7170         return nMax;
7171     }
7172 
readU8(sal_uInt8 const * p,std::size_t offset,sal_uInt8 const * pEnd,T * value)7173     template<typename T> bool readU8(
7174         sal_uInt8 const * p, std::size_t offset, sal_uInt8 const * pEnd,
7175         T * value)
7176     {
7177         assert(p <= pEnd);
7178         assert(value != nullptr);
7179         if (offset >= o3tl::make_unsigned(pEnd - p)) {
7180             return false;
7181         }
7182         *value = p[offset];
7183         return true;
7184     }
7185 
readS16(sal_uInt8 const * p,std::size_t offset,sal_uInt8 const * pEnd,short * value)7186     bool readS16(
7187         sal_uInt8 const * p, std::size_t offset, sal_uInt8 const * pEnd,
7188         short * value)
7189     {
7190         assert(p <= pEnd);
7191         assert(value != nullptr);
7192         if (offset > o3tl::make_unsigned(pEnd - p)
7193             || static_cast<std::size_t>(pEnd - p) - offset < 2)
7194         {
7195             return false;
7196         }
7197         *value = unsigned(p[offset]) + (unsigned(p[offset + 1]) << 8);
7198         return true;
7199     }
7200 
getStringLengthWithMax(sal_uInt8 const * p,std::size_t offset,sal_uInt8 const * pEnd,std::size_t maxchars)7201     sal_Int32 getStringLengthWithMax(
7202         sal_uInt8 const * p, std::size_t offset, sal_uInt8 const * pEnd, std::size_t maxchars)
7203     {
7204         assert(p <= pEnd);
7205         assert(pEnd - p <= SAL_MAX_INT32);
7206         if (offset >= o3tl::make_unsigned(pEnd - p)) {
7207             return -1;
7208         }
7209         std::size_t nbytes = static_cast<std::size_t>(pEnd - p) - offset;
7210         std::size_t nsearch = std::min(nbytes, maxchars + 1);
7211         void const * p2 = std::memchr(p + offset, 0, nsearch);
7212         if (p2 == nullptr) {
7213             return -1;
7214         }
7215         return static_cast<sal_uInt8 const *>(p2) - (p + offset);
7216     }
7217 }
7218 
WW8Fonts(SvStream & rSt,WW8Fib const & rFib)7219 WW8Fonts::WW8Fonts( SvStream& rSt, WW8Fib const & rFib )
7220 {
7221     // Attention: MacWord-Documents have their Fontnames
7222     // always in ANSI, even if eStructCharSet == CHARSET_MAC !!
7223     if( rFib.m_lcbSttbfffn <= 2 )
7224     {
7225         OSL_ENSURE( false, "font table is broken! (rFib.lcbSttbfffn < 2)" );
7226         return;
7227     }
7228 
7229     if (!checkSeek(rSt, rFib.m_fcSttbfffn))
7230         return;
7231 
7232     sal_Int32 nFFn = rFib.m_lcbSttbfffn - 2;
7233 
7234     const sal_uInt64 nMaxPossible = rSt.remainingSize();
7235     if (o3tl::make_unsigned(nFFn) > nMaxPossible)
7236     {
7237         SAL_WARN("sw.ww8", "FFN structure longer than available data");
7238         nFFn = nMaxPossible;
7239     }
7240 
7241     // allocate Font Array
7242     std::vector<sal_uInt8> aA(nFFn);
7243     memset(aA.data(), 0, nFFn);
7244 
7245     ww::WordVersion eVersion = rFib.GetFIBVersion();
7246 
7247     sal_uInt16 nMax(0);
7248     if( eVersion >= ww::eWW8 )
7249     {
7250         // bVer8: read the count of strings in nMax
7251         rSt.ReadUInt16(nMax);
7252     }
7253 
7254     // Ver8:  skip undefined uint16
7255     // Ver67: skip the herein stored total byte of structure
7256     //        - we already got that information in rFib.lcbSttbfffn
7257     rSt.SeekRel( 2 );
7258 
7259     // read all font information
7260     nFFn = rSt.ReadBytes(aA.data(), nFFn);
7261     sal_uInt8 * const pEnd = aA.data() + nFFn;
7262     const sal_uInt16 nCalcMax = calcMaxFonts(aA.data(), nFFn);
7263 
7264     if (eVersion < ww::eWW8)
7265         nMax = nCalcMax;
7266     else
7267     {
7268         //newer versions include supportive count of fonts, so take min of that
7269         //and calced max
7270         nMax = std::min(nMax, nCalcMax);
7271     }
7272 
7273     if (nMax)
7274     {
7275         // allocate Index Array
7276         m_aFontA.resize(nMax);
7277         WW8_FFN* p = m_aFontA.data();
7278 
7279         if( eVersion <= ww::eWW2 )
7280         {
7281             sal_uInt8 const * pVer2 = aA.data();
7282             sal_uInt16 i = 0;
7283             for(; i<nMax; ++i, ++p)
7284             {
7285                 if (!readU8(
7286                         pVer2, offsetof(WW8_FFN_BASE, cbFfnM1), pEnd,
7287                         &p->aFFNBase.cbFfnM1))
7288                 {
7289                     break;
7290                 }
7291 
7292                 p->aFFNBase.prg       =  0;
7293                 p->aFFNBase.fTrueType = 0;
7294                 p->aFFNBase.ff        = 0;
7295 
7296                 if (!(readU8(pVer2, 1, pEnd, &p->aFFNBase.wWeight)
7297                       && readU8(pVer2, 2, pEnd, &p->aFFNBase.chs)))
7298                 {
7299                     break;
7300                 }
7301                 /*
7302                  #i8726# 7- seems to encode the name in the same encoding as
7303                  the font, e.g load the doc in 97 and save to see the unicode
7304                  ver of the asian fontnames in that example to confirm.
7305                 */
7306                 rtl_TextEncoding eEnc = WW8Fib::GetFIBCharset(p->aFFNBase.chs, rFib.m_lid);
7307                 if ((eEnc == RTL_TEXTENCODING_SYMBOL) || (eEnc == RTL_TEXTENCODING_DONTKNOW))
7308                     eEnc = RTL_TEXTENCODING_MS_1252;
7309 
7310                 const size_t nStringOffset = 1 + 2;
7311                 sal_Int32 n = getStringLengthWithMax(pVer2, nStringOffset, pEnd, maxStrSize);
7312                 if (n == -1) {
7313                     break;
7314                 }
7315                 p->sFontname = OUString(
7316                     reinterpret_cast<char const *>(pVer2 + nStringOffset), n, eEnc);
7317                 pVer2 = pVer2 + p->aFFNBase.cbFfnM1 + 1;
7318             }
7319             nMax = i;
7320         }
7321         else if( eVersion < ww::eWW8 )
7322         {
7323             sal_uInt8 const * pVer6 = aA.data();
7324             sal_uInt16 i = 0;
7325             for(; i<nMax; ++i, ++p)
7326             {
7327                 if (!readU8(
7328                         pVer6, offsetof(WW8_FFN_BASE, cbFfnM1), pEnd,
7329                         &p->aFFNBase.cbFfnM1))
7330                 {
7331                     break;
7332                 }
7333                 sal_uInt8 c2;
7334                 if (!readU8(pVer6, 1, pEnd, &c2)) {
7335                     break;
7336                 }
7337 
7338                 p->aFFNBase.prg       =  c2 & 0x02;
7339                 p->aFFNBase.fTrueType = (c2 & 0x04) >> 2;
7340                 // skip a reserve bit
7341                 p->aFFNBase.ff        = (c2 & 0x70) >> 4;
7342 
7343                 if (!(readS16(
7344                           pVer6, offsetof(WW8_FFN_BASE, wWeight), pEnd,
7345                           &p->aFFNBase.wWeight)
7346                       && readU8(
7347                           pVer6, offsetof(WW8_FFN_BASE, chs), pEnd, &p->aFFNBase.chs)
7348                       && readU8(
7349                           pVer6, offsetof(WW8_FFN_BASE, ibszAlt), pEnd,
7350                           &p->aFFNBase.ibszAlt)))
7351                 {
7352                     break;
7353                 }
7354                 /*
7355                  #i8726# 7- seems to encode the name in the same encoding as
7356                  the font, e.g load the doc in 97 and save to see the unicode
7357                  ver of the asian fontnames in that example to confirm.
7358                  */
7359                 rtl_TextEncoding eEnc = WW8Fib::GetFIBCharset(p->aFFNBase.chs, rFib.m_lid);
7360                 if ((eEnc == RTL_TEXTENCODING_SYMBOL) || (eEnc == RTL_TEXTENCODING_DONTKNOW))
7361                     eEnc = RTL_TEXTENCODING_MS_1252;
7362                 const size_t nStringOffset = offsetof(WW8_FFN_Ver6, szFfn);
7363                 sal_Int32 n = getStringLengthWithMax(pVer6, nStringOffset, pEnd, maxStrSize);
7364                 if (n == -1) {
7365                     break;
7366                 }
7367                 p->sFontname = OUString(reinterpret_cast<char const*>(pVer6 + nStringOffset), n, eEnc);
7368                 if (p->aFFNBase.ibszAlt && p->aFFNBase.ibszAlt < maxStrSize) //don't start after end of string
7369                 {
7370                     const size_t nAltStringOffset = offsetof(WW8_FFN_Ver6, szFfn) + p->aFFNBase.ibszAlt;
7371                     n = getStringLengthWithMax(pVer6, nAltStringOffset, pEnd, maxStrSize);
7372                     if (n == -1) {
7373                         break;
7374                     }
7375                     p->sFontname += ";" + OUString(reinterpret_cast<char const*>(pVer6 + nAltStringOffset),
7376                         n, eEnc);
7377                 }
7378                 else
7379                 {
7380                     //#i18369# if it's a symbol font set Symbol as fallback
7381                     if (
7382                          RTL_TEXTENCODING_SYMBOL == WW8Fib::GetFIBCharset(p->aFFNBase.chs, rFib.m_lid)
7383                          && p->sFontname!="Symbol"
7384                        )
7385                     {
7386                         p->sFontname += ";Symbol";
7387                     }
7388                 }
7389                 pVer6 = pVer6 + p->aFFNBase.cbFfnM1 + 1;
7390             }
7391             nMax = i;
7392         }
7393         else
7394         {
7395             //count of bytes in minimum FontFamilyInformation payload
7396             const sal_uInt8 cbMinFFNPayload = 41;
7397             sal_uInt16 nValidFonts = 0;
7398             sal_Int32 nRemainingFFn = nFFn;
7399             sal_uInt8* pRaw = aA.data();
7400             for (sal_uInt16 i=0; i < nMax && nRemainingFFn; ++i, ++p)
7401             {
7402                 //pRaw[0] is cbFfnM1, the alleged total length of FFN - 1
7403                 //i.e. length after cbFfnM1
7404                 sal_uInt8 cbFfnM1 = *pRaw++;
7405                 --nRemainingFFn;
7406 
7407                 if (cbFfnM1 > nRemainingFFn)
7408                     break;
7409 
7410                 if (cbFfnM1 < cbMinFFNPayload)
7411                     break;
7412 
7413                 p->aFFNBase.cbFfnM1 = cbFfnM1;
7414 
7415                 sal_uInt8 *pVer8 = pRaw;
7416 
7417                 sal_uInt8 c2 = *pVer8++;
7418                 --cbFfnM1;
7419 
7420                 p->aFFNBase.prg = c2 & 0x02;
7421                 p->aFFNBase.fTrueType = (c2 & 0x04) >> 2;
7422                 // skip a reserve bit
7423                 p->aFFNBase.ff = (c2 & 0x70) >> 4;
7424 
7425                 p->aFFNBase.wWeight = SVBT16ToUInt16(*reinterpret_cast<SVBT16*>(pVer8));
7426                 pVer8+=2;
7427                 cbFfnM1-=2;
7428 
7429                 p->aFFNBase.chs = *pVer8++;
7430                 --cbFfnM1;
7431 
7432                 p->aFFNBase.ibszAlt = *pVer8++;
7433                 --cbFfnM1;
7434 
7435                 pVer8 += 10; //PANOSE
7436                 cbFfnM1-=10;
7437                 pVer8 += 24; //FONTSIGNATURE
7438                 cbFfnM1-=24;
7439 
7440                 assert(cbFfnM1 >= 2);
7441 
7442                 sal_uInt8 nMaxNullTerminatedPossible = cbFfnM1/2 - 1;
7443                 sal_Unicode *pPrimary = reinterpret_cast<sal_Unicode*>(pVer8);
7444                 pPrimary[nMaxNullTerminatedPossible] = 0;
7445 #ifdef OSL_BIGENDIAN
7446                 swapEndian(pPrimary);
7447 #endif
7448                 p->sFontname = pPrimary;
7449                 if (p->aFFNBase.ibszAlt && p->aFFNBase.ibszAlt < nMaxNullTerminatedPossible)
7450                 {
7451                     sal_Unicode *pSecondary = pPrimary + p->aFFNBase.ibszAlt;
7452 #ifdef OSL_BIGENDIAN
7453                     swapEndian(pSecondary);
7454 #endif
7455                     p->sFontname += OUString::Concat(";") + pSecondary;
7456                 }
7457 
7458                 // #i43762# check font name for illegal characters
7459                 lcl_checkFontname( p->sFontname );
7460 
7461                 // set pointer one font back to original array
7462                 pRaw += p->aFFNBase.cbFfnM1;
7463                 nRemainingFFn -= p->aFFNBase.cbFfnM1;
7464                 ++nValidFonts;
7465             }
7466             OSL_ENSURE(nMax == nValidFonts, "Font count differs with availability");
7467             nMax = std::min(nMax, nValidFonts);
7468         }
7469     }
7470     m_aFontA.resize(nMax);
7471     m_aFontA.shrink_to_fit();
7472 }
7473 
GetFont(sal_uInt16 nNum) const7474 const WW8_FFN* WW8Fonts::GetFont( sal_uInt16 nNum ) const
7475 {
7476     if (nNum >= m_aFontA.size())
7477         return nullptr;
7478 
7479     return &m_aFontA[nNum];
7480 }
7481 
7482 // Search after a header/footer for an index in the ww list from header/footer
7483 
7484 // specials for WinWord6 and -7:
7485 //
7486 // 1) At the start of reading we must build WWPLCF_HdFt with Fib and Dop
7487 // 2) The main text must be read sequentially over all sections
7488 // 3) For every header/footer in the main text, we must call UpdateIndex()
7489 //    exactly once with the parameter from the attribute.
7490 //    (per section can be maximally one). This call must take place *after*
7491 //    the last call from GetTextPos().
7492 // 4) GetTextPos() can be called with exactly one flag
7493 //    out of WW8_{FOOTER,HEADER}_{ODD,EVEN,FIRST} (Do not change!)
7494 //  -> maybe we can get a right result then
7495 
WW8PLCF_HdFt(SvStream * pSt,WW8Fib const & rFib,WW8Dop const & rDop)7496 WW8PLCF_HdFt::WW8PLCF_HdFt( SvStream* pSt, WW8Fib const & rFib, WW8Dop const & rDop )
7497     : m_aPLCF(*pSt, rFib.m_fcPlcfhdd , rFib.m_lcbPlcfhdd , 0)
7498 {
7499     m_nIdxOffset = 0;
7500 
7501      /*
7502       This dop.grpfIhdt has a bit set for each special
7503       footnote *and endnote!!* separator,continuation separator, and
7504       continuation notice entry, the documentation does not mention the
7505       endnote separators, the documentation also gets the index numbers
7506       backwards when specifying which bits to test. The bottom six bits
7507       of this value must be tested and skipped over. Each section's
7508       grpfIhdt is then tested for the existence of the appropriate headers
7509       and footers, at the end of each section the nIdxOffset must be updated
7510       to point to the beginning of the next section's group of headers and
7511       footers in this PLCF, UpdateIndex does that task.
7512       */
7513     for( sal_uInt8 nI = 0x1; nI <= 0x20; nI <<= 1 )
7514         if( nI & rDop.grpfIhdt )                // bit set?
7515             m_nIdxOffset++;
7516 }
7517 
GetTextPos(sal_uInt8 grpfIhdt,sal_uInt8 nWhich,WW8_CP & rStart,WW8_CP & rLen)7518 bool WW8PLCF_HdFt::GetTextPos(sal_uInt8 grpfIhdt, sal_uInt8 nWhich, WW8_CP& rStart,
7519     WW8_CP& rLen)
7520 {
7521     sal_uInt8 nI = 0x01;
7522     short nIdx = m_nIdxOffset;
7523     while (true)
7524     {
7525         if( nI & nWhich )
7526             break;                      // found
7527         if( grpfIhdt & nI )
7528             nIdx++;                     // uninteresting Header / Footer
7529         nI <<= 1;                       // text next bit
7530         if( nI > 0x20 )
7531             return false;               // not found
7532     }
7533                                         // nIdx is HdFt-Index
7534     WW8_CP nEnd;
7535     void* pData;
7536 
7537     m_aPLCF.SetIdx( nIdx );               // Lookup suitable CP
7538     m_aPLCF.Get( rStart, nEnd, pData );
7539     if (nEnd < rStart)
7540     {
7541         SAL_WARN("sw.ww8", "End " << nEnd << " before Start " << rStart);
7542         return false;
7543     }
7544 
7545     bool bFail = o3tl::checked_sub(nEnd, rStart, rLen);
7546     if (bFail)
7547     {
7548         SAL_WARN("sw.ww8", "broken offset, ignoring");
7549         return false;
7550     }
7551 
7552     m_aPLCF.advance();
7553 
7554     return true;
7555 }
7556 
GetTextPosExact(short nIdx,WW8_CP & rStart,WW8_CP & rLen)7557 void WW8PLCF_HdFt::GetTextPosExact(short nIdx, WW8_CP& rStart, WW8_CP& rLen)
7558 {
7559     WW8_CP nEnd;
7560     void* pData;
7561 
7562     m_aPLCF.SetIdx( nIdx );               // Lookup suitable CP
7563     m_aPLCF.Get( rStart, nEnd, pData );
7564     if (nEnd < rStart)
7565     {
7566         SAL_WARN("sw.ww8", "End " << nEnd << " before Start " << rStart);
7567         rLen = 0;
7568         return;
7569     }
7570     if (o3tl::checked_sub(nEnd, rStart, rLen))
7571     {
7572         SAL_WARN("sw.ww8", "GetTextPosExact overflow");
7573         rLen = 0;
7574     }
7575 }
7576 
UpdateIndex(sal_uInt8 grpfIhdt)7577 void WW8PLCF_HdFt::UpdateIndex( sal_uInt8 grpfIhdt )
7578 {
7579     // Caution: Description is not correct
7580     for( sal_uInt8 nI = 0x01; nI <= 0x20; nI <<= 1 )
7581         if( nI & grpfIhdt )
7582             m_nIdxOffset++;
7583 }
7584 
WW8Dop(SvStream & rSt,sal_Int16 nFib,sal_Int32 nPos,sal_uInt32 nSize)7585 WW8Dop::WW8Dop(SvStream& rSt, sal_Int16 nFib, sal_Int32 nPos, sal_uInt32 nSize):
7586     fFacingPages(false), fWidowControl(false), fPMHMainDoc(false), grfSuppression(0), fpc(0),
7587     grpfIhdt(0), rncFootnote(0), nFootnote(0), fOutlineDirtySave(false), fOnlyMacPics(false),
7588     fOnlyWinPics(false), fLabelDoc(false), fHyphCapitals(false), fAutoHyphen(false),
7589     fFormNoFields(false), fLinkStyles(false), fRevMarking(false), fBackup(false),
7590     fExactCWords(false), fPagHidden(false), fPagResults(false), fLockAtn(false),
7591     fMirrorMargins(false), fReadOnlyRecommended(false), fDfltTrueType(false),
7592     fPagSuppressTopSpacing(false), fProtEnabled(false), fDispFormFieldSel(false), fRMView(false),
7593     fRMPrint(false), fWriteReservation(false), fLockRev(false), fEmbedFonts(false),
7594     copts_fNoTabForInd(false), copts_fNoSpaceRaiseLower(false), copts_fSuppressSpbfAfterPgBrk(false),
7595     copts_fWrapTrailSpaces(false), copts_fMapPrintTextColor(false), copts_fNoColumnBalance(false),
7596     copts_fConvMailMergeEsc(false), copts_fSuppressTopSpacing(false),
7597     copts_fOrigWordTableRules(false), copts_fTransparentMetafiles(false),
7598     copts_fShowBreaksInFrames(false), copts_fSwapBordersFacingPgs(false), copts_fExpShRtn(false),
7599     rncEdn(0), nEdn(0), epc(0), fPrintFormData(false), fSaveFormData(false), fShadeFormData(false),
7600     fWCFootnoteEdn(false), wvkSaved(0), wScaleSaved(0), zkSaved(0), fRotateFontW6(false),
7601     iGutterPos(false), fNoTabForInd(false), fNoSpaceRaiseLower(false),
7602     fSuppressSpbfAfterPageBreak(false), fWrapTrailSpaces(false), fMapPrintTextColor(false),
7603     fNoColumnBalance(false), fConvMailMergeEsc(false), fSuppressTopSpacing(false),
7604     fOrigWordTableRules(false), fTransparentMetafiles(false), fShowBreaksInFrames(false),
7605     fSwapBordersFacingPgs(false), fCompatibilityOptions_Unknown1_13(false), fExpShRtn(false),
7606     fCompatibilityOptions_Unknown1_15(false), fCompatibilityOptions_Unknown1_16(false),
7607     fSuppressTopSpacingMac5(false), fTruncDxaExpand(false), fPrintBodyBeforeHdr(false),
7608     fNoLeading(false), fCompatibilityOptions_Unknown1_21(false), fMWSmallCaps(false),
7609     fCompatibilityOptions_Unknown1_23(false), fCompatibilityOptions_Unknown1_24(false),
7610     fCompatibilityOptions_Unknown1_25(false), fCompatibilityOptions_Unknown1_26(false),
7611     fCompatibilityOptions_Unknown1_27(false), fCompatibilityOptions_Unknown1_28(false),
7612     fCompatibilityOptions_Unknown1_29(false), fCompatibilityOptions_Unknown1_30(false),
7613     fCompatibilityOptions_Unknown1_31(false), fUsePrinterMetrics(false), lvl(0), fHtmlDoc(false),
7614     fSnapBorder(false), fIncludeHeader(false), fIncludeFooter(false), fForcePageSizePag(false),
7615     fMinFontSizePag(false), fHaveVersions(false), fAutoVersion(false),
7616     fCompatibilityOptions_Unknown2_1(false), fCompatibilityOptions_Unknown2_2(false),
7617     fDontUseHTMLAutoSpacing(false), fCompatibilityOptions_Unknown2_4(false),
7618     fCompatibilityOptions_Unknown2_5(false), fCompatibilityOptions_Unknown2_6(false),
7619     fCompatibilityOptions_Unknown2_7(false), fCompatibilityOptions_Unknown2_8(false),
7620     fCompatibilityOptions_Unknown2_9(false), fCompatibilityOptions_Unknown2_10(false),
7621     fDontBreakWrappedTables(false), fCompatibilityOptions_Unknown2_12(false),
7622     fCompatibilityOptions_Unknown2_13(false), fCompatibilityOptions_Unknown2_14(false),
7623     fCompatibilityOptions_Unknown2_15(false), fCompatibilityOptions_Unknown2_16(false),
7624     fCompatibilityOptions_Unknown2_17(false), fCompatibilityOptions_Unknown2_18(false),
7625     fCompatibilityOptions_Unknown2_19(false), fCompatibilityOptions_Unknown2_20(false),
7626     fCompatibilityOptions_Unknown2_21(false), fCompatibilityOptions_Unknown2_22(false),
7627     fCompatibilityOptions_Unknown2_23(false), fCompatibilityOptions_Unknown2_24(false),
7628     fCompatibilityOptions_Unknown2_25(false), fCompatibilityOptions_Unknown2_26(false),
7629     fCompatibilityOptions_Unknown2_27(false), fCompatibilityOptions_Unknown2_28(false),
7630     fCompatibilityOptions_Unknown2_29(false), fCompatibilityOptions_Unknown2_30(false),
7631     fCompatibilityOptions_Unknown2_31(false), fCompatibilityOptions_Unknown2_32(false),
7632     fUnknown3(0), fUseBackGroundInAllmodes(false), fDoNotEmbedSystemFont(false), fWordCompat(false),
7633     fLiveRecover(false), fEmbedFactoids(false), fFactoidXML(false), fFactoidAllDone(false),
7634     fFolioPrint(false), fReverseFolio(false), iTextLineEnding(0), fHideFcc(false),
7635     fAcetateShowMarkup(false), fAcetateShowAtn(false), fAcetateShowInsDel(false),
7636     fAcetateShowProps(false)
7637         // in C++20 with P06831R1 "Default member initializers for bit-fields (revision 1)", the
7638         // above bit-field member initializations can be moved to the class definition
7639 {
7640     fDontUseHTMLAutoSpacing = true; //default
7641     fAcetateShowAtn = true; //default
7642     const sal_uInt32 nMaxDopSize = 0x268;
7643     std::unique_ptr<sal_uInt8[]> pDataPtr( new sal_uInt8[ nMaxDopSize ] );
7644     sal_uInt8* pData = pDataPtr.get();
7645 
7646     sal_uInt32 nRead = std::min(nMaxDopSize, nSize);
7647     if (nSize < 2 || !checkSeek(rSt, nPos) || nRead != rSt.ReadBytes(pData, nRead))
7648         nDopError = ERR_SWG_READ_ERROR;     // report error
7649     else
7650     {
7651         if (nMaxDopSize > nRead)
7652             memset( pData + nRead, 0, nMaxDopSize - nRead );
7653 
7654         // interpret the data
7655         sal_uInt32 a32Bit;
7656         sal_uInt16 a16Bit;
7657         sal_uInt8   a8Bit;
7658 
7659         a16Bit = Get_UShort( pData );        // 0 0x00
7660         fFacingPages        = 0 != ( a16Bit  &  0x0001 )     ;
7661         fWidowControl       = 0 != ( a16Bit  &  0x0002 )     ;
7662         fPMHMainDoc         = 0 != ( a16Bit  &  0x0004 )     ;
7663         grfSuppression      =      ( a16Bit  &  0x0018 ) >> 3;
7664         fpc                 =      ( a16Bit  &  0x0060 ) >> 5;
7665         grpfIhdt            =      ( a16Bit  &  0xff00 ) >> 8;
7666 
7667         a16Bit = Get_UShort( pData );        // 2 0x02
7668         rncFootnote              =   a16Bit  &  0x0003        ;
7669         nFootnote                = ( a16Bit  & ~0x0003 ) >> 2 ;
7670 
7671         a8Bit = Get_Byte( pData );           // 4 0x04
7672         fOutlineDirtySave      = 0 != ( a8Bit  &  0x01   );
7673 
7674         a8Bit = Get_Byte( pData );           // 5 0x05
7675         fOnlyMacPics           = 0 != ( a8Bit  &  0x01   );
7676         fOnlyWinPics           = 0 != ( a8Bit  &  0x02   );
7677         fLabelDoc              = 0 != ( a8Bit  &  0x04   );
7678         fHyphCapitals          = 0 != ( a8Bit  &  0x08   );
7679         fAutoHyphen            = 0 != ( a8Bit  &  0x10   );
7680         fFormNoFields          = 0 != ( a8Bit  &  0x20   );
7681         fLinkStyles            = 0 != ( a8Bit  &  0x40   );
7682         fRevMarking            = 0 != ( a8Bit  &  0x80   );
7683 
7684         a8Bit = Get_Byte( pData );           // 6 0x06
7685         fBackup                = 0 != ( a8Bit  &  0x01   );
7686         fExactCWords           = 0 != ( a8Bit  &  0x02   );
7687         fPagHidden             = 0 != ( a8Bit  &  0x04   );
7688         fPagResults            = 0 != ( a8Bit  &  0x08   );
7689         fLockAtn               = 0 != ( a8Bit  &  0x10   );
7690         fMirrorMargins         = 0 != ( a8Bit  &  0x20   );
7691         fReadOnlyRecommended   = 0 != ( a8Bit  &  0x40   );
7692         fDfltTrueType          = 0 != ( a8Bit  &  0x80   );
7693 
7694         a8Bit = Get_Byte( pData );           // 7 0x07
7695         fPagSuppressTopSpacing = 0 != ( a8Bit  &  0x01   );
7696         fProtEnabled           = 0 != ( a8Bit  &  0x02   );
7697         fDispFormFieldSel        = 0 != ( a8Bit  &  0x04   );
7698         fRMView                = 0 != ( a8Bit  &  0x08   );
7699         fRMPrint               = 0 != ( a8Bit  &  0x10   );
7700         fWriteReservation      = 0 != ( a8Bit  &  0x20   );
7701         fLockRev               = 0 != ( a8Bit  &  0x40   );
7702         fEmbedFonts            = 0 != ( a8Bit  &  0x80   );
7703 
7704         a8Bit = Get_Byte( pData );           // 8 0x08
7705         copts_fNoTabForInd           = 0 != ( a8Bit  &  0x01   );
7706         copts_fNoSpaceRaiseLower     = 0 != ( a8Bit  &  0x02   );
7707         copts_fSuppressSpbfAfterPgBrk = 0 != ( a8Bit  &  0x04   );
7708         copts_fWrapTrailSpaces       = 0 != ( a8Bit  &  0x08   );
7709         copts_fMapPrintTextColor     = 0 != ( a8Bit  &  0x10   );
7710         copts_fNoColumnBalance       = 0 != ( a8Bit  &  0x20   );
7711         copts_fConvMailMergeEsc      = 0 != ( a8Bit  &  0x40   );
7712         copts_fSuppressTopSpacing    = 0 != ( a8Bit  &  0x80   );
7713 
7714         a8Bit = Get_Byte( pData );           // 9 0x09
7715         copts_fOrigWordTableRules    = 0 != ( a8Bit  &  0x01   );
7716         copts_fTransparentMetafiles  = 0 != ( a8Bit  &  0x02   );
7717         copts_fShowBreaksInFrames    = 0 != ( a8Bit  &  0x04   );
7718         copts_fSwapBordersFacingPgs  = 0 != ( a8Bit  &  0x08   );
7719         copts_fExpShRtn              = 0 != ( a8Bit  &  0x20   );  // #i56856#
7720 
7721         dxaTab = Get_Short( pData );         // 10 0x0a
7722         wSpare = Get_UShort( pData );        // 12 0x0c
7723         dxaHotZ = Get_UShort( pData );       // 14 0x0e
7724         cConsecHypLim = Get_UShort( pData ); // 16 0x10
7725         wSpare2 = Get_UShort( pData );       // 18 0x12
7726         dttmCreated = Get_Long( pData );     // 20 0x14
7727         dttmRevised = Get_Long( pData );     // 24 0x18
7728         dttmLastPrint = Get_Long( pData );   // 28 0x1c
7729         nRevision = Get_Short( pData );      // 32 0x20
7730         tmEdited = Get_Long( pData );        // 34 0x22
7731         cWords = Get_Long( pData );          // 38 0x26
7732         cCh = Get_Long( pData );             // 42 0x2a
7733         cPg = Get_Short( pData );            // 46 0x2e
7734         cParas = Get_Long( pData );          // 48 0x30
7735 
7736         a16Bit = Get_UShort( pData );        // 52 0x34
7737         rncEdn =   a16Bit &  0x0003       ;
7738         nEdn   = ( a16Bit & ~0x0003 ) >> 2;
7739 
7740         a16Bit = Get_UShort( pData );        // 54 0x36
7741         epc            =   a16Bit &  0x0003       ;
7742         nfcFootnoteRef      = ( a16Bit &  0x003c ) >> 2;
7743         nfcEdnRef      = ( a16Bit &  0x03c0 ) >> 6;
7744         fPrintFormData = 0 != ( a16Bit &  0x0400 );
7745         fSaveFormData  = 0 != ( a16Bit &  0x0800 );
7746         fShadeFormData = 0 != ( a16Bit &  0x1000 );
7747         fWCFootnoteEdn      = 0 != ( a16Bit &  0x8000 );
7748 
7749         cLines = Get_Long( pData );          // 56 0x38
7750         cWordsFootnoteEnd = Get_Long( pData );    // 60 0x3c
7751         cChFootnoteEdn = Get_Long( pData );       // 64 0x40
7752         cPgFootnoteEdn = Get_Short( pData );      // 68 0x44
7753         cParasFootnoteEdn = Get_Long( pData );    // 70 0x46
7754         cLinesFootnoteEdn = Get_Long( pData );    // 74 0x4a
7755         lKeyProtDoc = Get_Long( pData );     // 78 0x4e
7756 
7757         a16Bit = Get_UShort( pData );        // 82 0x52
7758         wvkSaved    =   a16Bit & 0x0007        ;
7759         wScaleSaved = ( a16Bit & 0x0ff8 ) >> 3 ;
7760         zkSaved     = ( a16Bit & 0x3000 ) >> 12;
7761         fRotateFontW6 = ( a16Bit & 0x4000 ) >> 14;
7762         iGutterPos = ( a16Bit &  0x8000 ) >> 15;
7763 
7764         if (nFib >= 103) // Word 6/32bit, 95, 97, 2000, 2002, 2003, 2007
7765         {
7766             a32Bit = Get_ULong( pData );     // 84 0x54
7767             SetCompatibilityOptions(a32Bit);
7768         }
7769 
7770         //#i22436#, for all WW7- documents
7771         if (nFib <= 104) // Word 95
7772             fUsePrinterMetrics = true;
7773 
7774         if (nFib > 105) // Word 97, 2000, 2002, 2003, 2007
7775         {
7776             adt = Get_Short( pData );            // 88 0x58
7777 
7778             doptypography.ReadFromMem(pData);    // 90 0x5a
7779 
7780             memcpy( &dogrid, pData, sizeof( WW8_DOGRID )); // 400 0x190
7781             pData += sizeof( WW8_DOGRID );
7782 
7783             a16Bit = Get_UShort( pData );        // 410 0x19a
7784             // the following 9 bit are uninteresting
7785             fHtmlDoc                = ( a16Bit &  0x0200 ) >>  9 ;
7786             fSnapBorder             = ( a16Bit &  0x0800 ) >> 11 ;
7787             fIncludeHeader          = ( a16Bit &  0x1000 ) >> 12 ;
7788             fIncludeFooter          = ( a16Bit &  0x2000 ) >> 13 ;
7789             fForcePageSizePag       = ( a16Bit &  0x4000 ) >> 14 ;
7790             fMinFontSizePag         = ( a16Bit &  0x8000 ) >> 15 ;
7791 
7792             a16Bit = Get_UShort( pData );        // 412 0x19c
7793             fHaveVersions   = 0 != ( a16Bit  &  0x0001 );
7794             fAutoVersion    = 0 != ( a16Bit  &  0x0002 );
7795 
7796             pData += 12;                         // 414 0x19e
7797 
7798             cChWS = Get_Long( pData );           // 426 0x1aa
7799             cChWSFootnoteEdn = Get_Long( pData );     // 430 0x1ae
7800             grfDocEvents = Get_Long( pData );    // 434 0x1b2
7801 
7802             pData += 4+30+8;  // 438 0x1b6; 442 0x1ba; 472 0x1d8; 476 0x1dc
7803 
7804             cDBC = Get_Long( pData );            // 480 0x1e0
7805             cDBCFootnoteEdn = Get_Long( pData );      // 484 0x1e4
7806 
7807             pData += 1 * sizeof( sal_Int32);         // 488 0x1e8
7808 
7809             nfcFootnoteRef = Get_Short( pData );      // 492 0x1ec
7810             nfcEdnRef = Get_Short( pData );      // 494 0x1ee
7811             hpsZoomFontPag = Get_Short( pData ); // 496 0x1f0
7812             dywDispPag = Get_Short( pData );     // 498 0x1f2
7813 
7814             if (nRead >= 516)
7815             {
7816                 //500 -> 508, Appear to be repeated here in 2000+
7817                 pData += 8;                      // 500 0x1f4
7818                 a32Bit = Get_Long( pData );      // 508 0x1fc
7819                 SetCompatibilityOptions(a32Bit);
7820                 a32Bit = Get_Long( pData );      // 512 0x200
7821 
7822                 // i#78591#
7823                 SetCompatibilityOptions2(a32Bit);
7824             }
7825             if (nRead >= 550)
7826             {
7827                 pData += 32;
7828                 a16Bit = Get_UShort( pData );
7829                 fDoNotEmbedSystemFont = ( a16Bit &  0x0001 );
7830                 fWordCompat = ( a16Bit &  0x0002 ) >> 1;
7831                 fLiveRecover = ( a16Bit &  0x0004 ) >> 2;
7832                 fEmbedFactoids = ( a16Bit &  0x0008 ) >> 3;
7833                 fFactoidXML = ( a16Bit &  0x00010 ) >> 4;
7834                 fFactoidAllDone = ( a16Bit &  0x0020 ) >> 5;
7835                 fFolioPrint = ( a16Bit &  0x0040 ) >> 6;
7836                 fReverseFolio = ( a16Bit &  0x0080 ) >> 7;
7837                 iTextLineEnding = ( a16Bit &  0x0700 ) >> 8;
7838                 fHideFcc = ( a16Bit &  0x0800 ) >> 11;
7839                 fAcetateShowMarkup = ( a16Bit &  0x1000 ) >> 12;
7840                 fAcetateShowAtn = ( a16Bit &  0x2000 ) >> 13;
7841                 fAcetateShowInsDel = ( a16Bit &  0x4000 ) >> 14;
7842                 fAcetateShowProps = ( a16Bit &  0x8000 ) >> 15;
7843             }
7844             if (nRead >= 600)
7845             {
7846                 pData += 48;
7847                 a16Bit = Get_Short(pData);
7848                 fUseBackGroundInAllmodes = (a16Bit & 0x0080) >> 7;
7849             }
7850         }
7851     }
7852 }
7853 
WW8Dop()7854 WW8Dop::WW8Dop():
7855     fFacingPages(false), fWidowControl(true), fPMHMainDoc(false), grfSuppression(0), fpc(1),
7856     grpfIhdt(0), rncFootnote(0), nFootnote(1), fOutlineDirtySave(true), fOnlyMacPics(false),
7857     fOnlyWinPics(false), fLabelDoc(false), fHyphCapitals(true), fAutoHyphen(false),
7858     fFormNoFields(false), fLinkStyles(false), fRevMarking(false), fBackup(true),
7859     fExactCWords(false), fPagHidden(true), fPagResults(true), fLockAtn(false),
7860     fMirrorMargins(false), fReadOnlyRecommended(false), fDfltTrueType(true),
7861     fPagSuppressTopSpacing(false), fProtEnabled(false), fDispFormFieldSel(false), fRMView(true),
7862     fRMPrint(true), fWriteReservation(false), fLockRev(false), fEmbedFonts(false),
7863     copts_fNoTabForInd(false), copts_fNoSpaceRaiseLower(false), copts_fSuppressSpbfAfterPgBrk(false),
7864     copts_fWrapTrailSpaces(false), copts_fMapPrintTextColor(false), copts_fNoColumnBalance(false),
7865     copts_fConvMailMergeEsc(false), copts_fSuppressTopSpacing(false),
7866     copts_fOrigWordTableRules(false), copts_fTransparentMetafiles(false),
7867     copts_fShowBreaksInFrames(false), copts_fSwapBordersFacingPgs(false), copts_fExpShRtn(false),
7868     dxaTab(0x2d0), dxaHotZ(0x168), nRevision(1),
7869     rncEdn(0), nEdn(1), epc(3), fPrintFormData(false), fSaveFormData(false), fShadeFormData(true),
7870     fWCFootnoteEdn(false), wvkSaved(2), wScaleSaved(100), zkSaved(0), fRotateFontW6(false),
7871     iGutterPos(false), fNoTabForInd(false), fNoSpaceRaiseLower(false),
7872     fSuppressSpbfAfterPageBreak(false), fWrapTrailSpaces(false), fMapPrintTextColor(false),
7873     fNoColumnBalance(false), fConvMailMergeEsc(false), fSuppressTopSpacing(false),
7874     fOrigWordTableRules(false), fTransparentMetafiles(false), fShowBreaksInFrames(false),
7875     fSwapBordersFacingPgs(false), fCompatibilityOptions_Unknown1_13(false), fExpShRtn(false),
7876     fCompatibilityOptions_Unknown1_15(false), fCompatibilityOptions_Unknown1_16(false),
7877     fSuppressTopSpacingMac5(false), fTruncDxaExpand(false), fPrintBodyBeforeHdr(false),
7878     fNoLeading(true), fCompatibilityOptions_Unknown1_21(false), fMWSmallCaps(false),
7879     fCompatibilityOptions_Unknown1_23(false), fCompatibilityOptions_Unknown1_24(false),
7880     fCompatibilityOptions_Unknown1_25(false), fCompatibilityOptions_Unknown1_26(false),
7881     fCompatibilityOptions_Unknown1_27(false), fCompatibilityOptions_Unknown1_28(false),
7882     fCompatibilityOptions_Unknown1_29(false), fCompatibilityOptions_Unknown1_30(false),
7883     fCompatibilityOptions_Unknown1_31(false), fUsePrinterMetrics(true), lvl(9), fHtmlDoc(false),
7884     fSnapBorder(false), fIncludeHeader(true), fIncludeFooter(true), fForcePageSizePag(false),
7885     fMinFontSizePag(false), fHaveVersions(false), fAutoVersion(false),
7886     cChWS(0), cChWSFootnoteEdn(0), cDBC(0), cDBCFootnoteEdn(0), nfcEdnRef(2),
7887     fCompatibilityOptions_Unknown2_1(false), fCompatibilityOptions_Unknown2_2(false),
7888     fDontUseHTMLAutoSpacing(false), fCompatibilityOptions_Unknown2_4(false),
7889     fCompatibilityOptions_Unknown2_5(false), fCompatibilityOptions_Unknown2_6(false),
7890     fCompatibilityOptions_Unknown2_7(false), fCompatibilityOptions_Unknown2_8(false),
7891     fCompatibilityOptions_Unknown2_9(false), fCompatibilityOptions_Unknown2_10(false),
7892     fDontBreakWrappedTables(false), fCompatibilityOptions_Unknown2_12(false),
7893     fCompatibilityOptions_Unknown2_13(false), fCompatibilityOptions_Unknown2_14(false),
7894     fCompatibilityOptions_Unknown2_15(false), fCompatibilityOptions_Unknown2_16(false),
7895     fCompatibilityOptions_Unknown2_17(false), fCompatibilityOptions_Unknown2_18(false),
7896     fCompatibilityOptions_Unknown2_19(false), fCompatibilityOptions_Unknown2_20(false),
7897     fCompatibilityOptions_Unknown2_21(false), fCompatibilityOptions_Unknown2_22(false),
7898     fCompatibilityOptions_Unknown2_23(false), fCompatibilityOptions_Unknown2_24(false),
7899     fCompatibilityOptions_Unknown2_25(false), fCompatibilityOptions_Unknown2_26(false),
7900     fCompatibilityOptions_Unknown2_27(false), fCompatibilityOptions_Unknown2_28(false),
7901     fCompatibilityOptions_Unknown2_29(false), fCompatibilityOptions_Unknown2_30(false),
7902     fCompatibilityOptions_Unknown2_31(false), fCompatibilityOptions_Unknown2_32(false),
7903     fUnknown3(0), fUseBackGroundInAllmodes(false), fDoNotEmbedSystemFont(false), fWordCompat(false),
7904     fLiveRecover(false), fEmbedFactoids(false), fFactoidXML(false), fFactoidAllDone(false),
7905     fFolioPrint(false), fReverseFolio(false), iTextLineEnding(0), fHideFcc(false),
7906     fAcetateShowMarkup(false), fAcetateShowAtn(true), fAcetateShowInsDel(false),
7907     fAcetateShowProps(false)
7908         // in C++20 with P06831R1 "Default member initializers for bit-fields (revision 1)", the
7909         // above bit-field member initializations can be moved to the class definition
7910 {
7911     /*
7912     Writer acts like this all the time at the moment, ideally we need an
7913     option for these two as well to import word docs that are not like
7914     this by default
7915     */
7916     // put in initialization list
7917     // fNoLeading = true;
7918     //fUsePrinterMetrics = true;
7919 }
7920 
SetCompatibilityOptions(sal_uInt32 a32Bit)7921 void WW8Dop::SetCompatibilityOptions(sal_uInt32 a32Bit)
7922 {
7923     fNoTabForInd                = ( a32Bit &  0x00000001 )       ;
7924     fNoSpaceRaiseLower          = ( a32Bit &  0x00000002 ) >>  1 ;
7925     fSuppressSpbfAfterPageBreak = ( a32Bit &  0x00000004 ) >>  2 ;
7926     fWrapTrailSpaces            = ( a32Bit &  0x00000008 ) >>  3 ;
7927     fMapPrintTextColor          = ( a32Bit &  0x00000010 ) >>  4 ;
7928     fNoColumnBalance            = ( a32Bit &  0x00000020 ) >>  5 ;
7929     fConvMailMergeEsc           = ( a32Bit &  0x00000040 ) >>  6 ;
7930     fSuppressTopSpacing         = ( a32Bit &  0x00000080 ) >>  7 ;
7931     fOrigWordTableRules         = ( a32Bit &  0x00000100 ) >>  8 ;
7932     fTransparentMetafiles       = ( a32Bit &  0x00000200 ) >>  9 ;
7933     fShowBreaksInFrames         = ( a32Bit &  0x00000400 ) >> 10 ;
7934     fSwapBordersFacingPgs       = ( a32Bit &  0x00000800 ) >> 11 ;
7935     fCompatibilityOptions_Unknown1_13       = ( a32Bit &  0x00001000 ) >> 12 ;
7936     fExpShRtn                   = ( a32Bit &  0x00002000 ) >> 13 ; // #i56856#
7937     fCompatibilityOptions_Unknown1_15       = ( a32Bit &  0x00004000 ) >> 14 ;
7938     fCompatibilityOptions_Unknown1_16       = ( a32Bit &  0x00008000 ) >> 15 ;
7939     fSuppressTopSpacingMac5     = ( a32Bit &  0x00010000 ) >> 16 ;
7940     fTruncDxaExpand             = ( a32Bit &  0x00020000 ) >> 17 ;
7941     fPrintBodyBeforeHdr         = ( a32Bit &  0x00040000 ) >> 18 ;
7942     fNoLeading                  = ( a32Bit &  0x00080000 ) >> 19 ;
7943     fCompatibilityOptions_Unknown1_21       = ( a32Bit &  0x00100000 ) >> 20 ;
7944     fMWSmallCaps                = ( a32Bit &  0x00200000 ) >> 21 ;
7945     fCompatibilityOptions_Unknown1_23       = ( a32Bit &  0x00400000 ) >> 22 ;
7946     fCompatibilityOptions_Unknown1_24       = ( a32Bit &  0x00800800 ) >> 23 ;
7947     fCompatibilityOptions_Unknown1_25       = ( a32Bit &  0x01000000 ) >> 24 ;
7948     fCompatibilityOptions_Unknown1_26       = ( a32Bit &  0x02000000 ) >> 25 ;
7949     fCompatibilityOptions_Unknown1_27       = ( a32Bit &  0x04000000 ) >> 26 ;
7950     fCompatibilityOptions_Unknown1_28       = ( a32Bit &  0x08000000 ) >> 27 ;
7951     fCompatibilityOptions_Unknown1_29       = ( a32Bit &  0x10000000 ) >> 28 ;
7952     fCompatibilityOptions_Unknown1_30       = ( a32Bit &  0x20000000 ) >> 29 ;
7953     fCompatibilityOptions_Unknown1_31       = ( a32Bit &  0x40000000 ) >> 30 ;
7954 
7955     fUsePrinterMetrics          = ( a32Bit &  0x80000000 ) >> 31 ;
7956 }
7957 
GetCompatibilityOptions() const7958 sal_uInt32 WW8Dop::GetCompatibilityOptions() const
7959 {
7960     sal_uInt32 a32Bit = 0;
7961     if (fNoTabForInd)                   a32Bit |= 0x00000001;
7962     if (fNoSpaceRaiseLower)             a32Bit |= 0x00000002;
7963     if (fSuppressSpbfAfterPageBreak)    a32Bit |= 0x00000004;
7964     if (fWrapTrailSpaces)               a32Bit |= 0x00000008;
7965     if (fMapPrintTextColor)             a32Bit |= 0x00000010;
7966     if (fNoColumnBalance)               a32Bit |= 0x00000020;
7967     if (fConvMailMergeEsc)              a32Bit |= 0x00000040;
7968     if (fSuppressTopSpacing)            a32Bit |= 0x00000080;
7969     if (fOrigWordTableRules)            a32Bit |= 0x00000100;
7970     if (fTransparentMetafiles)          a32Bit |= 0x00000200;
7971     if (fShowBreaksInFrames)            a32Bit |= 0x00000400;
7972     if (fSwapBordersFacingPgs)          a32Bit |= 0x00000800;
7973     if (fCompatibilityOptions_Unknown1_13)          a32Bit |= 0x00001000;
7974     if (fExpShRtn)                      a32Bit |= 0x00002000; // #i56856#
7975     if (fCompatibilityOptions_Unknown1_15)          a32Bit |= 0x00004000;
7976     if (fCompatibilityOptions_Unknown1_16)          a32Bit |= 0x00008000;
7977     if (fSuppressTopSpacingMac5)        a32Bit |= 0x00010000;
7978     if (fTruncDxaExpand)                a32Bit |= 0x00020000;
7979     if (fPrintBodyBeforeHdr)            a32Bit |= 0x00040000;
7980     if (fNoLeading)                     a32Bit |= 0x00080000;
7981     if (fCompatibilityOptions_Unknown1_21)          a32Bit |= 0x00100000;
7982     if (fMWSmallCaps)                   a32Bit |= 0x00200000;
7983     if (fCompatibilityOptions_Unknown1_23)          a32Bit |= 0x00400000;
7984     if (fCompatibilityOptions_Unknown1_24)          a32Bit |= 0x00800000;
7985     if (fCompatibilityOptions_Unknown1_25)          a32Bit |= 0x01000000;
7986     if (fCompatibilityOptions_Unknown1_26)          a32Bit |= 0x02000000;
7987     if (fCompatibilityOptions_Unknown1_27)          a32Bit |= 0x04000000;
7988     if (fCompatibilityOptions_Unknown1_28)          a32Bit |= 0x08000000;
7989     if (fCompatibilityOptions_Unknown1_29)          a32Bit |= 0x10000000;
7990     if (fCompatibilityOptions_Unknown1_30)          a32Bit |= 0x20000000;
7991     if (fCompatibilityOptions_Unknown1_31)          a32Bit |= 0x40000000;
7992     if (fUsePrinterMetrics)             a32Bit |= 0x80000000;
7993     return a32Bit;
7994 }
7995 
7996 // i#78591#
SetCompatibilityOptions2(sal_uInt32 a32Bit)7997 void WW8Dop::SetCompatibilityOptions2(sal_uInt32 a32Bit)
7998 {
7999     fCompatibilityOptions_Unknown2_1                        = ( a32Bit &  0x00000001 );
8000     fCompatibilityOptions_Unknown2_2                        = ( a32Bit &  0x00000002 ) >>  1 ;
8001     fDontUseHTMLAutoSpacing     = ( a32Bit &  0x00000004 ) >>  2 ;
8002     fCompatibilityOptions_Unknown2_4                    = ( a32Bit &  0x00000008 ) >>  3 ;
8003     fCompatibilityOptions_Unknown2_5                 = ( a32Bit &  0x00000010 ) >>  4 ;
8004     fCompatibilityOptions_Unknown2_6                 = ( a32Bit &  0x00000020 ) >>  5 ;
8005     fCompatibilityOptions_Unknown2_7                 = ( a32Bit &  0x00000040 ) >>  6 ;
8006     fCompatibilityOptions_Unknown2_8                 = ( a32Bit &  0x00000080 ) >>  7 ;
8007     fCompatibilityOptions_Unknown2_9                 = ( a32Bit &  0x00000100 ) >>  8 ;
8008     fCompatibilityOptions_Unknown2_10                    = ( a32Bit &  0x00000200 ) >>  9 ;
8009     fDontBreakWrappedTables                              = ( a32Bit &  0x00000400 ) >> 10 ;
8010     fCompatibilityOptions_Unknown2_12                    = ( a32Bit &  0x00000800 ) >> 11 ;
8011     fCompatibilityOptions_Unknown2_13                   = ( a32Bit &  0x00001000 ) >> 12 ;
8012     fCompatibilityOptions_Unknown2_14                   = ( a32Bit &  0x00002000 ) >> 13 ;
8013     fCompatibilityOptions_Unknown2_15                   = ( a32Bit &  0x00004000 ) >> 14 ;
8014     fCompatibilityOptions_Unknown2_16                   = ( a32Bit &  0x00008000 ) >> 15 ;
8015     fCompatibilityOptions_Unknown2_17                    = ( a32Bit &  0x00010000 ) >> 16 ;
8016     fCompatibilityOptions_Unknown2_18                    = ( a32Bit &  0x00020000 ) >> 17 ;
8017     fCompatibilityOptions_Unknown2_19                    = ( a32Bit &  0x00040000 ) >> 18 ;
8018     fCompatibilityOptions_Unknown2_20                    = ( a32Bit &  0x00080000 ) >> 19 ;
8019     fCompatibilityOptions_Unknown2_21                   = ( a32Bit &  0x00100000 ) >> 20 ;
8020     fCompatibilityOptions_Unknown2_22                    = ( a32Bit &  0x00200000 ) >> 21 ;
8021     fCompatibilityOptions_Unknown2_23                   = ( a32Bit &  0x00400000 ) >> 22 ;
8022     fCompatibilityOptions_Unknown2_24                   = ( a32Bit &  0x00800800 ) >> 23 ;
8023     fCompatibilityOptions_Unknown2_25                   = ( a32Bit &  0x01000800 ) >> 24 ;
8024     fCompatibilityOptions_Unknown2_26                   = ( a32Bit &  0x02000800 ) >> 25 ;
8025     fCompatibilityOptions_Unknown2_27                   = ( a32Bit &  0x04000800 ) >> 26 ;
8026     fCompatibilityOptions_Unknown2_28                   = ( a32Bit &  0x08000800 ) >> 27 ;
8027     fCompatibilityOptions_Unknown2_29                   = ( a32Bit &  0x10000800 ) >> 28 ;
8028     fCompatibilityOptions_Unknown2_30                   = ( a32Bit &  0x20000800 ) >> 29 ;
8029     fCompatibilityOptions_Unknown2_31                   = ( a32Bit &  0x40000800 ) >> 30 ;
8030     fCompatibilityOptions_Unknown2_32                    = ( a32Bit &  0x80000000 ) >> 31 ;
8031 }
8032 
GetCompatibilityOptions2() const8033 sal_uInt32 WW8Dop::GetCompatibilityOptions2() const
8034 {
8035     sal_uInt32 a32Bit = 0;
8036     if (fCompatibilityOptions_Unknown2_1)           a32Bit |= 0x00000001;
8037     if (fCompatibilityOptions_Unknown2_2)           a32Bit |= 0x00000002;
8038     if (fDontUseHTMLAutoSpacing)     a32Bit |= 0x00000004;
8039     if (fCompatibilityOptions_Unknown2_4)           a32Bit |= 0x00000008;
8040     if (fCompatibilityOptions_Unknown2_5)           a32Bit |= 0x00000010;
8041     if (fCompatibilityOptions_Unknown2_6)           a32Bit |= 0x00000020;
8042     if (fCompatibilityOptions_Unknown2_7)           a32Bit |= 0x00000040;
8043     if (fCompatibilityOptions_Unknown2_8)           a32Bit |= 0x00000080;
8044     if (fCompatibilityOptions_Unknown2_9)           a32Bit |= 0x00000100;
8045     if (fCompatibilityOptions_Unknown2_10)          a32Bit |= 0x00000200;
8046     if (fDontBreakWrappedTables)                    a32Bit |= 0x00000400;
8047     if (fCompatibilityOptions_Unknown2_12)          a32Bit |= 0x00000800;
8048     if (fCompatibilityOptions_Unknown2_13)          a32Bit |= 0x00001000;
8049     //#i42909# set thai "line breaking rules" compatibility option
8050     // pflin, wonder whether bUseThaiLineBreakingRules is correct
8051     // when importing word document.
8052     if (bUseThaiLineBreakingRules)          a32Bit |= 0x00002000;
8053     else if (fCompatibilityOptions_Unknown2_14)         a32Bit |= 0x00002000;
8054     if (fCompatibilityOptions_Unknown2_15)          a32Bit |= 0x00004000;
8055     if (fCompatibilityOptions_Unknown2_16)          a32Bit |= 0x00008000;
8056     if (fCompatibilityOptions_Unknown2_17)          a32Bit |= 0x00010000;
8057     if (fCompatibilityOptions_Unknown2_18)          a32Bit |= 0x00020000;
8058     if (fCompatibilityOptions_Unknown2_19)          a32Bit |= 0x00040000;
8059     if (fCompatibilityOptions_Unknown2_20)          a32Bit |= 0x00080000;
8060     if (fCompatibilityOptions_Unknown2_21)          a32Bit |= 0x00100000;
8061     if (fCompatibilityOptions_Unknown2_22)          a32Bit |= 0x00200000;
8062     if (fCompatibilityOptions_Unknown2_23)          a32Bit |= 0x00400000;
8063     if (fCompatibilityOptions_Unknown2_24)          a32Bit |= 0x00800000;
8064     if (fCompatibilityOptions_Unknown2_25)          a32Bit |= 0x01000000;
8065     if (fCompatibilityOptions_Unknown2_26)          a32Bit |= 0x02000000;
8066     if (fCompatibilityOptions_Unknown2_27)          a32Bit |= 0x04000000;
8067     if (fCompatibilityOptions_Unknown2_28)          a32Bit |= 0x08000000;
8068     if (fCompatibilityOptions_Unknown2_29)          a32Bit |= 0x10000000;
8069     if (fCompatibilityOptions_Unknown2_30)          a32Bit |= 0x20000000;
8070     if (fCompatibilityOptions_Unknown2_31)          a32Bit |= 0x40000000;
8071     if (fCompatibilityOptions_Unknown2_32)          a32Bit |= 0x80000000;
8072     return a32Bit;
8073 }
8074 
Write(SvStream & rStrm,WW8Fib & rFib) const8075 void WW8Dop::Write(SvStream& rStrm, WW8Fib& rFib) const
8076 {
8077     const int nMaxDopLen = 610;
8078     sal_uInt32 nLen = 8 == rFib.m_nVersion ? nMaxDopLen : 84;
8079     rFib.m_fcDop =  rStrm.Tell();
8080     rFib.m_lcbDop = nLen;
8081 
8082     sal_uInt8 aData[ nMaxDopLen ] = {};
8083     sal_uInt8* pData = aData;
8084 
8085     // analyse the data
8086     sal_uInt16 a16Bit;
8087     sal_uInt8   a8Bit;
8088 
8089     a16Bit = 0;                         // 0 0x00
8090     if (fFacingPages)
8091         a16Bit |= 0x0001;
8092     if (fWidowControl)
8093         a16Bit |= 0x0002;
8094     if (fPMHMainDoc)
8095         a16Bit |= 0x0004;
8096     a16Bit |= ( 0x0018 & (grfSuppression << 3));
8097     a16Bit |= ( 0x0060 & (fpc << 5));
8098     a16Bit |= ( 0xff00 & (grpfIhdt << 8));
8099     Set_UInt16( pData, a16Bit );
8100 
8101     a16Bit = 0;                         // 2 0x02
8102     a16Bit |= ( 0x0003 & rncFootnote );
8103     a16Bit |= ( ~0x0003 & (nFootnote << 2));
8104     Set_UInt16( pData, a16Bit );
8105 
8106     a8Bit = 0;                          // 4 0x04
8107     if( fOutlineDirtySave ) a8Bit |= 0x01;
8108     Set_UInt8( pData, a8Bit );
8109 
8110     a8Bit = 0;                          // 5 0x05
8111     if( fOnlyMacPics )  a8Bit |= 0x01;
8112     if( fOnlyWinPics )  a8Bit |= 0x02;
8113     if( fLabelDoc )     a8Bit |= 0x04;
8114     if( fHyphCapitals ) a8Bit |= 0x08;
8115     if( fAutoHyphen )   a8Bit |= 0x10;
8116     if( fFormNoFields ) a8Bit |= 0x20;
8117     if( fLinkStyles )   a8Bit |= 0x40;
8118     if( fRevMarking )   a8Bit |= 0x80;
8119     Set_UInt8( pData, a8Bit );
8120 
8121     a8Bit = 0;                          // 6 0x06
8122     if( fBackup )               a8Bit |= 0x01;
8123     if( fExactCWords )          a8Bit |= 0x02;
8124     if( fPagHidden )            a8Bit |= 0x04;
8125     if( fPagResults )           a8Bit |= 0x08;
8126     if( fLockAtn )              a8Bit |= 0x10;
8127     if( fMirrorMargins )        a8Bit |= 0x20;
8128     if( fReadOnlyRecommended )  a8Bit |= 0x40;
8129     if( fDfltTrueType )         a8Bit |= 0x80;
8130     Set_UInt8( pData, a8Bit );
8131 
8132     a8Bit = 0;                          // 7 0x07
8133     if( fPagSuppressTopSpacing )    a8Bit |= 0x01;
8134     if( fProtEnabled )              a8Bit |= 0x02;
8135     if( fDispFormFieldSel )           a8Bit |= 0x04;
8136     if( fRMView )                   a8Bit |= 0x08;
8137     if( fRMPrint )                  a8Bit |= 0x10;
8138     if( fWriteReservation )         a8Bit |= 0x20;
8139     if( fLockRev )                  a8Bit |= 0x40;
8140     if( fEmbedFonts )               a8Bit |= 0x80;
8141     Set_UInt8( pData, a8Bit );
8142 
8143     a8Bit = 0;                          // 8 0x08
8144     if( copts_fNoTabForInd )            a8Bit |= 0x01;
8145     if( copts_fNoSpaceRaiseLower )      a8Bit |= 0x02;
8146     if( copts_fSuppressSpbfAfterPgBrk ) a8Bit |= 0x04;
8147     if( copts_fWrapTrailSpaces )        a8Bit |= 0x08;
8148     if( copts_fMapPrintTextColor )      a8Bit |= 0x10;
8149     if( copts_fNoColumnBalance )        a8Bit |= 0x20;
8150     if( copts_fConvMailMergeEsc )       a8Bit |= 0x40;
8151     if( copts_fSuppressTopSpacing )     a8Bit |= 0x80;
8152     Set_UInt8( pData, a8Bit );
8153 
8154     a8Bit = 0;                          // 9 0x09
8155     if( copts_fOrigWordTableRules )     a8Bit |= 0x01;
8156     if( copts_fTransparentMetafiles )   a8Bit |= 0x02;
8157     if( copts_fShowBreaksInFrames )     a8Bit |= 0x04;
8158     if( copts_fSwapBordersFacingPgs )   a8Bit |= 0x08;
8159     if( copts_fExpShRtn )               a8Bit |= 0x20;  // #i56856#
8160     Set_UInt8( pData, a8Bit );
8161 
8162     Set_UInt16( pData, dxaTab );        // 10 0x0a
8163     Set_UInt16( pData, wSpare );        // 12 0x0c
8164     Set_UInt16( pData, dxaHotZ );       // 14 0x0e
8165     Set_UInt16( pData, cConsecHypLim ); // 16 0x10
8166     Set_UInt16( pData, wSpare2 );       // 18 0x12
8167     Set_UInt32( pData, dttmCreated );   // 20 0x14
8168     Set_UInt32( pData, dttmRevised );   // 24 0x18
8169     Set_UInt32( pData, dttmLastPrint ); // 28 0x1c
8170     Set_UInt16( pData, nRevision );     // 32 0x20
8171     Set_UInt32( pData, tmEdited );      // 34 0x22
8172     Set_UInt32( pData, cWords );        // 38 0x26
8173     Set_UInt32( pData, cCh );           // 42 0x2a
8174     Set_UInt16( pData, cPg );           // 46 0x2e
8175     Set_UInt32( pData, cParas );        // 48 0x30
8176 
8177     a16Bit = 0;                         // 52 0x34
8178     a16Bit |= ( 0x0003 & rncEdn );
8179     a16Bit |= (~0x0003 & ( nEdn << 2));
8180     Set_UInt16( pData, a16Bit );
8181 
8182     a16Bit = 0;                         // 54 0x36
8183     a16Bit |= (0x0003 & epc );
8184     a16Bit |= (0x003c & (nfcFootnoteRef << 2));
8185     a16Bit |= (0x03c0 & (nfcEdnRef << 6));
8186     if( fPrintFormData )    a16Bit |= 0x0400;
8187     if( fSaveFormData )     a16Bit |= 0x0800;
8188     if( fShadeFormData )    a16Bit |= 0x1000;
8189     if( fWCFootnoteEdn )         a16Bit |= 0x8000;
8190     Set_UInt16( pData, a16Bit );
8191 
8192     Set_UInt32( pData, cLines );        // 56 0x38
8193     Set_UInt32( pData, cWordsFootnoteEnd );  // 60 0x3c
8194     Set_UInt32( pData, cChFootnoteEdn );     // 64 0x40
8195     Set_UInt16( pData, cPgFootnoteEdn );     // 68 0x44
8196     Set_UInt32( pData, cParasFootnoteEdn );  // 70 0x46
8197     Set_UInt32( pData, cLinesFootnoteEdn );  // 74 0x4a
8198     Set_UInt32( pData, lKeyProtDoc );   // 78 0x4e
8199 
8200     a16Bit = 0;                         // 82 0x52
8201     if (wvkSaved)
8202         a16Bit |= 0x0007;
8203     a16Bit |= (0x0ff8 & (wScaleSaved << 3));
8204     a16Bit |= (0x3000 & (zkSaved << 12));
8205     if (iGutterPos)
8206     {
8207         // Last bit: gutter at top.
8208         a16Bit |= 0x8000;
8209     }
8210     Set_UInt16( pData, a16Bit );
8211 
8212     if( 8 == rFib.m_nVersion )
8213     {
8214         Set_UInt32(pData, GetCompatibilityOptions());  // 84 0x54
8215 
8216         Set_UInt16( pData, adt );                      // 88 0x58
8217 
8218         doptypography.WriteToMem(pData);               // 400 0x190
8219 
8220         memcpy( pData, &dogrid, sizeof( WW8_DOGRID ));
8221         pData += sizeof( WW8_DOGRID );
8222 
8223         a16Bit = 0x12;      // set lvl to 9            // 410 0x19a
8224         if( fHtmlDoc )          a16Bit |= 0x0200;
8225         if( fSnapBorder )       a16Bit |= 0x0800;
8226         if( fIncludeHeader )    a16Bit |= 0x1000;
8227         if( fIncludeFooter )    a16Bit |= 0x2000;
8228         if( fForcePageSizePag ) a16Bit |= 0x4000;
8229         if( fMinFontSizePag )   a16Bit |= 0x8000;
8230         Set_UInt16( pData, a16Bit );
8231 
8232         a16Bit = 0;                                    // 412 0x19c
8233         if( fHaveVersions ) a16Bit |= 0x0001;
8234         if( fAutoVersion )  a16Bit |= 0x0002;
8235         Set_UInt16( pData, a16Bit );
8236 
8237         pData += 12;                                   // 414 0x19e
8238 
8239         Set_UInt32( pData, cChWS );                    // 426 0x1aa
8240         Set_UInt32( pData, cChWSFootnoteEdn );              // 430 0x1ae
8241         Set_UInt32( pData, grfDocEvents );             // 434 0x1b2
8242 
8243         pData += 4+30+8;  // 438 0x1b6; 442 0x1ba; 472 0x1d8; 476 0x1dc
8244 
8245         Set_UInt32( pData, cDBC );                     // 480 0x1e0
8246         Set_UInt32( pData, cDBCFootnoteEdn );               // 484 0x1e4
8247 
8248         pData += 1 * sizeof( sal_Int32);                   // 488 0x1e8
8249 
8250         Set_UInt16( pData, nfcFootnoteRef );                // 492 0x1ec
8251         Set_UInt16( pData, nfcEdnRef );                // 494 0x1ee
8252         Set_UInt16( pData, hpsZoomFontPag );           // 496 0x1f0
8253         Set_UInt16( pData, dywDispPag );               // 498 0x1f2
8254 
8255         //500 -> 508, Appear to be repeated here in 2000+
8256         pData += 8;
8257         Set_UInt32(pData, GetCompatibilityOptions());
8258         Set_UInt32(pData, GetCompatibilityOptions2());
8259         pData += 32;
8260 
8261         a16Bit = 0;
8262         if (fEmbedFactoids)
8263             a16Bit |= 0x8;
8264         if (fAcetateShowMarkup)
8265             a16Bit |= 0x1000;
8266         //Word XP at least requires fAcetateShowMarkup to honour fAcetateShowAtn
8267         if (fAcetateShowAtn)
8268         {
8269             a16Bit |= 0x1000;
8270             a16Bit |= 0x2000;
8271         }
8272         Set_UInt16(pData, a16Bit);
8273 
8274         pData += 48;
8275         a16Bit = 0x0080;
8276         Set_UInt16(pData, a16Bit);
8277     }
8278     rStrm.WriteBytes(aData, nLen);
8279 }
8280 
ReadFromMem(sal_uInt8 * & pData)8281 void WW8DopTypography::ReadFromMem(sal_uInt8 *&pData)
8282 {
8283     sal_uInt16 a16Bit = Get_UShort(pData);
8284     m_fKerningPunct = (a16Bit & 0x0001);
8285     m_iJustification = (a16Bit & 0x0006) >>  1;
8286     m_iLevelOfKinsoku = (a16Bit & 0x0018) >>  3;
8287     m_f2on1 = (a16Bit & 0x0020) >>  5;
8288     m_reserved1 = (a16Bit & 0x03C0) >>  6;
8289     m_reserved2 = (a16Bit & 0xFC00) >>  10;
8290 
8291     m_cchFollowingPunct = Get_Short(pData);
8292     m_cchLeadingPunct = Get_Short(pData);
8293 
8294     sal_Int16 i;
8295     for (i=0; i < nMaxFollowing; ++i)
8296         m_rgxchFPunct[i] = Get_Short(pData);
8297     for (i=0; i < nMaxLeading; ++i)
8298         m_rgxchLPunct[i] = Get_Short(pData);
8299 
8300     if (m_cchFollowingPunct >= 0 && m_cchFollowingPunct < nMaxFollowing)
8301         m_rgxchFPunct[m_cchFollowingPunct]=0;
8302     else
8303         m_rgxchFPunct[nMaxFollowing - 1]=0;
8304 
8305     if (m_cchLeadingPunct >= 0 && m_cchLeadingPunct < nMaxLeading)
8306         m_rgxchLPunct[m_cchLeadingPunct]=0;
8307     else
8308         m_rgxchLPunct[nMaxLeading - 1]=0;
8309 
8310 }
8311 
WriteToMem(sal_uInt8 * & pData) const8312 void WW8DopTypography::WriteToMem(sal_uInt8 *&pData) const
8313 {
8314     sal_uInt16 a16Bit = sal_uInt16(m_fKerningPunct);
8315     a16Bit |= (m_iJustification << 1) & 0x0006;
8316     a16Bit |= (m_iLevelOfKinsoku << 3) & 0x0018;
8317     a16Bit |= (int(m_f2on1) << 5) & 0x0020;
8318     a16Bit |= (m_reserved1 << 6) & 0x03C0;
8319     a16Bit |= (m_reserved2 << 10) & 0xFC00;
8320     Set_UInt16(pData,a16Bit);
8321 
8322     Set_UInt16(pData,m_cchFollowingPunct);
8323     Set_UInt16(pData,m_cchLeadingPunct);
8324 
8325     sal_Int16 i;
8326     for (i=0; i < nMaxFollowing; ++i)
8327         Set_UInt16(pData,m_rgxchFPunct[i]);
8328     for (i=0; i < nMaxLeading; ++i)
8329         Set_UInt16(pData,m_rgxchLPunct[i]);
8330 }
8331 
GetConvertedLang() const8332 LanguageType WW8DopTypography::GetConvertedLang() const
8333 {
8334     LanguageType nLang;
8335     //I have assumed people's republic/taiwan == simplified/traditional
8336 
8337     //This isn't a documented issue, so we might have it all wrong,
8338     //i.e. i.e. what's with the powers of two ?
8339 
8340     /*
8341     One example of 3 for reserved1 which was really Japanese, perhaps last bit
8342     is for some other use ?, or redundant. If more examples trigger the assert
8343     we might be able to figure it out.
8344     */
8345     switch(m_reserved1 & 0xE)
8346     {
8347         case 2:     //Japan
8348             nLang = LANGUAGE_JAPANESE;
8349             break;
8350         case 4:     //Chinese (People's Republic)
8351             nLang = LANGUAGE_CHINESE_SIMPLIFIED;
8352             break;
8353         case 6:     //Korean
8354             nLang = LANGUAGE_KOREAN;
8355             break;
8356         case 8:     //Chinese (Taiwan)
8357             nLang = LANGUAGE_CHINESE_TRADITIONAL;
8358             break;
8359         default:
8360             OSL_ENSURE(false, "Unknown MS Asian Typography language, report");
8361             nLang = LANGUAGE_CHINESE_SIMPLIFIED_LEGACY;
8362             break;
8363         case 0:
8364             //And here we have the possibility that it says 2, but it's really
8365             //a bug and only japanese level 2 has been selected after a custom
8366             //version was chosen on last save!
8367             nLang = LANGUAGE_JAPANESE;
8368             break;
8369     }
8370     return nLang;
8371 }
8372 
8373 //              Sprms
8374 
GetSprmTailLen(sal_uInt16 nId,const sal_uInt8 * pSprm,sal_Int32 nRemLen) const8375 sal_uInt16 wwSprmParser::GetSprmTailLen(sal_uInt16 nId, const sal_uInt8* pSprm, sal_Int32 nRemLen)
8376     const
8377 {
8378     SprmInfo aSprm = GetSprmInfo(nId);
8379     sal_uInt16 nL = 0;                      // number of Bytes to read
8380 
8381     //sprmPChgTabs
8382     switch( nId )
8383     {
8384         case 23:
8385         case 0xC615:
8386             if( pSprm[1 + mnDelta] != 255 )
8387                 nL = static_cast< sal_uInt16 >(pSprm[1 + mnDelta] + aSprm.nLen);
8388             else
8389             {
8390                 sal_uInt8 nDelIdx = 2 + mnDelta;
8391                 sal_uInt8 nDel = nDelIdx < nRemLen ? pSprm[nDelIdx] : 0;
8392                 sal_uInt8 nInsIdx = 3 + mnDelta + 4 * nDel;
8393                 sal_uInt8 nIns = nInsIdx < nRemLen ? pSprm[nInsIdx] : 0;
8394 
8395                 nL = 2 + 4 * nDel + 3 * nIns;
8396             }
8397             break;
8398         default:
8399             switch (aSprm.nVari)
8400             {
8401                 case L_FIX:
8402                     nL = aSprm.nLen;        // Excl. Token
8403                     break;
8404                 case L_VAR:
8405                     // Variable 1-Byte Length
8406                     // parameter length (i.e. excluding token and length byte)
8407                     nL = static_cast< sal_uInt16 >(pSprm[1 + mnDelta] + aSprm.nLen);
8408                     break;
8409                 case L_VAR2:
8410                 {
8411                     // Variable 2-Byte Length
8412                     // For sprmTDefTable and sprmTDefTable10, the length of the
8413                     // parameter plus 1 is recorded in the two bytes beginning
8414                     // at offset (WW7-) 1 or (WW8+) 2
8415                     sal_uInt8 nIndex = 1 + mnDelta;
8416                     sal_uInt16 nCount;
8417                     if (nIndex + 1 >= nRemLen)
8418                     {
8419                         SAL_WARN("sw.ww8", "sprm longer than remaining bytes, doc or parser is wrong");
8420                         nCount = 0;
8421                     }
8422                     else
8423                     {
8424                         nCount = SVBT16ToUInt16(&pSprm[nIndex]);
8425                         SAL_WARN_IF(nCount < 1, "sw.ww8", "length should have been at least 1");
8426                         if (nCount)
8427                             --nCount;
8428                     }
8429                     nL = static_cast<sal_uInt16>(nCount + aSprm.nLen);
8430                     break;
8431                 }
8432                 default:
8433                     OSL_ENSURE(false, "Unknown sprm variant");
8434                     break;
8435             }
8436             break;
8437     }
8438     return nL;
8439 }
8440 
8441 // one or two bytes at the beginning at the sprm id
GetSprmId(const sal_uInt8 * pSp) const8442 sal_uInt16 wwSprmParser::GetSprmId(const sal_uInt8* pSp) const
8443 {
8444     OSL_ENSURE(pSp, "Why GetSprmId with pSp of 0");
8445     if (!pSp)
8446         return 0;
8447 
8448     sal_uInt16 nId = 0;
8449 
8450     if (ww::IsSevenMinus(meVersion))
8451     {
8452         nId = *pSp; // [0..0xff]
8453     }
8454     else
8455     {
8456         nId = SVBT16ToUInt16(pSp);
8457         if (0x0800 > nId)
8458             nId = 0;
8459     }
8460 
8461     return nId;
8462 }
8463 
8464 // with tokens and length byte
GetSprmSize(sal_uInt16 nId,const sal_uInt8 * pSprm,sal_Int32 nRemLen) const8465 sal_Int32 wwSprmParser::GetSprmSize(sal_uInt16 nId, const sal_uInt8* pSprm, sal_Int32 nRemLen) const
8466 {
8467     return GetSprmTailLen(nId, pSprm, nRemLen) + 1 + mnDelta + SprmDataOfs(nId);
8468 }
8469 
SprmDataOfs(sal_uInt16 nId) const8470 sal_uInt8 wwSprmParser::SprmDataOfs(sal_uInt16 nId) const
8471 {
8472     return GetSprmInfo(nId).nVari;
8473 }
8474 
DistanceToData(sal_uInt16 nId) const8475 sal_Int32 wwSprmParser::DistanceToData(sal_uInt16 nId) const
8476 {
8477     return 1 + mnDelta + SprmDataOfs(nId);
8478 }
8479 
findSprmData(sal_uInt16 nId,sal_uInt8 * pSprms,sal_Int32 nLen) const8480 SprmResult wwSprmParser::findSprmData(sal_uInt16 nId, sal_uInt8* pSprms,
8481     sal_Int32 nLen) const
8482 {
8483     while (nLen >= MinSprmLen())
8484     {
8485         const sal_uInt16 nCurrentId = GetSprmId(pSprms);
8486         // set pointer to data
8487         sal_Int32 nSize = GetSprmSize(nCurrentId, pSprms, nLen);
8488 
8489         bool bValid = nSize <= nLen;
8490 
8491         SAL_WARN_IF(!bValid, "sw.ww8",
8492             "sprm 0x" << std::hex << nCurrentId << std::dec << " longer than remaining bytes, " <<
8493             nSize << " vs " << nLen << "doc or parser is wrong");
8494 
8495         if (nCurrentId == nId && bValid) // Sprm found
8496         {
8497             sal_Int32 nFixedLen = DistanceToData(nId);
8498             return SprmResult(pSprms + nFixedLen, nSize - nFixedLen);
8499         }
8500 
8501         //Clip to available size if wrong
8502         nSize = std::min(nSize, nLen);
8503         pSprms += nSize;
8504         nLen -= nSize;
8505     }
8506     // Sprm not found
8507     return SprmResult();
8508 }
8509 
SEPr()8510 SEPr::SEPr() :
8511     bkc(2), fTitlePage(0), fAutoPgn(0), nfcPgn(0), fUnlocked(0), cnsPgn(0),
8512     fPgnRestart(0), fEndNote(1), lnc(0), grpfIhdt(0), nLnnMod(0), dxaLnn(0),
8513     dxaPgn(720), dyaPgn(720), fLBetween(0), vjc(0), dmBinFirst(0),
8514     dmBinOther(0), dmPaperReq(0), fPropRMark(0), ibstPropRMark(0),
8515     dttmPropRMark(0), dxtCharSpace(0), dyaLinePitch(0), clm(0), reserved1(0),
8516     dmOrientPage(0), iHeadingPgn(0), pgnStart(1), lnnMin(0), wTextFlow(0),
8517     reserved2(0), pgbApplyTo(0), pgbPageDepth(0), pgbOffsetFrom(0),
8518     xaPage(lLetterWidth), yaPage(lLetterHeight), xaPageNUp(lLetterWidth), yaPageNUp(lLetterHeight),
8519     dxaLeft(1800), dxaRight(1800), dyaTop(1440), dyaBottom(1440), dzaGutter(0),
8520     dyaHdrTop(720), dyaHdrBottom(720), ccolM1(0), fEvenlySpaced(1),
8521     reserved3(0), fBiDi(0), fFacingCol(0), fRTLGutter(0), fRTLAlignment(0),
8522     dxaColumns(720), dxaColumnWidth(0), dmOrientFirst(0), fLayout(0),
8523     reserved4(0)
8524 {
8525 }
8526 
checkRead(SvStream & rSt,void * pDest,sal_uInt32 nLength)8527 bool checkRead(SvStream &rSt, void *pDest, sal_uInt32 nLength)
8528 {
8529     return (rSt.ReadBytes(pDest, nLength) == static_cast<std::size_t>(nLength));
8530 }
8531 
8532 #ifdef OSL_BIGENDIAN
swapEndian(sal_Unicode * pString)8533 void swapEndian(sal_Unicode *pString)
8534 {
8535     for (sal_Unicode *pWork = pString; *pWork; ++pWork)
8536         *pWork = OSL_SWAPWORD(*pWork);
8537 }
8538 #endif
8539 
8540 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
8541