Revert "tdf#158280 Replace usage of InputDialog with SvxNameDialog"
[LibreOffice.git] / sw / source / filter / ww8 / ww8scan.cxx
blob97af529488c7cd331132f7eabec3cd304ef5d725
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <memory>
21 #include "ww8scan.hxx"
22 #include "ww8par.hxx"
24 #include <cassert>
25 #include <cstddef>
26 #include <cstring>
27 #include <algorithm>
29 #include <i18nlangtag/mslangid.hxx>
30 #include "sprmids.hxx"
31 #include <rtl/tencinfo.h>
32 #include <sal/macros.h>
33 #include <sal/log.hxx>
34 #include <osl/diagnose.h>
36 #include <swerror.h>
38 #include <comphelper/string.hxx>
39 #include <unotools/localedatawrapper.hxx>
40 #include <i18nlangtag/lang.h>
41 #include <o3tl/safeint.hxx>
42 #include <tools/stream.hxx>
44 #include <vcl/settings.hxx>
45 #include <vcl/svapp.hxx>
47 using namespace ::com::sun::star::lang;
49 namespace
51 /**
52 winword strings are typically Belt and Braces strings preceded with a
53 pascal style count, and ending with a c style 0 terminator. 16bit chars
54 and count for ww8+ and 8bit chars and count for ww7-. The count and 0
55 can be checked for integrity to catch errors (e.g. lotus created
56 documents) where in error 8bit strings are used instead of 16bits
57 strings for style names.
59 bool TestBeltAndBraces(SvStream& rStrm)
61 bool bRet = false;
62 sal_uInt64 nOldPos = rStrm.Tell();
63 sal_uInt16 nBelt(0);
64 rStrm.ReadUInt16( nBelt );
65 nBelt *= sizeof(sal_Unicode);
66 if (rStrm.good() && (rStrm.remainingSize() >= (nBelt + sizeof(sal_Unicode))))
68 rStrm.SeekRel(nBelt);
69 if (rStrm.good())
71 sal_Unicode cBraces(0);
72 rStrm.ReadUtf16( cBraces );
73 if (rStrm.good() && cBraces == 0)
74 bRet = true;
77 rStrm.Seek(nOldPos);
78 return bRet;
82 const wwSprmSearcher *wwSprmParser::GetWW2SprmSearcher()
84 //double lock me
85 // WW2 Sprms
86 static const SprmInfoRow aSprms[] =
88 { 0, { 0, L_FIX} }, // "Default-sprm", will be skipped
89 { 2, { 1, L_FIX} }, // "sprmPIstd", pap.istd (style code)
90 { 3, { 0, L_VAR} }, // "sprmPIstdPermute pap.istd permutation
91 { 4, { 1, L_FIX} }, // "sprmPIncLv1" pap.istddifference
92 { 5, { 1, L_FIX} }, // "sprmPJc" pap.jc (justification)
93 { 6, { 1, L_FIX} }, // "sprmPFSideBySide" pap.fSideBySide
94 { 7, { 1, L_FIX} }, // "sprmPFKeep" pap.fKeep
95 { 8, { 1, L_FIX} }, // "sprmPFKeepFollow " pap.fKeepFollow
96 { 9, { 1, L_FIX} }, // "sprmPPageBreakBefore" pap.fPageBreakBefore
97 { 10, { 1, L_FIX} }, // "sprmPBrcl" pap.brcl
98 { 11, { 1, L_FIX} }, // "sprmPBrcp" pap.brcp
99 { 12, { 1, L_FIX} }, // "sprmPNfcSeqNumb" pap.nfcSeqNumb
100 { 13, { 1, L_FIX} }, // "sprmPNoSeqNumb" pap.nnSeqNumb
101 { 14, { 1, L_FIX} }, // "sprmPFNoLineNumb" pap.fNoLnn
102 { 15, { 0, L_VAR} }, // "?sprmPChgTabsPapx" pap.itbdMac, ...
103 { 16, { 2, L_FIX} }, // "sprmPDxaRight" pap.dxaRight
104 { 17, { 2, L_FIX} }, // "sprmPDxaLeft" pap.dxaLeft
105 { 18, { 2, L_FIX} }, // "sprmPNest" pap.dxaLeft
106 { 19, { 2, L_FIX} }, // "sprmPDxaLeft1" pap.dxaLeft1
107 { 20, { 2, L_FIX} }, // "sprmPDyaLine" pap.lspd an LSPD
108 { 21, { 2, L_FIX} }, // "sprmPDyaBefore" pap.dyaBefore
109 { 22, { 2, L_FIX} }, // "sprmPDyaAfter" pap.dyaAfter
110 { 23, { 0, L_VAR} }, // "?sprmPChgTabs" pap.itbdMac, pap.rgdxaTab, ...
111 { 24, { 1, L_FIX} }, // "sprmPFInTable" pap.fInTable
112 { 25, { 1, L_FIX} }, // "sprmPTtp" pap.fTtp
113 { 26, { 2, L_FIX} }, // "sprmPDxaAbs" pap.dxaAbs
114 { 27, { 2, L_FIX} }, // "sprmPDyaAbs" pap.dyaAbs
115 { 28, { 2, L_FIX} }, // "sprmPDxaWidth" pap.dxaWidth
116 { 29, { 1, L_FIX} }, // "sprmPPc" pap.pcHorz, pap.pcVert
117 { 30, { 2, L_FIX} }, // "sprmPBrcTop10" pap.brcTop BRC10
118 { 31, { 2, L_FIX} }, // "sprmPBrcLeft10" pap.brcLeft BRC10
119 { 32, { 2, L_FIX} }, // "sprmPBrcBottom10" pap.brcBottom BRC10
120 { 33, { 2, L_FIX} }, // "sprmPBrcRight10" pap.brcRight BRC10
121 { 34, { 2, L_FIX} }, // "sprmPBrcBetween10" pap.brcBetween BRC10
122 { 35, { 2, L_FIX} }, // "sprmPBrcBar10" pap.brcBar BRC10
123 { 36, { 2, L_FIX} }, // "sprmPFromText10" pap.dxaFromText dxa
124 { 37, { 1, L_FIX} }, // "sprmPWr" pap.wr wr
125 { 38, { 2, L_FIX} }, // "sprmPBrcTop" pap.brcTop BRC
126 { 39, { 2, L_FIX} }, // "sprmPBrcLeft" pap.brcLeft BRC
127 { 40, { 2, L_FIX} }, // "sprmPBrcBottom" pap.brcBottom BRC
128 { 41, { 2, L_FIX} }, // "sprmPBrcRight" pap.brcRight BRC
129 { 42, { 2, L_FIX} }, // "sprmPBrcBetween" pap.brcBetween BRC
130 { 43, { 2, L_FIX} }, // "sprmPBrcBar" pap.brcBar BRC word
131 { 44, { 1, L_FIX} }, // "sprmPFNoAutoHyph" pap.fNoAutoHyph
132 { 45, { 2, L_FIX} }, // "sprmPWHeightAbs" pap.wHeightAbs w
133 { 46, { 2, L_FIX} }, // "sprmPDcs" pap.dcs DCS
134 { 47, { 2, L_FIX} }, // "sprmPShd" pap.shd SHD
135 { 48, { 2, L_FIX} }, // "sprmPDyaFromText" pap.dyaFromText dya
136 { 49, { 2, L_FIX} }, // "sprmPDxaFromText" pap.dxaFromText dxa
137 { 50, { 1, L_FIX} }, // "sprmPFBiDi" pap.fBiDi 0 or 1 byte
138 { 51, { 1, L_FIX} }, // "sprmPFWidowControl" pap.fWidowControl 0 or 1 byte
139 { 52, { 0, L_FIX} }, // "?sprmPRuler 52"
140 { 53, { 1, L_FIX} }, // "sprmCFStrikeRM" chp.fRMarkDel 1 or 0 bit
141 { 54, { 1, L_FIX} }, // "sprmCFRMark" chp.fRMark 1 or 0 bit
142 { 55, { 1, L_FIX} }, // "sprmCFFieldVanish" chp.fFieldVanish 1 or 0 bit
143 { 57, { 0, L_VAR} }, // "sprmCDefault" whole CHP
144 { 58, { 0, L_FIX} }, // "sprmCPlain" whole CHP
145 { 60, { 1, L_FIX} }, // "sprmCFBold" chp.fBold 0,1, 128, or 129
146 { 61, { 1, L_FIX} }, // "sprmCFItalic" chp.fItalic 0,1, 128, or 129
147 { 62, { 1, L_FIX} }, // "sprmCFStrike" chp.fStrike 0,1, 128, or 129
148 { 63, { 1, L_FIX} }, // "sprmCFOutline" chp.fOutline 0,1, 128, or 129
149 { 64, { 1, L_FIX} }, // "sprmCFShadow" chp.fShadow 0,1, 128, or 129
150 { 65, { 1, L_FIX} }, // "sprmCFSmallCaps" chp.fSmallCaps 0,1, 128, or 129
151 { 66, { 1, L_FIX} }, // "sprmCFCaps" chp.fCaps 0,1, 128, or 129
152 { 67, { 1, L_FIX} }, // "sprmCFVanish" chp.fVanish 0,1, 128, or 129
153 { 68, { 2, L_FIX} }, // "sprmCFtc" chp.ftc ftc word
154 { 69, { 1, L_FIX} }, // "sprmCKul" chp.kul kul byte
155 { 70, { 3, L_FIX} }, // "sprmCSizePos" chp.hps, chp.hpsPos
156 { 71, { 2, L_FIX} }, // "sprmCDxaSpace" chp.dxaSpace dxa
157 { 72, { 2, L_FIX} }, // "sprmCLid" chp.lid LID
158 { 73, { 1, L_FIX} }, // "sprmCIco" chp.ico ico byte
159 { 74, { 1, L_FIX} }, // "sprmCHps" chp.hps hps !word!
160 { 75, { 1, L_FIX} }, // "sprmCHpsInc" chp.hps
161 { 76, { 1, L_FIX} }, // "sprmCHpsPos" chp.hpsPos hps !word!
162 { 77, { 1, L_FIX} }, // "sprmCHpsPosAdj" chp.hpsPos hps
163 { 78, { 0, L_VAR} }, // "?sprmCMajority" chp.fBold, chp.fItalic, ...
164 { 80, { 1, L_FIX} }, // "sprmCFBoldBi" chp.fBoldBi
165 { 81, { 1, L_FIX} }, // "sprmCFItalicBi" chp.fItalicBi
166 { 82, { 2, L_FIX} }, // "sprmCFtcBi" chp.ftcBi
167 { 83, { 2, L_FIX} }, // "sprmClidBi" chp.lidBi
168 { 84, { 1, L_FIX} }, // "sprmCIcoBi" chp.icoBi
169 { 85, { 1, L_FIX} }, // "sprmCHpsBi" chp.hpsBi
170 { 86, { 1, L_FIX} }, // "sprmCFBiDi" chp.fBiDi
171 { 87, { 1, L_FIX} }, // "sprmCFDiacColor" chp.fDiacUSico
172 { 94, { 1, L_FIX} }, // "sprmPicBrcl" pic.brcl brcl (see PIC definition)
173 { 95, {12, L_VAR} }, // "sprmPicScale" pic.mx, pic.my, pic.dxaCropleft,
174 { 96, { 2, L_FIX} }, // "sprmPicBrcTop" pic.brcTop BRC word
175 { 97, { 2, L_FIX} }, // "sprmPicBrcLeft" pic.brcLeft BRC word
176 { 98, { 2, L_FIX} }, // "sprmPicBrcBottom" pic.brcBottom BRC word
177 { 99, { 2, L_FIX} }, // "sprmPicBrcRight" pic.brcRight BRC word
178 {112, { 1, L_FIX} }, // "sprmSFRTLGutter", set to one if gutter is on
179 {114, { 1, L_FIX} }, // "sprmSFBiDi" ;;;
180 {115, { 2, L_FIX} }, // "sprmSDmBinFirst" sep.dmBinFirst word
181 {116, { 2, L_FIX} }, // "sprmSDmBinOther" sep.dmBinOther word
182 {117, { 1, L_FIX} }, // "sprmSBkc" sep.bkc bkc byte
183 {118, { 1, L_FIX} }, // "sprmSFTitlePage" sep.fTitlePage 0 or 1 byte
184 {119, { 2, L_FIX} }, // "sprmSCcolumns" sep.ccolM1 # of cols - 1 word
185 {120, { 2, L_FIX} }, // "sprmSDxaColumns" sep.dxaColumns dxa word
186 {121, { 1, L_FIX} }, // "sprmSFAutoPgn" sep.fAutoPgn obsolete byte
187 {122, { 1, L_FIX} }, // "sprmSNfcPgn" sep.nfcPgn nfc byte
188 {123, { 2, L_FIX} }, // "sprmSDyaPgn" sep.dyaPgn dya short
189 {124, { 2, L_FIX} }, // "sprmSDxaPgn" sep.dxaPgn dya short
190 {125, { 1, L_FIX} }, // "sprmSFPgnRestart" sep.fPgnRestart 0 or 1 byte
191 {126, { 1, L_FIX} }, // "sprmSFEndnote" sep.fEndnote 0 or 1 byte
192 {127, { 1, L_FIX} }, // "sprmSLnc" sep.lnc lnc byte
193 {128, { 1, L_FIX} }, // "sprmSGprfIhdt" sep.grpfIhdt grpfihdt
194 {129, { 2, L_FIX} }, // "sprmSNLnnMod" sep.nLnnMod non-neg int. word
195 {130, { 2, L_FIX} }, // "sprmSDxaLnn" sep.dxaLnn dxa word
196 {131, { 2, L_FIX} }, // "sprmSDyaHdrTop" sep.dyaHdrTop dya word
197 {132, { 2, L_FIX} }, // "sprmSDyaHdrBottom" sep.dyaHdrBottom dya word
198 {133, { 1, L_FIX} }, // "sprmSLBetween" sep.fLBetween 0 or 1 byte
199 {134, { 1, L_FIX} }, // "sprmSVjc" sep.vjc vjc byte
200 {135, { 2, L_FIX} }, // "sprmSLnnMin" sep.lnnMin lnn word
201 {136, { 2, L_FIX} }, // "sprmSPgnStart" sep.pgnStart pgn word
202 {137, { 1, L_FIX} }, // "sprmSBOrientation" sep.dmOrientPage dm byte
203 {138, { 1, L_FIX} }, // "sprmSFFacingCol" ;;;
204 {139, { 2, L_FIX} }, // "sprmSXaPage" sep.xaPage xa word
205 {140, { 2, L_FIX} }, // "sprmSYaPage" sep.yaPage ya word
206 {141, { 2, L_FIX} }, // "sprmSDxaLeft" sep.dxaLeft dxa word
207 {142, { 2, L_FIX} }, // "sprmSDxaRight" sep.dxaRight dxa word
208 {143, { 2, L_FIX} }, // "sprmSDyaTop" sep.dyaTop dya word
209 {144, { 2, L_FIX} }, // "sprmSDyaBottom" sep.dyaBottom dya word
210 {145, { 2, L_FIX} }, // "sprmSDzaGutter" sep.dzaGutter dza word
211 {146, { 2, L_FIX} }, // "sprmTJc" tap.jc jc (low order byte is significant)
212 {147, { 2, L_FIX} }, // "sprmTDxaLeft" tap.rgdxaCenter dxa word
213 {148, { 2, L_FIX} }, // "sprmTDxaGapHalf" tap.dxaGapHalf, tap.rgdxaCenter
214 {149, { 1, L_FIX} }, // "sprmTFBiDi" ;;;
215 {152, { 0, L_VAR2} },// "sprmTDefTable10" tap.rgdxaCenter, tap.rgtc complex
216 {153, { 2, L_FIX} }, // "sprmTDyaRowHeight" tap.dyaRowHeight dya word
217 {154, { 0, L_VAR2} },// "sprmTDefTable" tap.rgtc complex
218 {155, { 1, L_VAR} }, // "sprmTDefTableShd" tap.rgshd complex
219 {157, { 5, L_FIX} }, // "sprmTSetBrc" tap.rgtc[].rgbrc complex 5 bytes
220 {158, { 4, L_FIX} }, // "sprmTInsert" tap.rgdxaCenter,tap.rgtc complex
221 {159, { 2, L_FIX} }, // "sprmTDelete" tap.rgdxaCenter, tap.rgtc complex
222 {160, { 4, L_FIX} }, // "sprmTDxaCol" tap.rgdxaCenter complex
223 {161, { 2, L_FIX} }, // "sprmTMerge" tap.fFirstMerged, tap.fMerged complex
224 {162, { 2, L_FIX} }, // "sprmTSplit" tap.fFirstMerged, tap.fMerged complex
225 {163, { 5, L_FIX} }, // "sprmTSetBrc10" tap.rgtc[].rgbrc complex 5 bytes
226 {164, { 4, L_FIX} }, // "sprmTSetShd", tap.rgshd complex 4 bytes
229 static wwSprmSearcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
230 return &aSprmSrch;
233 const wwSprmSearcher *wwSprmParser::GetWW6SprmSearcher(const WW8Fib& rFib)
235 //double lock me
236 // WW7- Sprms
237 static const SprmInfoRow aSprms[] =
239 { 0, { 0, L_FIX} }, // "Default-sprm", is skipped
240 {NS_sprm::v6::sprmPIstd, { 2, L_FIX} }, // pap.istd (style code)
241 {NS_sprm::v6::sprmPIstdPermute, { 3, L_VAR} }, // pap.istd permutation
242 {NS_sprm::v6::sprmPIncLv1, { 1, L_FIX} }, // pap.istddifference
243 {NS_sprm::v6::sprmPJc, { 1, L_FIX} }, // pap.jc (justification)
244 {NS_sprm::v6::sprmPFSideBySide, { 1, L_FIX} }, // pap.fSideBySide
245 {NS_sprm::v6::sprmPFKeep, { 1, L_FIX} }, // pap.fKeep
246 {NS_sprm::v6::sprmPFKeepFollow, { 1, L_FIX} }, // pap.fKeepFollow
247 {NS_sprm::v6::sprmPPageBreakBefore, { 1, L_FIX} }, // pap.fPageBreakBefore
248 {NS_sprm::v6::sprmPBrcl, { 1, L_FIX} }, // pap.brcl
249 {NS_sprm::v6::sprmPBrcp, { 1, L_FIX} }, // pap.brcp
250 {NS_sprm::v6::sprmPAnld, { 0, L_VAR} }, // pap.anld (ANLD structure)
251 {NS_sprm::v6::sprmPNLvlAnm, { 1, L_FIX} }, // pap.nLvlAnm nn
252 {NS_sprm::v6::sprmPFNoLineNumb, { 1, L_FIX} }, // pap.fNoLnn
253 {NS_sprm::v6::sprmPChgTabsPapx, { 0, L_VAR} }, // pap.itbdMac, ...
254 {NS_sprm::v6::sprmPDxaRight, { 2, L_FIX} }, // pap.dxaRight
255 {NS_sprm::v6::sprmPDxaLeft, { 2, L_FIX} }, // pap.dxaLeft
256 {NS_sprm::v6::sprmPNest, { 2, L_FIX} }, // pap.dxaLeft
257 {NS_sprm::v6::sprmPDxaLeft1, { 2, L_FIX} }, // pap.dxaLeft1
258 {NS_sprm::v6::sprmPDyaLine, { 4, L_FIX} }, // pap.lspd an LSPD
259 {NS_sprm::v6::sprmPDyaBefore, { 2, L_FIX} }, // pap.dyaBefore
260 {NS_sprm::v6::sprmPDyaAfter, { 2, L_FIX} }, // pap.dyaAfter
261 {NS_sprm::v6::sprmPChgTabs, { 0, L_VAR} }, // pap.itbdMac, pap.rgdxaTab, ...
262 {NS_sprm::v6::sprmPFInTable, { 1, L_FIX} }, // pap.fInTable
263 {NS_sprm::v6::sprmPTtp, { 1, L_FIX} }, // pap.fTtp
264 {NS_sprm::v6::sprmPDxaAbs, { 2, L_FIX} }, // pap.dxaAbs
265 {NS_sprm::v6::sprmPDyaAbs, { 2, L_FIX} }, // pap.dyaAbs
266 {NS_sprm::v6::sprmPDxaWidth, { 2, L_FIX} }, // pap.dxaWidth
267 {NS_sprm::v6::sprmPPc, { 1, L_FIX} }, // pap.pcHorz, pap.pcVert
268 {NS_sprm::v6::sprmPBrcTop10, { 2, L_FIX} }, // pap.brcTop BRC10
269 {NS_sprm::v6::sprmPBrcLeft10, { 2, L_FIX} }, // pap.brcLeft BRC10
270 {NS_sprm::v6::sprmPBrcBottom10, { 2, L_FIX} }, // pap.brcBottom BRC10
271 {NS_sprm::v6::sprmPBrcRight10, { 2, L_FIX} }, // pap.brcRight BRC10
272 {NS_sprm::v6::sprmPBrcBetween10, { 2, L_FIX} }, // pap.brcBetween BRC10
273 {NS_sprm::v6::sprmPBrcBar10, { 2, L_FIX} }, // pap.brcBar BRC10
274 {NS_sprm::v6::sprmPFromText10, { 2, L_FIX} }, // pap.dxaFromText dxa
275 {NS_sprm::v6::sprmPWr, { 1, L_FIX} }, // pap.wr wr
276 {NS_sprm::v6::sprmPBrcTop, { 2, L_FIX} }, // pap.brcTop BRC
277 {NS_sprm::v6::sprmPBrcLeft, { 2, L_FIX} }, // pap.brcLeft BRC
278 {NS_sprm::v6::sprmPBrcBottom, { 2, L_FIX} }, // pap.brcBottom BRC
279 {NS_sprm::v6::sprmPBrcRight, { 2, L_FIX} }, // pap.brcRight BRC
280 {NS_sprm::v6::sprmPBrcBetween, { 2, L_FIX} }, // pap.brcBetween BRC
281 {NS_sprm::v6::sprmPBrcBar, { 2, L_FIX} }, // pap.brcBar BRC word
282 {NS_sprm::v6::sprmPFNoAutoHyph, { 1, L_FIX} }, // pap.fNoAutoHyph
283 {NS_sprm::v6::sprmPWHeightAbs, { 2, L_FIX} }, // pap.wHeightAbs w
284 {NS_sprm::v6::sprmPDcs, { 2, L_FIX} }, // pap.dcs DCS
285 {NS_sprm::v6::sprmPShd, { 2, L_FIX} }, // pap.shd SHD
286 {NS_sprm::v6::sprmPDyaFromText, { 2, L_FIX} }, // pap.dyaFromText dya
287 {NS_sprm::v6::sprmPDxaFromText, { 2, L_FIX} }, // pap.dxaFromText dxa
288 {NS_sprm::v6::sprmPFLocked, { 1, L_FIX} }, // pap.fLocked 0 or 1 byte
289 {NS_sprm::v6::sprmPFWidowControl, { 1, L_FIX} }, // pap.fWidowControl 0 or 1 byte
290 {NS_sprm::v6::sprmPRuler, { 0, L_FIX} },
291 { 64, { 0, L_VAR} }, // rtl property ?
292 {NS_sprm::v6::sprmCFStrikeRM, { 1, L_FIX} }, // chp.fRMarkDel 1 or 0 bit
293 {NS_sprm::v6::sprmCFRMark, { 1, L_FIX} }, // chp.fRMark 1 or 0 bit
294 {NS_sprm::v6::sprmCFFldVanish, { 1, L_FIX} }, // chp.fFieldVanish 1 or 0 bit
295 {NS_sprm::v6::sprmCPicLocation, { 0, L_VAR} }, // chp.fcPic and chp.fSpec
296 {NS_sprm::v6::sprmCIbstRMark, { 2, L_FIX} }, // chp.ibstRMark index into sttbRMark
297 {NS_sprm::v6::sprmCDttmRMark, { 4, L_FIX} }, // chp.dttm DTTM long
298 {NS_sprm::v6::sprmCFData, { 1, L_FIX} }, // chp.fData 1 or 0 bit
299 {NS_sprm::v6::sprmCRMReason, { 2, L_FIX} }, // chp.idslRMReason an index to a table
300 {NS_sprm::v6::sprmCChse, { 3, L_FIX} }, // chp.fChsDiff and chp.chse
301 {NS_sprm::v6::sprmCSymbol, { 0, L_VAR} }, // chp.fSpec, chp.chSym and chp.ftcSym
302 {NS_sprm::v6::sprmCFOle2, { 1, L_FIX} }, // chp.fOle2 1 or 0 bit
303 { 77, { 0, L_VAR} }, // unknown
304 { 79, { 0, L_VAR} }, // unknown
305 {NS_sprm::v6::sprmCIstd, { 2, L_FIX} }, // chp.istd istd, see stylesheet definition
306 {NS_sprm::v6::sprmCIstdPermute, { 0, L_VAR} }, // chp.istd permutation vector
307 {NS_sprm::v6::sprmCDefault, { 0, L_VAR} }, // whole CHP
308 {NS_sprm::v6::sprmCPlain, { 0, L_FIX} }, // whole CHP
309 {NS_sprm::v6::sprmCFBold, { 1, L_FIX} }, // chp.fBold 0,1, 128, or 129
310 {NS_sprm::v6::sprmCFItalic, { 1, L_FIX} }, // chp.fItalic 0,1, 128, or 129
311 {NS_sprm::v6::sprmCFStrike, { 1, L_FIX} }, // chp.fStrike 0,1, 128, or 129
312 {NS_sprm::v6::sprmCFOutline, { 1, L_FIX} }, // chp.fOutline 0,1, 128, or 129
313 {NS_sprm::v6::sprmCFShadow, { 1, L_FIX} }, // chp.fShadow 0,1, 128, or 129
314 {NS_sprm::v6::sprmCFSmallCaps, { 1, L_FIX} }, // chp.fSmallCaps 0,1, 128, or 129
315 {NS_sprm::v6::sprmCFCaps, { 1, L_FIX} }, // chp.fCaps 0,1, 128, or 129
316 {NS_sprm::v6::sprmCFVanish, { 1, L_FIX} }, // chp.fVanish 0,1, 128, or 129
317 {NS_sprm::v6::sprmCFtc, { 2, L_FIX} }, // chp.ftc ftc word
318 {NS_sprm::v6::sprmCKul, { 1, L_FIX} }, // chp.kul kul byte
319 {NS_sprm::v6::sprmCSizePos, { 3, L_FIX} }, // chp.hps, chp.hpsPos
320 {NS_sprm::v6::sprmCDxaSpace, { 2, L_FIX} }, // chp.dxaSpace dxa
321 {NS_sprm::v6::sprmCLid, { 2, L_FIX} }, // chp.lid LID
322 {NS_sprm::v6::sprmCIco, { 1, L_FIX} }, // chp.ico ico byte
323 {NS_sprm::v6::sprmCHps, { 2, L_FIX} }, // chp.hps hps !word!
324 {NS_sprm::v6::sprmCHpsInc, { 1, L_FIX} }, // chp.hps
325 {NS_sprm::v6::sprmCHpsPos, { 2, L_FIX} }, // chp.hpsPos hps !word!
326 {NS_sprm::v6::sprmCHpsPosAdj, { 1, L_FIX} }, // chp.hpsPos hps
327 {NS_sprm::v6::sprmCMajority, { 0, L_VAR} }, // chp.fBold, chp.fItalic, ...
328 {NS_sprm::v6::sprmCIss, { 1, L_FIX} }, // chp.iss iss
329 {NS_sprm::v6::sprmCHpsNew50, { 0, L_VAR} }, // chp.hps hps variable width
330 {NS_sprm::v6::sprmCHpsInc1, { 0, L_VAR} }, // chp.hps complex
331 {NS_sprm::v6::sprmCHpsKern, { 2, L_FIX} }, // chp.hpsKern hps
332 {NS_sprm::v6::sprmCMajority50, { 0, L_VAR} }, // chp.fBold, chp.fItalic, ...
333 {NS_sprm::v6::sprmCHpsMul, { 2, L_FIX} }, // chp.hps percentage to grow hps
334 {NS_sprm::v6::sprmCCondHyhen, { 2, L_FIX} }, // chp.ysri ysri
335 {111, { 0, L_VAR} }, // sprmCFBoldBi or font code
336 {112, { 0, L_VAR} }, // sprmCFItalicBi or font code
337 {113, { 0, L_VAR} }, // ww7 rtl font
338 {114, { 0, L_VAR} }, // ww7 lid
339 {115, { 0, L_VAR} }, // ww7 CJK font
340 {116, { 0, L_VAR} }, // ww7 fontsize
341 {NS_sprm::v6::sprmCFSpec, { 1, L_FIX} }, // chp.fSpec 1 or 0 bit
342 {NS_sprm::v6::sprmCFObj, { 1, L_FIX} }, // chp.fObj 1 or 0 bit
343 {NS_sprm::v6::sprmPicBrcl, { 1, L_FIX} }, // pic.brcl brcl (see PIC definition)
344 {NS_sprm::v6::sprmPicScale, {12, L_VAR} }, // pic.mx, pic.my, pic.dxaCropleft,
345 {NS_sprm::v6::sprmPicBrcTop, { 2, L_FIX} }, // pic.brcTop BRC word
346 {NS_sprm::v6::sprmPicBrcLeft, { 2, L_FIX} }, // pic.brcLeft BRC word
347 {NS_sprm::v6::sprmPicBrcBottom, { 2, L_FIX} }, // pic.brcBottom BRC word
348 {NS_sprm::v6::sprmPicBrcRight, { 2, L_FIX} }, // pic.brcRight BRC word
349 {NS_sprm::v6::sprmSScnsPgn, { 1, L_FIX} }, // sep.cnsPgn cns byte
350 {NS_sprm::v6::sprmSiHeadingPgn, { 1, L_FIX} }, // sep.iHeadingPgn
351 {NS_sprm::v6::sprmSOlstAnm, { 0, L_VAR} }, // sep.olstAnm OLST variable length
352 {NS_sprm::v6::sprmSDxaColWidth, { 3, L_FIX} }, // sep.rgdxaColWidthSpacing complex
353 {NS_sprm::v6::sprmSDxaColSpacing, { 3, L_FIX} }, // sep.rgdxaColWidthSpacing
354 {NS_sprm::v6::sprmSFEvenlySpaced, { 1, L_FIX} }, // sep.fEvenlySpaced 1 or 0
355 {NS_sprm::v6::sprmSFProtected, { 1, L_FIX} }, // sep.fUnlocked 1 or 0 byte
356 {NS_sprm::v6::sprmSDmBinFirst, { 2, L_FIX} }, // sep.dmBinFirst word
357 {NS_sprm::v6::sprmSDmBinOther, { 2, L_FIX} }, // sep.dmBinOther word
358 {NS_sprm::v6::sprmSBkc, { 1, L_FIX} }, // sep.bkc bkc byte
359 {NS_sprm::v6::sprmSFTitlePage, { 1, L_FIX} }, // sep.fTitlePage 0 or 1 byte
360 {NS_sprm::v6::sprmSCcolumns, { 2, L_FIX} }, // sep.ccolM1 # of cols - 1 word
361 {NS_sprm::v6::sprmSDxaColumns, { 2, L_FIX} }, // sep.dxaColumns dxa word
362 {NS_sprm::v6::sprmSFAutoPgn, { 1, L_FIX} }, // sep.fAutoPgn obsolete byte
363 {NS_sprm::v6::sprmSNfcPgn, { 1, L_FIX} }, // sep.nfcPgn nfc byte
364 {NS_sprm::v6::sprmSDyaPgn, { 2, L_FIX} }, // sep.dyaPgn dya short
365 {NS_sprm::v6::sprmSDxaPgn, { 2, L_FIX} }, // sep.dxaPgn dya short
366 {NS_sprm::v6::sprmSFPgnRestart, { 1, L_FIX} }, // sep.fPgnRestart 0 or 1 byte
367 {NS_sprm::v6::sprmSFEndnote, { 1, L_FIX} }, // sep.fEndnote 0 or 1 byte
368 {NS_sprm::v6::sprmSLnc, { 1, L_FIX} }, // sep.lnc lnc byte
369 {NS_sprm::v6::sprmSGprfIhdt, { 1, L_FIX} }, // sep.grpfIhdt grpfihdt
370 {NS_sprm::v6::sprmSNLnnMod, { 2, L_FIX} }, // sep.nLnnMod non-neg int. word
371 {NS_sprm::v6::sprmSDxaLnn, { 2, L_FIX} }, // sep.dxaLnn dxa word
372 {NS_sprm::v6::sprmSDyaHdrTop, { 2, L_FIX} }, // sep.dyaHdrTop dya word
373 {NS_sprm::v6::sprmSDyaHdrBottom, { 2, L_FIX} }, // sep.dyaHdrBottom dya word
374 {NS_sprm::v6::sprmSLBetween, { 1, L_FIX} }, // sep.fLBetween 0 or 1 byte
375 {NS_sprm::v6::sprmSVjc, { 1, L_FIX} }, // sep.vjc vjc byte
376 {NS_sprm::v6::sprmSLnnMin, { 2, L_FIX} }, // sep.lnnMin lnn word
377 {NS_sprm::v6::sprmSPgnStart, { 2, L_FIX} }, // sep.pgnStart pgn word
378 {NS_sprm::v6::sprmSBOrientation, { 1, L_FIX} }, // sep.dmOrientPage dm byte
379 {NS_sprm::v6::sprmSBCustomize, { 0, L_FIX} },
380 {NS_sprm::v6::sprmSXaPage, { 2, L_FIX} }, // sep.xaPage xa word
381 {NS_sprm::v6::sprmSYaPage, { 2, L_FIX} }, // sep.yaPage ya word
382 {NS_sprm::v6::sprmSDxaLeft, { 2, L_FIX} }, // sep.dxaLeft dxa word
383 {NS_sprm::v6::sprmSDxaRight, { 2, L_FIX} }, // sep.dxaRight dxa word
384 {NS_sprm::v6::sprmSDyaTop, { 2, L_FIX} }, // sep.dyaTop dya word
385 {NS_sprm::v6::sprmSDyaBottom, { 2, L_FIX} }, // sep.dyaBottom dya word
386 {NS_sprm::v6::sprmSDzaGutter, { 2, L_FIX} }, // sep.dzaGutter dza word
387 {NS_sprm::v6::sprmSDMPaperReq, { 2, L_FIX} }, // sep.dmPaperReq dm word
388 {179, { 0, L_VAR} }, // rtl property ?
389 {181, { 0, L_VAR} }, // rtl property ?
390 {NS_sprm::v6::sprmTJc, { 2, L_FIX} }, // tap.jc jc (low order byte is significant)
391 {NS_sprm::v6::sprmTDxaLeft, { 2, L_FIX} }, // tap.rgdxaCenter dxa word
392 {NS_sprm::v6::sprmTDxaGapHalf, { 2, L_FIX} }, // tap.dxaGapHalf, tap.rgdxaCenter
393 {NS_sprm::v6::sprmTFCantSplit, { 1, L_FIX} }, // tap.fCantSplit 1 or 0 byte
394 {NS_sprm::v6::sprmTTableHeader, { 1, L_FIX} }, // tap.fTableHeader 1 or 0 byte
395 {NS_sprm::v6::sprmTTableBorders, {12, L_FIX} }, // tap.rgbrcTable complex 12 bytes
396 {NS_sprm::v6::sprmTDefTable10, { 0, L_VAR2} }, // tap.rgdxaCenter, tap.rgtc complex
397 {NS_sprm::v6::sprmTDyaRowHeight, { 2, L_FIX} }, // tap.dyaRowHeight dya word
398 {NS_sprm::v6::sprmTDefTable, { 0, L_VAR2} }, // tap.rgtc complex
399 {NS_sprm::v6::sprmTDefTableShd, { 1, L_VAR} }, // tap.rgshd complex
400 {NS_sprm::v6::sprmTTlp, { 4, L_FIX} }, // tap.tlp TLP 4 bytes
401 {NS_sprm::v6::sprmTSetBrc, { 5, L_FIX} }, // tap.rgtc[].rgbrc complex 5 bytes
402 {NS_sprm::v6::sprmTInsert, { 4, L_FIX} }, // tap.rgdxaCenter,tap.rgtc complex
403 {NS_sprm::v6::sprmTDelete, { 2, L_FIX} }, // tap.rgdxaCenter, tap.rgtc complex
404 {NS_sprm::v6::sprmTDxaCol, { 4, L_FIX} }, // tap.rgdxaCenter complex
405 {NS_sprm::v6::sprmTMerge, { 2, L_FIX} }, // tap.fFirstMerged, tap.fMerged complex
406 {NS_sprm::v6::sprmTSplit, { 2, L_FIX} }, // tap.fFirstMerged, tap.fMerged complex
407 {NS_sprm::v6::sprmTSetBrc10, { 5, L_FIX} }, // tap.rgtc[].rgbrc complex 5 bytes
408 {NS_sprm::v6::sprmTSetShd, { 4, L_FIX} }, // tap.rgshd complex 4 bytes
409 {207, { 0, L_VAR} } // rtl property ?
412 if (rFib.m_wIdent >= 0xa697 && rFib.m_wIdent <= 0xa699)
414 //see Read_AmbiguousSPRM for this oddity
415 static wwSprmSearcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms), true);
416 return &aSprmSrch;
419 static wwSprmSearcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
420 return &aSprmSrch;
423 void wwSprmSearcher::patchCJKVariant()
425 for (sal_uInt16 nId = 111; nId <= 113; ++nId)
427 SprmInfo& amb1 = map_[nId];
428 amb1.nLen = 2;
429 amb1.nVari = wwSprmParser::L_FIX;
433 template <class Sprm> static constexpr SprmInfoRow InfoRow()
435 return { Sprm::val, { Sprm::len, Sprm::varlen ? wwSprmParser::L_VAR : wwSprmParser::L_FIX } };
438 const wwSprmSearcher *wwSprmParser::GetWW8SprmSearcher()
440 //double lock me
441 //WW8+ Sprms
442 static const SprmInfoRow aSprms[] =
444 { 0, { 0, L_FIX} }, // "Default-sprm"/ is skipped
445 InfoRow<NS_sprm::PIstd>(), // pap.istd;istd (style code);short;
446 InfoRow<NS_sprm::PIstdPermute>(), // pap.istd;permutation vector
447 InfoRow<NS_sprm::PIncLvl>(), // pap.istd, pap.lvl;difference
448 // between istd of base PAP and istd of PAP to be
449 // produced
450 InfoRow<NS_sprm::PJc80>(), // pap.jc;jc (justification);byte;
451 {NS_sprm::LN_PFSideBySide, { 1, L_FIX} }, // "sprmPFSideBySide" pap.fSideBySide;0 or 1;byte;
452 InfoRow<NS_sprm::PFKeep>(), // pap.fKeep;0 or 1;byte;
453 InfoRow<NS_sprm::PFKeepFollow>(), // pap.fKeepFollow;0 or 1;byte;
454 InfoRow<NS_sprm::PFPageBreakBefore>(), // pap.fPageBreakBefore;
455 // 0 or 1
456 {NS_sprm::LN_PBrcl, { 1, L_FIX} }, // "sprmPBrcl" pap.brcl;brcl;byte;
457 {NS_sprm::LN_PBrcp, { 1, L_FIX} }, // "sprmPBrcp" pap.brcp;brcp;byte;
458 InfoRow<NS_sprm::PIlvl>(), // pap.ilvl;ilvl;byte;
459 InfoRow<NS_sprm::PIlfo>(), // pap.ilfo;ilfo (list index) ;short;
460 InfoRow<NS_sprm::PFNoLineNumb>(), // pap.fNoLnn;0 or 1;byte;
461 InfoRow<NS_sprm::PChgTabsPapx>(), // pap.itbdMac, pap.rgdxaTab,
462 // pap.rgtbd;complex
463 InfoRow<NS_sprm::PDxaRight80>(), // pap.dxaRight;dxa;word;
464 InfoRow<NS_sprm::PDxaLeft80>(), // pap.dxaLeft;dxa;word;
465 InfoRow<NS_sprm::PNest80>(), // pap.dxaLeft;dxa
466 InfoRow<NS_sprm::PDxaLeft180>(), // pap.dxaLeft1;dxa;word;
467 InfoRow<NS_sprm::PDyaLine>(), // pap.lspd;an LSPD, a long word
468 // structure consisting of a short of dyaLine
469 // followed by a short of fMultLinespace
470 InfoRow<NS_sprm::PDyaBefore>(), // pap.dyaBefore;dya;word;
471 InfoRow<NS_sprm::PDyaAfter>(), // pap.dyaAfter;dya;word;
472 InfoRow<NS_sprm::PChgTabs>(), // pap.itbdMac, pap.rgdxaTab,
473 // pap.rgtbd;complex
474 InfoRow<NS_sprm::PFInTable>(), // pap.fInTable;0 or 1;byte;
475 InfoRow<NS_sprm::PFTtp>(), // pap.fTtp;0 or 1;byte;
476 InfoRow<NS_sprm::PDxaAbs>(), // pap.dxaAbs;dxa;word;
477 InfoRow<NS_sprm::PDyaAbs>(), // pap.dyaAbs;dya;word;
478 InfoRow<NS_sprm::PDxaWidth>(), // pap.dxaWidth;dxa;word;
479 InfoRow<NS_sprm::PPc>(), // pap.pcHorz, pap.pcVert;complex
480 {NS_sprm::LN_PBrcTop10, { 2, L_FIX} }, // "sprmPBrcTop10" pap.brcTop;BRC10;word;
481 {NS_sprm::LN_PBrcLeft10, { 2, L_FIX} }, // "sprmPBrcLeft10" pap.brcLeft;BRC10;word;
482 {NS_sprm::LN_PBrcBottom10, { 2, L_FIX} }, // "sprmPBrcBottom10" pap.brcBottom;BRC10;word;
483 {NS_sprm::LN_PBrcRight10, { 2, L_FIX} }, // "sprmPBrcRight10" pap.brcRight;BRC10;word;
484 {NS_sprm::LN_PBrcBetween10, { 2, L_FIX} }, // "sprmPBrcBetween10" pap.brcBetween;BRC10;word;
485 {NS_sprm::LN_PBrcBar10, { 2, L_FIX} }, // "sprmPBrcBar10" pap.brcBar;BRC10;word;
486 {NS_sprm::LN_PDxaFromText10, { 2, L_FIX} }, // "sprmPDxaFromText10" pap.dxaFromText;dxa;word;
487 InfoRow<NS_sprm::PWr>(), // pap.wr;wr
488 InfoRow<NS_sprm::PBrcTop80>(), // pap.brcTop;BRC;long;
489 InfoRow<NS_sprm::PBrcLeft80>(), // pap.brcLeft;BRC;long;
490 InfoRow<NS_sprm::PBrcBottom80>(), // pap.brcBottom;BRC;long;
491 InfoRow<NS_sprm::PBrcRight80>(), // pap.brcRight;BRC;long;
492 InfoRow<NS_sprm::PBrcBetween80>(), // pap.brcBetween;BRC;long;
493 InfoRow<NS_sprm::PBrcBar80>(), // pap.brcBar;BRC;long;
494 InfoRow<NS_sprm::PFNoAutoHyph>(), // pap.fNoAutoHyph;0 or 1;byte;
495 InfoRow<NS_sprm::PWHeightAbs>(), // pap.wHeightAbs;w;word;
496 InfoRow<NS_sprm::PDcs>(), // pap.dcs;DCS;short;
497 InfoRow<NS_sprm::PShd80>(), // pap.shd;SHD;word;
498 InfoRow<NS_sprm::PDyaFromText>(), // pap.dyaFromText;dya;word;
499 InfoRow<NS_sprm::PDxaFromText>(), // pap.dxaFromText;dxa;word;
500 InfoRow<NS_sprm::PFLocked>(), // pap.fLocked;0 or 1;byte;
501 InfoRow<NS_sprm::PFWidowControl>(), // pap.fWidowControl;0 or 1
502 {NS_sprm::LN_PRuler, { 0, L_VAR} }, // "sprmPRuler" ;;variable length;
503 InfoRow<NS_sprm::PFKinsoku>(), // pap.fKinsoku;0 or 1;byte;
504 InfoRow<NS_sprm::PFWordWrap>(), // pap.fWordWrap;0 or 1;byte;
505 InfoRow<NS_sprm::PFOverflowPunct>(), // pap.fOverflowPunct;0 or 1
506 InfoRow<NS_sprm::PFTopLinePunct>(), // pap.fTopLinePunct;0 or 1
507 InfoRow<NS_sprm::PFAutoSpaceDE>(), // pap.fAutoSpaceDE;0 or 1
508 InfoRow<NS_sprm::PFAutoSpaceDN>(), // pap.fAutoSpaceDN;0 or 1
509 InfoRow<NS_sprm::PWAlignFont>(), // pap.wAlignFont;iFa
510 InfoRow<NS_sprm::PFrameTextFlow>(), // pap.fVertical pap.fBackward
511 // pap.fRotateFont;complex
512 {NS_sprm::LN_PISnapBaseLine, { 1, L_FIX} }, // "sprmPISnapBaseLine" obsolete: not applicable in
513 // Word97 and later versions;
514 {NS_sprm::LN_PAnld, { 0, L_VAR} }, // "sprmPAnld" pap.anld;;variable length;
515 {NS_sprm::LN_PPropRMark, { 0, L_VAR} }, // "sprmPPropRMark" pap.fPropRMark;complex
516 InfoRow<NS_sprm::POutLvl>(), // pap.lvl;has no effect if pap.istd
517 // is < 1 or is > 9
518 InfoRow<NS_sprm::PFBiDi>(), // ;;byte;
519 InfoRow<NS_sprm::PFNumRMIns>(), // pap.fNumRMIns;1 or 0;bit;
520 {NS_sprm::LN_PCrLf, { 1, L_FIX} }, // "sprmPCrLf" ;;byte;
521 InfoRow<NS_sprm::PNumRM>(), // pap.numrm;;variable length;
522 {NS_sprm::LN_PHugePapx, { 4, L_FIX} }, // "sprmPHugePapx" fc in the data stream to locate
523 // the huge grpprl
524 InfoRow<NS_sprm::PHugePapx>(), // fc in the data stream to locate
525 // the huge grpprl
526 InfoRow<NS_sprm::PFUsePgsuSettings>(), // pap.fUsePgsuSettings;
527 // 1 or 0
528 InfoRow<NS_sprm::PFAdjustRight>(), // pap.fAdjustRight;1 or 0;byte;
529 InfoRow<NS_sprm::CFRMarkDel>(), // chp.fRMarkDel;1 or 0;bit;
530 InfoRow<NS_sprm::CFRMarkIns>(), // chp.fRMark;1 or 0;bit;
531 InfoRow<NS_sprm::CFFldVanish>(), // chp.fFieldVanish;1 or 0;bit;
532 InfoRow<NS_sprm::CPicLocation>(), // chp.fcPic and chp.fSpec;
533 InfoRow<NS_sprm::CIbstRMark>(), // chp.ibstRMark;index into
534 // sttbRMark
535 InfoRow<NS_sprm::CDttmRMark>(), // chp.dttmRMark;DTTM;long;
536 InfoRow<NS_sprm::CFData>(), // chp.fData;1 or 0;bit;
537 InfoRow<NS_sprm::CIdslRMark>(), // chp.idslRMReason;an index to a
538 // table of strings defined in Word 6.0
539 // executables;short;
540 {NS_sprm::LN_CChs, { 1, L_FIX} }, // "sprmCChs" chp.fChsDiff and chp.chse;
541 InfoRow<NS_sprm::CSymbol>(), // chp.fSpec, chp.xchSym and
542 // chp.ftcSym
543 InfoRow<NS_sprm::CFOle2>(), // chp.fOle2;1 or 0;bit;
544 {NS_sprm::LN_CIdCharType, { 0, L_FIX} }, // "sprmCIdCharType" obsolete: not applicable in
545 // Word97 and later versions;
546 InfoRow<NS_sprm::CHighlight>(), // chp.fHighlight,
547 // chp.icoHighlight;ico (fHighlight is set to 1 iff
548 // ico is not 0)
549 {NS_sprm::LN_CObjLocation, { 4, L_FIX} }, // "sprmCObjLocation" chp.fcObj;FC;long;
550 {NS_sprm::LN_CFFtcAsciSymb, { 0, L_FIX} }, // "sprmCFFtcAsciSymb" ;;;
551 InfoRow<NS_sprm::CIstd>(), // chp.istd;istd, see stylesheet def
552 InfoRow<NS_sprm::CIstdPermute>(), // chp.istd;permutation vector
553 {NS_sprm::LN_CDefault, { 0, L_VAR} }, // "sprmCDefault" whole CHP;none;variable length;
554 InfoRow<NS_sprm::CPlain>(), // whole CHP;none;0;
555 InfoRow<NS_sprm::CKcd>(), // ;;;
556 InfoRow<NS_sprm::CFBold>(), // chp.fBold;0,1, 128, or 129
557 InfoRow<NS_sprm::CFItalic>(), // chp.fItalic;0,1, 128, or 129
558 InfoRow<NS_sprm::CFStrike>(), // chp.fStrike;0,1, 128, or 129
559 InfoRow<NS_sprm::CFOutline>(), // chp.fOutline;0,1, 128, or 129
560 InfoRow<NS_sprm::CFShadow>(), // chp.fShadow;0,1, 128, or 129
561 InfoRow<NS_sprm::CFSmallCaps>(), // chp.fSmallCaps;0,1, 128, or 129
562 InfoRow<NS_sprm::CFCaps>(), // chp.fCaps;0,1, 128, or 129
563 InfoRow<NS_sprm::CFVanish>(), // chp.fVanish;0,1, 128, or 129
564 {NS_sprm::LN_CFtcDefault, { 2, L_FIX} }, // "sprmCFtcDefault" ;ftc, only used internally
565 InfoRow<NS_sprm::CKul>(), // chp.kul;kul;byte;
566 {NS_sprm::LN_CSizePos, { 3, L_FIX} }, // "sprmCSizePos" chp.hps, chp.hpsPos;3 bytes;
567 InfoRow<NS_sprm::CDxaSpace>(), // chp.dxaSpace;dxa;word;
568 {NS_sprm::LN_CLid, { 2, L_FIX} }, // "sprmCLid" ;only used internally never stored
569 InfoRow<NS_sprm::CIco>(), // chp.ico;ico;byte;
570 InfoRow<NS_sprm::CHps>(), // chp.hps;hps
571 {NS_sprm::LN_CHpsInc, { 1, L_FIX} }, // "sprmCHpsInc" chp.hps;
572 InfoRow<NS_sprm::CHpsPos>(), // chp.hpsPos;hps;short; (doc wrong)
573 {NS_sprm::LN_CHpsPosAdj, { 1, L_FIX} }, // "sprmCHpsPosAdj" chp.hpsPos;hps
574 InfoRow<NS_sprm::CMajority>(), // chp.fBold, chp.fItalic,
575 // chp.fSmallCaps, chp.fVanish, chp.fStrike,
576 // chp.fCaps, chp.rgftc, chp.hps, chp.hpsPos,
577 // chp.kul, chp.dxaSpace, chp.ico,
578 // chp.rglid;complex;variable length, length byte
579 // plus size of following grpprl;
580 InfoRow<NS_sprm::CIss>(), // chp.iss;iss;byte;
581 {NS_sprm::LN_CHpsNew50, { 0, L_VAR} }, // "sprmCHpsNew50" chp.hps;hps;variable width
582 {NS_sprm::LN_CHpsInc1, { 0, L_VAR} }, // "sprmCHpsInc1" chp.hps;complex
583 InfoRow<NS_sprm::CHpsKern>(), // chp.hpsKern;hps;short;
584 {NS_sprm::LN_CMajority50, { 2, L_FIX} }, // "sprmCMajority50" chp.fBold, chp.fItalic,
585 // chp.fSmallCaps, chp.fVanish, chp.fStrike,
586 // chp.fCaps, chp.ftc, chp.hps, chp.hpsPos, chp.kul,
587 // chp.dxaSpace, chp.ico,;complex
588 {NS_sprm::LN_CHpsMul, { 2, L_FIX} }, // "sprmCHpsMul" chp.hps;percentage to grow hps
589 InfoRow<NS_sprm::CHresi>(), // chp.ysri;ysri;short;
590 InfoRow<NS_sprm::CRgFtc0>(), // chp.rgftc[0];ftc for ASCII text
591 InfoRow<NS_sprm::CRgFtc1>(), // chp.rgftc[1];ftc for Far East text
592 InfoRow<NS_sprm::CRgFtc2>(), // chp.rgftc[2];ftc for non-FE text
593 InfoRow<NS_sprm::CCharScale>(),
594 InfoRow<NS_sprm::CFDStrike>(), // chp.fDStrike;;byte;
595 InfoRow<NS_sprm::CFImprint>(), // chp.fImprint;1 or 0;bit;
596 InfoRow<NS_sprm::CFSpec>(), // chp.fSpec ;1 or 0;bit;
597 InfoRow<NS_sprm::CFObj>(), // chp.fObj;1 or 0;bit;
598 InfoRow<NS_sprm::CPropRMark90>(), // chp.fPropRMark,
599 // chp.ibstPropRMark, chp.dttmPropRMark;Complex
600 InfoRow<NS_sprm::CFEmboss>(), // chp.fEmboss;1 or 0;bit;
601 InfoRow<NS_sprm::CSfxText>(), // chp.sfxtText;text animation;byte;
602 InfoRow<NS_sprm::CFBiDi>(), // ;;;
603 {NS_sprm::LN_CFDiacColor, { 1, L_FIX} }, // "sprmCFDiacColor" ;;;
604 InfoRow<NS_sprm::CFBoldBi>(), // ;;;
605 InfoRow<NS_sprm::CFItalicBi>(), // ;;;
606 InfoRow<NS_sprm::CFtcBi>(),
607 InfoRow<NS_sprm::CLidBi>(), // ;;;
608 InfoRow<NS_sprm::CIcoBi>(), // ;;;
609 InfoRow<NS_sprm::CHpsBi>(), // ;;;
610 InfoRow<NS_sprm::CDispFldRMark>(), // chp.fDispFieldRMark,
611 // chp.ibstDispFieldRMark, chp.dttmDispFieldRMark ;
612 InfoRow<NS_sprm::CIbstRMarkDel>(), // chp.ibstRMarkDel;index into
613 // sttbRMark;short;
614 InfoRow<NS_sprm::CDttmRMarkDel>(), // chp.dttmRMarkDel;DTTM;long;
615 InfoRow<NS_sprm::CBrc80>(), // chp.brc;BRC;long;
616 InfoRow<NS_sprm::CShd80>(), // chp.shd;SHD;short;
617 InfoRow<NS_sprm::CIdslRMarkDel>(), // chp.idslRMReasonDel;an index
618 // to a table of strings defined in Word 6.0
619 // executables;short;
620 InfoRow<NS_sprm::CFUsePgsuSettings>(),
621 // chp.fUsePgsuSettings;1 or 0
622 {NS_sprm::LN_CCpg, { 2, L_FIX} }, // "sprmCCpg" ;;word;
623 InfoRow<NS_sprm::CRgLid0_80>(), // chp.rglid[0];LID: for non-FE text
624 InfoRow<NS_sprm::CRgLid1_80>(), // chp.rglid[1];LID: for Far East text
625 InfoRow<NS_sprm::CIdctHint>(), // chp.idctHint;IDCT:
626 {NS_sprm::LN_PicBrcl, { 1, L_FIX} }, // "sprmPicBrcl" pic.brcl;brcl (see PIC definition)
627 {NS_sprm::LN_PicScale, { 0, L_VAR} }, // "sprmPicScale" pic.mx, pic.my, pic.dxaCropleft,
628 // pic.dyaCropTop pic.dxaCropRight,
629 // pic.dyaCropBottom;Complex
630 InfoRow<NS_sprm::PicBrcTop80>(), // pic.brcTop;BRC;long;
631 InfoRow<NS_sprm::PicBrcLeft80>(), // pic.brcLeft;BRC;long;
632 InfoRow<NS_sprm::PicBrcBottom80>(), // pic.brcBottom;BRC;long;
633 InfoRow<NS_sprm::PicBrcRight80>(), // pic.brcRight;BRC;long;
634 InfoRow<NS_sprm::ScnsPgn>(), // sep.cnsPgn;cns;byte;
635 InfoRow<NS_sprm::SiHeadingPgn>(), // sep.iHeadingPgn;heading number
636 // level;byte;
637 {NS_sprm::LN_SOlstAnm, { 0, L_VAR} }, // "sprmSOlstAnm" sep.olstAnm;OLST;variable length;
638 InfoRow<NS_sprm::SDxaColWidth>(), // sep.rgdxaColWidthSpacing;
639 InfoRow<NS_sprm::SDxaColSpacing>(), // sep.rgdxaColWidthSpacing;
640 // complex
641 InfoRow<NS_sprm::SFEvenlySpaced>(), // sep.fEvenlySpaced;1 or 0
642 InfoRow<NS_sprm::SFProtected>(), // sep.fUnlocked;1 or 0;byte;
643 InfoRow<NS_sprm::SDmBinFirst>(), // sep.dmBinFirst;;word;
644 InfoRow<NS_sprm::SDmBinOther>(), // sep.dmBinOther;;word;
645 InfoRow<NS_sprm::SBkc>(), // sep.bkc;bkc;byte;
646 InfoRow<NS_sprm::SFTitlePage>(), // sep.fTitlePage;0 or 1;byte;
647 InfoRow<NS_sprm::SCcolumns>(), // sep.ccolM1;# of cols - 1;word;
648 InfoRow<NS_sprm::SDxaColumns>(), // sep.dxaColumns;dxa;word;
649 {NS_sprm::LN_SFAutoPgn, { 1, L_FIX} }, // "sprmSFAutoPgn" sep.fAutoPgn;obsolete;byte;
650 InfoRow<NS_sprm::SNfcPgn>(), // sep.nfcPgn;nfc;byte;
651 {NS_sprm::LN_SDyaPgn, { 2, L_FIX} }, // "sprmSDyaPgn" sep.dyaPgn;dya;short;
652 {NS_sprm::LN_SDxaPgn, { 2, L_FIX} }, // "sprmSDxaPgn" sep.dxaPgn;dya;short;
653 InfoRow<NS_sprm::SFPgnRestart>(), // sep.fPgnRestart;0 or 1;byte;
654 InfoRow<NS_sprm::SFEndnote>(), // sep.fEndnote;0 or 1;byte;
655 InfoRow<NS_sprm::SLnc>(), // sep.lnc;lnc;byte;
656 {NS_sprm::LN_SGprfIhdt, { 1, L_FIX} }, // "sprmSGprfIhdt" sep.grpfIhdt;grpfihdt
657 InfoRow<NS_sprm::SNLnnMod>(), // sep.nLnnMod;non-neg int.;word;
658 InfoRow<NS_sprm::SDxaLnn>(), // sep.dxaLnn;dxa;word;
659 InfoRow<NS_sprm::SDyaHdrTop>(), // sep.dyaHdrTop;dya;word;
660 InfoRow<NS_sprm::SDyaHdrBottom>(), // sep.dyaHdrBottom;dya;word;
661 InfoRow<NS_sprm::SLBetween>(), // sep.fLBetween;0 or 1;byte;
662 InfoRow<NS_sprm::SVjc>(), // sep.vjc;vjc;byte;
663 InfoRow<NS_sprm::SLnnMin>(), // sep.lnnMin;lnn;word;
664 InfoRow<NS_sprm::SPgnStart97>(), // sep.pgnStart;pgn;word;
665 InfoRow<NS_sprm::SBOrientation>(), // sep.dmOrientPage;dm;byte;
666 {NS_sprm::LN_SBCustomize, { 1, L_FIX} }, // "sprmSBCustomize" ;;;
667 InfoRow<NS_sprm::SXaPage>(), // sep.xaPage;xa;word;
668 InfoRow<NS_sprm::SYaPage>(), // sep.yaPage;ya;word;
669 InfoRow<NS_sprm::SDxaLeft>(), // sep.dxaLeft;dxa;word;
670 InfoRow<NS_sprm::SDxaRight>(), // sep.dxaRight;dxa;word;
671 InfoRow<NS_sprm::SDyaTop>(), // sep.dyaTop;dya;word;
672 InfoRow<NS_sprm::SDyaBottom>(), // sep.dyaBottom;dya;word;
673 InfoRow<NS_sprm::SDzaGutter>(), // sep.dzaGutter;dza;word;
674 InfoRow<NS_sprm::SDmPaperReq>(), // sep.dmPaperReq;dm;word;
675 {NS_sprm::LN_SPropRMark, { 0, L_VAR} }, // "sprmSPropRMark" sep.fPropRMark,
676 // sep.ibstPropRMark, sep.dttmPropRMark ;complex
677 InfoRow<NS_sprm::SFBiDi>(), // ;;;
678 {NS_sprm::LN_SFFacingCol, { 1, L_FIX} }, // "sprmSFFacingCol" ;;;
679 InfoRow<NS_sprm::SFRTLGutter>(), //, set to one if gutter is on
680 // right
681 InfoRow<NS_sprm::SBrcTop80>(), // sep.brcTop;BRC;long;
682 InfoRow<NS_sprm::SBrcLeft80>(), // sep.brcLeft;BRC;long;
683 InfoRow<NS_sprm::SBrcBottom80>(), // sep.brcBottom;BRC;long;
684 InfoRow<NS_sprm::SBrcRight80>(), // sep.brcRight;BRC;long;
685 InfoRow<NS_sprm::SPgbProp>(), // sep.pgbProp;;word;
686 InfoRow<NS_sprm::SDxtCharSpace>(), // sep.dxtCharSpace;dxt;long;
687 InfoRow<NS_sprm::SDyaLinePitch>(),
688 // sep.dyaLinePitch;dya; WRONG:long; RIGHT:short; !
689 InfoRow<NS_sprm::SClm>(), // ;;;
690 InfoRow<NS_sprm::STextFlow>(), // sep.wTextFlow;complex
691 InfoRow<NS_sprm::TJc90>(), // tap.jc;jc;word (low order byte is
692 // significant);
693 InfoRow<NS_sprm::TDxaLeft>(), // tap.rgdxaCenter
694 InfoRow<NS_sprm::TDxaGapHalf>(), // tap.dxaGapHalf,
695 // tap.rgdxaCenter
696 InfoRow<NS_sprm::TFCantSplit90>(), // tap.fCantSplit90;1 or 0;byte;
697 InfoRow<NS_sprm::TTableHeader>(), // tap.fTableHeader;1 or 0;byte;
698 InfoRow<NS_sprm::TFCantSplit>(), // tap.fCantSplit;1 or 0;byte;
699 InfoRow<NS_sprm::TTableBorders80>(), // tap.rgbrcTable;complex
700 {NS_sprm::LN_TDefTable10, { 0, L_VAR2} }, // "sprmTDefTable10" tap.rgdxaCenter,
701 // tap.rgtc;complex
702 InfoRow<NS_sprm::TDyaRowHeight>(), // tap.dyaRowHeight;dya;word;
703 {NS_sprm::LN_TDefTable, { 0, L_VAR2} }, // "sprmTDefTable" tap.rgtc;complex
704 InfoRow<NS_sprm::TDefTableShd80>(), // tap.rgshd;complex
705 InfoRow<NS_sprm::TTlp>(), // tap.tlp;TLP;4 bytes;
706 InfoRow<NS_sprm::TFBiDi>(), // ;;;
707 {NS_sprm::LN_THTMLProps, { 1, L_FIX} }, // "sprmTHTMLProps" ;;;
708 InfoRow<NS_sprm::TSetBrc80>(), // tap.rgtc[].rgbrc;complex
709 InfoRow<NS_sprm::TInsert>(), // tap.rgdxaCenter, tap.rgtc;complex
710 InfoRow<NS_sprm::TDelete>(), // tap.rgdxaCenter, tap.rgtc;complex
711 InfoRow<NS_sprm::TDxaCol>(), // tap.rgdxaCenter;complex
712 InfoRow<NS_sprm::TMerge>(), // tap.fFirstMerged, tap.fMerged;
713 InfoRow<NS_sprm::TSplit>(), // tap.fFirstMerged, tap.fMerged;
714 {NS_sprm::LN_TSetBrc10, { 0, L_VAR} }, // "sprmTSetBrc10" tap.rgtc[].rgbrc;complex
715 {NS_sprm::LN_TSetShd80, { 0, L_VAR} }, // "sprmTSetShd80" tap.rgshd;complex
716 {NS_sprm::LN_TSetShdOdd80, { 0, L_VAR} }, // "sprmTSetShdOdd80" tap.rgshd;complex
717 InfoRow<NS_sprm::TTextFlow>(), // tap.rgtc[].fVerticaltap,
718 // rgtc[].fBackwardtap, rgtc[].fRotateFont;0 or 10
719 // or 10 or 1;word;
720 {NS_sprm::LN_TDiagLine, { 1, L_FIX} }, // "sprmTDiagLine" ;;;
721 InfoRow<NS_sprm::TVertMerge>(), // tap.rgtc[].vertMerge
722 InfoRow<NS_sprm::TVertAlign>(), // tap.rgtc[].vertAlign
723 InfoRow<NS_sprm::CFELayout>(),
724 InfoRow<NS_sprm::PItap>(), // undocumented
725 InfoRow<NS_sprm::TTableWidth>(), // undocumented
726 InfoRow<NS_sprm::TDefTableShd>(),
727 InfoRow<NS_sprm::TTableBorders>(),
728 InfoRow<NS_sprm::TBrcTopCv>(), // undocumented
729 InfoRow<NS_sprm::TBrcLeftCv>(), // undocumented
730 InfoRow<NS_sprm::TBrcBottomCv>(), // undocumented
731 InfoRow<NS_sprm::TBrcRightCv>(), // undocumented
732 InfoRow<NS_sprm::TCellPadding>(), // undocumented
733 InfoRow<NS_sprm::TCellPaddingDefault>(), // undocumented
734 {0xD238, { 0, L_VAR} }, // undocumented sep
735 InfoRow<NS_sprm::PBrcTop>(),
736 InfoRow<NS_sprm::PBrcLeft>(),
737 InfoRow<NS_sprm::PBrcBottom>(),
738 InfoRow<NS_sprm::PBrcRight>(),
739 InfoRow<NS_sprm::PBrcBetween>(),
740 InfoRow<NS_sprm::TWidthIndent>(), // undocumented
741 InfoRow<NS_sprm::CRgLid0>(), // chp.rglid[0];LID: for non-FE text
742 InfoRow<NS_sprm::CRgLid1>(), // chp.rglid[1];LID: for Far East text
743 {0x6463, { 4, L_FIX} }, // undocumented
744 InfoRow<NS_sprm::PJc>(), // undoc, must be asian version of "sprmPJc"
745 InfoRow<NS_sprm::PDxaRight>(), // undoc, must be asian version of "sprmPDxaRight"
746 InfoRow<NS_sprm::PDxaLeft>(), // undoc, must be asian version of "sprmPDxaLeft"
747 InfoRow<NS_sprm::PDxaLeft1>(), // undoc, must be asian version of "sprmPDxaLeft1"
748 InfoRow<NS_sprm::TFAutofit>(), // undocumented
749 InfoRow<NS_sprm::TPc>(), // undocumented
750 InfoRow<NS_sprm::SRsid>(), // undocumented, sep, perhaps related to textgrids ?
751 InfoRow<NS_sprm::SFpc>(), // undocumented, sep
752 InfoRow<NS_sprm::PFInnerTableCell>(), // undocumented, subtable "sprmPFInTable" equiv ?
753 InfoRow<NS_sprm::PFInnerTtp>(), // undocumented, subtable "sprmPFTtp" equiv ?
754 InfoRow<NS_sprm::TDxaAbs>(), // undocumented
755 InfoRow<NS_sprm::TDyaAbs>(), // undocumented
756 InfoRow<NS_sprm::TDxaFromText>(), // undocumented
757 InfoRow<NS_sprm::CRsidProp>(), // undocumented
758 InfoRow<NS_sprm::CRsidText>(), // undocumented
759 InfoRow<NS_sprm::CCv>(), // text colour
760 InfoRow<NS_sprm::PShd>(), // undocumented, para back colour
761 InfoRow<NS_sprm::PRsid>(), // undocumented
762 InfoRow<NS_sprm::PTableProps>(), // undocumented
763 InfoRow<NS_sprm::TWidthBefore>(), // undocumented
764 InfoRow<NS_sprm::TSetShdTable>(), // undocumented, something to do with colour.
765 InfoRow<NS_sprm::TDefTableShdRaw>(), // undocumented, something to do with colour.
766 InfoRow<NS_sprm::CShd>(), // text backcolour
767 InfoRow<NS_sprm::SRncFtn>(), // undocumented, sep
768 InfoRow<NS_sprm::PFDyaBeforeAuto>(), // undocumented, para autobefore
769 InfoRow<NS_sprm::PFDyaAfterAuto>(), // undocumented, para autoafter
770 // "sprmPFContextualSpacing", don't add space between para of the same style
771 InfoRow<NS_sprm::PFContextualSpacing>(),
774 static wwSprmSearcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
775 return &aSprmSrch;
778 wwSprmParser::wwSprmParser(const WW8Fib& rFib) : meVersion(rFib.GetFIBVersion())
780 OSL_ENSURE((meVersion >= ww::eWW1 && meVersion <= ww::eWW8),
781 "Impossible value for version");
783 mnDelta = (ww::IsSevenMinus(meVersion)) ? 0 : 1;
785 if (meVersion <= ww::eWW2)
786 mpKnownSprms = GetWW2SprmSearcher();
787 else if (meVersion < ww::eWW8)
788 mpKnownSprms = GetWW6SprmSearcher(rFib);
789 else
790 mpKnownSprms = GetWW8SprmSearcher();
793 SprmInfo wwSprmParser::GetSprmInfo(sal_uInt16 nId) const
795 const SprmInfo* pFound = mpKnownSprms->search(nId);
796 if (pFound != nullptr)
798 return *pFound;
801 OSL_ENSURE(ww::IsEightPlus(meVersion),
802 "Unknown ww7- sprm, dangerous, report to development");
804 //All the unknown ww7 sprms appear to be variable (which makes sense)
805 SprmInfo aSrch = { 0, L_VAR };
806 if (ww::IsEightPlus(meVersion)) //We can recover perfectly in this case
808 aSrch.nVari = L_FIX;
809 switch (nId >> 13)
811 case 0:
812 case 1:
813 aSrch.nLen = 1;
814 break;
815 case 2:
816 aSrch.nLen = 2;
817 break;
818 case 3:
819 aSrch.nLen = 4;
820 break;
821 case 4:
822 case 5:
823 aSrch.nLen = 2;
824 break;
825 case 6:
826 aSrch.nLen = 0;
827 aSrch.nVari = L_VAR;
828 break;
829 case 7:
830 default:
831 aSrch.nLen = 3;
832 break;
835 return aSrch;
838 //-end
840 static sal_uInt8 Get_Byte( sal_uInt8 *& p )
842 sal_uInt8 n = *p;
843 p += 1;
844 return n;
847 static sal_uInt16 Get_UShort( sal_uInt8 *& p )
849 const sal_uInt16 n = SVBT16ToUInt16( *reinterpret_cast<SVBT16*>(p) );
850 p += 2;
851 return n;
854 static sal_Int16 Get_Short( sal_uInt8 *& p )
856 return Get_UShort(p);
859 static sal_uInt32 Get_ULong( sal_uInt8 *& p )
861 sal_uInt32 n = SVBT32ToUInt32( *reinterpret_cast<SVBT32*>(p) );
862 p += 4;
863 return n;
866 static sal_Int32 Get_Long( sal_uInt8 *& p )
868 return Get_ULong(p);
871 WW8SprmIter::WW8SprmIter(const sal_uInt8* pSprms_, sal_Int32 nLen_,
872 const wwSprmParser &rParser)
873 : mrSprmParser(rParser), m_pSprms( pSprms_), m_nRemLen( nLen_)
875 UpdateMyMembers();
878 void WW8SprmIter::SetSprms(const sal_uInt8* pSprms_, sal_Int32 nLen_)
880 m_pSprms = pSprms_;
881 m_nRemLen = nLen_;
882 UpdateMyMembers();
885 void WW8SprmIter::advance()
887 if (m_nRemLen > 0 )
889 sal_uInt16 nSize = m_nCurrentSize;
890 if (nSize > m_nRemLen)
891 nSize = m_nRemLen;
892 m_pSprms += nSize;
893 m_nRemLen -= nSize;
894 UpdateMyMembers();
898 void WW8SprmIter::UpdateMyMembers()
900 bool bValid = (m_pSprms && m_nRemLen >= mrSprmParser.MinSprmLen());
902 if (bValid)
904 m_nCurrentId = mrSprmParser.GetSprmId(m_pSprms);
905 m_nCurrentSize = mrSprmParser.GetSprmSize(m_nCurrentId, m_pSprms, m_nRemLen);
906 m_pCurrentParams = m_pSprms + mrSprmParser.DistanceToData(m_nCurrentId);
907 bValid = m_nCurrentSize <= m_nRemLen;
908 SAL_WARN_IF(!bValid, "sw.ww8", "sprm longer than remaining bytes, doc or parser is wrong");
911 if (!bValid)
913 m_nCurrentId = 0;
914 m_pCurrentParams = nullptr;
915 m_nCurrentSize = 0;
916 m_nRemLen = 0;
920 SprmResult WW8SprmIter::FindSprm(sal_uInt16 nId, bool bFindFirst, const sal_uInt8* pNextByteMatch)
922 SprmResult aRet;
924 while (GetSprms())
926 if (GetCurrentId() == nId)
928 sal_Int32 nFixedLen = mrSprmParser.DistanceToData(nId);
929 sal_Int32 nL = mrSprmParser.GetSprmSize(nId, GetSprms(), GetRemLen());
930 SprmResult aSprmResult(GetCurrentParams(), nL - nFixedLen);
931 // typically pNextByteMatch is nullptr and we just return the first match
932 // very occasionally we want one with a specific following byte
933 if ( !pNextByteMatch || (aSprmResult.nRemainingData >= 1 && *aSprmResult.pSprm == *pNextByteMatch) )
935 if ( bFindFirst )
936 return aSprmResult;
937 aRet = aSprmResult;
940 advance();
943 return aRet;
946 // temporary test
947 // WW8PLCFx_PCDAttrs cling to WW8PLCF_Pcd and therefore do not have their own iterators.
948 // All methods relating to iterators are therefore dummies.
949 WW8PLCFx_PCDAttrs::WW8PLCFx_PCDAttrs(const WW8Fib& rFib,
950 WW8PLCFx_PCD* pPLCFx_PCD, const WW8ScannerBase* pBase)
951 : WW8PLCFx(rFib, true), m_pPcdI(pPLCFx_PCD->GetPLCFIter()),
952 m_pPcd(pPLCFx_PCD), mrGrpprls(pBase->m_aPieceGrpprls)
956 sal_uInt32 WW8PLCFx_PCDAttrs::GetIdx() const
958 return 0;
961 void WW8PLCFx_PCDAttrs::SetIdx(sal_uInt32)
965 bool WW8PLCFx_PCDAttrs::SeekPos(WW8_CP )
967 return true;
970 void WW8PLCFx_PCDAttrs::advance()
974 WW8_CP WW8PLCFx_PCDAttrs::Where()
976 return m_pPcd ? m_pPcd->Where() : WW8_CP_MAX;
979 void WW8PLCFx_PCDAttrs::GetSprms(WW8PLCFxDesc* p)
981 void* pData;
983 p->bRealLineEnd = false;
984 if ( !m_pPcdI || !m_pPcdI->Get(p->nStartPos, p->nEndPos, pData) )
986 // PLCF fully processed
987 p->nStartPos = p->nEndPos = WW8_CP_MAX;
988 p->pMemPos = nullptr;
989 p->nSprmsLen = 0;
990 return;
993 const sal_uInt16 nPrm = SVBT16ToUInt16( static_cast<WW8_PCD*>(pData)->prm );
994 if ( nPrm & 1 )
996 // PRM Variant 2
997 const sal_uInt16 nSprmIdx = nPrm >> 1;
999 if( nSprmIdx >= mrGrpprls.size() )
1001 // Invalid Index
1002 p->nStartPos = p->nEndPos = WW8_CP_MAX;
1003 p->pMemPos = nullptr;
1004 p->nSprmsLen = 0;
1005 return;
1007 const sal_uInt8* pSprms = mrGrpprls[ nSprmIdx ].get();
1009 p->nSprmsLen = SVBT16ToUInt16( pSprms ); // Length
1010 pSprms += 2;
1011 p->pMemPos = pSprms; // Position
1013 else
1015 // SPRM is stored directly into members var
1017 These are the attr that are in the piece-table instead of in the text!
1020 if (IsSevenMinus(GetFIBVersion()))
1022 m_aShortSprm[0] = static_cast<sal_uInt8>( ( nPrm & 0xfe) >> 1 );
1023 m_aShortSprm[1] = static_cast<sal_uInt8>( nPrm >> 8 );
1024 p->nSprmsLen = nPrm ? 2 : 0; // length
1026 // store Position of internal mini storage in Data Pointer
1027 p->pMemPos = m_aShortSprm;
1029 else
1031 p->pMemPos = nullptr;
1032 p->nSprmsLen = 0;
1033 sal_uInt8 nSprmListIdx = static_cast<sal_uInt8>((nPrm & 0xfe) >> 1);
1034 if( nSprmListIdx )
1036 // process Sprm Id Matching as explained in MS Documentation
1038 // ''Property Modifier(variant 1) (PRM)''
1039 // see file: s62f39.htm
1041 // Since Sprm is 7 bits, rgsprmPrm can hold 0x80 entries.
1042 static const sal_uInt16 aSprmId[0x80] =
1044 // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1045 0x0000,0x0000,0x0000,0x0000,
1046 // sprmPIncLvl, sprmPJc, sprmPFSideBySide, sprmPFKeep
1047 0x2402,0x2403,NS_sprm::LN_PFSideBySide,0x2405,
1048 // sprmPFKeepFollow, sprmPFPageBreakBefore, sprmPBrcl,
1049 // sprmPBrcp
1050 0x2406,0x2407,NS_sprm::LN_PBrcl,NS_sprm::LN_PBrcp,
1051 // sprmPIlvl, sprmNoop, sprmPFNoLineNumb, sprmNoop
1052 0x260A,0x0000,0x240C,0x0000,
1053 // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1054 0x0000,0x0000,0x0000,0x0000,
1055 // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1056 0x0000,0x0000,0x0000,0x0000,
1057 // sprmPFInTable, sprmPFTtp, sprmNoop, sprmNoop
1058 0x2416,0x2417,0x0000,0x0000,
1059 // sprmNoop, sprmPPc, sprmNoop, sprmNoop
1060 0x0000,0x261B,0x0000,0x0000,
1061 // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1062 0x0000,0x0000,0x0000,0x0000,
1063 // sprmNoop, sprmPWr, sprmNoop, sprmNoop
1064 0x0000,0x2423,0x0000,0x0000,
1065 // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1066 0x0000,0x0000,0x0000,0x0000,
1067 // sprmPFNoAutoHyph, sprmNoop, sprmNoop, sprmNoop
1068 0x242A,0x0000,0x0000,0x0000,
1069 // sprmNoop, sprmNoop, sprmPFLocked, sprmPFWidowControl
1070 0x0000,0x0000,0x2430,0x2431,
1071 // sprmNoop, sprmPFKinsoku, sprmPFWordWrap,
1072 // sprmPFOverflowPunct
1073 0x0000,0x2433,0x2434,0x2435,
1074 // sprmPFTopLinePunct, sprmPFAutoSpaceDE,
1075 // sprmPFAutoSpaceDN, sprmNoop
1076 0x2436,0x2437,0x2438,0x0000,
1077 // sprmNoop, sprmPISnapBaseLine, sprmNoop, sprmNoop
1078 0x0000,NS_sprm::LN_PISnapBaseLine,0x000,0x0000,
1079 // sprmNoop, sprmCFStrikeRM, sprmCFRMark, sprmCFFieldVanish
1080 0x0000,0x0800,0x0801,0x0802,
1081 // sprmNoop, sprmNoop, sprmNoop, sprmCFData
1082 0x0000,0x0000,0x0000,0x0806,
1083 // sprmNoop, sprmNoop, sprmNoop, sprmCFOle2
1084 0x0000,0x0000,0x0000,0x080A,
1085 // sprmNoop, sprmCHighlight, sprmCFEmboss, sprmCSfxText
1086 0x0000,0x2A0C,0x0858,0x2859,
1087 // sprmNoop, sprmNoop, sprmNoop, sprmCPlain
1088 0x0000,0x0000,0x0000,0x2A33,
1089 // sprmNoop, sprmCFBold, sprmCFItalic, sprmCFStrike
1090 0x0000,0x0835,0x0836,0x0837,
1091 // sprmCFOutline, sprmCFShadow, sprmCFSmallCaps, sprmCFCaps,
1092 0x0838,0x0839,0x083a,0x083b,
1093 // sprmCFVanish, sprmNoop, sprmCKul, sprmNoop,
1094 0x083C,0x0000,0x2A3E,0x0000,
1095 // sprmNoop, sprmNoop, sprmCIco, sprmNoop,
1096 0x0000,0x0000,0x2A42,0x0000,
1097 // sprmCHpsInc, sprmNoop, sprmCHpsPosAdj, sprmNoop,
1098 NS_sprm::LN_CHpsInc,0x0000,NS_sprm::LN_CHpsPosAdj,0x0000,
1099 // sprmCIss, sprmNoop, sprmNoop, sprmNoop,
1100 0x2A48,0x0000,0x0000,0x0000,
1101 // sprmNoop, sprmNoop, sprmNoop, sprmNoop,
1102 0x0000,0x0000,0x0000,0x0000,
1103 // sprmNoop, sprmNoop, sprmNoop, sprmCFDStrike,
1104 0x0000,0x0000,0x0000,0x2A53,
1105 // sprmCFImprint, sprmCFSpec, sprmCFObj, sprmPicBrcl,
1106 0x0854,0x0855,0x0856,NS_sprm::LN_PicBrcl,
1107 // sprmPOutLvl, sprmPFBiDi, sprmNoop, sprmNoop,
1108 0x2640,0x2441,0x0000,0x0000,
1109 // sprmNoop, sprmNoop, sprmPPnbrRMarkNot
1110 0x0000,0x0000,0x0000,0x0000
1113 // find real Sprm Id:
1114 const sal_uInt16 nSprmId = aSprmId[ nSprmListIdx ];
1116 if( nSprmId )
1118 // move Sprm Id and Sprm Param to internal mini storage:
1119 m_aShortSprm[0] = static_cast<sal_uInt8>( nSprmId & 0x00ff) ;
1120 m_aShortSprm[1] = static_cast<sal_uInt8>( ( nSprmId & 0xff00) >> 8 );
1121 m_aShortSprm[2] = static_cast<sal_uInt8>( nPrm >> 8 );
1123 // store Sprm Length in member:
1124 p->nSprmsLen = nPrm ? 3 : 0;
1126 // store Position of internal mini storage in Data Pointer
1127 p->pMemPos = m_aShortSprm;
1134 WW8PLCFx_PCD::WW8PLCFx_PCD(const WW8Fib& rFib, WW8PLCFpcd* pPLCFpcd,
1135 WW8_CP nStartCp, bool bVer67P)
1136 : WW8PLCFx(rFib, false), m_nClipStart(-1)
1138 // construct own iterator
1139 m_pPcdI.reset( new WW8PLCFpcd_Iter(*pPLCFpcd, nStartCp) );
1140 m_bVer67= bVer67P;
1143 WW8PLCFx_PCD::~WW8PLCFx_PCD()
1147 sal_uInt32 WW8PLCFx_PCD::GetIMax() const
1149 return m_pPcdI ? m_pPcdI->GetIMax() : 0;
1152 sal_uInt32 WW8PLCFx_PCD::GetIdx() const
1154 return m_pPcdI ? m_pPcdI->GetIdx() : 0;
1157 void WW8PLCFx_PCD::SetIdx(sal_uInt32 nIdx)
1159 if (m_pPcdI)
1160 m_pPcdI->SetIdx( nIdx );
1163 bool WW8PLCFx_PCD::SeekPos(WW8_CP nCpPos)
1165 return m_pPcdI && m_pPcdI->SeekPos( nCpPos );
1168 WW8_CP WW8PLCFx_PCD::Where()
1170 return m_pPcdI ? m_pPcdI->Where() : WW8_CP_MAX;
1173 tools::Long WW8PLCFx_PCD::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
1175 void* pData;
1176 rLen = 0;
1178 if ( !m_pPcdI || !m_pPcdI->Get(rStart, rEnd, pData) )
1180 rStart = rEnd = WW8_CP_MAX;
1181 return -1;
1183 return m_pPcdI->GetIdx();
1186 void WW8PLCFx_PCD::advance()
1188 OSL_ENSURE(m_pPcdI , "missing pPcdI");
1189 if (m_pPcdI)
1190 m_pPcdI->advance();
1193 WW8_FC WW8PLCFx_PCD::CurrentPieceStartCp2Fc( WW8_CP nCp )
1195 WW8_CP nCpStart, nCpEnd;
1196 void* pData;
1198 if ( !m_pPcdI->Get(nCpStart, nCpEnd, pData) )
1200 OSL_ENSURE( false, "CurrentPieceStartCp2Fc() with false Cp found (1)" );
1201 return WW8_FC_MAX;
1204 OSL_ENSURE( nCp >= nCpStart && nCp < nCpEnd,
1205 "AktPieceCp2Fc() with false Cp found (2)" );
1207 if( nCp < nCpStart )
1208 nCp = nCpStart;
1209 if( nCp >= nCpEnd )
1210 nCp = nCpEnd - 1;
1212 bool bIsUnicode = false;
1213 WW8_FC nFC = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
1214 if( !m_bVer67 )
1215 nFC = WW8PLCFx_PCD::TransformPieceAddress( nFC, bIsUnicode );
1217 WW8_CP nDistance;
1218 bool bFail = o3tl::checked_sub(nCp, nCpStart, nDistance);
1219 if (bFail)
1221 SAL_WARN("sw.ww8", "broken offset, ignoring");
1222 return WW8_FC_MAX;
1225 if (bIsUnicode)
1227 bFail = o3tl::checked_multiply<WW8_CP>(nDistance, 2, nDistance);
1228 if (bFail)
1230 SAL_WARN("sw.ww8", "broken offset, ignoring");
1231 return WW8_FC_MAX;
1235 WW8_FC nRet;
1236 bFail = o3tl::checked_add(nFC, nDistance, nRet);
1237 if (bFail)
1239 SAL_WARN("sw.ww8", "broken offset, ignoring");
1240 return WW8_FC_MAX;
1243 return nRet;
1246 void WW8PLCFx_PCD::CurrentPieceFc2Cp( WW8_CP& rStartPos, WW8_CP& rEndPos,
1247 const WW8ScannerBase *pSBase )
1249 //No point going anywhere with this
1250 if ((rStartPos == WW8_CP_MAX) && (rEndPos == WW8_CP_MAX))
1251 return;
1253 rStartPos = pSBase->WW8Fc2Cp( rStartPos );
1254 rEndPos = pSBase->WW8Fc2Cp( rEndPos );
1257 WW8_CP WW8PLCFx_PCD::CurrentPieceStartFc2Cp( WW8_FC nStartPos )
1259 WW8_CP nCpStart, nCpEnd;
1260 void* pData;
1261 if ( !m_pPcdI->Get( nCpStart, nCpEnd, pData ) )
1263 OSL_ENSURE( false, "CurrentPieceStartFc2Cp() - error" );
1264 return WW8_CP_MAX;
1266 bool bIsUnicode = false;
1267 sal_Int32 nFcStart = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
1268 if( !m_bVer67 )
1269 nFcStart = WW8PLCFx_PCD::TransformPieceAddress( nFcStart, bIsUnicode );
1271 sal_Int32 nUnicodeFactor = bIsUnicode ? 2 : 1;
1273 if( nStartPos < nFcStart )
1274 nStartPos = nFcStart;
1276 WW8_CP nCpLen;
1277 bool bFail = o3tl::checked_sub(nCpEnd, nCpStart, nCpLen);
1278 if (bFail)
1280 SAL_WARN("sw.ww8", "broken offset, ignoring");
1281 return WW8_CP_MAX;
1284 WW8_CP nCpLenBytes;
1285 bFail = o3tl::checked_multiply(nCpLen, nUnicodeFactor, nCpLenBytes);
1286 if (bFail)
1288 SAL_WARN("sw.ww8", "broken offset, ignoring");
1289 return WW8_CP_MAX;
1292 WW8_FC nFcLen;
1293 bFail = o3tl::checked_add(nFcStart, nCpLenBytes, nFcLen);
1294 if (bFail)
1296 SAL_WARN("sw.ww8", "broken offset, ignoring");
1297 return WW8_CP_MAX;
1300 WW8_FC nFcEnd;
1301 bFail = o3tl::checked_add(nFcStart, nFcLen, nFcEnd);
1302 if (bFail)
1304 SAL_WARN("sw.ww8", "broken offset, ignoring");
1305 return WW8_CP_MAX;
1309 if (nStartPos >= nFcEnd)
1310 nStartPos = nFcEnd - (1 * nUnicodeFactor);
1312 WW8_FC nFcDiff = (nStartPos - nFcStart) / nUnicodeFactor;
1314 WW8_FC nCpRet;
1315 bFail = o3tl::checked_add(nCpStart, nFcDiff, nCpRet);
1316 if (bFail)
1318 SAL_WARN("sw.ww8", "broken offset, ignoring");
1319 return WW8_CP_MAX;
1322 return nCpRet;
1325 // Helper routines for all
1327 // Convert BRC from WW6 to WW8 format
1328 WW8_BRC::WW8_BRC(const WW8_BRCVer6& brcVer6)
1330 sal_uInt8 _dptLineWidth = brcVer6.dxpLineWidth(),
1331 _brcType = brcVer6.brcType();
1333 if (_dptLineWidth > 5) // this signifies dashed(6) or dotted(7) line
1335 _brcType = _dptLineWidth;
1336 _dptLineWidth = 1;
1338 _dptLineWidth *= 6; // convert units from 0.75pt to 1/8pt
1340 *this = WW8_BRC(_dptLineWidth, _brcType, brcVer6.ico(), brcVer6.dxpSpace(),
1341 brcVer6.fShadow(), false);
1344 // Convert BRC from WW8 to WW9 format
1345 WW8_BRCVer9::WW8_BRCVer9(const WW8_BRC& brcVer8)
1347 if (brcVer8.isNil()) {
1348 UInt32ToSVBT32(0, aBits1);
1349 UInt32ToSVBT32(0xffffffff, aBits2);
1351 else
1353 sal_uInt32 _cv = brcVer8.ico() == 0 ? 0xff000000 // "auto" colour
1354 : wwUtility::RGBToBGR(SwWW8ImplReader::GetCol(brcVer8.ico()));
1355 *this = WW8_BRCVer9(_cv, brcVer8.dptLineWidth(), brcVer8.brcType(),
1356 brcVer8.dptSpace(), brcVer8.fShadow(), brcVer8.fFrame());
1360 short WW8_BRC::DetermineBorderProperties(short *pSpace) const
1362 WW8_BRCVer9 brcVer9(*this);
1363 return brcVer9.DetermineBorderProperties(pSpace);
1366 short WW8_BRCVer9::DetermineBorderProperties(short *pSpace) const
1369 Word does not factor the width of the border into the width/height
1370 stored in the information for graphic/table/object widths, so we need
1371 to figure out this extra width here and utilize the returned size in
1372 our calculations
1374 short nMSTotalWidth;
1376 //Specification in 8ths of a point, 1 Point = 20 Twips, so by 2.5
1377 nMSTotalWidth = static_cast<short>(dptLineWidth()) * 20 / 8;
1379 //Figure out the real size of the border according to word
1380 switch (brcType())
1382 //Note that codes over 25 are undocumented, and I can't create
1383 //these 4 here in the wild.
1384 case 2:
1385 case 4:
1386 case 5:
1387 case 22:
1388 OSL_FAIL("Can't create these from the menus, please report");
1389 break;
1390 default:
1391 case 23: //Only 3pt in the menus, but honours the size setting.
1392 break;
1393 case 10:
1395 triple line is five times the width of an ordinary line,
1396 except that the smallest 1/4 point size appears to have
1397 exactly the same total border width as a 3/4 point size
1398 ordinary line, i.e. three times the nominal line width. The
1399 second smallest 1/2 point size appears to have exactly the
1400 total border width as a 2 1/4 border, i.e 4.5 times the size.
1402 if (nMSTotalWidth == 5)
1403 nMSTotalWidth*=3;
1404 else if (nMSTotalWidth == 10)
1405 nMSTotalWidth = nMSTotalWidth*9/2;
1406 else
1407 nMSTotalWidth*=5;
1408 break;
1409 case 20:
1411 wave, the dimensions appear to be created by the drawing of
1412 the wave, so we have only two possibilities in the menus, 3/4
1413 point is equal to solid 3 point. This calculation seems to
1414 match well to results.
1416 nMSTotalWidth +=45;
1417 break;
1418 case 21:
1420 double wave, the dimensions appear to be created by the
1421 drawing of the wave, so we have only one possibilities in the
1422 menus, that of 3/4 point is equal to solid 3 point. This
1423 calculation seems to match well to results.
1425 nMSTotalWidth += 45*2;
1426 break;
1429 if (pSpace)
1430 *pSpace = static_cast<short>(dptSpace()) * 20; // convert from points to twips
1431 return nMSTotalWidth;
1435 * WW8Cp2Fc is a good method, a CP always maps to a FC
1436 * WW8Fc2Cp on the other hand is more dubious, a random FC
1437 * may not map to a valid CP. Try and avoid WW8Fc2Cp where
1438 * possible
1440 WW8_CP WW8ScannerBase::WW8Fc2Cp( WW8_FC nFcPos ) const
1442 WW8_CP nFallBackCpEnd = WW8_CP_MAX;
1443 if( nFcPos == WW8_FC_MAX )
1444 return nFallBackCpEnd;
1446 bool bIsUnicode;
1447 if (m_pWw8Fib->m_nVersion >= 8)
1448 bIsUnicode = false;
1449 else
1450 bIsUnicode = m_pWw8Fib->m_fExtChar;
1452 if( m_pPieceIter ) // Complex File ?
1454 sal_uInt32 nOldPos = m_pPieceIter->GetIdx();
1456 for (m_pPieceIter->SetIdx(0);
1457 m_pPieceIter->GetIdx() < m_pPieceIter->GetIMax(); m_pPieceIter->advance())
1459 WW8_CP nCpStart, nCpEnd;
1460 void* pData;
1461 if( !m_pPieceIter->Get( nCpStart, nCpEnd, pData ) )
1462 { // outside PLCFfpcd ?
1463 OSL_ENSURE( false, "PLCFpcd-WW8Fc2Cp() went wrong" );
1464 break;
1466 sal_Int32 nFcStart = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
1467 if (m_pWw8Fib->m_nVersion >= 8)
1469 nFcStart = WW8PLCFx_PCD::TransformPieceAddress( nFcStart,
1470 bIsUnicode );
1472 else
1474 bIsUnicode = m_pWw8Fib->m_fExtChar;
1477 sal_Int32 nLen;
1478 if (o3tl::checked_sub(nCpEnd, nCpStart, nLen))
1480 SAL_WARN("sw.ww8", "broken offset, ignoring");
1481 return WW8_CP_MAX;
1483 if (bIsUnicode)
1485 if (o3tl::checked_multiply<WW8_CP>(nLen, 2, nLen))
1487 SAL_WARN("sw.ww8", "broken offset, ignoring");
1488 return WW8_CP_MAX;
1493 If this cp is inside this piece, or it's the last piece and we are
1494 on the very last cp of that piece
1496 if (nFcPos >= nFcStart)
1498 // found
1499 WW8_FC nFcDiff;
1500 if (o3tl::checked_sub(nFcPos, nFcStart, nFcDiff))
1502 SAL_WARN("sw.ww8", "broken offset, ignoring");
1503 return WW8_CP_MAX;
1505 if (bIsUnicode)
1506 nFcDiff /= 2;
1507 WW8_CP nTempCp;
1508 if (o3tl::checked_add(nCpStart, nFcDiff, nTempCp))
1510 SAL_WARN("sw.ww8", "broken offset, ignoring");
1511 return WW8_CP_MAX;
1513 WW8_FC nFcEnd;
1514 if (o3tl::checked_add(nFcStart, nLen, nFcEnd))
1516 SAL_WARN("sw.ww8", "broken offset, ignoring");
1517 return WW8_CP_MAX;
1519 if (nFcPos < nFcEnd)
1521 m_pPieceIter->SetIdx( nOldPos );
1522 return nTempCp;
1524 else if (nFcPos == nFcEnd)
1526 //Keep this cp as its on a piece boundary because we might
1527 //need it if tests fail
1528 nFallBackCpEnd = nTempCp;
1532 // not found
1533 m_pPieceIter->SetIdx( nOldPos ); // not found
1535 If it was not found, then this is because it has fallen between two
1536 stools, i.e. either it is the last cp/fc of the last piece, or it is
1537 the last cp/fc of a disjoint piece.
1539 return nFallBackCpEnd;
1542 WW8_FC nFcDiff;
1543 if (o3tl::checked_sub(nFcPos, m_pWw8Fib->m_fcMin, nFcDiff))
1545 SAL_WARN("sw.ww8", "broken offset, ignoring");
1546 return WW8_CP_MAX;
1549 // No complex file
1550 if (!bIsUnicode)
1551 nFallBackCpEnd = nFcDiff;
1552 else
1553 nFallBackCpEnd = (nFcDiff + 1) / 2;
1555 return nFallBackCpEnd;
1558 // the fib of WinWord2 has a last entry of cpnBtePap of 2 byte sized type PN at
1559 // offset 324
1560 const int nSmallestPossibleFib = 326;
1562 WW8_FC WW8ScannerBase::WW8Cp2Fc(WW8_CP nCpPos, bool* pIsUnicode,
1563 WW8_CP* pNextPieceCp, bool* pTestFlag) const
1565 if( pTestFlag )
1566 *pTestFlag = true;
1567 if( WW8_CP_MAX == nCpPos )
1568 return WW8_CP_MAX;
1570 bool bIsUnicode;
1571 if( !pIsUnicode )
1572 pIsUnicode = &bIsUnicode;
1574 if (m_pWw8Fib->m_nVersion >= 8)
1575 *pIsUnicode = false;
1576 else
1577 *pIsUnicode = m_pWw8Fib->m_fExtChar;
1579 WW8_FC nRet;
1581 if( m_pPieceIter )
1583 // Complex File
1584 if( pNextPieceCp )
1585 *pNextPieceCp = WW8_CP_MAX;
1587 if( !m_pPieceIter->SeekPos( nCpPos ) )
1589 if( pTestFlag )
1590 *pTestFlag = false;
1591 else {
1592 OSL_ENSURE( false, "Handed over wrong CP to WW8Cp2Fc()" );
1594 return WW8_FC_MAX;
1596 WW8_CP nCpStart, nCpEnd;
1597 void* pData;
1598 if( !m_pPieceIter->Get( nCpStart, nCpEnd, pData ) )
1600 if( pTestFlag )
1601 *pTestFlag = false;
1602 else {
1603 OSL_ENSURE( false, "PLCFfpcd-Get went wrong" );
1605 return WW8_FC_MAX;
1607 if( pNextPieceCp )
1608 *pNextPieceCp = nCpEnd;
1610 nRet = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
1611 if (m_pWw8Fib->m_nVersion >= 8)
1612 nRet = WW8PLCFx_PCD::TransformPieceAddress( nRet, *pIsUnicode );
1613 else
1614 *pIsUnicode = m_pWw8Fib->m_fExtChar;
1616 WW8_CP nCpLen;
1617 bool bFail = o3tl::checked_sub(nCpPos, nCpStart, nCpLen);
1618 if (bFail)
1620 SAL_WARN("sw.ww8", "broken offset, ignoring");
1621 return WW8_CP_MAX;
1624 if (*pIsUnicode)
1626 bFail = o3tl::checked_multiply<WW8_CP>(nCpLen, 2, nCpLen);
1627 if (bFail)
1629 SAL_WARN("sw.ww8", "broken offset, ignoring");
1630 return WW8_CP_MAX;
1634 bFail = o3tl::checked_add(nRet, nCpLen, nRet);
1635 if (bFail)
1637 SAL_WARN("sw.ww8", "broken offset, ignoring");
1638 return WW8_CP_MAX;
1641 return nRet;
1644 if (*pIsUnicode)
1646 const bool bFail = o3tl::checked_multiply<WW8_CP>(nCpPos, 2, nCpPos);
1647 if (bFail)
1649 SAL_WARN("sw.ww8", "broken offset, ignoring");
1650 return WW8_CP_MAX;
1654 // No complex file
1655 const bool bFail = o3tl::checked_add(m_pWw8Fib->m_fcMin, nCpPos, nRet);
1656 if (bFail)
1658 SAL_WARN("sw.ww8", "broken offset, ignoring");
1659 return WW8_CP_MAX;
1662 // the text and the fib share the same stream, if the text is inside the fib
1663 // then it's definitely a bad offset. The smallest FIB supported is that of
1664 // WW2 which is 326 bytes in size
1665 if (nRet < nSmallestPossibleFib)
1667 SAL_WARN("sw.ww8", "broken offset, ignoring");
1668 return WW8_CP_MAX;
1671 return nRet;
1674 std::unique_ptr<WW8PLCFpcd> WW8ScannerBase::OpenPieceTable( SvStream* pStr, const WW8Fib* pWwF )
1676 if ( ((8 > m_pWw8Fib->m_nVersion) && !pWwF->m_fComplex) || !pWwF->m_lcbClx )
1677 return nullptr;
1679 if (pWwF->m_lcbClx < 0)
1680 return nullptr;
1682 WW8_FC nClxPos = pWwF->m_fcClx;
1684 if (!checkSeek(*pStr, nClxPos))
1685 return nullptr;
1687 sal_Int32 nClxLen = pWwF->m_lcbClx;
1688 sal_Int32 nLeft = nClxLen;
1690 while (true)
1692 sal_uInt8 clxt(2);
1693 pStr->ReadUChar( clxt );
1694 nLeft--;
1695 if( 2 == clxt) // PLCFfpcd ?
1696 break; // PLCFfpcd found
1697 sal_uInt16 nLen(0);
1698 pStr->ReadUInt16( nLen );
1699 nLeft -= 2 + nLen;
1700 if( nLeft < 0 )
1701 return nullptr; // gone wrong
1702 if( 1 == clxt ) // clxtGrpprl ?
1704 if (m_aPieceGrpprls.size() == SHRT_MAX)
1705 return nullptr;
1706 if (nLen > pStr->remainingSize())
1707 return nullptr;
1708 std::unique_ptr<sal_uInt8[]> p(new sal_uInt8[nLen+2]); // allocate
1709 ShortToSVBT16(nLen, p.get()); // add length
1710 if (!checkRead(*pStr, p.get()+2, nLen)) // read grpprl
1712 return nullptr;
1714 m_aPieceGrpprls.push_back(std::move(p)); // add to array
1716 else
1718 nLen = std::min<sal_uInt64>(nLen, pStr->remainingSize());
1719 pStr->Seek(pStr->Tell() + nLen); // non-Grpprl left
1723 // read Piece Table PLCF
1724 sal_Int32 nPLCFfLen(0);
1725 if (pWwF->GetFIBVersion() <= ww::eWW2)
1727 sal_Int16 nWordTwoLen(0);
1728 pStr->ReadInt16( nWordTwoLen );
1729 nPLCFfLen = nWordTwoLen;
1731 else
1732 pStr->ReadInt32( nPLCFfLen );
1733 OSL_ENSURE( 65536 > nPLCFfLen, "PLCFfpcd above 64 k" );
1734 return std::make_unique<WW8PLCFpcd>( pStr, pStr->Tell(), nPLCFfLen, 8 );
1737 WW8ScannerBase::WW8ScannerBase( SvStream* pSt, SvStream* pTableSt,
1738 SvStream* pDataSt, WW8Fib* pWwFib )
1739 : m_pWw8Fib(pWwFib)
1741 m_pPiecePLCF = OpenPieceTable( pTableSt, m_pWw8Fib ); // Complex
1742 if( m_pPiecePLCF )
1744 m_pPieceIter.reset(new WW8PLCFpcd_Iter( *m_pPiecePLCF ));
1745 m_pPLCFx_PCD.reset( new WW8PLCFx_PCD(*pWwFib, m_pPiecePLCF.get(), 0,
1746 IsSevenMinus(m_pWw8Fib->GetFIBVersion())));
1747 m_pPLCFx_PCDAttrs.reset(new WW8PLCFx_PCDAttrs(*pWwFib,
1748 m_pPLCFx_PCD.get(), this));
1750 else
1752 m_pPieceIter = nullptr;
1753 m_pPLCFx_PCD = nullptr;
1754 m_pPLCFx_PCDAttrs = nullptr;
1757 // pChpPLCF and pPapPLCF may NOT be created before pPLCFx_PCD !!
1758 m_pChpPLCF.reset(new WW8PLCFx_Cp_FKP( pSt, pTableSt, pDataSt, *this, CHP )); // CHPX
1759 m_pPapPLCF.reset(new WW8PLCFx_Cp_FKP( pSt, pTableSt, pDataSt, *this, PAP )); // PAPX
1761 m_pSepPLCF.reset(new WW8PLCFx_SEPX( pSt, pTableSt, *pWwFib, 0 )); // SEPX
1763 // Footnotes
1764 m_pFootnotePLCF.reset(new WW8PLCFx_SubDoc( pTableSt, *pWwFib, 0,
1765 pWwFib->m_fcPlcffndRef, pWwFib->m_lcbPlcffndRef, pWwFib->m_fcPlcffndText,
1766 pWwFib->m_lcbPlcffndText, 2 ));
1767 // Endnotes
1768 m_pEdnPLCF.reset(new WW8PLCFx_SubDoc( pTableSt, *pWwFib, 0,
1769 pWwFib->m_fcPlcfendRef, pWwFib->m_lcbPlcfendRef, pWwFib->m_fcPlcfendText,
1770 pWwFib->m_lcbPlcfendText, 2 ));
1771 // Comments
1772 m_pAndPLCF.reset(new WW8PLCFx_SubDoc( pTableSt, *pWwFib, 0,
1773 pWwFib->m_fcPlcfandRef, pWwFib->m_lcbPlcfandRef, pWwFib->m_fcPlcfandText,
1774 pWwFib->m_lcbPlcfandText, IsSevenMinus(pWwFib->GetFIBVersion()) ? 20 : 30));
1776 // Fields Main Text
1777 m_pFieldPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_MAINTEXT));
1778 // Fields Header / Footer
1779 m_pFieldHdFtPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_HDFT));
1780 // Fields Footnote
1781 m_pFieldFootnotePLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_FTN));
1782 // Fields Endnote
1783 m_pFieldEdnPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_EDN));
1784 // Fields Comments
1785 m_pFieldAndPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_AND));
1786 // Fields in Textboxes in Main Text
1787 m_pFieldTxbxPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_TXBX));
1788 // Fields in Textboxes in Header / Footer
1789 m_pFieldTxbxHdFtPLCF.reset(new WW8PLCFx_FLD(pTableSt,*pWwFib,MAN_TXBX_HDFT));
1791 // Note: 6 stands for "6 OR 7", 7 stands for "ONLY 7"
1792 switch( m_pWw8Fib->m_nVersion )
1794 case 6:
1795 case 7:
1796 if( pWwFib->m_fcPlcfdoaMom && pWwFib->m_lcbPlcfdoaMom )
1798 m_pMainFdoa.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfdoaMom,
1799 pWwFib->m_lcbPlcfdoaMom, 6 ));
1801 if( pWwFib->m_fcPlcfdoaHdr && pWwFib->m_lcbPlcfdoaHdr )
1803 m_pHdFtFdoa.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfdoaHdr,
1804 pWwFib->m_lcbPlcfdoaHdr, 6 ));
1806 break;
1807 case 8:
1808 if( pWwFib->m_fcPlcfspaMom && pWwFib->m_lcbPlcfspaMom )
1810 m_pMainFdoa.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfspaMom,
1811 pWwFib->m_lcbPlcfspaMom, 26 ));
1813 if( pWwFib->m_fcPlcfspaHdr && pWwFib->m_lcbPlcfspaHdr )
1815 m_pHdFtFdoa.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfspaHdr,
1816 pWwFib->m_lcbPlcfspaHdr, 26 ));
1818 // PLCF for TextBox break-descriptors in the main text
1819 if( pWwFib->m_fcPlcftxbxBkd && pWwFib->m_lcbPlcftxbxBkd )
1821 m_pMainTxbxBkd.reset(new WW8PLCFspecial( pTableSt,
1822 pWwFib->m_fcPlcftxbxBkd, pWwFib->m_lcbPlcftxbxBkd, 0));
1824 // PLCF for TextBox break-descriptors in Header/Footer range
1825 if( pWwFib->m_fcPlcfHdrtxbxBkd && pWwFib->m_lcbPlcfHdrtxbxBkd )
1827 m_pHdFtTxbxBkd.reset(new WW8PLCFspecial( pTableSt,
1828 pWwFib->m_fcPlcfHdrtxbxBkd, pWwFib->m_lcbPlcfHdrtxbxBkd, 0));
1830 // Sub table cp positions
1831 if (pWwFib->m_fcPlcfTch && pWwFib->m_lcbPlcfTch)
1833 m_pMagicTables.reset(new WW8PLCFspecial( pTableSt,
1834 pWwFib->m_fcPlcfTch, pWwFib->m_lcbPlcfTch, 4));
1836 // Sub document cp positions
1837 if (pWwFib->m_fcPlcfwkb && pWwFib->m_lcbPlcfwkb)
1839 m_pSubdocs.reset(new WW8PLCFspecial( pTableSt,
1840 pWwFib->m_fcPlcfwkb, pWwFib->m_lcbPlcfwkb, 12));
1842 // Extended ATRD
1843 if (pWwFib->m_fcAtrdExtra && pWwFib->m_lcbAtrdExtra)
1845 sal_uInt64 const nOldPos = pTableSt->Tell();
1846 if (checkSeek(*pTableSt, pWwFib->m_fcAtrdExtra) && (pTableSt->remainingSize() >= pWwFib->m_lcbAtrdExtra))
1848 m_pExtendedAtrds.reset( new sal_uInt8[pWwFib->m_lcbAtrdExtra] );
1849 pWwFib->m_lcbAtrdExtra = pTableSt->ReadBytes(m_pExtendedAtrds.get(), pWwFib->m_lcbAtrdExtra);
1851 else
1852 pWwFib->m_lcbAtrdExtra = 0;
1853 pTableSt->Seek(nOldPos);
1856 break;
1857 default:
1858 OSL_ENSURE( false, "nVersion not implemented!" );
1859 break;
1862 // PLCF for TextBox stories in main text
1863 sal_uInt32 nLenTxBxS = (8 > m_pWw8Fib->m_nVersion) ? 0 : 22;
1864 if( pWwFib->m_fcPlcftxbxText && pWwFib->m_lcbPlcftxbxText )
1866 m_pMainTxbx.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcftxbxText,
1867 pWwFib->m_lcbPlcftxbxText, nLenTxBxS ));
1870 // PLCF for TextBox stories in Header/Footer range
1871 if( pWwFib->m_fcPlcfHdrtxbxText && pWwFib->m_lcbPlcfHdrtxbxText )
1873 m_pHdFtTxbx.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfHdrtxbxText,
1874 pWwFib->m_lcbPlcfHdrtxbxText, nLenTxBxS ));
1877 m_pBook.reset(new WW8PLCFx_Book(pTableSt, *pWwFib));
1878 m_pAtnBook.reset(new WW8PLCFx_AtnBook(pTableSt, *pWwFib));
1879 m_pFactoidBook.reset(new WW8PLCFx_FactoidBook(pTableSt, *pWwFib));
1882 WW8ScannerBase::~WW8ScannerBase()
1884 m_aPieceGrpprls.clear();
1885 m_pPLCFx_PCDAttrs.reset();
1886 m_pPLCFx_PCD.reset();
1887 m_pPieceIter.reset();
1888 m_pPiecePLCF.reset();
1889 m_pFactoidBook.reset();
1890 m_pAtnBook.reset();
1891 m_pBook.reset();
1892 m_pFieldEdnPLCF.reset();
1893 m_pFieldFootnotePLCF.reset();
1894 m_pFieldAndPLCF.reset();
1895 m_pFieldHdFtPLCF.reset();
1896 m_pFieldPLCF.reset();
1897 m_pFieldTxbxPLCF.reset();
1898 m_pFieldTxbxHdFtPLCF.reset();
1899 m_pEdnPLCF.reset();
1900 m_pFootnotePLCF.reset();
1901 m_pAndPLCF.reset();
1902 m_pSepPLCF.reset();
1903 m_pPapPLCF.reset();
1904 m_pChpPLCF.reset();
1905 m_pMainFdoa.reset();
1906 m_pHdFtFdoa.reset();
1907 m_pMainTxbx.reset();
1908 m_pMainTxbxBkd.reset();
1909 m_pHdFtTxbx.reset();
1910 m_pHdFtTxbxBkd.reset();
1911 m_pMagicTables.reset();
1912 m_pSubdocs.reset();
1915 // Fields
1917 static bool WW8SkipField(WW8PLCFspecial& rPLCF)
1919 void* pData;
1920 WW8_CP nP;
1922 if (!rPLCF.Get(nP, pData)) // End of PLCFspecial?
1923 return false;
1925 rPLCF.advance();
1927 if((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) != 0x13 ) // No beginning?
1928 return true; // Do not terminate on error
1930 if( !rPLCF.Get( nP, pData ) )
1931 return false;
1933 while((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x13 )
1935 // still new (nested) beginnings ?
1936 WW8SkipField( rPLCF ); // nested Field in description
1937 if( !rPLCF.Get( nP, pData ) )
1938 return false;
1941 if((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x14 )
1944 // Field Separator ?
1945 rPLCF.advance();
1947 if( !rPLCF.Get( nP, pData ) )
1948 return false;
1950 while ((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x13)
1952 // still new (nested) beginnings?
1953 WW8SkipField( rPLCF ); // nested Field in Results
1954 if( !rPLCF.Get( nP, pData ) )
1955 return false;
1958 rPLCF.advance();
1960 return true;
1963 static bool WW8GetFieldPara(WW8PLCFspecial& rPLCF, WW8FieldDesc& rF)
1965 void* pData;
1966 sal_uInt32 nOldIdx = rPLCF.GetIdx();
1968 rF.nLen = rF.nId = rF.nOpt = 0;
1969 rF.bCodeNest = rF.bResNest = false;
1971 if (!rPLCF.Get(rF.nSCode, pData) || rF.nSCode < 0) // end of PLCFspecial?
1972 goto Err;
1974 rPLCF.advance();
1976 if (!pData || (static_cast<sal_uInt8*>(pData)[0] & 0x1f) != 0x13) // No beginning?
1977 goto Err;
1979 rF.nId = static_cast<sal_uInt8*>(pData)[1];
1981 if( !rPLCF.Get( rF.nLCode, pData ) )
1982 goto Err;
1984 if (rF.nLCode < rF.nSCode)
1985 goto Err;
1987 rF.nSRes = rF.nLCode; // Default
1988 rF.nSCode++; // without markers
1989 rF.nLCode -= rF.nSCode; // Pos -> length
1991 while((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x13 )
1993 // still new (nested) beginnings ?
1994 WW8SkipField( rPLCF ); // nested Field in description
1995 rF.bCodeNest = true;
1996 if (!rPLCF.Get(rF.nSRes, pData) || rF.nSRes < 0)
1997 goto Err;
2000 if ((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x14 ) // Field Separator?
2002 rPLCF.advance();
2004 if (!rPLCF.Get(rF.nLRes, pData) || rF.nLRes < 0)
2005 goto Err;
2007 while((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x13 )
2009 // still new (nested) beginnings ?
2010 WW8SkipField( rPLCF ); // nested Field in results
2011 rF.bResNest = true;
2012 if (!rPLCF.Get(rF.nLRes, pData) || rF.nLRes < 0)
2013 goto Err;
2015 WW8_CP nTmp;
2016 if (o3tl::checked_sub<WW8_CP>(rF.nLRes, rF.nSCode, nTmp))
2018 rF.nLen = 0;
2019 goto Err;
2021 if (o3tl::checked_add<WW8_CP>(nTmp, 2, rF.nLen)) // nLRes is still the final position
2023 rF.nLen = 0;
2024 goto Err;
2026 rF.nLRes -= rF.nSRes; // now: nLRes = length
2027 if (o3tl::checked_add<WW8_CP>(rF.nSRes, 1, rF.nSRes)) // Endpos including Markers
2029 rF.nLen = 0;
2030 goto Err;
2032 rF.nLRes--;
2033 }else{
2034 rF.nLRes = 0; // no result found
2035 WW8_CP nTmp;
2036 if (o3tl::checked_sub<WW8_CP>(rF.nSRes, rF.nSCode, nTmp))
2038 rF.nLen = 0;
2039 goto Err;
2041 if (o3tl::checked_add<WW8_CP>(nTmp, 2, rF.nLen)) // total length
2043 rF.nLen = 0;
2044 goto Err;
2048 if (rF.nLen < 0)
2050 rF.nLen = 0;
2051 goto Err;
2054 rPLCF.advance();
2055 if((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x15 )
2057 // Field end ?
2058 // INDEX-Field has set Bit7?
2059 rF.nOpt = static_cast<sal_uInt8*>(pData)[1]; // yes -> copy flags
2060 }else{
2061 rF.nId = 0; // no -> Field invalid
2064 rPLCF.SetIdx( nOldIdx );
2065 return true;
2066 Err:
2067 rPLCF.SetIdx( nOldIdx );
2068 return false;
2071 OUString read_uInt8_BeltAndBracesString(SvStream& rStrm, rtl_TextEncoding eEnc)
2073 const OUString aRet = read_uInt8_lenPrefixed_uInt8s_ToOUString(rStrm, eEnc);
2074 rStrm.SeekRel(sizeof(sal_uInt8)); // skip null-byte at end
2075 return aRet;
2078 OUString read_uInt16_BeltAndBracesString(SvStream& rStrm)
2080 const OUString aRet = read_uInt16_PascalString(rStrm);
2081 rStrm.SeekRel(sizeof(sal_Unicode)); // skip null-byte at end
2082 return aRet;
2085 sal_Int32 WW8ScannerBase::WW8ReadString( SvStream& rStrm, OUString& rStr,
2086 WW8_CP nCurrentStartCp, tools::Long nTotalLen, rtl_TextEncoding eEnc ) const
2088 // Read in plain text, which can extend over several pieces
2089 rStr.clear();
2091 if (nCurrentStartCp < 0 || nTotalLen < 0)
2092 return 0;
2094 WW8_CP nBehindTextCp = nCurrentStartCp + nTotalLen;
2095 WW8_CP nNextPieceCp = nBehindTextCp; // Initialization, important for Ver6
2096 tools::Long nTotalRead = 0;
2099 bool bIsUnicode(false), bPosOk(false);
2100 WW8_FC fcAct = WW8Cp2Fc(nCurrentStartCp,&bIsUnicode,&nNextPieceCp,&bPosOk);
2102 // Probably aimed beyond file end, doesn't matter!
2103 if( !bPosOk )
2104 break;
2106 bool bValid = checkSeek(rStrm, fcAct);
2107 if (!bValid)
2108 break;
2110 WW8_CP nEnd = (nNextPieceCp < nBehindTextCp) ? nNextPieceCp
2111 : nBehindTextCp;
2112 WW8_CP nLen;
2113 const bool bFail = o3tl::checked_sub(nEnd, nCurrentStartCp, nLen);
2114 if (bFail)
2115 break;
2117 if( 0 >= nLen )
2118 break;
2120 rStr += bIsUnicode
2121 ? read_uInt16s_ToOUString(rStrm, nLen)
2122 : read_uInt8s_ToOUString(rStrm, nLen, eEnc);
2124 nTotalRead += nLen;
2125 nCurrentStartCp += nLen;
2126 if ( nTotalRead != rStr.getLength() )
2127 break;
2129 while( nTotalRead < nTotalLen );
2131 return rStr.getLength();
2134 WW8PLCFspecial::WW8PLCFspecial(SvStream* pSt, sal_uInt32 nFilePos,
2135 sal_uInt32 nPLCF, sal_uInt32 nStruct)
2136 : m_nIdx(0), m_nStru(nStruct)
2138 const sal_uInt32 nValidMin=4;
2140 sal_uInt64 const nOldPos = pSt->Tell();
2142 bool bValid = checkSeek(*pSt, nFilePos);
2143 std::size_t nRemainingSize = pSt->remainingSize();
2144 if( nRemainingSize < nValidMin || nPLCF < nValidMin )
2145 bValid = false;
2146 nPLCF = bValid ? std::min(nRemainingSize, static_cast<std::size_t>(nPLCF)) : nValidMin;
2148 // Pointer to Pos- and Struct-array
2149 m_pPLCF_PosArray.reset( new sal_Int32[ ( nPLCF + 3 ) / 4 ] );
2150 m_pPLCF_PosArray[0] = 0;
2152 nPLCF = bValid ? pSt->ReadBytes(m_pPLCF_PosArray.get(), nPLCF) : nValidMin;
2154 nPLCF = std::max(nPLCF, nValidMin);
2156 m_nIMax = ( nPLCF - 4 ) / ( 4 + nStruct );
2157 #ifdef OSL_BIGENDIAN
2158 for( m_nIdx = 0; m_nIdx <= m_nIMax; m_nIdx++ )
2159 m_pPLCF_PosArray[m_nIdx] = OSL_SWAPDWORD( m_pPLCF_PosArray[m_nIdx] );
2160 m_nIdx = 0;
2161 #endif // OSL_BIGENDIAN
2162 if( nStruct ) // Pointer to content array
2163 m_pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&m_pPLCF_PosArray[m_nIMax + 1]);
2164 else
2165 m_pPLCF_Contents = nullptr; // no content
2167 pSt->Seek(nOldPos);
2170 // WW8PLCFspecial::SeekPos() sets WW8PLCFspecial to position nPos, while also the entry is used
2171 // that begins before nPos and ends after nPos.
2172 // Suitable for normal attributes. However, the beginning of the attribute is not corrected onto
2173 // the position nPos.
2174 bool WW8PLCFspecial::SeekPos(tools::Long nP)
2176 if( nP < m_pPLCF_PosArray[0] )
2178 m_nIdx = 0;
2179 return false; // Not found: nP less than smallest entry
2182 // Search from beginning?
2183 if ((m_nIdx < 1) || (nP < m_pPLCF_PosArray[m_nIdx - 1]))
2184 m_nIdx = 1;
2186 tools::Long nI = m_nIdx;
2187 tools::Long nEnd = m_nIMax;
2189 for(int n = (1==m_nIdx ? 1 : 2); n; --n )
2191 for( ; nI <=nEnd; ++nI)
2192 { // search with an index that is incremented by 1
2193 if( nP < m_pPLCF_PosArray[nI] )
2194 { // found position
2195 m_nIdx = nI - 1; // nI - 1 is the correct index
2196 return true; // done
2199 nI = 1;
2200 nEnd = m_nIdx-1;
2202 m_nIdx = m_nIMax; // not found, greater than all entries
2203 return false;
2206 // WW8PLCFspecial::SeekPosExact() like SeekPos(), but it is ensured that no attribute is cut,
2207 // i.e. the next given attribute begins at or after nPos.
2208 // Is used for fields and bookmarks.
2209 bool WW8PLCFspecial::SeekPosExact(tools::Long nP)
2211 if( nP < m_pPLCF_PosArray[0] )
2213 m_nIdx = 0;
2214 return false; // Not found: nP less than smallest entry
2216 // Search from beginning?
2217 if( nP <=m_pPLCF_PosArray[m_nIdx] )
2218 m_nIdx = 0;
2220 tools::Long nI = m_nIdx ? m_nIdx-1 : 0;
2221 tools::Long nEnd = m_nIMax;
2223 for(int n = (0==m_nIdx ? 1 : 2); n; --n )
2225 for( ; nI < nEnd; ++nI)
2227 if( nP <=m_pPLCF_PosArray[nI] )
2228 { // found position
2229 m_nIdx = nI; // nI is the correct index
2230 return true; // done
2233 nI = 0;
2234 nEnd = m_nIdx;
2236 m_nIdx = m_nIMax; // Not found, greater than all entries
2237 return false;
2240 bool WW8PLCFspecial::Get(WW8_CP& rPos, void*& rpValue) const
2242 return GetData( m_nIdx, rPos, rpValue );
2245 bool WW8PLCFspecial::GetData(tools::Long nInIdx, WW8_CP& rPos, void*& rpValue) const
2247 if ( nInIdx >= m_nIMax )
2249 rPos = WW8_CP_MAX;
2250 return false;
2252 rPos = m_pPLCF_PosArray[nInIdx];
2253 rpValue = m_pPLCF_Contents ? static_cast<void*>(&m_pPLCF_Contents[nInIdx * m_nStru]) : nullptr;
2254 return true;
2257 // WW8PLCF e.g. for SEPX
2258 // Ctor for *others* than Fkps
2259 // With nStartPos < 0, the first element of PLCFs will be taken
2260 WW8PLCF::WW8PLCF(SvStream& rSt, WW8_FC nFilePos, sal_Int32 nPLCF, int nStruct,
2261 WW8_CP nStartPos) : m_nIdx(0), m_nStru(nStruct)
2263 if (nPLCF < 0)
2265 SAL_WARN("sw.ww8", "broken WW8PLCF, ignoring");
2266 nPLCF = 0;
2268 else
2269 m_nIMax = (nPLCF - 4) / (4 + nStruct);
2271 ReadPLCF(rSt, nFilePos, nPLCF);
2273 if( nStartPos >= 0 )
2274 SeekPos( nStartPos );
2277 // Ctor *only* for Fkps
2278 // The last 2 parameters are needed for PLCF.Chpx and PLCF.Papx.
2279 // If ncpN != 0, then an incomplete PLCF will be completed. This is always required for WW6 with
2280 // lack of resources and for WordPad (W95).
2281 // With nStartPos < 0, the first element of the PLCFs is taken.
2282 WW8PLCF::WW8PLCF(SvStream& rSt, WW8_FC nFilePos, sal_Int32 nPLCF, int nStruct,
2283 WW8_CP nStartPos, sal_Int32 nPN, sal_Int32 ncpN): m_nIdx(0),
2284 m_nStru(nStruct)
2286 if (nPLCF < 0)
2288 SAL_WARN("sw.ww8", "broken WW8PLCF, ignoring");
2289 m_nIMax = SAL_MAX_INT32;
2291 else
2292 m_nIMax = (nPLCF - 4) / (4 + nStruct);
2294 if( m_nIMax >= ncpN )
2295 ReadPLCF(rSt, nFilePos, nPLCF);
2296 else
2297 GeneratePLCF(rSt, nPN, ncpN);
2299 if( nStartPos >= 0 )
2300 SeekPos( nStartPos );
2303 void WW8PLCF::ReadPLCF(SvStream& rSt, WW8_FC nFilePos, sal_uInt32 nPLCF)
2305 sal_uInt64 const nOldPos = rSt.Tell();
2306 bool bValid = nPLCF != 0 && checkSeek(rSt, nFilePos)
2307 && (rSt.remainingSize() >= nPLCF);
2309 if (bValid)
2311 // Pointer to Pos-array
2312 const size_t nEntries = (nPLCF + 3) / 4;
2313 m_pPLCF_PosArray.reset(new WW8_CP[nEntries]);
2314 bValid = checkRead(rSt, m_pPLCF_PosArray.get(), nPLCF);
2315 size_t nBytesAllocated = nEntries * sizeof(WW8_CP);
2316 if (bValid && nPLCF != nBytesAllocated)
2318 sal_uInt8* pStartBlock = reinterpret_cast<sal_uInt8*>(m_pPLCF_PosArray.get());
2319 memset(pStartBlock + nPLCF, 0, nBytesAllocated - nPLCF);
2323 if (bValid)
2325 #ifdef OSL_BIGENDIAN
2326 for( m_nIdx = 0; m_nIdx <= m_nIMax; m_nIdx++ )
2327 m_pPLCF_PosArray[m_nIdx] = OSL_SWAPDWORD( m_pPLCF_PosArray[m_nIdx] );
2328 m_nIdx = 0;
2329 #endif // OSL_BIGENDIAN
2330 // Pointer to content array
2331 m_pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&m_pPLCF_PosArray[m_nIMax + 1]);
2333 TruncToSortedRange();
2336 OSL_ENSURE(bValid, "Document has corrupt PLCF, ignoring it");
2338 if (!bValid)
2339 MakeFailedPLCF();
2341 rSt.Seek(nOldPos);
2344 void WW8PLCF::MakeFailedPLCF()
2346 m_nIMax = 0;
2347 m_pPLCF_PosArray.reset( new WW8_CP[2] );
2348 m_pPLCF_PosArray[0] = m_pPLCF_PosArray[1] = WW8_CP_MAX;
2349 m_pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&m_pPLCF_PosArray[m_nIMax + 1]);
2352 namespace
2354 sal_Int32 TruncToSortedRange(const sal_Int32* pPLCF_PosArray, sal_Int32 nIMax)
2356 //Docs state that: ... all Plcs ... are sorted in ascending order.
2357 //So ensure that here for broken documents.
2358 for (auto nI = 0; nI < nIMax; ++nI)
2360 if (pPLCF_PosArray[nI] > pPLCF_PosArray[nI+1])
2362 SAL_WARN("sw.ww8", "Document has unsorted PLCF, truncated to sorted portion");
2363 nIMax = nI;
2364 break;
2367 return nIMax;
2371 void WW8PLCFpcd::TruncToSortedRange()
2373 m_nIMax = ::TruncToSortedRange(m_pPLCF_PosArray.get(), m_nIMax);
2376 void WW8PLCF::TruncToSortedRange()
2378 m_nIMax = ::TruncToSortedRange(m_pPLCF_PosArray.get(), m_nIMax);
2381 void WW8PLCF::GeneratePLCF(SvStream& rSt, sal_Int32 nPN, sal_Int32 ncpN)
2383 OSL_ENSURE( m_nIMax < ncpN, "Pcl.Fkp: Why is PLCF too big?" );
2385 bool failure = false;
2386 m_nIMax = ncpN;
2388 if ((m_nIMax < 1) || (m_nIMax > (WW8_CP_MAX - 4) / (4 + m_nStru)) || nPN < 0)
2389 failure = true;
2391 if (!failure)
2393 // Check arguments to ShortToSVBT16 in loop below will all be valid:
2394 sal_Int32 nResult;
2395 failure = o3tl::checked_add(nPN, ncpN, nResult) || nResult > SAL_MAX_UINT16;
2398 if (!failure)
2400 size_t nSiz = (4 + m_nStru) * m_nIMax + 4;
2401 size_t nElems = ( nSiz + 3 ) / 4;
2402 m_pPLCF_PosArray.reset( new WW8_CP[ nElems ] ); // Pointer to Pos-array
2404 for (sal_Int32 i = 0; i < ncpN && !failure; ++i)
2406 failure = true;
2407 // construct FC entries
2408 // first FC entry of each Fkp
2409 if (!checkSeek(rSt, (nPN + i) << 9))
2410 break;
2412 WW8_CP nFc(0);
2413 rSt.ReadInt32( nFc );
2414 m_pPLCF_PosArray[i] = nFc;
2416 failure = bool(rSt.GetError());
2420 if (!failure)
2424 failure = true;
2426 std::size_t nLastFkpPos = nPN + m_nIMax - 1;
2427 nLastFkpPos = nLastFkpPos << 9;
2428 // number of FC entries of last Fkp
2429 if (!checkSeek(rSt, nLastFkpPos + 511))
2430 break;
2432 sal_uInt8 nb(0);
2433 rSt.ReadUChar( nb );
2434 // last FC entry of last Fkp
2435 if (!checkSeek(rSt, nLastFkpPos + nb * 4))
2436 break;
2438 WW8_CP nFc(0);
2439 rSt.ReadInt32( nFc );
2440 m_pPLCF_PosArray[m_nIMax] = nFc; // end of the last Fkp
2442 failure = bool(rSt.GetError());
2443 } while(false);
2446 if (!failure)
2448 // Pointer to content array
2449 m_pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&m_pPLCF_PosArray[m_nIMax + 1]);
2450 sal_uInt8* p = m_pPLCF_Contents;
2452 for (sal_Int32 i = 0; i < ncpN; ++i) // construct PNs
2454 ShortToSVBT16(o3tl::narrowing<sal_uInt16>(nPN + i), p);
2455 p += m_nStru;
2459 SAL_WARN_IF(failure, "sw.ww8", "Document has corrupt PLCF, ignoring it");
2461 if (failure)
2462 MakeFailedPLCF();
2465 bool WW8PLCF::SeekPos(WW8_CP nPos)
2467 WW8_CP nP = nPos;
2469 if( nP < m_pPLCF_PosArray[0] )
2471 m_nIdx = 0;
2472 // not found: nPos less than smallest entry
2473 return false;
2476 // Search from beginning?
2477 if ((m_nIdx < 1) || (nP < m_pPLCF_PosArray[m_nIdx - 1]))
2478 m_nIdx = 1;
2480 sal_Int32 nI = m_nIdx;
2481 sal_Int32 nEnd = m_nIMax;
2483 for(int n = (1==m_nIdx ? 1 : 2); n; --n )
2485 for( ; nI <=nEnd; ++nI) // search with an index that is incremented by 1
2487 if( nP < m_pPLCF_PosArray[nI] ) // found position
2489 m_nIdx = nI - 1; // nI - 1 is the correct index
2490 return true; // done
2493 nI = 1;
2494 nEnd = m_nIdx-1;
2497 m_nIdx = m_nIMax; // not found, greater than all entries
2498 return false;
2501 bool WW8PLCF::Get(WW8_CP& rStart, WW8_CP& rEnd, void*& rpValue) const
2503 if ( m_nIdx >= m_nIMax )
2505 rStart = rEnd = WW8_CP_MAX;
2506 return false;
2508 rStart = m_pPLCF_PosArray[ m_nIdx ];
2509 rEnd = m_pPLCF_PosArray[ m_nIdx + 1 ];
2510 rpValue = static_cast<void*>(&m_pPLCF_Contents[m_nIdx * m_nStru]);
2511 return true;
2514 WW8_CP WW8PLCF::Where() const
2516 if ( m_nIdx >= m_nIMax )
2517 return WW8_CP_MAX;
2519 return m_pPLCF_PosArray[m_nIdx];
2522 WW8PLCFpcd::WW8PLCFpcd(SvStream* pSt, sal_uInt32 nFilePos,
2523 sal_uInt32 nPLCF, sal_uInt32 nStruct)
2524 : m_nStru( nStruct )
2526 const sal_uInt32 nValidMin=4;
2528 sal_uInt64 const nOldPos = pSt->Tell();
2530 bool bValid = checkSeek(*pSt, nFilePos);
2531 std::size_t nRemainingSize = pSt->remainingSize();
2532 if( nRemainingSize < nValidMin || nPLCF < nValidMin )
2533 bValid = false;
2534 nPLCF = bValid ? std::min(nRemainingSize, static_cast<std::size_t>(nPLCF)) : nValidMin;
2536 m_pPLCF_PosArray.reset( new WW8_CP[ ( nPLCF + 3 ) / 4 ] ); // Pointer to Pos-array
2537 m_pPLCF_PosArray[0] = 0;
2539 nPLCF = bValid ? pSt->ReadBytes(m_pPLCF_PosArray.get(), nPLCF) : nValidMin;
2540 nPLCF = std::max(nPLCF, nValidMin);
2542 m_nIMax = ( nPLCF - 4 ) / ( 4 + nStruct );
2543 #ifdef OSL_BIGENDIAN
2544 for( tools::Long nI = 0; nI <= m_nIMax; nI++ )
2545 m_pPLCF_PosArray[nI] = OSL_SWAPDWORD( m_pPLCF_PosArray[nI] );
2546 #endif // OSL_BIGENDIAN
2548 // Pointer to content array
2549 m_pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&m_pPLCF_PosArray[m_nIMax + 1]);
2550 TruncToSortedRange();
2552 pSt->Seek( nOldPos );
2555 // If nStartPos < 0, the first element of PLCFs will be taken
2556 WW8PLCFpcd_Iter::WW8PLCFpcd_Iter( WW8PLCFpcd& rPLCFpcd, tools::Long nStartPos )
2557 :m_rPLCF( rPLCFpcd ), m_nIdx( 0 )
2559 if( nStartPos >= 0 )
2560 SeekPos( nStartPos );
2563 bool WW8PLCFpcd_Iter::SeekPos(tools::Long nPos)
2565 tools::Long nP = nPos;
2567 if( nP < m_rPLCF.m_pPLCF_PosArray[0] )
2569 m_nIdx = 0;
2570 return false; // not found: nPos less than smallest entry
2572 // Search from beginning?
2573 if ((m_nIdx < 1) || (nP < m_rPLCF.m_pPLCF_PosArray[m_nIdx - 1]))
2574 m_nIdx = 1;
2576 tools::Long nI = m_nIdx;
2577 tools::Long nEnd = m_rPLCF.m_nIMax;
2579 for(int n = (1==m_nIdx ? 1 : 2); n; --n )
2581 for( ; nI <=nEnd; ++nI)
2582 { // search with an index that is incremented by 1
2583 if( nP < m_rPLCF.m_pPLCF_PosArray[nI] )
2584 { // found position
2585 m_nIdx = nI - 1; // nI - 1 is the correct index
2586 return true; // done
2589 nI = 1;
2590 nEnd = m_nIdx-1;
2592 m_nIdx = m_rPLCF.m_nIMax; // not found, greater than all entries
2593 return false;
2596 bool WW8PLCFpcd_Iter::Get(WW8_CP& rStart, WW8_CP& rEnd, void*& rpValue) const
2598 if( m_nIdx >= m_rPLCF.m_nIMax )
2600 rStart = rEnd = WW8_CP_MAX;
2601 return false;
2603 rStart = m_rPLCF.m_pPLCF_PosArray[m_nIdx];
2604 rEnd = m_rPLCF.m_pPLCF_PosArray[m_nIdx + 1];
2605 rpValue = static_cast<void*>(&m_rPLCF.m_pPLCF_Contents[m_nIdx * m_rPLCF.m_nStru]);
2606 return true;
2609 sal_Int32 WW8PLCFpcd_Iter::Where() const
2611 if ( m_nIdx >= m_rPLCF.m_nIMax )
2612 return SAL_MAX_INT32;
2614 return m_rPLCF.m_pPLCF_PosArray[m_nIdx];
2617 bool WW8PLCFx_Fc_FKP::WW8Fkp::Entry::operator<
2618 (const WW8PLCFx_Fc_FKP::WW8Fkp::Entry& rSecond) const
2620 return (mnFC < rSecond.mnFC);
2623 static bool IsReplaceAllSprm(sal_uInt16 nSpId)
2625 return (NS_sprm::LN_PHugePapx == nSpId || 0x6646 == nSpId);
2628 static bool IsExpandableSprm(sal_uInt16 nSpId)
2630 return 0x646B == nSpId;
2633 void WW8PLCFx_Fc_FKP::WW8Fkp::FillEntry(WW8PLCFx_Fc_FKP::WW8Fkp::Entry &rEntry,
2634 std::size_t nDataOffset, sal_uInt16 nLen)
2636 bool bValidPos = (nDataOffset < sizeof(maRawData));
2638 OSL_ENSURE(bValidPos, "sprm sequence offset is out of range, ignoring");
2640 if (!bValidPos)
2642 rEntry.mnLen = 0;
2643 return;
2646 const sal_uInt16 nAvailableData = sizeof(maRawData)-nDataOffset;
2647 OSL_ENSURE(nLen <= nAvailableData, "sprm sequence len is out of range, clipping");
2648 rEntry.mnLen = std::min(nLen, nAvailableData);
2649 rEntry.mpData = maRawData + nDataOffset;
2652 WW8PLCFx_Fc_FKP::WW8Fkp::WW8Fkp(const WW8Fib& rFib, SvStream* pSt,
2653 SvStream* pDataSt, tools::Long _nFilePos, tools::Long nItemSiz, ePLCFT ePl,
2654 WW8_FC nStartFc)
2655 : m_nItemSize(nItemSiz), m_nFilePos(_nFilePos), mnIdx(0), m_ePLCF(ePl)
2656 , mnMustRemainCached(0), maSprmParser(rFib)
2658 memset(maRawData, 0, 512);
2660 const ww::WordVersion eVersion = rFib.GetFIBVersion();
2662 sal_uInt64 const nOldPos = pSt->Tell();
2664 bool bCouldSeek = checkSeek(*pSt, m_nFilePos);
2665 bool bCouldRead = bCouldSeek && checkRead(*pSt, maRawData, 512);
2667 mnIMax = bCouldRead ? maRawData[511] : 0;
2669 sal_uInt8 *pStart = maRawData;
2670 // Offset-Location in maRawData
2671 const size_t nRawDataStart = (mnIMax + 1) * 4;
2673 for (mnIdx = 0; mnIdx < mnIMax; ++mnIdx)
2675 const size_t nRawDataOffset = nRawDataStart + mnIdx * m_nItemSize;
2677 //clip to available data, corrupt fkp
2678 if (nRawDataOffset >= 511)
2680 mnIMax = mnIdx;
2681 break;
2684 unsigned int nOfs = maRawData[nRawDataOffset] * 2;
2685 // nOfs in [0..0xff*2=510]
2687 Entry aEntry(Get_Long(pStart));
2689 if (nOfs)
2691 switch (m_ePLCF)
2693 case CHP:
2695 aEntry.mnLen = maRawData[nOfs];
2697 //len byte
2698 std::size_t nDataOffset = nOfs + 1;
2700 FillEntry(aEntry, nDataOffset, aEntry.mnLen);
2702 if (aEntry.mnLen && eVersion <= ww::eWW2)
2704 Word2CHPX aChpx = ReadWord2Chpx(*pSt, m_nFilePos + nOfs + 1, static_cast< sal_uInt8 >(aEntry.mnLen));
2705 std::vector<sal_uInt8> aSprms = ChpxToSprms(aChpx);
2706 aEntry.mnLen = static_cast< sal_uInt16 >(aSprms.size());
2707 if (aEntry.mnLen)
2709 aEntry.mpData = new sal_uInt8[aEntry.mnLen];
2710 memcpy(aEntry.mpData, aSprms.data(), aEntry.mnLen);
2711 aEntry.mbMustDelete = true;
2714 break;
2716 case PAP:
2718 sal_uInt8 nDelta = 0;
2720 aEntry.mnLen = maRawData[nOfs];
2721 if (IsEightPlus(eVersion) && !aEntry.mnLen)
2723 aEntry.mnLen = maRawData[nOfs+1];
2724 nDelta++;
2726 aEntry.mnLen *= 2;
2728 //stylecode, std/istd
2729 if (eVersion <= ww::eWW2)
2731 if (aEntry.mnLen >= 1)
2733 aEntry.mnIStd = *(maRawData+nOfs+1+nDelta);
2734 aEntry.mnLen--; //style code
2735 if (aEntry.mnLen >= 6)
2737 aEntry.mnLen-=6; //PHE
2738 //skip stc, len byte + 6 byte PHE
2739 unsigned int nOffset = nOfs + 8;
2740 if (nOffset >= 511) //Bad offset
2741 aEntry.mnLen=0;
2742 if (aEntry.mnLen) //start is ok
2744 if (nOffset + aEntry.mnLen > 512) //Bad end, clip
2745 aEntry.mnLen = 512 - nOffset;
2746 aEntry.mpData = maRawData + nOffset;
2749 else
2750 aEntry.mnLen=0; //Too short
2753 else
2755 if (aEntry.mnLen >= 2)
2757 //len byte + optional extra len byte
2758 std::size_t nDataOffset = nOfs + 1 + nDelta;
2759 aEntry.mnIStd = nDataOffset <= sizeof(maRawData)-sizeof(aEntry.mnIStd) ?
2760 SVBT16ToUInt16(maRawData+nDataOffset) : 0;
2761 aEntry.mnLen-=2; //istd
2762 if (aEntry.mnLen)
2764 //additional istd
2765 nDataOffset += sizeof(aEntry.mnIStd);
2767 FillEntry(aEntry, nDataOffset, aEntry.mnLen);
2770 else
2771 aEntry.mnLen=0; //Too short, ignore
2774 const sal_uInt16 nSpId = aEntry.mnLen
2775 ? maSprmParser.GetSprmId(aEntry.mpData) : 0;
2778 If we replace then we throw away the old data, if we
2779 are expanding, then we tack the old data onto the end
2780 of the new data
2782 const bool bExpand = IsExpandableSprm(nSpId);
2783 const sal_uInt8* pStartData
2784 = aEntry.mpData == nullptr ? nullptr : aEntry.mpData + 2;
2785 const sal_uInt8* pLastValidDataPos = maRawData + 512 - sizeof(sal_uInt32);
2786 if (pStartData != nullptr && pStartData > pLastValidDataPos)
2787 pStartData = nullptr;
2788 if ((IsReplaceAllSprm(nSpId) || bExpand) && pStartData)
2790 sal_uInt64 nCurr = pDataSt->Tell();
2791 sal_uInt32 nPos = SVBT32ToUInt32(pStartData);
2792 sal_uInt16 nLen(0);
2794 bool bOk = checkSeek(*pDataSt, nPos);
2795 if (bOk)
2797 pDataSt->ReadUInt16( nLen );
2798 bOk = nLen <= pDataSt->remainingSize();
2801 if (bOk)
2803 const sal_uInt16 nOrigLen = bExpand ? aEntry.mnLen : 0;
2804 sal_uInt8 *pOrigData = bExpand ? aEntry.mpData : nullptr;
2806 aEntry.mnLen = nLen;
2807 aEntry.mpData =
2808 new sal_uInt8[aEntry.mnLen + nOrigLen];
2809 aEntry.mbMustDelete = true;
2810 aEntry.mnLen =
2811 pDataSt->ReadBytes(aEntry.mpData, aEntry.mnLen);
2813 pDataSt->Seek( nCurr );
2815 if (pOrigData)
2817 memcpy(aEntry.mpData + aEntry.mnLen,
2818 pOrigData, nOrigLen);
2819 aEntry.mnLen = aEntry.mnLen + nOrigLen;
2824 break;
2825 default:
2826 OSL_FAIL("sweet god, what have you done!");
2827 break;
2831 maEntries.push_back(aEntry);
2834 //one more FC than grrpl entries
2835 maEntries.emplace_back(Get_Long(pStart));
2837 //we expect them sorted, but it appears possible for them to arrive unsorted
2838 std::stable_sort(maEntries.begin(), maEntries.end());
2840 mnIdx = 0;
2842 if (nStartFc >= 0)
2843 SeekPos(nStartFc);
2845 pSt->Seek(nOldPos);
2848 WW8PLCFx_Fc_FKP::WW8Fkp::Entry::Entry(const Entry &rEntry)
2849 : mnFC(rEntry.mnFC), mnLen(rEntry.mnLen), mnIStd(rEntry.mnIStd),
2850 mbMustDelete(rEntry.mbMustDelete)
2852 if (mbMustDelete)
2854 mpData = new sal_uInt8[mnLen];
2855 memcpy(mpData, rEntry.mpData, mnLen);
2857 else
2858 mpData = rEntry.mpData;
2861 WW8PLCFx_Fc_FKP::WW8Fkp::Entry&
2862 WW8PLCFx_Fc_FKP::WW8Fkp::Entry::operator=(const Entry &rEntry)
2864 if (this == &rEntry)
2865 return *this;
2867 if (mbMustDelete)
2868 delete[] mpData;
2870 mnFC = rEntry.mnFC;
2871 mnLen = rEntry.mnLen;
2872 mnIStd = rEntry.mnIStd;
2873 mbMustDelete = rEntry.mbMustDelete;
2875 if (rEntry.mbMustDelete)
2877 mpData = new sal_uInt8[mnLen];
2878 memcpy(mpData, rEntry.mpData, mnLen);
2880 else
2881 mpData = rEntry.mpData;
2883 return *this;
2886 WW8PLCFx_Fc_FKP::WW8Fkp::Entry::~Entry()
2888 if (mbMustDelete)
2889 delete[] mpData;
2892 void WW8PLCFx_Fc_FKP::WW8Fkp::Reset(WW8_FC nFc)
2894 SetIdx(0);
2895 if (nFc >= 0)
2896 SeekPos(nFc);
2899 bool WW8PLCFx_Fc_FKP::WW8Fkp::SeekPos(WW8_FC nFc)
2901 if (nFc < maEntries[0].mnFC)
2903 mnIdx = 0;
2904 return false; // not found: nPos less than smallest entry
2907 // Search from beginning?
2908 if ((mnIdx < 1) || (nFc < maEntries[mnIdx - 1].mnFC))
2909 mnIdx = 1;
2911 sal_uInt8 nI = mnIdx;
2912 sal_uInt8 nEnd = mnIMax;
2914 for(sal_uInt8 n = (1==mnIdx ? 1 : 2); n; --n )
2916 for( ; nI <=nEnd; ++nI)
2917 { // search with an index that is incremented by 1
2918 if (nFc < maEntries[nI].mnFC)
2919 { // found position
2920 mnIdx = nI - 1; // nI - 1 is the correct index
2921 return true; // done
2924 nI = 1;
2925 nEnd = mnIdx-1;
2927 mnIdx = mnIMax; // not found, greater than all entries
2928 return false;
2931 sal_uInt8* WW8PLCFx_Fc_FKP::WW8Fkp::Get(WW8_FC& rStart, WW8_FC& rEnd, sal_Int32& rLen)
2932 const
2934 rLen = 0;
2936 if (mnIdx >= mnIMax)
2938 rStart = WW8_FC_MAX;
2939 return nullptr;
2942 rStart = maEntries[mnIdx].mnFC;
2943 rEnd = maEntries[mnIdx + 1].mnFC;
2945 sal_uInt8* pSprms = GetLenAndIStdAndSprms( rLen );
2946 return pSprms;
2949 void WW8PLCFx_Fc_FKP::WW8Fkp::SetIdx(sal_uInt8 nI)
2951 if (nI < mnIMax)
2953 mnIdx = nI;
2957 sal_uInt8* WW8PLCFx_Fc_FKP::WW8Fkp::GetLenAndIStdAndSprms(sal_Int32& rLen) const
2959 rLen = maEntries[mnIdx].mnLen;
2960 return maEntries[mnIdx].mpData;
2963 SprmResult WW8PLCFx_Fc_FKP::WW8Fkp::HasSprm( sal_uInt16 nId, bool bFindFirst )
2965 if (mnIdx >= mnIMax)
2966 return SprmResult();
2968 sal_Int32 nLen;
2969 sal_uInt8* pSprms = GetLenAndIStdAndSprms( nLen );
2971 WW8SprmIter aIter(pSprms, nLen, maSprmParser);
2972 return aIter.FindSprm(nId, bFindFirst);
2975 void WW8PLCFx_Fc_FKP::WW8Fkp::HasSprm(sal_uInt16 nId,
2976 std::vector<SprmResult> &rResult)
2978 if (mnIdx >= mnIMax)
2979 return;
2981 sal_Int32 nLen;
2982 sal_uInt8* pSprms = GetLenAndIStdAndSprms( nLen );
2984 WW8SprmIter aIter(pSprms, nLen, maSprmParser);
2986 while(aIter.GetSprms())
2988 if (aIter.GetCurrentId() == nId)
2990 sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId);
2991 sal_Int32 nL = maSprmParser.GetSprmSize(nId, aIter.GetSprms(), aIter.GetRemLen());
2992 rResult.emplace_back(aIter.GetCurrentParams(), nL - nFixedLen);
2994 aIter.advance();
2998 ww::WordVersion WW8PLCFx::GetFIBVersion() const
3000 return mrFib.GetFIBVersion();
3003 void WW8PLCFx::GetSprms( WW8PLCFxDesc* p )
3005 OSL_ENSURE( false, "Called wrong GetSprms" );
3006 p->nStartPos = p->nEndPos = WW8_CP_MAX;
3007 p->pMemPos = nullptr;
3008 p->nSprmsLen = 0;
3009 p->bRealLineEnd = false;
3012 tools::Long WW8PLCFx::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
3014 OSL_ENSURE( false, "Called wrong GetNoSprms" );
3015 rStart = rEnd = WW8_CP_MAX;
3016 rLen = 0;
3017 return 0;
3020 // ...Idx2: Default: ignore
3021 sal_uInt32 WW8PLCFx::GetIdx2() const
3023 return 0;
3026 void WW8PLCFx::SetIdx2(sal_uInt32)
3030 namespace {
3032 class SamePos
3034 private:
3035 tools::Long mnPo;
3036 public:
3037 explicit SamePos(tools::Long nPo) : mnPo(nPo) {}
3038 bool operator()(const std::unique_ptr<WW8PLCFx_Fc_FKP::WW8Fkp>& pFkp)
3039 {return mnPo == pFkp->GetFilePos();}
3044 bool WW8PLCFx_Fc_FKP::NewFkp()
3046 WW8_CP nPLCFStart, nPLCFEnd;
3047 void* pPage;
3049 static const int WW8FkpSizeTabVer2[ PLCF_END ] =
3051 1, 1, 0 /*, 0, 0, 0*/
3053 static const int WW8FkpSizeTabVer6[ PLCF_END ] =
3055 1, 7, 0 /*, 0, 0, 0*/
3057 static const int WW8FkpSizeTabVer8[ PLCF_END ] =
3059 1, 13, 0 /*, 0, 0, 0*/
3061 const int* pFkpSizeTab;
3063 switch (GetFIBVersion())
3065 case ww::eWW1:
3066 case ww::eWW2:
3067 pFkpSizeTab = WW8FkpSizeTabVer2;
3068 break;
3069 case ww::eWW6:
3070 case ww::eWW7:
3071 pFkpSizeTab = WW8FkpSizeTabVer6;
3072 break;
3073 case ww::eWW8:
3074 pFkpSizeTab = WW8FkpSizeTabVer8;
3075 break;
3076 default:
3077 // program error!
3078 OSL_ENSURE( false, "nVersion not implemented!" );
3079 return false;
3082 if (!m_pPLCF->Get( nPLCFStart, nPLCFEnd, pPage ))
3084 m_pFkp = nullptr;
3085 return false; // PLCF completely processed
3087 m_pPLCF->advance();
3088 tools::Long nPo = SVBT16ToUInt16( static_cast<sal_uInt8 *>(pPage) );
3089 nPo <<= 9; // shift as LONG
3091 tools::Long nCurrentFkpFilePos = m_pFkp ? m_pFkp->GetFilePos() : -1;
3092 if (nCurrentFkpFilePos == nPo)
3093 m_pFkp->Reset(GetStartFc());
3094 else
3096 auto aIter =
3097 std::find_if(maFkpCache.begin(), maFkpCache.end(), SamePos(nPo));
3098 if (aIter != maFkpCache.end())
3100 m_pFkp = aIter->get();
3101 m_pFkp->Reset(GetStartFc());
3103 else
3105 m_pFkp = new WW8Fkp(GetFIB(), m_pFKPStrm, m_pDataStrm, nPo,
3106 pFkpSizeTab[ m_ePLCF ], m_ePLCF, GetStartFc());
3107 maFkpCache.push_back(std::unique_ptr<WW8Fkp>(m_pFkp));
3109 if (maFkpCache.size() > eMaxCache)
3111 WW8Fkp* pCachedFkp = maFkpCache.front().get();
3112 if (!pCachedFkp->IsMustRemainCache())
3114 maFkpCache.pop_front();
3120 SetStartFc( -1 ); // only the first time
3121 return true;
3124 WW8PLCFx_Fc_FKP::WW8PLCFx_Fc_FKP(SvStream* pSt, SvStream* pTableSt,
3125 SvStream* pDataSt, const WW8Fib& rFib, ePLCFT ePl, WW8_FC nStartFcL)
3126 : WW8PLCFx(rFib, true), m_pFKPStrm(pSt), m_pDataStrm(pDataSt)
3127 , m_pFkp(nullptr), m_ePLCF(ePl)
3129 SetStartFc(nStartFcL);
3130 tools::Long nLenStruct = (8 > rFib.m_nVersion) ? 2 : 4;
3131 if (ePl == CHP)
3133 m_pPLCF.reset(new WW8PLCF(*pTableSt, rFib.m_fcPlcfbteChpx, rFib.m_lcbPlcfbteChpx,
3134 nLenStruct, GetStartFc(), rFib.m_pnChpFirst, rFib.m_cpnBteChp));
3136 else
3138 m_pPLCF.reset(new WW8PLCF(*pTableSt, rFib.m_fcPlcfbtePapx, rFib.m_lcbPlcfbtePapx,
3139 nLenStruct, GetStartFc(), rFib.m_pnPapFirst, rFib.m_cpnBtePap));
3143 WW8PLCFx_Fc_FKP::~WW8PLCFx_Fc_FKP()
3145 maFkpCache.clear();
3146 m_pPLCF.reset();
3147 m_pPCDAttrs.reset();
3150 sal_uInt32 WW8PLCFx_Fc_FKP::GetIdx() const
3152 sal_uInt32 u = m_pPLCF->GetIdx() << 8;
3153 if (m_pFkp)
3154 u |= m_pFkp->GetIdx();
3155 return u;
3158 void WW8PLCFx_Fc_FKP::SetIdx(sal_uInt32 nIdx)
3160 if( !( nIdx & 0xffffff00L ) )
3162 m_pPLCF->SetIdx( nIdx >> 8 );
3163 m_pFkp = nullptr;
3165 else
3166 { // there was a Fkp
3167 // Set PLCF one position back to retrieve the address of the Fkp
3168 m_pPLCF->SetIdx( ( nIdx >> 8 ) - 1 );
3169 if (NewFkp()) // read Fkp again
3171 sal_uInt8 nFkpIdx = static_cast<sal_uInt8>(nIdx & 0xff);
3172 m_pFkp->SetIdx(nFkpIdx); // set Fkp-Pos again
3177 bool WW8PLCFx_Fc_FKP::SeekPos(WW8_FC nFcPos)
3179 // StartPos for next Where()
3180 SetStartFc( nFcPos );
3182 // find StartPos for next pPLCF->Get()
3183 bool bRet = m_pPLCF->SeekPos(nFcPos);
3185 // make FKP invalid?
3186 WW8_CP nPLCFStart, nPLCFEnd;
3187 void* pPage;
3188 if( m_pFkp && m_pPLCF->Get( nPLCFStart, nPLCFEnd, pPage ) )
3190 tools::Long nPo = SVBT16ToUInt16( static_cast<sal_uInt8 *>(pPage) );
3191 nPo <<= 9; // shift as LONG
3192 if (nPo != m_pFkp->GetFilePos())
3193 m_pFkp = nullptr;
3194 else
3195 m_pFkp->SeekPos( nFcPos );
3197 return bRet;
3200 WW8_FC WW8PLCFx_Fc_FKP::Where()
3202 if( !m_pFkp && !NewFkp() )
3203 return WW8_FC_MAX;
3204 WW8_FC nP = m_pFkp ? m_pFkp->Where() : WW8_FC_MAX;
3205 if( nP != WW8_FC_MAX )
3206 return nP;
3208 m_pFkp = nullptr; // FKP finished -> get new
3209 return Where(); // easiest way: do it recursively
3212 sal_uInt8* WW8PLCFx_Fc_FKP::GetSprmsAndPos(WW8_FC& rStart, WW8_FC& rEnd, sal_Int32& rLen)
3214 rLen = 0; // Default
3215 rStart = rEnd = WW8_FC_MAX;
3217 if( !m_pFkp ) // Fkp not there ?
3219 if( !NewFkp() )
3220 return nullptr;
3223 sal_uInt8* pPos = m_pFkp ? m_pFkp->Get( rStart, rEnd, rLen ) : nullptr;
3224 if( rStart == WW8_FC_MAX ) //Not found
3225 return nullptr;
3226 return pPos;
3229 void WW8PLCFx_Fc_FKP::advance()
3231 if( !m_pFkp && !NewFkp() )
3232 return;
3234 if (!m_pFkp)
3235 return;
3237 m_pFkp->advance();
3238 if( m_pFkp->Where() == WW8_FC_MAX )
3239 (void)NewFkp();
3242 sal_uInt16 WW8PLCFx_Fc_FKP::GetIstd() const
3244 return m_pFkp ? m_pFkp->GetIstd() : 0xFFFF;
3247 void WW8PLCFx_Fc_FKP::GetPCDSprms( WW8PLCFxDesc& rDesc )
3249 rDesc.pMemPos = nullptr;
3250 rDesc.nSprmsLen = 0;
3251 if( m_pPCDAttrs )
3253 if( !m_pFkp )
3255 OSL_FAIL("+Problem: GetPCDSprms: NewFkp necessary (not possible!)" );
3256 if( !NewFkp() )
3257 return;
3259 m_pPCDAttrs->GetSprms(&rDesc);
3263 SprmResult WW8PLCFx_Fc_FKP::HasSprm(sal_uInt16 nId, bool bFindFirst)
3265 // const would be nicer, but for that, NewFkp() would need to be replaced or eliminated
3266 if( !m_pFkp )
3268 OSL_FAIL( "+Motz: HasSprm: NewFkp needed ( no const possible )" );
3269 // happens in BugDoc 31722
3270 if( !NewFkp() )
3271 return SprmResult();
3274 if (!m_pFkp)
3275 return SprmResult();
3277 SprmResult aRes = m_pFkp->HasSprm(nId, bFindFirst);
3279 if (!aRes.pSprm)
3281 WW8PLCFxDesc aDesc;
3282 GetPCDSprms( aDesc );
3284 if (aDesc.pMemPos)
3286 WW8SprmIter aIter(aDesc.pMemPos, aDesc.nSprmsLen,
3287 m_pFkp->GetSprmParser());
3288 aRes = aIter.FindSprm(nId, bFindFirst);
3292 return aRes;
3295 void WW8PLCFx_Fc_FKP::HasSprm(sal_uInt16 nId, std::vector<SprmResult> &rResult)
3297 // const would be nicer, but for that, NewFkp() would need to be replaced or eliminated
3298 if (!m_pFkp)
3300 OSL_FAIL( "+Motz: HasSprm: NewFkp needed ( no const possible )" );
3301 // happens in BugDoc 31722
3302 if( !NewFkp() )
3303 return;
3306 if (!m_pFkp)
3307 return;
3309 m_pFkp->HasSprm(nId, rResult);
3311 WW8PLCFxDesc aDesc;
3312 GetPCDSprms( aDesc );
3314 if (!aDesc.pMemPos)
3315 return;
3317 const wwSprmParser &rSprmParser = m_pFkp->GetSprmParser();
3318 WW8SprmIter aIter(aDesc.pMemPos, aDesc.nSprmsLen, rSprmParser);
3319 while(aIter.GetSprms())
3321 if (aIter.GetCurrentId() == nId)
3323 sal_Int32 nFixedLen = rSprmParser.DistanceToData(nId);
3324 sal_Int32 nL = rSprmParser.GetSprmSize(nId, aIter.GetSprms(), aIter.GetRemLen());
3325 rResult.emplace_back(aIter.GetCurrentParams(), nL - nFixedLen);
3327 aIter.advance();
3331 WW8PLCFx_Cp_FKP::WW8PLCFx_Cp_FKP( SvStream* pSt, SvStream* pTableSt,
3332 SvStream* pDataSt, const WW8ScannerBase& rBase, ePLCFT ePl )
3333 : WW8PLCFx_Fc_FKP(pSt, pTableSt, pDataSt, *rBase.m_pWw8Fib, ePl,
3334 rBase.WW8Cp2Fc(0)), m_rSBase(rBase), m_nAttrStart(-1), m_nAttrEnd(-1),
3335 m_bLineEnd(false),
3336 m_bComplex( (7 < rBase.m_pWw8Fib->m_nVersion) || rBase.m_pWw8Fib->m_fComplex )
3338 ResetAttrStartEnd();
3340 if (m_rSBase.m_pPiecePLCF)
3341 m_pPcd.reset( new WW8PLCFx_PCD(GetFIB(), rBase.m_pPiecePLCF.get(), 0, IsSevenMinus(GetFIBVersion())) );
3344 Make a copy of the piece attributes for so that the calls to HasSprm on a
3345 Fc_FKP will be able to take into account the current piece attributes,
3346 despite the fact that such attributes can only be found through a cp based
3347 mechanism.
3349 if (m_pPcd)
3351 m_pPCDAttrs.reset( m_rSBase.m_pPLCFx_PCDAttrs ? new WW8PLCFx_PCDAttrs(
3352 *m_rSBase.m_pWw8Fib, m_pPcd.get(), &m_rSBase) : nullptr);
3355 m_pPieceIter = m_rSBase.m_pPieceIter.get();
3358 WW8PLCFx_Cp_FKP::~WW8PLCFx_Cp_FKP()
3362 void WW8PLCFx_Cp_FKP::ResetAttrStartEnd()
3364 m_nAttrStart = -1;
3365 m_nAttrEnd = -1;
3366 m_bLineEnd = false;
3369 sal_uInt32 WW8PLCFx_Cp_FKP::GetPCDIdx() const
3371 return m_pPcd ? m_pPcd->GetIdx() : 0;
3374 bool WW8PLCFx_Cp_FKP::SeekPos(WW8_CP nCpPos)
3376 if( m_pPcd ) // Complex
3378 if( !m_pPcd->SeekPos( nCpPos ) ) // set piece
3379 return false;
3380 if (m_pPCDAttrs && !m_pPCDAttrs->GetIter()->SeekPos(nCpPos))
3381 return false;
3382 return WW8PLCFx_Fc_FKP::SeekPos(m_pPcd->CurrentPieceStartCp2Fc(nCpPos));
3384 // NO piece table !!!
3385 return WW8PLCFx_Fc_FKP::SeekPos( m_rSBase.WW8Cp2Fc(nCpPos) );
3388 WW8_CP WW8PLCFx_Cp_FKP::Where()
3390 WW8_FC nFc = WW8PLCFx_Fc_FKP::Where();
3391 if( m_pPcd )
3392 return m_pPcd->CurrentPieceStartFc2Cp( nFc ); // identify piece
3393 return m_rSBase.WW8Fc2Cp( nFc ); // NO piece table !!!
3396 void WW8PLCFx_Cp_FKP::GetSprms(WW8PLCFxDesc* p)
3398 WW8_CP nOrigCp = p->nStartPos;
3400 if (!GetDirty()) //Normal case
3402 p->pMemPos = WW8PLCFx_Fc_FKP::GetSprmsAndPos(p->nStartPos, p->nEndPos,
3403 p->nSprmsLen);
3405 else
3408 For the odd case where we have a location in a fastsaved file which
3409 does not have an entry in the FKP, perhaps its para end is in the next
3410 piece, or perhaps the cp just doesn't exist at all in this document.
3411 AdvSprm doesn't know so it sets the PLCF as dirty and we figure out
3412 in this method what the situation is
3414 It doesn't exist then the piece iterator will not be able to find it.
3415 Otherwise our cool fastsave algorithm can be brought to bear on the
3416 problem.
3418 if( !m_pPieceIter )
3419 return;
3420 const sal_uInt32 nOldPos = m_pPieceIter->GetIdx();
3421 bool bOk = m_pPieceIter->SeekPos(nOrigCp);
3422 m_pPieceIter->SetIdx(nOldPos);
3423 if (!bOk)
3424 return;
3427 if( m_pPcd ) // piece table available
3429 // Init ( no ++ called, yet )
3430 if( (m_nAttrStart > m_nAttrEnd) || (m_nAttrStart == -1) )
3432 p->bRealLineEnd = (m_ePLCF == PAP);
3434 if ( ((m_ePLCF == PAP ) || (m_ePLCF == CHP)) && (nOrigCp != WW8_CP_MAX) )
3436 bool bIsUnicode=false;
3438 To find the end of a paragraph for a character in a
3439 complex format file.
3441 It is necessary to know the piece that contains the
3442 character and the FC assigned to the character.
3445 //We set the piece iterator to the piece that contains the
3446 //character, now we have the correct piece for this character
3447 sal_uInt32 nOldPos = m_pPieceIter->GetIdx();
3448 p->nStartPos = nOrigCp;
3449 m_pPieceIter->SeekPos( p->nStartPos);
3451 //This is the FC assigned to the character, but we already
3452 //have the result of the next stage, so we can skip this step
3453 //WW8_FC nStartFc = rSBase.WW8Cp2Fc(p->nStartPos, &bIsUnicode);
3456 Using the FC of the character, first search the FKP that
3457 describes the character to find the smallest FC in the rgfc
3458 that is larger than the character FC.
3460 //But the search has already been done, the next largest FC is
3461 //p->nEndPos.
3462 WW8_FC nOldEndPos = p->nEndPos;
3465 If the FC found in the FKP is less than or equal to the limit
3466 FC of the piece, the end of the paragraph that contains the
3467 character is at the FKP FC minus 1.
3469 WW8_CP nCpStart, nCpEnd;
3470 void* pData=nullptr;
3471 bool bOk = m_pPieceIter->Get(nCpStart, nCpEnd, pData);
3473 if (!bOk)
3475 m_pPieceIter->SetIdx(nOldPos);
3476 return;
3479 WW8_FC nLimitFC = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
3480 WW8_FC nBeginLimitFC = nLimitFC;
3481 if (IsEightPlus(GetFIBVersion()))
3483 nBeginLimitFC =
3484 WW8PLCFx_PCD::TransformPieceAddress(nLimitFC,
3485 bIsUnicode);
3488 WW8_CP nCpLen;
3489 bool bFail = o3tl::checked_sub(nCpEnd, nCpStart, nCpLen);
3490 if (bFail)
3492 SAL_WARN("sw.ww8", "broken offset, ignoring");
3493 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3494 m_pPieceIter->SetIdx(nOldPos);
3495 return;
3498 if (bIsUnicode)
3500 bFail = o3tl::checked_multiply<WW8_CP>(nCpLen, 2, nCpLen);
3501 if (bFail)
3503 SAL_WARN("sw.ww8", "broken offset, ignoring");
3504 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3505 m_pPieceIter->SetIdx(nOldPos);
3506 return;
3510 bFail = o3tl::checked_add(nBeginLimitFC, nCpLen, nLimitFC);
3511 if (bFail)
3513 SAL_WARN("sw.ww8", "broken offset, ignoring");
3514 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3515 m_pPieceIter->SetIdx(nOldPos);
3516 return;
3519 if (nOldEndPos <= nLimitFC)
3521 bFail = o3tl::checked_sub(nLimitFC, nOldEndPos, nCpLen);
3522 if (bFail)
3524 SAL_WARN("sw.ww8", "broken offset, ignoring");
3525 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3526 m_pPieceIter->SetIdx(nOldPos);
3527 return;
3530 nCpLen /= (bIsUnicode ? 2 : 1);
3532 bFail = o3tl::checked_sub(nCpEnd, nCpLen, p->nEndPos);
3533 if (bFail)
3535 SAL_WARN("sw.ww8", "broken offset, ignoring");
3536 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3537 m_pPieceIter->SetIdx(nOldPos);
3538 return;
3541 else
3543 p->nEndPos = nCpEnd;
3544 if (m_ePLCF != CHP)
3547 If the FKP FC that was found was greater than the FC
3548 of the end of the piece, scan piece by piece toward
3549 the end of the document until a piece is found that
3550 contains a paragraph end mark.
3554 It's possible to check if a piece contains a paragraph
3555 mark by using the FC of the beginning of the piece to
3556 search in the FKPs for the smallest FC in the FKP rgfc
3557 that is greater than the FC of the beginning of the
3558 piece. If the FC found is less than or equal to the
3559 limit FC of the piece, then the character that ends
3560 the paragraph is the character immediately before the
3561 FKP fc
3564 m_pPieceIter->advance();
3566 for (;m_pPieceIter->GetIdx() < m_pPieceIter->GetIMax();
3567 m_pPieceIter->advance())
3569 if( !m_pPieceIter->Get( nCpStart, nCpEnd, pData ) )
3571 OSL_ENSURE( false, "piece iter broken!" );
3572 break;
3574 bIsUnicode = false;
3575 sal_Int32 nFcStart=SVBT32ToUInt32(static_cast<WW8_PCD*>(pData)->fc);
3577 if (IsEightPlus(GetFIBVersion()))
3579 nFcStart =
3580 WW8PLCFx_PCD::TransformPieceAddress(
3581 nFcStart,bIsUnicode );
3584 bFail = o3tl::checked_sub(nCpEnd, nCpStart, nCpLen);
3585 if (bFail)
3587 SAL_WARN("sw.ww8", "broken offset, ignoring");
3588 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3589 continue;
3592 if (bIsUnicode)
3594 bFail = o3tl::checked_multiply<WW8_CP>(nCpLen, 2, nCpLen);
3595 if (bFail)
3597 SAL_WARN("sw.ww8", "broken offset, ignoring");
3598 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3599 continue;
3603 bFail = o3tl::checked_add(nFcStart, nCpLen, nLimitFC);
3604 if (bFail)
3606 SAL_WARN("sw.ww8", "broken offset, ignoring");
3607 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3608 continue;
3611 //if it doesn't exist, skip it
3612 if (!SeekPos(nCpStart))
3613 continue;
3615 WW8_FC nOne,nSmallest;
3616 p->pMemPos = WW8PLCFx_Fc_FKP::GetSprmsAndPos(nOne,
3617 nSmallest, p->nSprmsLen);
3619 if (nSmallest <= nLimitFC)
3621 WW8_CP nCpDiff;
3622 bFail = o3tl::checked_sub(nLimitFC, nSmallest, nCpDiff);
3623 if (bFail)
3625 SAL_WARN("sw.ww8", "broken offset, ignoring");
3626 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3627 continue;
3629 if (bIsUnicode)
3630 nCpDiff /= 2;
3632 WW8_CP nEndPos;
3633 bFail = o3tl::checked_sub(nCpEnd, nCpDiff, nEndPos);
3634 if (bFail)
3636 SAL_WARN("sw.ww8", "broken offset, ignoring");
3637 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3638 continue;
3641 OSL_ENSURE(nEndPos >= p->nStartPos, "EndPos before StartPos");
3643 if (nEndPos >= p->nStartPos)
3644 p->nEndPos = nEndPos;
3646 break;
3651 m_pPieceIter->SetIdx( nOldPos );
3653 else
3654 WW8PLCFx_PCD::CurrentPieceFc2Cp( p->nStartPos, p->nEndPos,&m_rSBase );
3656 else
3658 p->nStartPos = m_nAttrStart;
3659 p->nEndPos = m_nAttrEnd;
3660 p->bRealLineEnd = m_bLineEnd;
3663 else // NO piece table !!!
3665 p->nStartPos = m_rSBase.WW8Fc2Cp( p->nStartPos );
3666 p->nEndPos = m_rSBase.WW8Fc2Cp( p->nEndPos );
3667 p->bRealLineEnd = m_ePLCF == PAP;
3671 void WW8PLCFx_Cp_FKP::advance()
3673 WW8PLCFx_Fc_FKP::advance();
3674 // !pPcd: emergency break
3675 if ( !m_bComplex || !m_pPcd )
3676 return;
3678 if( GetPCDIdx() >= m_pPcd->GetIMax() ) // End of PLCF
3680 m_nAttrStart = m_nAttrEnd = WW8_CP_MAX;
3681 return;
3684 sal_Int32 nFkpLen; // Fkp entry
3685 // get Fkp entry
3686 WW8PLCFx_Fc_FKP::GetSprmsAndPos(m_nAttrStart, m_nAttrEnd, nFkpLen);
3688 WW8PLCFx_PCD::CurrentPieceFc2Cp( m_nAttrStart, m_nAttrEnd, &m_rSBase );
3689 m_bLineEnd = (m_ePLCF == PAP);
3692 WW8PLCFx_SEPX::WW8PLCFx_SEPX(SvStream* pSt, SvStream* pTableSt,
3693 const WW8Fib& rFib, WW8_CP nStartCp)
3694 : WW8PLCFx(rFib, true), maSprmParser(rFib),
3695 m_pStrm(pSt), m_nArrMax(256), m_nSprmSiz(0)
3697 if (rFib.m_lcbPlcfsed)
3698 m_pPLCF.reset( new WW8PLCF(*pTableSt, rFib.m_fcPlcfsed, rFib.m_lcbPlcfsed,
3699 GetFIBVersion() <= ww::eWW2 ? 6 : 12, nStartCp) );
3701 m_pSprms.reset( new sal_uInt8[m_nArrMax] ); // maximum length
3704 WW8PLCFx_SEPX::~WW8PLCFx_SEPX()
3708 sal_uInt32 WW8PLCFx_SEPX::GetIdx() const
3710 return m_pPLCF ? m_pPLCF->GetIdx() : 0;
3713 void WW8PLCFx_SEPX::SetIdx(sal_uInt32 nIdx)
3715 if( m_pPLCF ) m_pPLCF->SetIdx( nIdx );
3718 bool WW8PLCFx_SEPX::SeekPos(WW8_CP nCpPos)
3720 return m_pPLCF && m_pPLCF->SeekPos( nCpPos );
3723 WW8_CP WW8PLCFx_SEPX::Where()
3725 return m_pPLCF ? m_pPLCF->Where() : 0;
3728 void WW8PLCFx_SEPX::GetSprms(WW8PLCFxDesc* p)
3730 if( !m_pPLCF ) return;
3732 void* pData;
3734 p->bRealLineEnd = false;
3735 if (!m_pPLCF->Get( p->nStartPos, p->nEndPos, pData ))
3737 p->nStartPos = p->nEndPos = WW8_CP_MAX; // PLCF completely processed
3738 p->pMemPos = nullptr;
3739 p->nSprmsLen = 0;
3741 else
3743 sal_uInt32 nPo = SVBT32ToUInt32( static_cast<sal_uInt8*>(pData)+2 );
3744 if (nPo == 0xFFFFFFFF || !checkSeek(*m_pStrm, nPo))
3746 p->nStartPos = p->nEndPos = WW8_CP_MAX; // Sepx empty
3747 p->pMemPos = nullptr;
3748 p->nSprmsLen = 0;
3750 else
3752 // read len
3753 if (GetFIBVersion() <= ww::eWW2) // eWW6 ?, docs say yes, but...
3755 sal_uInt8 nSiz(0);
3756 m_pStrm->ReadUChar( nSiz );
3757 m_nSprmSiz = nSiz;
3759 else
3761 m_pStrm->ReadUInt16( m_nSprmSiz );
3764 std::size_t nRemaining = m_pStrm->remainingSize();
3765 if (m_nSprmSiz > nRemaining)
3766 m_nSprmSiz = nRemaining;
3768 if( m_nSprmSiz > m_nArrMax )
3769 { // does not fit
3770 m_nArrMax = m_nSprmSiz; // Get more memory
3771 m_pSprms.reset( new sal_uInt8[m_nArrMax] );
3773 m_nSprmSiz = m_pStrm->ReadBytes(m_pSprms.get(), m_nSprmSiz); // read Sprms
3775 p->nSprmsLen = m_nSprmSiz;
3776 p->pMemPos = m_pSprms.get(); // return Position
3781 void WW8PLCFx_SEPX::advance()
3783 if (m_pPLCF)
3784 m_pPLCF->advance();
3787 SprmResult WW8PLCFx_SEPX::HasSprm(sal_uInt16 nId) const
3789 return HasSprm(nId, m_pSprms.get(), m_nSprmSiz);
3792 SprmResult WW8PLCFx_SEPX::HasSprm( sal_uInt16 nId, const sal_uInt8* pOtherSprms,
3793 tools::Long nOtherSprmSiz ) const
3795 SprmResult aRet;
3796 if (m_pPLCF)
3798 WW8SprmIter aIter(pOtherSprms, nOtherSprmSiz, maSprmParser);
3799 aRet = aIter.FindSprm(nId, /*bFindFirst=*/true);
3801 return aRet;
3804 bool WW8PLCFx_SEPX::Find4Sprms(sal_uInt16 nId1,sal_uInt16 nId2,sal_uInt16 nId3,sal_uInt16 nId4,
3805 SprmResult& r1, SprmResult& r2, SprmResult& r3, SprmResult& r4) const
3807 if( !m_pPLCF )
3808 return false;
3810 bool bFound = false;
3812 sal_uInt8* pSp = m_pSprms.get();
3813 size_t i = 0;
3814 while (i + maSprmParser.MinSprmLen() <= m_nSprmSiz)
3816 // Sprm found?
3817 const sal_uInt16 nCurrentId = maSprmParser.GetSprmId(pSp);
3818 sal_Int32 nRemLen = m_nSprmSiz - i;
3819 const sal_Int32 x = maSprmParser.GetSprmSize(nCurrentId, pSp, nRemLen);
3820 bool bValid = x <= nRemLen;
3821 if (!bValid)
3823 SAL_WARN("sw.ww8", "sprm longer than remaining bytes, doc or parser is wrong");
3824 break;
3826 bool bOk = true;
3827 if( nCurrentId == nId1 )
3829 sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId1);
3830 r1 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3832 else if( nCurrentId == nId2 )
3834 sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId2);
3835 r2 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3837 else if( nCurrentId == nId3 )
3839 sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId3);
3840 r3 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3842 else if( nCurrentId == nId4 )
3844 sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId4);
3845 r4 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3847 else
3848 bOk = false;
3849 bFound |= bOk;
3850 // increment pointer so that it points to next SPRM
3851 i += x;
3852 pSp += x;
3854 return bFound;
3857 SprmResult WW8PLCFx_SEPX::HasSprm( sal_uInt16 nId, sal_uInt8 n2nd ) const
3859 SprmResult aRet;
3860 if (m_pPLCF)
3862 WW8SprmIter aIter(m_pSprms.get(), m_nSprmSiz, maSprmParser);
3863 aRet = aIter.FindSprm(nId, /*bFindFirst=*/true, &n2nd);
3865 return aRet;
3868 WW8PLCFx_SubDoc::WW8PLCFx_SubDoc(SvStream* pSt, const WW8Fib& rFib,
3869 WW8_CP nStartCp, tools::Long nFcRef, tools::Long nLenRef, tools::Long nFcText, tools::Long nLenText,
3870 tools::Long nStruct)
3871 : WW8PLCFx(rFib, true)
3873 if( nLenRef && nLenText )
3875 m_pRef.reset(new WW8PLCF(*pSt, nFcRef, nLenRef, nStruct, nStartCp));
3876 m_pText.reset(new WW8PLCF(*pSt, nFcText, nLenText, 0, nStartCp));
3880 WW8PLCFx_SubDoc::~WW8PLCFx_SubDoc()
3882 m_pRef.reset();
3883 m_pText.reset();
3886 sal_uInt32 WW8PLCFx_SubDoc::GetIdx() const
3888 // Probably pText ... no need for it
3889 if( m_pRef )
3890 return ( m_pRef->GetIdx() << 16 | m_pText->GetIdx() );
3891 return 0;
3894 void WW8PLCFx_SubDoc::SetIdx(sal_uInt32 nIdx)
3896 if( m_pRef )
3898 m_pRef->SetIdx( nIdx >> 16 );
3899 // Probably pText ... no need for it
3900 m_pText->SetIdx( nIdx & 0xFFFF );
3904 bool WW8PLCFx_SubDoc::SeekPos( WW8_CP nCpPos )
3906 return m_pRef && m_pRef->SeekPos( nCpPos );
3909 WW8_CP WW8PLCFx_SubDoc::Where()
3911 return m_pRef ? m_pRef->Where() : WW8_CP_MAX;
3914 void WW8PLCFx_SubDoc::GetSprms(WW8PLCFxDesc* p)
3916 p->nStartPos = p->nEndPos = WW8_CP_MAX;
3917 p->pMemPos = nullptr;
3918 p->nSprmsLen = 0;
3919 p->bRealLineEnd = false;
3921 if (!m_pRef)
3922 return;
3924 sal_uInt32 nNr = m_pRef->GetIdx();
3926 void *pData;
3927 WW8_CP nFoo;
3928 if (!m_pRef->Get(p->nStartPos, nFoo, pData))
3930 p->nEndPos = p->nStartPos = WW8_CP_MAX;
3931 return;
3934 if (o3tl::checked_add<WW8_CP>(p->nStartPos, 1, p->nEndPos))
3936 SAL_WARN("sw.ww8", "broken offset, ignoring");
3937 p->nEndPos = p->nStartPos = WW8_CP_MAX;
3938 return;
3941 if (!m_pText)
3942 return;
3944 m_pText->SetIdx(nNr);
3946 if (!m_pText->Get(p->nCp2OrIdx, p->nSprmsLen, pData))
3948 p->nEndPos = p->nStartPos = WW8_CP_MAX;
3949 p->nSprmsLen = 0;
3950 return;
3953 if (p->nCp2OrIdx < 0 || p->nCp2OrIdx > p->nSprmsLen)
3955 SAL_WARN("sw.ww8", "Document has invalid Cp or Idx, ignoring it");
3956 p->nEndPos = p->nStartPos = WW8_CP_MAX;
3957 p->nSprmsLen = 0;
3958 return;
3961 p->nSprmsLen -= p->nCp2OrIdx;
3964 void WW8PLCFx_SubDoc::advance()
3966 if (m_pRef && m_pText)
3968 m_pRef->advance();
3969 m_pText->advance();
3973 // fields
3974 WW8PLCFx_FLD::WW8PLCFx_FLD( SvStream* pSt, const WW8Fib& rMyFib, short nType)
3975 : WW8PLCFx(rMyFib, true), m_rFib(rMyFib)
3977 WW8_FC nFc;
3978 sal_Int32 nLen;
3980 switch( nType )
3982 case MAN_HDFT:
3983 nFc = m_rFib.m_fcPlcffldHdr;
3984 nLen = m_rFib.m_lcbPlcffldHdr;
3985 break;
3986 case MAN_FTN:
3987 nFc = m_rFib.m_fcPlcffldFootnote;
3988 nLen = m_rFib.m_lcbPlcffldFootnote;
3989 break;
3990 case MAN_EDN:
3991 nFc = m_rFib.m_fcPlcffldEdn;
3992 nLen = m_rFib.m_lcbPlcffldEdn;
3993 break;
3994 case MAN_AND:
3995 nFc = m_rFib.m_fcPlcffldAtn;
3996 nLen = m_rFib.m_lcbPlcffldAtn;
3997 break;
3998 case MAN_TXBX:
3999 nFc = m_rFib.m_fcPlcffldTxbx;
4000 nLen = m_rFib.m_lcbPlcffldTxbx;
4001 break;
4002 case MAN_TXBX_HDFT:
4003 nFc = m_rFib.m_fcPlcffldHdrTxbx;
4004 nLen = m_rFib.m_lcbPlcffldHdrTxbx;
4005 break;
4006 default:
4007 nFc = m_rFib.m_fcPlcffldMom;
4008 nLen = m_rFib.m_lcbPlcffldMom;
4009 break;
4012 if( nLen )
4013 m_pPLCF.reset( new WW8PLCFspecial( pSt, nFc, nLen, 2 ) );
4016 WW8PLCFx_FLD::~WW8PLCFx_FLD()
4020 sal_uInt32 WW8PLCFx_FLD::GetIdx() const
4022 return m_pPLCF ? m_pPLCF->GetIdx() : 0;
4025 void WW8PLCFx_FLD::SetIdx(sal_uInt32 nIdx)
4027 if( m_pPLCF )
4028 m_pPLCF->SetIdx( nIdx );
4031 bool WW8PLCFx_FLD::SeekPos(WW8_CP nCpPos)
4033 return m_pPLCF && m_pPLCF->SeekPosExact( nCpPos );
4036 WW8_CP WW8PLCFx_FLD::Where()
4038 return m_pPLCF ? m_pPLCF->Where() : WW8_CP_MAX;
4041 bool WW8PLCFx_FLD::StartPosIsFieldStart()
4043 void* pData;
4044 sal_Int32 nTest;
4045 return m_pPLCF && m_pPLCF->Get(nTest, pData) && ((static_cast<sal_uInt8*>(pData)[0] & 0x1f) == 0x13);
4048 bool WW8PLCFx_FLD::EndPosIsFieldEnd(WW8_CP& nCP)
4050 bool bRet = false;
4052 if (m_pPLCF)
4054 tools::Long n = m_pPLCF->GetIdx();
4056 m_pPLCF->advance();
4058 void* pData;
4059 sal_Int32 nTest;
4060 if ( m_pPLCF->Get(nTest, pData) && ((static_cast<sal_uInt8*>(pData)[0] & 0x1f) == 0x15) )
4062 nCP = nTest;
4063 bRet = true;
4066 m_pPLCF->SetIdx(n);
4069 return bRet;
4072 void WW8PLCFx_FLD::GetSprms(WW8PLCFxDesc* p)
4074 p->nStartPos = p->nEndPos = WW8_CP_MAX;
4075 p->pMemPos = nullptr;
4076 p->nSprmsLen = 0;
4077 p->bRealLineEnd = false;
4079 if (!m_pPLCF)
4081 p->nStartPos = WW8_CP_MAX; // there are no fields
4082 return;
4085 tools::Long n = m_pPLCF->GetIdx();
4087 sal_Int32 nP;
4088 void *pData;
4089 if (!m_pPLCF->Get(nP, pData)) // end of PLCFspecial?
4091 p->nStartPos = WW8_CP_MAX; // PLCF completely processed
4092 return;
4095 p->nStartPos = nP;
4097 m_pPLCF->advance();
4098 if (!m_pPLCF->Get(nP, pData)) // end of PLCFspecial?
4100 p->nStartPos = WW8_CP_MAX; // PLCF completely processed
4101 return;
4104 p->nEndPos = nP;
4106 m_pPLCF->SetIdx(n);
4108 p->nCp2OrIdx = m_pPLCF->GetIdx();
4111 void WW8PLCFx_FLD::advance()
4113 SAL_WARN_IF(!m_pPLCF, "sw.ww8", "Call without PLCFspecial field");
4114 if( !m_pPLCF )
4115 return;
4116 m_pPLCF->advance();
4119 bool WW8PLCFx_FLD::GetPara(tools::Long nIdx, WW8FieldDesc& rF)
4121 SAL_WARN_IF(!m_pPLCF, "sw.ww8", "Call without PLCFspecial field");
4122 if( !m_pPLCF )
4123 return false;
4125 tools::Long n = m_pPLCF->GetIdx();
4126 m_pPLCF->SetIdx(nIdx);
4128 bool bOk = WW8GetFieldPara(*m_pPLCF, rF);
4130 m_pPLCF->SetIdx(n);
4131 return bOk;
4134 // WW8PLCF_Book
4135 void WW8ReadSTTBF(bool bVer8, SvStream& rStrm, sal_uInt32 nStart, sal_Int32 nLen,
4136 sal_uInt16 nExtraLen, rtl_TextEncoding eCS, std::vector<OUString> &rArray,
4137 std::vector<ww::bytes>* pExtraArray, std::vector<OUString>* pValueArray)
4139 if (nLen==0) // Handle Empty STTBF
4140 return;
4142 sal_uInt64 const nOldPos = rStrm.Tell();
4143 if (checkSeek(rStrm, nStart))
4145 sal_uInt16 nLen2(0);
4146 rStrm.ReadUInt16( nLen2 ); // bVer67: total length of structure
4147 // bVer8 : count of strings
4149 if( bVer8 )
4151 sal_uInt16 nStrings(0);
4152 bool bUnicode = (0xFFFF == nLen2);
4153 if (bUnicode)
4154 rStrm.ReadUInt16( nStrings );
4155 else
4156 nStrings = nLen2;
4158 rStrm.ReadUInt16( nExtraLen );
4160 const size_t nMinStringLen = bUnicode ? sizeof(sal_uInt16) : sizeof(sal_uInt8);
4161 const size_t nMinRecordSize = nExtraLen + nMinStringLen;
4162 assert(nMinRecordSize != 0 && "impossible to be zero");
4163 const size_t nMaxPossibleStrings = rStrm.remainingSize() / nMinRecordSize;
4164 if (nStrings > nMaxPossibleStrings)
4166 SAL_WARN("sw.ww8", "STTBF claims " << nStrings << " entries, but only " << nMaxPossibleStrings << " are possible");
4167 nStrings = nMaxPossibleStrings;
4170 if (nExtraLen && nStrings)
4172 const size_t nMaxExtraLen = (rStrm.remainingSize() - (nStrings * nMinStringLen)) / nStrings;
4173 if (nExtraLen > nMaxExtraLen)
4175 SAL_WARN("sw.ww8", "STTBF claims " << nMaxExtraLen << " extra len, but only " << nMaxExtraLen << " are possible");
4176 nExtraLen = nMaxExtraLen;
4180 for (sal_uInt16 i=0; i < nStrings; ++i)
4182 if (bUnicode)
4183 rArray.push_back(read_uInt16_PascalString(rStrm));
4184 else
4186 OString aTmp = read_uInt8_lenPrefixed_uInt8s_ToOString(rStrm);
4187 rArray.push_back(OStringToOUString(aTmp, eCS));
4190 // Skip the extra data
4191 if (nExtraLen)
4193 if (pExtraArray)
4195 ww::bytes extraData(nExtraLen);
4196 rStrm.ReadBytes(extraData.data(), nExtraLen);
4197 pExtraArray->push_back(extraData);
4199 else
4200 rStrm.SeekRel( nExtraLen );
4203 // read the value of the document variables, if requested.
4204 if (pValueArray)
4206 for (sal_uInt16 i=0; i < nStrings; ++i)
4208 if( bUnicode )
4209 pValueArray->push_back(read_uInt16_PascalString(rStrm));
4210 else
4212 OString aTmp = read_uInt8_lenPrefixed_uInt8s_ToOString(rStrm);
4213 pValueArray->push_back(OStringToOUString(aTmp, eCS));
4218 else
4220 if( nLen2 != nLen )
4222 OSL_ENSURE(nLen2 == nLen,
4223 "Fib length and read length are different");
4224 if (nLen > SAL_MAX_UINT16)
4225 nLen = SAL_MAX_UINT16;
4226 else if (nLen < 2 )
4227 nLen = 2;
4228 nLen2 = o3tl::narrowing<sal_uInt16>(nLen);
4230 sal_uLong nRead = 2;
4231 while (nRead < nLen2)
4233 sal_uInt8 nBChar(0);
4234 rStrm.ReadUChar( nBChar );
4235 ++nRead;
4236 if (nBChar)
4238 OString aTmp = read_uInt8s_ToOString(rStrm, nBChar);
4239 nRead += aTmp.getLength();
4240 rArray.push_back(OStringToOUString(aTmp, eCS));
4242 else
4243 rArray.emplace_back();
4245 // Skip the extra data (for bVer67 versions this must come from
4246 // external knowledge)
4247 if (nExtraLen)
4249 if (pExtraArray)
4251 ww::bytes extraData(nExtraLen);
4252 rStrm.ReadBytes(extraData.data(), nExtraLen);
4253 pExtraArray->push_back(extraData);
4255 else
4256 rStrm.SeekRel( nExtraLen );
4257 nRead+=nExtraLen;
4262 rStrm.Seek(nOldPos);
4265 WW8PLCFx_Book::WW8PLCFx_Book(SvStream* pTableSt, const WW8Fib& rFib)
4266 : WW8PLCFx(rFib, false), m_nIsEnd(0), m_nBookmarkId(1)
4268 if( !rFib.m_fcPlcfbkf || !rFib.m_lcbPlcfbkf || !rFib.m_fcPlcfbkl ||
4269 !rFib.m_lcbPlcfbkl || !rFib.m_fcSttbfbkmk || !rFib.m_lcbSttbfbkmk )
4271 m_nIMax = 0;
4273 else
4275 m_pBook[0].reset( new WW8PLCFspecial(pTableSt,rFib.m_fcPlcfbkf,rFib.m_lcbPlcfbkf,4) );
4277 m_pBook[1].reset( new WW8PLCFspecial(pTableSt,rFib.m_fcPlcfbkl,rFib.m_lcbPlcfbkl,0) );
4279 rtl_TextEncoding eStructChrSet = WW8Fib::GetFIBCharset(rFib.m_chseTables, rFib.m_lid);
4281 WW8ReadSTTBF( (7 < rFib.m_nVersion), *pTableSt, rFib.m_fcSttbfbkmk,
4282 rFib.m_lcbSttbfbkmk, 0, eStructChrSet, m_aBookNames );
4284 m_nIMax = m_aBookNames.size();
4286 if( m_pBook[0]->GetIMax() < m_nIMax ) // Count of Bookmarks
4287 m_nIMax = m_pBook[0]->GetIMax();
4288 if( m_pBook[1]->GetIMax() < m_nIMax )
4289 m_nIMax = m_pBook[1]->GetIMax();
4290 m_aStatus.resize(m_nIMax);
4294 WW8PLCFx_Book::~WW8PLCFx_Book()
4298 sal_uInt32 WW8PLCFx_Book::GetIdx() const
4300 return m_nIMax ? m_pBook[0]->GetIdx() : 0;
4303 void WW8PLCFx_Book::SetIdx(sal_uInt32 nI)
4305 if( m_nIMax )
4306 m_pBook[0]->SetIdx( nI );
4309 sal_uInt32 WW8PLCFx_Book::GetIdx2() const
4311 return m_nIMax ? ( m_pBook[1]->GetIdx() | ( m_nIsEnd ? 0x80000000 : 0 ) ) : 0;
4314 void WW8PLCFx_Book::SetIdx2(sal_uInt32 nI)
4316 if( m_nIMax )
4318 m_pBook[1]->SetIdx( nI & 0x7fffffff );
4319 m_nIsEnd = o3tl::narrowing<sal_uInt16>( ( nI >> 31 ) & 1 ); // 0 or 1
4323 bool WW8PLCFx_Book::SeekPos(WW8_CP nCpPos)
4325 if( !m_pBook[0] )
4326 return false;
4328 bool bOk = m_pBook[0]->SeekPosExact( nCpPos );
4329 bOk &= m_pBook[1]->SeekPosExact( nCpPos );
4330 m_nIsEnd = 0;
4332 return bOk;
4335 WW8_CP WW8PLCFx_Book::Where()
4337 return m_pBook[m_nIsEnd]->Where();
4340 tools::Long WW8PLCFx_Book::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
4342 void* pData;
4343 rEnd = WW8_CP_MAX;
4344 rLen = 0;
4346 if (!m_pBook[0] || !m_pBook[1] || !m_nIMax || (m_pBook[m_nIsEnd]->GetIdx()) >= m_nIMax)
4348 rStart = rEnd = WW8_CP_MAX;
4349 return -1;
4352 (void)m_pBook[m_nIsEnd]->Get( rStart, pData ); // query position
4353 return m_pBook[m_nIsEnd]->GetIdx();
4356 // The operator ++ has a pitfall: If 2 bookmarks adjoin each other,
4357 // we should first go to the end of the first one
4358 // and then to the beginning of the second one.
4359 // But if 2 bookmarks with the length of 0 lie on top of each other,
4360 // we *must* first find the start and end of each bookmark.
4361 // The case of: ][
4362 // [...]
4363 // ][
4364 // is not solved yet.
4365 // Because I must jump back and forth in the start- and end-indices then.
4366 // This would require one more index or bitfield to remember
4367 // the already processed bookmarks.
4369 void WW8PLCFx_Book::advance()
4371 if( !(m_pBook[0] && m_pBook[1] && m_nIMax) )
4372 return;
4374 (*m_pBook[m_nIsEnd]).advance();
4376 sal_uLong l0 = m_pBook[0]->Where();
4377 sal_uLong l1 = m_pBook[1]->Where();
4378 if( l0 < l1 )
4379 m_nIsEnd = 0;
4380 else if( l1 < l0 )
4381 m_nIsEnd = 1;
4382 else
4384 const void * p = m_pBook[0]->GetData(m_pBook[0]->GetIdx());
4385 tools::Long nPairFor = (p == nullptr) ? 0 : SVBT16ToUInt16(*static_cast<SVBT16 const *>(p));
4386 if (nPairFor == m_pBook[1]->GetIdx())
4387 m_nIsEnd = 0;
4388 else
4389 m_nIsEnd = m_nIsEnd ? 0 : 1;
4393 tools::Long WW8PLCFx_Book::GetLen() const
4395 if( m_nIsEnd )
4397 OSL_ENSURE( false, "Incorrect call (1) of PLCF_Book::GetLen()" );
4398 return 0;
4400 void * p;
4401 WW8_CP nStartPos;
4402 if( !m_pBook[0]->Get( nStartPos, p ) )
4404 OSL_ENSURE( false, "Incorrect call (2) of PLCF_Book::GetLen()" );
4405 return 0;
4407 const sal_uInt16 nEndIdx = SVBT16ToUInt16( *static_cast<SVBT16*>(p) );
4408 tools::Long nNum = m_pBook[1]->GetPos( nEndIdx );
4409 nNum -= nStartPos;
4410 return nNum;
4413 void WW8PLCFx_Book::SetStatus(sal_uInt16 nIndex, eBookStatus eStat)
4415 SAL_WARN_IF(nIndex >= m_nIMax, "sw.ww8",
4416 "bookmark index " << nIndex << " invalid");
4417 eBookStatus eStatus = m_aStatus.at(nIndex);
4418 m_aStatus[nIndex] = static_cast<eBookStatus>(eStatus | eStat);
4421 eBookStatus WW8PLCFx_Book::GetStatus() const
4423 if (m_aStatus.empty())
4424 return BOOK_NORMAL;
4425 tools::Long nEndIdx = GetHandle();
4426 return ( nEndIdx < m_nIMax ) ? m_aStatus[nEndIdx] : BOOK_NORMAL;
4429 tools::Long WW8PLCFx_Book::GetHandle() const
4431 if( !m_pBook[0] || !m_pBook[1] )
4432 return LONG_MAX;
4434 if( m_nIsEnd )
4435 return m_pBook[1]->GetIdx();
4436 else
4438 if (const void* p = m_pBook[0]->GetData(m_pBook[0]->GetIdx()))
4439 return SVBT16ToUInt16( *static_cast<SVBT16 const *>(p) );
4440 else
4441 return LONG_MAX;
4445 OUString WW8PLCFx_Book::GetBookmark(tools::Long nStart,tools::Long nEnd, sal_uInt16 &nIndex)
4447 bool bFound = false;
4448 sal_uInt16 i = 0;
4449 if (m_pBook[0] && m_pBook[1])
4451 WW8_CP nStartCurrent, nEndCurrent;
4452 while (sal::static_int_cast<decltype(m_aBookNames)::size_type>(i) < m_aBookNames.size())
4454 void* p;
4455 sal_uInt16 nEndIdx;
4457 if( m_pBook[0]->GetData( i, nStartCurrent, p ) && p )
4458 nEndIdx = SVBT16ToUInt16( *static_cast<SVBT16*>(p) );
4459 else
4461 OSL_ENSURE( false, "Bookmark-EndIdx not readable" );
4462 nEndIdx = i;
4465 nEndCurrent = m_pBook[1]->GetPos( nEndIdx );
4467 if ((nStartCurrent >= nStart) && (nEndCurrent <= nEnd))
4469 nIndex = i;
4470 bFound=true;
4471 break;
4473 ++i;
4476 return bFound ? m_aBookNames[i] : OUString();
4479 OUString WW8PLCFx_Book::GetUniqueBookmarkName(const OUString &rSuggestedName)
4481 OUString aRet(rSuggestedName.isEmpty() ? u"Unnamed"_ustr : rSuggestedName);
4482 size_t i = 0;
4483 while (i < m_aBookNames.size())
4485 if (aRet == m_aBookNames[i])
4487 sal_Int32 len = aRet.getLength();
4488 sal_Int32 p = len - 1;
4489 while (p > 0 && aRet[p] >= '0' && aRet[p] <= '9')
4490 --p;
4491 aRet = aRet.subView(0, p+1) + OUString::number(m_nBookmarkId++);
4492 i = 0; // start search from beginning
4494 else
4495 ++i;
4497 return aRet;
4500 void WW8PLCFx_Book::MapName(OUString& rName)
4502 if( !m_pBook[0] || !m_pBook[1] )
4503 return;
4505 size_t i = 0;
4506 while (i < m_aBookNames.size())
4508 if (rName.equalsIgnoreAsciiCase(m_aBookNames[i]))
4510 rName = m_aBookNames[i];
4511 break;
4513 ++i;
4517 const OUString* WW8PLCFx_Book::GetName() const
4519 const OUString *pRet = nullptr;
4520 if (!m_nIsEnd && (m_pBook[0]->GetIdx() < m_nIMax))
4521 pRet = &(m_aBookNames[m_pBook[0]->GetIdx()]);
4522 return pRet;
4525 WW8PLCFx_AtnBook::WW8PLCFx_AtnBook(SvStream* pTableSt, const WW8Fib& rFib)
4526 : WW8PLCFx(rFib, /*bSprm=*/false),
4527 m_bIsEnd(false)
4529 if (!rFib.m_fcPlcfAtnbkf || !rFib.m_lcbPlcfAtnbkf || !rFib.m_fcPlcfAtnbkl || !rFib.m_lcbPlcfAtnbkl)
4531 m_nIMax = 0;
4533 else
4535 m_pBook[0].reset( new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfAtnbkf, rFib.m_lcbPlcfAtnbkf, 4) );
4536 m_pBook[1].reset( new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfAtnbkl, rFib.m_lcbPlcfAtnbkl, 0) );
4538 m_nIMax = m_pBook[0]->GetIMax();
4539 if (m_pBook[1]->GetIMax() < m_nIMax)
4540 m_nIMax = m_pBook[1]->GetIMax();
4544 WW8PLCFx_AtnBook::~WW8PLCFx_AtnBook()
4548 sal_uInt32 WW8PLCFx_AtnBook::GetIdx() const
4550 return m_nIMax ? m_pBook[0]->GetIdx() : 0;
4553 void WW8PLCFx_AtnBook::SetIdx(sal_uInt32 nI)
4555 if( m_nIMax )
4556 m_pBook[0]->SetIdx( nI );
4559 sal_uInt32 WW8PLCFx_AtnBook::GetIdx2() const
4561 if (m_nIMax)
4562 return m_pBook[1]->GetIdx() | ( m_bIsEnd ? 0x80000000 : 0 );
4563 else
4564 return 0;
4567 void WW8PLCFx_AtnBook::SetIdx2(sal_uInt32 nI)
4569 if( m_nIMax )
4571 m_pBook[1]->SetIdx( nI & 0x7fffffff );
4572 m_bIsEnd = static_cast<bool>(( nI >> 31 ) & 1);
4576 bool WW8PLCFx_AtnBook::SeekPos(WW8_CP nCpPos)
4578 if (!m_pBook[0])
4579 return false;
4581 bool bOk = m_pBook[0]->SeekPosExact(nCpPos);
4582 bOk &= m_pBook[1]->SeekPosExact(nCpPos);
4583 m_bIsEnd = false;
4585 return bOk;
4588 WW8_CP WW8PLCFx_AtnBook::Where()
4590 return m_pBook[static_cast<int>(m_bIsEnd)]->Where();
4593 tools::Long WW8PLCFx_AtnBook::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
4595 void* pData;
4596 rEnd = WW8_CP_MAX;
4597 rLen = 0;
4599 if (!m_pBook[0] || !m_pBook[1] || !m_nIMax || (m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx()) >= m_nIMax)
4601 rStart = rEnd = WW8_CP_MAX;
4602 return -1;
4605 (void)m_pBook[static_cast<int>(m_bIsEnd)]->Get(rStart, pData);
4606 return m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx();
4609 void WW8PLCFx_AtnBook::advance()
4611 if( !(m_pBook[0] && m_pBook[1] && m_nIMax) )
4612 return;
4614 (*m_pBook[static_cast<int>(m_bIsEnd)]).advance();
4616 sal_uLong l0 = m_pBook[0]->Where();
4617 sal_uLong l1 = m_pBook[1]->Where();
4618 if( l0 < l1 )
4619 m_bIsEnd = false;
4620 else if( l1 < l0 )
4621 m_bIsEnd = true;
4622 else
4624 const void * p = m_pBook[0]->GetData(m_pBook[0]->GetIdx());
4625 tools::Long nPairFor = (p == nullptr) ? 0 : SVBT16ToUInt16(*static_cast<SVBT16 const *>(p));
4626 if (nPairFor == m_pBook[1]->GetIdx())
4627 m_bIsEnd = false;
4628 else
4629 m_bIsEnd = !m_bIsEnd;
4633 tools::Long WW8PLCFx_AtnBook::getHandle() const
4635 if (!m_pBook[0] || !m_pBook[1])
4636 return LONG_MAX;
4638 if (m_bIsEnd)
4639 return m_pBook[1]->GetIdx();
4640 else
4642 if (const void* p = m_pBook[0]->GetData(m_pBook[0]->GetIdx()))
4643 return SVBT16ToUInt16(*static_cast<const SVBT16*>(p));
4644 else
4645 return LONG_MAX;
4649 bool WW8PLCFx_AtnBook::getIsEnd() const
4651 return m_bIsEnd;
4654 WW8PLCFx_FactoidBook::WW8PLCFx_FactoidBook(SvStream* pTableSt, const WW8Fib& rFib)
4655 : WW8PLCFx(rFib, /*bSprm=*/false),
4656 m_bIsEnd(false)
4658 if (!rFib.m_fcPlcfBkfFactoid || !rFib.m_lcbPlcfBkfFactoid || !rFib.m_fcPlcfBklFactoid || !rFib.m_lcbPlcfBklFactoid)
4660 m_nIMax = 0;
4662 else
4664 m_pBook[0].reset(new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfBkfFactoid, rFib.m_lcbPlcfBkfFactoid, 6));
4665 m_pBook[1].reset(new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfBklFactoid, rFib.m_lcbPlcfBklFactoid, 4));
4667 m_nIMax = m_pBook[0]->GetIMax();
4668 if (m_pBook[1]->GetIMax() < m_nIMax)
4669 m_nIMax = m_pBook[1]->GetIMax();
4673 WW8PLCFx_FactoidBook::~WW8PLCFx_FactoidBook()
4677 sal_uInt32 WW8PLCFx_FactoidBook::GetIdx() const
4679 return m_nIMax ? m_pBook[0]->GetIdx() : 0;
4682 void WW8PLCFx_FactoidBook::SetIdx(sal_uInt32 nI)
4684 if (m_nIMax)
4685 m_pBook[0]->SetIdx(nI);
4688 sal_uInt32 WW8PLCFx_FactoidBook::GetIdx2() const
4690 if (m_nIMax)
4691 return m_pBook[1]->GetIdx() | (m_bIsEnd ? 0x80000000 : 0);
4692 else
4693 return 0;
4696 void WW8PLCFx_FactoidBook::SetIdx2(sal_uInt32 nI)
4698 if (m_nIMax)
4700 m_pBook[1]->SetIdx(nI & 0x7fffffff);
4701 m_bIsEnd = static_cast<bool>((nI >> 31) & 1);
4705 bool WW8PLCFx_FactoidBook::SeekPos(WW8_CP nCpPos)
4707 if (!m_pBook[0])
4708 return false;
4710 bool bOk = m_pBook[0]->SeekPosExact(nCpPos);
4711 bOk &= m_pBook[1]->SeekPosExact(nCpPos);
4712 m_bIsEnd = false;
4714 return bOk;
4717 WW8_CP WW8PLCFx_FactoidBook::Where()
4719 return m_pBook[static_cast<int>(m_bIsEnd)]->Where();
4722 tools::Long WW8PLCFx_FactoidBook::GetNoSprms(WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen)
4724 void* pData;
4725 rEnd = WW8_CP_MAX;
4726 rLen = 0;
4728 if (!m_pBook[0] || !m_pBook[1] || !m_nIMax || (m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx()) >= m_nIMax)
4730 rStart = rEnd = WW8_CP_MAX;
4731 return -1;
4734 (void)m_pBook[static_cast<int>(m_bIsEnd)]->Get(rStart, pData);
4735 return m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx();
4738 void WW8PLCFx_FactoidBook::advance()
4740 if (!(m_pBook[0] && m_pBook[1] && m_nIMax))
4741 return;
4743 (*m_pBook[static_cast<int>(m_bIsEnd)]).advance();
4745 sal_uLong l0 = m_pBook[0]->Where();
4746 sal_uLong l1 = m_pBook[1]->Where();
4747 if (l0 < l1)
4748 m_bIsEnd = false;
4749 else if (l1 < l0)
4750 m_bIsEnd = true;
4751 else
4753 const void * p = m_pBook[0]->GetData(m_pBook[0]->GetIdx());
4754 tools::Long nPairFor = (p == nullptr) ? 0 : SVBT16ToUInt16(*static_cast<SVBT16 const *>(p));
4755 if (nPairFor == m_pBook[1]->GetIdx())
4756 m_bIsEnd = false;
4757 else
4758 m_bIsEnd = !m_bIsEnd;
4762 tools::Long WW8PLCFx_FactoidBook::getHandle() const
4764 if (!m_pBook[0] || !m_pBook[1])
4765 return LONG_MAX;
4767 if (m_bIsEnd)
4768 return m_pBook[1]->GetIdx();
4769 else
4771 if (const void* p = m_pBook[0]->GetData(m_pBook[0]->GetIdx()))
4772 return SVBT16ToUInt16(*static_cast<const SVBT16*>(p));
4773 else
4774 return LONG_MAX;
4778 bool WW8PLCFx_FactoidBook::getIsEnd() const
4780 return m_bIsEnd;
4783 // In the end of a paragraph in WW6 the attribute extends after the <CR>.
4784 // This will be reset by one character to be used with SW,
4785 // if we don't expect trouble thereby.
4786 void WW8PLCFMan::AdjustEnds( WW8PLCFxDesc& rDesc )
4788 // might be necessary to do this for pChp and/or pSep as well,
4789 // but its definitely the case for paragraphs that EndPos > StartPos
4790 // for a well formed paragraph as those always have a paragraph
4791 // <cr> in them
4792 if (&rDesc == m_pPap && rDesc.bRealLineEnd)
4794 if (rDesc.nStartPos == rDesc.nEndPos && rDesc.nEndPos != WW8_CP_MAX)
4796 SAL_WARN("sw.ww8", "WW8PLCFxDesc End same as Start, abandoning to avoid looping");
4797 rDesc.nEndPos = WW8_CP_MAX;
4801 //Store old end position for supercool new property finder that uses
4802 //cp instead of fc's as nature intended
4803 rDesc.nOrigEndPos = rDesc.nEndPos;
4804 rDesc.nOrigStartPos = rDesc.nStartPos;
4807 Normally given ^XXX{para end}^ we don't actually insert a para end
4808 character into the document, so we clip the para end property one to the
4809 left to make the para properties end when the paragraph text does. In a
4810 drawing textbox we actually do insert a para end character, so we don't
4811 clip it. Making the para end properties end after the para end char.
4813 if (GetDoingDrawTextBox())
4814 return;
4816 if ( (&rDesc == m_pPap) && rDesc.bRealLineEnd )
4818 if ( m_pPap->nEndPos != WW8_CP_MAX ) // Para adjust
4820 m_nLineEnd = m_pPap->nEndPos;// nLineEnd points *after* the <CR>
4821 m_pPap->nEndPos--; // shorten paragraph end by one character
4823 // Is there already a sep end, which points to the current paragraph end?
4824 // Then we also must shorten by one character
4825 if( m_pSep->nEndPos == m_nLineEnd )
4826 m_pSep->nEndPos--;
4829 else if (&rDesc == m_pSep)
4831 // Sep Adjust if end Char-Attr == paragraph end ...
4832 if( (rDesc.nEndPos == m_nLineEnd) && (rDesc.nEndPos > rDesc.nStartPos) )
4833 rDesc.nEndPos--; // ... then shorten by one character
4837 void WW8PLCFxDesc::ReduceByOffset()
4839 SAL_WARN_IF(WW8_CP_MAX != nStartPos && nStartPos > nEndPos, "sw.ww8",
4840 "End " << nEndPos << " before Start " << nStartPos);
4842 if( nStartPos != WW8_CP_MAX )
4845 ##516##,##517##
4846 Force the property change to happen at the beginning of this
4847 subdocument, same as in GetNewNoSprms, except that the target type is
4848 attributes attached to a piece that might span subdocument boundaries
4850 if (nCpOfs > nStartPos)
4851 nStartPos = 0;
4852 else
4853 nStartPos -= nCpOfs;
4855 if (nEndPos != WW8_CP_MAX)
4857 if (nCpOfs > nEndPos)
4859 SAL_WARN("sw.ww8", "broken subdocument piece entry");
4860 nEndPos = WW8_CP_MAX;
4862 else
4863 nEndPos -= nCpOfs;
4867 void WW8PLCFMan::GetNewSprms( WW8PLCFxDesc& rDesc )
4869 rDesc.pPLCFx->GetSprms(&rDesc);
4870 rDesc.ReduceByOffset();
4872 rDesc.bFirstSprm = true;
4873 AdjustEnds( rDesc );
4874 rDesc.nOrigSprmsLen = rDesc.nSprmsLen;
4877 void WW8PLCFMan::GetNewNoSprms( WW8PLCFxDesc& rDesc )
4879 rDesc.nCp2OrIdx = rDesc.pPLCFx->GetNoSprms(rDesc.nStartPos, rDesc.nEndPos,
4880 rDesc.nSprmsLen);
4882 SAL_WARN_IF(WW8_CP_MAX != rDesc.nStartPos && rDesc.nStartPos > rDesc.nEndPos, "sw.ww8",
4883 "End " << rDesc.nEndPos << " before Start " << rDesc.nStartPos);
4885 rDesc.ReduceByOffset();
4887 rDesc.bFirstSprm = true;
4888 rDesc.nOrigSprmsLen = rDesc.nSprmsLen;
4891 sal_uInt16 WW8PLCFMan::GetId(const WW8PLCFxDesc* p) const
4893 sal_uInt16 nId = 0; // Id = 0 for empty attributes
4895 if (p == m_pField)
4896 nId = eFLD;
4897 else if (p == m_pFootnote)
4898 nId = eFTN;
4899 else if (p == m_pEdn)
4900 nId = eEDN;
4901 else if (p == m_pAnd)
4902 nId = eAND;
4903 else if (p->nSprmsLen >= maSprmParser.MinSprmLen())
4904 nId = maSprmParser.GetSprmId(p->pMemPos);
4906 return nId;
4909 WW8PLCFMan::WW8PLCFMan(const WW8ScannerBase* pBase, ManTypes nType, tools::Long nStartCp,
4910 bool bDoingDrawTextBox)
4911 : maSprmParser(*pBase->m_pWw8Fib),
4912 m_nLineEnd(WW8_CP_MAX),
4913 mbDoingDrawTextBox(bDoingDrawTextBox)
4915 m_pWwFib = pBase->m_pWw8Fib;
4917 m_nManType = nType;
4919 if( MAN_MAINTEXT == nType )
4921 // search order of the attributes
4922 m_nPLCF = MAN_PLCF_COUNT;
4923 m_pField = &m_aD[0];
4924 m_pBkm = &m_aD[1];
4925 m_pEdn = &m_aD[2];
4926 m_pFootnote = &m_aD[3];
4927 m_pAnd = &m_aD[4];
4929 m_pPcd = pBase->m_pPLCFx_PCD ? &m_aD[5] : nullptr;
4930 //pPcdA index == pPcd index + 1
4931 m_pPcdA = pBase->m_pPLCFx_PCDAttrs ? &m_aD[6] : nullptr;
4933 m_pChp = &m_aD[7];
4934 m_pPap = &m_aD[8];
4935 m_pSep = &m_aD[9];
4936 m_pAtnBkm = &m_aD[10];
4937 m_pFactoidBkm = &m_aD[11];
4939 m_pSep->pPLCFx = pBase->m_pSepPLCF.get();
4940 m_pFootnote->pPLCFx = pBase->m_pFootnotePLCF.get();
4941 m_pEdn->pPLCFx = pBase->m_pEdnPLCF.get();
4942 m_pBkm->pPLCFx = pBase->m_pBook.get();
4943 m_pAnd->pPLCFx = pBase->m_pAndPLCF.get();
4944 m_pAtnBkm->pPLCFx = pBase->m_pAtnBook.get();
4945 m_pFactoidBkm->pPLCFx = pBase->m_pFactoidBook.get();
4948 else
4950 // search order of the attributes
4951 m_nPLCF = 7;
4952 m_pField = &m_aD[0];
4953 m_pBkm = pBase->m_pBook ? &m_aD[1] : nullptr;
4955 m_pPcd = pBase->m_pPLCFx_PCD ? &m_aD[2] : nullptr;
4956 //pPcdA index == pPcd index + 1
4957 m_pPcdA= pBase->m_pPLCFx_PCDAttrs ? &m_aD[3] : nullptr;
4959 m_pChp = &m_aD[4];
4960 m_pPap = &m_aD[5];
4961 m_pSep = &m_aD[6]; // Dummy
4963 m_pAnd = m_pAtnBkm = m_pFactoidBkm = m_pFootnote = m_pEdn = nullptr; // not used at SpezText
4966 m_pChp->pPLCFx = pBase->m_pChpPLCF.get();
4967 m_pPap->pPLCFx = pBase->m_pPapPLCF.get();
4968 if( m_pPcd )
4969 m_pPcd->pPLCFx = pBase->m_pPLCFx_PCD.get();
4970 if( m_pPcdA )
4971 m_pPcdA->pPLCFx= pBase->m_pPLCFx_PCDAttrs.get();
4972 if( m_pBkm )
4973 m_pBkm->pPLCFx = pBase->m_pBook.get();
4975 m_pMagicTables = pBase->m_pMagicTables.get();
4976 m_pSubdocs = pBase->m_pSubdocs.get();
4977 m_pExtendedAtrds = pBase->m_pExtendedAtrds.get();
4979 switch( nType ) // field initialization
4981 case MAN_HDFT:
4982 m_pField->pPLCFx = pBase->m_pFieldHdFtPLCF.get();
4983 m_pFdoa = pBase->m_pHdFtFdoa.get();
4984 m_pTxbx = pBase->m_pHdFtTxbx.get();
4985 m_pTxbxBkd = pBase->m_pHdFtTxbxBkd.get();
4986 break;
4987 case MAN_FTN:
4988 m_pField->pPLCFx = pBase->m_pFieldFootnotePLCF.get();
4989 m_pFdoa = m_pTxbx = m_pTxbxBkd = nullptr;
4990 break;
4991 case MAN_EDN:
4992 m_pField->pPLCFx = pBase->m_pFieldEdnPLCF.get();
4993 m_pFdoa = m_pTxbx = m_pTxbxBkd = nullptr;
4994 break;
4995 case MAN_AND:
4996 m_pField->pPLCFx = pBase->m_pFieldAndPLCF.get();
4997 m_pFdoa = m_pTxbx = m_pTxbxBkd = nullptr;
4998 break;
4999 case MAN_TXBX:
5000 m_pField->pPLCFx = pBase->m_pFieldTxbxPLCF.get();
5001 m_pTxbx = pBase->m_pMainTxbx.get();
5002 m_pTxbxBkd = pBase->m_pMainTxbxBkd.get();
5003 m_pFdoa = nullptr;
5004 break;
5005 case MAN_TXBX_HDFT:
5006 m_pField->pPLCFx = pBase->m_pFieldTxbxHdFtPLCF.get();
5007 m_pTxbx = pBase->m_pHdFtTxbx.get();
5008 m_pTxbxBkd = pBase->m_pHdFtTxbxBkd.get();
5009 m_pFdoa = nullptr;
5010 break;
5011 default:
5012 m_pField->pPLCFx = pBase->m_pFieldPLCF.get();
5013 m_pFdoa = pBase->m_pMainFdoa.get();
5014 m_pTxbx = pBase->m_pMainTxbx.get();
5015 m_pTxbxBkd = pBase->m_pMainTxbxBkd.get();
5016 break;
5019 WW8_CP cp = 0;
5020 m_pWwFib->GetBaseCp(nType, &cp); //TODO: check return value
5021 m_nCpO = cp;
5023 if( nStartCp || m_nCpO )
5024 SeekPos( nStartCp ); // adjust PLCFe at text StartPos
5026 // initialization to the member vars Low-Level
5027 GetChpPLCF()->ResetAttrStartEnd();
5028 GetPapPLCF()->ResetAttrStartEnd();
5029 for( sal_uInt16 i=0; i < m_nPLCF; ++i)
5031 WW8PLCFxDesc* p = &m_aD[i];
5034 ##516##,##517##
5035 For subdocuments we modify the cp of properties to be relative to
5036 the beginning of subdocuments, we should also do the same for
5037 piecetable changes, and piecetable properties, otherwise a piece
5038 change that happens in a subdocument is lost.
5040 p->nCpOfs = ( p == m_pChp || p == m_pPap || p == m_pBkm || p == m_pPcd ||
5041 p == m_pPcdA ) ? m_nCpO : 0;
5043 p->nCp2OrIdx = 0;
5044 p->bFirstSprm = false;
5045 p->xIdStack.reset();
5047 if ((p == m_pChp) || (p == m_pPap))
5048 p->nStartPos = p->nEndPos = nStartCp;
5049 else
5050 p->nStartPos = p->nEndPos = WW8_CP_MAX;
5053 // initialization to the member vars High-Level
5054 for( sal_uInt16 i=0; i<m_nPLCF; ++i){
5055 WW8PLCFxDesc* p = &m_aD[i];
5057 if( !p->pPLCFx )
5059 p->nStartPos = p->nEndPos = WW8_CP_MAX;
5060 continue;
5063 if( p->pPLCFx->IsSprm() )
5065 // Careful: nEndPos must be
5066 p->xIdStack.emplace();
5067 if ((p == m_pChp) || (p == m_pPap))
5069 WW8_CP nTemp = p->nEndPos+p->nCpOfs;
5070 p->pMemPos = nullptr;
5071 p->nSprmsLen = 0;
5072 p->nStartPos = nTemp;
5073 if (!(*p->pPLCFx).SeekPos(p->nStartPos))
5074 p->nEndPos = p->nStartPos = WW8_CP_MAX;
5075 else
5076 GetNewSprms( *p );
5078 else
5079 GetNewSprms( *p ); // initialized at all PLCFs
5081 else if( p->pPLCFx )
5082 GetNewNoSprms( *p );
5086 WW8PLCFMan::~WW8PLCFMan()
5088 for( sal_uInt16 i=0; i<m_nPLCF; i++)
5089 m_aD[i].xIdStack.reset();
5092 // 0. which attr class,
5093 // 1. if it's an attr start,
5094 // 2. CP, where is next attr change
5095 sal_uInt16 WW8PLCFMan::WhereIdx(bool *const pbStart, WW8_CP *const pPos) const
5097 OSL_ENSURE(m_nPLCF,"What the hell");
5098 WW8_CP nNext = WW8_CP_MAX; // search order:
5099 sal_uInt16 nNextIdx = m_nPLCF;// first ending found ( CHP, PAP, ( SEP ) ),
5100 bool bStart = true; // now find beginnings ( ( SEP ), PAP, CHP )
5101 const WW8PLCFxDesc* pD;
5102 for (sal_uInt16 i=0; i < m_nPLCF; ++i)
5104 pD = &m_aD[i];
5105 if (pD != m_pPcdA)
5107 if( (pD->nEndPos < nNext) && (pD->nStartPos == WW8_CP_MAX) )
5109 // otherwise start = end
5110 nNext = pD->nEndPos;
5111 nNextIdx = i;
5112 bStart = false;
5116 for (sal_uInt16 i=m_nPLCF; i > 0; --i)
5118 pD = &m_aD[i-1];
5119 if (pD != m_pPcdA && pD->nStartPos < nNext )
5121 nNext = pD->nStartPos;
5122 nNextIdx = i-1;
5123 bStart = true;
5126 if( pPos )
5127 *pPos = nNext;
5128 if( pbStart )
5129 *pbStart = bStart;
5130 return nNextIdx;
5133 // gives the CP pos of the next attr change
5134 WW8_CP WW8PLCFMan::Where() const
5136 WW8_CP l;
5137 WhereIdx(nullptr, &l);
5138 return l;
5141 void WW8PLCFMan::SeekPos( tools::Long nNewCp )
5143 m_pChp->pPLCFx->SeekPos( nNewCp + m_nCpO ); // create new attr
5144 m_pPap->pPLCFx->SeekPos( nNewCp + m_nCpO );
5145 m_pField->pPLCFx->SeekPos( nNewCp );
5146 if( m_pPcd )
5147 m_pPcd->pPLCFx->SeekPos( nNewCp + m_nCpO );
5148 if( m_pBkm )
5149 m_pBkm->pPLCFx->SeekPos( nNewCp + m_nCpO );
5152 void WW8PLCFMan::SaveAllPLCFx( WW8PLCFxSaveAll& rSave ) const
5154 sal_uInt16 n=0;
5155 if( m_pPcd )
5156 m_pPcd->Save( rSave.aS[n++] );
5157 if( m_pPcdA )
5158 m_pPcdA->Save( rSave.aS[n++] );
5160 for(sal_uInt16 i=0; i<m_nPLCF; ++i)
5161 if( m_pPcd != &m_aD[i] && m_pPcdA != &m_aD[i] )
5162 m_aD[i].Save( rSave.aS[n++] );
5165 void WW8PLCFMan::RestoreAllPLCFx( const WW8PLCFxSaveAll& rSave )
5167 sal_uInt16 n=0;
5168 if( m_pPcd )
5169 m_pPcd->Restore( rSave.aS[n++] );
5170 if( m_pPcdA )
5171 m_pPcdA->Restore( rSave.aS[n++] );
5173 for(sal_uInt16 i=0; i<m_nPLCF; ++i)
5174 if( m_pPcd != &m_aD[i] && m_pPcdA != &m_aD[i] )
5175 m_aD[i].Restore( rSave.aS[n++] );
5178 namespace
5180 bool IsSizeLegal(tools::Long nSprmLen, sal_Int32 nSprmsLen)
5182 if (nSprmLen > nSprmsLen)
5184 SAL_WARN("sw.ww8", "Short sprm, len " << nSprmLen << " claimed, max possible is " << nSprmsLen);
5185 return false;
5187 return true;
5191 bool WW8PLCFMan::IsSprmLegalForCategory(sal_uInt16 nSprmId, short nIdx) const
5193 const WW8PLCFxDesc* p = &m_aD[nIdx];
5194 if (p != m_pSep) // just check sep for now
5195 return true;
5197 bool bRet;
5198 ww::WordVersion eVersion = maSprmParser.GetFIBVersion();
5199 if (eVersion <= ww::eWW2)
5200 bRet = nSprmId >= 112 && nSprmId <= 145;
5201 else if (eVersion < ww::eWW8)
5202 bRet = nSprmId >= NS_sprm::v6::sprmSScnsPgn && nSprmId <= NS_sprm::v6::sprmSDMPaperReq;
5203 else
5206 Sprm bits: 10-12 sgc sprm group; type of sprm (PAP, CHP, etc)
5208 sgc value type of sprm
5209 1 PAP
5210 2 CHP
5211 3 PIC
5212 4 SEP
5213 5 TAP
5215 auto nSGC = ((nSprmId & 0x1C00) >> 10);
5216 bRet = nSGC == 4;
5218 if (!bRet)
5219 SAL_INFO("sw.ww8", "sprm, id " << nSprmId << " wrong category for section properties");
5220 return bRet;
5223 void WW8PLCFMan::GetSprmStart( short nIdx, WW8PLCFManResult* pRes ) const
5225 memset( pRes, 0, sizeof( WW8PLCFManResult ) );
5227 // verifying !!!
5229 pRes->nMemLen = 0;
5231 const WW8PLCFxDesc* p = &m_aD[nIdx];
5233 // first Sprm in a Group
5234 if( p->bFirstSprm )
5236 if( p == m_pPap )
5237 pRes->nFlags |= MAN_MASK_NEW_PAP;
5238 else if( p == m_pSep )
5239 pRes->nFlags |= MAN_MASK_NEW_SEP;
5241 pRes->pMemPos = p->pMemPos;
5242 pRes->nSprmId = GetId(p);
5243 pRes->nCp2OrIdx = p->nCp2OrIdx;
5244 if ((p == m_pFootnote) || (p == m_pEdn) || (p == m_pAnd))
5245 pRes->nMemLen = p->nSprmsLen;
5246 else if (p->nSprmsLen >= maSprmParser.MinSprmLen()) //normal
5248 // Length of actual sprm
5249 pRes->nMemLen = maSprmParser.GetSprmSize(pRes->nSprmId, pRes->pMemPos, p->nSprmsLen);
5250 if (!IsSizeLegal(pRes->nMemLen, p->nSprmsLen) || !IsSprmLegalForCategory(pRes->nSprmId, nIdx))
5252 pRes->nSprmId = 0;
5257 void WW8PLCFMan::GetSprmEnd( short nIdx, WW8PLCFManResult* pRes ) const
5259 memset( pRes, 0, sizeof( WW8PLCFManResult ) );
5261 const WW8PLCFxDesc* p = &m_aD[nIdx];
5263 if (!(p->xIdStack->empty()))
5264 pRes->nSprmId = p->xIdStack->top(); // get end position
5265 else
5267 OSL_ENSURE( false, "No Id on the Stack" );
5268 pRes->nSprmId = 0;
5272 void WW8PLCFMan::GetNoSprmStart( short nIdx, WW8PLCFManResult* pRes ) const
5274 const WW8PLCFxDesc* p = &m_aD[nIdx];
5276 pRes->nCpPos = p->nStartPos;
5277 pRes->nMemLen = p->nSprmsLen;
5278 pRes->nCp2OrIdx = p->nCp2OrIdx;
5280 if( p == m_pField )
5281 pRes->nSprmId = eFLD;
5282 else if( p == m_pFootnote )
5283 pRes->nSprmId = eFTN;
5284 else if( p == m_pEdn )
5285 pRes->nSprmId = eEDN;
5286 else if( p == m_pBkm )
5287 pRes->nSprmId = eBKN;
5288 else if (p == m_pAtnBkm)
5289 pRes->nSprmId = eATNBKN;
5290 else if (p == m_pFactoidBkm)
5291 pRes->nSprmId = eFACTOIDBKN;
5292 else if( p == m_pAnd )
5293 pRes->nSprmId = eAND;
5294 else if( p == m_pPcd )
5296 //We slave the piece table attributes to the piece table, the piece
5297 //table attribute iterator contains the sprms for this piece.
5298 GetSprmStart( nIdx+1, pRes );
5300 else
5301 pRes->nSprmId = 0; // default: not found
5304 void WW8PLCFMan::GetNoSprmEnd( short nIdx, WW8PLCFManResult* pRes ) const
5306 pRes->nMemLen = -1; // end tag
5308 if( &m_aD[nIdx] == m_pBkm )
5309 pRes->nSprmId = eBKN;
5310 else if (&m_aD[nIdx] == m_pAtnBkm)
5311 pRes->nSprmId = eATNBKN;
5312 else if (&m_aD[nIdx] == m_pFactoidBkm)
5313 pRes->nSprmId = eFACTOIDBKN;
5314 else if( &m_aD[nIdx] == m_pPcd )
5316 //We slave the piece table attributes to the piece table, the piece
5317 //table attribute iterator contains the sprms for this piece.
5318 GetSprmEnd( nIdx+1, pRes );
5320 else
5321 pRes->nSprmId = 0;
5324 void WW8PLCFMan::TransferOpenSprms(std::stack<sal_uInt16> &rStack)
5326 for (sal_uInt16 i = 0; i < m_nPLCF; ++i)
5328 WW8PLCFxDesc* p = &m_aD[i];
5329 if (!p || !p->xIdStack)
5330 continue;
5331 while (!p->xIdStack->empty())
5333 rStack.push(p->xIdStack->top());
5334 p->xIdStack->pop();
5339 void WW8PLCFMan::AdvSprm(short nIdx, bool bStart)
5341 WW8PLCFxDesc* p = &m_aD[nIdx]; // determine sprm class(!)
5343 p->bFirstSprm = false;
5344 if( bStart )
5346 const sal_uInt16 nLastId = GetId(p);
5348 const sal_uInt16 nLastAttribStarted = IsSprmLegalForCategory(nLastId, nIdx) ? nLastId : 0;
5350 p->xIdStack->push(nLastAttribStarted); // remember Id for attribute end
5352 if( p->nSprmsLen )
5353 { /*
5354 Check, if we have to process more sprm(s).
5356 if( p->pMemPos )
5358 // Length of last sprm
5359 const sal_Int32 nSprmL = maSprmParser.GetSprmSize(nLastId, p->pMemPos, p->nSprmsLen);
5361 // Reduce length of all sprms by length of last sprm
5362 p->nSprmsLen -= nSprmL;
5364 // pos of next possible sprm
5365 if (p->nSprmsLen < maSprmParser.MinSprmLen())
5367 // preventively set to 0, because the end follows!
5368 p->pMemPos = nullptr;
5369 p->nSprmsLen = 0;
5371 else
5372 p->pMemPos += nSprmL;
5374 else
5375 p->nSprmsLen = 0;
5377 if (p->nSprmsLen < maSprmParser.MinSprmLen())
5378 p->nStartPos = WW8_CP_MAX; // the ending follows
5380 else
5382 if (!(p->xIdStack->empty()))
5383 p->xIdStack->pop();
5384 if (p->xIdStack->empty())
5386 if ( (p == m_pChp) || (p == m_pPap) )
5388 p->pMemPos = nullptr;
5389 p->nSprmsLen = 0;
5390 p->nStartPos = p->nOrigEndPos+p->nCpOfs;
5393 On failed seek we have run out of sprms, probably. But if it's
5394 a fastsaved file (has pPcd) then we may be just in a sprm free
5395 gap between pieces that have them, so set dirty flag in sprm
5396 finder to consider than.
5398 if (!(*p->pPLCFx).SeekPos(p->nStartPos))
5400 p->nEndPos = WW8_CP_MAX;
5401 p->pPLCFx->SetDirty(true);
5403 if (!p->pPLCFx->GetDirty() || m_pPcd)
5404 GetNewSprms( *p );
5405 p->pPLCFx->SetDirty(false);
5408 #i2325#
5409 To get the character and paragraph properties you first get
5410 the pap and chp and then apply the fastsaved pPcd properties
5411 to the range. If a pap or chp starts inside the pPcd range
5412 then we must bring the current pPcd range to a halt so as to
5413 end those sprms, then the pap/chp will be processed, and then
5414 we must force a restart of the pPcd on that pap/chp starting
5415 boundary. Doing that effectively means that the pPcd sprms will
5416 be applied to the new range. Not doing it means that the pPcd
5417 sprms will only be applied to the first pap/chp set of
5418 properties contained in the pap/chp range.
5420 So we bring the pPcd to a halt on this location here, by
5421 settings its end to the current start, then store the starting
5422 position of the current range to clipstart. The pPcd sprms
5423 will end as normal (albeit earlier than originally expected),
5424 and the existence of a clipstart will force the pPcd iterator
5425 to reread the current set of sprms instead of advancing to its
5426 next set. Then the clipstart will be set as the starting
5427 position which will force them to be applied directly after
5428 the pap and chps.
5430 if (m_pPcd && ((p->nStartPos > m_pPcd->nStartPos) ||
5431 (m_pPcd->nStartPos == WW8_CP_MAX)) &&
5432 (m_pPcd->nEndPos != p->nStartPos))
5434 m_pPcd->nEndPos = p->nStartPos;
5435 static_cast<WW8PLCFx_PCD *>(m_pPcd->pPLCFx)->SetClipStart(
5436 p->nStartPos);
5440 else
5442 p->pPLCFx->advance(); // next Group of Sprms
5443 p->pMemPos = nullptr; // !!!
5444 p->nSprmsLen = 0;
5445 GetNewSprms( *p );
5447 SAL_WARN_IF(p->nStartPos > p->nEndPos, "sw.ww8",
5448 "End " << p->nEndPos << " before Start " << p->nStartPos);
5453 void WW8PLCFMan::AdvNoSprm(short nIdx, bool bStart)
5456 For the case of a piece table we slave the piece table attribute iterator
5457 to the piece table and access it through that only. They are two separate
5458 structures, but act together as one logical one. The attributes only go
5459 to the next entry when the piece changes
5461 WW8PLCFxDesc* p = &m_aD[nIdx];
5463 if( p == m_pPcd )
5465 AdvSprm(nIdx+1,bStart);
5466 if( bStart )
5467 p->nStartPos = m_aD[nIdx+1].nStartPos;
5468 else
5470 if (m_aD[nIdx+1].xIdStack->empty())
5472 WW8PLCFx_PCD *pTemp = static_cast<WW8PLCFx_PCD*>(m_pPcd->pPLCFx);
5474 #i2325#
5475 As per normal, go on to the next set of properties, i.e. we
5476 have traversed over to the next piece. With a clipstart set
5477 we are being told to reread the current piece sprms so as to
5478 reapply them to a new chp or pap range.
5480 if (pTemp->GetClipStart() == -1)
5481 p->pPLCFx->advance();
5482 p->pMemPos = nullptr;
5483 p->nSprmsLen = 0;
5484 GetNewSprms( m_aD[nIdx+1] );
5485 GetNewNoSprms( *p );
5486 if (pTemp->GetClipStart() != -1)
5489 #i2325#, now we will force our starting position to the
5490 clipping start so as to force the application of these
5491 sprms after the current pap/chp sprms so as to apply the
5492 fastsave sprms to the current range.
5494 p->nStartPos = pTemp->GetClipStart();
5495 pTemp->SetClipStart(-1);
5500 else
5501 { // NoSprm without end
5502 p->pPLCFx->advance();
5503 p->pMemPos = nullptr; // MemPos invalid
5504 p->nSprmsLen = 0;
5505 GetNewNoSprms( *p );
5509 void WW8PLCFMan::advance()
5511 bool bStart;
5512 const sal_uInt16 nIdx = WhereIdx(&bStart);
5513 if (nIdx < m_nPLCF)
5515 WW8PLCFxDesc* p = &m_aD[nIdx];
5517 p->bFirstSprm = true; // Default
5519 if( p->pPLCFx->IsSprm() )
5520 AdvSprm( nIdx, bStart );
5521 else // NoSprm
5522 AdvNoSprm( nIdx, bStart );
5526 // return true for the beginning of an attribute or error,
5527 // false for the end of an attribute
5528 // remaining return values are delivered to the caller from WW8PclxManResults.
5529 bool WW8PLCFMan::Get(WW8PLCFManResult* pRes) const
5531 memset( pRes, 0, sizeof( WW8PLCFManResult ) );
5532 bool bStart;
5533 const sal_uInt16 nIdx = WhereIdx(&bStart);
5535 if( nIdx >= m_nPLCF )
5537 OSL_ENSURE( false, "Position not found" );
5538 return true;
5541 if( m_aD[nIdx].pPLCFx->IsSprm() )
5543 if( bStart )
5545 GetSprmStart( nIdx, pRes );
5546 return true;
5548 else
5550 GetSprmEnd( nIdx, pRes );
5551 return false;
5554 else
5556 if( bStart )
5558 GetNoSprmStart( nIdx, pRes );
5559 return true;
5561 else
5563 GetNoSprmEnd( nIdx, pRes );
5564 return false;
5569 sal_uInt16 WW8PLCFMan::GetColl() const
5571 if( m_pPap->pPLCFx )
5572 return m_pPap->pPLCFx->GetIstd();
5573 else
5575 OSL_ENSURE( false, "GetColl without PLCF_Pap" );
5576 return 0;
5580 WW8PLCFx_FLD* WW8PLCFMan::GetField() const
5582 return static_cast<WW8PLCFx_FLD*>(m_pField->pPLCFx);
5585 SprmResult WW8PLCFMan::HasParaSprm( sal_uInt16 nId ) const
5587 return static_cast<WW8PLCFx_Cp_FKP*>(m_pPap->pPLCFx)->HasSprm( nId );
5590 SprmResult WW8PLCFMan::HasCharSprm( sal_uInt16 nId ) const
5592 return static_cast<WW8PLCFx_Cp_FKP*>(m_pChp->pPLCFx)->HasSprm( nId );
5595 void WW8PLCFMan::HasCharSprm(sal_uInt16 nId,
5596 std::vector<SprmResult> &rResult) const
5598 static_cast<WW8PLCFx_Cp_FKP*>(m_pChp->pPLCFx)->HasSprm(nId, rResult);
5601 void WW8PLCFx::Save( WW8PLCFxSave1& rSave ) const
5603 rSave.nPLCFxPos = GetIdx();
5604 rSave.nPLCFxPos2 = GetIdx2();
5605 rSave.nPLCFxMemOfs = 0;
5606 rSave.nStartFC = GetStartFc();
5609 void WW8PLCFx::Restore( const WW8PLCFxSave1& rSave )
5611 SetIdx( rSave.nPLCFxPos );
5612 SetIdx2( rSave.nPLCFxPos2 );
5613 SetStartFc( rSave.nStartFC );
5616 sal_uInt32 WW8PLCFx_Cp_FKP::GetIdx2() const
5618 return GetPCDIdx();
5621 void WW8PLCFx_Cp_FKP::SetIdx2(sal_uInt32 nIdx)
5623 if( m_pPcd )
5624 m_pPcd->SetIdx( nIdx );
5627 void WW8PLCFx_Cp_FKP::Save( WW8PLCFxSave1& rSave ) const
5629 if (m_pFkp)
5630 m_pFkp->IncMustRemainCache();
5631 WW8PLCFx::Save( rSave );
5633 rSave.nAttrStart = m_nAttrStart;
5634 rSave.nAttrEnd = m_nAttrEnd;
5635 rSave.bLineEnd = m_bLineEnd;
5638 void WW8PLCFx_Cp_FKP::Restore( const WW8PLCFxSave1& rSave )
5640 WW8PLCFx::Restore( rSave );
5642 m_nAttrStart = rSave.nAttrStart;
5643 m_nAttrEnd = rSave.nAttrEnd;
5644 m_bLineEnd = rSave.bLineEnd;
5646 if (m_pFkp)
5647 m_pFkp->DecMustRemainCache();
5650 void WW8PLCFxDesc::Save( WW8PLCFxSave1& rSave ) const
5652 if( !pPLCFx )
5653 return;
5655 pPLCFx->Save( rSave );
5656 if( !pPLCFx->IsSprm() )
5657 return;
5659 WW8PLCFxDesc aD;
5660 aD.nStartPos = nOrigStartPos+nCpOfs;
5661 aD.nCpOfs = rSave.nCpOfs = nCpOfs;
5662 if (!(pPLCFx->SeekPos(aD.nStartPos)))
5664 aD.nEndPos = WW8_CP_MAX;
5665 pPLCFx->SetDirty(true);
5667 pPLCFx->GetSprms(&aD);
5668 pPLCFx->SetDirty(false);
5669 aD.ReduceByOffset();
5670 rSave.nStartCp = aD.nStartPos;
5671 rSave.nPLCFxMemOfs = nOrigSprmsLen - nSprmsLen;
5674 void WW8PLCFxDesc::Restore( const WW8PLCFxSave1& rSave )
5676 if( !pPLCFx )
5677 return;
5679 pPLCFx->Restore( rSave );
5680 if( !pPLCFx->IsSprm() )
5681 return;
5683 WW8PLCFxDesc aD;
5684 aD.nStartPos = rSave.nStartCp+rSave.nCpOfs;
5685 nCpOfs = aD.nCpOfs = rSave.nCpOfs;
5686 if (!(pPLCFx->SeekPos(aD.nStartPos)))
5688 aD.nEndPos = WW8_CP_MAX;
5689 pPLCFx->SetDirty(true);
5691 pPLCFx->GetSprms(&aD);
5692 pPLCFx->SetDirty(false);
5693 aD.ReduceByOffset();
5695 if (nOrigSprmsLen > aD.nSprmsLen)
5697 //two entries exist for the same offset, cut and run
5698 SAL_WARN("sw.ww8", "restored properties don't match saved properties, bailing out");
5699 nSprmsLen = 0;
5700 pMemPos = nullptr;
5702 else
5704 nSprmsLen = nOrigSprmsLen - rSave.nPLCFxMemOfs;
5705 pMemPos = aD.pMemPos == nullptr ? nullptr : aD.pMemPos + rSave.nPLCFxMemOfs;
5709 namespace
5711 sal_uInt32 Readcb(SvStream& rSt, ww::WordVersion eVer)
5713 if (eVer <= ww::eWW2)
5715 sal_uInt16 nShort(0);
5716 rSt.ReadUInt16(nShort);
5717 return nShort;
5719 else
5721 sal_uInt32 nLong(0);
5722 rSt.ReadUInt32(nLong);
5723 return nLong;
5728 bool WW8Fib::GetBaseCp(ManTypes nType, WW8_CP * cp) const
5730 assert(cp != nullptr);
5731 WW8_CP nOffset = 0;
5733 switch (nType)
5735 case MAN_TXBX_HDFT:
5736 if (m_ccpTxbx < 0) {
5737 return false;
5739 nOffset = m_ccpTxbx;
5740 [[fallthrough]];
5741 case MAN_TXBX:
5742 if (m_ccpEdn < 0 || m_ccpEdn > std::numeric_limits<WW8_CP>::max() - nOffset) {
5743 return false;
5745 nOffset += m_ccpEdn;
5746 [[fallthrough]];
5747 case MAN_EDN:
5748 if (m_ccpAtn < 0 || m_ccpAtn > std::numeric_limits<WW8_CP>::max() - nOffset) {
5749 return false;
5751 nOffset += m_ccpAtn;
5752 [[fallthrough]];
5753 case MAN_AND:
5754 if (m_ccpMcr < 0 || m_ccpMcr > std::numeric_limits<WW8_CP>::max() - nOffset) {
5755 return false;
5757 nOffset += m_ccpMcr;
5759 // fall through
5761 A subdocument of this kind (MAN_MACRO) probably exists in some defunct
5762 version of MSWord, but now ccpMcr is always 0. If some example that
5763 uses this comes to light, this is the likely calculation required
5765 case MAN_MACRO:
5767 if (m_ccpHdr < 0 || m_ccpHdr > std::numeric_limits<WW8_CP>::max() - nOffset) {
5768 return false;
5770 nOffset += m_ccpHdr;
5771 [[fallthrough]];
5772 case MAN_HDFT:
5773 if (m_ccpFootnote < 0 || m_ccpFootnote > std::numeric_limits<WW8_CP>::max() - nOffset) {
5774 return false;
5776 nOffset += m_ccpFootnote;
5777 [[fallthrough]];
5778 case MAN_FTN:
5779 if (m_ccpText < 0 || m_ccpText > std::numeric_limits<WW8_CP>::max() - nOffset) {
5780 return false;
5782 nOffset += m_ccpText;
5783 [[fallthrough]];
5784 case MAN_MAINTEXT:
5785 break;
5787 *cp = nOffset;
5788 return true;
5791 ww::WordVersion WW8Fib::GetFIBVersion() const
5793 ww::WordVersion eVer = ww::eWW8;
5795 * Word for Windows 2 I think (1.X might work too if anyone has an example.
5797 * 0xA59B for Word 1 for Windows
5798 * 0xA59C for Word 1 for OS/2 "PM Word"
5800 * Various pages claim that the fileformats of Word 1 and 2 for Windows are
5801 * equivalent to Word for Macintosh 4 and 5. On the other hand
5803 * wIdents for Word for Mac versions...
5804 * 0xFE32 for Word 1
5805 * 0xFE34 for Word 3
5806 * 0xFE37 for Word 4 et 5.
5808 * and this document
5809 * http://cmsdoc.cern.ch/documents/docformat/CMS_CERN_LetterHead.word is
5810 * claimed to be "Word 5 for Mac" by Office etc and has that wIdent, but
5811 * its format isn't the same as that of Word 2 for windows. Nor is it
5812 * the same as that of Word for DOS/PCWord 5
5814 if (m_wIdent == 0xa59b || m_wIdent == 0xa59c)
5815 eVer = ww::eWW1;
5816 else if (m_wIdent == 0xa5db)
5817 eVer = ww::eWW2;
5818 else
5820 switch (m_nVersion)
5822 case 6:
5823 eVer = ww::eWW6;
5824 break;
5825 case 7:
5826 eVer = ww::eWW7;
5827 break;
5828 case 8:
5829 eVer = ww::eWW8;
5830 break;
5833 return eVer;
5836 WW8Fib::WW8Fib(SvStream& rSt, sal_uInt8 nWantedVersion, sal_uInt32 nOffset):
5837 m_fDot(false), m_fGlsy(false), m_fComplex(false), m_fHasPic(false), m_cQuickSaves(0),
5838 m_fEncrypted(false), m_fWhichTableStm(false), m_fReadOnlyRecommended(false),
5839 m_fWriteReservation(false), m_fExtChar(false), m_fFarEast(false), m_fObfuscated(false),
5840 m_fMac(false), m_fEmptySpecial(false), m_fLoadOverridePage(false), m_fFuturesavedUndo(false),
5841 m_fWord97Saved(false), m_fWord2000Saved(false)
5842 // in C++20 with P06831R1 "Default member initializers for bit-fields (revision 1)", the
5843 // above bit-field member initializations can be moved to the class definition
5845 // See [MS-DOC] 2.5.15 "How to read the FIB".
5846 rSt.Seek( nOffset );
5848 note desired number, identify file version number
5849 and check against desired number!
5851 m_nVersion = nWantedVersion;
5852 rSt.ReadUInt16( m_wIdent );
5853 rSt.ReadUInt16( m_nFib );
5854 rSt.ReadUInt16( m_nProduct );
5855 if( ERRCODE_NONE != rSt.GetError() )
5857 sal_Int16 nFibMin;
5858 sal_Int16 nFibMax;
5859 // note: 6 stands for "6 OR 7", 7 stands for "ONLY 7"
5860 switch( m_nVersion )
5862 case 6:
5863 nFibMin = 0x0065; // from 101 WinWord 6.0
5864 // 102 "
5865 // and 103 WinWord 6.0 for Macintosh
5866 // 104 "
5867 nFibMax = 0x0069; // to 105 WinWord 95
5868 break;
5869 case 7:
5870 nFibMin = 0x0069; // from 105 WinWord 95
5871 nFibMax = 0x0069; // to 105 WinWord 95
5872 break;
5873 case 8:
5874 nFibMin = 0x006A; // from 106 WinWord 97
5875 nFibMax = 0x00c1; // to 193 WinWord 97 (?)
5876 break;
5877 default:
5878 nFibMin = 0; // program error!
5879 nFibMax = 0;
5880 m_nFib = 1;
5881 OSL_ENSURE( false, "nVersion not implemented!" );
5882 break;
5884 if ( (m_nFib < nFibMin) || (m_nFib > nFibMax) )
5886 m_nFibError = ERR_SWG_READ_ERROR; // report error
5887 return;
5891 ww::WordVersion eVer = GetFIBVersion();
5893 // helper vars for Ver67:
5894 sal_Int16 pnChpFirst_Ver67=0;
5895 sal_Int16 pnPapFirst_Ver67=0;
5896 sal_Int16 cpnBteChp_Ver67=0;
5897 sal_Int16 cpnBtePap_Ver67=0;
5899 // read FIB
5900 sal_uInt16 nTmpLid = 0;
5901 rSt.ReadUInt16(nTmpLid);
5902 m_lid = LanguageType(nTmpLid);
5903 rSt.ReadInt16( m_pnNext );
5904 sal_uInt8 aBits1(0);
5905 rSt.ReadUChar( aBits1 );
5906 sal_uInt8 aBits2(0);
5907 rSt.ReadUChar( aBits2 );
5908 rSt.ReadUInt16( m_nFibBack );
5909 rSt.ReadUInt16( m_nHash );
5910 rSt.ReadUInt16( m_nKey );
5911 rSt.ReadUChar( m_envr );
5912 sal_uInt8 aVer8Bits1(0); // only used starting with WinWord 8
5913 rSt.ReadUChar( aVer8Bits1 ); // only have an empty reserve field under Ver67
5914 // content from aVer8Bits1
5916 // sal_uInt8 fMac :1;
5917 // sal_uInt8 fEmptySpecial :1;
5918 // sal_uInt8 fLoadOverridePage :1;
5919 // sal_uInt8 fFuturesavedUndo :1;
5920 // sal_uInt8 fWord97Saved :1;
5921 // sal_uInt8 :3;
5922 rSt.ReadUInt16( m_chse );
5923 rSt.ReadUInt16( m_chseTables );
5924 rSt.ReadInt32( m_fcMin );
5925 rSt.ReadInt32( m_fcMac );
5927 // insertion for WW8
5928 if (IsEightPlus(eVer))
5930 rSt.ReadUInt16( m_csw );
5932 // Marke: "rgsw" Beginning of the array of shorts
5933 rSt.ReadUInt16( m_wMagicCreated );
5934 rSt.ReadUInt16( m_wMagicRevised );
5935 rSt.ReadUInt16( m_wMagicCreatedPrivate );
5936 rSt.ReadUInt16( m_wMagicRevisedPrivate );
5937 rSt.SeekRel( 9 * sizeof( sal_Int16 ) );
5940 // these are the 9 unused fields:
5941 && (bVer67 || WW8ReadINT16( rSt, pnFbpChpFirst_W6 )) // 1
5942 && (bVer67 || WW8ReadINT16( rSt, pnChpFirst_W6 )) // 2
5943 && (bVer67 || WW8ReadINT16( rSt, cpnBteChp_W6 )) // 3
5944 && (bVer67 || WW8ReadINT16( rSt, pnFbpPapFirst_W6 )) // 4
5945 && (bVer67 || WW8ReadINT16( rSt, pnPapFirst_W6 )) // 5
5946 && (bVer67 || WW8ReadINT16( rSt, cpnBtePap_W6 )) // 6
5947 && (bVer67 || WW8ReadINT16( rSt, pnFbpLvcFirst_W6 )) // 7
5948 && (bVer67 || WW8ReadINT16( rSt, pnLvcFirst_W6 )) // 8
5949 && (bVer67 || WW8ReadINT16( rSt, cpnBteLvc_W6 )) // 9
5951 sal_uInt16 nTmpFE = 0;
5952 rSt.ReadUInt16(nTmpFE);
5953 m_lidFE = LanguageType(nTmpFE);
5954 rSt.ReadUInt16( m_clw );
5957 // end of the insertion for WW8
5959 // Marke: "rglw" Beginning of the array of longs
5960 rSt.ReadInt32( m_cbMac );
5962 // ignore 2 longs, because they are unimportant
5963 rSt.SeekRel( 2 * sizeof( sal_Int32) );
5965 // skipping 2 more longs only at Ver67
5966 if (IsSevenMinus(eVer))
5967 rSt.SeekRel( 2 * sizeof( sal_Int32) );
5969 rSt.ReadInt32( m_ccpText );
5970 rSt.ReadInt32( m_ccpFootnote );
5971 rSt.ReadInt32( m_ccpHdr );
5972 rSt.ReadInt32( m_ccpMcr );
5973 rSt.ReadInt32( m_ccpAtn );
5974 rSt.ReadInt32( m_ccpEdn );
5975 rSt.ReadInt32( m_ccpTxbx );
5976 rSt.ReadInt32( m_ccpHdrTxbx );
5978 // only skip one more long at Ver67
5979 if (IsSevenMinus(eVer))
5980 rSt.SeekRel( 1 * sizeof( sal_Int32) );
5981 else
5983 // insertion for WW8
5984 rSt.ReadInt32( m_pnFbpChpFirst );
5985 rSt.ReadInt32( m_pnChpFirst );
5986 rSt.ReadInt32( m_cpnBteChp );
5987 rSt.ReadInt32( m_pnFbpPapFirst );
5988 rSt.ReadInt32( m_pnPapFirst );
5989 rSt.ReadInt32( m_cpnBtePap );
5990 rSt.ReadInt32( m_pnFbpLvcFirst );
5991 rSt.ReadInt32( m_pnLvcFirst );
5992 rSt.ReadInt32( m_cpnBteLvc );
5993 rSt.ReadInt32( m_fcIslandFirst );
5994 rSt.ReadInt32( m_fcIslandLim );
5995 rSt.ReadUInt16( m_cfclcb );
5997 // Read cswNew to find out if nFib should be ignored.
5998 sal_uInt64 nPos = rSt.Tell();
5999 rSt.SeekRel(m_cfclcb * 8);
6000 if (rSt.good() && rSt.remainingSize() >= 2)
6002 rSt.ReadUInt16(m_cswNew);
6004 rSt.Seek(nPos);
6007 // end of the insertion for WW8
6009 // Marke: "rgfclcb" Beginning of array of FC/LCB pairs.
6010 rSt.ReadInt32( m_fcStshfOrig );
6011 m_lcbStshfOrig = Readcb(rSt, eVer);
6012 rSt.ReadInt32( m_fcStshf );
6013 m_lcbStshf = Readcb(rSt, eVer);
6014 rSt.ReadInt32( m_fcPlcffndRef );
6015 m_lcbPlcffndRef = Readcb(rSt, eVer);
6016 rSt.ReadInt32( m_fcPlcffndText );
6017 m_lcbPlcffndText = Readcb(rSt, eVer);
6018 rSt.ReadInt32( m_fcPlcfandRef );
6019 m_lcbPlcfandRef = Readcb(rSt, eVer);
6020 rSt.ReadInt32( m_fcPlcfandText );
6021 m_lcbPlcfandText = Readcb(rSt, eVer);
6022 rSt.ReadInt32( m_fcPlcfsed );
6023 m_lcbPlcfsed = Readcb(rSt, eVer);
6024 rSt.ReadInt32( m_fcPlcfpad );
6025 m_lcbPlcfpad = Readcb(rSt, eVer);
6026 rSt.ReadInt32( m_fcPlcfphe );
6027 m_lcbPlcfphe = Readcb(rSt, eVer);
6028 rSt.ReadInt32( m_fcSttbfglsy );
6029 m_lcbSttbfglsy = Readcb(rSt, eVer);
6030 rSt.ReadInt32( m_fcPlcfglsy );
6031 m_lcbPlcfglsy = Readcb(rSt, eVer);
6032 rSt.ReadInt32( m_fcPlcfhdd );
6033 m_lcbPlcfhdd = Readcb(rSt, eVer);
6034 rSt.ReadInt32( m_fcPlcfbteChpx );
6035 m_lcbPlcfbteChpx = Readcb(rSt, eVer);
6036 rSt.ReadInt32( m_fcPlcfbtePapx );
6037 m_lcbPlcfbtePapx = Readcb(rSt, eVer);
6038 rSt.ReadInt32( m_fcPlcfsea );
6039 m_lcbPlcfsea = Readcb(rSt, eVer);
6040 rSt.ReadInt32( m_fcSttbfffn );
6041 m_lcbSttbfffn = Readcb(rSt, eVer);
6042 rSt.ReadInt32( m_fcPlcffldMom );
6043 m_lcbPlcffldMom = Readcb(rSt, eVer);
6044 rSt.ReadInt32( m_fcPlcffldHdr );
6045 m_lcbPlcffldHdr = Readcb(rSt, eVer);
6046 rSt.ReadInt32( m_fcPlcffldFootnote );
6047 m_lcbPlcffldFootnote = Readcb(rSt, eVer);
6048 rSt.ReadInt32( m_fcPlcffldAtn );
6049 m_lcbPlcffldAtn = Readcb(rSt, eVer);
6050 rSt.ReadInt32( m_fcPlcffldMcr );
6051 m_lcbPlcffldMcr = Readcb(rSt, eVer);
6052 rSt.ReadInt32( m_fcSttbfbkmk );
6053 m_lcbSttbfbkmk = Readcb(rSt, eVer);
6054 rSt.ReadInt32( m_fcPlcfbkf );
6055 m_lcbPlcfbkf = Readcb(rSt, eVer);
6056 rSt.ReadInt32( m_fcPlcfbkl );
6057 m_lcbPlcfbkl = Readcb(rSt, eVer);
6058 rSt.ReadInt32( m_fcCmds );
6059 m_lcbCmds = Readcb(rSt, eVer);
6060 rSt.ReadInt32( m_fcPlcfmcr );
6061 m_lcbPlcfmcr = Readcb(rSt, eVer);
6062 rSt.ReadInt32( m_fcSttbfmcr );
6063 m_lcbSttbfmcr = Readcb(rSt, eVer);
6064 if (eVer >= ww::eWW2)
6066 rSt.ReadInt32( m_fcPrDrvr );
6067 m_lcbPrDrvr = Readcb(rSt, eVer);
6068 rSt.ReadInt32( m_fcPrEnvPort );
6069 m_lcbPrEnvPort = Readcb(rSt, eVer);
6070 rSt.ReadInt32( m_fcPrEnvLand );
6071 m_lcbPrEnvLand = Readcb(rSt, eVer);
6073 else
6075 rSt.ReadInt32( m_fcPrEnvPort );
6076 m_lcbPrEnvPort = Readcb(rSt, eVer);
6078 rSt.ReadInt32( m_fcWss );
6079 m_lcbWss = Readcb(rSt, eVer);
6080 rSt.ReadInt32( m_fcDop );
6081 m_lcbDop = Readcb(rSt, eVer);
6082 rSt.ReadInt32( m_fcSttbfAssoc );
6083 m_lcbSttbfAssoc = Readcb(rSt, eVer);
6084 rSt.ReadInt32( m_fcClx );
6085 m_lcbClx = Readcb(rSt, eVer);
6086 rSt.ReadInt32( m_fcPlcfpgdFootnote );
6087 m_lcbPlcfpgdFootnote = Readcb(rSt, eVer);
6088 rSt.ReadInt32( m_fcAutosaveSource );
6089 m_lcbAutosaveSource = Readcb(rSt, eVer);
6090 rSt.ReadInt32( m_fcGrpStAtnOwners );
6091 m_lcbGrpStAtnOwners = Readcb(rSt, eVer);
6092 rSt.ReadInt32( m_fcSttbfAtnbkmk );
6093 m_lcbSttbfAtnbkmk = Readcb(rSt, eVer);
6095 // only skip more shot at Ver67
6096 if (IsSevenMinus(eVer))
6098 if (eVer == ww::eWW1)
6099 rSt.SeekRel(1*sizeof(sal_Int32));
6100 rSt.SeekRel(1*sizeof(sal_Int16));
6102 if (eVer >= ww::eWW2)
6104 rSt.ReadInt16(pnChpFirst_Ver67);
6105 rSt.ReadInt16(pnPapFirst_Ver67);
6107 rSt.ReadInt16(cpnBteChp_Ver67);
6108 rSt.ReadInt16(cpnBtePap_Ver67);
6111 if (eVer > ww::eWW2)
6113 rSt.ReadInt32( m_fcPlcfdoaMom );
6114 rSt.ReadInt32( m_lcbPlcfdoaMom );
6115 rSt.ReadInt32( m_fcPlcfdoaHdr );
6116 rSt.ReadInt32( m_lcbPlcfdoaHdr );
6117 rSt.ReadInt32( m_fcPlcfspaMom );
6118 rSt.ReadInt32( m_lcbPlcfspaMom );
6119 rSt.ReadInt32( m_fcPlcfspaHdr );
6120 rSt.ReadInt32( m_lcbPlcfspaHdr );
6122 rSt.ReadInt32( m_fcPlcfAtnbkf );
6123 rSt.ReadInt32( m_lcbPlcfAtnbkf );
6124 rSt.ReadInt32( m_fcPlcfAtnbkl );
6125 rSt.ReadInt32( m_lcbPlcfAtnbkl );
6126 rSt.ReadInt32( m_fcPms );
6127 rSt.ReadInt32( m_lcbPMS );
6128 rSt.ReadInt32( m_fcFormFieldSttbf );
6129 rSt.ReadInt32( m_lcbFormFieldSttbf );
6130 rSt.ReadInt32( m_fcPlcfendRef );
6131 rSt.ReadInt32( m_lcbPlcfendRef );
6132 rSt.ReadInt32( m_fcPlcfendText );
6133 rSt.ReadInt32( m_lcbPlcfendText );
6134 rSt.ReadInt32( m_fcPlcffldEdn );
6135 rSt.ReadInt32( m_lcbPlcffldEdn );
6136 rSt.ReadInt32( m_fcPlcfpgdEdn );
6137 rSt.ReadInt32( m_lcbPlcfpgdEdn );
6138 rSt.ReadInt32( m_fcDggInfo );
6139 rSt.ReadInt32( m_lcbDggInfo );
6140 rSt.ReadInt32( m_fcSttbfRMark );
6141 rSt.ReadInt32( m_lcbSttbfRMark );
6142 rSt.ReadInt32( m_fcSttbfCaption );
6143 rSt.ReadInt32( m_lcbSttbfCaption );
6144 rSt.ReadInt32( m_fcSttbAutoCaption );
6145 rSt.ReadInt32( m_lcbSttbAutoCaption );
6146 rSt.ReadInt32( m_fcPlcfwkb );
6147 rSt.ReadInt32( m_lcbPlcfwkb );
6148 rSt.ReadInt32( m_fcPlcfspl );
6149 rSt.ReadInt32( m_lcbPlcfspl );
6150 rSt.ReadInt32( m_fcPlcftxbxText );
6151 rSt.ReadInt32( m_lcbPlcftxbxText );
6152 rSt.ReadInt32( m_fcPlcffldTxbx );
6153 rSt.ReadInt32( m_lcbPlcffldTxbx );
6154 rSt.ReadInt32( m_fcPlcfHdrtxbxText );
6155 rSt.ReadInt32( m_lcbPlcfHdrtxbxText );
6156 rSt.ReadInt32( m_fcPlcffldHdrTxbx );
6157 rSt.ReadInt32( m_lcbPlcffldHdrTxbx );
6158 rSt.ReadInt32( m_fcStwUser );
6159 rSt.ReadUInt32( m_lcbStwUser );
6160 rSt.ReadInt32( m_fcSttbttmbd );
6161 rSt.ReadUInt32( m_lcbSttbttmbd );
6164 if( ERRCODE_NONE == rSt.GetError() )
6166 // set bit flag
6167 m_fDot = aBits1 & 0x01 ;
6168 m_fGlsy = ( aBits1 & 0x02 ) >> 1;
6169 m_fComplex = ( aBits1 & 0x04 ) >> 2;
6170 m_fHasPic = ( aBits1 & 0x08 ) >> 3;
6171 m_cQuickSaves = ( aBits1 & 0xf0 ) >> 4;
6172 m_fEncrypted = aBits2 & 0x01 ;
6173 m_fWhichTableStm= ( aBits2 & 0x02 ) >> 1;
6174 m_fReadOnlyRecommended = (aBits2 & 0x4) >> 2;
6175 m_fWriteReservation = (aBits2 & 0x8) >> 3;
6176 m_fExtChar = ( aBits2 & 0x10 ) >> 4;
6177 // dummy = ( aBits2 & 0x20 ) >> 5;
6178 m_fFarEast = ( aBits2 & 0x40 ) >> 6; // #i90932#
6179 // dummy = ( aBits2 & 0x80 ) >> 7;
6182 p.r.n. fill targeted variable with xxx_Ver67
6183 or set flags
6185 if (IsSevenMinus(eVer))
6187 m_pnChpFirst = pnChpFirst_Ver67;
6188 m_pnPapFirst = pnPapFirst_Ver67;
6189 m_cpnBteChp = cpnBteChp_Ver67;
6190 m_cpnBtePap = cpnBtePap_Ver67;
6192 else if (IsEightPlus(eVer))
6194 m_fMac = aVer8Bits1 & 0x01 ;
6195 m_fEmptySpecial = ( aVer8Bits1 & 0x02 ) >> 1;
6196 m_fLoadOverridePage = ( aVer8Bits1 & 0x04 ) >> 2;
6197 m_fFuturesavedUndo = ( aVer8Bits1 & 0x08 ) >> 3;
6198 m_fWord97Saved = ( aVer8Bits1 & 0x10 ) >> 4;
6199 m_fWord2000Saved = ( aVer8Bits1 & 0x20 ) >> 5;
6202 especially for WW8:
6203 identify the values for PLCF and PLF LFO
6204 and PLCF for the textbox break descriptors
6206 sal_uInt64 nOldPos = rSt.Tell();
6208 rSt.Seek( 0x02da );
6209 rSt.ReadInt32( m_fcSttbFnm );
6210 rSt.ReadInt32( m_lcbSttbFnm );
6211 rSt.ReadInt32( m_fcPlcfLst );
6212 rSt.ReadInt32( m_lcbPlcfLst );
6213 rSt.ReadInt32( m_fcPlfLfo );
6214 rSt.ReadInt32( m_lcbPlfLfo );
6215 rSt.ReadInt32( m_fcPlcftxbxBkd );
6216 rSt.ReadInt32( m_lcbPlcftxbxBkd );
6217 rSt.ReadInt32( m_fcPlcfHdrtxbxBkd );
6218 rSt.ReadInt32( m_lcbPlcfHdrtxbxBkd );
6219 if( ERRCODE_NONE != rSt.GetError() )
6221 m_nFibError = ERR_SWG_READ_ERROR;
6224 rSt.Seek( 0x372 ); // fcSttbListNames
6225 rSt.ReadInt32( m_fcSttbListNames );
6226 rSt.ReadInt32( m_lcbSttbListNames );
6228 if (m_cfclcb > 93)
6230 rSt.Seek( 0x382 ); // MagicTables
6231 rSt.ReadInt32( m_fcPlcfTch );
6232 rSt.ReadInt32( m_lcbPlcfTch );
6235 if (m_cfclcb > 113)
6237 rSt.Seek( 0x41A ); // new ATRD
6238 rSt.ReadInt32( m_fcAtrdExtra );
6239 rSt.ReadUInt32( m_lcbAtrdExtra );
6242 // Factoid bookmarks
6243 if (m_cfclcb > 134)
6245 rSt.Seek(0x432);
6246 rSt.ReadInt32(m_fcPlcfBkfFactoid);
6247 rSt.ReadUInt32(m_lcbPlcfBkfFactoid);
6249 rSt.Seek(0x442);
6250 rSt.ReadInt32(m_fcPlcfBklFactoid);
6251 rSt.ReadUInt32(m_lcbPlcfBklFactoid);
6253 rSt.Seek(0x44a);
6254 rSt.ReadInt32(m_fcFactoidData);
6255 rSt.ReadUInt32(m_lcbFactoidData);
6258 if( ERRCODE_NONE != rSt.GetError() )
6259 m_nFibError = ERR_SWG_READ_ERROR;
6261 rSt.Seek( 0x5bc ); // Actual nFib introduced in Word 2003
6262 rSt.ReadUInt16( m_nFib_actual );
6264 rSt.Seek( nOldPos );
6267 else
6269 m_nFibError = ERR_SWG_READ_ERROR; // report error
6273 WW8Fib::WW8Fib(sal_uInt8 nVer, bool bDot):
6274 m_nVersion(nVer), m_fDot(false), m_fGlsy(false), m_fComplex(false), m_fHasPic(false), m_cQuickSaves(0),
6275 m_fEncrypted(false), m_fWhichTableStm(false), m_fReadOnlyRecommended(false),
6276 m_fWriteReservation(false), m_fExtChar(false), m_fFarEast(false), m_fObfuscated(false),
6277 m_fMac(false), m_fEmptySpecial(false), m_fLoadOverridePage(false), m_fFuturesavedUndo(false),
6278 m_fWord97Saved(false), m_fWord2000Saved(false)
6279 // in C++20 with P06831R1 "Default member initializers for bit-fields (revision 1)", the
6280 // above bit-field member initializations can be moved to the class definition
6282 if (8 == nVer)
6284 m_fcMin = 0x800;
6285 m_wIdent = 0xa5ec;
6286 m_nFib = 0x0101;
6287 m_nFibBack = 0xbf;
6288 m_nProduct = 0x204D;
6289 m_fDot = bDot;
6291 m_csw = 0x0e; // Is this really necessary???
6292 m_cfclcb = 0x88; // -""-
6293 m_clw = 0x16; // -""-
6294 m_pnFbpChpFirst = m_pnFbpPapFirst = m_pnFbpLvcFirst = 0x000fffff;
6295 m_fExtChar = true;
6296 m_fWord97Saved = m_fWord2000Saved = true;
6298 // Just a fancy way to write 'Caolan80'.
6299 m_wMagicCreated = 0x6143;
6300 m_wMagicRevised = 0x6C6F;
6301 m_wMagicCreatedPrivate = 0x6E61;
6302 m_wMagicRevisedPrivate = 0x3038;
6304 else
6306 m_fcMin = 0x300;
6307 m_wIdent = 0xa5dc;
6308 m_nFib = m_nFibBack = 0x65;
6309 m_nProduct = 0xc02d;
6312 //If nFib is 0x00D9 or greater, then cQuickSaves MUST be 0xF
6313 m_cQuickSaves = m_nFib >= 0x00D9 ? 0xF : 0;
6315 // --> #i90932#
6316 m_lid = LanguageType(0x409); // LANGUAGE_ENGLISH_US
6318 LanguageType nLang = Application::GetSettings().GetLanguageTag().getLanguageType();
6319 m_fFarEast = MsLangId::isCJK(nLang);
6320 if (m_fFarEast)
6321 m_lidFE = nLang;
6322 else
6323 m_lidFE = m_lid;
6325 LanguageTag aLanguageTag( m_lid );
6326 LocaleDataWrapper aLocaleWrapper( std::move(aLanguageTag) );
6327 m_nNumDecimalSep = aLocaleWrapper.getNumDecimalSep()[0];
6331 void WW8Fib::WriteHeader(SvStream& rStrm)
6333 bool bVer8 = 8 == m_nVersion;
6335 size_t nUnencryptedHdr = bVer8 ? 0x44 : 0x24;
6336 std::unique_ptr<sal_uInt8[]> pDataPtr( new sal_uInt8[ nUnencryptedHdr ] );
6337 sal_uInt8 *pData = pDataPtr.get();
6338 memset( pData, 0, nUnencryptedHdr );
6340 m_cbMac = rStrm.TellEnd();
6342 Set_UInt16( pData, m_wIdent );
6343 Set_UInt16( pData, m_nFib );
6344 Set_UInt16( pData, m_nProduct );
6345 Set_UInt16( pData, static_cast<sal_uInt16>(m_lid) );
6346 Set_UInt16( pData, m_pnNext );
6348 sal_uInt16 nBits16 = 0;
6349 if( m_fDot ) nBits16 |= 0x0001;
6350 if( m_fGlsy) nBits16 |= 0x0002;
6351 if( m_fComplex ) nBits16 |= 0x0004;
6352 if( m_fHasPic ) nBits16 |= 0x0008;
6353 nBits16 |= (0xf0 & ( m_cQuickSaves << 4 ));
6354 if( m_fEncrypted ) nBits16 |= 0x0100;
6355 if( m_fWhichTableStm ) nBits16 |= 0x0200;
6357 if (m_fReadOnlyRecommended)
6358 nBits16 |= 0x0400;
6359 if (m_fWriteReservation)
6360 nBits16 |= 0x0800;
6362 if( m_fExtChar ) nBits16 |= 0x1000;
6363 if( m_fFarEast ) nBits16 |= 0x4000; // #i90932#
6364 if( m_fObfuscated ) nBits16 |= 0x8000;
6365 Set_UInt16( pData, nBits16 );
6367 Set_UInt16( pData, m_nFibBack );
6368 Set_UInt16( pData, m_nHash );
6369 Set_UInt16( pData, m_nKey );
6370 Set_UInt8( pData, m_envr );
6372 sal_uInt8 nBits8 = 0;
6373 if( bVer8 )
6375 if( m_fMac ) nBits8 |= 0x0001;
6376 if( m_fEmptySpecial ) nBits8 |= 0x0002;
6377 if( m_fLoadOverridePage ) nBits8 |= 0x0004;
6378 if( m_fFuturesavedUndo ) nBits8 |= 0x0008;
6379 if( m_fWord97Saved ) nBits8 |= 0x0010;
6380 if( m_fWord2000Saved ) nBits8 |= 0x0020;
6382 // under Ver67 these are only reserved
6383 Set_UInt8( pData, nBits8 );
6385 Set_UInt16( pData, m_chse );
6386 Set_UInt16( pData, m_chseTables );
6387 Set_UInt32( pData, m_fcMin );
6388 Set_UInt32( pData, m_fcMac );
6390 // insertion for WW8
6392 // Marke: "rgsw" Beginning of the array of shorts
6393 if( bVer8 )
6395 Set_UInt16( pData, m_csw );
6396 Set_UInt16( pData, m_wMagicCreated );
6397 Set_UInt16( pData, m_wMagicRevised );
6398 Set_UInt16( pData, m_wMagicCreatedPrivate );
6399 Set_UInt16( pData, m_wMagicRevisedPrivate );
6400 pData += 9 * sizeof( sal_Int16 );
6401 Set_UInt16( pData, static_cast<sal_uInt16>(m_lidFE) );
6402 Set_UInt16( pData, m_clw );
6405 // end of the insertion for WW8
6407 // Marke: "rglw" Beginning of the array of longs
6408 Set_UInt32( pData, m_cbMac );
6410 rStrm.WriteBytes(pDataPtr.get(), nUnencryptedHdr);
6413 void WW8Fib::Write(SvStream& rStrm)
6415 bool bVer8 = 8 == m_nVersion;
6417 WriteHeader( rStrm );
6419 size_t nUnencryptedHdr = bVer8 ? 0x44 : 0x24;
6421 std::unique_ptr<sal_uInt8[]> pDataPtr( new sal_uInt8[ m_fcMin - nUnencryptedHdr ] );
6422 sal_uInt8 *pData = pDataPtr.get();
6423 memset( pData, 0, m_fcMin - nUnencryptedHdr );
6425 m_cbMac = rStrm.TellEnd();
6427 // ignore 2 longs, because they are unimportant
6428 pData += 2 * sizeof( sal_Int32);
6430 // skipping 2 more longs only at Ver67
6431 if( !bVer8 )
6432 pData += 2 * sizeof( sal_Int32);
6434 Set_UInt32( pData, m_ccpText );
6435 Set_UInt32( pData, m_ccpFootnote );
6436 Set_UInt32( pData, m_ccpHdr );
6437 Set_UInt32( pData, m_ccpMcr );
6438 Set_UInt32( pData, m_ccpAtn );
6439 Set_UInt32( pData, m_ccpEdn );
6440 Set_UInt32( pData, m_ccpTxbx );
6441 Set_UInt32( pData, m_ccpHdrTxbx );
6443 // only skip one more long at Ver67
6444 if( !bVer8 )
6445 pData += 1 * sizeof( sal_Int32);
6447 // insertion for WW8
6448 if( bVer8 )
6450 Set_UInt32( pData, m_pnFbpChpFirst );
6451 Set_UInt32( pData, m_pnChpFirst );
6452 Set_UInt32( pData, m_cpnBteChp );
6453 Set_UInt32( pData, m_pnFbpPapFirst );
6454 Set_UInt32( pData, m_pnPapFirst );
6455 Set_UInt32( pData, m_cpnBtePap );
6456 Set_UInt32( pData, m_pnFbpLvcFirst );
6457 Set_UInt32( pData, m_pnLvcFirst );
6458 Set_UInt32( pData, m_cpnBteLvc );
6459 Set_UInt32( pData, m_fcIslandFirst );
6460 Set_UInt32( pData, m_fcIslandLim );
6461 Set_UInt16( pData, m_cfclcb );
6463 // end of the insertion for WW8
6465 // Marke: "rgfclcb" Beginning of array of FC/LCB pairs.
6466 Set_UInt32( pData, m_fcStshfOrig );
6467 Set_UInt32( pData, m_lcbStshfOrig );
6468 Set_UInt32( pData, m_fcStshf );
6469 Set_UInt32( pData, m_lcbStshf );
6470 Set_UInt32( pData, m_fcPlcffndRef );
6471 Set_UInt32( pData, m_lcbPlcffndRef );
6472 Set_UInt32( pData, m_fcPlcffndText );
6473 Set_UInt32( pData, m_lcbPlcffndText );
6474 Set_UInt32( pData, m_fcPlcfandRef );
6475 Set_UInt32( pData, m_lcbPlcfandRef );
6476 Set_UInt32( pData, m_fcPlcfandText );
6477 Set_UInt32( pData, m_lcbPlcfandText );
6478 Set_UInt32( pData, m_fcPlcfsed );
6479 Set_UInt32( pData, m_lcbPlcfsed );
6480 Set_UInt32( pData, m_fcPlcfpad );
6481 Set_UInt32( pData, m_lcbPlcfpad );
6482 Set_UInt32( pData, m_fcPlcfphe );
6483 Set_UInt32( pData, m_lcbPlcfphe );
6484 Set_UInt32( pData, m_fcSttbfglsy );
6485 Set_UInt32( pData, m_lcbSttbfglsy );
6486 Set_UInt32( pData, m_fcPlcfglsy );
6487 Set_UInt32( pData, m_lcbPlcfglsy );
6488 Set_UInt32( pData, m_fcPlcfhdd );
6489 Set_UInt32( pData, m_lcbPlcfhdd );
6490 Set_UInt32( pData, m_fcPlcfbteChpx );
6491 Set_UInt32( pData, m_lcbPlcfbteChpx );
6492 Set_UInt32( pData, m_fcPlcfbtePapx );
6493 Set_UInt32( pData, m_lcbPlcfbtePapx );
6494 Set_UInt32( pData, m_fcPlcfsea );
6495 Set_UInt32( pData, m_lcbPlcfsea );
6496 Set_UInt32( pData, m_fcSttbfffn );
6497 Set_UInt32( pData, m_lcbSttbfffn );
6498 Set_UInt32( pData, m_fcPlcffldMom );
6499 Set_UInt32( pData, m_lcbPlcffldMom );
6500 Set_UInt32( pData, m_fcPlcffldHdr );
6501 Set_UInt32( pData, m_lcbPlcffldHdr );
6502 Set_UInt32( pData, m_fcPlcffldFootnote );
6503 Set_UInt32( pData, m_lcbPlcffldFootnote );
6504 Set_UInt32( pData, m_fcPlcffldAtn );
6505 Set_UInt32( pData, m_lcbPlcffldAtn );
6506 Set_UInt32( pData, m_fcPlcffldMcr );
6507 Set_UInt32( pData, m_lcbPlcffldMcr );
6508 Set_UInt32( pData, m_fcSttbfbkmk );
6509 Set_UInt32( pData, m_lcbSttbfbkmk );
6510 Set_UInt32( pData, m_fcPlcfbkf );
6511 Set_UInt32( pData, m_lcbPlcfbkf );
6512 Set_UInt32( pData, m_fcPlcfbkl );
6513 Set_UInt32( pData, m_lcbPlcfbkl );
6514 Set_UInt32( pData, m_fcCmds );
6515 Set_UInt32( pData, m_lcbCmds );
6516 Set_UInt32( pData, m_fcPlcfmcr );
6517 Set_UInt32( pData, m_lcbPlcfmcr );
6518 Set_UInt32( pData, m_fcSttbfmcr );
6519 Set_UInt32( pData, m_lcbSttbfmcr );
6520 Set_UInt32( pData, m_fcPrDrvr );
6521 Set_UInt32( pData, m_lcbPrDrvr );
6522 Set_UInt32( pData, m_fcPrEnvPort );
6523 Set_UInt32( pData, m_lcbPrEnvPort );
6524 Set_UInt32( pData, m_fcPrEnvLand );
6525 Set_UInt32( pData, m_lcbPrEnvLand );
6526 Set_UInt32( pData, m_fcWss );
6527 Set_UInt32( pData, m_lcbWss );
6528 Set_UInt32( pData, m_fcDop );
6529 Set_UInt32( pData, m_lcbDop );
6530 Set_UInt32( pData, m_fcSttbfAssoc );
6531 Set_UInt32( pData, m_lcbSttbfAssoc );
6532 Set_UInt32( pData, m_fcClx );
6533 Set_UInt32( pData, m_lcbClx );
6534 Set_UInt32( pData, m_fcPlcfpgdFootnote );
6535 Set_UInt32( pData, m_lcbPlcfpgdFootnote );
6536 Set_UInt32( pData, m_fcAutosaveSource );
6537 Set_UInt32( pData, m_lcbAutosaveSource );
6538 Set_UInt32( pData, m_fcGrpStAtnOwners );
6539 Set_UInt32( pData, m_lcbGrpStAtnOwners );
6540 Set_UInt32( pData, m_fcSttbfAtnbkmk );
6541 Set_UInt32( pData, m_lcbSttbfAtnbkmk );
6543 // only skip one more short at Ver67
6544 if( !bVer8 )
6546 pData += 1*sizeof( sal_Int16);
6547 Set_UInt16( pData, o3tl::narrowing<sal_uInt16>(m_pnChpFirst) );
6548 Set_UInt16( pData, o3tl::narrowing<sal_uInt16>(m_pnPapFirst) );
6549 Set_UInt16( pData, o3tl::narrowing<sal_uInt16>(m_cpnBteChp) );
6550 Set_UInt16( pData, o3tl::narrowing<sal_uInt16>(m_cpnBtePap) );
6553 Set_UInt32( pData, m_fcPlcfdoaMom ); // only at Ver67, in Ver8 unused
6554 Set_UInt32( pData, m_lcbPlcfdoaMom ); // only at Ver67, in Ver8 unused
6555 Set_UInt32( pData, m_fcPlcfdoaHdr ); // only at Ver67, in Ver8 unused
6556 Set_UInt32( pData, m_lcbPlcfdoaHdr ); // only at Ver67, in Ver8 unused
6558 Set_UInt32( pData, m_fcPlcfspaMom ); // in Ver67 empty reserve
6559 Set_UInt32( pData, m_lcbPlcfspaMom ); // in Ver67 empty reserve
6560 Set_UInt32( pData, m_fcPlcfspaHdr ); // in Ver67 empty reserve
6561 Set_UInt32( pData, m_lcbPlcfspaHdr ); // in Ver67 empty reserve
6563 Set_UInt32( pData, m_fcPlcfAtnbkf );
6564 Set_UInt32( pData, m_lcbPlcfAtnbkf );
6565 Set_UInt32( pData, m_fcPlcfAtnbkl );
6566 Set_UInt32( pData, m_lcbPlcfAtnbkl );
6567 Set_UInt32( pData, m_fcPms );
6568 Set_UInt32( pData, m_lcbPMS );
6569 Set_UInt32( pData, m_fcFormFieldSttbf );
6570 Set_UInt32( pData, m_lcbFormFieldSttbf );
6571 Set_UInt32( pData, m_fcPlcfendRef );
6572 Set_UInt32( pData, m_lcbPlcfendRef );
6573 Set_UInt32( pData, m_fcPlcfendText );
6574 Set_UInt32( pData, m_lcbPlcfendText );
6575 Set_UInt32( pData, m_fcPlcffldEdn );
6576 Set_UInt32( pData, m_lcbPlcffldEdn );
6577 Set_UInt32( pData, m_fcPlcfpgdEdn );
6578 Set_UInt32( pData, m_lcbPlcfpgdEdn );
6579 Set_UInt32( pData, m_fcDggInfo ); // in Ver67 empty reserve
6580 Set_UInt32( pData, m_lcbDggInfo ); // in Ver67 empty reserve
6581 Set_UInt32( pData, m_fcSttbfRMark );
6582 Set_UInt32( pData, m_lcbSttbfRMark );
6583 Set_UInt32( pData, m_fcSttbfCaption );
6584 Set_UInt32( pData, m_lcbSttbfCaption );
6585 Set_UInt32( pData, m_fcSttbAutoCaption );
6586 Set_UInt32( pData, m_lcbSttbAutoCaption );
6587 Set_UInt32( pData, m_fcPlcfwkb );
6588 Set_UInt32( pData, m_lcbPlcfwkb );
6589 Set_UInt32( pData, m_fcPlcfspl ); // in Ver67 empty reserve
6590 Set_UInt32( pData, m_lcbPlcfspl ); // in Ver67 empty reserve
6591 Set_UInt32( pData, m_fcPlcftxbxText );
6592 Set_UInt32( pData, m_lcbPlcftxbxText );
6593 Set_UInt32( pData, m_fcPlcffldTxbx );
6594 Set_UInt32( pData, m_lcbPlcffldTxbx );
6595 Set_UInt32( pData, m_fcPlcfHdrtxbxText );
6596 Set_UInt32( pData, m_lcbPlcfHdrtxbxText );
6597 Set_UInt32( pData, m_fcPlcffldHdrTxbx );
6598 Set_UInt32( pData, m_lcbPlcffldHdrTxbx );
6600 if( bVer8 )
6602 pData += 0x2da - 0x27a; // Pos + Offset (fcPlcfLst - fcStwUser)
6603 Set_UInt32( pData, m_fcSttbFnm);
6604 Set_UInt32( pData, m_lcbSttbFnm);
6605 Set_UInt32( pData, m_fcPlcfLst );
6606 Set_UInt32( pData, m_lcbPlcfLst );
6607 Set_UInt32( pData, m_fcPlfLfo );
6608 Set_UInt32( pData, m_lcbPlfLfo );
6609 Set_UInt32( pData, m_fcPlcftxbxBkd );
6610 Set_UInt32( pData, m_lcbPlcftxbxBkd );
6611 Set_UInt32( pData, m_fcPlcfHdrtxbxBkd );
6612 Set_UInt32( pData, m_lcbPlcfHdrtxbxBkd );
6614 pData += 0x372 - 0x302; // Pos + Offset (fcSttbListNames - fcDocUndo)
6615 Set_UInt32( pData, m_fcSttbListNames );
6616 Set_UInt32( pData, m_lcbSttbListNames );
6618 pData += 0x382 - 0x37A;
6619 Set_UInt32( pData, m_fcPlcfTch );
6620 Set_UInt32( pData, m_lcbPlcfTch );
6622 pData += 0x3FA - 0x38A;
6623 Set_UInt16( pData, sal_uInt16(0x0002));
6624 Set_UInt16( pData, sal_uInt16(0x00D9));
6626 pData += 0x41A - 0x3FE;
6627 Set_UInt32( pData, m_fcAtrdExtra );
6628 Set_UInt32( pData, m_lcbAtrdExtra );
6630 pData += 0x42a - 0x422;
6631 Set_UInt32(pData, m_fcSttbfBkmkFactoid);
6632 Set_UInt32(pData, m_lcbSttbfBkmkFactoid);
6633 Set_UInt32(pData, m_fcPlcfBkfFactoid);
6634 Set_UInt32(pData, m_lcbPlcfBkfFactoid);
6636 pData += 0x442 - 0x43A;
6637 Set_UInt32(pData, m_fcPlcfBklFactoid);
6638 Set_UInt32(pData, m_lcbPlcfBklFactoid);
6639 Set_UInt32(pData, m_fcFactoidData);
6640 Set_UInt32(pData, m_lcbFactoidData);
6642 pData += 0x4BA - 0x452;
6643 Set_UInt32(pData, m_fcPlcffactoid);
6644 Set_UInt32(pData, m_lcbPlcffactoid);
6646 pData += 0x4DA - 0x4c2;
6647 Set_UInt32( pData, m_fcHplxsdr );
6648 Set_UInt32( pData, 0);
6651 rStrm.WriteBytes(pDataPtr.get(), m_fcMin - nUnencryptedHdr);
6654 rtl_TextEncoding WW8Fib::GetFIBCharset(sal_uInt16 chs, LanguageType nLidLocale)
6656 OSL_ENSURE(chs <= 0x100, "overflowed winword charset set");
6657 if (chs == 0x0100)
6658 return RTL_TEXTENCODING_APPLE_ROMAN;
6659 if (chs == 0 && static_cast<sal_uInt16>(nLidLocale) >= 999)
6662 nLidLocale:
6663 language stamp -- localized version In pre-WinWord 2.0 files this
6664 value was the nLocale. If value is < 999, then it is the nLocale,
6665 otherwise it is the lid.
6667 css::lang::Locale aLocale(LanguageTag::convertToLocale(nLidLocale));
6668 return msfilter::util::getBestTextEncodingFromLocale(aLocale);
6670 return rtl_getTextEncodingFromWindowsCharset(static_cast<sal_uInt8>(chs));
6673 MSOFactoidType::MSOFactoidType()
6674 : m_nId(0)
6678 namespace MSOPBString
6680 static OUString Read(SvStream& rStream)
6682 OUString aRet;
6684 sal_uInt16 nBuf(0);
6685 rStream.ReadUInt16(nBuf);
6686 sal_uInt16 nCch = nBuf & 0x7fff; // Bits 1..15.
6687 bool bAnsiString = (nBuf & (1 << 15)) >> 15; // 16th bit.
6688 if (bAnsiString)
6689 aRet = OStringToOUString(read_uInt8s_ToOString(rStream, nCch), RTL_TEXTENCODING_ASCII_US);
6690 else
6691 aRet = read_uInt16s_ToOUString(rStream, nCch);
6693 return aRet;
6696 static void Write(std::u16string_view aString, SvStream& rStream)
6698 sal_uInt16 nBuf = 0;
6699 nBuf |= sal_Int32(aString.size()); // cch, 0..14th bits.
6700 nBuf |= 0x8000; // fAnsiString, 15th bit.
6701 rStream.WriteUInt16(nBuf);
6702 SwWW8Writer::WriteString8(rStream, aString, false, RTL_TEXTENCODING_ASCII_US);
6706 void MSOFactoidType::Read(SvStream& rStream)
6708 sal_uInt32 cbFactoid(0);
6709 rStream.ReadUInt32(cbFactoid);
6710 rStream.ReadUInt32(m_nId);
6711 m_aUri = MSOPBString::Read(rStream);
6712 m_aTag = MSOPBString::Read(rStream);
6713 MSOPBString::Read(rStream); // rgbDownloadURL
6716 void MSOFactoidType::Write(WW8Export& rExport)
6718 SvStream& rStream = *rExport.m_pTableStrm;
6720 SvMemoryStream aStream;
6721 aStream.WriteUInt32(m_nId); // id
6722 MSOPBString::Write(m_aUri, aStream);
6723 MSOPBString::Write(m_aTag, aStream);
6724 MSOPBString::Write(u"", aStream); // rgbDownloadURL
6725 rStream.WriteUInt32(aStream.Tell());
6726 aStream.Seek(0);
6727 rStream.WriteStream(aStream);
6730 void MSOPropertyBagStore::Read(SvStream& rStream)
6732 sal_uInt32 cFactoidType(0);
6733 rStream.ReadUInt32(cFactoidType);
6734 for (sal_uInt32 i = 0; i < cFactoidType && rStream.good(); ++i)
6736 MSOFactoidType aFactoidType;
6737 aFactoidType.Read(rStream);
6738 m_aFactoidTypes.push_back(aFactoidType);
6740 sal_uInt16 cbHdr(0);
6741 rStream.ReadUInt16(cbHdr);
6742 SAL_WARN_IF(cbHdr != 0xc, "sw.ww8", "MSOPropertyBagStore::Read: unexpected cbHdr");
6743 sal_uInt16 nVer(0);
6744 rStream.ReadUInt16(nVer);
6745 SAL_WARN_IF(nVer != 0x0100, "sw.ww8", "MSOPropertyBagStore::Read: unexpected nVer");
6746 rStream.SeekRel(4); // cfactoid
6747 sal_uInt32 nCste(0);
6748 rStream.ReadUInt32(nCste);
6750 //each string has a 2 byte len record at the start
6751 const size_t nMaxPossibleRecords = rStream.remainingSize() / sizeof(sal_uInt16);
6752 if (nCste > nMaxPossibleRecords)
6754 SAL_WARN("sw.ww8", nCste << " records claimed, but max possible is " << nMaxPossibleRecords);
6755 nCste = nMaxPossibleRecords;
6758 for (sal_uInt32 i = 0; i < nCste; ++i)
6760 OUString aString = MSOPBString::Read(rStream);
6761 m_aStringTable.push_back(aString);
6765 void MSOPropertyBagStore::Write(WW8Export& rExport)
6767 SvStream& rStream = *rExport.m_pTableStrm;
6768 rStream.WriteUInt32(m_aFactoidTypes.size()); // cFactoidType
6769 for (MSOFactoidType& rType : m_aFactoidTypes)
6770 rType.Write(rExport);
6771 rStream.WriteUInt16(0xc); // cbHdr
6772 rStream.WriteUInt16(0x0100); // sVer
6773 rStream.WriteUInt32(0); // cfactoid
6774 rStream.WriteUInt32(m_aStringTable.size()); // cste
6775 for (const OUString& rString : m_aStringTable)
6776 MSOPBString::Write(rString, rStream);
6779 MSOProperty::MSOProperty()
6780 : m_nKey(0)
6781 , m_nValue(0)
6785 void MSOProperty::Read(SvStream& rStream)
6787 rStream.ReadUInt32(m_nKey);
6788 rStream.ReadUInt32(m_nValue);
6791 void MSOProperty::Write(SvStream& rStream)
6793 rStream.WriteUInt32(m_nKey);
6794 rStream.WriteUInt32(m_nValue);
6797 MSOPropertyBag::MSOPropertyBag()
6798 : m_nId(0)
6802 bool MSOPropertyBag::Read(SvStream& rStream)
6804 rStream.ReadUInt16(m_nId);
6805 sal_uInt16 cProp(0);
6806 rStream.ReadUInt16(cProp);
6807 if (!rStream.good())
6808 return false;
6809 rStream.SeekRel(2); // cbUnknown
6810 //each MSOProperty is 8 bytes in size
6811 const size_t nMaxPossibleRecords = rStream.remainingSize() / 8;
6812 if (cProp > nMaxPossibleRecords)
6814 SAL_WARN("sw.ww8", cProp << " records claimed, but max possible is " << nMaxPossibleRecords);
6815 cProp = nMaxPossibleRecords;
6817 for (sal_uInt16 i = 0; i < cProp && rStream.good(); ++i)
6819 MSOProperty aProperty;
6820 aProperty.Read(rStream);
6821 m_aProperties.push_back(aProperty);
6823 return rStream.good();
6826 void MSOPropertyBag::Write(WW8Export& rExport)
6828 SvStream& rStream = *rExport.m_pTableStrm;
6829 rStream.WriteUInt16(m_nId);
6830 rStream.WriteUInt16(m_aProperties.size());
6831 rStream.WriteUInt16(0); // cbUnknown
6832 for (MSOProperty& rProperty : m_aProperties)
6833 rProperty.Write(rStream);
6836 void WW8SmartTagData::Read(SvStream& rStream, WW8_FC fcFactoidData, sal_uInt32 lcbFactoidData)
6838 sal_uInt64 nOldPosition = rStream.Tell();
6839 if (!checkSeek(rStream, fcFactoidData))
6840 return;
6842 m_aPropBagStore.Read(rStream);
6843 while (rStream.good() && rStream.Tell() < fcFactoidData + lcbFactoidData)
6845 MSOPropertyBag aPropertyBag;
6846 if (!aPropertyBag.Read(rStream))
6847 break;
6848 m_aPropBags.push_back(aPropertyBag);
6851 rStream.Seek(nOldPosition);
6854 void WW8SmartTagData::Write(WW8Export& rExport)
6856 m_aPropBagStore.Write(rExport);
6857 for (MSOPropertyBag& rPropertyBag : m_aPropBags)
6858 rPropertyBag.Write(rExport);
6861 WW8Style::WW8Style(SvStream& rStream, WW8Fib& rFibPara)
6862 : m_rFib(rFibPara), m_rStream(rStream), m_cstd(0), m_cbSTDBaseInFile(0), m_fStdStylenamesWritten(0)
6863 , m_stiMaxWhenSaved(0), m_istdMaxFixedWhenSaved(0), m_nVerBuiltInNamesWhenSaved(0)
6864 , m_ftcAsci(0), m_ftcFE(0), m_ftcOther(0), m_ftcBi(0)
6866 if (!checkSeek(m_rStream, m_rFib.m_fcStshf))
6867 return;
6869 sal_uInt16 cbStshi = 0; // 2 bytes size of the following STSHI structure
6870 sal_uInt32 nRemaining = m_rFib.m_lcbStshf;
6871 const sal_uInt32 nMinValidStshi = 4;
6873 if (m_rFib.GetFIBVersion() <= ww::eWW2)
6875 cbStshi = 0;
6876 m_cstd = 256;
6878 else
6880 if (m_rFib.m_nFib < 67) // old Version ? (need to find this again to fix)
6881 cbStshi = nMinValidStshi;
6882 else // new version
6884 if (nRemaining < sizeof(cbStshi))
6885 return;
6886 // reads the length of the structure in the file
6887 m_rStream.ReadUInt16( cbStshi );
6888 nRemaining-=2;
6892 cbStshi = std::min(static_cast<sal_uInt32>(cbStshi), nRemaining);
6893 if (cbStshi < nMinValidStshi)
6894 return;
6896 const sal_uInt16 nRead = cbStshi;
6899 m_rStream.ReadUInt16( m_cstd );
6901 m_rStream.ReadUInt16( m_cbSTDBaseInFile );
6903 if( 6 > nRead ) break;
6905 sal_uInt16 a16Bit;
6906 m_rStream.ReadUInt16( a16Bit );
6907 m_fStdStylenamesWritten = a16Bit & 0x0001;
6909 if( 8 > nRead ) break;
6910 m_rStream.ReadUInt16( m_stiMaxWhenSaved );
6912 if( 10 > nRead ) break;
6913 m_rStream.ReadUInt16( m_istdMaxFixedWhenSaved );
6915 if( 12 > nRead ) break;
6916 m_rStream.ReadUInt16( m_nVerBuiltInNamesWhenSaved );
6918 if( 14 > nRead ) break;
6919 m_rStream.ReadUInt16( m_ftcAsci );
6921 if( 16 > nRead ) break;
6922 m_rStream.ReadUInt16( m_ftcFE );
6924 if ( 18 > nRead ) break;
6925 m_rStream.ReadUInt16( m_ftcOther );
6927 m_ftcBi = m_ftcOther;
6929 if ( 20 > nRead ) break;
6930 m_rStream.ReadUInt16( m_ftcBi );
6932 // p.r.n. ignore the rest
6933 if( 20 < nRead )
6934 m_rStream.SeekRel( nRead-20 );
6936 while( false ); // trick: the block above will be passed through exactly one time
6937 // and that's why we can early exit with "break".
6939 nRemaining -= cbStshi;
6941 //There will be stshi.cstd (cbSTD, STD) pairs in the file following the
6942 //STSHI. Note that styles can be empty, i.e. cbSTD == 0
6943 const sal_uInt32 nMinRecordSize = sizeof(sal_uInt16);
6944 const sal_uInt16 nMaxPossibleRecords = nRemaining/nMinRecordSize;
6946 OSL_ENSURE(m_cstd <= nMaxPossibleRecords,
6947 "allegedly more styles that available data");
6948 m_cstd = o3tl::sanitizing_min(m_cstd, nMaxPossibleRecords);
6951 // Read1STDFixed() reads a style. If the style is completely existent,
6952 // so it has no empty slot, we should allocate memory and a pointer should
6953 // reference to STD (perhaps filled with 0). If the slot is empty,
6954 // it will return a null pointer.
6955 std::unique_ptr<WW8_STD> WW8Style::Read1STDFixed(sal_uInt16& rSkip)
6957 if (m_rStream.remainingSize() < 2)
6959 rSkip = 0;
6960 return nullptr;
6963 std::unique_ptr<WW8_STD> pStd;
6965 sal_uInt16 cbStd(0);
6966 m_rStream.ReadUInt16(cbStd); // read length
6968 if( cbStd >= m_cbSTDBaseInFile )
6970 // Fixed part completely available
6972 // read fixed part of STD
6973 pStd.reset(new WW8_STD);
6974 memset( pStd.get(), 0, sizeof( *pStd ) );
6978 if( 2 > m_cbSTDBaseInFile ) break;
6980 sal_uInt16 a16Bit = 0;
6981 m_rStream.ReadUInt16( a16Bit );
6982 pStd->sti = a16Bit & 0x0fff ;
6983 pStd->fScratch = sal_uInt16(0 != ( a16Bit & 0x1000 ));
6984 pStd->fInvalHeight = sal_uInt16(0 != ( a16Bit & 0x2000 ));
6985 pStd->fHasUpe = sal_uInt16(0 != ( a16Bit & 0x4000 ));
6986 pStd->fMassCopy = sal_uInt16(0 != ( a16Bit & 0x8000 ));
6988 if( 4 > m_cbSTDBaseInFile ) break;
6989 a16Bit = 0;
6990 m_rStream.ReadUInt16( a16Bit );
6991 pStd->sgc = a16Bit & 0x000f ;
6992 pStd->istdBase = ( a16Bit & 0xfff0 ) >> 4;
6994 if( 6 > m_cbSTDBaseInFile ) break;
6995 a16Bit = 0;
6996 m_rStream.ReadUInt16( a16Bit );
6997 pStd->cupx = a16Bit & 0x000f ;
6998 pStd->istdNext = ( a16Bit & 0xfff0 ) >> 4;
7000 if( 8 > m_cbSTDBaseInFile ) break;
7001 m_rStream.ReadUInt16( pStd->bchUpe );
7003 // from Ver8 this two fields should be added:
7004 if (10 > m_cbSTDBaseInFile) break;
7005 a16Bit = 0;
7006 m_rStream.ReadUInt16( a16Bit );
7007 pStd->fAutoRedef = a16Bit & 0x0001 ;
7008 pStd->fHidden = ( a16Bit & 0x0002 ) >> 1;
7009 // You never know: cautionary skipped
7010 if (m_cbSTDBaseInFile > 10)
7012 auto nSkip = std::min<sal_uInt64>(m_cbSTDBaseInFile - 10, m_rStream.remainingSize());
7013 m_rStream.Seek(m_rStream.Tell() + nSkip);
7016 while( false ); // trick: the block above will passed through exactly one time
7017 // and can be left early with a "break"
7019 if (!m_rStream.good() || !m_cbSTDBaseInFile)
7021 pStd.reset(); // report error with NULL
7024 rSkip = cbStd - m_cbSTDBaseInFile;
7026 else
7027 { // Fixed part too short
7028 if( cbStd )
7029 m_rStream.SeekRel( cbStd ); // skip leftovers
7030 rSkip = 0;
7032 return pStd;
7035 std::unique_ptr<WW8_STD> WW8Style::Read1Style(sal_uInt16& rSkip, OUString* pString)
7037 // Attention: MacWord-Documents have their Stylenames
7038 // always in ANSI, even if eStructCharSet == CHARSET_MAC !!
7040 std::unique_ptr<WW8_STD> pStd = Read1STDFixed(rSkip); // read STD
7042 // string desired?
7043 if( pString )
7044 { // real style?
7045 if ( pStd )
7047 sal_Int32 nLenStringBytes = 0;
7048 switch( m_rFib.m_nVersion )
7050 case 6:
7051 case 7:
7052 // read pascal string
7053 *pString = read_uInt8_BeltAndBracesString(m_rStream, RTL_TEXTENCODING_MS_1252);
7054 // leading len and trailing zero --> 2
7055 nLenStringBytes = pString->getLength() + 2;
7056 break;
7057 case 8:
7058 // handle Unicode-String with leading length short and
7059 // trailing zero
7060 if (TestBeltAndBraces(m_rStream))
7062 *pString = read_uInt16_BeltAndBracesString(m_rStream);
7063 nLenStringBytes = (pString->getLength() + 2) * 2;
7065 else
7068 #i8114#
7069 This is supposed to be impossible, it's just supposed
7070 to be 16 bit count followed by the string and ending
7071 in a 0 short. But "Lotus SmartSuite Product: Word Pro"
7072 is creating invalid style names in ww7- format. So we
7073 use the belt and braces of the ms strings to see if
7074 they are not corrupt. If they are then we try them as
7075 8bit ones
7077 *pString = read_uInt8_BeltAndBracesString(m_rStream,RTL_TEXTENCODING_MS_1252);
7078 // leading len and trailing zero --> 2
7079 nLenStringBytes = pString->getLength() + 2;
7081 break;
7082 default:
7083 OSL_ENSURE(false, "It was forgotten to code nVersion!");
7084 break;
7086 if (nLenStringBytes > rSkip)
7088 SAL_WARN("sw.ww8", "WW8Style structure corrupt");
7089 nLenStringBytes = rSkip;
7091 rSkip -= nLenStringBytes;
7093 else
7094 pString->clear(); // can not return a name
7096 return pStd;
7099 namespace {
7100 const sal_uInt16 maxStrSize = 65;
7102 struct WW8_FFN_Ver6
7104 WW8_FFN_BASE base;
7105 // from Ver6
7106 char szFfn[maxStrSize]; // 0x6 or 0x40 from Ver8 on zero terminated string that
7107 // records name of font.
7108 // Maximal size of szFfn is 65 characters.
7109 // Attention: This array can also be smaller!!!
7110 // Possibly followed by a second sz which records the
7111 // name of an alternate font to use if the first named
7112 // font does not exist on this system.
7117 // #i43762# check font name for illegal characters
7118 static void lcl_checkFontname( OUString& sString )
7120 // for efficiency, we'd like to use String methods as far as possible.
7121 // Hence, we will:
7122 // 1) convert all invalid chars to \u0001
7123 // 2) then erase all \u0001 chars (if anywhere found), and
7124 // 3) erase leading/trailing ';', in case a font name was
7125 // completely removed
7127 // convert all invalid chars to \u0001
7128 OUStringBuffer aBuf(sString);
7129 const sal_Int32 nLen = aBuf.getLength();
7130 bool bFound = false;
7131 for ( sal_Int32 n = 0; n < nLen; ++n )
7133 if ( aBuf[n] < 0x20 )
7135 aBuf[n] = 1;
7136 bFound = true;
7139 sString = aBuf.makeStringAndClear();
7141 // if anything was found, remove \u0001 + leading/trailing ';'
7142 if( bFound )
7144 sString = comphelper::string::strip(sString.replaceAll("\001", ""), ';');
7148 namespace
7150 sal_uInt16 calcMaxFonts(sal_uInt8 *p, sal_Int32 nFFn)
7152 // Figure out the max number of fonts defined here
7153 sal_uInt16 nMax = 0;
7154 sal_Int32 nRemaining = nFFn;
7155 while (nRemaining)
7157 //p[0] is cbFfnM1, the alleged total length of FFN - 1.
7158 //i.e. length after cbFfnM1
7159 const sal_uInt16 cbFfnM1 = *p++;
7160 --nRemaining;
7162 if (cbFfnM1 > nRemaining)
7163 break;
7165 nMax++;
7166 nRemaining -= cbFfnM1;
7167 p += cbFfnM1;
7169 return nMax;
7172 template<typename T> bool readU8(
7173 sal_uInt8 const * p, std::size_t offset, sal_uInt8 const * pEnd,
7174 T * value)
7176 assert(p <= pEnd);
7177 assert(value != nullptr);
7178 if (offset >= o3tl::make_unsigned(pEnd - p)) {
7179 return false;
7181 *value = p[offset];
7182 return true;
7185 bool readS16(
7186 sal_uInt8 const * p, std::size_t offset, sal_uInt8 const * pEnd,
7187 short * value)
7189 assert(p <= pEnd);
7190 assert(value != nullptr);
7191 if (offset > o3tl::make_unsigned(pEnd - p)
7192 || static_cast<std::size_t>(pEnd - p) - offset < 2)
7194 return false;
7196 *value = unsigned(p[offset]) + (unsigned(p[offset + 1]) << 8);
7197 return true;
7200 sal_Int32 getStringLengthWithMax(
7201 sal_uInt8 const * p, std::size_t offset, sal_uInt8 const * pEnd, std::size_t maxchars)
7203 assert(p <= pEnd);
7204 assert(pEnd - p <= SAL_MAX_INT32);
7205 if (offset >= o3tl::make_unsigned(pEnd - p)) {
7206 return -1;
7208 std::size_t nbytes = static_cast<std::size_t>(pEnd - p) - offset;
7209 std::size_t nsearch = std::min(nbytes, maxchars + 1);
7210 void const * p2 = std::memchr(p + offset, 0, nsearch);
7211 if (p2 == nullptr) {
7212 return -1;
7214 return static_cast<sal_uInt8 const *>(p2) - (p + offset);
7218 WW8Fonts::WW8Fonts( SvStream& rSt, WW8Fib const & rFib )
7220 // Attention: MacWord-Documents have their Fontnames
7221 // always in ANSI, even if eStructCharSet == CHARSET_MAC !!
7222 if( rFib.m_lcbSttbfffn <= 2 )
7224 OSL_ENSURE( false, "font table is broken! (rFib.lcbSttbfffn < 2)" );
7225 return;
7228 if (!checkSeek(rSt, rFib.m_fcSttbfffn))
7229 return;
7231 sal_Int32 nFFn = rFib.m_lcbSttbfffn - 2;
7233 const sal_uInt64 nMaxPossible = rSt.remainingSize();
7234 if (o3tl::make_unsigned(nFFn) > nMaxPossible)
7236 SAL_WARN("sw.ww8", "FFN structure longer than available data");
7237 nFFn = nMaxPossible;
7240 // allocate Font Array
7241 std::vector<sal_uInt8> aA(nFFn);
7242 memset(aA.data(), 0, nFFn);
7244 ww::WordVersion eVersion = rFib.GetFIBVersion();
7246 sal_uInt16 nMax(0);
7247 if( eVersion >= ww::eWW8 )
7249 // bVer8: read the count of strings in nMax
7250 rSt.ReadUInt16(nMax);
7253 // Ver8: skip undefined uint16
7254 // Ver67: skip the herein stored total byte of structure
7255 // - we already got that information in rFib.lcbSttbfffn
7256 rSt.SeekRel( 2 );
7258 // read all font information
7259 nFFn = rSt.ReadBytes(aA.data(), nFFn);
7260 sal_uInt8 * const pEnd = aA.data() + nFFn;
7261 const sal_uInt16 nCalcMax = calcMaxFonts(aA.data(), nFFn);
7263 if (eVersion < ww::eWW8)
7264 nMax = nCalcMax;
7265 else
7267 //newer versions include supportive count of fonts, so take min of that
7268 //and calced max
7269 nMax = std::min(nMax, nCalcMax);
7272 if (nMax)
7274 // allocate Index Array
7275 m_aFontA.resize(nMax);
7276 WW8_FFN* p = m_aFontA.data();
7278 if( eVersion <= ww::eWW2 )
7280 sal_uInt8 const * pVer2 = aA.data();
7281 sal_uInt16 i = 0;
7282 for(; i<nMax; ++i, ++p)
7284 if (!readU8(
7285 pVer2, offsetof(WW8_FFN_BASE, cbFfnM1), pEnd,
7286 &p->aFFNBase.cbFfnM1))
7288 break;
7291 p->aFFNBase.prg = 0;
7292 p->aFFNBase.fTrueType = 0;
7293 p->aFFNBase.ff = 0;
7295 if (!(readU8(pVer2, 1, pEnd, &p->aFFNBase.wWeight)
7296 && readU8(pVer2, 2, pEnd, &p->aFFNBase.chs)))
7298 break;
7301 #i8726# 7- seems to encode the name in the same encoding as
7302 the font, e.g load the doc in 97 and save to see the unicode
7303 ver of the asian fontnames in that example to confirm.
7305 rtl_TextEncoding eEnc = WW8Fib::GetFIBCharset(p->aFFNBase.chs, rFib.m_lid);
7306 if ((eEnc == RTL_TEXTENCODING_SYMBOL) || (eEnc == RTL_TEXTENCODING_DONTKNOW))
7307 eEnc = RTL_TEXTENCODING_MS_1252;
7309 const size_t nStringOffset = 1 + 2;
7310 sal_Int32 n = getStringLengthWithMax(pVer2, nStringOffset, pEnd, maxStrSize);
7311 if (n == -1) {
7312 break;
7314 p->sFontname = OUString(
7315 reinterpret_cast<char const *>(pVer2 + nStringOffset), n, eEnc);
7316 pVer2 = pVer2 + p->aFFNBase.cbFfnM1 + 1;
7318 nMax = i;
7320 else if( eVersion < ww::eWW8 )
7322 sal_uInt8 const * pVer6 = aA.data();
7323 sal_uInt16 i = 0;
7324 for(; i<nMax; ++i, ++p)
7326 if (!readU8(
7327 pVer6, offsetof(WW8_FFN_BASE, cbFfnM1), pEnd,
7328 &p->aFFNBase.cbFfnM1))
7330 break;
7332 sal_uInt8 c2;
7333 if (!readU8(pVer6, 1, pEnd, &c2)) {
7334 break;
7337 p->aFFNBase.prg = c2 & 0x02;
7338 p->aFFNBase.fTrueType = (c2 & 0x04) >> 2;
7339 // skip a reserve bit
7340 p->aFFNBase.ff = (c2 & 0x70) >> 4;
7342 if (!(readS16(
7343 pVer6, offsetof(WW8_FFN_BASE, wWeight), pEnd,
7344 &p->aFFNBase.wWeight)
7345 && readU8(
7346 pVer6, offsetof(WW8_FFN_BASE, chs), pEnd, &p->aFFNBase.chs)
7347 && readU8(
7348 pVer6, offsetof(WW8_FFN_BASE, ibszAlt), pEnd,
7349 &p->aFFNBase.ibszAlt)))
7351 break;
7354 #i8726# 7- seems to encode the name in the same encoding as
7355 the font, e.g load the doc in 97 and save to see the unicode
7356 ver of the asian fontnames in that example to confirm.
7358 rtl_TextEncoding eEnc = WW8Fib::GetFIBCharset(p->aFFNBase.chs, rFib.m_lid);
7359 if ((eEnc == RTL_TEXTENCODING_SYMBOL) || (eEnc == RTL_TEXTENCODING_DONTKNOW))
7360 eEnc = RTL_TEXTENCODING_MS_1252;
7361 const size_t nStringOffset = offsetof(WW8_FFN_Ver6, szFfn);
7362 sal_Int32 n = getStringLengthWithMax(pVer6, nStringOffset, pEnd, maxStrSize);
7363 if (n == -1) {
7364 break;
7366 p->sFontname = OUString(reinterpret_cast<char const*>(pVer6 + nStringOffset), n, eEnc);
7367 if (p->aFFNBase.ibszAlt && p->aFFNBase.ibszAlt < maxStrSize) //don't start after end of string
7369 const size_t nAltStringOffset = offsetof(WW8_FFN_Ver6, szFfn) + p->aFFNBase.ibszAlt;
7370 n = getStringLengthWithMax(pVer6, nAltStringOffset, pEnd, maxStrSize);
7371 if (n == -1) {
7372 break;
7374 p->sFontname += ";" + OUString(reinterpret_cast<char const*>(pVer6 + nAltStringOffset),
7375 n, eEnc);
7377 else
7379 //#i18369# if it's a symbol font set Symbol as fallback
7380 if (
7381 RTL_TEXTENCODING_SYMBOL == WW8Fib::GetFIBCharset(p->aFFNBase.chs, rFib.m_lid)
7382 && p->sFontname!="Symbol"
7385 p->sFontname += ";Symbol";
7388 pVer6 = pVer6 + p->aFFNBase.cbFfnM1 + 1;
7390 nMax = i;
7392 else
7394 //count of bytes in minimum FontFamilyInformation payload
7395 const sal_uInt8 cbMinFFNPayload = 41;
7396 sal_uInt16 nValidFonts = 0;
7397 sal_Int32 nRemainingFFn = nFFn;
7398 sal_uInt8* pRaw = aA.data();
7399 for (sal_uInt16 i=0; i < nMax && nRemainingFFn; ++i, ++p)
7401 //pRaw[0] is cbFfnM1, the alleged total length of FFN - 1
7402 //i.e. length after cbFfnM1
7403 sal_uInt8 cbFfnM1 = *pRaw++;
7404 --nRemainingFFn;
7406 if (cbFfnM1 > nRemainingFFn)
7407 break;
7409 if (cbFfnM1 < cbMinFFNPayload)
7410 break;
7412 p->aFFNBase.cbFfnM1 = cbFfnM1;
7414 sal_uInt8 *pVer8 = pRaw;
7416 sal_uInt8 c2 = *pVer8++;
7417 --cbFfnM1;
7419 p->aFFNBase.prg = c2 & 0x02;
7420 p->aFFNBase.fTrueType = (c2 & 0x04) >> 2;
7421 // skip a reserve bit
7422 p->aFFNBase.ff = (c2 & 0x70) >> 4;
7424 p->aFFNBase.wWeight = SVBT16ToUInt16(*reinterpret_cast<SVBT16*>(pVer8));
7425 pVer8+=2;
7426 cbFfnM1-=2;
7428 p->aFFNBase.chs = *pVer8++;
7429 --cbFfnM1;
7431 p->aFFNBase.ibszAlt = *pVer8++;
7432 --cbFfnM1;
7434 pVer8 += 10; //PANOSE
7435 cbFfnM1-=10;
7436 pVer8 += 24; //FONTSIGNATURE
7437 cbFfnM1-=24;
7439 assert(cbFfnM1 >= 2);
7441 sal_uInt8 nMaxNullTerminatedPossible = cbFfnM1/2 - 1;
7442 sal_Unicode *pPrimary = reinterpret_cast<sal_Unicode*>(pVer8);
7443 pPrimary[nMaxNullTerminatedPossible] = 0;
7444 #ifdef OSL_BIGENDIAN
7445 swapEndian(pPrimary);
7446 #endif
7447 p->sFontname = pPrimary;
7448 if (p->aFFNBase.ibszAlt && p->aFFNBase.ibszAlt < nMaxNullTerminatedPossible)
7450 sal_Unicode *pSecondary = pPrimary + p->aFFNBase.ibszAlt;
7451 #ifdef OSL_BIGENDIAN
7452 swapEndian(pSecondary);
7453 #endif
7454 p->sFontname += OUString::Concat(";") + pSecondary;
7457 // #i43762# check font name for illegal characters
7458 lcl_checkFontname( p->sFontname );
7460 // set pointer one font back to original array
7461 pRaw += p->aFFNBase.cbFfnM1;
7462 nRemainingFFn -= p->aFFNBase.cbFfnM1;
7463 ++nValidFonts;
7465 OSL_ENSURE(nMax == nValidFonts, "Font count differs with availability");
7466 nMax = std::min(nMax, nValidFonts);
7469 m_aFontA.resize(nMax);
7470 m_aFontA.shrink_to_fit();
7473 const WW8_FFN* WW8Fonts::GetFont( sal_uInt16 nNum ) const
7475 if (nNum >= m_aFontA.size())
7476 return nullptr;
7478 return &m_aFontA[nNum];
7481 // Search after a header/footer for an index in the ww list from header/footer
7483 // specials for WinWord6 and -7:
7485 // 1) At the start of reading we must build WWPLCF_HdFt with Fib and Dop
7486 // 2) The main text must be read sequentially over all sections
7487 // 3) For every header/footer in the main text, we must call UpdateIndex()
7488 // exactly once with the parameter from the attribute.
7489 // (per section can be maximally one). This call must take place *after*
7490 // the last call from GetTextPos().
7491 // 4) GetTextPos() can be called with exactly one flag
7492 // out of WW8_{FOOTER,HEADER}_{ODD,EVEN,FIRST} (Do not change!)
7493 // -> maybe we can get a right result then
7495 WW8PLCF_HdFt::WW8PLCF_HdFt( SvStream* pSt, WW8Fib const & rFib, WW8Dop const & rDop )
7496 : m_aPLCF(*pSt, rFib.m_fcPlcfhdd , rFib.m_lcbPlcfhdd , 0)
7498 m_nIdxOffset = 0;
7501 This dop.grpfIhdt has a bit set for each special
7502 footnote *and endnote!!* separator,continuation separator, and
7503 continuation notice entry, the documentation does not mention the
7504 endnote separators, the documentation also gets the index numbers
7505 backwards when specifying which bits to test. The bottom six bits
7506 of this value must be tested and skipped over. Each section's
7507 grpfIhdt is then tested for the existence of the appropriate headers
7508 and footers, at the end of each section the nIdxOffset must be updated
7509 to point to the beginning of the next section's group of headers and
7510 footers in this PLCF, UpdateIndex does that task.
7512 for( sal_uInt8 nI = 0x1; nI <= 0x20; nI <<= 1 )
7513 if( nI & rDop.grpfIhdt ) // bit set?
7514 m_nIdxOffset++;
7517 bool WW8PLCF_HdFt::GetTextPos(sal_uInt8 grpfIhdt, sal_uInt8 nWhich, WW8_CP& rStart,
7518 WW8_CP& rLen)
7520 sal_uInt8 nI = 0x01;
7521 short nIdx = m_nIdxOffset;
7522 while (true)
7524 if( nI & nWhich )
7525 break; // found
7526 if( grpfIhdt & nI )
7527 nIdx++; // uninteresting Header / Footer
7528 nI <<= 1; // text next bit
7529 if( nI > 0x20 )
7530 return false; // not found
7532 // nIdx is HdFt-Index
7533 WW8_CP nEnd;
7534 void* pData;
7536 m_aPLCF.SetIdx( nIdx ); // Lookup suitable CP
7537 m_aPLCF.Get( rStart, nEnd, pData );
7538 if (nEnd < rStart)
7540 SAL_WARN("sw.ww8", "End " << nEnd << " before Start " << rStart);
7541 return false;
7544 bool bFail = o3tl::checked_sub(nEnd, rStart, rLen);
7545 if (bFail)
7547 SAL_WARN("sw.ww8", "broken offset, ignoring");
7548 return false;
7551 m_aPLCF.advance();
7553 return true;
7556 void WW8PLCF_HdFt::GetTextPosExact(short nIdx, WW8_CP& rStart, WW8_CP& rLen)
7558 WW8_CP nEnd;
7559 void* pData;
7561 m_aPLCF.SetIdx( nIdx ); // Lookup suitable CP
7562 m_aPLCF.Get( rStart, nEnd, pData );
7563 if (nEnd < rStart)
7565 SAL_WARN("sw.ww8", "End " << nEnd << " before Start " << rStart);
7566 rLen = 0;
7567 return;
7569 if (o3tl::checked_sub(nEnd, rStart, rLen))
7571 SAL_WARN("sw.ww8", "GetTextPosExact overflow");
7572 rLen = 0;
7576 void WW8PLCF_HdFt::UpdateIndex( sal_uInt8 grpfIhdt )
7578 // Caution: Description is not correct
7579 for( sal_uInt8 nI = 0x01; nI <= 0x20; nI <<= 1 )
7580 if( nI & grpfIhdt )
7581 m_nIdxOffset++;
7584 WW8Dop::WW8Dop(SvStream& rSt, sal_Int16 nFib, sal_Int32 nPos, sal_uInt32 nSize):
7585 fFacingPages(false), fWidowControl(false), fPMHMainDoc(false), grfSuppression(0), fpc(0),
7586 grpfIhdt(0), rncFootnote(0), nFootnote(0), fOutlineDirtySave(false), fOnlyMacPics(false),
7587 fOnlyWinPics(false), fLabelDoc(false), fHyphCapitals(false), fAutoHyphen(false),
7588 fFormNoFields(false), fLinkStyles(false), fRevMarking(false), fBackup(false),
7589 fExactCWords(false), fPagHidden(false), fPagResults(false), fLockAtn(false),
7590 fMirrorMargins(false), fReadOnlyRecommended(false), fDfltTrueType(false),
7591 fPagSuppressTopSpacing(false), fProtEnabled(false), fDispFormFieldSel(false), fRMView(false),
7592 fRMPrint(false), fWriteReservation(false), fLockRev(false), fEmbedFonts(false),
7593 copts_fNoTabForInd(false), copts_fNoSpaceRaiseLower(false), copts_fSuppressSpbfAfterPgBrk(false),
7594 copts_fWrapTrailSpaces(false), copts_fMapPrintTextColor(false), copts_fNoColumnBalance(false),
7595 copts_fConvMailMergeEsc(false), copts_fSuppressTopSpacing(false),
7596 copts_fOrigWordTableRules(false), copts_fTransparentMetafiles(false),
7597 copts_fShowBreaksInFrames(false), copts_fSwapBordersFacingPgs(false), copts_fExpShRtn(false),
7598 rncEdn(0), nEdn(0), epc(0), fPrintFormData(false), fSaveFormData(false), fShadeFormData(false),
7599 fWCFootnoteEdn(false), wvkSaved(0), wScaleSaved(0), zkSaved(0), fRotateFontW6(false),
7600 iGutterPos(false), fNoTabForInd(false), fNoSpaceRaiseLower(false),
7601 fSuppressSpbfAfterPageBreak(false), fWrapTrailSpaces(false), fMapPrintTextColor(false),
7602 fNoColumnBalance(false), fConvMailMergeEsc(false), fSuppressTopSpacing(false),
7603 fOrigWordTableRules(false), fTransparentMetafiles(false), fShowBreaksInFrames(false),
7604 fSwapBordersFacingPgs(false), fCompatibilityOptions_Unknown1_13(false), fExpShRtn(false),
7605 fCompatibilityOptions_Unknown1_15(false), fCompatibilityOptions_Unknown1_16(false),
7606 fSuppressTopSpacingMac5(false), fTruncDxaExpand(false), fPrintBodyBeforeHdr(false),
7607 fNoLeading(false), fCompatibilityOptions_Unknown1_21(false), fMWSmallCaps(false),
7608 fCompatibilityOptions_Unknown1_23(false), fCompatibilityOptions_Unknown1_24(false),
7609 fCompatibilityOptions_Unknown1_25(false), fCompatibilityOptions_Unknown1_26(false),
7610 fCompatibilityOptions_Unknown1_27(false), fCompatibilityOptions_Unknown1_28(false),
7611 fCompatibilityOptions_Unknown1_29(false), fCompatibilityOptions_Unknown1_30(false),
7612 fCompatibilityOptions_Unknown1_31(false), fUsePrinterMetrics(false), lvl(0), fHtmlDoc(false),
7613 fSnapBorder(false), fIncludeHeader(false), fIncludeFooter(false), fForcePageSizePag(false),
7614 fMinFontSizePag(false), fHaveVersions(false), fAutoVersion(false),
7615 fCompatibilityOptions_Unknown2_1(false), fCompatibilityOptions_Unknown2_2(false),
7616 fDontUseHTMLAutoSpacing(false), fCompatibilityOptions_Unknown2_4(false),
7617 fCompatibilityOptions_Unknown2_5(false), fCompatibilityOptions_Unknown2_6(false),
7618 fCompatibilityOptions_Unknown2_7(false), fCompatibilityOptions_Unknown2_8(false),
7619 fCompatibilityOptions_Unknown2_9(false), fCompatibilityOptions_Unknown2_10(false),
7620 fDontBreakWrappedTables(false), fCompatibilityOptions_Unknown2_12(false),
7621 fCompatibilityOptions_Unknown2_13(false), fCompatibilityOptions_Unknown2_14(false),
7622 fCompatibilityOptions_Unknown2_15(false), fCompatibilityOptions_Unknown2_16(false),
7623 fCompatibilityOptions_Unknown2_17(false), fCompatibilityOptions_Unknown2_18(false),
7624 fCompatibilityOptions_Unknown2_19(false), fCompatibilityOptions_Unknown2_20(false),
7625 fCompatibilityOptions_Unknown2_21(false), fCompatibilityOptions_Unknown2_22(false),
7626 fCompatibilityOptions_Unknown2_23(false), fCompatibilityOptions_Unknown2_24(false),
7627 fCompatibilityOptions_Unknown2_25(false), fCompatibilityOptions_Unknown2_26(false),
7628 fCompatibilityOptions_Unknown2_27(false), fCompatibilityOptions_Unknown2_28(false),
7629 fCompatibilityOptions_Unknown2_29(false), fCompatibilityOptions_Unknown2_30(false),
7630 fCompatibilityOptions_Unknown2_31(false), fCompatibilityOptions_Unknown2_32(false),
7631 fUnknown3(0), fUseBackGroundInAllmodes(false), fDoNotEmbedSystemFont(false), fWordCompat(false),
7632 fLiveRecover(false), fEmbedFactoids(false), fFactoidXML(false), fFactoidAllDone(false),
7633 fFolioPrint(false), fReverseFolio(false), iTextLineEnding(0), fHideFcc(false),
7634 fAcetateShowMarkup(false), fAcetateShowAtn(false), fAcetateShowInsDel(false),
7635 fAcetateShowProps(false)
7636 // in C++20 with P06831R1 "Default member initializers for bit-fields (revision 1)", the
7637 // above bit-field member initializations can be moved to the class definition
7639 fDontUseHTMLAutoSpacing = true; //default
7640 fAcetateShowAtn = true; //default
7641 const sal_uInt32 nMaxDopSize = 0x268;
7642 std::unique_ptr<sal_uInt8[]> pDataPtr( new sal_uInt8[ nMaxDopSize ] );
7643 sal_uInt8* pData = pDataPtr.get();
7645 sal_uInt32 nRead = std::min(nMaxDopSize, nSize);
7646 if (nSize < 2 || !checkSeek(rSt, nPos) || nRead != rSt.ReadBytes(pData, nRead))
7647 nDopError = ERR_SWG_READ_ERROR; // report error
7648 else
7650 if (nMaxDopSize > nRead)
7651 memset( pData + nRead, 0, nMaxDopSize - nRead );
7653 // interpret the data
7654 sal_uInt32 a32Bit;
7655 sal_uInt16 a16Bit;
7656 sal_uInt8 a8Bit;
7658 a16Bit = Get_UShort( pData ); // 0 0x00
7659 fFacingPages = 0 != ( a16Bit & 0x0001 ) ;
7660 fWidowControl = 0 != ( a16Bit & 0x0002 ) ;
7661 fPMHMainDoc = 0 != ( a16Bit & 0x0004 ) ;
7662 grfSuppression = ( a16Bit & 0x0018 ) >> 3;
7663 fpc = ( a16Bit & 0x0060 ) >> 5;
7664 grpfIhdt = ( a16Bit & 0xff00 ) >> 8;
7666 a16Bit = Get_UShort( pData ); // 2 0x02
7667 rncFootnote = a16Bit & 0x0003 ;
7668 nFootnote = ( a16Bit & ~0x0003 ) >> 2 ;
7670 a8Bit = Get_Byte( pData ); // 4 0x04
7671 fOutlineDirtySave = 0 != ( a8Bit & 0x01 );
7673 a8Bit = Get_Byte( pData ); // 5 0x05
7674 fOnlyMacPics = 0 != ( a8Bit & 0x01 );
7675 fOnlyWinPics = 0 != ( a8Bit & 0x02 );
7676 fLabelDoc = 0 != ( a8Bit & 0x04 );
7677 fHyphCapitals = 0 != ( a8Bit & 0x08 );
7678 fAutoHyphen = 0 != ( a8Bit & 0x10 );
7679 fFormNoFields = 0 != ( a8Bit & 0x20 );
7680 fLinkStyles = 0 != ( a8Bit & 0x40 );
7681 fRevMarking = 0 != ( a8Bit & 0x80 );
7683 a8Bit = Get_Byte( pData ); // 6 0x06
7684 fBackup = 0 != ( a8Bit & 0x01 );
7685 fExactCWords = 0 != ( a8Bit & 0x02 );
7686 fPagHidden = 0 != ( a8Bit & 0x04 );
7687 fPagResults = 0 != ( a8Bit & 0x08 );
7688 fLockAtn = 0 != ( a8Bit & 0x10 );
7689 fMirrorMargins = 0 != ( a8Bit & 0x20 );
7690 fReadOnlyRecommended = 0 != ( a8Bit & 0x40 );
7691 fDfltTrueType = 0 != ( a8Bit & 0x80 );
7693 a8Bit = Get_Byte( pData ); // 7 0x07
7694 fPagSuppressTopSpacing = 0 != ( a8Bit & 0x01 );
7695 fProtEnabled = 0 != ( a8Bit & 0x02 );
7696 fDispFormFieldSel = 0 != ( a8Bit & 0x04 );
7697 fRMView = 0 != ( a8Bit & 0x08 );
7698 fRMPrint = 0 != ( a8Bit & 0x10 );
7699 fWriteReservation = 0 != ( a8Bit & 0x20 );
7700 fLockRev = 0 != ( a8Bit & 0x40 );
7701 fEmbedFonts = 0 != ( a8Bit & 0x80 );
7703 a8Bit = Get_Byte( pData ); // 8 0x08
7704 copts_fNoTabForInd = 0 != ( a8Bit & 0x01 );
7705 copts_fNoSpaceRaiseLower = 0 != ( a8Bit & 0x02 );
7706 copts_fSuppressSpbfAfterPgBrk = 0 != ( a8Bit & 0x04 );
7707 copts_fWrapTrailSpaces = 0 != ( a8Bit & 0x08 );
7708 copts_fMapPrintTextColor = 0 != ( a8Bit & 0x10 );
7709 copts_fNoColumnBalance = 0 != ( a8Bit & 0x20 );
7710 copts_fConvMailMergeEsc = 0 != ( a8Bit & 0x40 );
7711 copts_fSuppressTopSpacing = 0 != ( a8Bit & 0x80 );
7713 a8Bit = Get_Byte( pData ); // 9 0x09
7714 copts_fOrigWordTableRules = 0 != ( a8Bit & 0x01 );
7715 copts_fTransparentMetafiles = 0 != ( a8Bit & 0x02 );
7716 copts_fShowBreaksInFrames = 0 != ( a8Bit & 0x04 );
7717 copts_fSwapBordersFacingPgs = 0 != ( a8Bit & 0x08 );
7718 copts_fExpShRtn = 0 != ( a8Bit & 0x20 ); // #i56856#
7720 dxaTab = Get_Short( pData ); // 10 0x0a
7721 wSpare = Get_UShort( pData ); // 12 0x0c
7722 dxaHotZ = Get_UShort( pData ); // 14 0x0e
7723 cConsecHypLim = Get_UShort( pData ); // 16 0x10
7724 wSpare2 = Get_UShort( pData ); // 18 0x12
7725 dttmCreated = Get_Long( pData ); // 20 0x14
7726 dttmRevised = Get_Long( pData ); // 24 0x18
7727 dttmLastPrint = Get_Long( pData ); // 28 0x1c
7728 nRevision = Get_Short( pData ); // 32 0x20
7729 tmEdited = Get_Long( pData ); // 34 0x22
7730 cWords = Get_Long( pData ); // 38 0x26
7731 cCh = Get_Long( pData ); // 42 0x2a
7732 cPg = Get_Short( pData ); // 46 0x2e
7733 cParas = Get_Long( pData ); // 48 0x30
7735 a16Bit = Get_UShort( pData ); // 52 0x34
7736 rncEdn = a16Bit & 0x0003 ;
7737 nEdn = ( a16Bit & ~0x0003 ) >> 2;
7739 a16Bit = Get_UShort( pData ); // 54 0x36
7740 epc = a16Bit & 0x0003 ;
7741 nfcFootnoteRef = ( a16Bit & 0x003c ) >> 2;
7742 nfcEdnRef = ( a16Bit & 0x03c0 ) >> 6;
7743 fPrintFormData = 0 != ( a16Bit & 0x0400 );
7744 fSaveFormData = 0 != ( a16Bit & 0x0800 );
7745 fShadeFormData = 0 != ( a16Bit & 0x1000 );
7746 fWCFootnoteEdn = 0 != ( a16Bit & 0x8000 );
7748 cLines = Get_Long( pData ); // 56 0x38
7749 cWordsFootnoteEnd = Get_Long( pData ); // 60 0x3c
7750 cChFootnoteEdn = Get_Long( pData ); // 64 0x40
7751 cPgFootnoteEdn = Get_Short( pData ); // 68 0x44
7752 cParasFootnoteEdn = Get_Long( pData ); // 70 0x46
7753 cLinesFootnoteEdn = Get_Long( pData ); // 74 0x4a
7754 lKeyProtDoc = Get_Long( pData ); // 78 0x4e
7756 a16Bit = Get_UShort( pData ); // 82 0x52
7757 wvkSaved = a16Bit & 0x0007 ;
7758 wScaleSaved = ( a16Bit & 0x0ff8 ) >> 3 ;
7759 zkSaved = ( a16Bit & 0x3000 ) >> 12;
7760 fRotateFontW6 = ( a16Bit & 0x4000 ) >> 14;
7761 iGutterPos = ( a16Bit & 0x8000 ) >> 15;
7763 if (nFib >= 103) // Word 6/32bit, 95, 97, 2000, 2002, 2003, 2007
7765 a32Bit = Get_ULong( pData ); // 84 0x54
7766 SetCompatibilityOptions(a32Bit);
7769 //#i22436#, for all WW7- documents
7770 if (nFib <= 104) // Word 95
7771 fUsePrinterMetrics = true;
7773 if (nFib > 105) // Word 97, 2000, 2002, 2003, 2007
7775 adt = Get_Short( pData ); // 88 0x58
7777 doptypography.ReadFromMem(pData); // 90 0x5a
7779 memcpy( &dogrid, pData, sizeof( WW8_DOGRID )); // 400 0x190
7780 pData += sizeof( WW8_DOGRID );
7782 a16Bit = Get_UShort( pData ); // 410 0x19a
7783 // the following 9 bit are uninteresting
7784 fHtmlDoc = ( a16Bit & 0x0200 ) >> 9 ;
7785 fSnapBorder = ( a16Bit & 0x0800 ) >> 11 ;
7786 fIncludeHeader = ( a16Bit & 0x1000 ) >> 12 ;
7787 fIncludeFooter = ( a16Bit & 0x2000 ) >> 13 ;
7788 fForcePageSizePag = ( a16Bit & 0x4000 ) >> 14 ;
7789 fMinFontSizePag = ( a16Bit & 0x8000 ) >> 15 ;
7791 a16Bit = Get_UShort( pData ); // 412 0x19c
7792 fHaveVersions = 0 != ( a16Bit & 0x0001 );
7793 fAutoVersion = 0 != ( a16Bit & 0x0002 );
7795 pData += 12; // 414 0x19e
7797 cChWS = Get_Long( pData ); // 426 0x1aa
7798 cChWSFootnoteEdn = Get_Long( pData ); // 430 0x1ae
7799 grfDocEvents = Get_Long( pData ); // 434 0x1b2
7801 pData += 4+30+8; // 438 0x1b6; 442 0x1ba; 472 0x1d8; 476 0x1dc
7803 cDBC = Get_Long( pData ); // 480 0x1e0
7804 cDBCFootnoteEdn = Get_Long( pData ); // 484 0x1e4
7806 pData += 1 * sizeof( sal_Int32); // 488 0x1e8
7808 nfcFootnoteRef = Get_Short( pData ); // 492 0x1ec
7809 nfcEdnRef = Get_Short( pData ); // 494 0x1ee
7810 hpsZoomFontPag = Get_Short( pData ); // 496 0x1f0
7811 dywDispPag = Get_Short( pData ); // 498 0x1f2
7813 if (nRead >= 516)
7815 //500 -> 508, Appear to be repeated here in 2000+
7816 pData += 8; // 500 0x1f4
7817 a32Bit = Get_Long( pData ); // 508 0x1fc
7818 SetCompatibilityOptions(a32Bit);
7819 a32Bit = Get_Long( pData ); // 512 0x200
7821 // i#78591#
7822 SetCompatibilityOptions2(a32Bit);
7824 if (nRead >= 550)
7826 pData += 32;
7827 a16Bit = Get_UShort( pData );
7828 fDoNotEmbedSystemFont = ( a16Bit & 0x0001 );
7829 fWordCompat = ( a16Bit & 0x0002 ) >> 1;
7830 fLiveRecover = ( a16Bit & 0x0004 ) >> 2;
7831 fEmbedFactoids = ( a16Bit & 0x0008 ) >> 3;
7832 fFactoidXML = ( a16Bit & 0x00010 ) >> 4;
7833 fFactoidAllDone = ( a16Bit & 0x0020 ) >> 5;
7834 fFolioPrint = ( a16Bit & 0x0040 ) >> 6;
7835 fReverseFolio = ( a16Bit & 0x0080 ) >> 7;
7836 iTextLineEnding = ( a16Bit & 0x0700 ) >> 8;
7837 fHideFcc = ( a16Bit & 0x0800 ) >> 11;
7838 fAcetateShowMarkup = ( a16Bit & 0x1000 ) >> 12;
7839 fAcetateShowAtn = ( a16Bit & 0x2000 ) >> 13;
7840 fAcetateShowInsDel = ( a16Bit & 0x4000 ) >> 14;
7841 fAcetateShowProps = ( a16Bit & 0x8000 ) >> 15;
7843 if (nRead >= 600)
7845 pData += 48;
7846 a16Bit = Get_Short(pData);
7847 fUseBackGroundInAllmodes = (a16Bit & 0x0080) >> 7;
7853 WW8Dop::WW8Dop():
7854 fFacingPages(false), fWidowControl(true), fPMHMainDoc(false), grfSuppression(0), fpc(1),
7855 grpfIhdt(0), rncFootnote(0), nFootnote(1), fOutlineDirtySave(true), fOnlyMacPics(false),
7856 fOnlyWinPics(false), fLabelDoc(false), fHyphCapitals(true), fAutoHyphen(false),
7857 fFormNoFields(false), fLinkStyles(false), fRevMarking(false), fBackup(true),
7858 fExactCWords(false), fPagHidden(true), fPagResults(true), fLockAtn(false),
7859 fMirrorMargins(false), fReadOnlyRecommended(false), fDfltTrueType(true),
7860 fPagSuppressTopSpacing(false), fProtEnabled(false), fDispFormFieldSel(false), fRMView(true),
7861 fRMPrint(true), fWriteReservation(false), fLockRev(false), fEmbedFonts(false),
7862 copts_fNoTabForInd(false), copts_fNoSpaceRaiseLower(false), copts_fSuppressSpbfAfterPgBrk(false),
7863 copts_fWrapTrailSpaces(false), copts_fMapPrintTextColor(false), copts_fNoColumnBalance(false),
7864 copts_fConvMailMergeEsc(false), copts_fSuppressTopSpacing(false),
7865 copts_fOrigWordTableRules(false), copts_fTransparentMetafiles(false),
7866 copts_fShowBreaksInFrames(false), copts_fSwapBordersFacingPgs(false), copts_fExpShRtn(false),
7867 dxaTab(0x2d0), dxaHotZ(0x168), nRevision(1),
7868 rncEdn(0), nEdn(1), epc(3), fPrintFormData(false), fSaveFormData(false), fShadeFormData(true),
7869 fWCFootnoteEdn(false), wvkSaved(2), wScaleSaved(100), zkSaved(0), fRotateFontW6(false),
7870 iGutterPos(false), fNoTabForInd(false), fNoSpaceRaiseLower(false),
7871 fSuppressSpbfAfterPageBreak(false), fWrapTrailSpaces(false), fMapPrintTextColor(false),
7872 fNoColumnBalance(false), fConvMailMergeEsc(false), fSuppressTopSpacing(false),
7873 fOrigWordTableRules(false), fTransparentMetafiles(false), fShowBreaksInFrames(false),
7874 fSwapBordersFacingPgs(false), fCompatibilityOptions_Unknown1_13(false), fExpShRtn(false),
7875 fCompatibilityOptions_Unknown1_15(false), fCompatibilityOptions_Unknown1_16(false),
7876 fSuppressTopSpacingMac5(false), fTruncDxaExpand(false), fPrintBodyBeforeHdr(false),
7877 fNoLeading(true), fCompatibilityOptions_Unknown1_21(false), fMWSmallCaps(false),
7878 fCompatibilityOptions_Unknown1_23(false), fCompatibilityOptions_Unknown1_24(false),
7879 fCompatibilityOptions_Unknown1_25(false), fCompatibilityOptions_Unknown1_26(false),
7880 fCompatibilityOptions_Unknown1_27(false), fCompatibilityOptions_Unknown1_28(false),
7881 fCompatibilityOptions_Unknown1_29(false), fCompatibilityOptions_Unknown1_30(false),
7882 fCompatibilityOptions_Unknown1_31(false), fUsePrinterMetrics(true), lvl(9), fHtmlDoc(false),
7883 fSnapBorder(false), fIncludeHeader(true), fIncludeFooter(true), fForcePageSizePag(false),
7884 fMinFontSizePag(false), fHaveVersions(false), fAutoVersion(false),
7885 cChWS(0), cChWSFootnoteEdn(0), cDBC(0), cDBCFootnoteEdn(0), nfcEdnRef(2),
7886 fCompatibilityOptions_Unknown2_1(false), fCompatibilityOptions_Unknown2_2(false),
7887 fDontUseHTMLAutoSpacing(false), fCompatibilityOptions_Unknown2_4(false),
7888 fCompatibilityOptions_Unknown2_5(false), fCompatibilityOptions_Unknown2_6(false),
7889 fCompatibilityOptions_Unknown2_7(false), fCompatibilityOptions_Unknown2_8(false),
7890 fCompatibilityOptions_Unknown2_9(false), fCompatibilityOptions_Unknown2_10(false),
7891 fDontBreakWrappedTables(false), fCompatibilityOptions_Unknown2_12(false),
7892 fCompatibilityOptions_Unknown2_13(false), fCompatibilityOptions_Unknown2_14(false),
7893 fCompatibilityOptions_Unknown2_15(false), fCompatibilityOptions_Unknown2_16(false),
7894 fCompatibilityOptions_Unknown2_17(false), fCompatibilityOptions_Unknown2_18(false),
7895 fCompatibilityOptions_Unknown2_19(false), fCompatibilityOptions_Unknown2_20(false),
7896 fCompatibilityOptions_Unknown2_21(false), fCompatibilityOptions_Unknown2_22(false),
7897 fCompatibilityOptions_Unknown2_23(false), fCompatibilityOptions_Unknown2_24(false),
7898 fCompatibilityOptions_Unknown2_25(false), fCompatibilityOptions_Unknown2_26(false),
7899 fCompatibilityOptions_Unknown2_27(false), fCompatibilityOptions_Unknown2_28(false),
7900 fCompatibilityOptions_Unknown2_29(false), fCompatibilityOptions_Unknown2_30(false),
7901 fCompatibilityOptions_Unknown2_31(false), fCompatibilityOptions_Unknown2_32(false),
7902 fUnknown3(0), fUseBackGroundInAllmodes(false), fDoNotEmbedSystemFont(false), fWordCompat(false),
7903 fLiveRecover(false), fEmbedFactoids(false), fFactoidXML(false), fFactoidAllDone(false),
7904 fFolioPrint(false), fReverseFolio(false), iTextLineEnding(0), fHideFcc(false),
7905 fAcetateShowMarkup(false), fAcetateShowAtn(true), fAcetateShowInsDel(false),
7906 fAcetateShowProps(false)
7907 // in C++20 with P06831R1 "Default member initializers for bit-fields (revision 1)", the
7908 // above bit-field member initializations can be moved to the class definition
7911 Writer acts like this all the time at the moment, ideally we need an
7912 option for these two as well to import word docs that are not like
7913 this by default
7915 // put in initialization list
7916 // fNoLeading = true;
7917 //fUsePrinterMetrics = true;
7920 void WW8Dop::SetCompatibilityOptions(sal_uInt32 a32Bit)
7922 fNoTabForInd = ( a32Bit & 0x00000001 ) ;
7923 fNoSpaceRaiseLower = ( a32Bit & 0x00000002 ) >> 1 ;
7924 fSuppressSpbfAfterPageBreak = ( a32Bit & 0x00000004 ) >> 2 ;
7925 fWrapTrailSpaces = ( a32Bit & 0x00000008 ) >> 3 ;
7926 fMapPrintTextColor = ( a32Bit & 0x00000010 ) >> 4 ;
7927 fNoColumnBalance = ( a32Bit & 0x00000020 ) >> 5 ;
7928 fConvMailMergeEsc = ( a32Bit & 0x00000040 ) >> 6 ;
7929 fSuppressTopSpacing = ( a32Bit & 0x00000080 ) >> 7 ;
7930 fOrigWordTableRules = ( a32Bit & 0x00000100 ) >> 8 ;
7931 fTransparentMetafiles = ( a32Bit & 0x00000200 ) >> 9 ;
7932 fShowBreaksInFrames = ( a32Bit & 0x00000400 ) >> 10 ;
7933 fSwapBordersFacingPgs = ( a32Bit & 0x00000800 ) >> 11 ;
7934 fCompatibilityOptions_Unknown1_13 = ( a32Bit & 0x00001000 ) >> 12 ;
7935 fExpShRtn = ( a32Bit & 0x00002000 ) >> 13 ; // #i56856#
7936 fCompatibilityOptions_Unknown1_15 = ( a32Bit & 0x00004000 ) >> 14 ;
7937 fCompatibilityOptions_Unknown1_16 = ( a32Bit & 0x00008000 ) >> 15 ;
7938 fSuppressTopSpacingMac5 = ( a32Bit & 0x00010000 ) >> 16 ;
7939 fTruncDxaExpand = ( a32Bit & 0x00020000 ) >> 17 ;
7940 fPrintBodyBeforeHdr = ( a32Bit & 0x00040000 ) >> 18 ;
7941 fNoLeading = ( a32Bit & 0x00080000 ) >> 19 ;
7942 fCompatibilityOptions_Unknown1_21 = ( a32Bit & 0x00100000 ) >> 20 ;
7943 fMWSmallCaps = ( a32Bit & 0x00200000 ) >> 21 ;
7944 fCompatibilityOptions_Unknown1_23 = ( a32Bit & 0x00400000 ) >> 22 ;
7945 fCompatibilityOptions_Unknown1_24 = ( a32Bit & 0x00800800 ) >> 23 ;
7946 fCompatibilityOptions_Unknown1_25 = ( a32Bit & 0x01000000 ) >> 24 ;
7947 fCompatibilityOptions_Unknown1_26 = ( a32Bit & 0x02000000 ) >> 25 ;
7948 fCompatibilityOptions_Unknown1_27 = ( a32Bit & 0x04000000 ) >> 26 ;
7949 fCompatibilityOptions_Unknown1_28 = ( a32Bit & 0x08000000 ) >> 27 ;
7950 fCompatibilityOptions_Unknown1_29 = ( a32Bit & 0x10000000 ) >> 28 ;
7951 fCompatibilityOptions_Unknown1_30 = ( a32Bit & 0x20000000 ) >> 29 ;
7952 fCompatibilityOptions_Unknown1_31 = ( a32Bit & 0x40000000 ) >> 30 ;
7954 fUsePrinterMetrics = ( a32Bit & 0x80000000 ) >> 31 ;
7957 sal_uInt32 WW8Dop::GetCompatibilityOptions() const
7959 sal_uInt32 a32Bit = 0;
7960 if (fNoTabForInd) a32Bit |= 0x00000001;
7961 if (fNoSpaceRaiseLower) a32Bit |= 0x00000002;
7962 if (fSuppressSpbfAfterPageBreak) a32Bit |= 0x00000004;
7963 if (fWrapTrailSpaces) a32Bit |= 0x00000008;
7964 if (fMapPrintTextColor) a32Bit |= 0x00000010;
7965 if (fNoColumnBalance) a32Bit |= 0x00000020;
7966 if (fConvMailMergeEsc) a32Bit |= 0x00000040;
7967 if (fSuppressTopSpacing) a32Bit |= 0x00000080;
7968 if (fOrigWordTableRules) a32Bit |= 0x00000100;
7969 if (fTransparentMetafiles) a32Bit |= 0x00000200;
7970 if (fShowBreaksInFrames) a32Bit |= 0x00000400;
7971 if (fSwapBordersFacingPgs) a32Bit |= 0x00000800;
7972 if (fCompatibilityOptions_Unknown1_13) a32Bit |= 0x00001000;
7973 if (fExpShRtn) a32Bit |= 0x00002000; // #i56856#
7974 if (fCompatibilityOptions_Unknown1_15) a32Bit |= 0x00004000;
7975 if (fCompatibilityOptions_Unknown1_16) a32Bit |= 0x00008000;
7976 if (fSuppressTopSpacingMac5) a32Bit |= 0x00010000;
7977 if (fTruncDxaExpand) a32Bit |= 0x00020000;
7978 if (fPrintBodyBeforeHdr) a32Bit |= 0x00040000;
7979 if (fNoLeading) a32Bit |= 0x00080000;
7980 if (fCompatibilityOptions_Unknown1_21) a32Bit |= 0x00100000;
7981 if (fMWSmallCaps) a32Bit |= 0x00200000;
7982 if (fCompatibilityOptions_Unknown1_23) a32Bit |= 0x00400000;
7983 if (fCompatibilityOptions_Unknown1_24) a32Bit |= 0x00800000;
7984 if (fCompatibilityOptions_Unknown1_25) a32Bit |= 0x01000000;
7985 if (fCompatibilityOptions_Unknown1_26) a32Bit |= 0x02000000;
7986 if (fCompatibilityOptions_Unknown1_27) a32Bit |= 0x04000000;
7987 if (fCompatibilityOptions_Unknown1_28) a32Bit |= 0x08000000;
7988 if (fCompatibilityOptions_Unknown1_29) a32Bit |= 0x10000000;
7989 if (fCompatibilityOptions_Unknown1_30) a32Bit |= 0x20000000;
7990 if (fCompatibilityOptions_Unknown1_31) a32Bit |= 0x40000000;
7991 if (fUsePrinterMetrics) a32Bit |= 0x80000000;
7992 return a32Bit;
7995 // i#78591#
7996 void WW8Dop::SetCompatibilityOptions2(sal_uInt32 a32Bit)
7998 fCompatibilityOptions_Unknown2_1 = ( a32Bit & 0x00000001 );
7999 fCompatibilityOptions_Unknown2_2 = ( a32Bit & 0x00000002 ) >> 1 ;
8000 fDontUseHTMLAutoSpacing = ( a32Bit & 0x00000004 ) >> 2 ;
8001 fCompatibilityOptions_Unknown2_4 = ( a32Bit & 0x00000008 ) >> 3 ;
8002 fCompatibilityOptions_Unknown2_5 = ( a32Bit & 0x00000010 ) >> 4 ;
8003 fCompatibilityOptions_Unknown2_6 = ( a32Bit & 0x00000020 ) >> 5 ;
8004 fCompatibilityOptions_Unknown2_7 = ( a32Bit & 0x00000040 ) >> 6 ;
8005 fCompatibilityOptions_Unknown2_8 = ( a32Bit & 0x00000080 ) >> 7 ;
8006 fCompatibilityOptions_Unknown2_9 = ( a32Bit & 0x00000100 ) >> 8 ;
8007 fCompatibilityOptions_Unknown2_10 = ( a32Bit & 0x00000200 ) >> 9 ;
8008 fDontBreakWrappedTables = ( a32Bit & 0x00000400 ) >> 10 ;
8009 fCompatibilityOptions_Unknown2_12 = ( a32Bit & 0x00000800 ) >> 11 ;
8010 fCompatibilityOptions_Unknown2_13 = ( a32Bit & 0x00001000 ) >> 12 ;
8011 fCompatibilityOptions_Unknown2_14 = ( a32Bit & 0x00002000 ) >> 13 ;
8012 fCompatibilityOptions_Unknown2_15 = ( a32Bit & 0x00004000 ) >> 14 ;
8013 fCompatibilityOptions_Unknown2_16 = ( a32Bit & 0x00008000 ) >> 15 ;
8014 fCompatibilityOptions_Unknown2_17 = ( a32Bit & 0x00010000 ) >> 16 ;
8015 fCompatibilityOptions_Unknown2_18 = ( a32Bit & 0x00020000 ) >> 17 ;
8016 fCompatibilityOptions_Unknown2_19 = ( a32Bit & 0x00040000 ) >> 18 ;
8017 fCompatibilityOptions_Unknown2_20 = ( a32Bit & 0x00080000 ) >> 19 ;
8018 fCompatibilityOptions_Unknown2_21 = ( a32Bit & 0x00100000 ) >> 20 ;
8019 fCompatibilityOptions_Unknown2_22 = ( a32Bit & 0x00200000 ) >> 21 ;
8020 fCompatibilityOptions_Unknown2_23 = ( a32Bit & 0x00400000 ) >> 22 ;
8021 fCompatibilityOptions_Unknown2_24 = ( a32Bit & 0x00800800 ) >> 23 ;
8022 fCompatibilityOptions_Unknown2_25 = ( a32Bit & 0x01000800 ) >> 24 ;
8023 fCompatibilityOptions_Unknown2_26 = ( a32Bit & 0x02000800 ) >> 25 ;
8024 fCompatibilityOptions_Unknown2_27 = ( a32Bit & 0x04000800 ) >> 26 ;
8025 fCompatibilityOptions_Unknown2_28 = ( a32Bit & 0x08000800 ) >> 27 ;
8026 fCompatibilityOptions_Unknown2_29 = ( a32Bit & 0x10000800 ) >> 28 ;
8027 fCompatibilityOptions_Unknown2_30 = ( a32Bit & 0x20000800 ) >> 29 ;
8028 fCompatibilityOptions_Unknown2_31 = ( a32Bit & 0x40000800 ) >> 30 ;
8029 fCompatibilityOptions_Unknown2_32 = ( a32Bit & 0x80000000 ) >> 31 ;
8032 sal_uInt32 WW8Dop::GetCompatibilityOptions2() const
8034 sal_uInt32 a32Bit = 0;
8035 if (fCompatibilityOptions_Unknown2_1) a32Bit |= 0x00000001;
8036 if (fCompatibilityOptions_Unknown2_2) a32Bit |= 0x00000002;
8037 if (fDontUseHTMLAutoSpacing) a32Bit |= 0x00000004;
8038 if (fCompatibilityOptions_Unknown2_4) a32Bit |= 0x00000008;
8039 if (fCompatibilityOptions_Unknown2_5) a32Bit |= 0x00000010;
8040 if (fCompatibilityOptions_Unknown2_6) a32Bit |= 0x00000020;
8041 if (fCompatibilityOptions_Unknown2_7) a32Bit |= 0x00000040;
8042 if (fCompatibilityOptions_Unknown2_8) a32Bit |= 0x00000080;
8043 if (fCompatibilityOptions_Unknown2_9) a32Bit |= 0x00000100;
8044 if (fCompatibilityOptions_Unknown2_10) a32Bit |= 0x00000200;
8045 if (fDontBreakWrappedTables) a32Bit |= 0x00000400;
8046 if (fCompatibilityOptions_Unknown2_12) a32Bit |= 0x00000800;
8047 if (fCompatibilityOptions_Unknown2_13) a32Bit |= 0x00001000;
8048 //#i42909# set thai "line breaking rules" compatibility option
8049 // pflin, wonder whether bUseThaiLineBreakingRules is correct
8050 // when importing word document.
8051 if (bUseThaiLineBreakingRules) a32Bit |= 0x00002000;
8052 else if (fCompatibilityOptions_Unknown2_14) a32Bit |= 0x00002000;
8053 if (fCompatibilityOptions_Unknown2_15) a32Bit |= 0x00004000;
8054 if (fCompatibilityOptions_Unknown2_16) a32Bit |= 0x00008000;
8055 if (fCompatibilityOptions_Unknown2_17) a32Bit |= 0x00010000;
8056 if (fCompatibilityOptions_Unknown2_18) a32Bit |= 0x00020000;
8057 if (fCompatibilityOptions_Unknown2_19) a32Bit |= 0x00040000;
8058 if (fCompatibilityOptions_Unknown2_20) a32Bit |= 0x00080000;
8059 if (fCompatibilityOptions_Unknown2_21) a32Bit |= 0x00100000;
8060 if (fCompatibilityOptions_Unknown2_22) a32Bit |= 0x00200000;
8061 if (fCompatibilityOptions_Unknown2_23) a32Bit |= 0x00400000;
8062 if (fCompatibilityOptions_Unknown2_24) a32Bit |= 0x00800000;
8063 if (fCompatibilityOptions_Unknown2_25) a32Bit |= 0x01000000;
8064 if (fCompatibilityOptions_Unknown2_26) a32Bit |= 0x02000000;
8065 if (fCompatibilityOptions_Unknown2_27) a32Bit |= 0x04000000;
8066 if (fCompatibilityOptions_Unknown2_28) a32Bit |= 0x08000000;
8067 if (fCompatibilityOptions_Unknown2_29) a32Bit |= 0x10000000;
8068 if (fCompatibilityOptions_Unknown2_30) a32Bit |= 0x20000000;
8069 if (fCompatibilityOptions_Unknown2_31) a32Bit |= 0x40000000;
8070 if (fCompatibilityOptions_Unknown2_32) a32Bit |= 0x80000000;
8071 return a32Bit;
8074 void WW8Dop::Write(SvStream& rStrm, WW8Fib& rFib) const
8076 const int nMaxDopLen = 610;
8077 sal_uInt32 nLen = 8 == rFib.m_nVersion ? nMaxDopLen : 84;
8078 rFib.m_fcDop = rStrm.Tell();
8079 rFib.m_lcbDop = nLen;
8081 sal_uInt8 aData[ nMaxDopLen ] = {};
8082 sal_uInt8* pData = aData;
8084 // analyse the data
8085 sal_uInt16 a16Bit;
8086 sal_uInt8 a8Bit;
8088 a16Bit = 0; // 0 0x00
8089 if (fFacingPages)
8090 a16Bit |= 0x0001;
8091 if (fWidowControl)
8092 a16Bit |= 0x0002;
8093 if (fPMHMainDoc)
8094 a16Bit |= 0x0004;
8095 a16Bit |= ( 0x0018 & (grfSuppression << 3));
8096 a16Bit |= ( 0x0060 & (fpc << 5));
8097 a16Bit |= ( 0xff00 & (grpfIhdt << 8));
8098 Set_UInt16( pData, a16Bit );
8100 a16Bit = 0; // 2 0x02
8101 a16Bit |= ( 0x0003 & rncFootnote );
8102 a16Bit |= ( ~0x0003 & (nFootnote << 2));
8103 Set_UInt16( pData, a16Bit );
8105 a8Bit = 0; // 4 0x04
8106 if( fOutlineDirtySave ) a8Bit |= 0x01;
8107 Set_UInt8( pData, a8Bit );
8109 a8Bit = 0; // 5 0x05
8110 if( fOnlyMacPics ) a8Bit |= 0x01;
8111 if( fOnlyWinPics ) a8Bit |= 0x02;
8112 if( fLabelDoc ) a8Bit |= 0x04;
8113 if( fHyphCapitals ) a8Bit |= 0x08;
8114 if( fAutoHyphen ) a8Bit |= 0x10;
8115 if( fFormNoFields ) a8Bit |= 0x20;
8116 if( fLinkStyles ) a8Bit |= 0x40;
8117 if( fRevMarking ) a8Bit |= 0x80;
8118 Set_UInt8( pData, a8Bit );
8120 a8Bit = 0; // 6 0x06
8121 if( fBackup ) a8Bit |= 0x01;
8122 if( fExactCWords ) a8Bit |= 0x02;
8123 if( fPagHidden ) a8Bit |= 0x04;
8124 if( fPagResults ) a8Bit |= 0x08;
8125 if( fLockAtn ) a8Bit |= 0x10;
8126 if( fMirrorMargins ) a8Bit |= 0x20;
8127 if( fReadOnlyRecommended ) a8Bit |= 0x40;
8128 if( fDfltTrueType ) a8Bit |= 0x80;
8129 Set_UInt8( pData, a8Bit );
8131 a8Bit = 0; // 7 0x07
8132 if( fPagSuppressTopSpacing ) a8Bit |= 0x01;
8133 if( fProtEnabled ) a8Bit |= 0x02;
8134 if( fDispFormFieldSel ) a8Bit |= 0x04;
8135 if( fRMView ) a8Bit |= 0x08;
8136 if( fRMPrint ) a8Bit |= 0x10;
8137 if( fWriteReservation ) a8Bit |= 0x20;
8138 if( fLockRev ) a8Bit |= 0x40;
8139 if( fEmbedFonts ) a8Bit |= 0x80;
8140 Set_UInt8( pData, a8Bit );
8142 a8Bit = 0; // 8 0x08
8143 if( copts_fNoTabForInd ) a8Bit |= 0x01;
8144 if( copts_fNoSpaceRaiseLower ) a8Bit |= 0x02;
8145 if( copts_fSuppressSpbfAfterPgBrk ) a8Bit |= 0x04;
8146 if( copts_fWrapTrailSpaces ) a8Bit |= 0x08;
8147 if( copts_fMapPrintTextColor ) a8Bit |= 0x10;
8148 if( copts_fNoColumnBalance ) a8Bit |= 0x20;
8149 if( copts_fConvMailMergeEsc ) a8Bit |= 0x40;
8150 if( copts_fSuppressTopSpacing ) a8Bit |= 0x80;
8151 Set_UInt8( pData, a8Bit );
8153 a8Bit = 0; // 9 0x09
8154 if( copts_fOrigWordTableRules ) a8Bit |= 0x01;
8155 if( copts_fTransparentMetafiles ) a8Bit |= 0x02;
8156 if( copts_fShowBreaksInFrames ) a8Bit |= 0x04;
8157 if( copts_fSwapBordersFacingPgs ) a8Bit |= 0x08;
8158 if( copts_fExpShRtn ) a8Bit |= 0x20; // #i56856#
8159 Set_UInt8( pData, a8Bit );
8161 Set_UInt16( pData, dxaTab ); // 10 0x0a
8162 Set_UInt16( pData, wSpare ); // 12 0x0c
8163 Set_UInt16( pData, dxaHotZ ); // 14 0x0e
8164 Set_UInt16( pData, cConsecHypLim ); // 16 0x10
8165 Set_UInt16( pData, wSpare2 ); // 18 0x12
8166 Set_UInt32( pData, dttmCreated ); // 20 0x14
8167 Set_UInt32( pData, dttmRevised ); // 24 0x18
8168 Set_UInt32( pData, dttmLastPrint ); // 28 0x1c
8169 Set_UInt16( pData, nRevision ); // 32 0x20
8170 Set_UInt32( pData, tmEdited ); // 34 0x22
8171 Set_UInt32( pData, cWords ); // 38 0x26
8172 Set_UInt32( pData, cCh ); // 42 0x2a
8173 Set_UInt16( pData, cPg ); // 46 0x2e
8174 Set_UInt32( pData, cParas ); // 48 0x30
8176 a16Bit = 0; // 52 0x34
8177 a16Bit |= ( 0x0003 & rncEdn );
8178 a16Bit |= (~0x0003 & ( nEdn << 2));
8179 Set_UInt16( pData, a16Bit );
8181 a16Bit = 0; // 54 0x36
8182 a16Bit |= (0x0003 & epc );
8183 a16Bit |= (0x003c & (nfcFootnoteRef << 2));
8184 a16Bit |= (0x03c0 & (nfcEdnRef << 6));
8185 if( fPrintFormData ) a16Bit |= 0x0400;
8186 if( fSaveFormData ) a16Bit |= 0x0800;
8187 if( fShadeFormData ) a16Bit |= 0x1000;
8188 if( fWCFootnoteEdn ) a16Bit |= 0x8000;
8189 Set_UInt16( pData, a16Bit );
8191 Set_UInt32( pData, cLines ); // 56 0x38
8192 Set_UInt32( pData, cWordsFootnoteEnd ); // 60 0x3c
8193 Set_UInt32( pData, cChFootnoteEdn ); // 64 0x40
8194 Set_UInt16( pData, cPgFootnoteEdn ); // 68 0x44
8195 Set_UInt32( pData, cParasFootnoteEdn ); // 70 0x46
8196 Set_UInt32( pData, cLinesFootnoteEdn ); // 74 0x4a
8197 Set_UInt32( pData, lKeyProtDoc ); // 78 0x4e
8199 a16Bit = 0; // 82 0x52
8200 if (wvkSaved)
8201 a16Bit |= 0x0007;
8202 a16Bit |= (0x0ff8 & (wScaleSaved << 3));
8203 a16Bit |= (0x3000 & (zkSaved << 12));
8204 if (iGutterPos)
8206 // Last bit: gutter at top.
8207 a16Bit |= 0x8000;
8209 Set_UInt16( pData, a16Bit );
8211 if( 8 == rFib.m_nVersion )
8213 Set_UInt32(pData, GetCompatibilityOptions()); // 84 0x54
8215 Set_UInt16( pData, adt ); // 88 0x58
8217 doptypography.WriteToMem(pData); // 400 0x190
8219 memcpy( pData, &dogrid, sizeof( WW8_DOGRID ));
8220 pData += sizeof( WW8_DOGRID );
8222 a16Bit = 0x12; // set lvl to 9 // 410 0x19a
8223 if( fHtmlDoc ) a16Bit |= 0x0200;
8224 if( fSnapBorder ) a16Bit |= 0x0800;
8225 if( fIncludeHeader ) a16Bit |= 0x1000;
8226 if( fIncludeFooter ) a16Bit |= 0x2000;
8227 if( fForcePageSizePag ) a16Bit |= 0x4000;
8228 if( fMinFontSizePag ) a16Bit |= 0x8000;
8229 Set_UInt16( pData, a16Bit );
8231 a16Bit = 0; // 412 0x19c
8232 if( fHaveVersions ) a16Bit |= 0x0001;
8233 if( fAutoVersion ) a16Bit |= 0x0002;
8234 Set_UInt16( pData, a16Bit );
8236 pData += 12; // 414 0x19e
8238 Set_UInt32( pData, cChWS ); // 426 0x1aa
8239 Set_UInt32( pData, cChWSFootnoteEdn ); // 430 0x1ae
8240 Set_UInt32( pData, grfDocEvents ); // 434 0x1b2
8242 pData += 4+30+8; // 438 0x1b6; 442 0x1ba; 472 0x1d8; 476 0x1dc
8244 Set_UInt32( pData, cDBC ); // 480 0x1e0
8245 Set_UInt32( pData, cDBCFootnoteEdn ); // 484 0x1e4
8247 pData += 1 * sizeof( sal_Int32); // 488 0x1e8
8249 Set_UInt16( pData, nfcFootnoteRef ); // 492 0x1ec
8250 Set_UInt16( pData, nfcEdnRef ); // 494 0x1ee
8251 Set_UInt16( pData, hpsZoomFontPag ); // 496 0x1f0
8252 Set_UInt16( pData, dywDispPag ); // 498 0x1f2
8254 //500 -> 508, Appear to be repeated here in 2000+
8255 pData += 8;
8256 Set_UInt32(pData, GetCompatibilityOptions());
8257 Set_UInt32(pData, GetCompatibilityOptions2());
8258 pData += 32;
8260 a16Bit = 0;
8261 if (fEmbedFactoids)
8262 a16Bit |= 0x8;
8263 if (fAcetateShowMarkup)
8264 a16Bit |= 0x1000;
8265 //Word XP at least requires fAcetateShowMarkup to honour fAcetateShowAtn
8266 if (fAcetateShowAtn)
8268 a16Bit |= 0x1000;
8269 a16Bit |= 0x2000;
8271 Set_UInt16(pData, a16Bit);
8273 pData += 48;
8274 a16Bit = 0x0080;
8275 Set_UInt16(pData, a16Bit);
8277 rStrm.WriteBytes(aData, nLen);
8280 void WW8DopTypography::ReadFromMem(sal_uInt8 *&pData)
8282 sal_uInt16 a16Bit = Get_UShort(pData);
8283 m_fKerningPunct = (a16Bit & 0x0001);
8284 m_iJustification = (a16Bit & 0x0006) >> 1;
8285 m_iLevelOfKinsoku = (a16Bit & 0x0018) >> 3;
8286 m_f2on1 = (a16Bit & 0x0020) >> 5;
8287 m_reserved1 = (a16Bit & 0x03C0) >> 6;
8288 m_reserved2 = (a16Bit & 0xFC00) >> 10;
8290 m_cchFollowingPunct = Get_Short(pData);
8291 m_cchLeadingPunct = Get_Short(pData);
8293 sal_Int16 i;
8294 for (i=0; i < nMaxFollowing; ++i)
8295 m_rgxchFPunct[i] = Get_Short(pData);
8296 for (i=0; i < nMaxLeading; ++i)
8297 m_rgxchLPunct[i] = Get_Short(pData);
8299 if (m_cchFollowingPunct >= 0 && m_cchFollowingPunct < nMaxFollowing)
8300 m_rgxchFPunct[m_cchFollowingPunct]=0;
8301 else
8302 m_rgxchFPunct[nMaxFollowing - 1]=0;
8304 if (m_cchLeadingPunct >= 0 && m_cchLeadingPunct < nMaxLeading)
8305 m_rgxchLPunct[m_cchLeadingPunct]=0;
8306 else
8307 m_rgxchLPunct[nMaxLeading - 1]=0;
8311 void WW8DopTypography::WriteToMem(sal_uInt8 *&pData) const
8313 sal_uInt16 a16Bit = sal_uInt16(m_fKerningPunct);
8314 a16Bit |= (m_iJustification << 1) & 0x0006;
8315 a16Bit |= (m_iLevelOfKinsoku << 3) & 0x0018;
8316 a16Bit |= (int(m_f2on1) << 5) & 0x0020;
8317 a16Bit |= (m_reserved1 << 6) & 0x03C0;
8318 a16Bit |= (m_reserved2 << 10) & 0xFC00;
8319 Set_UInt16(pData,a16Bit);
8321 Set_UInt16(pData,m_cchFollowingPunct);
8322 Set_UInt16(pData,m_cchLeadingPunct);
8324 sal_Int16 i;
8325 for (i=0; i < nMaxFollowing; ++i)
8326 Set_UInt16(pData,m_rgxchFPunct[i]);
8327 for (i=0; i < nMaxLeading; ++i)
8328 Set_UInt16(pData,m_rgxchLPunct[i]);
8331 LanguageType WW8DopTypography::GetConvertedLang() const
8333 LanguageType nLang;
8334 //I have assumed people's republic/taiwan == simplified/traditional
8336 //This isn't a documented issue, so we might have it all wrong,
8337 //i.e. i.e. what's with the powers of two ?
8340 One example of 3 for reserved1 which was really Japanese, perhaps last bit
8341 is for some other use ?, or redundant. If more examples trigger the assert
8342 we might be able to figure it out.
8344 switch(m_reserved1 & 0xE)
8346 case 2: //Japan
8347 nLang = LANGUAGE_JAPANESE;
8348 break;
8349 case 4: //Chinese (People's Republic)
8350 nLang = LANGUAGE_CHINESE_SIMPLIFIED;
8351 break;
8352 case 6: //Korean
8353 nLang = LANGUAGE_KOREAN;
8354 break;
8355 case 8: //Chinese (Taiwan)
8356 nLang = LANGUAGE_CHINESE_TRADITIONAL;
8357 break;
8358 default:
8359 OSL_ENSURE(false, "Unknown MS Asian Typography language, report");
8360 nLang = LANGUAGE_CHINESE_SIMPLIFIED_LEGACY;
8361 break;
8362 case 0:
8363 //And here we have the possibility that it says 2, but it's really
8364 //a bug and only japanese level 2 has been selected after a custom
8365 //version was chosen on last save!
8366 nLang = LANGUAGE_JAPANESE;
8367 break;
8369 return nLang;
8372 // Sprms
8374 sal_uInt16 wwSprmParser::GetSprmTailLen(sal_uInt16 nId, const sal_uInt8* pSprm, sal_Int32 nRemLen)
8375 const
8377 SprmInfo aSprm = GetSprmInfo(nId);
8378 sal_uInt16 nL = 0; // number of Bytes to read
8380 //sprmPChgTabs
8381 switch( nId )
8383 case 23:
8384 case 0xC615:
8385 if( pSprm[1 + mnDelta] != 255 )
8386 nL = static_cast< sal_uInt16 >(pSprm[1 + mnDelta] + aSprm.nLen);
8387 else
8389 sal_uInt8 nDelIdx = 2 + mnDelta;
8390 sal_uInt8 nDel = nDelIdx < nRemLen ? pSprm[nDelIdx] : 0;
8391 sal_uInt8 nInsIdx = 3 + mnDelta + 4 * nDel;
8392 sal_uInt8 nIns = nInsIdx < nRemLen ? pSprm[nInsIdx] : 0;
8394 nL = 2 + 4 * nDel + 3 * nIns;
8396 break;
8397 default:
8398 switch (aSprm.nVari)
8400 case L_FIX:
8401 nL = aSprm.nLen; // Excl. Token
8402 break;
8403 case L_VAR:
8404 // Variable 1-Byte Length
8405 // parameter length (i.e. excluding token and length byte)
8406 nL = static_cast< sal_uInt16 >(pSprm[1 + mnDelta] + aSprm.nLen);
8407 break;
8408 case L_VAR2:
8410 // Variable 2-Byte Length
8411 // For sprmTDefTable and sprmTDefTable10, the length of the
8412 // parameter plus 1 is recorded in the two bytes beginning
8413 // at offset (WW7-) 1 or (WW8+) 2
8414 sal_uInt8 nIndex = 1 + mnDelta;
8415 sal_uInt16 nCount;
8416 if (nIndex + 1 >= nRemLen)
8418 SAL_WARN("sw.ww8", "sprm longer than remaining bytes, doc or parser is wrong");
8419 nCount = 0;
8421 else
8423 nCount = SVBT16ToUInt16(&pSprm[nIndex]);
8424 SAL_WARN_IF(nCount < 1, "sw.ww8", "length should have been at least 1");
8425 if (nCount)
8426 --nCount;
8428 nL = static_cast<sal_uInt16>(nCount + aSprm.nLen);
8429 break;
8431 default:
8432 OSL_ENSURE(false, "Unknown sprm variant");
8433 break;
8435 break;
8437 return nL;
8440 // one or two bytes at the beginning at the sprm id
8441 sal_uInt16 wwSprmParser::GetSprmId(const sal_uInt8* pSp) const
8443 OSL_ENSURE(pSp, "Why GetSprmId with pSp of 0");
8444 if (!pSp)
8445 return 0;
8447 sal_uInt16 nId = 0;
8449 if (ww::IsSevenMinus(meVersion))
8451 nId = *pSp; // [0..0xff]
8453 else
8455 nId = SVBT16ToUInt16(pSp);
8456 if (0x0800 > nId)
8457 nId = 0;
8460 return nId;
8463 // with tokens and length byte
8464 sal_Int32 wwSprmParser::GetSprmSize(sal_uInt16 nId, const sal_uInt8* pSprm, sal_Int32 nRemLen) const
8466 return GetSprmTailLen(nId, pSprm, nRemLen) + 1 + mnDelta + SprmDataOfs(nId);
8469 sal_uInt8 wwSprmParser::SprmDataOfs(sal_uInt16 nId) const
8471 return GetSprmInfo(nId).nVari;
8474 sal_Int32 wwSprmParser::DistanceToData(sal_uInt16 nId) const
8476 return 1 + mnDelta + SprmDataOfs(nId);
8479 SprmResult wwSprmParser::findSprmData(sal_uInt16 nId, sal_uInt8* pSprms,
8480 sal_Int32 nLen) const
8482 while (nLen >= MinSprmLen())
8484 const sal_uInt16 nCurrentId = GetSprmId(pSprms);
8485 // set pointer to data
8486 sal_Int32 nSize = GetSprmSize(nCurrentId, pSprms, nLen);
8488 bool bValid = nSize <= nLen;
8490 SAL_WARN_IF(!bValid, "sw.ww8",
8491 "sprm 0x" << std::hex << nCurrentId << std::dec << " longer than remaining bytes, " <<
8492 nSize << " vs " << nLen << "doc or parser is wrong");
8494 if (nCurrentId == nId && bValid) // Sprm found
8496 sal_Int32 nFixedLen = DistanceToData(nId);
8497 return SprmResult(pSprms + nFixedLen, nSize - nFixedLen);
8500 //Clip to available size if wrong
8501 nSize = std::min(nSize, nLen);
8502 pSprms += nSize;
8503 nLen -= nSize;
8505 // Sprm not found
8506 return SprmResult();
8509 SEPr::SEPr() :
8510 bkc(2), fTitlePage(0), fAutoPgn(0), nfcPgn(0), fUnlocked(0), cnsPgn(0),
8511 fPgnRestart(0), fEndNote(1), lnc(0), grpfIhdt(0), nLnnMod(0), dxaLnn(0),
8512 dxaPgn(720), dyaPgn(720), fLBetween(0), vjc(0), dmBinFirst(0),
8513 dmBinOther(0), dmPaperReq(0), fPropRMark(0), ibstPropRMark(0),
8514 dttmPropRMark(0), dxtCharSpace(0), dyaLinePitch(0), clm(0), reserved1(0),
8515 dmOrientPage(0), iHeadingPgn(0), pgnStart(1), lnnMin(0), wTextFlow(0),
8516 reserved2(0), pgbApplyTo(0), pgbPageDepth(0), pgbOffsetFrom(0),
8517 xaPage(lLetterWidth), yaPage(lLetterHeight), xaPageNUp(lLetterWidth), yaPageNUp(lLetterHeight),
8518 dxaLeft(1800), dxaRight(1800), dyaTop(1440), dyaBottom(1440), dzaGutter(0),
8519 dyaHdrTop(720), dyaHdrBottom(720), ccolM1(0), fEvenlySpaced(1),
8520 reserved3(0), fBiDi(0), fFacingCol(0), fRTLGutter(0), fRTLAlignment(0),
8521 dxaColumns(720), dxaColumnWidth(0), dmOrientFirst(0), fLayout(0),
8522 reserved4(0)
8526 bool checkRead(SvStream &rSt, void *pDest, sal_uInt32 nLength)
8528 return (rSt.ReadBytes(pDest, nLength) == static_cast<std::size_t>(nLength));
8531 #ifdef OSL_BIGENDIAN
8532 void swapEndian(sal_Unicode *pString)
8534 for (sal_Unicode *pWork = pString; *pWork; ++pWork)
8535 *pWork = OSL_SWAPWORD(*pWork);
8537 #endif
8539 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */