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