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