nss: upgrade to release 3.73
[LibreOffice.git] / sw / source / filter / ww8 / ww8scan.cxx
blob4a21a87b9a5c183c6e514af686c97b8649fc6eba
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>
35 #include <swerror.h>
37 #include <comphelper/string.hxx>
38 #include <unotools/localedatawrapper.hxx>
39 #include <i18nlangtag/lang.h>
40 #include <o3tl/safeint.hxx>
41 #include <tools/stream.hxx>
43 #include <vcl/settings.hxx>
44 #include <vcl/svapp.hxx>
46 #ifdef DEBUGSPRMREADER
47 #include <stdio.h>
48 #endif
50 using namespace ::com::sun::star::lang;
52 namespace
54 /**
55 winword strings are typically Belt and Braces strings preceded with a
56 pascal style count, and ending with a c style 0 terminator. 16bit chars
57 and count for ww8+ and 8bit chars and count for ww7-. The count and 0
58 can be checked for integrity to catch errors (e.g. lotus created
59 documents) where in error 8bit strings are used instead of 16bits
60 strings for style names.
62 bool TestBeltAndBraces(SvStream& rStrm)
64 bool bRet = false;
65 sal_uInt32 nOldPos = rStrm.Tell();
66 sal_uInt16 nBelt(0);
67 rStrm.ReadUInt16( nBelt );
68 nBelt *= sizeof(sal_Unicode);
69 if (rStrm.good() && (rStrm.remainingSize() >= (nBelt + sizeof(sal_Unicode))))
71 rStrm.SeekRel(nBelt);
72 if (rStrm.good())
74 sal_Unicode cBraces(0);
75 rStrm.ReadUtf16( cBraces );
76 if (rStrm.good() && cBraces == 0)
77 bRet = true;
80 rStrm.Seek(nOldPos);
81 return bRet;
85 const wwSprmSearcher *wwSprmParser::GetWW2SprmSearcher()
87 //double lock me
88 // WW2 Sprms
89 static const SprmInfoRow aSprms[] =
91 { 0, { 0, L_FIX} }, // "Default-sprm", will be skipped
92 { 2, { 1, L_FIX} }, // "sprmPIstd", pap.istd (style code)
93 { 3, { 0, L_VAR} }, // "sprmPIstdPermute pap.istd permutation
94 { 4, { 1, L_FIX} }, // "sprmPIncLv1" pap.istddifference
95 { 5, { 1, L_FIX} }, // "sprmPJc" pap.jc (justification)
96 { 6, { 1, L_FIX} }, // "sprmPFSideBySide" pap.fSideBySide
97 { 7, { 1, L_FIX} }, // "sprmPFKeep" pap.fKeep
98 { 8, { 1, L_FIX} }, // "sprmPFKeepFollow " pap.fKeepFollow
99 { 9, { 1, L_FIX} }, // "sprmPPageBreakBefore" pap.fPageBreakBefore
100 { 10, { 1, L_FIX} }, // "sprmPBrcl" pap.brcl
101 { 11, { 1, L_FIX} }, // "sprmPBrcp" pap.brcp
102 { 12, { 1, L_FIX} }, // "sprmPNfcSeqNumb" pap.nfcSeqNumb
103 { 13, { 1, L_FIX} }, // "sprmPNoSeqNumb" pap.nnSeqNumb
104 { 14, { 1, L_FIX} }, // "sprmPFNoLineNumb" pap.fNoLnn
105 { 15, { 0, L_VAR} }, // "?sprmPChgTabsPapx" pap.itbdMac, ...
106 { 16, { 2, L_FIX} }, // "sprmPDxaRight" pap.dxaRight
107 { 17, { 2, L_FIX} }, // "sprmPDxaLeft" pap.dxaLeft
108 { 18, { 2, L_FIX} }, // "sprmPNest" pap.dxaLeft
109 { 19, { 2, L_FIX} }, // "sprmPDxaLeft1" pap.dxaLeft1
110 { 20, { 2, L_FIX} }, // "sprmPDyaLine" pap.lspd an LSPD
111 { 21, { 2, L_FIX} }, // "sprmPDyaBefore" pap.dyaBefore
112 { 22, { 2, L_FIX} }, // "sprmPDyaAfter" pap.dyaAfter
113 { 23, { 0, L_VAR} }, // "?sprmPChgTabs" pap.itbdMac, pap.rgdxaTab, ...
114 { 24, { 1, L_FIX} }, // "sprmPFInTable" pap.fInTable
115 { 25, { 1, L_FIX} }, // "sprmPTtp" pap.fTtp
116 { 26, { 2, L_FIX} }, // "sprmPDxaAbs" pap.dxaAbs
117 { 27, { 2, L_FIX} }, // "sprmPDyaAbs" pap.dyaAbs
118 { 28, { 2, L_FIX} }, // "sprmPDxaWidth" pap.dxaWidth
119 { 29, { 1, L_FIX} }, // "sprmPPc" pap.pcHorz, pap.pcVert
120 { 30, { 2, L_FIX} }, // "sprmPBrcTop10" pap.brcTop BRC10
121 { 31, { 2, L_FIX} }, // "sprmPBrcLeft10" pap.brcLeft BRC10
122 { 32, { 2, L_FIX} }, // "sprmPBrcBottom10" pap.brcBottom BRC10
123 { 33, { 2, L_FIX} }, // "sprmPBrcRight10" pap.brcRight BRC10
124 { 34, { 2, L_FIX} }, // "sprmPBrcBetween10" pap.brcBetween BRC10
125 { 35, { 2, L_FIX} }, // "sprmPBrcBar10" pap.brcBar BRC10
126 { 36, { 2, L_FIX} }, // "sprmPFromText10" pap.dxaFromText dxa
127 { 37, { 1, L_FIX} }, // "sprmPWr" pap.wr wr
128 { 38, { 2, L_FIX} }, // "sprmPBrcTop" pap.brcTop BRC
129 { 39, { 2, L_FIX} }, // "sprmPBrcLeft" pap.brcLeft BRC
130 { 40, { 2, L_FIX} }, // "sprmPBrcBottom" pap.brcBottom BRC
131 { 41, { 2, L_FIX} }, // "sprmPBrcRight" pap.brcRight BRC
132 { 42, { 2, L_FIX} }, // "sprmPBrcBetween" pap.brcBetween BRC
133 { 43, { 2, L_FIX} }, // "sprmPBrcBar" pap.brcBar BRC word
134 { 44, { 1, L_FIX} }, // "sprmPFNoAutoHyph" pap.fNoAutoHyph
135 { 45, { 2, L_FIX} }, // "sprmPWHeightAbs" pap.wHeightAbs w
136 { 46, { 2, L_FIX} }, // "sprmPDcs" pap.dcs DCS
137 { 47, { 2, L_FIX} }, // "sprmPShd" pap.shd SHD
138 { 48, { 2, L_FIX} }, // "sprmPDyaFromText" pap.dyaFromText dya
139 { 49, { 2, L_FIX} }, // "sprmPDxaFromText" pap.dxaFromText dxa
140 { 50, { 1, L_FIX} }, // "sprmPFBiDi" pap.fBiDi 0 or 1 byte
141 { 51, { 1, L_FIX} }, // "sprmPFWidowControl" pap.fWidowControl 0 or 1 byte
142 { 52, { 0, L_FIX} }, // "?sprmPRuler 52"
143 { 53, { 1, L_FIX} }, // "sprmCFStrikeRM" chp.fRMarkDel 1 or 0 bit
144 { 54, { 1, L_FIX} }, // "sprmCFRMark" chp.fRMark 1 or 0 bit
145 { 55, { 1, L_FIX} }, // "sprmCFFieldVanish" chp.fFieldVanish 1 or 0 bit
146 { 57, { 0, L_VAR} }, // "sprmCDefault" whole CHP
147 { 58, { 0, L_FIX} }, // "sprmCPlain" whole CHP
148 { 60, { 1, L_FIX} }, // "sprmCFBold" chp.fBold 0,1, 128, or 129
149 { 61, { 1, L_FIX} }, // "sprmCFItalic" chp.fItalic 0,1, 128, or 129
150 { 62, { 1, L_FIX} }, // "sprmCFStrike" chp.fStrike 0,1, 128, or 129
151 { 63, { 1, L_FIX} }, // "sprmCFOutline" chp.fOutline 0,1, 128, or 129
152 { 64, { 1, L_FIX} }, // "sprmCFShadow" chp.fShadow 0,1, 128, or 129
153 { 65, { 1, L_FIX} }, // "sprmCFSmallCaps" chp.fSmallCaps 0,1, 128, or 129
154 { 66, { 1, L_FIX} }, // "sprmCFCaps" chp.fCaps 0,1, 128, or 129
155 { 67, { 1, L_FIX} }, // "sprmCFVanish" chp.fVanish 0,1, 128, or 129
156 { 68, { 2, L_FIX} }, // "sprmCFtc" chp.ftc ftc word
157 { 69, { 1, L_FIX} }, // "sprmCKul" chp.kul kul byte
158 { 70, { 3, L_FIX} }, // "sprmCSizePos" chp.hps, chp.hpsPos
159 { 71, { 2, L_FIX} }, // "sprmCDxaSpace" chp.dxaSpace dxa
160 { 72, { 2, L_FIX} }, // "sprmCLid" chp.lid LID
161 { 73, { 1, L_FIX} }, // "sprmCIco" chp.ico ico byte
162 { 74, { 1, L_FIX} }, // "sprmCHps" chp.hps hps !word!
163 { 75, { 1, L_FIX} }, // "sprmCHpsInc" chp.hps
164 { 76, { 1, L_FIX} }, // "sprmCHpsPos" chp.hpsPos hps !word!
165 { 77, { 1, L_FIX} }, // "sprmCHpsPosAdj" chp.hpsPos hps
166 { 78, { 0, L_VAR} }, // "?sprmCMajority" chp.fBold, chp.fItalic, ...
167 { 80, { 1, L_FIX} }, // "sprmCFBoldBi" chp.fBoldBi
168 { 81, { 1, L_FIX} }, // "sprmCFItalicBi" chp.fItalicBi
169 { 82, { 2, L_FIX} }, // "sprmCFtcBi" chp.ftcBi
170 { 83, { 2, L_FIX} }, // "sprmClidBi" chp.lidBi
171 { 84, { 1, L_FIX} }, // "sprmCIcoBi" chp.icoBi
172 { 85, { 1, L_FIX} }, // "sprmCHpsBi" chp.hpsBi
173 { 86, { 1, L_FIX} }, // "sprmCFBiDi" chp.fBiDi
174 { 87, { 1, L_FIX} }, // "sprmCFDiacColor" chp.fDiacUSico
175 { 94, { 1, L_FIX} }, // "sprmPicBrcl" pic.brcl brcl (see PIC definition)
176 { 95, {12, L_VAR} }, // "sprmPicScale" pic.mx, pic.my, pic.dxaCropleft,
177 { 96, { 2, L_FIX} }, // "sprmPicBrcTop" pic.brcTop BRC word
178 { 97, { 2, L_FIX} }, // "sprmPicBrcLeft" pic.brcLeft BRC word
179 { 98, { 2, L_FIX} }, // "sprmPicBrcBottom" pic.brcBottom BRC word
180 { 99, { 2, L_FIX} }, // "sprmPicBrcRight" pic.brcRight BRC word
181 {112, { 1, L_FIX} }, // "sprmSFRTLGutter", set to one if gutter is on
182 {114, { 1, L_FIX} }, // "sprmSFBiDi" ;;;
183 {115, { 2, L_FIX} }, // "sprmSDmBinFirst" sep.dmBinFirst word
184 {116, { 2, L_FIX} }, // "sprmSDmBinOther" sep.dmBinOther word
185 {117, { 1, L_FIX} }, // "sprmSBkc" sep.bkc bkc byte
186 {118, { 1, L_FIX} }, // "sprmSFTitlePage" sep.fTitlePage 0 or 1 byte
187 {119, { 2, L_FIX} }, // "sprmSCcolumns" sep.ccolM1 # of cols - 1 word
188 {120, { 2, L_FIX} }, // "sprmSDxaColumns" sep.dxaColumns dxa word
189 {121, { 1, L_FIX} }, // "sprmSFAutoPgn" sep.fAutoPgn obsolete byte
190 {122, { 1, L_FIX} }, // "sprmSNfcPgn" sep.nfcPgn nfc byte
191 {123, { 2, L_FIX} }, // "sprmSDyaPgn" sep.dyaPgn dya short
192 {124, { 2, L_FIX} }, // "sprmSDxaPgn" sep.dxaPgn dya short
193 {125, { 1, L_FIX} }, // "sprmSFPgnRestart" sep.fPgnRestart 0 or 1 byte
194 {126, { 1, L_FIX} }, // "sprmSFEndnote" sep.fEndnote 0 or 1 byte
195 {127, { 1, L_FIX} }, // "sprmSLnc" sep.lnc lnc byte
196 {128, { 1, L_FIX} }, // "sprmSGprfIhdt" sep.grpfIhdt grpfihdt
197 {129, { 2, L_FIX} }, // "sprmSNLnnMod" sep.nLnnMod non-neg int. word
198 {130, { 2, L_FIX} }, // "sprmSDxaLnn" sep.dxaLnn dxa word
199 {131, { 2, L_FIX} }, // "sprmSDyaHdrTop" sep.dyaHdrTop dya word
200 {132, { 2, L_FIX} }, // "sprmSDyaHdrBottom" sep.dyaHdrBottom dya word
201 {133, { 1, L_FIX} }, // "sprmSLBetween" sep.fLBetween 0 or 1 byte
202 {134, { 1, L_FIX} }, // "sprmSVjc" sep.vjc vjc byte
203 {135, { 2, L_FIX} }, // "sprmSLnnMin" sep.lnnMin lnn word
204 {136, { 2, L_FIX} }, // "sprmSPgnStart" sep.pgnStart pgn word
205 {137, { 1, L_FIX} }, // "sprmSBOrientation" sep.dmOrientPage dm byte
206 {138, { 1, L_FIX} }, // "sprmSFFacingCol" ;;;
207 {139, { 2, L_FIX} }, // "sprmSXaPage" sep.xaPage xa word
208 {140, { 2, L_FIX} }, // "sprmSYaPage" sep.yaPage ya word
209 {141, { 2, L_FIX} }, // "sprmSDxaLeft" sep.dxaLeft dxa word
210 {142, { 2, L_FIX} }, // "sprmSDxaRight" sep.dxaRight dxa word
211 {143, { 2, L_FIX} }, // "sprmSDyaTop" sep.dyaTop dya word
212 {144, { 2, L_FIX} }, // "sprmSDyaBottom" sep.dyaBottom dya word
213 {145, { 2, L_FIX} }, // "sprmSDzaGutter" sep.dzaGutter dza word
214 {146, { 2, L_FIX} }, // "sprmTJc" tap.jc jc (low order byte is significant)
215 {147, { 2, L_FIX} }, // "sprmTDxaLeft" tap.rgdxaCenter dxa word
216 {148, { 2, L_FIX} }, // "sprmTDxaGapHalf" tap.dxaGapHalf, tap.rgdxaCenter
217 {149, { 1, L_FIX} }, // "sprmTFBiDi" ;;;
218 {152, { 0, L_VAR} }, // "sprmTDefTable10" tap.rgdxaCenter, tap.rgtc complex
219 {153, { 2, L_FIX} }, // "sprmTDyaRowHeight" tap.dyaRowHeight dya word
220 {154, { 0, L_VAR2} },// "sprmTDefTable" tap.rgtc complex
221 {155, { 1, L_VAR} }, // "sprmTDefTableShd" tap.rgshd complex
222 {157, { 5, L_FIX} }, // "sprmTSetBrc" tap.rgtc[].rgbrc complex 5 bytes
223 {158, { 4, L_FIX} }, // "sprmTInsert" tap.rgdxaCenter,tap.rgtc complex
224 {159, { 2, L_FIX} }, // "sprmTDelete" tap.rgdxaCenter, tap.rgtc complex
225 {160, { 4, L_FIX} }, // "sprmTDxaCol" tap.rgdxaCenter complex
226 {161, { 2, L_FIX} }, // "sprmTMerge" tap.fFirstMerged, tap.fMerged complex
227 {162, { 2, L_FIX} }, // "sprmTSplit" tap.fFirstMerged, tap.fMerged complex
228 {163, { 5, L_FIX} }, // "sprmTSetBrc10" tap.rgtc[].rgbrc complex 5 bytes
229 {164, { 4, L_FIX} }, // "sprmTSetShd", tap.rgshd complex 4 bytes
232 static wwSprmSearcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
233 return &aSprmSrch;
236 const wwSprmSearcher *wwSprmParser::GetWW6SprmSearcher(const WW8Fib& rFib)
238 //double lock me
239 // WW7- Sprms
240 static const SprmInfoRow aSprms[] =
242 { 0, { 0, L_FIX} }, // "Default-sprm", is skipped
243 {NS_sprm::v6::sprmPIstd, { 2, L_FIX} }, // pap.istd (style code)
244 {NS_sprm::v6::sprmPIstdPermute, { 3, L_VAR} }, // pap.istd permutation
245 {NS_sprm::v6::sprmPIncLv1, { 1, L_FIX} }, // pap.istddifference
246 {NS_sprm::v6::sprmPJc, { 1, L_FIX} }, // pap.jc (justification)
247 {NS_sprm::v6::sprmPFSideBySide, { 1, L_FIX} }, // pap.fSideBySide
248 {NS_sprm::v6::sprmPFKeep, { 1, L_FIX} }, // pap.fKeep
249 {NS_sprm::v6::sprmPFKeepFollow, { 1, L_FIX} }, // pap.fKeepFollow
250 {NS_sprm::v6::sprmPPageBreakBefore, { 1, L_FIX} }, // pap.fPageBreakBefore
251 {NS_sprm::v6::sprmPBrcl, { 1, L_FIX} }, // pap.brcl
252 {NS_sprm::v6::sprmPBrcp, { 1, L_FIX} }, // pap.brcp
253 {NS_sprm::v6::sprmPAnld, { 0, L_VAR} }, // pap.anld (ANLD structure)
254 {NS_sprm::v6::sprmPNLvlAnm, { 1, L_FIX} }, // pap.nLvlAnm nn
255 {NS_sprm::v6::sprmPFNoLineNumb, { 1, L_FIX} }, // pap.fNoLnn
256 {NS_sprm::v6::sprmPChgTabsPapx, { 0, L_VAR} }, // pap.itbdMac, ...
257 {NS_sprm::v6::sprmPDxaRight, { 2, L_FIX} }, // pap.dxaRight
258 {NS_sprm::v6::sprmPDxaLeft, { 2, L_FIX} }, // pap.dxaLeft
259 {NS_sprm::v6::sprmPNest, { 2, L_FIX} }, // pap.dxaLeft
260 {NS_sprm::v6::sprmPDxaLeft1, { 2, L_FIX} }, // pap.dxaLeft1
261 {NS_sprm::v6::sprmPDyaLine, { 4, L_FIX} }, // pap.lspd an LSPD
262 {NS_sprm::v6::sprmPDyaBefore, { 2, L_FIX} }, // pap.dyaBefore
263 {NS_sprm::v6::sprmPDyaAfter, { 2, L_FIX} }, // pap.dyaAfter
264 {NS_sprm::v6::sprmPChgTabs, { 0, L_VAR} }, // pap.itbdMac, pap.rgdxaTab, ...
265 {NS_sprm::v6::sprmPFInTable, { 1, L_FIX} }, // pap.fInTable
266 {NS_sprm::v6::sprmPTtp, { 1, L_FIX} }, // pap.fTtp
267 {NS_sprm::v6::sprmPDxaAbs, { 2, L_FIX} }, // pap.dxaAbs
268 {NS_sprm::v6::sprmPDyaAbs, { 2, L_FIX} }, // pap.dyaAbs
269 {NS_sprm::v6::sprmPDxaWidth, { 2, L_FIX} }, // pap.dxaWidth
270 {NS_sprm::v6::sprmPPc, { 1, L_FIX} }, // pap.pcHorz, pap.pcVert
271 {NS_sprm::v6::sprmPBrcTop10, { 2, L_FIX} }, // pap.brcTop BRC10
272 {NS_sprm::v6::sprmPBrcLeft10, { 2, L_FIX} }, // pap.brcLeft BRC10
273 {NS_sprm::v6::sprmPBrcBottom10, { 2, L_FIX} }, // pap.brcBottom BRC10
274 {NS_sprm::v6::sprmPBrcRight10, { 2, L_FIX} }, // pap.brcRight BRC10
275 {NS_sprm::v6::sprmPBrcBetween10, { 2, L_FIX} }, // pap.brcBetween BRC10
276 {NS_sprm::v6::sprmPBrcBar10, { 2, L_FIX} }, // pap.brcBar BRC10
277 {NS_sprm::v6::sprmPFromText10, { 2, L_FIX} }, // pap.dxaFromText dxa
278 {NS_sprm::v6::sprmPWr, { 1, L_FIX} }, // pap.wr wr
279 {NS_sprm::v6::sprmPBrcTop, { 2, L_FIX} }, // pap.brcTop BRC
280 {NS_sprm::v6::sprmPBrcLeft, { 2, L_FIX} }, // pap.brcLeft BRC
281 {NS_sprm::v6::sprmPBrcBottom, { 2, L_FIX} }, // pap.brcBottom BRC
282 {NS_sprm::v6::sprmPBrcRight, { 2, L_FIX} }, // pap.brcRight BRC
283 {NS_sprm::v6::sprmPBrcBetween, { 2, L_FIX} }, // pap.brcBetween BRC
284 {NS_sprm::v6::sprmPBrcBar, { 2, L_FIX} }, // pap.brcBar BRC word
285 {NS_sprm::v6::sprmPFNoAutoHyph, { 1, L_FIX} }, // pap.fNoAutoHyph
286 {NS_sprm::v6::sprmPWHeightAbs, { 2, L_FIX} }, // pap.wHeightAbs w
287 {NS_sprm::v6::sprmPDcs, { 2, L_FIX} }, // pap.dcs DCS
288 {NS_sprm::v6::sprmPShd, { 2, L_FIX} }, // pap.shd SHD
289 {NS_sprm::v6::sprmPDyaFromText, { 2, L_FIX} }, // pap.dyaFromText dya
290 {NS_sprm::v6::sprmPDxaFromText, { 2, L_FIX} }, // pap.dxaFromText dxa
291 {NS_sprm::v6::sprmPFLocked, { 1, L_FIX} }, // pap.fLocked 0 or 1 byte
292 {NS_sprm::v6::sprmPFWidowControl, { 1, L_FIX} }, // pap.fWidowControl 0 or 1 byte
293 {NS_sprm::v6::sprmPRuler, { 0, L_FIX} },
294 { 64, { 0, L_VAR} }, // rtl property ?
295 {NS_sprm::v6::sprmCFStrikeRM, { 1, L_FIX} }, // chp.fRMarkDel 1 or 0 bit
296 {NS_sprm::v6::sprmCFRMark, { 1, L_FIX} }, // chp.fRMark 1 or 0 bit
297 {NS_sprm::v6::sprmCFFldVanish, { 1, L_FIX} }, // chp.fFieldVanish 1 or 0 bit
298 {NS_sprm::v6::sprmCPicLocation, { 0, L_VAR} }, // chp.fcPic and chp.fSpec
299 {NS_sprm::v6::sprmCIbstRMark, { 2, L_FIX} }, // chp.ibstRMark index into sttbRMark
300 {NS_sprm::v6::sprmCDttmRMark, { 4, L_FIX} }, // chp.dttm DTTM long
301 {NS_sprm::v6::sprmCFData, { 1, L_FIX} }, // chp.fData 1 or 0 bit
302 {NS_sprm::v6::sprmCRMReason, { 2, L_FIX} }, // chp.idslRMReason an index to a table
303 {NS_sprm::v6::sprmCChse, { 3, L_FIX} }, // chp.fChsDiff and chp.chse
304 {NS_sprm::v6::sprmCSymbol, { 0, L_VAR} }, // chp.fSpec, chp.chSym and chp.ftcSym
305 {NS_sprm::v6::sprmCFOle2, { 1, L_FIX} }, // chp.fOle2 1 or 0 bit
306 { 77, { 0, L_VAR} }, // unknown
307 { 79, { 0, L_VAR} }, // unknown
308 {NS_sprm::v6::sprmCIstd, { 2, L_FIX} }, // chp.istd istd, see stylesheet definition
309 {NS_sprm::v6::sprmCIstdPermute, { 0, L_VAR} }, // chp.istd permutation vector
310 {NS_sprm::v6::sprmCDefault, { 0, L_VAR} }, // whole CHP
311 {NS_sprm::v6::sprmCPlain, { 0, L_FIX} }, // whole CHP
312 {NS_sprm::v6::sprmCFBold, { 1, L_FIX} }, // chp.fBold 0,1, 128, or 129
313 {NS_sprm::v6::sprmCFItalic, { 1, L_FIX} }, // chp.fItalic 0,1, 128, or 129
314 {NS_sprm::v6::sprmCFStrike, { 1, L_FIX} }, // chp.fStrike 0,1, 128, or 129
315 {NS_sprm::v6::sprmCFOutline, { 1, L_FIX} }, // chp.fOutline 0,1, 128, or 129
316 {NS_sprm::v6::sprmCFShadow, { 1, L_FIX} }, // chp.fShadow 0,1, 128, or 129
317 {NS_sprm::v6::sprmCFSmallCaps, { 1, L_FIX} }, // chp.fSmallCaps 0,1, 128, or 129
318 {NS_sprm::v6::sprmCFCaps, { 1, L_FIX} }, // chp.fCaps 0,1, 128, or 129
319 {NS_sprm::v6::sprmCFVanish, { 1, L_FIX} }, // chp.fVanish 0,1, 128, or 129
320 {NS_sprm::v6::sprmCFtc, { 2, L_FIX} }, // chp.ftc ftc word
321 {NS_sprm::v6::sprmCKul, { 1, L_FIX} }, // chp.kul kul byte
322 {NS_sprm::v6::sprmCSizePos, { 3, L_FIX} }, // chp.hps, chp.hpsPos
323 {NS_sprm::v6::sprmCDxaSpace, { 2, L_FIX} }, // chp.dxaSpace dxa
324 {NS_sprm::v6::sprmCLid, { 2, L_FIX} }, // chp.lid LID
325 {NS_sprm::v6::sprmCIco, { 1, L_FIX} }, // chp.ico ico byte
326 {NS_sprm::v6::sprmCHps, { 2, L_FIX} }, // chp.hps hps !word!
327 {NS_sprm::v6::sprmCHpsInc, { 1, L_FIX} }, // chp.hps
328 {NS_sprm::v6::sprmCHpsPos, { 2, L_FIX} }, // chp.hpsPos hps !word!
329 {NS_sprm::v6::sprmCHpsPosAdj, { 1, L_FIX} }, // chp.hpsPos hps
330 {NS_sprm::v6::sprmCMajority, { 0, L_VAR} }, // chp.fBold, chp.fItalic, ...
331 {NS_sprm::v6::sprmCIss, { 1, L_FIX} }, // chp.iss iss
332 {NS_sprm::v6::sprmCHpsNew50, { 0, L_VAR} }, // chp.hps hps variable width
333 {NS_sprm::v6::sprmCHpsInc1, { 0, L_VAR} }, // chp.hps complex
334 {NS_sprm::v6::sprmCHpsKern, { 2, L_FIX} }, // chp.hpsKern hps
335 {NS_sprm::v6::sprmCMajority50, { 0, L_VAR} }, // chp.fBold, chp.fItalic, ...
336 {NS_sprm::v6::sprmCHpsMul, { 2, L_FIX} }, // chp.hps percentage to grow hps
337 {NS_sprm::v6::sprmCCondHyhen, { 2, L_FIX} }, // chp.ysri ysri
338 {111, { 0, L_VAR} }, // sprmCFBoldBi or font code
339 {112, { 0, L_VAR} }, // sprmCFItalicBi or font code
340 {113, { 0, L_VAR} }, // ww7 rtl font
341 {114, { 0, L_VAR} }, // ww7 lid
342 {115, { 0, L_VAR} }, // ww7 CJK font
343 {116, { 0, L_VAR} }, // ww7 fontsize
344 {NS_sprm::v6::sprmCFSpec, { 1, L_FIX} }, // chp.fSpec 1 or 0 bit
345 {NS_sprm::v6::sprmCFObj, { 1, L_FIX} }, // chp.fObj 1 or 0 bit
346 {NS_sprm::v6::sprmPicBrcl, { 1, L_FIX} }, // pic.brcl brcl (see PIC definition)
347 {NS_sprm::v6::sprmPicScale, {12, L_VAR} }, // pic.mx, pic.my, pic.dxaCropleft,
348 {NS_sprm::v6::sprmPicBrcTop, { 2, L_FIX} }, // pic.brcTop BRC word
349 {NS_sprm::v6::sprmPicBrcLeft, { 2, L_FIX} }, // pic.brcLeft BRC word
350 {NS_sprm::v6::sprmPicBrcBottom, { 2, L_FIX} }, // pic.brcBottom BRC word
351 {NS_sprm::v6::sprmPicBrcRight, { 2, L_FIX} }, // pic.brcRight BRC word
352 {NS_sprm::v6::sprmSScnsPgn, { 1, L_FIX} }, // sep.cnsPgn cns byte
353 {NS_sprm::v6::sprmSiHeadingPgn, { 1, L_FIX} }, // sep.iHeadingPgn
354 {NS_sprm::v6::sprmSOlstAnm, { 0, L_VAR} }, // sep.olstAnm OLST variable length
355 {NS_sprm::v6::sprmSDxaColWidth, { 3, L_FIX} }, // sep.rgdxaColWidthSpacing complex
356 {NS_sprm::v6::sprmSDxaColSpacing, { 3, L_FIX} }, // sep.rgdxaColWidthSpacing
357 {NS_sprm::v6::sprmSFEvenlySpaced, { 1, L_FIX} }, // sep.fEvenlySpaced 1 or 0
358 {NS_sprm::v6::sprmSFProtected, { 1, L_FIX} }, // sep.fUnlocked 1 or 0 byte
359 {NS_sprm::v6::sprmSDmBinFirst, { 2, L_FIX} }, // sep.dmBinFirst word
360 {NS_sprm::v6::sprmSDmBinOther, { 2, L_FIX} }, // sep.dmBinOther word
361 {NS_sprm::v6::sprmSBkc, { 1, L_FIX} }, // sep.bkc bkc byte
362 {NS_sprm::v6::sprmSFTitlePage, { 1, L_FIX} }, // sep.fTitlePage 0 or 1 byte
363 {NS_sprm::v6::sprmSCcolumns, { 2, L_FIX} }, // sep.ccolM1 # of cols - 1 word
364 {NS_sprm::v6::sprmSDxaColumns, { 2, L_FIX} }, // sep.dxaColumns dxa word
365 {NS_sprm::v6::sprmSFAutoPgn, { 1, L_FIX} }, // sep.fAutoPgn obsolete byte
366 {NS_sprm::v6::sprmSNfcPgn, { 1, L_FIX} }, // sep.nfcPgn nfc byte
367 {NS_sprm::v6::sprmSDyaPgn, { 2, L_FIX} }, // sep.dyaPgn dya short
368 {NS_sprm::v6::sprmSDxaPgn, { 2, L_FIX} }, // sep.dxaPgn dya short
369 {NS_sprm::v6::sprmSFPgnRestart, { 1, L_FIX} }, // sep.fPgnRestart 0 or 1 byte
370 {NS_sprm::v6::sprmSFEndnote, { 1, L_FIX} }, // sep.fEndnote 0 or 1 byte
371 {NS_sprm::v6::sprmSLnc, { 1, L_FIX} }, // sep.lnc lnc byte
372 {NS_sprm::v6::sprmSGprfIhdt, { 1, L_FIX} }, // sep.grpfIhdt grpfihdt
373 {NS_sprm::v6::sprmSNLnnMod, { 2, L_FIX} }, // sep.nLnnMod non-neg int. word
374 {NS_sprm::v6::sprmSDxaLnn, { 2, L_FIX} }, // sep.dxaLnn dxa word
375 {NS_sprm::v6::sprmSDyaHdrTop, { 2, L_FIX} }, // sep.dyaHdrTop dya word
376 {NS_sprm::v6::sprmSDyaHdrBottom, { 2, L_FIX} }, // sep.dyaHdrBottom dya word
377 {NS_sprm::v6::sprmSLBetween, { 1, L_FIX} }, // sep.fLBetween 0 or 1 byte
378 {NS_sprm::v6::sprmSVjc, { 1, L_FIX} }, // sep.vjc vjc byte
379 {NS_sprm::v6::sprmSLnnMin, { 2, L_FIX} }, // sep.lnnMin lnn word
380 {NS_sprm::v6::sprmSPgnStart, { 2, L_FIX} }, // sep.pgnStart pgn word
381 {NS_sprm::v6::sprmSBOrientation, { 1, L_FIX} }, // sep.dmOrientPage dm byte
382 {NS_sprm::v6::sprmSBCustomize, { 0, L_FIX} },
383 {NS_sprm::v6::sprmSXaPage, { 2, L_FIX} }, // sep.xaPage xa word
384 {NS_sprm::v6::sprmSYaPage, { 2, L_FIX} }, // sep.yaPage ya word
385 {NS_sprm::v6::sprmSDxaLeft, { 2, L_FIX} }, // sep.dxaLeft dxa word
386 {NS_sprm::v6::sprmSDxaRight, { 2, L_FIX} }, // sep.dxaRight dxa word
387 {NS_sprm::v6::sprmSDyaTop, { 2, L_FIX} }, // sep.dyaTop dya word
388 {NS_sprm::v6::sprmSDyaBottom, { 2, L_FIX} }, // sep.dyaBottom dya word
389 {NS_sprm::v6::sprmSDzaGutter, { 2, L_FIX} }, // sep.dzaGutter dza word
390 {NS_sprm::v6::sprmSDMPaperReq, { 2, L_FIX} }, // sep.dmPaperReq dm word
391 {179, { 0, L_VAR} }, // rtl property ?
392 {181, { 0, L_VAR} }, // rtl property ?
393 {NS_sprm::v6::sprmTJc, { 2, L_FIX} }, // tap.jc jc (low order byte is significant)
394 {NS_sprm::v6::sprmTDxaLeft, { 2, L_FIX} }, // tap.rgdxaCenter dxa word
395 {NS_sprm::v6::sprmTDxaGapHalf, { 2, L_FIX} }, // tap.dxaGapHalf, tap.rgdxaCenter
396 {NS_sprm::v6::sprmTFCantSplit, { 1, L_FIX} }, // tap.fCantSplit 1 or 0 byte
397 {NS_sprm::v6::sprmTTableHeader, { 1, L_FIX} }, // tap.fTableHeader 1 or 0 byte
398 {NS_sprm::v6::sprmTTableBorders, {12, L_FIX} }, // tap.rgbrcTable complex 12 bytes
399 {NS_sprm::v6::sprmTDefTable10, { 0, L_VAR} }, // tap.rgdxaCenter, tap.rgtc complex
400 {NS_sprm::v6::sprmTDyaRowHeight, { 2, L_FIX} }, // tap.dyaRowHeight dya word
401 {NS_sprm::v6::sprmTDefTable, { 0, L_VAR2} }, // tap.rgtc complex
402 {NS_sprm::v6::sprmTDefTableShd, { 1, L_VAR} }, // tap.rgshd complex
403 {NS_sprm::v6::sprmTTlp, { 4, L_FIX} }, // tap.tlp TLP 4 bytes
404 {NS_sprm::v6::sprmTSetBrc, { 5, L_FIX} }, // tap.rgtc[].rgbrc complex 5 bytes
405 {NS_sprm::v6::sprmTInsert, { 4, L_FIX} }, // tap.rgdxaCenter,tap.rgtc complex
406 {NS_sprm::v6::sprmTDelete, { 2, L_FIX} }, // tap.rgdxaCenter, tap.rgtc complex
407 {NS_sprm::v6::sprmTDxaCol, { 4, L_FIX} }, // tap.rgdxaCenter complex
408 {NS_sprm::v6::sprmTMerge, { 2, L_FIX} }, // tap.fFirstMerged, tap.fMerged complex
409 {NS_sprm::v6::sprmTSplit, { 2, L_FIX} }, // tap.fFirstMerged, tap.fMerged complex
410 {NS_sprm::v6::sprmTSetBrc10, { 5, L_FIX} }, // tap.rgtc[].rgbrc complex 5 bytes
411 {NS_sprm::v6::sprmTSetShd, { 4, L_FIX} }, // tap.rgshd complex 4 bytes
412 {207, { 0, L_VAR} } // rtl property ?
415 if (rFib.m_wIdent >= 0xa697 && rFib.m_wIdent <= 0xa699)
417 //see Read_AmbiguousSPRM for this oddity
418 static wwSprmSearcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms), true);
419 return &aSprmSrch;
422 static wwSprmSearcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
423 return &aSprmSrch;
426 void wwSprmSearcher::patchCJKVariant()
428 for (sal_uInt16 nId = 111; nId <= 113; ++nId)
430 SprmInfo& amb1 = map_[nId];
431 amb1.nLen = 2;
432 amb1.nVari = wwSprmParser::L_FIX;
436 template <class Sprm> static constexpr SprmInfoRow InfoRow()
438 return { Sprm::val, { Sprm::len, Sprm::varlen ? wwSprmParser::L_VAR : wwSprmParser::L_FIX } };
441 const wwSprmSearcher *wwSprmParser::GetWW8SprmSearcher()
443 //double lock me
444 //WW8+ Sprms
445 static const SprmInfoRow aSprms[] =
447 { 0, { 0, L_FIX} }, // "Default-sprm"/ is skipped
448 InfoRow<NS_sprm::PIstd>(), // pap.istd;istd (style code);short;
449 InfoRow<NS_sprm::PIstdPermute>(), // pap.istd;permutation vector
450 InfoRow<NS_sprm::PIncLvl>(), // pap.istd, pap.lvl;difference
451 // between istd of base PAP and istd of PAP to be
452 // produced
453 InfoRow<NS_sprm::PJc80>(), // pap.jc;jc (justification);byte;
454 {NS_sprm::LN_PFSideBySide, { 1, L_FIX} }, // "sprmPFSideBySide" pap.fSideBySide;0 or 1;byte;
455 InfoRow<NS_sprm::PFKeep>(), // pap.fKeep;0 or 1;byte;
456 InfoRow<NS_sprm::PFKeepFollow>(), // pap.fKeepFollow;0 or 1;byte;
457 InfoRow<NS_sprm::PFPageBreakBefore>(), // pap.fPageBreakBefore;
458 // 0 or 1
459 {NS_sprm::LN_PBrcl, { 1, L_FIX} }, // "sprmPBrcl" pap.brcl;brcl;byte;
460 {NS_sprm::LN_PBrcp, { 1, L_FIX} }, // "sprmPBrcp" pap.brcp;brcp;byte;
461 InfoRow<NS_sprm::PIlvl>(), // pap.ilvl;ilvl;byte;
462 InfoRow<NS_sprm::PIlfo>(), // pap.ilfo;ilfo (list index) ;short;
463 InfoRow<NS_sprm::PFNoLineNumb>(), // pap.fNoLnn;0 or 1;byte;
464 InfoRow<NS_sprm::PChgTabsPapx>(), // pap.itbdMac, pap.rgdxaTab,
465 // pap.rgtbd;complex
466 InfoRow<NS_sprm::PDxaRight80>(), // pap.dxaRight;dxa;word;
467 InfoRow<NS_sprm::PDxaLeft80>(), // pap.dxaLeft;dxa;word;
468 InfoRow<NS_sprm::PNest80>(), // pap.dxaLeft;dxa
469 InfoRow<NS_sprm::PDxaLeft180>(), // pap.dxaLeft1;dxa;word;
470 InfoRow<NS_sprm::PDyaLine>(), // pap.lspd;an LSPD, a long word
471 // structure consisting of a short of dyaLine
472 // followed by a short of fMultLinespace
473 InfoRow<NS_sprm::PDyaBefore>(), // pap.dyaBefore;dya;word;
474 InfoRow<NS_sprm::PDyaAfter>(), // pap.dyaAfter;dya;word;
475 InfoRow<NS_sprm::PChgTabs>(), // pap.itbdMac, pap.rgdxaTab,
476 // pap.rgtbd;complex
477 InfoRow<NS_sprm::PFInTable>(), // pap.fInTable;0 or 1;byte;
478 InfoRow<NS_sprm::PFTtp>(), // pap.fTtp;0 or 1;byte;
479 InfoRow<NS_sprm::PDxaAbs>(), // pap.dxaAbs;dxa;word;
480 InfoRow<NS_sprm::PDyaAbs>(), // pap.dyaAbs;dya;word;
481 InfoRow<NS_sprm::PDxaWidth>(), // pap.dxaWidth;dxa;word;
482 InfoRow<NS_sprm::PPc>(), // pap.pcHorz, pap.pcVert;complex
483 {NS_sprm::LN_PBrcTop10, { 2, L_FIX} }, // "sprmPBrcTop10" pap.brcTop;BRC10;word;
484 {NS_sprm::LN_PBrcLeft10, { 2, L_FIX} }, // "sprmPBrcLeft10" pap.brcLeft;BRC10;word;
485 {NS_sprm::LN_PBrcBottom10, { 2, L_FIX} }, // "sprmPBrcBottom10" pap.brcBottom;BRC10;word;
486 {NS_sprm::LN_PBrcRight10, { 2, L_FIX} }, // "sprmPBrcRight10" pap.brcRight;BRC10;word;
487 {NS_sprm::LN_PBrcBetween10, { 2, L_FIX} }, // "sprmPBrcBetween10" pap.brcBetween;BRC10;word;
488 {NS_sprm::LN_PBrcBar10, { 2, L_FIX} }, // "sprmPBrcBar10" pap.brcBar;BRC10;word;
489 {NS_sprm::LN_PDxaFromText10, { 2, L_FIX} }, // "sprmPDxaFromText10" pap.dxaFromText;dxa;word;
490 InfoRow<NS_sprm::PWr>(), // pap.wr;wr
491 InfoRow<NS_sprm::PBrcTop80>(), // pap.brcTop;BRC;long;
492 InfoRow<NS_sprm::PBrcLeft80>(), // pap.brcLeft;BRC;long;
493 InfoRow<NS_sprm::PBrcBottom80>(), // pap.brcBottom;BRC;long;
494 InfoRow<NS_sprm::PBrcRight80>(), // pap.brcRight;BRC;long;
495 InfoRow<NS_sprm::PBrcBetween80>(), // pap.brcBetween;BRC;long;
496 InfoRow<NS_sprm::PBrcBar80>(), // pap.brcBar;BRC;long;
497 InfoRow<NS_sprm::PFNoAutoHyph>(), // pap.fNoAutoHyph;0 or 1;byte;
498 InfoRow<NS_sprm::PWHeightAbs>(), // pap.wHeightAbs;w;word;
499 InfoRow<NS_sprm::PDcs>(), // pap.dcs;DCS;short;
500 InfoRow<NS_sprm::PShd80>(), // pap.shd;SHD;word;
501 InfoRow<NS_sprm::PDyaFromText>(), // pap.dyaFromText;dya;word;
502 InfoRow<NS_sprm::PDxaFromText>(), // pap.dxaFromText;dxa;word;
503 InfoRow<NS_sprm::PFLocked>(), // pap.fLocked;0 or 1;byte;
504 InfoRow<NS_sprm::PFWidowControl>(), // pap.fWidowControl;0 or 1
505 {NS_sprm::LN_PRuler, { 0, L_VAR} }, // "sprmPRuler" ;;variable length;
506 InfoRow<NS_sprm::PFKinsoku>(), // pap.fKinsoku;0 or 1;byte;
507 InfoRow<NS_sprm::PFWordWrap>(), // pap.fWordWrap;0 or 1;byte;
508 InfoRow<NS_sprm::PFOverflowPunct>(), // pap.fOverflowPunct;0 or 1
509 InfoRow<NS_sprm::PFTopLinePunct>(), // pap.fTopLinePunct;0 or 1
510 InfoRow<NS_sprm::PFAutoSpaceDE>(), // pap.fAutoSpaceDE;0 or 1
511 InfoRow<NS_sprm::PFAutoSpaceDN>(), // pap.fAutoSpaceDN;0 or 1
512 InfoRow<NS_sprm::PWAlignFont>(), // pap.wAlignFont;iFa
513 InfoRow<NS_sprm::PFrameTextFlow>(), // pap.fVertical pap.fBackward
514 // pap.fRotateFont;complex
515 {NS_sprm::LN_PISnapBaseLine, { 1, L_FIX} }, // "sprmPISnapBaseLine" obsolete: not applicable in
516 // Word97 and later versions;
517 {NS_sprm::LN_PAnld, { 0, L_VAR} }, // "sprmPAnld" pap.anld;;variable length;
518 {NS_sprm::LN_PPropRMark, { 0, L_VAR} }, // "sprmPPropRMark" pap.fPropRMark;complex
519 InfoRow<NS_sprm::POutLvl>(), // pap.lvl;has no effect if pap.istd
520 // is < 1 or is > 9
521 InfoRow<NS_sprm::PFBiDi>(), // ;;byte;
522 InfoRow<NS_sprm::PFNumRMIns>(), // pap.fNumRMIns;1 or 0;bit;
523 {NS_sprm::LN_PCrLf, { 1, L_FIX} }, // "sprmPCrLf" ;;byte;
524 InfoRow<NS_sprm::PNumRM>(), // pap.numrm;;variable length;
525 {NS_sprm::LN_PHugePapx, { 4, L_FIX} }, // "sprmPHugePapx" fc in the data stream to locate
526 // the huge grpprl
527 InfoRow<NS_sprm::PHugePapx>(), // fc in the data stream to locate
528 // the huge grpprl
529 InfoRow<NS_sprm::PFUsePgsuSettings>(), // pap.fUsePgsuSettings;
530 // 1 or 0
531 InfoRow<NS_sprm::PFAdjustRight>(), // pap.fAdjustRight;1 or 0;byte;
532 InfoRow<NS_sprm::CFRMarkDel>(), // chp.fRMarkDel;1 or 0;bit;
533 InfoRow<NS_sprm::CFRMarkIns>(), // chp.fRMark;1 or 0;bit;
534 InfoRow<NS_sprm::CFFldVanish>(), // chp.fFieldVanish;1 or 0;bit;
535 InfoRow<NS_sprm::CPicLocation>(), // chp.fcPic and chp.fSpec;
536 InfoRow<NS_sprm::CIbstRMark>(), // chp.ibstRMark;index into
537 // sttbRMark
538 InfoRow<NS_sprm::CDttmRMark>(), // chp.dttmRMark;DTTM;long;
539 InfoRow<NS_sprm::CFData>(), // chp.fData;1 or 0;bit;
540 InfoRow<NS_sprm::CIdslRMark>(), // chp.idslRMReason;an index to a
541 // table of strings defined in Word 6.0
542 // executables;short;
543 {NS_sprm::LN_CChs, { 1, L_FIX} }, // "sprmCChs" chp.fChsDiff and chp.chse;
544 InfoRow<NS_sprm::CSymbol>(), // chp.fSpec, chp.xchSym and
545 // chp.ftcSym
546 InfoRow<NS_sprm::CFOle2>(), // chp.fOle2;1 or 0;bit;
547 {NS_sprm::LN_CIdCharType, { 0, L_FIX} }, // "sprmCIdCharType" obsolete: not applicable in
548 // Word97 and later versions;
549 InfoRow<NS_sprm::CHighlight>(), // chp.fHighlight,
550 // chp.icoHighlight;ico (fHighlight is set to 1 iff
551 // ico is not 0)
552 {NS_sprm::LN_CObjLocation, { 4, L_FIX} }, // "sprmCObjLocation" chp.fcObj;FC;long;
553 {NS_sprm::LN_CFFtcAsciSymb, { 0, L_FIX} }, // "sprmCFFtcAsciSymb" ;;;
554 InfoRow<NS_sprm::CIstd>(), // chp.istd;istd, see stylesheet def
555 InfoRow<NS_sprm::CIstdPermute>(), // chp.istd;permutation vector
556 {NS_sprm::LN_CDefault, { 0, L_VAR} }, // "sprmCDefault" whole CHP;none;variable length;
557 InfoRow<NS_sprm::CPlain>(), // whole CHP;none;0;
558 InfoRow<NS_sprm::CKcd>(), // ;;;
559 InfoRow<NS_sprm::CFBold>(), // chp.fBold;0,1, 128, or 129
560 InfoRow<NS_sprm::CFItalic>(), // chp.fItalic;0,1, 128, or 129
561 InfoRow<NS_sprm::CFStrike>(), // chp.fStrike;0,1, 128, or 129
562 InfoRow<NS_sprm::CFOutline>(), // chp.fOutline;0,1, 128, or 129
563 InfoRow<NS_sprm::CFShadow>(), // chp.fShadow;0,1, 128, or 129
564 InfoRow<NS_sprm::CFSmallCaps>(), // chp.fSmallCaps;0,1, 128, or 129
565 InfoRow<NS_sprm::CFCaps>(), // chp.fCaps;0,1, 128, or 129
566 InfoRow<NS_sprm::CFVanish>(), // chp.fVanish;0,1, 128, or 129
567 {NS_sprm::LN_CFtcDefault, { 2, L_FIX} }, // "sprmCFtcDefault" ;ftc, only used internally
568 InfoRow<NS_sprm::CKul>(), // chp.kul;kul;byte;
569 {NS_sprm::LN_CSizePos, { 3, L_FIX} }, // "sprmCSizePos" chp.hps, chp.hpsPos;3 bytes;
570 InfoRow<NS_sprm::CDxaSpace>(), // chp.dxaSpace;dxa;word;
571 {NS_sprm::LN_CLid, { 2, L_FIX} }, // "sprmCLid" ;only used internally never stored
572 InfoRow<NS_sprm::CIco>(), // chp.ico;ico;byte;
573 InfoRow<NS_sprm::CHps>(), // chp.hps;hps
574 {NS_sprm::LN_CHpsInc, { 1, L_FIX} }, // "sprmCHpsInc" chp.hps;
575 InfoRow<NS_sprm::CHpsPos>(), // chp.hpsPos;hps;short; (doc wrong)
576 {NS_sprm::LN_CHpsPosAdj, { 1, L_FIX} }, // "sprmCHpsPosAdj" chp.hpsPos;hps
577 InfoRow<NS_sprm::CMajority>(), // chp.fBold, chp.fItalic,
578 // chp.fSmallCaps, chp.fVanish, chp.fStrike,
579 // chp.fCaps, chp.rgftc, chp.hps, chp.hpsPos,
580 // chp.kul, chp.dxaSpace, chp.ico,
581 // chp.rglid;complex;variable length, length byte
582 // plus size of following grpprl;
583 InfoRow<NS_sprm::CIss>(), // chp.iss;iss;byte;
584 {NS_sprm::LN_CHpsNew50, { 0, L_VAR} }, // "sprmCHpsNew50" chp.hps;hps;variable width
585 {NS_sprm::LN_CHpsInc1, { 0, L_VAR} }, // "sprmCHpsInc1" chp.hps;complex
586 InfoRow<NS_sprm::CHpsKern>(), // chp.hpsKern;hps;short;
587 {NS_sprm::LN_CMajority50, { 2, L_FIX} }, // "sprmCMajority50" chp.fBold, chp.fItalic,
588 // chp.fSmallCaps, chp.fVanish, chp.fStrike,
589 // chp.fCaps, chp.ftc, chp.hps, chp.hpsPos, chp.kul,
590 // chp.dxaSpace, chp.ico,;complex
591 {NS_sprm::LN_CHpsMul, { 2, L_FIX} }, // "sprmCHpsMul" chp.hps;percentage to grow hps
592 InfoRow<NS_sprm::CHresi>(), // chp.ysri;ysri;short;
593 InfoRow<NS_sprm::CRgFtc0>(), // chp.rgftc[0];ftc for ASCII text
594 InfoRow<NS_sprm::CRgFtc1>(), // chp.rgftc[1];ftc for Far East text
595 InfoRow<NS_sprm::CRgFtc2>(), // chp.rgftc[2];ftc for non-FE text
596 InfoRow<NS_sprm::CCharScale>(),
597 InfoRow<NS_sprm::CFDStrike>(), // chp.fDStrike;;byte;
598 InfoRow<NS_sprm::CFImprint>(), // chp.fImprint;1 or 0;bit;
599 InfoRow<NS_sprm::CFSpec>(), // chp.fSpec ;1 or 0;bit;
600 InfoRow<NS_sprm::CFObj>(), // chp.fObj;1 or 0;bit;
601 InfoRow<NS_sprm::CPropRMark90>(), // chp.fPropRMark,
602 // chp.ibstPropRMark, chp.dttmPropRMark;Complex
603 InfoRow<NS_sprm::CFEmboss>(), // chp.fEmboss;1 or 0;bit;
604 InfoRow<NS_sprm::CSfxText>(), // chp.sfxtText;text animation;byte;
605 InfoRow<NS_sprm::CFBiDi>(), // ;;;
606 {NS_sprm::LN_CFDiacColor, { 1, L_FIX} }, // "sprmCFDiacColor" ;;;
607 InfoRow<NS_sprm::CFBoldBi>(), // ;;;
608 InfoRow<NS_sprm::CFItalicBi>(), // ;;;
609 InfoRow<NS_sprm::CFtcBi>(),
610 InfoRow<NS_sprm::CLidBi>(), // ;;;
611 InfoRow<NS_sprm::CIcoBi>(), // ;;;
612 InfoRow<NS_sprm::CHpsBi>(), // ;;;
613 InfoRow<NS_sprm::CDispFldRMark>(), // chp.fDispFieldRMark,
614 // chp.ibstDispFieldRMark, chp.dttmDispFieldRMark ;
615 InfoRow<NS_sprm::CIbstRMarkDel>(), // chp.ibstRMarkDel;index into
616 // sttbRMark;short;
617 InfoRow<NS_sprm::CDttmRMarkDel>(), // chp.dttmRMarkDel;DTTM;long;
618 InfoRow<NS_sprm::CBrc80>(), // chp.brc;BRC;long;
619 InfoRow<NS_sprm::CShd80>(), // chp.shd;SHD;short;
620 InfoRow<NS_sprm::CIdslRMarkDel>(), // chp.idslRMReasonDel;an index
621 // to a table of strings defined in Word 6.0
622 // executables;short;
623 InfoRow<NS_sprm::CFUsePgsuSettings>(),
624 // chp.fUsePgsuSettings;1 or 0
625 {NS_sprm::LN_CCpg, { 2, L_FIX} }, // "sprmCCpg" ;;word;
626 InfoRow<NS_sprm::CRgLid0_80>(), // chp.rglid[0];LID: for non-FE text
627 InfoRow<NS_sprm::CRgLid1_80>(), // chp.rglid[1];LID: for Far East text
628 InfoRow<NS_sprm::CIdctHint>(), // chp.idctHint;IDCT:
629 {NS_sprm::LN_PicBrcl, { 1, L_FIX} }, // "sprmPicBrcl" pic.brcl;brcl (see PIC definition)
630 {NS_sprm::LN_PicScale, { 0, L_VAR} }, // "sprmPicScale" pic.mx, pic.my, pic.dxaCropleft,
631 // pic.dyaCropTop pic.dxaCropRight,
632 // pic.dyaCropBottom;Complex
633 InfoRow<NS_sprm::PicBrcTop80>(), // pic.brcTop;BRC;long;
634 InfoRow<NS_sprm::PicBrcLeft80>(), // pic.brcLeft;BRC;long;
635 InfoRow<NS_sprm::PicBrcBottom80>(), // pic.brcBottom;BRC;long;
636 InfoRow<NS_sprm::PicBrcRight80>(), // pic.brcRight;BRC;long;
637 InfoRow<NS_sprm::ScnsPgn>(), // sep.cnsPgn;cns;byte;
638 InfoRow<NS_sprm::SiHeadingPgn>(), // sep.iHeadingPgn;heading number
639 // level;byte;
640 {NS_sprm::LN_SOlstAnm, { 0, L_VAR} }, // "sprmSOlstAnm" sep.olstAnm;OLST;variable length;
641 InfoRow<NS_sprm::SDxaColWidth>(), // sep.rgdxaColWidthSpacing;
642 InfoRow<NS_sprm::SDxaColSpacing>(), // sep.rgdxaColWidthSpacing;
643 // complex
644 InfoRow<NS_sprm::SFEvenlySpaced>(), // sep.fEvenlySpaced;1 or 0
645 InfoRow<NS_sprm::SFProtected>(), // sep.fUnlocked;1 or 0;byte;
646 InfoRow<NS_sprm::SDmBinFirst>(), // sep.dmBinFirst;;word;
647 InfoRow<NS_sprm::SDmBinOther>(), // sep.dmBinOther;;word;
648 InfoRow<NS_sprm::SBkc>(), // sep.bkc;bkc;byte;
649 InfoRow<NS_sprm::SFTitlePage>(), // sep.fTitlePage;0 or 1;byte;
650 InfoRow<NS_sprm::SCcolumns>(), // sep.ccolM1;# of cols - 1;word;
651 InfoRow<NS_sprm::SDxaColumns>(), // sep.dxaColumns;dxa;word;
652 {NS_sprm::LN_SFAutoPgn, { 1, L_FIX} }, // "sprmSFAutoPgn" sep.fAutoPgn;obsolete;byte;
653 InfoRow<NS_sprm::SNfcPgn>(), // sep.nfcPgn;nfc;byte;
654 {NS_sprm::LN_SDyaPgn, { 2, L_FIX} }, // "sprmSDyaPgn" sep.dyaPgn;dya;short;
655 {NS_sprm::LN_SDxaPgn, { 2, L_FIX} }, // "sprmSDxaPgn" sep.dxaPgn;dya;short;
656 InfoRow<NS_sprm::SFPgnRestart>(), // sep.fPgnRestart;0 or 1;byte;
657 InfoRow<NS_sprm::SFEndnote>(), // sep.fEndnote;0 or 1;byte;
658 InfoRow<NS_sprm::SLnc>(), // sep.lnc;lnc;byte;
659 {NS_sprm::LN_SGprfIhdt, { 1, L_FIX} }, // "sprmSGprfIhdt" sep.grpfIhdt;grpfihdt
660 InfoRow<NS_sprm::SNLnnMod>(), // sep.nLnnMod;non-neg int.;word;
661 InfoRow<NS_sprm::SDxaLnn>(), // sep.dxaLnn;dxa;word;
662 InfoRow<NS_sprm::SDyaHdrTop>(), // sep.dyaHdrTop;dya;word;
663 InfoRow<NS_sprm::SDyaHdrBottom>(), // sep.dyaHdrBottom;dya;word;
664 InfoRow<NS_sprm::SLBetween>(), // sep.fLBetween;0 or 1;byte;
665 InfoRow<NS_sprm::SVjc>(), // sep.vjc;vjc;byte;
666 InfoRow<NS_sprm::SLnnMin>(), // sep.lnnMin;lnn;word;
667 InfoRow<NS_sprm::SPgnStart97>(), // sep.pgnStart;pgn;word;
668 InfoRow<NS_sprm::SBOrientation>(), // sep.dmOrientPage;dm;byte;
669 {NS_sprm::LN_SBCustomize, { 1, L_FIX} }, // "sprmSBCustomize" ;;;
670 InfoRow<NS_sprm::SXaPage>(), // sep.xaPage;xa;word;
671 InfoRow<NS_sprm::SYaPage>(), // sep.yaPage;ya;word;
672 InfoRow<NS_sprm::SDxaLeft>(), // sep.dxaLeft;dxa;word;
673 InfoRow<NS_sprm::SDxaRight>(), // sep.dxaRight;dxa;word;
674 InfoRow<NS_sprm::SDyaTop>(), // sep.dyaTop;dya;word;
675 InfoRow<NS_sprm::SDyaBottom>(), // sep.dyaBottom;dya;word;
676 InfoRow<NS_sprm::SDzaGutter>(), // sep.dzaGutter;dza;word;
677 InfoRow<NS_sprm::SDmPaperReq>(), // sep.dmPaperReq;dm;word;
678 {NS_sprm::LN_SPropRMark, { 0, L_VAR} }, // "sprmSPropRMark" sep.fPropRMark,
679 // sep.ibstPropRMark, sep.dttmPropRMark ;complex
680 InfoRow<NS_sprm::SFBiDi>(), // ;;;
681 {NS_sprm::LN_SFFacingCol, { 1, L_FIX} }, // "sprmSFFacingCol" ;;;
682 InfoRow<NS_sprm::SFRTLGutter>(), //, set to one if gutter is on
683 // right
684 InfoRow<NS_sprm::SBrcTop80>(), // sep.brcTop;BRC;long;
685 InfoRow<NS_sprm::SBrcLeft80>(), // sep.brcLeft;BRC;long;
686 InfoRow<NS_sprm::SBrcBottom80>(), // sep.brcBottom;BRC;long;
687 InfoRow<NS_sprm::SBrcRight80>(), // sep.brcRight;BRC;long;
688 InfoRow<NS_sprm::SPgbProp>(), // sep.pgbProp;;word;
689 InfoRow<NS_sprm::SDxtCharSpace>(), // sep.dxtCharSpace;dxt;long;
690 InfoRow<NS_sprm::SDyaLinePitch>(),
691 // sep.dyaLinePitch;dya; WRONG:long; RIGHT:short; !
692 InfoRow<NS_sprm::SClm>(), // ;;;
693 InfoRow<NS_sprm::STextFlow>(), // sep.wTextFlow;complex
694 InfoRow<NS_sprm::TJc90>(), // tap.jc;jc;word (low order byte is
695 // significant);
696 InfoRow<NS_sprm::TDxaLeft>(), // tap.rgdxaCenter
697 InfoRow<NS_sprm::TDxaGapHalf>(), // tap.dxaGapHalf,
698 // tap.rgdxaCenter
699 InfoRow<NS_sprm::TFCantSplit90>(), // tap.fCantSplit90;1 or 0;byte;
700 InfoRow<NS_sprm::TTableHeader>(), // tap.fTableHeader;1 or 0;byte;
701 InfoRow<NS_sprm::TFCantSplit>(), // tap.fCantSplit;1 or 0;byte;
702 InfoRow<NS_sprm::TTableBorders80>(), // tap.rgbrcTable;complex
703 {NS_sprm::LN_TDefTable10, { 0, L_VAR} }, // "sprmTDefTable10" tap.rgdxaCenter,
704 // tap.rgtc;complex
705 InfoRow<NS_sprm::TDyaRowHeight>(), // tap.dyaRowHeight;dya;word;
706 InfoRow<NS_sprm::TDefTable>(), // tap.rgtc;complex
707 InfoRow<NS_sprm::TDefTableShd80>(), // tap.rgshd;complex
708 InfoRow<NS_sprm::TTlp>(), // tap.tlp;TLP;4 bytes;
709 InfoRow<NS_sprm::TFBiDi>(), // ;;;
710 {NS_sprm::LN_THTMLProps, { 1, L_FIX} }, // "sprmTHTMLProps" ;;;
711 InfoRow<NS_sprm::TSetBrc80>(), // tap.rgtc[].rgbrc;complex
712 InfoRow<NS_sprm::TInsert>(), // tap.rgdxaCenter, tap.rgtc;complex
713 InfoRow<NS_sprm::TDelete>(), // tap.rgdxaCenter, tap.rgtc;complex
714 InfoRow<NS_sprm::TDxaCol>(), // tap.rgdxaCenter;complex
715 InfoRow<NS_sprm::TMerge>(), // tap.fFirstMerged, tap.fMerged;
716 InfoRow<NS_sprm::TSplit>(), // tap.fFirstMerged, tap.fMerged;
717 {NS_sprm::LN_TSetBrc10, { 0, L_VAR} }, // "sprmTSetBrc10" tap.rgtc[].rgbrc;complex
718 {NS_sprm::LN_TSetShd80, { 0, L_VAR} }, // "sprmTSetShd80" tap.rgshd;complex
719 {NS_sprm::LN_TSetShdOdd80, { 0, L_VAR} }, // "sprmTSetShdOdd80" tap.rgshd;complex
720 InfoRow<NS_sprm::TTextFlow>(), // tap.rgtc[].fVerticaltap,
721 // rgtc[].fBackwardtap, rgtc[].fRotateFont;0 or 10
722 // or 10 or 1;word;
723 {NS_sprm::LN_TDiagLine, { 1, L_FIX} }, // "sprmTDiagLine" ;;;
724 InfoRow<NS_sprm::TVertMerge>(), // tap.rgtc[].vertMerge
725 InfoRow<NS_sprm::TVertAlign>(), // tap.rgtc[].vertAlign
726 InfoRow<NS_sprm::CFELayout>(),
727 InfoRow<NS_sprm::PItap>(), // undocumented
728 InfoRow<NS_sprm::TTableWidth>(), // undocumented
729 InfoRow<NS_sprm::TDefTableShd>(),
730 InfoRow<NS_sprm::TTableBorders>(),
731 InfoRow<NS_sprm::TBrcTopCv>(), // undocumented
732 InfoRow<NS_sprm::TBrcLeftCv>(), // undocumented
733 InfoRow<NS_sprm::TBrcBottomCv>(), // undocumented
734 InfoRow<NS_sprm::TBrcRightCv>(), // undocumented
735 InfoRow<NS_sprm::TCellPadding>(), // undocumented
736 InfoRow<NS_sprm::TCellPaddingDefault>(), // undocumented
737 {0xD238, { 0, L_VAR} }, // undocumented sep
738 InfoRow<NS_sprm::PBrcTop>(),
739 InfoRow<NS_sprm::PBrcLeft>(),
740 InfoRow<NS_sprm::PBrcBottom>(),
741 InfoRow<NS_sprm::PBrcRight>(),
742 InfoRow<NS_sprm::PBrcBetween>(),
743 InfoRow<NS_sprm::TWidthIndent>(), // undocumented
744 InfoRow<NS_sprm::CRgLid0>(), // chp.rglid[0];LID: for non-FE text
745 InfoRow<NS_sprm::CRgLid1>(), // chp.rglid[1];LID: for Far East text
746 {0x6463, { 4, L_FIX} }, // undocumented
747 InfoRow<NS_sprm::PJc>(), // undoc, must be asian version of "sprmPJc"
748 InfoRow<NS_sprm::PDxaRight>(), // undoc, must be asian version of "sprmPDxaRight"
749 InfoRow<NS_sprm::PDxaLeft>(), // undoc, must be asian version of "sprmPDxaLeft"
750 InfoRow<NS_sprm::PDxaLeft1>(), // undoc, must be asian version of "sprmPDxaLeft1"
751 InfoRow<NS_sprm::TFAutofit>(), // undocumented
752 InfoRow<NS_sprm::TPc>(), // undocumented
753 InfoRow<NS_sprm::SRsid>(), // undocumented, sep, perhaps related to textgrids ?
754 InfoRow<NS_sprm::SFpc>(), // undocumented, sep
755 InfoRow<NS_sprm::PFInnerTableCell>(), // undocumented, subtable "sprmPFInTable" equiv ?
756 InfoRow<NS_sprm::PFInnerTtp>(), // undocumented, subtable "sprmPFTtp" equiv ?
757 InfoRow<NS_sprm::TDxaAbs>(), // undocumented
758 InfoRow<NS_sprm::TDyaAbs>(), // undocumented
759 InfoRow<NS_sprm::TDxaFromText>(), // undocumented
760 InfoRow<NS_sprm::CRsidProp>(), // undocumented
761 InfoRow<NS_sprm::CRsidText>(), // undocumented
762 InfoRow<NS_sprm::CCv>(), // text colour
763 InfoRow<NS_sprm::PShd>(), // undocumented, para back colour
764 InfoRow<NS_sprm::PRsid>(), // undocumented
765 InfoRow<NS_sprm::PTableProps>(), // undocumented
766 InfoRow<NS_sprm::TWidthBefore>(), // undocumented
767 InfoRow<NS_sprm::TSetShdTable>(), // undocumented, something to do with colour.
768 InfoRow<NS_sprm::TDefTableShdRaw>(), // undocumented, something to do with colour.
769 InfoRow<NS_sprm::CShd>(), // text backcolour
770 InfoRow<NS_sprm::SRncFtn>(), // undocumented, sep
771 InfoRow<NS_sprm::PFDyaBeforeAuto>(), // undocumented, para autobefore
772 InfoRow<NS_sprm::PFDyaAfterAuto>(), // undocumented, para autoafter
773 // "sprmPFContextualSpacing", don't add space between para of the same style
774 InfoRow<NS_sprm::PFContextualSpacing>(),
777 static wwSprmSearcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
778 return &aSprmSrch;
781 wwSprmParser::wwSprmParser(const WW8Fib& rFib) : meVersion(rFib.GetFIBVersion())
783 OSL_ENSURE((meVersion >= ww::eWW1 && meVersion <= ww::eWW8),
784 "Impossible value for version");
786 mnDelta = (ww::IsSevenMinus(meVersion)) ? 0 : 1;
788 if (meVersion <= ww::eWW2)
789 mpKnownSprms = GetWW2SprmSearcher();
790 else if (meVersion < ww::eWW8)
791 mpKnownSprms = GetWW6SprmSearcher(rFib);
792 else
793 mpKnownSprms = GetWW8SprmSearcher();
796 SprmInfo wwSprmParser::GetSprmInfo(sal_uInt16 nId) const
798 const SprmInfo* pFound = mpKnownSprms->search(nId);
799 if (pFound != nullptr)
801 return *pFound;
804 OSL_ENSURE(ww::IsEightPlus(meVersion),
805 "Unknown ww7- sprm, dangerous, report to development");
807 //All the unknown ww7 sprms appear to be variable (which makes sense)
808 SprmInfo aSrch = { 0, L_VAR };
809 if (ww::IsEightPlus(meVersion)) //We can recover perfectly in this case
811 aSrch.nVari = L_FIX;
812 switch (nId >> 13)
814 case 0:
815 case 1:
816 aSrch.nLen = 1;
817 break;
818 case 2:
819 aSrch.nLen = 2;
820 break;
821 case 3:
822 aSrch.nLen = 4;
823 break;
824 case 4:
825 case 5:
826 aSrch.nLen = 2;
827 break;
828 case 6:
829 aSrch.nLen = 0;
830 aSrch.nVari = L_VAR;
831 break;
832 case 7:
833 default:
834 aSrch.nLen = 3;
835 break;
838 return aSrch;
841 //-end
843 static sal_uInt8 Get_Byte( sal_uInt8 *& p )
845 sal_uInt8 n = *p;
846 p += 1;
847 return n;
850 static sal_uInt16 Get_UShort( sal_uInt8 *& p )
852 const sal_uInt16 n = SVBT16ToUInt16( *reinterpret_cast<SVBT16*>(p) );
853 p += 2;
854 return n;
857 static sal_Int16 Get_Short( sal_uInt8 *& p )
859 return Get_UShort(p);
862 static sal_uInt32 Get_ULong( sal_uInt8 *& p )
864 sal_uInt32 n = SVBT32ToUInt32( *reinterpret_cast<SVBT32*>(p) );
865 p += 4;
866 return n;
869 static sal_Int32 Get_Long( sal_uInt8 *& p )
871 return Get_ULong(p);
874 WW8SprmIter::WW8SprmIter(const sal_uInt8* pSprms_, sal_Int32 nLen_,
875 const wwSprmParser &rParser)
876 : mrSprmParser(rParser), pSprms( pSprms_), nRemLen( nLen_)
878 UpdateMyMembers();
881 void WW8SprmIter::SetSprms(const sal_uInt8* pSprms_, sal_Int32 nLen_)
883 pSprms = pSprms_;
884 nRemLen = nLen_;
885 UpdateMyMembers();
888 void WW8SprmIter::advance()
890 if (nRemLen > 0 )
892 sal_uInt16 nSize = nCurrentSize;
893 if (nSize > nRemLen)
894 nSize = nRemLen;
895 pSprms += nSize;
896 nRemLen -= nSize;
897 UpdateMyMembers();
901 void WW8SprmIter::UpdateMyMembers()
903 bool bValid = (pSprms && nRemLen >= mrSprmParser.MinSprmLen());
905 if (bValid)
907 nCurrentId = mrSprmParser.GetSprmId(pSprms);
908 nCurrentSize = mrSprmParser.GetSprmSize(nCurrentId, pSprms, nRemLen);
909 pCurrentParams = pSprms + mrSprmParser.DistanceToData(nCurrentId);
910 bValid = nCurrentSize <= nRemLen;
911 SAL_WARN_IF(!bValid, "sw.ww8", "sprm longer than remaining bytes, doc or parser is wrong");
914 if (!bValid)
916 nCurrentId = 0;
917 pCurrentParams = nullptr;
918 nCurrentSize = 0;
919 nRemLen = 0;
923 SprmResult WW8SprmIter::FindSprm(sal_uInt16 nId, bool bFindFirst, const sal_uInt8* pNextByteMatch)
925 SprmResult aRet;
927 while (GetSprms())
929 if (GetCurrentId() == nId)
931 sal_Int32 nFixedLen = mrSprmParser.DistanceToData(nId);
932 sal_Int32 nL = mrSprmParser.GetSprmSize(nId, GetSprms(), GetRemLen());
933 SprmResult aSprmResult(GetCurrentParams(), nL - nFixedLen);
934 // typically pNextByteMatch is nullptr and we just return the first match
935 // very occasionally we want one with a specific following byte
936 if ( !pNextByteMatch || (aSprmResult.nRemainingData >= 1 && *aSprmResult.pSprm == *pNextByteMatch) )
938 if ( bFindFirst )
939 return aSprmResult;
940 aRet = aSprmResult;
943 advance();
946 return aRet;
949 // temporary test
950 // WW8PLCFx_PCDAttrs cling to WW8PLCF_Pcd and therefore do not have their own iterators.
951 // All methods relating to iterators are therefore dummies.
952 WW8PLCFx_PCDAttrs::WW8PLCFx_PCDAttrs(const WW8Fib& rFib,
953 WW8PLCFx_PCD* pPLCFx_PCD, const WW8ScannerBase* pBase)
954 : WW8PLCFx(rFib, true), pPcdI(pPLCFx_PCD->GetPLCFIter()),
955 pPcd(pPLCFx_PCD), mrGrpprls(pBase->m_aPieceGrpprls)
959 sal_uInt32 WW8PLCFx_PCDAttrs::GetIdx() const
961 return 0;
964 void WW8PLCFx_PCDAttrs::SetIdx(sal_uInt32)
968 bool WW8PLCFx_PCDAttrs::SeekPos(WW8_CP )
970 return true;
973 void WW8PLCFx_PCDAttrs::advance()
977 WW8_CP WW8PLCFx_PCDAttrs::Where()
979 return pPcd ? pPcd->Where() : WW8_CP_MAX;
982 void WW8PLCFx_PCDAttrs::GetSprms(WW8PLCFxDesc* p)
984 void* pData;
986 p->bRealLineEnd = false;
987 if ( !pPcdI || !pPcdI->Get(p->nStartPos, p->nEndPos, pData) )
989 // PLCF fully processed
990 p->nStartPos = p->nEndPos = WW8_CP_MAX;
991 p->pMemPos = nullptr;
992 p->nSprmsLen = 0;
993 return;
996 const sal_uInt16 nPrm = SVBT16ToUInt16( static_cast<WW8_PCD*>(pData)->prm );
997 if ( nPrm & 1 )
999 // PRM Variant 2
1000 const sal_uInt16 nSprmIdx = nPrm >> 1;
1002 if( nSprmIdx >= mrGrpprls.size() )
1004 // Invalid Index
1005 p->nStartPos = p->nEndPos = WW8_CP_MAX;
1006 p->pMemPos = nullptr;
1007 p->nSprmsLen = 0;
1008 return;
1010 const sal_uInt8* pSprms = mrGrpprls[ nSprmIdx ].get();
1012 p->nSprmsLen = SVBT16ToUInt16( pSprms ); // Length
1013 pSprms += 2;
1014 p->pMemPos = pSprms; // Position
1016 else
1018 // SPRM is stored directly into members var
1020 These are the attr that are in the piece-table instead of in the text!
1023 if (IsSevenMinus(GetFIBVersion()))
1025 aShortSprm[0] = static_cast<sal_uInt8>( ( nPrm & 0xfe) >> 1 );
1026 aShortSprm[1] = static_cast<sal_uInt8>( nPrm >> 8 );
1027 p->nSprmsLen = nPrm ? 2 : 0; // length
1029 // store Position of internal mini storage in Data Pointer
1030 p->pMemPos = aShortSprm;
1032 else
1034 p->pMemPos = nullptr;
1035 p->nSprmsLen = 0;
1036 sal_uInt8 nSprmListIdx = static_cast<sal_uInt8>((nPrm & 0xfe) >> 1);
1037 if( nSprmListIdx )
1039 // process Sprm Id Matching as explained in MS Documentation
1041 // ''Property Modifier(variant 1) (PRM)''
1042 // see file: s62f39.htm
1044 // Since Sprm is 7 bits, rgsprmPrm can hold 0x80 entries.
1045 static const sal_uInt16 aSprmId[0x80] =
1047 // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1048 0x0000,0x0000,0x0000,0x0000,
1049 // sprmPIncLvl, sprmPJc, sprmPFSideBySide, sprmPFKeep
1050 0x2402,0x2403,NS_sprm::LN_PFSideBySide,0x2405,
1051 // sprmPFKeepFollow, sprmPFPageBreakBefore, sprmPBrcl,
1052 // sprmPBrcp
1053 0x2406,0x2407,NS_sprm::LN_PBrcl,NS_sprm::LN_PBrcp,
1054 // sprmPIlvl, sprmNoop, sprmPFNoLineNumb, sprmNoop
1055 0x260A,0x0000,0x240C,0x0000,
1056 // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1057 0x0000,0x0000,0x0000,0x0000,
1058 // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1059 0x0000,0x0000,0x0000,0x0000,
1060 // sprmPFInTable, sprmPFTtp, sprmNoop, sprmNoop
1061 0x2416,0x2417,0x0000,0x0000,
1062 // sprmNoop, sprmPPc, sprmNoop, sprmNoop
1063 0x0000,0x261B,0x0000,0x0000,
1064 // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1065 0x0000,0x0000,0x0000,0x0000,
1066 // sprmNoop, sprmPWr, sprmNoop, sprmNoop
1067 0x0000,0x2423,0x0000,0x0000,
1068 // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1069 0x0000,0x0000,0x0000,0x0000,
1070 // sprmPFNoAutoHyph, sprmNoop, sprmNoop, sprmNoop
1071 0x242A,0x0000,0x0000,0x0000,
1072 // sprmNoop, sprmNoop, sprmPFLocked, sprmPFWidowControl
1073 0x0000,0x0000,0x2430,0x2431,
1074 // sprmNoop, sprmPFKinsoku, sprmPFWordWrap,
1075 // sprmPFOverflowPunct
1076 0x0000,0x2433,0x2434,0x2435,
1077 // sprmPFTopLinePunct, sprmPFAutoSpaceDE,
1078 // sprmPFAutoSpaceDN, sprmNoop
1079 0x2436,0x2437,0x2438,0x0000,
1080 // sprmNoop, sprmPISnapBaseLine, sprmNoop, sprmNoop
1081 0x0000,NS_sprm::LN_PISnapBaseLine,0x000,0x0000,
1082 // sprmNoop, sprmCFStrikeRM, sprmCFRMark, sprmCFFieldVanish
1083 0x0000,0x0800,0x0801,0x0802,
1084 // sprmNoop, sprmNoop, sprmNoop, sprmCFData
1085 0x0000,0x0000,0x0000,0x0806,
1086 // sprmNoop, sprmNoop, sprmNoop, sprmCFOle2
1087 0x0000,0x0000,0x0000,0x080A,
1088 // sprmNoop, sprmCHighlight, sprmCFEmboss, sprmCSfxText
1089 0x0000,0x2A0C,0x0858,0x2859,
1090 // sprmNoop, sprmNoop, sprmNoop, sprmCPlain
1091 0x0000,0x0000,0x0000,0x2A33,
1092 // sprmNoop, sprmCFBold, sprmCFItalic, sprmCFStrike
1093 0x0000,0x0835,0x0836,0x0837,
1094 // sprmCFOutline, sprmCFShadow, sprmCFSmallCaps, sprmCFCaps,
1095 0x0838,0x0839,0x083a,0x083b,
1096 // sprmCFVanish, sprmNoop, sprmCKul, sprmNoop,
1097 0x083C,0x0000,0x2A3E,0x0000,
1098 // sprmNoop, sprmNoop, sprmCIco, sprmNoop,
1099 0x0000,0x0000,0x2A42,0x0000,
1100 // sprmCHpsInc, sprmNoop, sprmCHpsPosAdj, sprmNoop,
1101 NS_sprm::LN_CHpsInc,0x0000,NS_sprm::LN_CHpsPosAdj,0x0000,
1102 // sprmCIss, sprmNoop, sprmNoop, sprmNoop,
1103 0x2A48,0x0000,0x0000,0x0000,
1104 // sprmNoop, sprmNoop, sprmNoop, sprmNoop,
1105 0x0000,0x0000,0x0000,0x0000,
1106 // sprmNoop, sprmNoop, sprmNoop, sprmCFDStrike,
1107 0x0000,0x0000,0x0000,0x2A53,
1108 // sprmCFImprint, sprmCFSpec, sprmCFObj, sprmPicBrcl,
1109 0x0854,0x0855,0x0856,NS_sprm::LN_PicBrcl,
1110 // sprmPOutLvl, sprmPFBiDi, sprmNoop, sprmNoop,
1111 0x2640,0x2441,0x0000,0x0000,
1112 // sprmNoop, sprmNoop, sprmPPnbrRMarkNot
1113 0x0000,0x0000,0x0000,0x0000
1116 // find real Sprm Id:
1117 const sal_uInt16 nSprmId = aSprmId[ nSprmListIdx ];
1119 if( nSprmId )
1121 // move Sprm Id and Sprm Param to internal mini storage:
1122 aShortSprm[0] = static_cast<sal_uInt8>( nSprmId & 0x00ff) ;
1123 aShortSprm[1] = static_cast<sal_uInt8>( ( nSprmId & 0xff00) >> 8 );
1124 aShortSprm[2] = static_cast<sal_uInt8>( nPrm >> 8 );
1126 // store Sprm Length in member:
1127 p->nSprmsLen = nPrm ? 3 : 0;
1129 // store Position of internal mini storage in Data Pointer
1130 p->pMemPos = aShortSprm;
1137 WW8PLCFx_PCD::WW8PLCFx_PCD(const WW8Fib& rFib, WW8PLCFpcd* pPLCFpcd,
1138 WW8_CP nStartCp, bool bVer67P)
1139 : WW8PLCFx(rFib, false), nClipStart(-1)
1141 // construct own iterator
1142 pPcdI.reset( new WW8PLCFpcd_Iter(*pPLCFpcd, nStartCp) );
1143 bVer67= bVer67P;
1146 WW8PLCFx_PCD::~WW8PLCFx_PCD()
1150 sal_uInt32 WW8PLCFx_PCD::GetIMax() const
1152 return pPcdI ? pPcdI->GetIMax() : 0;
1155 sal_uInt32 WW8PLCFx_PCD::GetIdx() const
1157 return pPcdI ? pPcdI->GetIdx() : 0;
1160 void WW8PLCFx_PCD::SetIdx(sal_uInt32 nIdx)
1162 if (pPcdI)
1163 pPcdI->SetIdx( nIdx );
1166 bool WW8PLCFx_PCD::SeekPos(WW8_CP nCpPos)
1168 return pPcdI && pPcdI->SeekPos( nCpPos );
1171 WW8_CP WW8PLCFx_PCD::Where()
1173 return pPcdI ? pPcdI->Where() : WW8_CP_MAX;
1176 tools::Long WW8PLCFx_PCD::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
1178 void* pData;
1179 rLen = 0;
1181 if ( !pPcdI || !pPcdI->Get(rStart, rEnd, pData) )
1183 rStart = rEnd = WW8_CP_MAX;
1184 return -1;
1186 return pPcdI->GetIdx();
1189 void WW8PLCFx_PCD::advance()
1191 OSL_ENSURE(pPcdI , "missing pPcdI");
1192 if (pPcdI)
1193 pPcdI->advance();
1196 WW8_FC WW8PLCFx_PCD::CurrentPieceStartCp2Fc( WW8_CP nCp )
1198 WW8_CP nCpStart, nCpEnd;
1199 void* pData;
1201 if ( !pPcdI->Get(nCpStart, nCpEnd, pData) )
1203 OSL_ENSURE( false, "CurrentPieceStartCp2Fc() with false Cp found (1)" );
1204 return WW8_FC_MAX;
1207 OSL_ENSURE( nCp >= nCpStart && nCp < nCpEnd,
1208 "AktPieceCp2Fc() with false Cp found (2)" );
1210 if( nCp < nCpStart )
1211 nCp = nCpStart;
1212 if( nCp >= nCpEnd )
1213 nCp = nCpEnd - 1;
1215 bool bIsUnicode = false;
1216 WW8_FC nFC = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
1217 if( !bVer67 )
1218 nFC = WW8PLCFx_PCD::TransformPieceAddress( nFC, bIsUnicode );
1220 WW8_CP nDistance;
1221 bool bFail = o3tl::checked_sub(nCp, nCpStart, nDistance);
1222 if (bFail)
1224 SAL_WARN("sw.ww8", "broken offset, ignoring");
1225 return WW8_FC_MAX;
1228 if (bIsUnicode)
1230 bFail = o3tl::checked_multiply<WW8_CP>(nDistance, 2, nDistance);
1231 if (bFail)
1233 SAL_WARN("sw.ww8", "broken offset, ignoring");
1234 return WW8_FC_MAX;
1238 WW8_FC nRet;
1239 bFail = o3tl::checked_add(nFC, nDistance, nRet);
1240 if (bFail)
1242 SAL_WARN("sw.ww8", "broken offset, ignoring");
1243 return WW8_FC_MAX;
1246 return nRet;
1249 void WW8PLCFx_PCD::CurrentPieceFc2Cp( WW8_CP& rStartPos, WW8_CP& rEndPos,
1250 const WW8ScannerBase *pSBase )
1252 //No point going anywhere with this
1253 if ((rStartPos == WW8_CP_MAX) && (rEndPos == WW8_CP_MAX))
1254 return;
1256 rStartPos = pSBase->WW8Fc2Cp( rStartPos );
1257 rEndPos = pSBase->WW8Fc2Cp( rEndPos );
1260 WW8_CP WW8PLCFx_PCD::CurrentPieceStartFc2Cp( WW8_FC nStartPos )
1262 WW8_CP nCpStart, nCpEnd;
1263 void* pData;
1264 if ( !pPcdI->Get( nCpStart, nCpEnd, pData ) )
1266 OSL_ENSURE( false, "CurrentPieceStartFc2Cp() - error" );
1267 return WW8_CP_MAX;
1269 bool bIsUnicode = false;
1270 sal_Int32 nFcStart = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
1271 if( !bVer67 )
1272 nFcStart = WW8PLCFx_PCD::TransformPieceAddress( nFcStart, bIsUnicode );
1274 sal_Int32 nUnicodeFactor = bIsUnicode ? 2 : 1;
1276 if( nStartPos < nFcStart )
1277 nStartPos = nFcStart;
1279 WW8_CP nCpLen;
1280 bool bFail = o3tl::checked_sub(nCpEnd, nCpStart, nCpLen);
1281 if (bFail)
1283 SAL_WARN("sw.ww8", "broken offset, ignoring");
1284 return WW8_CP_MAX;
1287 WW8_CP nCpLenBytes;
1288 bFail = o3tl::checked_multiply(nCpLen, nUnicodeFactor, nCpLenBytes);
1289 if (bFail)
1291 SAL_WARN("sw.ww8", "broken offset, ignoring");
1292 return WW8_CP_MAX;
1295 WW8_FC nFcLen;
1296 bFail = o3tl::checked_add(nFcStart, nCpLenBytes, nFcLen);
1297 if (bFail)
1299 SAL_WARN("sw.ww8", "broken offset, ignoring");
1300 return WW8_CP_MAX;
1303 WW8_FC nFcEnd;
1304 bFail = o3tl::checked_add(nFcStart, nFcLen, nFcEnd);
1305 if (bFail)
1307 SAL_WARN("sw.ww8", "broken offset, ignoring");
1308 return WW8_CP_MAX;
1312 if (nStartPos >= nFcEnd)
1313 nStartPos = nFcEnd - (1 * nUnicodeFactor);
1315 WW8_FC nFcDiff = (nStartPos - nFcStart) / nUnicodeFactor;
1317 WW8_FC nCpRet;
1318 bFail = o3tl::checked_add(nCpStart, nFcDiff, nCpRet);
1319 if (bFail)
1321 SAL_WARN("sw.ww8", "broken offset, ignoring");
1322 return WW8_CP_MAX;
1325 return nCpRet;
1328 // Helper routines for all
1330 // Convert BRC from WW6 to WW8 format
1331 WW8_BRC::WW8_BRC(const WW8_BRCVer6& brcVer6)
1333 sal_uInt8 _dptLineWidth = brcVer6.dxpLineWidth(),
1334 _brcType = brcVer6.brcType();
1336 if (_dptLineWidth > 5) // this signifies dashed(6) or dotted(7) line
1338 _brcType = _dptLineWidth;
1339 _dptLineWidth = 1;
1341 _dptLineWidth *= 6; // convert units from 0.75pt to 1/8pt
1343 *this = WW8_BRC(_dptLineWidth, _brcType, brcVer6.ico(), brcVer6.dxpSpace(),
1344 brcVer6.fShadow(), false);
1347 // Convert BRC from WW8 to WW9 format
1348 WW8_BRCVer9::WW8_BRCVer9(const WW8_BRC& brcVer8)
1350 if (brcVer8.isNil()) {
1351 UInt32ToSVBT32(0, aBits1);
1352 UInt32ToSVBT32(0xffffffff, aBits2);
1354 else
1356 sal_uInt32 _cv = brcVer8.ico() == 0 ? 0xff000000 // "auto" colour
1357 : wwUtility::RGBToBGR(SwWW8ImplReader::GetCol(brcVer8.ico()));
1358 *this = WW8_BRCVer9(_cv, brcVer8.dptLineWidth(), brcVer8.brcType(),
1359 brcVer8.dptSpace(), brcVer8.fShadow(), brcVer8.fFrame());
1363 short WW8_BRC::DetermineBorderProperties(short *pSpace) const
1365 WW8_BRCVer9 brcVer9(*this);
1366 return brcVer9.DetermineBorderProperties(pSpace);
1369 short WW8_BRCVer9::DetermineBorderProperties(short *pSpace) const
1372 Word does not factor the width of the border into the width/height
1373 stored in the information for graphic/table/object widths, so we need
1374 to figure out this extra width here and utilize the returned size in
1375 our calculations
1377 short nMSTotalWidth;
1379 //Specification in 8ths of a point, 1 Point = 20 Twips, so by 2.5
1380 nMSTotalWidth = static_cast<short>(dptLineWidth()) * 20 / 8;
1382 //Figure out the real size of the border according to word
1383 switch (brcType())
1385 //Note that codes over 25 are undocumented, and I can't create
1386 //these 4 here in the wild.
1387 case 2:
1388 case 4:
1389 case 5:
1390 case 22:
1391 OSL_FAIL("Can't create these from the menus, please report");
1392 break;
1393 default:
1394 case 23: //Only 3pt in the menus, but honours the size setting.
1395 break;
1396 case 10:
1398 triple line is five times the width of an ordinary line,
1399 except that the smallest 1/4 point size appears to have
1400 exactly the same total border width as a 3/4 point size
1401 ordinary line, i.e. three times the nominal line width. The
1402 second smallest 1/2 point size appears to have exactly the
1403 total border width as a 2 1/4 border, i.e 4.5 times the size.
1405 if (nMSTotalWidth == 5)
1406 nMSTotalWidth*=3;
1407 else if (nMSTotalWidth == 10)
1408 nMSTotalWidth = nMSTotalWidth*9/2;
1409 else
1410 nMSTotalWidth*=5;
1411 break;
1412 case 20:
1414 wave, the dimensions appear to be created by the drawing of
1415 the wave, so we have only two possibilities in the menus, 3/4
1416 point is equal to solid 3 point. This calculation seems to
1417 match well to results.
1419 nMSTotalWidth +=45;
1420 break;
1421 case 21:
1423 double wave, the dimensions appear to be created by the
1424 drawing of the wave, so we have only one possibilities in the
1425 menus, that of 3/4 point is equal to solid 3 point. This
1426 calculation seems to match well to results.
1428 nMSTotalWidth += 45*2;
1429 break;
1432 if (pSpace)
1433 *pSpace = static_cast<short>(dptSpace()) * 20; // convert from points to twips
1434 return nMSTotalWidth;
1438 * WW8Cp2Fc is a good method, a CP always maps to a FC
1439 * WW8Fc2Cp on the other hand is more dubious, a random FC
1440 * may not map to a valid CP. Try and avoid WW8Fc2Cp where
1441 * possible
1443 WW8_CP WW8ScannerBase::WW8Fc2Cp( WW8_FC nFcPos ) const
1445 WW8_CP nFallBackCpEnd = WW8_CP_MAX;
1446 if( nFcPos == WW8_FC_MAX )
1447 return nFallBackCpEnd;
1449 bool bIsUnicode;
1450 if (m_pWw8Fib->m_nVersion >= 8)
1451 bIsUnicode = false;
1452 else
1453 bIsUnicode = m_pWw8Fib->m_fExtChar;
1455 if( m_pPieceIter ) // Complex File ?
1457 sal_uInt32 nOldPos = m_pPieceIter->GetIdx();
1459 for (m_pPieceIter->SetIdx(0);
1460 m_pPieceIter->GetIdx() < m_pPieceIter->GetIMax(); m_pPieceIter->advance())
1462 WW8_CP nCpStart, nCpEnd;
1463 void* pData;
1464 if( !m_pPieceIter->Get( nCpStart, nCpEnd, pData ) )
1465 { // outside PLCFfpcd ?
1466 OSL_ENSURE( false, "PLCFpcd-WW8Fc2Cp() went wrong" );
1467 break;
1469 sal_Int32 nFcStart = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
1470 if (m_pWw8Fib->m_nVersion >= 8)
1472 nFcStart = WW8PLCFx_PCD::TransformPieceAddress( nFcStart,
1473 bIsUnicode );
1475 else
1477 bIsUnicode = m_pWw8Fib->m_fExtChar;
1480 sal_Int32 nLen;
1481 if (o3tl::checked_sub(nCpEnd, nCpStart, nLen))
1483 SAL_WARN("sw.ww8", "broken offset, ignoring");
1484 return WW8_CP_MAX;
1486 if (bIsUnicode)
1488 if (o3tl::checked_multiply<WW8_CP>(nLen, 2, nLen))
1490 SAL_WARN("sw.ww8", "broken offset, ignoring");
1491 return WW8_CP_MAX;
1496 If this cp is inside this piece, or it's the last piece and we are
1497 on the very last cp of that piece
1499 if (nFcPos >= nFcStart)
1501 // found
1502 WW8_FC nFcDiff;
1503 if (o3tl::checked_sub(nFcPos, nFcStart, nFcDiff))
1505 SAL_WARN("sw.ww8", "broken offset, ignoring");
1506 return WW8_CP_MAX;
1508 if (bIsUnicode)
1509 nFcDiff /= 2;
1510 WW8_CP nTempCp;
1511 if (o3tl::checked_add(nCpStart, nFcDiff, nTempCp))
1513 SAL_WARN("sw.ww8", "broken offset, ignoring");
1514 return WW8_CP_MAX;
1516 WW8_FC nFcEnd;
1517 if (o3tl::checked_add(nFcStart, nLen, nFcEnd))
1519 SAL_WARN("sw.ww8", "broken offset, ignoring");
1520 return WW8_CP_MAX;
1522 if (nFcPos < nFcEnd)
1524 m_pPieceIter->SetIdx( nOldPos );
1525 return nTempCp;
1527 else if (nFcPos == nFcEnd)
1529 //Keep this cp as its on a piece boundary because we might
1530 //need it if tests fail
1531 nFallBackCpEnd = nTempCp;
1535 // not found
1536 m_pPieceIter->SetIdx( nOldPos ); // not found
1538 If it was not found, then this is because it has fallen between two
1539 stools, i.e. either it is the last cp/fc of the last piece, or it is
1540 the last cp/fc of a disjoint piece.
1542 return nFallBackCpEnd;
1545 WW8_FC nFcDiff;
1546 if (o3tl::checked_sub(nFcPos, m_pWw8Fib->m_fcMin, nFcDiff))
1548 SAL_WARN("sw.ww8", "broken offset, ignoring");
1549 return WW8_CP_MAX;
1552 // No complex file
1553 if (!bIsUnicode)
1554 nFallBackCpEnd = nFcDiff;
1555 else
1556 nFallBackCpEnd = (nFcDiff + 1) / 2;
1558 return nFallBackCpEnd;
1561 // the fib of WinWord2 has a last entry of cpnBtePap of 2 byte sized type PN at
1562 // offset 324
1563 const int nSmallestPossibleFib = 326;
1565 WW8_FC WW8ScannerBase::WW8Cp2Fc(WW8_CP nCpPos, bool* pIsUnicode,
1566 WW8_CP* pNextPieceCp, bool* pTestFlag) const
1568 if( pTestFlag )
1569 *pTestFlag = true;
1570 if( WW8_CP_MAX == nCpPos )
1571 return WW8_CP_MAX;
1573 bool bIsUnicode;
1574 if( !pIsUnicode )
1575 pIsUnicode = &bIsUnicode;
1577 if (m_pWw8Fib->m_nVersion >= 8)
1578 *pIsUnicode = false;
1579 else
1580 *pIsUnicode = m_pWw8Fib->m_fExtChar;
1582 WW8_FC nRet;
1584 if( m_pPieceIter )
1586 // Complex File
1587 if( pNextPieceCp )
1588 *pNextPieceCp = WW8_CP_MAX;
1590 if( !m_pPieceIter->SeekPos( nCpPos ) )
1592 if( pTestFlag )
1593 *pTestFlag = false;
1594 else {
1595 OSL_ENSURE( false, "Handed over wrong CP to WW8Cp2Fc()" );
1597 return WW8_FC_MAX;
1599 WW8_CP nCpStart, nCpEnd;
1600 void* pData;
1601 if( !m_pPieceIter->Get( nCpStart, nCpEnd, pData ) )
1603 if( pTestFlag )
1604 *pTestFlag = false;
1605 else {
1606 OSL_ENSURE( false, "PLCFfpcd-Get went wrong" );
1608 return WW8_FC_MAX;
1610 if( pNextPieceCp )
1611 *pNextPieceCp = nCpEnd;
1613 nRet = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
1614 if (m_pWw8Fib->m_nVersion >= 8)
1615 nRet = WW8PLCFx_PCD::TransformPieceAddress( nRet, *pIsUnicode );
1616 else
1617 *pIsUnicode = m_pWw8Fib->m_fExtChar;
1619 WW8_CP nCpLen;
1620 bool bFail = o3tl::checked_sub(nCpPos, nCpStart, nCpLen);
1621 if (bFail)
1623 SAL_WARN("sw.ww8", "broken offset, ignoring");
1624 return WW8_CP_MAX;
1627 if (*pIsUnicode)
1629 bFail = o3tl::checked_multiply<WW8_CP>(nCpLen, 2, nCpLen);
1630 if (bFail)
1632 SAL_WARN("sw.ww8", "broken offset, ignoring");
1633 return WW8_CP_MAX;
1637 bFail = o3tl::checked_add(nRet, nCpLen, nRet);
1638 if (bFail)
1640 SAL_WARN("sw.ww8", "broken offset, ignoring");
1641 return WW8_CP_MAX;
1644 return nRet;
1647 if (*pIsUnicode)
1649 const bool bFail = o3tl::checked_multiply<WW8_CP>(nCpPos, 2, nCpPos);
1650 if (bFail)
1652 SAL_WARN("sw.ww8", "broken offset, ignoring");
1653 return WW8_CP_MAX;
1657 // No complex file
1658 const bool bFail = o3tl::checked_add(m_pWw8Fib->m_fcMin, nCpPos, nRet);
1659 if (bFail)
1661 SAL_WARN("sw.ww8", "broken offset, ignoring");
1662 return WW8_CP_MAX;
1665 // the text and the fib share the same stream, if the text is inside the fib
1666 // then it's definitely a bad offset. The smallest FIB supported is that of
1667 // WW2 which is 326 bytes in size
1668 if (nRet < nSmallestPossibleFib)
1670 SAL_WARN("sw.ww8", "broken offset, ignoring");
1671 return WW8_CP_MAX;
1674 return nRet;
1677 std::unique_ptr<WW8PLCFpcd> WW8ScannerBase::OpenPieceTable( SvStream* pStr, const WW8Fib* pWwF )
1679 if ( ((8 > m_pWw8Fib->m_nVersion) && !pWwF->m_fComplex) || !pWwF->m_lcbClx )
1680 return nullptr;
1682 if (pWwF->m_lcbClx < 0)
1683 return nullptr;
1685 WW8_FC nClxPos = pWwF->m_fcClx;
1687 if (!checkSeek(*pStr, nClxPos))
1688 return nullptr;
1690 sal_Int32 nClxLen = pWwF->m_lcbClx;
1691 sal_Int32 nLeft = nClxLen;
1693 while (true)
1695 sal_uInt8 clxt(2);
1696 pStr->ReadUChar( clxt );
1697 nLeft--;
1698 if( 2 == clxt) // PLCFfpcd ?
1699 break; // PLCFfpcd found
1700 sal_uInt16 nLen(0);
1701 pStr->ReadUInt16( nLen );
1702 nLeft -= 2 + nLen;
1703 if( nLeft < 0 )
1704 return nullptr; // gone wrong
1705 if( 1 == clxt ) // clxtGrpprl ?
1707 if (m_aPieceGrpprls.size() == SHRT_MAX)
1708 return nullptr;
1709 if (nLen > pStr->remainingSize())
1710 return nullptr;
1711 std::unique_ptr<sal_uInt8[]> p(new sal_uInt8[nLen+2]); // allocate
1712 ShortToSVBT16(nLen, p.get()); // add length
1713 if (!checkRead(*pStr, p.get()+2, nLen)) // read grpprl
1715 return nullptr;
1717 m_aPieceGrpprls.push_back(std::move(p)); // add to array
1719 else
1721 nLen = std::min<sal_uInt64>(nLen, pStr->remainingSize());
1722 pStr->Seek(pStr->Tell() + nLen); // non-Grpprl left
1726 // read Piece Table PLCF
1727 sal_Int32 nPLCFfLen(0);
1728 if (pWwF->GetFIBVersion() <= ww::eWW2)
1730 sal_Int16 nWordTwoLen(0);
1731 pStr->ReadInt16( nWordTwoLen );
1732 nPLCFfLen = nWordTwoLen;
1734 else
1735 pStr->ReadInt32( nPLCFfLen );
1736 OSL_ENSURE( 65536 > nPLCFfLen, "PLCFfpcd above 64 k" );
1737 return std::make_unique<WW8PLCFpcd>( pStr, pStr->Tell(), nPLCFfLen, 8 );
1740 WW8ScannerBase::WW8ScannerBase( SvStream* pSt, SvStream* pTableSt,
1741 SvStream* pDataSt, WW8Fib* pWwFib )
1742 : m_pWw8Fib(pWwFib)
1744 m_pPiecePLCF = OpenPieceTable( pTableSt, m_pWw8Fib ); // Complex
1745 if( m_pPiecePLCF )
1747 m_pPieceIter.reset(new WW8PLCFpcd_Iter( *m_pPiecePLCF ));
1748 m_pPLCFx_PCD.reset( new WW8PLCFx_PCD(*pWwFib, m_pPiecePLCF.get(), 0,
1749 IsSevenMinus(m_pWw8Fib->GetFIBVersion())));
1750 m_pPLCFx_PCDAttrs.reset(new WW8PLCFx_PCDAttrs(*pWwFib,
1751 m_pPLCFx_PCD.get(), this));
1753 else
1755 m_pPieceIter = nullptr;
1756 m_pPLCFx_PCD = nullptr;
1757 m_pPLCFx_PCDAttrs = nullptr;
1760 // pChpPLCF and pPapPLCF may NOT be created before pPLCFx_PCD !!
1761 m_pChpPLCF.reset(new WW8PLCFx_Cp_FKP( pSt, pTableSt, pDataSt, *this, CHP )); // CHPX
1762 m_pPapPLCF.reset(new WW8PLCFx_Cp_FKP( pSt, pTableSt, pDataSt, *this, PAP )); // PAPX
1764 m_pSepPLCF.reset(new WW8PLCFx_SEPX( pSt, pTableSt, *pWwFib, 0 )); // SEPX
1766 // Footnotes
1767 m_pFootnotePLCF.reset(new WW8PLCFx_SubDoc( pTableSt, *pWwFib, 0,
1768 pWwFib->m_fcPlcffndRef, pWwFib->m_lcbPlcffndRef, pWwFib->m_fcPlcffndText,
1769 pWwFib->m_lcbPlcffndText, 2 ));
1770 // Endnotes
1771 m_pEdnPLCF.reset(new WW8PLCFx_SubDoc( pTableSt, *pWwFib, 0,
1772 pWwFib->m_fcPlcfendRef, pWwFib->m_lcbPlcfendRef, pWwFib->m_fcPlcfendText,
1773 pWwFib->m_lcbPlcfendText, 2 ));
1774 // Comments
1775 m_pAndPLCF.reset(new WW8PLCFx_SubDoc( pTableSt, *pWwFib, 0,
1776 pWwFib->m_fcPlcfandRef, pWwFib->m_lcbPlcfandRef, pWwFib->m_fcPlcfandText,
1777 pWwFib->m_lcbPlcfandText, IsSevenMinus(pWwFib->GetFIBVersion()) ? 20 : 30));
1779 // Fields Main Text
1780 m_pFieldPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_MAINTEXT));
1781 // Fields Header / Footer
1782 m_pFieldHdFtPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_HDFT));
1783 // Fields Footnote
1784 m_pFieldFootnotePLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_FTN));
1785 // Fields Endnote
1786 m_pFieldEdnPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_EDN));
1787 // Fields Comments
1788 m_pFieldAndPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_AND));
1789 // Fields in Textboxes in Main Text
1790 m_pFieldTxbxPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_TXBX));
1791 // Fields in Textboxes in Header / Footer
1792 m_pFieldTxbxHdFtPLCF.reset(new WW8PLCFx_FLD(pTableSt,*pWwFib,MAN_TXBX_HDFT));
1794 // Note: 6 stands for "6 OR 7", 7 stands for "ONLY 7"
1795 switch( m_pWw8Fib->m_nVersion )
1797 case 6:
1798 case 7:
1799 if( pWwFib->m_fcPlcfdoaMom && pWwFib->m_lcbPlcfdoaMom )
1801 m_pMainFdoa.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfdoaMom,
1802 pWwFib->m_lcbPlcfdoaMom, 6 ));
1804 if( pWwFib->m_fcPlcfdoaHdr && pWwFib->m_lcbPlcfdoaHdr )
1806 m_pHdFtFdoa.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfdoaHdr,
1807 pWwFib->m_lcbPlcfdoaHdr, 6 ));
1809 break;
1810 case 8:
1811 if( pWwFib->m_fcPlcfspaMom && pWwFib->m_lcbPlcfspaMom )
1813 m_pMainFdoa.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfspaMom,
1814 pWwFib->m_lcbPlcfspaMom, 26 ));
1816 if( pWwFib->m_fcPlcfspaHdr && pWwFib->m_lcbPlcfspaHdr )
1818 m_pHdFtFdoa.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfspaHdr,
1819 pWwFib->m_lcbPlcfspaHdr, 26 ));
1821 // PLCF for TextBox break-descriptors in the main text
1822 if( pWwFib->m_fcPlcftxbxBkd && pWwFib->m_lcbPlcftxbxBkd )
1824 m_pMainTxbxBkd.reset(new WW8PLCFspecial( pTableSt,
1825 pWwFib->m_fcPlcftxbxBkd, pWwFib->m_lcbPlcftxbxBkd, 0));
1827 // PLCF for TextBox break-descriptors in Header/Footer range
1828 if( pWwFib->m_fcPlcfHdrtxbxBkd && pWwFib->m_lcbPlcfHdrtxbxBkd )
1830 m_pHdFtTxbxBkd.reset(new WW8PLCFspecial( pTableSt,
1831 pWwFib->m_fcPlcfHdrtxbxBkd, pWwFib->m_lcbPlcfHdrtxbxBkd, 0));
1833 // Sub table cp positions
1834 if (pWwFib->m_fcPlcfTch && pWwFib->m_lcbPlcfTch)
1836 m_pMagicTables.reset(new WW8PLCFspecial( pTableSt,
1837 pWwFib->m_fcPlcfTch, pWwFib->m_lcbPlcfTch, 4));
1839 // Sub document cp positions
1840 if (pWwFib->m_fcPlcfwkb && pWwFib->m_lcbPlcfwkb)
1842 m_pSubdocs.reset(new WW8PLCFspecial( pTableSt,
1843 pWwFib->m_fcPlcfwkb, pWwFib->m_lcbPlcfwkb, 12));
1845 // Extended ATRD
1846 if (pWwFib->m_fcAtrdExtra && pWwFib->m_lcbAtrdExtra)
1848 sal_uInt64 const nOldPos = pTableSt->Tell();
1849 if (checkSeek(*pTableSt, pWwFib->m_fcAtrdExtra) && (pTableSt->remainingSize() >= pWwFib->m_lcbAtrdExtra))
1851 m_pExtendedAtrds.reset( new sal_uInt8[pWwFib->m_lcbAtrdExtra] );
1852 pWwFib->m_lcbAtrdExtra = pTableSt->ReadBytes(m_pExtendedAtrds.get(), pWwFib->m_lcbAtrdExtra);
1854 else
1855 pWwFib->m_lcbAtrdExtra = 0;
1856 pTableSt->Seek(nOldPos);
1859 break;
1860 default:
1861 OSL_ENSURE( false, "nVersion not implemented!" );
1862 break;
1865 // PLCF for TextBox stories in main text
1866 sal_uInt32 nLenTxBxS = (8 > m_pWw8Fib->m_nVersion) ? 0 : 22;
1867 if( pWwFib->m_fcPlcftxbxText && pWwFib->m_lcbPlcftxbxText )
1869 m_pMainTxbx.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcftxbxText,
1870 pWwFib->m_lcbPlcftxbxText, nLenTxBxS ));
1873 // PLCF for TextBox stories in Header/Footer range
1874 if( pWwFib->m_fcPlcfHdrtxbxText && pWwFib->m_lcbPlcfHdrtxbxText )
1876 m_pHdFtTxbx.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfHdrtxbxText,
1877 pWwFib->m_lcbPlcfHdrtxbxText, nLenTxBxS ));
1880 m_pBook.reset(new WW8PLCFx_Book(pTableSt, *pWwFib));
1881 m_pAtnBook.reset(new WW8PLCFx_AtnBook(pTableSt, *pWwFib));
1882 m_pFactoidBook.reset(new WW8PLCFx_FactoidBook(pTableSt, *pWwFib));
1885 WW8ScannerBase::~WW8ScannerBase()
1887 m_aPieceGrpprls.clear();
1888 m_pPLCFx_PCDAttrs.reset();
1889 m_pPLCFx_PCD.reset();
1890 m_pPieceIter.reset();
1891 m_pPiecePLCF.reset();
1892 m_pFactoidBook.reset();
1893 m_pAtnBook.reset();
1894 m_pBook.reset();
1895 m_pFieldEdnPLCF.reset();
1896 m_pFieldFootnotePLCF.reset();
1897 m_pFieldAndPLCF.reset();
1898 m_pFieldHdFtPLCF.reset();
1899 m_pFieldPLCF.reset();
1900 m_pFieldTxbxPLCF.reset();
1901 m_pFieldTxbxHdFtPLCF.reset();
1902 m_pEdnPLCF.reset();
1903 m_pFootnotePLCF.reset();
1904 m_pAndPLCF.reset();
1905 m_pSepPLCF.reset();
1906 m_pPapPLCF.reset();
1907 m_pChpPLCF.reset();
1908 m_pMainFdoa.reset();
1909 m_pHdFtFdoa.reset();
1910 m_pMainTxbx.reset();
1911 m_pMainTxbxBkd.reset();
1912 m_pHdFtTxbx.reset();
1913 m_pHdFtTxbxBkd.reset();
1914 m_pMagicTables.reset();
1915 m_pSubdocs.reset();
1918 // Fields
1920 static bool WW8SkipField(WW8PLCFspecial& rPLCF)
1922 void* pData;
1923 WW8_CP nP;
1925 if (!rPLCF.Get(nP, pData)) // End of PLCFspecial?
1926 return false;
1928 rPLCF.advance();
1930 if((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) != 0x13 ) // No beginning?
1931 return true; // Do not terminate on error
1933 if( !rPLCF.Get( nP, pData ) )
1934 return false;
1936 while((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x13 )
1938 // still new (nested) beginnings ?
1939 WW8SkipField( rPLCF ); // nested Field in description
1940 if( !rPLCF.Get( nP, pData ) )
1941 return false;
1944 if((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x14 )
1947 // Field Separator ?
1948 rPLCF.advance();
1950 if( !rPLCF.Get( nP, pData ) )
1951 return false;
1953 while ((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x13)
1955 // still new (nested) beginnings?
1956 WW8SkipField( rPLCF ); // nested Field in Results
1957 if( !rPLCF.Get( nP, pData ) )
1958 return false;
1961 rPLCF.advance();
1963 return true;
1966 static bool WW8GetFieldPara(WW8PLCFspecial& rPLCF, WW8FieldDesc& rF)
1968 void* pData;
1969 sal_uInt32 nOldIdx = rPLCF.GetIdx();
1971 rF.nLen = rF.nId = rF.nOpt = 0;
1972 rF.bCodeNest = rF.bResNest = false;
1974 if (!rPLCF.Get(rF.nSCode, pData) || rF.nSCode < 0) // end of PLCFspecial?
1975 goto Err;
1977 rPLCF.advance();
1979 if (!pData || (static_cast<sal_uInt8*>(pData)[0] & 0x1f) != 0x13) // No beginning?
1980 goto Err;
1982 rF.nId = static_cast<sal_uInt8*>(pData)[1];
1984 if( !rPLCF.Get( rF.nLCode, pData ) )
1985 goto Err;
1987 if (rF.nLCode < rF.nSCode)
1988 goto Err;
1990 rF.nSRes = rF.nLCode; // Default
1991 rF.nSCode++; // without markers
1992 rF.nLCode -= rF.nSCode; // Pos -> length
1994 while((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x13 )
1996 // still new (nested) beginnings ?
1997 WW8SkipField( rPLCF ); // nested Field in description
1998 rF.bCodeNest = true;
1999 if (!rPLCF.Get(rF.nSRes, pData) || rF.nSRes < 0)
2000 goto Err;
2003 if ((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x14 ) // Field Separator?
2005 rPLCF.advance();
2007 if (!rPLCF.Get(rF.nLRes, pData) || rF.nLRes < 0)
2008 goto Err;
2010 while((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x13 )
2012 // still new (nested) beginnings ?
2013 WW8SkipField( rPLCF ); // nested Field in results
2014 rF.bResNest = true;
2015 if (!rPLCF.Get(rF.nLRes, pData) || rF.nLRes < 0)
2016 goto Err;
2018 WW8_CP nTmp;
2019 if (o3tl::checked_sub<WW8_CP>(rF.nLRes, rF.nSCode, nTmp))
2021 rF.nLen = 0;
2022 goto Err;
2024 if (o3tl::checked_add<WW8_CP>(nTmp, 2, rF.nLen)) // nLRes is still the final position
2026 rF.nLen = 0;
2027 goto Err;
2029 rF.nLRes -= rF.nSRes; // now: nLRes = length
2030 if (o3tl::checked_add<WW8_CP>(rF.nSRes, 1, rF.nSRes)) // Endpos including Markers
2032 rF.nLen = 0;
2033 goto Err;
2035 rF.nLRes--;
2036 }else{
2037 rF.nLRes = 0; // no result found
2038 WW8_CP nTmp;
2039 if (o3tl::checked_sub<WW8_CP>(rF.nSRes, rF.nSCode, nTmp))
2041 rF.nLen = 0;
2042 goto Err;
2044 if (o3tl::checked_add<WW8_CP>(nTmp, 2, rF.nLen)) // total length
2046 rF.nLen = 0;
2047 goto Err;
2051 if (rF.nLen < 0)
2053 rF.nLen = 0;
2054 goto Err;
2057 rPLCF.advance();
2058 if((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x15 )
2060 // Field end ?
2061 // INDEX-Field has set Bit7?
2062 rF.nOpt = static_cast<sal_uInt8*>(pData)[1]; // yes -> copy flags
2063 }else{
2064 rF.nId = 0; // no -> Field invalid
2067 rPLCF.SetIdx( nOldIdx );
2068 return true;
2069 Err:
2070 rPLCF.SetIdx( nOldIdx );
2071 return false;
2074 OUString read_uInt8_BeltAndBracesString(SvStream& rStrm, rtl_TextEncoding eEnc)
2076 const OUString aRet = read_uInt8_lenPrefixed_uInt8s_ToOUString(rStrm, eEnc);
2077 rStrm.SeekRel(sizeof(sal_uInt8)); // skip null-byte at end
2078 return aRet;
2081 OUString read_uInt16_BeltAndBracesString(SvStream& rStrm)
2083 const OUString aRet = read_uInt16_PascalString(rStrm);
2084 rStrm.SeekRel(sizeof(sal_Unicode)); // skip null-byte at end
2085 return aRet;
2088 sal_Int32 WW8ScannerBase::WW8ReadString( SvStream& rStrm, OUString& rStr,
2089 WW8_CP nCurrentStartCp, tools::Long nTotalLen, rtl_TextEncoding eEnc ) const
2091 // Read in plain text, which can extend over several pieces
2092 rStr.clear();
2094 if (nCurrentStartCp < 0 || nTotalLen < 0)
2095 return 0;
2097 WW8_CP nBehindTextCp = nCurrentStartCp + nTotalLen;
2098 WW8_CP nNextPieceCp = nBehindTextCp; // Initialization, important for Ver6
2099 tools::Long nTotalRead = 0;
2102 bool bIsUnicode(false), bPosOk(false);
2103 WW8_FC fcAct = WW8Cp2Fc(nCurrentStartCp,&bIsUnicode,&nNextPieceCp,&bPosOk);
2105 // Probably aimed beyond file end, doesn't matter!
2106 if( !bPosOk )
2107 break;
2109 bool bValid = checkSeek(rStrm, fcAct);
2110 if (!bValid)
2111 break;
2113 WW8_CP nEnd = (nNextPieceCp < nBehindTextCp) ? nNextPieceCp
2114 : nBehindTextCp;
2115 WW8_CP nLen;
2116 const bool bFail = o3tl::checked_sub(nEnd, nCurrentStartCp, nLen);
2117 if (bFail)
2118 break;
2120 if( 0 >= nLen )
2121 break;
2123 rStr += bIsUnicode
2124 ? read_uInt16s_ToOUString(rStrm, nLen)
2125 : read_uInt8s_ToOUString(rStrm, nLen, eEnc);
2127 nTotalRead += nLen;
2128 nCurrentStartCp += nLen;
2129 if ( nTotalRead != rStr.getLength() )
2130 break;
2132 while( nTotalRead < nTotalLen );
2134 return rStr.getLength();
2137 WW8PLCFspecial::WW8PLCFspecial(SvStream* pSt, sal_uInt32 nFilePos,
2138 sal_uInt32 nPLCF, sal_uInt32 nStruct)
2139 : nIdx(0), nStru(nStruct)
2141 const sal_uInt32 nValidMin=4;
2143 sal_uInt64 const nOldPos = pSt->Tell();
2145 bool bValid = checkSeek(*pSt, nFilePos);
2146 std::size_t nRemainingSize = pSt->remainingSize();
2147 if( nRemainingSize < nValidMin || nPLCF < nValidMin )
2148 bValid = false;
2149 nPLCF = bValid ? std::min(nRemainingSize, static_cast<std::size_t>(nPLCF)) : nValidMin;
2151 // Pointer to Pos- and Struct-array
2152 pPLCF_PosArray.reset( new sal_Int32[ ( nPLCF + 3 ) / 4 ] );
2153 pPLCF_PosArray[0] = 0;
2155 nPLCF = bValid ? pSt->ReadBytes(pPLCF_PosArray.get(), nPLCF) : nValidMin;
2157 nPLCF = std::max(nPLCF, nValidMin);
2159 nIMax = ( nPLCF - 4 ) / ( 4 + nStruct );
2160 #ifdef OSL_BIGENDIAN
2161 for( nIdx = 0; nIdx <= nIMax; nIdx++ )
2162 pPLCF_PosArray[nIdx] = OSL_SWAPDWORD( pPLCF_PosArray[nIdx] );
2163 nIdx = 0;
2164 #endif // OSL_BIGENDIAN
2165 if( nStruct ) // Pointer to content array
2166 pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&pPLCF_PosArray[nIMax + 1]);
2167 else
2168 pPLCF_Contents = nullptr; // no content
2170 pSt->Seek(nOldPos);
2173 // WW8PLCFspecial::SeekPos() sets WW8PLCFspecial to position nPos, while also the entry is used
2174 // that begins before nPos and ends after nPos.
2175 // Suitable for normal attributes. However, the beginning of the attribute is not corrected onto
2176 // the position nPos.
2177 bool WW8PLCFspecial::SeekPos(tools::Long nP)
2179 if( nP < pPLCF_PosArray[0] )
2181 nIdx = 0;
2182 return false; // Not found: nP less than smallest entry
2185 // Search from beginning?
2186 if ((nIdx < 1) || (nP < pPLCF_PosArray[nIdx - 1]))
2187 nIdx = 1;
2189 tools::Long nI = nIdx;
2190 tools::Long nEnd = nIMax;
2192 for(int n = (1==nIdx ? 1 : 2); n; --n )
2194 for( ; nI <=nEnd; ++nI)
2195 { // search with an index that is incremented by 1
2196 if( nP < pPLCF_PosArray[nI] )
2197 { // found position
2198 nIdx = nI - 1; // nI - 1 is the correct index
2199 return true; // done
2202 nI = 1;
2203 nEnd = nIdx-1;
2205 nIdx = nIMax; // not found, greater than all entries
2206 return false;
2209 // WW8PLCFspecial::SeekPosExact() like SeekPos(), but it is ensured that no attribute is cut,
2210 // i.e. the next given attribute begins at or after nPos.
2211 // Is used for fields and bookmarks.
2212 bool WW8PLCFspecial::SeekPosExact(tools::Long nP)
2214 if( nP < pPLCF_PosArray[0] )
2216 nIdx = 0;
2217 return false; // Not found: nP less than smallest entry
2219 // Search from beginning?
2220 if( nP <=pPLCF_PosArray[nIdx] )
2221 nIdx = 0;
2223 tools::Long nI = nIdx ? nIdx-1 : 0;
2224 tools::Long nEnd = nIMax;
2226 for(int n = (0==nIdx ? 1 : 2); n; --n )
2228 for( ; nI < nEnd; ++nI)
2230 if( nP <=pPLCF_PosArray[nI] )
2231 { // found position
2232 nIdx = nI; // nI is the correct index
2233 return true; // done
2236 nI = 0;
2237 nEnd = nIdx;
2239 nIdx = nIMax; // Not found, greater than all entries
2240 return false;
2243 bool WW8PLCFspecial::Get(WW8_CP& rPos, void*& rpValue) const
2245 return GetData( nIdx, rPos, rpValue );
2248 bool WW8PLCFspecial::GetData(tools::Long nInIdx, WW8_CP& rPos, void*& rpValue) const
2250 if ( nInIdx >= nIMax )
2252 rPos = WW8_CP_MAX;
2253 return false;
2255 rPos = pPLCF_PosArray[nInIdx];
2256 rpValue = pPLCF_Contents ? static_cast<void*>(&pPLCF_Contents[nInIdx * nStru]) : nullptr;
2257 return true;
2260 // WW8PLCF e.g. for SEPX
2261 // Ctor for *others* than Fkps
2262 // With nStartPos < 0, the first element of PLCFs will be taken
2263 WW8PLCF::WW8PLCF(SvStream& rSt, WW8_FC nFilePos, sal_Int32 nPLCF, int nStruct,
2264 WW8_CP nStartPos) : nIdx(0), nStru(nStruct)
2266 if (nPLCF < 0)
2268 SAL_WARN("sw.ww8", "broken WW8PLCF, ignoring");
2269 nPLCF = 0;
2271 else
2272 nIMax = (nPLCF - 4) / (4 + nStruct);
2274 ReadPLCF(rSt, nFilePos, nPLCF);
2276 if( nStartPos >= 0 )
2277 SeekPos( nStartPos );
2280 // Ctor *only* for Fkps
2281 // The last 2 parameters are needed for PLCF.Chpx and PLCF.Papx.
2282 // If ncpN != 0, then an incomplete PLCF will be completed. This is always required for WW6 with
2283 // lack of resources and for WordPad (W95).
2284 // With nStartPos < 0, the first element of the PLCFs is taken.
2285 WW8PLCF::WW8PLCF(SvStream& rSt, WW8_FC nFilePos, sal_Int32 nPLCF, int nStruct,
2286 WW8_CP nStartPos, sal_Int32 nPN, sal_Int32 ncpN): nIdx(0),
2287 nStru(nStruct)
2289 if (nPLCF < 0)
2291 SAL_WARN("sw.ww8", "broken WW8PLCF, ignoring");
2292 nIMax = SAL_MAX_INT32;
2294 else
2295 nIMax = (nPLCF - 4) / (4 + nStruct);
2297 if( nIMax >= ncpN )
2298 ReadPLCF(rSt, nFilePos, nPLCF);
2299 else
2300 GeneratePLCF(rSt, nPN, ncpN);
2302 if( nStartPos >= 0 )
2303 SeekPos( nStartPos );
2306 void WW8PLCF::ReadPLCF(SvStream& rSt, WW8_FC nFilePos, sal_uInt32 nPLCF)
2308 sal_uInt64 const nOldPos = rSt.Tell();
2309 bool bValid = nPLCF != 0 && checkSeek(rSt, nFilePos)
2310 && (rSt.remainingSize() >= nPLCF);
2312 if (bValid)
2314 // Pointer to Pos-array
2315 pPLCF_PosArray.reset( new WW8_CP[ ( nPLCF + 3 ) / 4 ] );
2316 bValid = checkRead(rSt, pPLCF_PosArray.get(), nPLCF);
2319 if (bValid)
2321 #ifdef OSL_BIGENDIAN
2322 for( nIdx = 0; nIdx <= nIMax; nIdx++ )
2323 pPLCF_PosArray[nIdx] = OSL_SWAPDWORD( pPLCF_PosArray[nIdx] );
2324 nIdx = 0;
2325 #endif // OSL_BIGENDIAN
2326 // Pointer to content array
2327 pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&pPLCF_PosArray[nIMax + 1]);
2329 TruncToSortedRange();
2332 OSL_ENSURE(bValid, "Document has corrupt PLCF, ignoring it");
2334 if (!bValid)
2335 MakeFailedPLCF();
2337 rSt.Seek(nOldPos);
2340 void WW8PLCF::MakeFailedPLCF()
2342 nIMax = 0;
2343 pPLCF_PosArray.reset( new WW8_CP[2] );
2344 pPLCF_PosArray[0] = pPLCF_PosArray[1] = WW8_CP_MAX;
2345 pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&pPLCF_PosArray[nIMax + 1]);
2348 namespace
2350 sal_Int32 TruncToSortedRange(const sal_Int32* pPLCF_PosArray, sal_Int32 nIMax)
2352 //Docs state that: ... all Plcs ... are sorted in ascending order.
2353 //So ensure that here for broken documents.
2354 for (auto nI = 0; nI < nIMax; ++nI)
2356 if (pPLCF_PosArray[nI] > pPLCF_PosArray[nI+1])
2358 SAL_WARN("sw.ww8", "Document has unsorted PLCF, truncated to sorted portion");
2359 nIMax = nI;
2360 break;
2363 return nIMax;
2367 void WW8PLCFpcd::TruncToSortedRange()
2369 nIMax = ::TruncToSortedRange(pPLCF_PosArray.get(), nIMax);
2372 void WW8PLCF::TruncToSortedRange()
2374 nIMax = ::TruncToSortedRange(pPLCF_PosArray.get(), nIMax);
2377 void WW8PLCF::GeneratePLCF(SvStream& rSt, sal_Int32 nPN, sal_Int32 ncpN)
2379 OSL_ENSURE( nIMax < ncpN, "Pcl.Fkp: Why is PLCF too big?" );
2381 bool failure = false;
2382 nIMax = ncpN;
2384 if ((nIMax < 1) || (nIMax > (WW8_CP_MAX - 4) / (4 + nStru)) || nPN < 0)
2385 failure = true;
2387 if (!failure)
2389 // Check arguments to ShortToSVBT16 in loop below will all be valid:
2390 sal_Int32 nResult;
2391 failure = o3tl::checked_add(nPN, ncpN, nResult) || nResult > SAL_MAX_UINT16;
2394 if (!failure)
2396 size_t nSiz = (4 + nStru) * nIMax + 4;
2397 size_t nElems = ( nSiz + 3 ) / 4;
2398 pPLCF_PosArray.reset( new WW8_CP[ nElems ] ); // Pointer to Pos-array
2400 for (sal_Int32 i = 0; i < ncpN && !failure; ++i)
2402 failure = true;
2403 // construct FC entries
2404 // first FC entry of each Fkp
2405 if (!checkSeek(rSt, (nPN + i) << 9))
2406 break;
2408 WW8_CP nFc(0);
2409 rSt.ReadInt32( nFc );
2410 pPLCF_PosArray[i] = nFc;
2412 failure = bool(rSt.GetError());
2416 if (!failure)
2420 failure = true;
2422 std::size_t nLastFkpPos = nPN + nIMax - 1;
2423 nLastFkpPos = nLastFkpPos << 9;
2424 // number of FC entries of last Fkp
2425 if (!checkSeek(rSt, nLastFkpPos + 511))
2426 break;
2428 sal_uInt8 nb(0);
2429 rSt.ReadUChar( nb );
2430 // last FC entry of last Fkp
2431 if (!checkSeek(rSt, nLastFkpPos + nb * 4))
2432 break;
2434 WW8_CP nFc(0);
2435 rSt.ReadInt32( nFc );
2436 pPLCF_PosArray[nIMax] = nFc; // end of the last Fkp
2438 failure = bool(rSt.GetError());
2439 } while(false);
2442 if (!failure)
2444 // Pointer to content array
2445 pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&pPLCF_PosArray[nIMax + 1]);
2446 sal_uInt8* p = pPLCF_Contents;
2448 for (sal_Int32 i = 0; i < ncpN; ++i) // construct PNs
2450 ShortToSVBT16(static_cast<sal_uInt16>(nPN + i), p);
2451 p += nStru;
2455 SAL_WARN_IF(failure, "sw.ww8", "Document has corrupt PLCF, ignoring it");
2457 if (failure)
2458 MakeFailedPLCF();
2461 bool WW8PLCF::SeekPos(WW8_CP nPos)
2463 WW8_CP nP = nPos;
2465 if( nP < pPLCF_PosArray[0] )
2467 nIdx = 0;
2468 // not found: nPos less than smallest entry
2469 return false;
2472 // Search from beginning?
2473 if ((nIdx < 1) || (nP < pPLCF_PosArray[nIdx - 1]))
2474 nIdx = 1;
2476 sal_Int32 nI = nIdx;
2477 sal_Int32 nEnd = nIMax;
2479 for(int n = (1==nIdx ? 1 : 2); n; --n )
2481 for( ; nI <=nEnd; ++nI) // search with an index that is incremented by 1
2483 if( nP < pPLCF_PosArray[nI] ) // found position
2485 nIdx = nI - 1; // nI - 1 is the correct index
2486 return true; // done
2489 nI = 1;
2490 nEnd = nIdx-1;
2493 nIdx = nIMax; // not found, greater than all entries
2494 return false;
2497 bool WW8PLCF::Get(WW8_CP& rStart, WW8_CP& rEnd, void*& rpValue) const
2499 if ( nIdx >= nIMax )
2501 rStart = rEnd = WW8_CP_MAX;
2502 return false;
2504 rStart = pPLCF_PosArray[ nIdx ];
2505 rEnd = pPLCF_PosArray[ nIdx + 1 ];
2506 rpValue = static_cast<void*>(&pPLCF_Contents[nIdx * nStru]);
2507 return true;
2510 WW8_CP WW8PLCF::Where() const
2512 if ( nIdx >= nIMax )
2513 return WW8_CP_MAX;
2515 return pPLCF_PosArray[nIdx];
2518 WW8PLCFpcd::WW8PLCFpcd(SvStream* pSt, sal_uInt32 nFilePos,
2519 sal_uInt32 nPLCF, sal_uInt32 nStruct)
2520 : nStru( nStruct )
2522 const sal_uInt32 nValidMin=4;
2524 sal_uInt64 const nOldPos = pSt->Tell();
2526 bool bValid = checkSeek(*pSt, nFilePos);
2527 std::size_t nRemainingSize = pSt->remainingSize();
2528 if( nRemainingSize < nValidMin || nPLCF < nValidMin )
2529 bValid = false;
2530 nPLCF = bValid ? std::min(nRemainingSize, static_cast<std::size_t>(nPLCF)) : nValidMin;
2532 pPLCF_PosArray.reset( new WW8_CP[ ( nPLCF + 3 ) / 4 ] ); // Pointer to Pos-array
2533 pPLCF_PosArray[0] = 0;
2535 nPLCF = bValid ? pSt->ReadBytes(pPLCF_PosArray.get(), nPLCF) : nValidMin;
2536 nPLCF = std::max(nPLCF, nValidMin);
2538 nIMax = ( nPLCF - 4 ) / ( 4 + nStruct );
2539 #ifdef OSL_BIGENDIAN
2540 for( tools::Long nI = 0; nI <= nIMax; nI++ )
2541 pPLCF_PosArray[nI] = OSL_SWAPDWORD( pPLCF_PosArray[nI] );
2542 #endif // OSL_BIGENDIAN
2544 // Pointer to content array
2545 pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&pPLCF_PosArray[nIMax + 1]);
2546 TruncToSortedRange();
2548 pSt->Seek( nOldPos );
2551 // If nStartPos < 0, the first element of PLCFs will be taken
2552 WW8PLCFpcd_Iter::WW8PLCFpcd_Iter( WW8PLCFpcd& rPLCFpcd, tools::Long nStartPos )
2553 :rPLCF( rPLCFpcd ), nIdx( 0 )
2555 if( nStartPos >= 0 )
2556 SeekPos( nStartPos );
2559 bool WW8PLCFpcd_Iter::SeekPos(tools::Long nPos)
2561 tools::Long nP = nPos;
2563 if( nP < rPLCF.pPLCF_PosArray[0] )
2565 nIdx = 0;
2566 return false; // not found: nPos less than smallest entry
2568 // Search from beginning?
2569 if ((nIdx < 1) || (nP < rPLCF.pPLCF_PosArray[nIdx - 1]))
2570 nIdx = 1;
2572 tools::Long nI = nIdx;
2573 tools::Long nEnd = rPLCF.nIMax;
2575 for(int n = (1==nIdx ? 1 : 2); n; --n )
2577 for( ; nI <=nEnd; ++nI)
2578 { // search with an index that is incremented by 1
2579 if( nP < rPLCF.pPLCF_PosArray[nI] )
2580 { // found position
2581 nIdx = nI - 1; // nI - 1 is the correct index
2582 return true; // done
2585 nI = 1;
2586 nEnd = nIdx-1;
2588 nIdx = rPLCF.nIMax; // not found, greater than all entries
2589 return false;
2592 bool WW8PLCFpcd_Iter::Get(WW8_CP& rStart, WW8_CP& rEnd, void*& rpValue) const
2594 if( nIdx >= rPLCF.nIMax )
2596 rStart = rEnd = WW8_CP_MAX;
2597 return false;
2599 rStart = rPLCF.pPLCF_PosArray[nIdx];
2600 rEnd = rPLCF.pPLCF_PosArray[nIdx + 1];
2601 rpValue = static_cast<void*>(&rPLCF.pPLCF_Contents[nIdx * rPLCF.nStru]);
2602 return true;
2605 sal_Int32 WW8PLCFpcd_Iter::Where() const
2607 if ( nIdx >= rPLCF.nIMax )
2608 return SAL_MAX_INT32;
2610 return rPLCF.pPLCF_PosArray[nIdx];
2613 bool WW8PLCFx_Fc_FKP::WW8Fkp::Entry::operator<
2614 (const WW8PLCFx_Fc_FKP::WW8Fkp::Entry& rSecond) const
2616 return (mnFC < rSecond.mnFC);
2619 static bool IsReplaceAllSprm(sal_uInt16 nSpId)
2621 return (NS_sprm::LN_PHugePapx == nSpId || 0x6646 == nSpId);
2624 static bool IsExpandableSprm(sal_uInt16 nSpId)
2626 return 0x646B == nSpId;
2629 void WW8PLCFx_Fc_FKP::WW8Fkp::FillEntry(WW8PLCFx_Fc_FKP::WW8Fkp::Entry &rEntry,
2630 std::size_t nDataOffset, sal_uInt16 nLen)
2632 bool bValidPos = (nDataOffset < sizeof(maRawData));
2634 OSL_ENSURE(bValidPos, "sprm sequence offset is out of range, ignoring");
2636 if (!bValidPos)
2638 rEntry.mnLen = 0;
2639 return;
2642 const sal_uInt16 nAvailableData = sizeof(maRawData)-nDataOffset;
2643 OSL_ENSURE(nLen <= nAvailableData, "srpm sequence len is out of range, clipping");
2644 rEntry.mnLen = std::min(nLen, nAvailableData);
2645 rEntry.mpData = maRawData + nDataOffset;
2648 WW8PLCFx_Fc_FKP::WW8Fkp::WW8Fkp(const WW8Fib& rFib, SvStream* pSt,
2649 SvStream* pDataSt, tools::Long _nFilePos, tools::Long nItemSiz, ePLCFT ePl,
2650 WW8_FC nStartFc)
2651 : nItemSize(nItemSiz), nFilePos(_nFilePos), mnIdx(0), ePLCF(ePl)
2652 , mnMustRemainCached(0), maSprmParser(rFib)
2654 memset(maRawData, 0, 512);
2656 const ww::WordVersion eVersion = rFib.GetFIBVersion();
2658 sal_uInt64 const nOldPos = pSt->Tell();
2660 bool bCouldSeek = checkSeek(*pSt, nFilePos);
2661 bool bCouldRead = bCouldSeek && checkRead(*pSt, maRawData, 512);
2663 mnIMax = bCouldRead ? maRawData[511] : 0;
2665 sal_uInt8 *pStart = maRawData;
2666 // Offset-Location in maRawData
2667 const size_t nRawDataStart = (mnIMax + 1) * 4;
2669 for (mnIdx = 0; mnIdx < mnIMax; ++mnIdx)
2671 const size_t nRawDataOffset = nRawDataStart + mnIdx * nItemSize;
2673 //clip to available data, corrupt fkp
2674 if (nRawDataOffset >= 511)
2676 mnIMax = mnIdx;
2677 break;
2680 unsigned int nOfs = maRawData[nRawDataOffset] * 2;
2681 // nOfs in [0..0xff*2=510]
2683 Entry aEntry(Get_Long(pStart));
2685 if (nOfs)
2687 switch (ePLCF)
2689 case CHP:
2691 aEntry.mnLen = maRawData[nOfs];
2693 //len byte
2694 std::size_t nDataOffset = nOfs + 1;
2696 FillEntry(aEntry, nDataOffset, aEntry.mnLen);
2698 if (aEntry.mnLen && eVersion <= ww::eWW2)
2700 Word2CHPX aChpx = ReadWord2Chpx(*pSt, nFilePos + nOfs + 1, static_cast< sal_uInt8 >(aEntry.mnLen));
2701 std::vector<sal_uInt8> aSprms = ChpxToSprms(aChpx);
2702 aEntry.mnLen = static_cast< sal_uInt16 >(aSprms.size());
2703 if (aEntry.mnLen)
2705 aEntry.mpData = new sal_uInt8[aEntry.mnLen];
2706 memcpy(aEntry.mpData, aSprms.data(), aEntry.mnLen);
2707 aEntry.mbMustDelete = true;
2710 break;
2712 case PAP:
2714 sal_uInt8 nDelta = 0;
2716 aEntry.mnLen = maRawData[nOfs];
2717 if (IsEightPlus(eVersion) && !aEntry.mnLen)
2719 aEntry.mnLen = maRawData[nOfs+1];
2720 nDelta++;
2722 aEntry.mnLen *= 2;
2724 //stylecode, std/istd
2725 if (eVersion <= ww::eWW2)
2727 if (aEntry.mnLen >= 1)
2729 aEntry.mnIStd = *(maRawData+nOfs+1+nDelta);
2730 aEntry.mnLen--; //style code
2731 if (aEntry.mnLen >= 6)
2733 aEntry.mnLen-=6; //PHE
2734 //skip stc, len byte + 6 byte PHE
2735 unsigned int nOffset = nOfs + 8;
2736 if (nOffset >= 511) //Bad offset
2737 aEntry.mnLen=0;
2738 if (aEntry.mnLen) //start is ok
2740 if (nOffset + aEntry.mnLen > 512) //Bad end, clip
2741 aEntry.mnLen = 512 - nOffset;
2742 aEntry.mpData = maRawData + nOffset;
2745 else
2746 aEntry.mnLen=0; //Too short
2749 else
2751 if (aEntry.mnLen >= 2)
2753 //len byte + optional extra len byte
2754 std::size_t nDataOffset = nOfs + 1 + nDelta;
2755 aEntry.mnIStd = nDataOffset <= sizeof(maRawData)-sizeof(aEntry.mnIStd) ?
2756 SVBT16ToUInt16(maRawData+nDataOffset) : 0;
2757 aEntry.mnLen-=2; //istd
2758 if (aEntry.mnLen)
2760 //additional istd
2761 nDataOffset += sizeof(aEntry.mnIStd);
2763 FillEntry(aEntry, nDataOffset, aEntry.mnLen);
2766 else
2767 aEntry.mnLen=0; //Too short, ignore
2770 const sal_uInt16 nSpId = aEntry.mnLen
2771 ? maSprmParser.GetSprmId(aEntry.mpData) : 0;
2774 If we replace then we throw away the old data, if we
2775 are expanding, then we tack the old data onto the end
2776 of the new data
2778 const bool bExpand = IsExpandableSprm(nSpId);
2779 const sal_uInt8* pStartData
2780 = aEntry.mpData == nullptr ? nullptr : aEntry.mpData + 2;
2781 const sal_uInt8* pLastValidDataPos = maRawData + 512 - sizeof(sal_uInt32);
2782 if (pStartData != nullptr && pStartData > pLastValidDataPos)
2783 pStartData = nullptr;
2784 if ((IsReplaceAllSprm(nSpId) || bExpand) && pStartData)
2786 sal_uInt32 nCurr = pDataSt->Tell();
2787 sal_uInt32 nPos = SVBT32ToUInt32(pStartData);
2788 sal_uInt16 nLen(0);
2790 bool bOk = checkSeek(*pDataSt, nPos);
2791 if (bOk)
2793 pDataSt->ReadUInt16( nLen );
2794 bOk = nLen <= pDataSt->remainingSize();
2797 if (bOk)
2799 const sal_uInt16 nOrigLen = bExpand ? aEntry.mnLen : 0;
2800 sal_uInt8 *pOrigData = bExpand ? aEntry.mpData : nullptr;
2802 aEntry.mnLen = nLen;
2803 aEntry.mpData =
2804 new sal_uInt8[aEntry.mnLen + nOrigLen];
2805 aEntry.mbMustDelete = true;
2806 aEntry.mnLen =
2807 pDataSt->ReadBytes(aEntry.mpData, aEntry.mnLen);
2809 pDataSt->Seek( nCurr );
2811 if (pOrigData)
2813 memcpy(aEntry.mpData + aEntry.mnLen,
2814 pOrigData, nOrigLen);
2815 aEntry.mnLen = aEntry.mnLen + nOrigLen;
2820 break;
2821 default:
2822 OSL_FAIL("sweet god, what have you done!");
2823 break;
2827 maEntries.push_back(aEntry);
2829 #ifdef DEBUGSPRMREADER
2831 sal_Int32 nLen;
2832 sal_uInt8* pSprms = GetLenAndIStdAndSprms( nLen );
2833 WW8SprmIter aIter(pSprms, nLen, maSprmParser);
2834 while (aIter.GetSprms())
2836 fprintf(stderr, "id is %x\n", aIter.GetCurrentId());
2837 aIter.advance();
2840 #endif
2843 //one more FC than grrpl entries
2844 maEntries.emplace_back(Get_Long(pStart));
2846 //we expect them sorted, but it appears possible for them to arrive unsorted
2847 std::stable_sort(maEntries.begin(), maEntries.end());
2849 mnIdx = 0;
2851 if (nStartFc >= 0)
2852 SeekPos(nStartFc);
2854 pSt->Seek(nOldPos);
2857 WW8PLCFx_Fc_FKP::WW8Fkp::Entry::Entry(const Entry &rEntry)
2858 : mnFC(rEntry.mnFC), mnLen(rEntry.mnLen), mnIStd(rEntry.mnIStd),
2859 mbMustDelete(rEntry.mbMustDelete)
2861 if (mbMustDelete)
2863 mpData = new sal_uInt8[mnLen];
2864 memcpy(mpData, rEntry.mpData, mnLen);
2866 else
2867 mpData = rEntry.mpData;
2870 WW8PLCFx_Fc_FKP::WW8Fkp::Entry&
2871 WW8PLCFx_Fc_FKP::WW8Fkp::Entry::operator=(const Entry &rEntry)
2873 if (this == &rEntry)
2874 return *this;
2876 if (mbMustDelete)
2877 delete[] mpData;
2879 mnFC = rEntry.mnFC;
2880 mnLen = rEntry.mnLen;
2881 mnIStd = rEntry.mnIStd;
2882 mbMustDelete = rEntry.mbMustDelete;
2884 if (rEntry.mbMustDelete)
2886 mpData = new sal_uInt8[mnLen];
2887 memcpy(mpData, rEntry.mpData, mnLen);
2889 else
2890 mpData = rEntry.mpData;
2892 return *this;
2895 WW8PLCFx_Fc_FKP::WW8Fkp::Entry::~Entry()
2897 if (mbMustDelete)
2898 delete[] mpData;
2901 void WW8PLCFx_Fc_FKP::WW8Fkp::Reset(WW8_FC nFc)
2903 SetIdx(0);
2904 if (nFc >= 0)
2905 SeekPos(nFc);
2908 bool WW8PLCFx_Fc_FKP::WW8Fkp::SeekPos(WW8_FC nFc)
2910 if (nFc < maEntries[0].mnFC)
2912 mnIdx = 0;
2913 return false; // not found: nPos less than smallest entry
2916 // Search from beginning?
2917 if ((mnIdx < 1) || (nFc < maEntries[mnIdx - 1].mnFC))
2918 mnIdx = 1;
2920 sal_uInt8 nI = mnIdx;
2921 sal_uInt8 nEnd = mnIMax;
2923 for(sal_uInt8 n = (1==mnIdx ? 1 : 2); n; --n )
2925 for( ; nI <=nEnd; ++nI)
2926 { // search with an index that is incremented by 1
2927 if (nFc < maEntries[nI].mnFC)
2928 { // found position
2929 mnIdx = nI - 1; // nI - 1 is the correct index
2930 return true; // done
2933 nI = 1;
2934 nEnd = mnIdx-1;
2936 mnIdx = mnIMax; // not found, greater than all entries
2937 return false;
2940 sal_uInt8* WW8PLCFx_Fc_FKP::WW8Fkp::Get(WW8_FC& rStart, WW8_FC& rEnd, sal_Int32& rLen)
2941 const
2943 rLen = 0;
2945 if (mnIdx >= mnIMax)
2947 rStart = WW8_FC_MAX;
2948 return nullptr;
2951 rStart = maEntries[mnIdx].mnFC;
2952 rEnd = maEntries[mnIdx + 1].mnFC;
2954 sal_uInt8* pSprms = GetLenAndIStdAndSprms( rLen );
2955 return pSprms;
2958 void WW8PLCFx_Fc_FKP::WW8Fkp::SetIdx(sal_uInt8 nI)
2960 if (nI < mnIMax)
2962 mnIdx = nI;
2966 sal_uInt8* WW8PLCFx_Fc_FKP::WW8Fkp::GetLenAndIStdAndSprms(sal_Int32& rLen) const
2968 rLen = maEntries[mnIdx].mnLen;
2969 return maEntries[mnIdx].mpData;
2972 SprmResult WW8PLCFx_Fc_FKP::WW8Fkp::HasSprm( sal_uInt16 nId, bool bFindFirst )
2974 if (mnIdx >= mnIMax)
2975 return SprmResult();
2977 sal_Int32 nLen;
2978 sal_uInt8* pSprms = GetLenAndIStdAndSprms( nLen );
2980 WW8SprmIter aIter(pSprms, nLen, maSprmParser);
2981 return aIter.FindSprm(nId, bFindFirst);
2984 void WW8PLCFx_Fc_FKP::WW8Fkp::HasSprm(sal_uInt16 nId,
2985 std::vector<SprmResult> &rResult)
2987 if (mnIdx >= mnIMax)
2988 return;
2990 sal_Int32 nLen;
2991 sal_uInt8* pSprms = GetLenAndIStdAndSprms( nLen );
2993 WW8SprmIter aIter(pSprms, nLen, maSprmParser);
2995 while(aIter.GetSprms())
2997 if (aIter.GetCurrentId() == nId)
2999 sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId);
3000 sal_Int32 nL = maSprmParser.GetSprmSize(nId, aIter.GetSprms(), aIter.GetRemLen());
3001 rResult.emplace_back(aIter.GetCurrentParams(), nL - nFixedLen);
3003 aIter.advance();
3007 ww::WordVersion WW8PLCFx::GetFIBVersion() const
3009 return mrFib.GetFIBVersion();
3012 void WW8PLCFx::GetSprms( WW8PLCFxDesc* p )
3014 OSL_ENSURE( false, "Called wrong GetSprms" );
3015 p->nStartPos = p->nEndPos = WW8_CP_MAX;
3016 p->pMemPos = nullptr;
3017 p->nSprmsLen = 0;
3018 p->bRealLineEnd = false;
3021 tools::Long WW8PLCFx::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
3023 OSL_ENSURE( false, "Called wrong GetNoSprms" );
3024 rStart = rEnd = WW8_CP_MAX;
3025 rLen = 0;
3026 return 0;
3029 // ...Idx2: Default: ignore
3030 sal_uInt32 WW8PLCFx::GetIdx2() const
3032 return 0;
3035 void WW8PLCFx::SetIdx2(sal_uInt32)
3039 namespace {
3041 class SamePos
3043 private:
3044 tools::Long mnPo;
3045 public:
3046 explicit SamePos(tools::Long nPo) : mnPo(nPo) {}
3047 bool operator()(const std::unique_ptr<WW8PLCFx_Fc_FKP::WW8Fkp>& pFkp)
3048 {return mnPo == pFkp->GetFilePos();}
3053 bool WW8PLCFx_Fc_FKP::NewFkp()
3055 WW8_CP nPLCFStart, nPLCFEnd;
3056 void* pPage;
3058 static const int WW8FkpSizeTabVer2[ PLCF_END ] =
3060 1, 1, 0 /*, 0, 0, 0*/
3062 static const int WW8FkpSizeTabVer6[ PLCF_END ] =
3064 1, 7, 0 /*, 0, 0, 0*/
3066 static const int WW8FkpSizeTabVer8[ PLCF_END ] =
3068 1, 13, 0 /*, 0, 0, 0*/
3070 const int* pFkpSizeTab;
3072 switch (GetFIBVersion())
3074 case ww::eWW1:
3075 case ww::eWW2:
3076 pFkpSizeTab = WW8FkpSizeTabVer2;
3077 break;
3078 case ww::eWW6:
3079 case ww::eWW7:
3080 pFkpSizeTab = WW8FkpSizeTabVer6;
3081 break;
3082 case ww::eWW8:
3083 pFkpSizeTab = WW8FkpSizeTabVer8;
3084 break;
3085 default:
3086 // program error!
3087 OSL_ENSURE( false, "nVersion not implemented!" );
3088 return false;
3091 if (!pPLCF->Get( nPLCFStart, nPLCFEnd, pPage ))
3093 pFkp = nullptr;
3094 return false; // PLCF completely processed
3096 pPLCF->advance();
3097 tools::Long nPo = SVBT16ToUInt16( static_cast<sal_uInt8 *>(pPage) );
3098 nPo <<= 9; // shift as LONG
3100 tools::Long nCurrentFkpFilePos = pFkp ? pFkp->GetFilePos() : -1;
3101 if (nCurrentFkpFilePos == nPo)
3102 pFkp->Reset(GetStartFc());
3103 else
3105 auto aIter =
3106 std::find_if(maFkpCache.begin(), maFkpCache.end(), SamePos(nPo));
3107 if (aIter != maFkpCache.end())
3109 pFkp = aIter->get();
3110 pFkp->Reset(GetStartFc());
3112 else
3114 pFkp = new WW8Fkp(GetFIB(), pFKPStrm, pDataStrm, nPo,
3115 pFkpSizeTab[ ePLCF ], ePLCF, GetStartFc());
3116 maFkpCache.push_back(std::unique_ptr<WW8Fkp>(pFkp));
3118 if (maFkpCache.size() > eMaxCache)
3120 WW8Fkp* pCachedFkp = maFkpCache.front().get();
3121 if (!pCachedFkp->IsMustRemainCache())
3123 maFkpCache.pop_front();
3129 SetStartFc( -1 ); // only the first time
3130 return true;
3133 WW8PLCFx_Fc_FKP::WW8PLCFx_Fc_FKP(SvStream* pSt, SvStream* pTableSt,
3134 SvStream* pDataSt, const WW8Fib& rFib, ePLCFT ePl, WW8_FC nStartFcL)
3135 : WW8PLCFx(rFib, true), pFKPStrm(pSt), pDataStrm(pDataSt)
3136 , pFkp(nullptr), ePLCF(ePl)
3138 SetStartFc(nStartFcL);
3139 tools::Long nLenStruct = (8 > rFib.m_nVersion) ? 2 : 4;
3140 if (ePl == CHP)
3142 pPLCF.reset(new WW8PLCF(*pTableSt, rFib.m_fcPlcfbteChpx, rFib.m_lcbPlcfbteChpx,
3143 nLenStruct, GetStartFc(), rFib.m_pnChpFirst, rFib.m_cpnBteChp));
3145 else
3147 pPLCF.reset(new WW8PLCF(*pTableSt, rFib.m_fcPlcfbtePapx, rFib.m_lcbPlcfbtePapx,
3148 nLenStruct, GetStartFc(), rFib.m_pnPapFirst, rFib.m_cpnBtePap));
3152 WW8PLCFx_Fc_FKP::~WW8PLCFx_Fc_FKP()
3154 maFkpCache.clear();
3155 pPLCF.reset();
3156 pPCDAttrs.reset();
3159 sal_uInt32 WW8PLCFx_Fc_FKP::GetIdx() const
3161 sal_uInt32 u = pPLCF->GetIdx() << 8;
3162 if (pFkp)
3163 u |= pFkp->GetIdx();
3164 return u;
3167 void WW8PLCFx_Fc_FKP::SetIdx(sal_uInt32 nIdx)
3169 if( !( nIdx & 0xffffff00L ) )
3171 pPLCF->SetIdx( nIdx >> 8 );
3172 pFkp = nullptr;
3174 else
3175 { // there was a Fkp
3176 // Set PLCF one position back to retrieve the address of the Fkp
3177 pPLCF->SetIdx( ( nIdx >> 8 ) - 1 );
3178 if (NewFkp()) // read Fkp again
3180 sal_uInt8 nFkpIdx = static_cast<sal_uInt8>(nIdx & 0xff);
3181 pFkp->SetIdx(nFkpIdx); // set Fkp-Pos again
3186 bool WW8PLCFx_Fc_FKP::SeekPos(WW8_FC nFcPos)
3188 // StartPos for next Where()
3189 SetStartFc( nFcPos );
3191 // find StartPos for next pPLCF->Get()
3192 bool bRet = pPLCF->SeekPos(nFcPos);
3194 // make FKP invalid?
3195 WW8_CP nPLCFStart, nPLCFEnd;
3196 void* pPage;
3197 if( pFkp && pPLCF->Get( nPLCFStart, nPLCFEnd, pPage ) )
3199 tools::Long nPo = SVBT16ToUInt16( static_cast<sal_uInt8 *>(pPage) );
3200 nPo <<= 9; // shift as LONG
3201 if (nPo != pFkp->GetFilePos())
3202 pFkp = nullptr;
3203 else
3204 pFkp->SeekPos( nFcPos );
3206 return bRet;
3209 WW8_FC WW8PLCFx_Fc_FKP::Where()
3211 if( !pFkp && !NewFkp() )
3212 return WW8_FC_MAX;
3213 WW8_FC nP = pFkp ? pFkp->Where() : WW8_FC_MAX;
3214 if( nP != WW8_FC_MAX )
3215 return nP;
3217 pFkp = nullptr; // FKP finished -> get new
3218 return Where(); // easiest way: do it recursively
3221 sal_uInt8* WW8PLCFx_Fc_FKP::GetSprmsAndPos(WW8_FC& rStart, WW8_FC& rEnd, sal_Int32& rLen)
3223 rLen = 0; // Default
3224 rStart = rEnd = WW8_FC_MAX;
3226 if( !pFkp ) // Fkp not there ?
3228 if( !NewFkp() )
3229 return nullptr;
3232 sal_uInt8* pPos = pFkp ? pFkp->Get( rStart, rEnd, rLen ) : nullptr;
3233 if( rStart == WW8_FC_MAX ) //Not found
3234 return nullptr;
3235 return pPos;
3238 void WW8PLCFx_Fc_FKP::advance()
3240 if( !pFkp && !NewFkp() )
3241 return;
3243 if (!pFkp)
3244 return;
3246 pFkp->advance();
3247 if( pFkp->Where() == WW8_FC_MAX )
3248 (void)NewFkp();
3251 sal_uInt16 WW8PLCFx_Fc_FKP::GetIstd() const
3253 return pFkp ? pFkp->GetIstd() : 0xFFFF;
3256 void WW8PLCFx_Fc_FKP::GetPCDSprms( WW8PLCFxDesc& rDesc )
3258 rDesc.pMemPos = nullptr;
3259 rDesc.nSprmsLen = 0;
3260 if( pPCDAttrs )
3262 if( !pFkp )
3264 OSL_FAIL("+Problem: GetPCDSprms: NewFkp necessary (not possible!)" );
3265 if( !NewFkp() )
3266 return;
3268 pPCDAttrs->GetSprms(&rDesc);
3272 SprmResult WW8PLCFx_Fc_FKP::HasSprm(sal_uInt16 nId, bool bFindFirst)
3274 // const would be nicer, but for that, NewFkp() would need to be replaced or eliminated
3275 if( !pFkp )
3277 OSL_FAIL( "+Motz: HasSprm: NewFkp needed ( no const possible )" );
3278 // happens in BugDoc 31722
3279 if( !NewFkp() )
3280 return SprmResult();
3283 if (!pFkp)
3284 return SprmResult();
3286 SprmResult aRes = pFkp->HasSprm(nId, bFindFirst);
3288 if (!aRes.pSprm)
3290 WW8PLCFxDesc aDesc;
3291 GetPCDSprms( aDesc );
3293 if (aDesc.pMemPos)
3295 WW8SprmIter aIter(aDesc.pMemPos, aDesc.nSprmsLen,
3296 pFkp->GetSprmParser());
3297 aRes = aIter.FindSprm(nId, bFindFirst);
3301 return aRes;
3304 void WW8PLCFx_Fc_FKP::HasSprm(sal_uInt16 nId, std::vector<SprmResult> &rResult)
3306 // const would be nicer, but for that, NewFkp() would need to be replaced or eliminated
3307 if (!pFkp)
3309 OSL_FAIL( "+Motz: HasSprm: NewFkp needed ( no const possible )" );
3310 // happens in BugDoc 31722
3311 if( !NewFkp() )
3312 return;
3315 if (!pFkp)
3316 return;
3318 pFkp->HasSprm(nId, rResult);
3320 WW8PLCFxDesc aDesc;
3321 GetPCDSprms( aDesc );
3323 if (!aDesc.pMemPos)
3324 return;
3326 const wwSprmParser &rSprmParser = pFkp->GetSprmParser();
3327 WW8SprmIter aIter(aDesc.pMemPos, aDesc.nSprmsLen, rSprmParser);
3328 while(aIter.GetSprms())
3330 if (aIter.GetCurrentId() == nId)
3332 sal_Int32 nFixedLen = rSprmParser.DistanceToData(nId);
3333 sal_Int32 nL = rSprmParser.GetSprmSize(nId, aIter.GetSprms(), aIter.GetRemLen());
3334 rResult.emplace_back(aIter.GetCurrentParams(), nL - nFixedLen);
3336 aIter.advance();
3340 WW8PLCFx_Cp_FKP::WW8PLCFx_Cp_FKP( SvStream* pSt, SvStream* pTableSt,
3341 SvStream* pDataSt, const WW8ScannerBase& rBase, ePLCFT ePl )
3342 : WW8PLCFx_Fc_FKP(pSt, pTableSt, pDataSt, *rBase.m_pWw8Fib, ePl,
3343 rBase.WW8Cp2Fc(0)), rSBase(rBase), nAttrStart(-1), nAttrEnd(-1),
3344 bLineEnd(false),
3345 bComplex( (7 < rBase.m_pWw8Fib->m_nVersion) || rBase.m_pWw8Fib->m_fComplex )
3347 ResetAttrStartEnd();
3349 if (rSBase.m_pPiecePLCF)
3350 pPcd.reset( new WW8PLCFx_PCD(GetFIB(), rBase.m_pPiecePLCF.get(), 0, IsSevenMinus(GetFIBVersion())) );
3353 Make a copy of the piece attributes for so that the calls to HasSprm on a
3354 Fc_FKP will be able to take into account the current piece attributes,
3355 despite the fact that such attributes can only be found through a cp based
3356 mechanism.
3358 if (pPcd)
3360 pPCDAttrs.reset( rSBase.m_pPLCFx_PCDAttrs ? new WW8PLCFx_PCDAttrs(
3361 *rSBase.m_pWw8Fib, pPcd.get(), &rSBase) : nullptr);
3364 pPieceIter = rSBase.m_pPieceIter.get();
3367 WW8PLCFx_Cp_FKP::~WW8PLCFx_Cp_FKP()
3371 void WW8PLCFx_Cp_FKP::ResetAttrStartEnd()
3373 nAttrStart = -1;
3374 nAttrEnd = -1;
3375 bLineEnd = false;
3378 sal_uInt32 WW8PLCFx_Cp_FKP::GetPCDIdx() const
3380 return pPcd ? pPcd->GetIdx() : 0;
3383 bool WW8PLCFx_Cp_FKP::SeekPos(WW8_CP nCpPos)
3385 if( pPcd ) // Complex
3387 if( !pPcd->SeekPos( nCpPos ) ) // set piece
3388 return false;
3389 if (pPCDAttrs && !pPCDAttrs->GetIter()->SeekPos(nCpPos))
3390 return false;
3391 return WW8PLCFx_Fc_FKP::SeekPos(pPcd->CurrentPieceStartCp2Fc(nCpPos));
3393 // NO piece table !!!
3394 return WW8PLCFx_Fc_FKP::SeekPos( rSBase.WW8Cp2Fc(nCpPos) );
3397 WW8_CP WW8PLCFx_Cp_FKP::Where()
3399 WW8_FC nFc = WW8PLCFx_Fc_FKP::Where();
3400 if( pPcd )
3401 return pPcd->CurrentPieceStartFc2Cp( nFc ); // identify piece
3402 return rSBase.WW8Fc2Cp( nFc ); // NO piece table !!!
3405 void WW8PLCFx_Cp_FKP::GetSprms(WW8PLCFxDesc* p)
3407 WW8_CP nOrigCp = p->nStartPos;
3409 if (!GetDirty()) //Normal case
3411 p->pMemPos = WW8PLCFx_Fc_FKP::GetSprmsAndPos(p->nStartPos, p->nEndPos,
3412 p->nSprmsLen);
3414 else
3417 For the odd case where we have a location in a fastsaved file which
3418 does not have an entry in the FKP, perhaps its para end is in the next
3419 piece, or perhaps the cp just doesn't exist at all in this document.
3420 AdvSprm doesn't know so it sets the PLCF as dirty and we figure out
3421 in this method what the situation is
3423 It doesn't exist then the piece iterator will not be able to find it.
3424 Otherwise our cool fastsave algorithm can be brought to bear on the
3425 problem.
3427 if( !pPieceIter )
3428 return;
3429 const sal_uInt32 nOldPos = pPieceIter->GetIdx();
3430 bool bOk = pPieceIter->SeekPos(nOrigCp);
3431 pPieceIter->SetIdx(nOldPos);
3432 if (!bOk)
3433 return;
3436 if( pPcd ) // piece table available
3438 // Init ( no ++ called, yet )
3439 if( (nAttrStart > nAttrEnd) || (nAttrStart == -1) )
3441 p->bRealLineEnd = (ePLCF == PAP);
3443 if ( ((ePLCF == PAP ) || (ePLCF == CHP)) && (nOrigCp != WW8_CP_MAX) )
3445 bool bIsUnicode=false;
3447 To find the end of a paragraph for a character in a
3448 complex format file.
3450 It is necessary to know the piece that contains the
3451 character and the FC assigned to the character.
3454 //We set the piece iterator to the piece that contains the
3455 //character, now we have the correct piece for this character
3456 sal_uInt32 nOldPos = pPieceIter->GetIdx();
3457 p->nStartPos = nOrigCp;
3458 pPieceIter->SeekPos( p->nStartPos);
3460 //This is the FC assigned to the character, but we already
3461 //have the result of the next stage, so we can skip this step
3462 //WW8_FC nStartFc = rSBase.WW8Cp2Fc(p->nStartPos, &bIsUnicode);
3465 Using the FC of the character, first search the FKP that
3466 describes the character to find the smallest FC in the rgfc
3467 that is larger than the character FC.
3469 //But the search has already been done, the next largest FC is
3470 //p->nEndPos.
3471 WW8_FC nOldEndPos = p->nEndPos;
3474 If the FC found in the FKP is less than or equal to the limit
3475 FC of the piece, the end of the paragraph that contains the
3476 character is at the FKP FC minus 1.
3478 WW8_CP nCpStart, nCpEnd;
3479 void* pData=nullptr;
3480 bool bOk = pPieceIter->Get(nCpStart, nCpEnd, pData);
3482 if (!bOk)
3484 pPieceIter->SetIdx(nOldPos);
3485 return;
3488 WW8_FC nLimitFC = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
3489 WW8_FC nBeginLimitFC = nLimitFC;
3490 if (IsEightPlus(GetFIBVersion()))
3492 nBeginLimitFC =
3493 WW8PLCFx_PCD::TransformPieceAddress(nLimitFC,
3494 bIsUnicode);
3497 WW8_CP nCpLen;
3498 bool bFail = o3tl::checked_sub(nCpEnd, nCpStart, nCpLen);
3499 if (bFail)
3501 SAL_WARN("sw.ww8", "broken offset, ignoring");
3502 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3503 pPieceIter->SetIdx(nOldPos);
3504 return;
3507 if (bIsUnicode)
3509 bFail = o3tl::checked_multiply<WW8_CP>(nCpLen, 2, nCpLen);
3510 if (bFail)
3512 SAL_WARN("sw.ww8", "broken offset, ignoring");
3513 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3514 pPieceIter->SetIdx(nOldPos);
3515 return;
3519 bFail = o3tl::checked_add(nBeginLimitFC, nCpLen, nLimitFC);
3520 if (bFail)
3522 SAL_WARN("sw.ww8", "broken offset, ignoring");
3523 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3524 pPieceIter->SetIdx(nOldPos);
3525 return;
3528 if (nOldEndPos <= nLimitFC)
3530 bFail = o3tl::checked_sub(nLimitFC, nOldEndPos, nCpLen);
3531 if (bFail)
3533 SAL_WARN("sw.ww8", "broken offset, ignoring");
3534 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3535 pPieceIter->SetIdx(nOldPos);
3536 return;
3539 nCpLen /= (bIsUnicode ? 2 : 1);
3541 bFail = o3tl::checked_sub(nCpEnd, nCpLen, p->nEndPos);
3542 if (bFail)
3544 SAL_WARN("sw.ww8", "broken offset, ignoring");
3545 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3546 pPieceIter->SetIdx(nOldPos);
3547 return;
3550 else
3552 if (ePLCF == CHP)
3553 p->nEndPos = nCpEnd;
3554 else
3557 If the FKP FC that was found was greater than the FC
3558 of the end of the piece, scan piece by piece toward
3559 the end of the document until a piece is found that
3560 contains a paragraph end mark.
3564 It's possible to check if a piece contains a paragraph
3565 mark by using the FC of the beginning of the piece to
3566 search in the FKPs for the smallest FC in the FKP rgfc
3567 that is greater than the FC of the beginning of the
3568 piece. If the FC found is less than or equal to the
3569 limit FC of the piece, then the character that ends
3570 the paragraph is the character immediately before the
3571 FKP fc
3574 pPieceIter->advance();
3576 for (;pPieceIter->GetIdx() < pPieceIter->GetIMax();
3577 pPieceIter->advance())
3579 if( !pPieceIter->Get( nCpStart, nCpEnd, pData ) )
3581 OSL_ENSURE( false, "piece iter broken!" );
3582 break;
3584 bIsUnicode = false;
3585 sal_Int32 nFcStart=SVBT32ToUInt32(static_cast<WW8_PCD*>(pData)->fc);
3587 if (IsEightPlus(GetFIBVersion()))
3589 nFcStart =
3590 WW8PLCFx_PCD::TransformPieceAddress(
3591 nFcStart,bIsUnicode );
3594 bFail = o3tl::checked_sub(nCpEnd, nCpStart, nCpLen);
3595 if (bFail)
3597 SAL_WARN("sw.ww8", "broken offset, ignoring");
3598 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3599 continue;
3602 if (bIsUnicode)
3604 bFail = o3tl::checked_multiply<WW8_CP>(nCpLen, 2, nCpLen);
3605 if (bFail)
3607 SAL_WARN("sw.ww8", "broken offset, ignoring");
3608 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3609 continue;
3613 bFail = o3tl::checked_add(nFcStart, nCpLen, nLimitFC);
3614 if (bFail)
3616 SAL_WARN("sw.ww8", "broken offset, ignoring");
3617 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3618 continue;
3621 //if it doesn't exist, skip it
3622 if (!SeekPos(nCpStart))
3623 continue;
3625 WW8_FC nOne,nSmallest;
3626 p->pMemPos = WW8PLCFx_Fc_FKP::GetSprmsAndPos(nOne,
3627 nSmallest, p->nSprmsLen);
3629 if (nSmallest <= nLimitFC)
3631 WW8_CP nCpDiff;
3632 bFail = o3tl::checked_sub(nLimitFC, nSmallest, nCpDiff);
3633 if (bFail)
3635 SAL_WARN("sw.ww8", "broken offset, ignoring");
3636 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3637 continue;
3639 if (bIsUnicode)
3640 nCpDiff /= 2;
3642 WW8_CP nEndPos;
3643 bFail = o3tl::checked_sub(nCpEnd, nCpDiff, nEndPos);
3644 if (bFail)
3646 SAL_WARN("sw.ww8", "broken offset, ignoring");
3647 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3648 continue;
3651 OSL_ENSURE(nEndPos >= p->nStartPos, "EndPos before StartPos");
3653 if (nEndPos >= p->nStartPos)
3654 p->nEndPos = nEndPos;
3656 break;
3661 pPieceIter->SetIdx( nOldPos );
3663 else
3664 WW8PLCFx_PCD::CurrentPieceFc2Cp( p->nStartPos, p->nEndPos,&rSBase );
3666 else
3668 p->nStartPos = nAttrStart;
3669 p->nEndPos = nAttrEnd;
3670 p->bRealLineEnd = bLineEnd;
3673 else // NO piece table !!!
3675 p->nStartPos = rSBase.WW8Fc2Cp( p->nStartPos );
3676 p->nEndPos = rSBase.WW8Fc2Cp( p->nEndPos );
3677 p->bRealLineEnd = ePLCF == PAP;
3681 void WW8PLCFx_Cp_FKP::advance()
3683 WW8PLCFx_Fc_FKP::advance();
3684 // !pPcd: emergency break
3685 if ( !bComplex || !pPcd )
3686 return;
3688 if( GetPCDIdx() >= pPcd->GetIMax() ) // End of PLCF
3690 nAttrStart = nAttrEnd = WW8_CP_MAX;
3691 return;
3694 sal_Int32 nFkpLen; // Fkp entry
3695 // get Fkp entry
3696 WW8PLCFx_Fc_FKP::GetSprmsAndPos(nAttrStart, nAttrEnd, nFkpLen);
3698 WW8PLCFx_PCD::CurrentPieceFc2Cp( nAttrStart, nAttrEnd, &rSBase );
3699 bLineEnd = (ePLCF == PAP);
3702 WW8PLCFx_SEPX::WW8PLCFx_SEPX(SvStream* pSt, SvStream* pTableSt,
3703 const WW8Fib& rFib, WW8_CP nStartCp)
3704 : WW8PLCFx(rFib, true), maSprmParser(rFib),
3705 pStrm(pSt), nArrMax(256), nSprmSiz(0)
3707 if (rFib.m_lcbPlcfsed)
3708 pPLCF.reset( new WW8PLCF(*pTableSt, rFib.m_fcPlcfsed, rFib.m_lcbPlcfsed,
3709 GetFIBVersion() <= ww::eWW2 ? 6 : 12, nStartCp) );
3711 pSprms.reset( new sal_uInt8[nArrMax] ); // maximum length
3714 WW8PLCFx_SEPX::~WW8PLCFx_SEPX()
3718 sal_uInt32 WW8PLCFx_SEPX::GetIdx() const
3720 return pPLCF ? pPLCF->GetIdx() : 0;
3723 void WW8PLCFx_SEPX::SetIdx(sal_uInt32 nIdx)
3725 if( pPLCF ) pPLCF->SetIdx( nIdx );
3728 bool WW8PLCFx_SEPX::SeekPos(WW8_CP nCpPos)
3730 return pPLCF && pPLCF->SeekPos( nCpPos );
3733 WW8_CP WW8PLCFx_SEPX::Where()
3735 return pPLCF ? pPLCF->Where() : 0;
3738 void WW8PLCFx_SEPX::GetSprms(WW8PLCFxDesc* p)
3740 if( !pPLCF ) return;
3742 void* pData;
3744 p->bRealLineEnd = false;
3745 if (!pPLCF->Get( p->nStartPos, p->nEndPos, pData ))
3747 p->nStartPos = p->nEndPos = WW8_CP_MAX; // PLCF completely processed
3748 p->pMemPos = nullptr;
3749 p->nSprmsLen = 0;
3751 else
3753 sal_uInt32 nPo = SVBT32ToUInt32( static_cast<sal_uInt8*>(pData)+2 );
3754 if (nPo == 0xFFFFFFFF || !checkSeek(*pStrm, nPo))
3756 p->nStartPos = p->nEndPos = WW8_CP_MAX; // Sepx empty
3757 p->pMemPos = nullptr;
3758 p->nSprmsLen = 0;
3760 else
3762 // read len
3763 if (GetFIBVersion() <= ww::eWW2) // eWW6 ?, docs say yes, but...
3765 sal_uInt8 nSiz(0);
3766 pStrm->ReadUChar( nSiz );
3767 nSprmSiz = nSiz;
3769 else
3771 pStrm->ReadUInt16( nSprmSiz );
3774 std::size_t nRemaining = pStrm->remainingSize();
3775 if (nSprmSiz > nRemaining)
3776 nSprmSiz = nRemaining;
3778 if( nSprmSiz > nArrMax )
3779 { // does not fit
3780 nArrMax = nSprmSiz; // Get more memory
3781 pSprms.reset( new sal_uInt8[nArrMax] );
3783 nSprmSiz = pStrm->ReadBytes(pSprms.get(), nSprmSiz); // read Sprms
3785 p->nSprmsLen = nSprmSiz;
3786 p->pMemPos = pSprms.get(); // return Position
3791 void WW8PLCFx_SEPX::advance()
3793 if (pPLCF)
3794 pPLCF->advance();
3797 SprmResult WW8PLCFx_SEPX::HasSprm(sal_uInt16 nId) const
3799 return HasSprm(nId, pSprms.get(), nSprmSiz);
3802 SprmResult WW8PLCFx_SEPX::HasSprm( sal_uInt16 nId, const sal_uInt8* pOtherSprms,
3803 tools::Long nOtherSprmSiz ) const
3805 SprmResult aRet;
3806 if (pPLCF)
3808 WW8SprmIter aIter(pOtherSprms, nOtherSprmSiz, maSprmParser);
3809 aRet = aIter.FindSprm(nId, /*bFindFirst=*/true);
3811 return aRet;
3814 bool WW8PLCFx_SEPX::Find4Sprms(sal_uInt16 nId1,sal_uInt16 nId2,sal_uInt16 nId3,sal_uInt16 nId4,
3815 SprmResult& r1, SprmResult& r2, SprmResult& r3, SprmResult& r4) const
3817 if( !pPLCF )
3818 return false;
3820 bool bFound = false;
3822 sal_uInt8* pSp = pSprms.get();
3823 size_t i = 0;
3824 while (i + maSprmParser.MinSprmLen() <= nSprmSiz)
3826 // Sprm found?
3827 const sal_uInt16 nCurrentId = maSprmParser.GetSprmId(pSp);
3828 sal_Int32 nRemLen = nSprmSiz - i;
3829 const sal_Int32 x = maSprmParser.GetSprmSize(nCurrentId, pSp, nRemLen);
3830 bool bValid = x <= nRemLen;
3831 if (!bValid)
3833 SAL_WARN("sw.ww8", "sprm longer than remaining bytes, doc or parser is wrong");
3834 break;
3836 bool bOk = true;
3837 if( nCurrentId == nId1 )
3839 sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId1);
3840 r1 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3842 else if( nCurrentId == nId2 )
3844 sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId2);
3845 r2 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3847 else if( nCurrentId == nId3 )
3849 sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId3);
3850 r3 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3852 else if( nCurrentId == nId4 )
3854 sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId4);
3855 r4 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3857 else
3858 bOk = false;
3859 bFound |= bOk;
3860 // increment pointer so that it points to next SPRM
3861 i += x;
3862 pSp += x;
3864 return bFound;
3867 SprmResult WW8PLCFx_SEPX::HasSprm( sal_uInt16 nId, sal_uInt8 n2nd ) const
3869 SprmResult aRet;
3870 if (pPLCF)
3872 WW8SprmIter aIter(pSprms.get(), nSprmSiz, maSprmParser);
3873 aRet = aIter.FindSprm(nId, /*bFindFirst=*/true, &n2nd);
3875 return aRet;
3878 WW8PLCFx_SubDoc::WW8PLCFx_SubDoc(SvStream* pSt, const WW8Fib& rFib,
3879 WW8_CP nStartCp, tools::Long nFcRef, tools::Long nLenRef, tools::Long nFcText, tools::Long nLenText,
3880 tools::Long nStruct)
3881 : WW8PLCFx(rFib, true)
3883 if( nLenRef && nLenText )
3885 pRef.reset(new WW8PLCF(*pSt, nFcRef, nLenRef, nStruct, nStartCp));
3886 pText.reset(new WW8PLCF(*pSt, nFcText, nLenText, 0, nStartCp));
3890 WW8PLCFx_SubDoc::~WW8PLCFx_SubDoc()
3892 pRef.reset();
3893 pText.reset();
3896 sal_uInt32 WW8PLCFx_SubDoc::GetIdx() const
3898 // Probably pText ... no need for it
3899 if( pRef )
3900 return ( pRef->GetIdx() << 16 | pText->GetIdx() );
3901 return 0;
3904 void WW8PLCFx_SubDoc::SetIdx(sal_uInt32 nIdx)
3906 if( pRef )
3908 pRef->SetIdx( nIdx >> 16 );
3909 // Probably pText ... no need for it
3910 pText->SetIdx( nIdx & 0xFFFF );
3914 bool WW8PLCFx_SubDoc::SeekPos( WW8_CP nCpPos )
3916 return pRef && pRef->SeekPos( nCpPos );
3919 WW8_CP WW8PLCFx_SubDoc::Where()
3921 return pRef ? pRef->Where() : WW8_CP_MAX;
3924 void WW8PLCFx_SubDoc::GetSprms(WW8PLCFxDesc* p)
3926 p->nStartPos = p->nEndPos = WW8_CP_MAX;
3927 p->pMemPos = nullptr;
3928 p->nSprmsLen = 0;
3929 p->bRealLineEnd = false;
3931 if (!pRef)
3932 return;
3934 sal_uInt32 nNr = pRef->GetIdx();
3936 void *pData;
3937 WW8_CP nFoo;
3938 if (!pRef->Get(p->nStartPos, nFoo, pData))
3940 p->nEndPos = p->nStartPos = WW8_CP_MAX;
3941 return;
3944 if (o3tl::checked_add<WW8_CP>(p->nStartPos, 1, p->nEndPos))
3946 SAL_WARN("sw.ww8", "broken offset, ignoring");
3947 p->nEndPos = p->nStartPos = WW8_CP_MAX;
3948 return;
3951 if (!pText)
3952 return;
3954 pText->SetIdx(nNr);
3956 if (!pText->Get(p->nCp2OrIdx, p->nSprmsLen, pData))
3958 p->nEndPos = p->nStartPos = WW8_CP_MAX;
3959 p->nSprmsLen = 0;
3960 return;
3963 if (p->nCp2OrIdx < 0 || p->nCp2OrIdx > p->nSprmsLen)
3965 SAL_WARN("sw.ww8", "Document has invalid Cp or Idx, ignoring it");
3966 p->nEndPos = p->nStartPos = WW8_CP_MAX;
3967 p->nSprmsLen = 0;
3968 return;
3971 p->nSprmsLen -= p->nCp2OrIdx;
3974 void WW8PLCFx_SubDoc::advance()
3976 if (pRef && pText)
3978 pRef->advance();
3979 pText->advance();
3983 // fields
3984 WW8PLCFx_FLD::WW8PLCFx_FLD( SvStream* pSt, const WW8Fib& rMyFib, short nType)
3985 : WW8PLCFx(rMyFib, true), rFib(rMyFib)
3987 WW8_FC nFc;
3988 sal_Int32 nLen;
3990 switch( nType )
3992 case MAN_HDFT:
3993 nFc = rFib.m_fcPlcffldHdr;
3994 nLen = rFib.m_lcbPlcffldHdr;
3995 break;
3996 case MAN_FTN:
3997 nFc = rFib.m_fcPlcffldFootnote;
3998 nLen = rFib.m_lcbPlcffldFootnote;
3999 break;
4000 case MAN_EDN:
4001 nFc = rFib.m_fcPlcffldEdn;
4002 nLen = rFib.m_lcbPlcffldEdn;
4003 break;
4004 case MAN_AND:
4005 nFc = rFib.m_fcPlcffldAtn;
4006 nLen = rFib.m_lcbPlcffldAtn;
4007 break;
4008 case MAN_TXBX:
4009 nFc = rFib.m_fcPlcffldTxbx;
4010 nLen = rFib.m_lcbPlcffldTxbx;
4011 break;
4012 case MAN_TXBX_HDFT:
4013 nFc = rFib.m_fcPlcffldHdrTxbx;
4014 nLen = rFib.m_lcbPlcffldHdrTxbx;
4015 break;
4016 default:
4017 nFc = rFib.m_fcPlcffldMom;
4018 nLen = rFib.m_lcbPlcffldMom;
4019 break;
4022 if( nLen )
4023 pPLCF.reset( new WW8PLCFspecial( pSt, nFc, nLen, 2 ) );
4026 WW8PLCFx_FLD::~WW8PLCFx_FLD()
4030 sal_uInt32 WW8PLCFx_FLD::GetIdx() const
4032 return pPLCF ? pPLCF->GetIdx() : 0;
4035 void WW8PLCFx_FLD::SetIdx(sal_uInt32 nIdx)
4037 if( pPLCF )
4038 pPLCF->SetIdx( nIdx );
4041 bool WW8PLCFx_FLD::SeekPos(WW8_CP nCpPos)
4043 return pPLCF && pPLCF->SeekPosExact( nCpPos );
4046 WW8_CP WW8PLCFx_FLD::Where()
4048 return pPLCF ? pPLCF->Where() : WW8_CP_MAX;
4051 bool WW8PLCFx_FLD::StartPosIsFieldStart()
4053 void* pData;
4054 sal_Int32 nTest;
4055 return pPLCF && pPLCF->Get(nTest, pData) && ((static_cast<sal_uInt8*>(pData)[0] & 0x1f) == 0x13);
4058 bool WW8PLCFx_FLD::EndPosIsFieldEnd(WW8_CP& nCP)
4060 bool bRet = false;
4062 if (pPLCF)
4064 tools::Long n = pPLCF->GetIdx();
4066 pPLCF->advance();
4068 void* pData;
4069 sal_Int32 nTest;
4070 if ( pPLCF->Get(nTest, pData) && ((static_cast<sal_uInt8*>(pData)[0] & 0x1f) == 0x15) )
4072 nCP = nTest;
4073 bRet = true;
4076 pPLCF->SetIdx(n);
4079 return bRet;
4082 void WW8PLCFx_FLD::GetSprms(WW8PLCFxDesc* p)
4084 p->nStartPos = p->nEndPos = WW8_CP_MAX;
4085 p->pMemPos = nullptr;
4086 p->nSprmsLen = 0;
4087 p->bRealLineEnd = false;
4089 if (!pPLCF)
4091 p->nStartPos = WW8_CP_MAX; // there are no fields
4092 return;
4095 tools::Long n = pPLCF->GetIdx();
4097 sal_Int32 nP;
4098 void *pData;
4099 if (!pPLCF->Get(nP, pData)) // end of PLCFspecial?
4101 p->nStartPos = WW8_CP_MAX; // PLCF completely processed
4102 return;
4105 p->nStartPos = nP;
4107 pPLCF->advance();
4108 if (!pPLCF->Get(nP, pData)) // end of PLCFspecial?
4110 p->nStartPos = WW8_CP_MAX; // PLCF completely processed
4111 return;
4114 p->nEndPos = nP;
4116 pPLCF->SetIdx(n);
4118 p->nCp2OrIdx = pPLCF->GetIdx();
4121 void WW8PLCFx_FLD::advance()
4123 SAL_WARN_IF(!pPLCF, "sw.ww8", "Call without PLCFspecial field");
4124 if( !pPLCF )
4125 return;
4126 pPLCF->advance();
4129 bool WW8PLCFx_FLD::GetPara(tools::Long nIdx, WW8FieldDesc& rF)
4131 SAL_WARN_IF(!pPLCF, "sw.ww8", "Call without PLCFspecial field");
4132 if( !pPLCF )
4133 return false;
4135 tools::Long n = pPLCF->GetIdx();
4136 pPLCF->SetIdx(nIdx);
4138 bool bOk = WW8GetFieldPara(*pPLCF, rF);
4140 pPLCF->SetIdx(n);
4141 return bOk;
4144 // WW8PLCF_Book
4145 void WW8ReadSTTBF(bool bVer8, SvStream& rStrm, sal_uInt32 nStart, sal_Int32 nLen,
4146 sal_uInt16 nExtraLen, rtl_TextEncoding eCS, std::vector<OUString> &rArray,
4147 std::vector<ww::bytes>* pExtraArray, std::vector<OUString>* pValueArray)
4149 if (nLen==0) // Handle Empty STTBF
4150 return;
4152 sal_uInt64 const nOldPos = rStrm.Tell();
4153 if (checkSeek(rStrm, nStart))
4155 sal_uInt16 nLen2(0);
4156 rStrm.ReadUInt16( nLen2 ); // bVer67: total length of structure
4157 // bVer8 : count of strings
4159 if( bVer8 )
4161 sal_uInt16 nStrings(0);
4162 bool bUnicode = (0xFFFF == nLen2);
4163 if (bUnicode)
4164 rStrm.ReadUInt16( nStrings );
4165 else
4166 nStrings = nLen2;
4168 rStrm.ReadUInt16( nExtraLen );
4170 const size_t nMinStringLen = bUnicode ? sizeof(sal_uInt16) : sizeof(sal_uInt8);
4171 const size_t nMinRecordSize = nExtraLen + nMinStringLen;
4172 const size_t nMaxPossibleStrings = rStrm.remainingSize() / nMinRecordSize;
4173 if (nStrings > nMaxPossibleStrings)
4175 SAL_WARN("sw.ww8", "STTBF claims " << nStrings << " entries, but only " << nMaxPossibleStrings << " are possible");
4176 nStrings = nMaxPossibleStrings;
4179 if (nExtraLen && nStrings)
4181 const size_t nMaxExtraLen = (rStrm.remainingSize() - (nStrings * nMinStringLen)) / nStrings;
4182 if (nExtraLen > nMaxExtraLen)
4184 SAL_WARN("sw.ww8", "STTBF claims " << nMaxExtraLen << " extra len, but only " << nMaxExtraLen << " are possible");
4185 nExtraLen = nMaxExtraLen;
4189 for (sal_uInt16 i=0; i < nStrings; ++i)
4191 if (bUnicode)
4192 rArray.push_back(read_uInt16_PascalString(rStrm));
4193 else
4195 OString aTmp = read_uInt8_lenPrefixed_uInt8s_ToOString(rStrm);
4196 rArray.push_back(OStringToOUString(aTmp, eCS));
4199 // Skip the extra data
4200 if (nExtraLen)
4202 if (pExtraArray)
4204 ww::bytes extraData(nExtraLen);
4205 rStrm.ReadBytes(extraData.data(), nExtraLen);
4206 pExtraArray->push_back(extraData);
4208 else
4209 rStrm.SeekRel( nExtraLen );
4212 // read the value of the document variables, if requested.
4213 if (pValueArray)
4215 for (sal_uInt16 i=0; i < nStrings; ++i)
4217 if( bUnicode )
4218 pValueArray->push_back(read_uInt16_PascalString(rStrm));
4219 else
4221 OString aTmp = read_uInt8_lenPrefixed_uInt8s_ToOString(rStrm);
4222 pValueArray->push_back(OStringToOUString(aTmp, eCS));
4227 else
4229 if( nLen2 != nLen )
4231 OSL_ENSURE(nLen2 == nLen,
4232 "Fib length and read length are different");
4233 if (nLen > SAL_MAX_UINT16)
4234 nLen = SAL_MAX_UINT16;
4235 else if (nLen < 2 )
4236 nLen = 2;
4237 nLen2 = static_cast<sal_uInt16>(nLen);
4239 sal_uLong nRead = 0;
4240 for( nLen2 -= 2; nRead < nLen2; )
4242 sal_uInt8 nBChar(0);
4243 rStrm.ReadUChar( nBChar );
4244 ++nRead;
4245 if (nBChar)
4247 OString aTmp = read_uInt8s_ToOString(rStrm, nBChar);
4248 nRead += aTmp.getLength();
4249 rArray.push_back(OStringToOUString(aTmp, eCS));
4251 else
4252 rArray.emplace_back();
4254 // Skip the extra data (for bVer67 versions this must come from
4255 // external knowledge)
4256 if (nExtraLen)
4258 if (pExtraArray)
4260 ww::bytes extraData(nExtraLen);
4261 rStrm.ReadBytes(extraData.data(), nExtraLen);
4262 pExtraArray->push_back(extraData);
4264 else
4265 rStrm.SeekRel( nExtraLen );
4266 nRead+=nExtraLen;
4271 rStrm.Seek(nOldPos);
4274 WW8PLCFx_Book::WW8PLCFx_Book(SvStream* pTableSt, const WW8Fib& rFib)
4275 : WW8PLCFx(rFib, false), nIsEnd(0), nBookmarkId(1)
4277 if( !rFib.m_fcPlcfbkf || !rFib.m_lcbPlcfbkf || !rFib.m_fcPlcfbkl ||
4278 !rFib.m_lcbPlcfbkl || !rFib.m_fcSttbfbkmk || !rFib.m_lcbSttbfbkmk )
4280 nIMax = 0;
4282 else
4284 pBook[0].reset( new WW8PLCFspecial(pTableSt,rFib.m_fcPlcfbkf,rFib.m_lcbPlcfbkf,4) );
4286 pBook[1].reset( new WW8PLCFspecial(pTableSt,rFib.m_fcPlcfbkl,rFib.m_lcbPlcfbkl,0) );
4288 rtl_TextEncoding eStructChrSet = WW8Fib::GetFIBCharset(rFib.m_chseTables, rFib.m_lid);
4290 WW8ReadSTTBF( (7 < rFib.m_nVersion), *pTableSt, rFib.m_fcSttbfbkmk,
4291 rFib.m_lcbSttbfbkmk, 0, eStructChrSet, aBookNames );
4293 nIMax = aBookNames.size();
4295 if( pBook[0]->GetIMax() < nIMax ) // Count of Bookmarks
4296 nIMax = pBook[0]->GetIMax();
4297 if( pBook[1]->GetIMax() < nIMax )
4298 nIMax = pBook[1]->GetIMax();
4299 aStatus.resize(nIMax);
4303 WW8PLCFx_Book::~WW8PLCFx_Book()
4307 sal_uInt32 WW8PLCFx_Book::GetIdx() const
4309 return nIMax ? pBook[0]->GetIdx() : 0;
4312 void WW8PLCFx_Book::SetIdx(sal_uInt32 nI)
4314 if( nIMax )
4315 pBook[0]->SetIdx( nI );
4318 sal_uInt32 WW8PLCFx_Book::GetIdx2() const
4320 return nIMax ? ( pBook[1]->GetIdx() | ( nIsEnd ? 0x80000000 : 0 ) ) : 0;
4323 void WW8PLCFx_Book::SetIdx2(sal_uInt32 nI)
4325 if( nIMax )
4327 pBook[1]->SetIdx( nI & 0x7fffffff );
4328 nIsEnd = static_cast<sal_uInt16>( ( nI >> 31 ) & 1 ); // 0 or 1
4332 bool WW8PLCFx_Book::SeekPos(WW8_CP nCpPos)
4334 if( !pBook[0] )
4335 return false;
4337 bool bOk = pBook[0]->SeekPosExact( nCpPos );
4338 bOk &= pBook[1]->SeekPosExact( nCpPos );
4339 nIsEnd = 0;
4341 return bOk;
4344 WW8_CP WW8PLCFx_Book::Where()
4346 return pBook[nIsEnd]->Where();
4349 tools::Long WW8PLCFx_Book::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
4351 void* pData;
4352 rEnd = WW8_CP_MAX;
4353 rLen = 0;
4355 if (!pBook[0] || !pBook[1] || !nIMax || (pBook[nIsEnd]->GetIdx()) >= nIMax)
4357 rStart = rEnd = WW8_CP_MAX;
4358 return -1;
4361 (void)pBook[nIsEnd]->Get( rStart, pData ); // query position
4362 return pBook[nIsEnd]->GetIdx();
4365 // The operator ++ has a pitfall: If 2 bookmarks adjoin each other,
4366 // we should first go to the end of the first one
4367 // and then to the beginning of the second one.
4368 // But if 2 bookmarks with the length of 0 lie on top of each other,
4369 // we *must* first find the start and end of each bookmark.
4370 // The case of: ][
4371 // [...]
4372 // ][
4373 // is not solved yet.
4374 // Because I must jump back and forth in the start- and end-indices then.
4375 // This would require one more index or bitfield to remember
4376 // the already processed bookmarks.
4378 void WW8PLCFx_Book::advance()
4380 if( !(pBook[0] && pBook[1] && nIMax) )
4381 return;
4383 (*pBook[nIsEnd]).advance();
4385 sal_uLong l0 = pBook[0]->Where();
4386 sal_uLong l1 = pBook[1]->Where();
4387 if( l0 < l1 )
4388 nIsEnd = 0;
4389 else if( l1 < l0 )
4390 nIsEnd = 1;
4391 else
4393 const void * p = pBook[0]->GetData(pBook[0]->GetIdx());
4394 tools::Long nPairFor = (p == nullptr) ? 0 : SVBT16ToUInt16(*static_cast<SVBT16 const *>(p));
4395 if (nPairFor == pBook[1]->GetIdx())
4396 nIsEnd = 0;
4397 else
4398 nIsEnd = nIsEnd ? 0 : 1;
4402 tools::Long WW8PLCFx_Book::GetLen() const
4404 if( nIsEnd )
4406 OSL_ENSURE( false, "Incorrect call (1) of PLCF_Book::GetLen()" );
4407 return 0;
4409 void * p;
4410 WW8_CP nStartPos;
4411 if( !pBook[0]->Get( nStartPos, p ) )
4413 OSL_ENSURE( false, "Incorrect call (2) of PLCF_Book::GetLen()" );
4414 return 0;
4416 const sal_uInt16 nEndIdx = SVBT16ToUInt16( *static_cast<SVBT16*>(p) );
4417 tools::Long nNum = pBook[1]->GetPos( nEndIdx );
4418 nNum -= nStartPos;
4419 return nNum;
4422 void WW8PLCFx_Book::SetStatus(sal_uInt16 nIndex, eBookStatus eStat)
4424 SAL_WARN_IF(nIndex >= nIMax, "sw.ww8",
4425 "bookmark index " << nIndex << " invalid");
4426 eBookStatus eStatus = aStatus.at(nIndex);
4427 aStatus[nIndex] = static_cast<eBookStatus>(eStatus | eStat);
4430 eBookStatus WW8PLCFx_Book::GetStatus() const
4432 if (aStatus.empty())
4433 return BOOK_NORMAL;
4434 tools::Long nEndIdx = GetHandle();
4435 return ( nEndIdx < nIMax ) ? aStatus[nEndIdx] : BOOK_NORMAL;
4438 tools::Long WW8PLCFx_Book::GetHandle() const
4440 if( !pBook[0] || !pBook[1] )
4441 return LONG_MAX;
4443 if( nIsEnd )
4444 return pBook[1]->GetIdx();
4445 else
4447 if (const void* p = pBook[0]->GetData(pBook[0]->GetIdx()))
4448 return SVBT16ToUInt16( *static_cast<SVBT16 const *>(p) );
4449 else
4450 return LONG_MAX;
4454 OUString WW8PLCFx_Book::GetBookmark(tools::Long nStart,tools::Long nEnd, sal_uInt16 &nIndex)
4456 bool bFound = false;
4457 sal_uInt16 i = 0;
4458 if (pBook[0] && pBook[1])
4460 WW8_CP nStartCurrent, nEndCurrent;
4461 while (sal::static_int_cast<decltype(aBookNames)::size_type>(i) < aBookNames.size())
4463 void* p;
4464 sal_uInt16 nEndIdx;
4466 if( pBook[0]->GetData( i, nStartCurrent, p ) && p )
4467 nEndIdx = SVBT16ToUInt16( *static_cast<SVBT16*>(p) );
4468 else
4470 OSL_ENSURE( false, "Bookmark-EndIdx not readable" );
4471 nEndIdx = i;
4474 nEndCurrent = pBook[1]->GetPos( nEndIdx );
4476 if ((nStartCurrent >= nStart) && (nEndCurrent <= nEnd))
4478 nIndex = i;
4479 bFound=true;
4480 break;
4482 ++i;
4485 return bFound ? aBookNames[i] : OUString();
4488 OUString WW8PLCFx_Book::GetUniqueBookmarkName(const OUString &rSuggestedName)
4490 OUString aRet(rSuggestedName.isEmpty() ? OUString("Unnamed") : rSuggestedName);
4491 size_t i = 0;
4492 while (i < aBookNames.size())
4494 if (aRet == aBookNames[i])
4496 sal_Int32 len = aRet.getLength();
4497 sal_Int32 p = len - 1;
4498 while (p > 0 && aRet[p] >= '0' && aRet[p] <= '9')
4499 --p;
4500 aRet = aRet.subView(0, p+1) + OUString::number(nBookmarkId++);
4501 i = 0; // start search from beginning
4503 else
4504 ++i;
4506 return aRet;
4509 void WW8PLCFx_Book::MapName(OUString& rName)
4511 if( !pBook[0] || !pBook[1] )
4512 return;
4514 size_t i = 0;
4515 while (i < aBookNames.size())
4517 if (rName.equalsIgnoreAsciiCase(aBookNames[i]))
4519 rName = aBookNames[i];
4520 break;
4522 ++i;
4526 const OUString* WW8PLCFx_Book::GetName() const
4528 const OUString *pRet = nullptr;
4529 if (!nIsEnd && (pBook[0]->GetIdx() < nIMax))
4530 pRet = &(aBookNames[pBook[0]->GetIdx()]);
4531 return pRet;
4534 WW8PLCFx_AtnBook::WW8PLCFx_AtnBook(SvStream* pTableSt, const WW8Fib& rFib)
4535 : WW8PLCFx(rFib, /*bSprm=*/false),
4536 m_bIsEnd(false)
4538 if (!rFib.m_fcPlcfAtnbkf || !rFib.m_lcbPlcfAtnbkf || !rFib.m_fcPlcfAtnbkl || !rFib.m_lcbPlcfAtnbkl)
4540 nIMax = 0;
4542 else
4544 m_pBook[0].reset( new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfAtnbkf, rFib.m_lcbPlcfAtnbkf, 4) );
4545 m_pBook[1].reset( new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfAtnbkl, rFib.m_lcbPlcfAtnbkl, 0) );
4547 nIMax = m_pBook[0]->GetIMax();
4548 if (m_pBook[1]->GetIMax() < nIMax)
4549 nIMax = m_pBook[1]->GetIMax();
4553 WW8PLCFx_AtnBook::~WW8PLCFx_AtnBook()
4557 sal_uInt32 WW8PLCFx_AtnBook::GetIdx() const
4559 return nIMax ? m_pBook[0]->GetIdx() : 0;
4562 void WW8PLCFx_AtnBook::SetIdx(sal_uInt32 nI)
4564 if( nIMax )
4565 m_pBook[0]->SetIdx( nI );
4568 sal_uInt32 WW8PLCFx_AtnBook::GetIdx2() const
4570 if (nIMax)
4571 return m_pBook[1]->GetIdx() | ( m_bIsEnd ? 0x80000000 : 0 );
4572 else
4573 return 0;
4576 void WW8PLCFx_AtnBook::SetIdx2(sal_uInt32 nI)
4578 if( nIMax )
4580 m_pBook[1]->SetIdx( nI & 0x7fffffff );
4581 m_bIsEnd = static_cast<bool>(( nI >> 31 ) & 1);
4585 bool WW8PLCFx_AtnBook::SeekPos(WW8_CP nCpPos)
4587 if (!m_pBook[0])
4588 return false;
4590 bool bOk = m_pBook[0]->SeekPosExact(nCpPos);
4591 bOk &= m_pBook[1]->SeekPosExact(nCpPos);
4592 m_bIsEnd = false;
4594 return bOk;
4597 WW8_CP WW8PLCFx_AtnBook::Where()
4599 return m_pBook[static_cast<int>(m_bIsEnd)]->Where();
4602 tools::Long WW8PLCFx_AtnBook::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
4604 void* pData;
4605 rEnd = WW8_CP_MAX;
4606 rLen = 0;
4608 if (!m_pBook[0] || !m_pBook[1] || !nIMax || (m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx()) >= nIMax)
4610 rStart = rEnd = WW8_CP_MAX;
4611 return -1;
4614 (void)m_pBook[static_cast<int>(m_bIsEnd)]->Get(rStart, pData);
4615 return m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx();
4618 void WW8PLCFx_AtnBook::advance()
4620 if( !(m_pBook[0] && m_pBook[1] && nIMax) )
4621 return;
4623 (*m_pBook[static_cast<int>(m_bIsEnd)]).advance();
4625 sal_uLong l0 = m_pBook[0]->Where();
4626 sal_uLong l1 = m_pBook[1]->Where();
4627 if( l0 < l1 )
4628 m_bIsEnd = false;
4629 else if( l1 < l0 )
4630 m_bIsEnd = true;
4631 else
4633 const void * p = m_pBook[0]->GetData(m_pBook[0]->GetIdx());
4634 tools::Long nPairFor = (p == nullptr) ? 0 : SVBT16ToUInt16(*static_cast<SVBT16 const *>(p));
4635 if (nPairFor == m_pBook[1]->GetIdx())
4636 m_bIsEnd = false;
4637 else
4638 m_bIsEnd = !m_bIsEnd;
4642 tools::Long WW8PLCFx_AtnBook::getHandle() const
4644 if (!m_pBook[0] || !m_pBook[1])
4645 return LONG_MAX;
4647 if (m_bIsEnd)
4648 return m_pBook[1]->GetIdx();
4649 else
4651 if (const void* p = m_pBook[0]->GetData(m_pBook[0]->GetIdx()))
4652 return SVBT16ToUInt16(*static_cast<const SVBT16*>(p));
4653 else
4654 return LONG_MAX;
4658 bool WW8PLCFx_AtnBook::getIsEnd() const
4660 return m_bIsEnd;
4663 WW8PLCFx_FactoidBook::WW8PLCFx_FactoidBook(SvStream* pTableSt, const WW8Fib& rFib)
4664 : WW8PLCFx(rFib, /*bSprm=*/false),
4665 m_bIsEnd(false)
4667 if (!rFib.m_fcPlcfBkfFactoid || !rFib.m_lcbPlcfBkfFactoid || !rFib.m_fcPlcfBklFactoid || !rFib.m_lcbPlcfBklFactoid)
4669 m_nIMax = 0;
4671 else
4673 m_pBook[0].reset(new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfBkfFactoid, rFib.m_lcbPlcfBkfFactoid, 6));
4674 m_pBook[1].reset(new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfBklFactoid, rFib.m_lcbPlcfBklFactoid, 4));
4676 m_nIMax = m_pBook[0]->GetIMax();
4677 if (m_pBook[1]->GetIMax() < m_nIMax)
4678 m_nIMax = m_pBook[1]->GetIMax();
4682 WW8PLCFx_FactoidBook::~WW8PLCFx_FactoidBook()
4686 sal_uInt32 WW8PLCFx_FactoidBook::GetIdx() const
4688 return m_nIMax ? m_pBook[0]->GetIdx() : 0;
4691 void WW8PLCFx_FactoidBook::SetIdx(sal_uInt32 nI)
4693 if (m_nIMax)
4694 m_pBook[0]->SetIdx(nI);
4697 sal_uInt32 WW8PLCFx_FactoidBook::GetIdx2() const
4699 if (m_nIMax)
4700 return m_pBook[1]->GetIdx() | (m_bIsEnd ? 0x80000000 : 0);
4701 else
4702 return 0;
4705 void WW8PLCFx_FactoidBook::SetIdx2(sal_uInt32 nI)
4707 if (m_nIMax)
4709 m_pBook[1]->SetIdx(nI & 0x7fffffff);
4710 m_bIsEnd = static_cast<bool>((nI >> 31) & 1);
4714 bool WW8PLCFx_FactoidBook::SeekPos(WW8_CP nCpPos)
4716 if (!m_pBook[0])
4717 return false;
4719 bool bOk = m_pBook[0]->SeekPosExact(nCpPos);
4720 bOk &= m_pBook[1]->SeekPosExact(nCpPos);
4721 m_bIsEnd = false;
4723 return bOk;
4726 WW8_CP WW8PLCFx_FactoidBook::Where()
4728 return m_pBook[static_cast<int>(m_bIsEnd)]->Where();
4731 tools::Long WW8PLCFx_FactoidBook::GetNoSprms(WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen)
4733 void* pData;
4734 rEnd = WW8_CP_MAX;
4735 rLen = 0;
4737 if (!m_pBook[0] || !m_pBook[1] || !m_nIMax || (m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx()) >= m_nIMax)
4739 rStart = rEnd = WW8_CP_MAX;
4740 return -1;
4743 (void)m_pBook[static_cast<int>(m_bIsEnd)]->Get(rStart, pData);
4744 return m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx();
4747 void WW8PLCFx_FactoidBook::advance()
4749 if (!(m_pBook[0] && m_pBook[1] && m_nIMax))
4750 return;
4752 (*m_pBook[static_cast<int>(m_bIsEnd)]).advance();
4754 sal_uLong l0 = m_pBook[0]->Where();
4755 sal_uLong l1 = m_pBook[1]->Where();
4756 if (l0 < l1)
4757 m_bIsEnd = false;
4758 else if (l1 < l0)
4759 m_bIsEnd = true;
4760 else
4762 const void * p = m_pBook[0]->GetData(m_pBook[0]->GetIdx());
4763 tools::Long nPairFor = (p == nullptr) ? 0 : SVBT16ToUInt16(*static_cast<SVBT16 const *>(p));
4764 if (nPairFor == m_pBook[1]->GetIdx())
4765 m_bIsEnd = false;
4766 else
4767 m_bIsEnd = !m_bIsEnd;
4771 tools::Long WW8PLCFx_FactoidBook::getHandle() const
4773 if (!m_pBook[0] || !m_pBook[1])
4774 return LONG_MAX;
4776 if (m_bIsEnd)
4777 return m_pBook[1]->GetIdx();
4778 else
4780 if (const void* p = m_pBook[0]->GetData(m_pBook[0]->GetIdx()))
4781 return SVBT16ToUInt16(*static_cast<const SVBT16*>(p));
4782 else
4783 return LONG_MAX;
4787 bool WW8PLCFx_FactoidBook::getIsEnd() const
4789 return m_bIsEnd;
4792 // In the end of a paragraph in WW6 the attribute extends after the <CR>.
4793 // This will be reset by one character to be used with SW,
4794 // if we don't expect trouble thereby.
4795 void WW8PLCFMan::AdjustEnds( WW8PLCFxDesc& rDesc )
4797 // might be necessary to do this for pChp and/or pSep as well,
4798 // but its definitely the case for paragraphs that EndPos > StartPos
4799 // for a well formed paragraph as those always have a paragraph
4800 // <cr> in them
4801 if (&rDesc == m_pPap && rDesc.bRealLineEnd)
4803 if (rDesc.nStartPos == rDesc.nEndPos && rDesc.nEndPos != WW8_CP_MAX)
4805 SAL_WARN("sw.ww8", "WW8PLCFxDesc End same as Start, abandoning to avoid looping");
4806 rDesc.nEndPos = WW8_CP_MAX;
4810 //Store old end position for supercool new property finder that uses
4811 //cp instead of fc's as nature intended
4812 rDesc.nOrigEndPos = rDesc.nEndPos;
4813 rDesc.nOrigStartPos = rDesc.nStartPos;
4816 Normally given ^XXX{para end}^ we don't actually insert a para end
4817 character into the document, so we clip the para end property one to the
4818 left to make the para properties end when the paragraph text does. In a
4819 drawing textbox we actually do insert a para end character, so we don't
4820 clip it. Making the para end properties end after the para end char.
4822 if (GetDoingDrawTextBox())
4823 return;
4825 if ( (&rDesc == m_pPap) && rDesc.bRealLineEnd )
4827 if ( m_pPap->nEndPos != WW8_CP_MAX ) // Para adjust
4829 m_nLineEnd = m_pPap->nEndPos;// nLineEnd points *after* the <CR>
4830 m_pPap->nEndPos--; // shorten paragraph end by one character
4832 // Is there already a sep end, which points to the current paragraph end?
4833 // Then we also must shorten by one character
4834 if( m_pSep->nEndPos == m_nLineEnd )
4835 m_pSep->nEndPos--;
4838 else if (&rDesc == m_pSep)
4840 // Sep Adjust if end Char-Attr == paragraph end ...
4841 if( (rDesc.nEndPos == m_nLineEnd) && (rDesc.nEndPos > rDesc.nStartPos) )
4842 rDesc.nEndPos--; // ... then shorten by one character
4846 void WW8PLCFxDesc::ReduceByOffset()
4848 SAL_WARN_IF(WW8_CP_MAX != nStartPos && nStartPos > nEndPos, "sw.ww8",
4849 "End " << nEndPos << " before Start " << nStartPos);
4851 if( nStartPos != WW8_CP_MAX )
4854 ##516##,##517##
4855 Force the property change to happen at the beginning of this
4856 subdocument, same as in GetNewNoSprms, except that the target type is
4857 attributes attached to a piece that might span subdocument boundaries
4859 if (nCpOfs > nStartPos)
4860 nStartPos = 0;
4861 else
4862 nStartPos -= nCpOfs;
4864 if (nEndPos != WW8_CP_MAX)
4866 if (nCpOfs > nEndPos)
4868 SAL_WARN("sw.ww8", "broken subdocument piece entry");
4869 nEndPos = WW8_CP_MAX;
4871 else
4872 nEndPos -= nCpOfs;
4876 void WW8PLCFMan::GetNewSprms( WW8PLCFxDesc& rDesc )
4878 rDesc.pPLCFx->GetSprms(&rDesc);
4879 rDesc.ReduceByOffset();
4881 rDesc.bFirstSprm = true;
4882 AdjustEnds( rDesc );
4883 rDesc.nOrigSprmsLen = rDesc.nSprmsLen;
4886 void WW8PLCFMan::GetNewNoSprms( WW8PLCFxDesc& rDesc )
4888 rDesc.nCp2OrIdx = rDesc.pPLCFx->GetNoSprms(rDesc.nStartPos, rDesc.nEndPos,
4889 rDesc.nSprmsLen);
4891 SAL_WARN_IF(WW8_CP_MAX != rDesc.nStartPos && rDesc.nStartPos > rDesc.nEndPos, "sw.ww8",
4892 "End " << rDesc.nEndPos << " before Start " << rDesc.nStartPos);
4894 rDesc.ReduceByOffset();
4896 rDesc.bFirstSprm = true;
4897 rDesc.nOrigSprmsLen = rDesc.nSprmsLen;
4900 sal_uInt16 WW8PLCFMan::GetId(const WW8PLCFxDesc* p) const
4902 sal_uInt16 nId = 0; // Id = 0 for empty attributes
4904 if (p == m_pField)
4905 nId = eFLD;
4906 else if (p == m_pFootnote)
4907 nId = eFTN;
4908 else if (p == m_pEdn)
4909 nId = eEDN;
4910 else if (p == m_pAnd)
4911 nId = eAND;
4912 else if (p->nSprmsLen >= maSprmParser.MinSprmLen())
4913 nId = maSprmParser.GetSprmId(p->pMemPos);
4915 return nId;
4918 WW8PLCFMan::WW8PLCFMan(const WW8ScannerBase* pBase, ManTypes nType, tools::Long nStartCp,
4919 bool bDoingDrawTextBox)
4920 : maSprmParser(*pBase->m_pWw8Fib),
4921 m_nLineEnd(WW8_CP_MAX),
4922 mbDoingDrawTextBox(bDoingDrawTextBox)
4924 m_pWwFib = pBase->m_pWw8Fib;
4926 m_nManType = nType;
4928 if( MAN_MAINTEXT == nType )
4930 // search order of the attributes
4931 m_nPLCF = MAN_PLCF_COUNT;
4932 m_pField = &m_aD[0];
4933 m_pBkm = &m_aD[1];
4934 m_pEdn = &m_aD[2];
4935 m_pFootnote = &m_aD[3];
4936 m_pAnd = &m_aD[4];
4938 m_pPcd = pBase->m_pPLCFx_PCD ? &m_aD[5] : nullptr;
4939 //pPcdA index == pPcd index + 1
4940 m_pPcdA = pBase->m_pPLCFx_PCDAttrs ? &m_aD[6] : nullptr;
4942 m_pChp = &m_aD[7];
4943 m_pPap = &m_aD[8];
4944 m_pSep = &m_aD[9];
4945 m_pAtnBkm = &m_aD[10];
4946 m_pFactoidBkm = &m_aD[11];
4948 m_pSep->pPLCFx = pBase->m_pSepPLCF.get();
4949 m_pFootnote->pPLCFx = pBase->m_pFootnotePLCF.get();
4950 m_pEdn->pPLCFx = pBase->m_pEdnPLCF.get();
4951 m_pBkm->pPLCFx = pBase->m_pBook.get();
4952 m_pAnd->pPLCFx = pBase->m_pAndPLCF.get();
4953 m_pAtnBkm->pPLCFx = pBase->m_pAtnBook.get();
4954 m_pFactoidBkm->pPLCFx = pBase->m_pFactoidBook.get();
4957 else
4959 // search order of the attributes
4960 m_nPLCF = 7;
4961 m_pField = &m_aD[0];
4962 m_pBkm = pBase->m_pBook ? &m_aD[1] : nullptr;
4964 m_pPcd = pBase->m_pPLCFx_PCD ? &m_aD[2] : nullptr;
4965 //pPcdA index == pPcd index + 1
4966 m_pPcdA= pBase->m_pPLCFx_PCDAttrs ? &m_aD[3] : nullptr;
4968 m_pChp = &m_aD[4];
4969 m_pPap = &m_aD[5];
4970 m_pSep = &m_aD[6]; // Dummy
4972 m_pAnd = m_pAtnBkm = m_pFactoidBkm = m_pFootnote = m_pEdn = nullptr; // not used at SpezText
4975 m_pChp->pPLCFx = pBase->m_pChpPLCF.get();
4976 m_pPap->pPLCFx = pBase->m_pPapPLCF.get();
4977 if( m_pPcd )
4978 m_pPcd->pPLCFx = pBase->m_pPLCFx_PCD.get();
4979 if( m_pPcdA )
4980 m_pPcdA->pPLCFx= pBase->m_pPLCFx_PCDAttrs.get();
4981 if( m_pBkm )
4982 m_pBkm->pPLCFx = pBase->m_pBook.get();
4984 m_pMagicTables = pBase->m_pMagicTables.get();
4985 m_pSubdocs = pBase->m_pSubdocs.get();
4986 m_pExtendedAtrds = pBase->m_pExtendedAtrds.get();
4988 switch( nType ) // field initialization
4990 case MAN_HDFT:
4991 m_pField->pPLCFx = pBase->m_pFieldHdFtPLCF.get();
4992 m_pFdoa = pBase->m_pHdFtFdoa.get();
4993 m_pTxbx = pBase->m_pHdFtTxbx.get();
4994 m_pTxbxBkd = pBase->m_pHdFtTxbxBkd.get();
4995 break;
4996 case MAN_FTN:
4997 m_pField->pPLCFx = pBase->m_pFieldFootnotePLCF.get();
4998 m_pFdoa = m_pTxbx = m_pTxbxBkd = nullptr;
4999 break;
5000 case MAN_EDN:
5001 m_pField->pPLCFx = pBase->m_pFieldEdnPLCF.get();
5002 m_pFdoa = m_pTxbx = m_pTxbxBkd = nullptr;
5003 break;
5004 case MAN_AND:
5005 m_pField->pPLCFx = pBase->m_pFieldAndPLCF.get();
5006 m_pFdoa = m_pTxbx = m_pTxbxBkd = nullptr;
5007 break;
5008 case MAN_TXBX:
5009 m_pField->pPLCFx = pBase->m_pFieldTxbxPLCF.get();
5010 m_pTxbx = pBase->m_pMainTxbx.get();
5011 m_pTxbxBkd = pBase->m_pMainTxbxBkd.get();
5012 m_pFdoa = nullptr;
5013 break;
5014 case MAN_TXBX_HDFT:
5015 m_pField->pPLCFx = pBase->m_pFieldTxbxHdFtPLCF.get();
5016 m_pTxbx = pBase->m_pHdFtTxbx.get();
5017 m_pTxbxBkd = pBase->m_pHdFtTxbxBkd.get();
5018 m_pFdoa = nullptr;
5019 break;
5020 default:
5021 m_pField->pPLCFx = pBase->m_pFieldPLCF.get();
5022 m_pFdoa = pBase->m_pMainFdoa.get();
5023 m_pTxbx = pBase->m_pMainTxbx.get();
5024 m_pTxbxBkd = pBase->m_pMainTxbxBkd.get();
5025 break;
5028 WW8_CP cp = 0;
5029 m_pWwFib->GetBaseCp(nType, &cp); //TODO: check return value
5030 m_nCpO = cp;
5032 if( nStartCp || m_nCpO )
5033 SeekPos( nStartCp ); // adjust PLCFe at text StartPos
5035 // initialization to the member vars Low-Level
5036 GetChpPLCF()->ResetAttrStartEnd();
5037 GetPapPLCF()->ResetAttrStartEnd();
5038 for( sal_uInt16 i=0; i < m_nPLCF; ++i)
5040 WW8PLCFxDesc* p = &m_aD[i];
5043 ##516##,##517##
5044 For subdocuments we modify the cp of properties to be relative to
5045 the beginning of subdocuments, we should also do the same for
5046 piecetable changes, and piecetable properties, otherwise a piece
5047 change that happens in a subdocument is lost.
5049 p->nCpOfs = ( p == m_pChp || p == m_pPap || p == m_pBkm || p == m_pPcd ||
5050 p == m_pPcdA ) ? m_nCpO : 0;
5052 p->nCp2OrIdx = 0;
5053 p->bFirstSprm = false;
5054 p->pIdStack = nullptr;
5056 if ((p == m_pChp) || (p == m_pPap))
5057 p->nStartPos = p->nEndPos = nStartCp;
5058 else
5059 p->nStartPos = p->nEndPos = WW8_CP_MAX;
5062 // initialization to the member vars High-Level
5063 for( sal_uInt16 i=0; i<m_nPLCF; ++i){
5064 WW8PLCFxDesc* p = &m_aD[i];
5066 if( !p->pPLCFx )
5068 p->nStartPos = p->nEndPos = WW8_CP_MAX;
5069 continue;
5072 if( p->pPLCFx->IsSprm() )
5074 // Careful: nEndPos must be
5075 p->pIdStack = new std::stack<sal_uInt16>;
5076 if ((p == m_pChp) || (p == m_pPap))
5078 WW8_CP nTemp = p->nEndPos+p->nCpOfs;
5079 p->pMemPos = nullptr;
5080 p->nSprmsLen = 0;
5081 p->nStartPos = nTemp;
5082 if (!(*p->pPLCFx).SeekPos(p->nStartPos))
5083 p->nEndPos = p->nStartPos = WW8_CP_MAX;
5084 else
5085 GetNewSprms( *p );
5087 else
5088 GetNewSprms( *p ); // initialized at all PLCFs
5090 else if( p->pPLCFx )
5091 GetNewNoSprms( *p );
5095 WW8PLCFMan::~WW8PLCFMan()
5097 for( sal_uInt16 i=0; i<m_nPLCF; i++)
5098 delete m_aD[i].pIdStack;
5101 // 0. which attr class,
5102 // 1. if it's an attr start,
5103 // 2. CP, where is next attr change
5104 sal_uInt16 WW8PLCFMan::WhereIdx(bool *const pbStart, WW8_CP *const pPos) const
5106 OSL_ENSURE(m_nPLCF,"What the hell");
5107 WW8_CP nNext = WW8_CP_MAX; // search order:
5108 sal_uInt16 nNextIdx = m_nPLCF;// first ending found ( CHP, PAP, ( SEP ) ),
5109 bool bStart = true; // now find beginnings ( ( SEP ), PAP, CHP )
5110 const WW8PLCFxDesc* pD;
5111 for (sal_uInt16 i=0; i < m_nPLCF; ++i)
5113 pD = &m_aD[i];
5114 if (pD != m_pPcdA)
5116 if( (pD->nEndPos < nNext) && (pD->nStartPos == WW8_CP_MAX) )
5118 // otherwise start = end
5119 nNext = pD->nEndPos;
5120 nNextIdx = i;
5121 bStart = false;
5125 for (sal_uInt16 i=m_nPLCF; i > 0; --i)
5127 pD = &m_aD[i-1];
5128 if (pD != m_pPcdA && pD->nStartPos < nNext )
5130 nNext = pD->nStartPos;
5131 nNextIdx = i-1;
5132 bStart = true;
5135 if( pPos )
5136 *pPos = nNext;
5137 if( pbStart )
5138 *pbStart = bStart;
5139 return nNextIdx;
5142 // gives the CP pos of the next attr change
5143 WW8_CP WW8PLCFMan::Where() const
5145 WW8_CP l;
5146 WhereIdx(nullptr, &l);
5147 return l;
5150 void WW8PLCFMan::SeekPos( tools::Long nNewCp )
5152 m_pChp->pPLCFx->SeekPos( nNewCp + m_nCpO ); // create new attr
5153 m_pPap->pPLCFx->SeekPos( nNewCp + m_nCpO );
5154 m_pField->pPLCFx->SeekPos( nNewCp );
5155 if( m_pPcd )
5156 m_pPcd->pPLCFx->SeekPos( nNewCp + m_nCpO );
5157 if( m_pBkm )
5158 m_pBkm->pPLCFx->SeekPos( nNewCp + m_nCpO );
5161 void WW8PLCFMan::SaveAllPLCFx( WW8PLCFxSaveAll& rSave ) const
5163 sal_uInt16 n=0;
5164 if( m_pPcd )
5165 m_pPcd->Save( rSave.aS[n++] );
5166 if( m_pPcdA )
5167 m_pPcdA->Save( rSave.aS[n++] );
5169 for(sal_uInt16 i=0; i<m_nPLCF; ++i)
5170 if( m_pPcd != &m_aD[i] && m_pPcdA != &m_aD[i] )
5171 m_aD[i].Save( rSave.aS[n++] );
5174 void WW8PLCFMan::RestoreAllPLCFx( const WW8PLCFxSaveAll& rSave )
5176 sal_uInt16 n=0;
5177 if( m_pPcd )
5178 m_pPcd->Restore( rSave.aS[n++] );
5179 if( m_pPcdA )
5180 m_pPcdA->Restore( rSave.aS[n++] );
5182 for(sal_uInt16 i=0; i<m_nPLCF; ++i)
5183 if( m_pPcd != &m_aD[i] && m_pPcdA != &m_aD[i] )
5184 m_aD[i].Restore( rSave.aS[n++] );
5187 namespace
5189 bool IsSizeLegal(tools::Long nSprmLen, sal_Int32 nSprmsLen)
5191 if (nSprmLen > nSprmsLen)
5193 SAL_WARN("sw.ww8", "Short sprm, len " << nSprmLen << " claimed, max possible is " << nSprmsLen);
5194 return false;
5196 return true;
5200 bool WW8PLCFMan::IsSprmLegalForCategory(sal_uInt16 nSprmId, short nIdx) const
5202 const WW8PLCFxDesc* p = &m_aD[nIdx];
5203 if (p != m_pSep) // just check sep for now
5204 return true;
5206 bool bRet;
5207 ww::WordVersion eVersion = maSprmParser.GetFIBVersion();
5208 if (eVersion <= ww::eWW2)
5209 bRet = nSprmId >= 112 && nSprmId <= 145;
5210 else if (eVersion < ww::eWW8)
5211 bRet = nSprmId >= NS_sprm::v6::sprmSScnsPgn && nSprmId <= NS_sprm::v6::sprmSDMPaperReq;
5212 else
5215 Sprm bits: 10-12 sgc sprm group; type of sprm (PAP, CHP, etc)
5217 sgc value type of sprm
5218 1 PAP
5219 2 CHP
5220 3 PIC
5221 4 SEP
5222 5 TAP
5224 auto nSGC = ((nSprmId & 0x1C00) >> 10);
5225 bRet = nSGC == 4;
5227 SAL_WARN_IF(!bRet, "sw.ww8", "sprm, id " << nSprmId << " wrong category for section properties");
5228 return bRet;
5231 void WW8PLCFMan::GetSprmStart( short nIdx, WW8PLCFManResult* pRes ) const
5233 memset( pRes, 0, sizeof( WW8PLCFManResult ) );
5235 // verifying !!!
5237 pRes->nMemLen = 0;
5239 const WW8PLCFxDesc* p = &m_aD[nIdx];
5241 // first Sprm in a Group
5242 if( p->bFirstSprm )
5244 if( p == m_pPap )
5245 pRes->nFlags |= MAN_MASK_NEW_PAP;
5246 else if( p == m_pSep )
5247 pRes->nFlags |= MAN_MASK_NEW_SEP;
5249 pRes->pMemPos = p->pMemPos;
5250 pRes->nSprmId = GetId(p);
5251 pRes->nCp2OrIdx = p->nCp2OrIdx;
5252 if ((p == m_pFootnote) || (p == m_pEdn) || (p == m_pAnd))
5253 pRes->nMemLen = p->nSprmsLen;
5254 else if (p->nSprmsLen >= maSprmParser.MinSprmLen()) //normal
5256 // Length of actual sprm
5257 pRes->nMemLen = maSprmParser.GetSprmSize(pRes->nSprmId, pRes->pMemPos, p->nSprmsLen);
5258 if (!IsSizeLegal(pRes->nMemLen, p->nSprmsLen) || !IsSprmLegalForCategory(pRes->nSprmId, nIdx))
5260 pRes->nSprmId = 0;
5265 void WW8PLCFMan::GetSprmEnd( short nIdx, WW8PLCFManResult* pRes ) const
5267 memset( pRes, 0, sizeof( WW8PLCFManResult ) );
5269 const WW8PLCFxDesc* p = &m_aD[nIdx];
5271 if (!(p->pIdStack->empty()))
5272 pRes->nSprmId = p->pIdStack->top(); // get end position
5273 else
5275 OSL_ENSURE( false, "No Id on the Stack" );
5276 pRes->nSprmId = 0;
5280 void WW8PLCFMan::GetNoSprmStart( short nIdx, WW8PLCFManResult* pRes ) const
5282 const WW8PLCFxDesc* p = &m_aD[nIdx];
5284 pRes->nCpPos = p->nStartPos;
5285 pRes->nMemLen = p->nSprmsLen;
5286 pRes->nCp2OrIdx = p->nCp2OrIdx;
5288 if( p == m_pField )
5289 pRes->nSprmId = eFLD;
5290 else if( p == m_pFootnote )
5291 pRes->nSprmId = eFTN;
5292 else if( p == m_pEdn )
5293 pRes->nSprmId = eEDN;
5294 else if( p == m_pBkm )
5295 pRes->nSprmId = eBKN;
5296 else if (p == m_pAtnBkm)
5297 pRes->nSprmId = eATNBKN;
5298 else if (p == m_pFactoidBkm)
5299 pRes->nSprmId = eFACTOIDBKN;
5300 else if( p == m_pAnd )
5301 pRes->nSprmId = eAND;
5302 else if( p == m_pPcd )
5304 //We slave the piece table attributes to the piece table, the piece
5305 //table attribute iterator contains the sprms for this piece.
5306 GetSprmStart( nIdx+1, pRes );
5308 else
5309 pRes->nSprmId = 0; // default: not found
5312 void WW8PLCFMan::GetNoSprmEnd( short nIdx, WW8PLCFManResult* pRes ) const
5314 pRes->nMemLen = -1; // end tag
5316 if( &m_aD[nIdx] == m_pBkm )
5317 pRes->nSprmId = eBKN;
5318 else if (&m_aD[nIdx] == m_pAtnBkm)
5319 pRes->nSprmId = eATNBKN;
5320 else if (&m_aD[nIdx] == m_pFactoidBkm)
5321 pRes->nSprmId = eFACTOIDBKN;
5322 else if( &m_aD[nIdx] == m_pPcd )
5324 //We slave the piece table attributes to the piece table, the piece
5325 //table attribute iterator contains the sprms for this piece.
5326 GetSprmEnd( nIdx+1, pRes );
5328 else
5329 pRes->nSprmId = 0;
5332 void WW8PLCFMan::TransferOpenSprms(std::stack<sal_uInt16> &rStack)
5334 for (sal_uInt16 i = 0; i < m_nPLCF; ++i)
5336 WW8PLCFxDesc* p = &m_aD[i];
5337 if (!p || !p->pIdStack)
5338 continue;
5339 while (!p->pIdStack->empty())
5341 rStack.push(p->pIdStack->top());
5342 p->pIdStack->pop();
5347 void WW8PLCFMan::AdvSprm(short nIdx, bool bStart)
5349 WW8PLCFxDesc* p = &m_aD[nIdx]; // determine sprm class(!)
5351 p->bFirstSprm = false;
5352 if( bStart )
5354 const sal_uInt16 nLastId = GetId(p);
5356 const sal_uInt16 nLastAttribStarted = IsSprmLegalForCategory(nLastId, nIdx) ? nLastId : 0;
5358 p->pIdStack->push(nLastAttribStarted); // remember Id for attribute end
5360 if( p->nSprmsLen )
5361 { /*
5362 Check, if we have to process more sprm(s).
5364 if( p->pMemPos )
5366 // Length of last sprm
5367 const sal_Int32 nSprmL = maSprmParser.GetSprmSize(nLastId, p->pMemPos, p->nSprmsLen);
5369 // Reduce length of all sprms by length of last sprm
5370 p->nSprmsLen -= nSprmL;
5372 // pos of next possible sprm
5373 if (p->nSprmsLen < maSprmParser.MinSprmLen())
5375 // preventively set to 0, because the end follows!
5376 p->pMemPos = nullptr;
5377 p->nSprmsLen = 0;
5379 else
5380 p->pMemPos += nSprmL;
5382 else
5383 p->nSprmsLen = 0;
5385 if (p->nSprmsLen < maSprmParser.MinSprmLen())
5386 p->nStartPos = WW8_CP_MAX; // the ending follows
5388 else
5390 if (!(p->pIdStack->empty()))
5391 p->pIdStack->pop();
5392 if (p->pIdStack->empty())
5394 if ( (p == m_pChp) || (p == m_pPap) )
5396 p->pMemPos = nullptr;
5397 p->nSprmsLen = 0;
5398 p->nStartPos = p->nOrigEndPos+p->nCpOfs;
5401 On failed seek we have run out of sprms, probably. But if its
5402 a fastsaved file (has pPcd) then we may be just in a sprm free
5403 gap between pieces that have them, so set dirty flag in sprm
5404 finder to consider than.
5406 if (!(*p->pPLCFx).SeekPos(p->nStartPos))
5408 p->nEndPos = WW8_CP_MAX;
5409 p->pPLCFx->SetDirty(true);
5411 if (!p->pPLCFx->GetDirty() || m_pPcd)
5412 GetNewSprms( *p );
5413 p->pPLCFx->SetDirty(false);
5416 #i2325#
5417 To get the character and paragraph properties you first get
5418 the pap and chp and then apply the fastsaved pPcd properties
5419 to the range. If a pap or chp starts inside the pPcd range
5420 then we must bring the current pPcd range to a halt so as to
5421 end those sprms, then the pap/chp will be processed, and then
5422 we must force a restart of the pPcd on that pap/chp starting
5423 boundary. Doing that effectively means that the pPcd sprms will
5424 be applied to the new range. Not doing it means that the pPcd
5425 sprms will only be applied to the first pap/chp set of
5426 properties contained in the pap/chp range.
5428 So we bring the pPcd to a halt on this location here, by
5429 settings its end to the current start, then store the starting
5430 position of the current range to clipstart. The pPcd sprms
5431 will end as normal (albeit earlier than originally expected),
5432 and the existence of a clipstart will force the pPcd iterator
5433 to reread the current set of sprms instead of advancing to its
5434 next set. Then the clipstart will be set as the starting
5435 position which will force them to be applied directly after
5436 the pap and chps.
5438 if (m_pPcd && ((p->nStartPos > m_pPcd->nStartPos) ||
5439 (m_pPcd->nStartPos == WW8_CP_MAX)) &&
5440 (m_pPcd->nEndPos != p->nStartPos))
5442 m_pPcd->nEndPos = p->nStartPos;
5443 static_cast<WW8PLCFx_PCD *>(m_pPcd->pPLCFx)->SetClipStart(
5444 p->nStartPos);
5448 else
5450 p->pPLCFx->advance(); // next Group of Sprms
5451 p->pMemPos = nullptr; // !!!
5452 p->nSprmsLen = 0;
5453 GetNewSprms( *p );
5455 SAL_WARN_IF(p->nStartPos > p->nEndPos, "sw.ww8",
5456 "End " << p->nEndPos << " before Start " << p->nStartPos);
5461 void WW8PLCFMan::AdvNoSprm(short nIdx, bool bStart)
5464 For the case of a piece table we slave the piece table attribute iterator
5465 to the piece table and access it through that only. They are two separate
5466 structures, but act together as one logical one. The attributes only go
5467 to the next entry when the piece changes
5469 WW8PLCFxDesc* p = &m_aD[nIdx];
5471 if( p == m_pPcd )
5473 AdvSprm(nIdx+1,bStart);
5474 if( bStart )
5475 p->nStartPos = m_aD[nIdx+1].nStartPos;
5476 else
5478 if (m_aD[nIdx+1].pIdStack->empty())
5480 WW8PLCFx_PCD *pTemp = static_cast<WW8PLCFx_PCD*>(m_pPcd->pPLCFx);
5482 #i2325#
5483 As per normal, go on to the next set of properties, i.e. we
5484 have traversed over to the next piece. With a clipstart set
5485 we are being told to reread the current piece sprms so as to
5486 reapply them to a new chp or pap range.
5488 if (pTemp->GetClipStart() == -1)
5489 p->pPLCFx->advance();
5490 p->pMemPos = nullptr;
5491 p->nSprmsLen = 0;
5492 GetNewSprms( m_aD[nIdx+1] );
5493 GetNewNoSprms( *p );
5494 if (pTemp->GetClipStart() != -1)
5497 #i2325#, now we will force our starting position to the
5498 clipping start so as to force the application of these
5499 sprms after the current pap/chp sprms so as to apply the
5500 fastsave sprms to the current range.
5502 p->nStartPos = pTemp->GetClipStart();
5503 pTemp->SetClipStart(-1);
5508 else
5509 { // NoSprm without end
5510 p->pPLCFx->advance();
5511 p->pMemPos = nullptr; // MemPos invalid
5512 p->nSprmsLen = 0;
5513 GetNewNoSprms( *p );
5517 void WW8PLCFMan::advance()
5519 bool bStart;
5520 const sal_uInt16 nIdx = WhereIdx(&bStart);
5521 if (nIdx < m_nPLCF)
5523 WW8PLCFxDesc* p = &m_aD[nIdx];
5525 p->bFirstSprm = true; // Default
5527 if( p->pPLCFx->IsSprm() )
5528 AdvSprm( nIdx, bStart );
5529 else // NoSprm
5530 AdvNoSprm( nIdx, bStart );
5534 // return true for the beginning of an attribute or error,
5535 // false for the end of an attribute
5536 // remaining return values are delivered to the caller from WW8PclxManResults.
5537 bool WW8PLCFMan::Get(WW8PLCFManResult* pRes) const
5539 memset( pRes, 0, sizeof( WW8PLCFManResult ) );
5540 bool bStart;
5541 const sal_uInt16 nIdx = WhereIdx(&bStart);
5543 if( nIdx >= m_nPLCF )
5545 OSL_ENSURE( false, "Position not found" );
5546 return true;
5549 if( m_aD[nIdx].pPLCFx->IsSprm() )
5551 if( bStart )
5553 GetSprmStart( nIdx, pRes );
5554 return true;
5556 else
5558 GetSprmEnd( nIdx, pRes );
5559 return false;
5562 else
5564 if( bStart )
5566 GetNoSprmStart( nIdx, pRes );
5567 return true;
5569 else
5571 GetNoSprmEnd( nIdx, pRes );
5572 return false;
5577 sal_uInt16 WW8PLCFMan::GetColl() const
5579 if( m_pPap->pPLCFx )
5580 return m_pPap->pPLCFx->GetIstd();
5581 else
5583 OSL_ENSURE( false, "GetColl without PLCF_Pap" );
5584 return 0;
5588 WW8PLCFx_FLD* WW8PLCFMan::GetField() const
5590 return static_cast<WW8PLCFx_FLD*>(m_pField->pPLCFx);
5593 SprmResult WW8PLCFMan::HasParaSprm( sal_uInt16 nId ) const
5595 return static_cast<WW8PLCFx_Cp_FKP*>(m_pPap->pPLCFx)->HasSprm( nId );
5598 SprmResult WW8PLCFMan::HasCharSprm( sal_uInt16 nId ) const
5600 return static_cast<WW8PLCFx_Cp_FKP*>(m_pChp->pPLCFx)->HasSprm( nId );
5603 void WW8PLCFMan::HasCharSprm(sal_uInt16 nId,
5604 std::vector<SprmResult> &rResult) const
5606 static_cast<WW8PLCFx_Cp_FKP*>(m_pChp->pPLCFx)->HasSprm(nId, rResult);
5609 void WW8PLCFx::Save( WW8PLCFxSave1& rSave ) const
5611 rSave.nPLCFxPos = GetIdx();
5612 rSave.nPLCFxPos2 = GetIdx2();
5613 rSave.nPLCFxMemOfs = 0;
5614 rSave.nStartFC = GetStartFc();
5617 void WW8PLCFx::Restore( const WW8PLCFxSave1& rSave )
5619 SetIdx( rSave.nPLCFxPos );
5620 SetIdx2( rSave.nPLCFxPos2 );
5621 SetStartFc( rSave.nStartFC );
5624 sal_uInt32 WW8PLCFx_Cp_FKP::GetIdx2() const
5626 return GetPCDIdx();
5629 void WW8PLCFx_Cp_FKP::SetIdx2(sal_uInt32 nIdx)
5631 if( pPcd )
5632 pPcd->SetIdx( nIdx );
5635 void WW8PLCFx_Cp_FKP::Save( WW8PLCFxSave1& rSave ) const
5637 if (pFkp)
5638 pFkp->IncMustRemainCache();
5639 WW8PLCFx::Save( rSave );
5641 rSave.nAttrStart = nAttrStart;
5642 rSave.nAttrEnd = nAttrEnd;
5643 rSave.bLineEnd = bLineEnd;
5646 void WW8PLCFx_Cp_FKP::Restore( const WW8PLCFxSave1& rSave )
5648 WW8PLCFx::Restore( rSave );
5650 nAttrStart = rSave.nAttrStart;
5651 nAttrEnd = rSave.nAttrEnd;
5652 bLineEnd = rSave.bLineEnd;
5654 if (pFkp)
5655 pFkp->DecMustRemainCache();
5658 void WW8PLCFxDesc::Save( WW8PLCFxSave1& rSave ) const
5660 if( !pPLCFx )
5661 return;
5663 pPLCFx->Save( rSave );
5664 if( !pPLCFx->IsSprm() )
5665 return;
5667 WW8PLCFxDesc aD;
5668 aD.nStartPos = nOrigStartPos+nCpOfs;
5669 aD.nCpOfs = rSave.nCpOfs = nCpOfs;
5670 if (!(pPLCFx->SeekPos(aD.nStartPos)))
5672 aD.nEndPos = WW8_CP_MAX;
5673 pPLCFx->SetDirty(true);
5675 pPLCFx->GetSprms(&aD);
5676 pPLCFx->SetDirty(false);
5677 aD.ReduceByOffset();
5678 rSave.nStartCp = aD.nStartPos;
5679 rSave.nPLCFxMemOfs = nOrigSprmsLen - nSprmsLen;
5682 void WW8PLCFxDesc::Restore( const WW8PLCFxSave1& rSave )
5684 if( !pPLCFx )
5685 return;
5687 pPLCFx->Restore( rSave );
5688 if( !pPLCFx->IsSprm() )
5689 return;
5691 WW8PLCFxDesc aD;
5692 aD.nStartPos = rSave.nStartCp+rSave.nCpOfs;
5693 nCpOfs = aD.nCpOfs = rSave.nCpOfs;
5694 if (!(pPLCFx->SeekPos(aD.nStartPos)))
5696 aD.nEndPos = WW8_CP_MAX;
5697 pPLCFx->SetDirty(true);
5699 pPLCFx->GetSprms(&aD);
5700 pPLCFx->SetDirty(false);
5701 aD.ReduceByOffset();
5703 if (nOrigSprmsLen > aD.nSprmsLen)
5705 //two entries exist for the same offset, cut and run
5706 SAL_WARN("sw.ww8", "restored properties don't match saved properties, bailing out");
5707 nSprmsLen = 0;
5708 pMemPos = nullptr;
5710 else
5712 nSprmsLen = nOrigSprmsLen - rSave.nPLCFxMemOfs;
5713 pMemPos = aD.pMemPos == nullptr ? nullptr : aD.pMemPos + rSave.nPLCFxMemOfs;
5717 namespace
5719 sal_uInt32 Readcb(SvStream& rSt, ww::WordVersion eVer)
5721 if (eVer <= ww::eWW2)
5723 sal_uInt16 nShort(0);
5724 rSt.ReadUInt16(nShort);
5725 return nShort;
5727 else
5729 sal_uInt32 nLong(0);
5730 rSt.ReadUInt32(nLong);
5731 return nLong;
5736 bool WW8Fib::GetBaseCp(ManTypes nType, WW8_CP * cp) const
5738 assert(cp != nullptr);
5739 WW8_CP nOffset = 0;
5741 switch (nType)
5743 case MAN_TXBX_HDFT:
5744 if (m_ccpTxbx < 0) {
5745 return false;
5747 nOffset = m_ccpTxbx;
5748 [[fallthrough]];
5749 case MAN_TXBX:
5750 if (m_ccpEdn < 0 || m_ccpEdn > std::numeric_limits<WW8_CP>::max() - nOffset) {
5751 return false;
5753 nOffset += m_ccpEdn;
5754 [[fallthrough]];
5755 case MAN_EDN:
5756 if (m_ccpAtn < 0 || m_ccpAtn > std::numeric_limits<WW8_CP>::max() - nOffset) {
5757 return false;
5759 nOffset += m_ccpAtn;
5760 [[fallthrough]];
5761 case MAN_AND:
5762 if (m_ccpMcr < 0 || m_ccpMcr > std::numeric_limits<WW8_CP>::max() - nOffset) {
5763 return false;
5765 nOffset += m_ccpMcr;
5767 // fall through
5769 A subdocument of this kind (MAN_MACRO) probably exists in some defunct
5770 version of MSWord, but now ccpMcr is always 0. If some example that
5771 uses this comes to light, this is the likely calculation required
5773 case MAN_MACRO:
5775 if (m_ccpHdr < 0 || m_ccpHdr > std::numeric_limits<WW8_CP>::max() - nOffset) {
5776 return false;
5778 nOffset += m_ccpHdr;
5779 [[fallthrough]];
5780 case MAN_HDFT:
5781 if (m_ccpFootnote < 0 || m_ccpFootnote > std::numeric_limits<WW8_CP>::max() - nOffset) {
5782 return false;
5784 nOffset += m_ccpFootnote;
5785 [[fallthrough]];
5786 case MAN_FTN:
5787 if (m_ccpText < 0 || m_ccpText > std::numeric_limits<WW8_CP>::max() - nOffset) {
5788 return false;
5790 nOffset += m_ccpText;
5791 [[fallthrough]];
5792 case MAN_MAINTEXT:
5793 break;
5795 *cp = nOffset;
5796 return true;
5799 ww::WordVersion WW8Fib::GetFIBVersion() const
5801 ww::WordVersion eVer = ww::eWW8;
5803 * Word for Windows 2 I think (1.X might work too if anyone has an example.
5805 * 0xA59B for Word 1 for Windows
5806 * 0xA59C for Word 1 for OS/2 "PM Word"
5808 * Various pages claim that the fileformats of Word 1 and 2 for Windows are
5809 * equivalent to Word for Macintosh 4 and 5. On the other hand
5811 * wIdents for Word for Mac versions...
5812 * 0xFE32 for Word 1
5813 * 0xFE34 for Word 3
5814 * 0xFE37 for Word 4 et 5.
5816 * and this document
5817 * http://cmsdoc.cern.ch/documents/docformat/CMS_CERN_LetterHead.word is
5818 * claimed to be "Word 5 for Mac" by Office etc and has that wIdent, but
5819 * its format isn't the same as that of Word 2 for windows. Nor is it
5820 * the same as that of Word for DOS/PCWord 5
5822 if (m_wIdent == 0xa59b || m_wIdent == 0xa59c)
5823 eVer = ww::eWW1;
5824 else if (m_wIdent == 0xa5db)
5825 eVer = ww::eWW2;
5826 else
5828 switch (m_nVersion)
5830 case 6:
5831 eVer = ww::eWW6;
5832 break;
5833 case 7:
5834 eVer = ww::eWW7;
5835 break;
5836 case 8:
5837 eVer = ww::eWW8;
5838 break;
5841 return eVer;
5844 WW8Fib::WW8Fib(SvStream& rSt, sal_uInt8 nWantedVersion, sal_uInt32 nOffset):
5845 m_fDot(false), m_fGlsy(false), m_fComplex(false), m_fHasPic(false), m_cQuickSaves(0),
5846 m_fEncrypted(false), m_fWhichTableStm(false), m_fReadOnlyRecommended(false),
5847 m_fWriteReservation(false), m_fExtChar(false), m_fFarEast(false), m_fObfuscated(false),
5848 m_fMac(false), m_fEmptySpecial(false), m_fLoadOverridePage(false), m_fFuturesavedUndo(false),
5849 m_fWord97Saved(false), m_fWord2000Saved(false)
5850 // in C++20 with P06831R1 "Default member initializers for bit-fields (revision 1)", the
5851 // above bit-field member initializations can be moved to the class definition
5853 // See [MS-DOC] 2.5.15 "How to read the FIB".
5854 sal_uInt8 aBits1;
5855 sal_uInt8 aBits2;
5856 sal_uInt8 aVer8Bits1; // only used starting with WinWord 8
5857 rSt.Seek( nOffset );
5859 note desired number, identify file version number
5860 and check against desired number!
5862 m_nVersion = nWantedVersion;
5863 rSt.ReadUInt16( m_wIdent );
5864 rSt.ReadUInt16( m_nFib );
5865 rSt.ReadUInt16( m_nProduct );
5866 if( ERRCODE_NONE != rSt.GetError() )
5868 sal_Int16 nFibMin;
5869 sal_Int16 nFibMax;
5870 // note: 6 stands for "6 OR 7", 7 stands for "ONLY 7"
5871 switch( m_nVersion )
5873 case 6:
5874 nFibMin = 0x0065; // from 101 WinWord 6.0
5875 // 102 "
5876 // and 103 WinWord 6.0 for Macintosh
5877 // 104 "
5878 nFibMax = 0x0069; // to 105 WinWord 95
5879 break;
5880 case 7:
5881 nFibMin = 0x0069; // from 105 WinWord 95
5882 nFibMax = 0x0069; // to 105 WinWord 95
5883 break;
5884 case 8:
5885 nFibMin = 0x006A; // from 106 WinWord 97
5886 nFibMax = 0x00c1; // to 193 WinWord 97 (?)
5887 break;
5888 default:
5889 nFibMin = 0; // program error!
5890 nFibMax = 0;
5891 m_nFib = 1;
5892 OSL_ENSURE( false, "nVersion not implemented!" );
5893 break;
5895 if ( (m_nFib < nFibMin) || (m_nFib > nFibMax) )
5897 m_nFibError = ERR_SWG_READ_ERROR; // report error
5898 return;
5902 ww::WordVersion eVer = GetFIBVersion();
5904 // helper vars for Ver67:
5905 sal_Int16 pnChpFirst_Ver67=0;
5906 sal_Int16 pnPapFirst_Ver67=0;
5907 sal_Int16 cpnBteChp_Ver67=0;
5908 sal_Int16 cpnBtePap_Ver67=0;
5910 // read FIB
5911 sal_uInt16 nTmpLid = 0;
5912 rSt.ReadUInt16(nTmpLid);
5913 m_lid = LanguageType(nTmpLid);
5914 rSt.ReadInt16( m_pnNext );
5915 rSt.ReadUChar( aBits1 );
5916 rSt.ReadUChar( aBits2 );
5917 rSt.ReadUInt16( m_nFibBack );
5918 rSt.ReadUInt16( m_nHash );
5919 rSt.ReadUInt16( m_nKey );
5920 rSt.ReadUChar( m_envr );
5921 rSt.ReadUChar( aVer8Bits1 ); // only have an empty reserve field under Ver67
5922 // content from aVer8Bits1
5924 // sal_uInt8 fMac :1;
5925 // sal_uInt8 fEmptySpecial :1;
5926 // sal_uInt8 fLoadOverridePage :1;
5927 // sal_uInt8 fFuturesavedUndo :1;
5928 // sal_uInt8 fWord97Saved :1;
5929 // sal_uInt8 :3;
5930 rSt.ReadUInt16( m_chse );
5931 rSt.ReadUInt16( m_chseTables );
5932 rSt.ReadInt32( m_fcMin );
5933 rSt.ReadInt32( m_fcMac );
5935 // insertion for WW8
5936 if (IsEightPlus(eVer))
5938 rSt.ReadUInt16( m_csw );
5940 // Marke: "rgsw" Beginning of the array of shorts
5941 rSt.ReadUInt16( m_wMagicCreated );
5942 rSt.ReadUInt16( m_wMagicRevised );
5943 rSt.ReadUInt16( m_wMagicCreatedPrivate );
5944 rSt.ReadUInt16( m_wMagicRevisedPrivate );
5945 rSt.SeekRel( 9 * sizeof( sal_Int16 ) );
5948 // these are the 9 unused fields:
5949 && (bVer67 || WW8ReadINT16( rSt, pnFbpChpFirst_W6 )) // 1
5950 && (bVer67 || WW8ReadINT16( rSt, pnChpFirst_W6 )) // 2
5951 && (bVer67 || WW8ReadINT16( rSt, cpnBteChp_W6 )) // 3
5952 && (bVer67 || WW8ReadINT16( rSt, pnFbpPapFirst_W6 )) // 4
5953 && (bVer67 || WW8ReadINT16( rSt, pnPapFirst_W6 )) // 5
5954 && (bVer67 || WW8ReadINT16( rSt, cpnBtePap_W6 )) // 6
5955 && (bVer67 || WW8ReadINT16( rSt, pnFbpLvcFirst_W6 )) // 7
5956 && (bVer67 || WW8ReadINT16( rSt, pnLvcFirst_W6 )) // 8
5957 && (bVer67 || WW8ReadINT16( rSt, cpnBteLvc_W6 )) // 9
5959 sal_uInt16 nTmpFE = 0;
5960 rSt.ReadUInt16(nTmpFE);
5961 m_lidFE = LanguageType(nTmpFE);
5962 rSt.ReadUInt16( m_clw );
5965 // end of the insertion for WW8
5967 // Marke: "rglw" Beginning of the array of longs
5968 rSt.ReadInt32( m_cbMac );
5970 // ignore 2 longs, because they are unimportant
5971 rSt.SeekRel( 2 * sizeof( sal_Int32) );
5973 // skipping 2 more longs only at Ver67
5974 if (IsSevenMinus(eVer))
5975 rSt.SeekRel( 2 * sizeof( sal_Int32) );
5977 rSt.ReadInt32( m_ccpText );
5978 rSt.ReadInt32( m_ccpFootnote );
5979 rSt.ReadInt32( m_ccpHdr );
5980 rSt.ReadInt32( m_ccpMcr );
5981 rSt.ReadInt32( m_ccpAtn );
5982 rSt.ReadInt32( m_ccpEdn );
5983 rSt.ReadInt32( m_ccpTxbx );
5984 rSt.ReadInt32( m_ccpHdrTxbx );
5986 // only skip one more long at Ver67
5987 if (IsSevenMinus(eVer))
5988 rSt.SeekRel( 1 * sizeof( sal_Int32) );
5989 else
5991 // insertion for WW8
5992 rSt.ReadInt32( m_pnFbpChpFirst );
5993 rSt.ReadInt32( m_pnChpFirst );
5994 rSt.ReadInt32( m_cpnBteChp );
5995 rSt.ReadInt32( m_pnFbpPapFirst );
5996 rSt.ReadInt32( m_pnPapFirst );
5997 rSt.ReadInt32( m_cpnBtePap );
5998 rSt.ReadInt32( m_pnFbpLvcFirst );
5999 rSt.ReadInt32( m_pnLvcFirst );
6000 rSt.ReadInt32( m_cpnBteLvc );
6001 rSt.ReadInt32( m_fcIslandFirst );
6002 rSt.ReadInt32( m_fcIslandLim );
6003 rSt.ReadUInt16( m_cfclcb );
6005 // Read cswNew to find out if nFib should be ignored.
6006 sal_uInt32 nPos = rSt.Tell();
6007 rSt.SeekRel(m_cfclcb * 8);
6008 if (rSt.good())
6010 rSt.ReadUInt16(m_cswNew);
6012 rSt.Seek(nPos);
6015 // end of the insertion for WW8
6017 // Marke: "rgfclcb" Beginning of array of FC/LCB pairs.
6018 rSt.ReadInt32( m_fcStshfOrig );
6019 m_lcbStshfOrig = Readcb(rSt, eVer);
6020 rSt.ReadInt32( m_fcStshf );
6021 m_lcbStshf = Readcb(rSt, eVer);
6022 rSt.ReadInt32( m_fcPlcffndRef );
6023 m_lcbPlcffndRef = Readcb(rSt, eVer);
6024 rSt.ReadInt32( m_fcPlcffndText );
6025 m_lcbPlcffndText = Readcb(rSt, eVer);
6026 rSt.ReadInt32( m_fcPlcfandRef );
6027 m_lcbPlcfandRef = Readcb(rSt, eVer);
6028 rSt.ReadInt32( m_fcPlcfandText );
6029 m_lcbPlcfandText = Readcb(rSt, eVer);
6030 rSt.ReadInt32( m_fcPlcfsed );
6031 m_lcbPlcfsed = Readcb(rSt, eVer);
6032 rSt.ReadInt32( m_fcPlcfpad );
6033 m_lcbPlcfpad = Readcb(rSt, eVer);
6034 rSt.ReadInt32( m_fcPlcfphe );
6035 m_lcbPlcfphe = Readcb(rSt, eVer);
6036 rSt.ReadInt32( m_fcSttbfglsy );
6037 m_lcbSttbfglsy = Readcb(rSt, eVer);
6038 rSt.ReadInt32( m_fcPlcfglsy );
6039 m_lcbPlcfglsy = Readcb(rSt, eVer);
6040 rSt.ReadInt32( m_fcPlcfhdd );
6041 m_lcbPlcfhdd = Readcb(rSt, eVer);
6042 rSt.ReadInt32( m_fcPlcfbteChpx );
6043 m_lcbPlcfbteChpx = Readcb(rSt, eVer);
6044 rSt.ReadInt32( m_fcPlcfbtePapx );
6045 m_lcbPlcfbtePapx = Readcb(rSt, eVer);
6046 rSt.ReadInt32( m_fcPlcfsea );
6047 m_lcbPlcfsea = Readcb(rSt, eVer);
6048 rSt.ReadInt32( m_fcSttbfffn );
6049 m_lcbSttbfffn = Readcb(rSt, eVer);
6050 rSt.ReadInt32( m_fcPlcffldMom );
6051 m_lcbPlcffldMom = Readcb(rSt, eVer);
6052 rSt.ReadInt32( m_fcPlcffldHdr );
6053 m_lcbPlcffldHdr = Readcb(rSt, eVer);
6054 rSt.ReadInt32( m_fcPlcffldFootnote );
6055 m_lcbPlcffldFootnote = Readcb(rSt, eVer);
6056 rSt.ReadInt32( m_fcPlcffldAtn );
6057 m_lcbPlcffldAtn = Readcb(rSt, eVer);
6058 rSt.ReadInt32( m_fcPlcffldMcr );
6059 m_lcbPlcffldMcr = Readcb(rSt, eVer);
6060 rSt.ReadInt32( m_fcSttbfbkmk );
6061 m_lcbSttbfbkmk = Readcb(rSt, eVer);
6062 rSt.ReadInt32( m_fcPlcfbkf );
6063 m_lcbPlcfbkf = Readcb(rSt, eVer);
6064 rSt.ReadInt32( m_fcPlcfbkl );
6065 m_lcbPlcfbkl = Readcb(rSt, eVer);
6066 rSt.ReadInt32( m_fcCmds );
6067 m_lcbCmds = Readcb(rSt, eVer);
6068 rSt.ReadInt32( m_fcPlcfmcr );
6069 m_lcbPlcfmcr = Readcb(rSt, eVer);
6070 rSt.ReadInt32( m_fcSttbfmcr );
6071 m_lcbSttbfmcr = Readcb(rSt, eVer);
6072 if (eVer >= ww::eWW2)
6074 rSt.ReadInt32( m_fcPrDrvr );
6075 m_lcbPrDrvr = Readcb(rSt, eVer);
6076 rSt.ReadInt32( m_fcPrEnvPort );
6077 m_lcbPrEnvPort = Readcb(rSt, eVer);
6078 rSt.ReadInt32( m_fcPrEnvLand );
6079 m_lcbPrEnvLand = Readcb(rSt, eVer);
6081 else
6083 rSt.ReadInt32( m_fcPrEnvPort );
6084 m_lcbPrEnvPort = Readcb(rSt, eVer);
6086 rSt.ReadInt32( m_fcWss );
6087 m_lcbWss = Readcb(rSt, eVer);
6088 rSt.ReadInt32( m_fcDop );
6089 m_lcbDop = Readcb(rSt, eVer);
6090 rSt.ReadInt32( m_fcSttbfAssoc );
6091 m_lcbSttbfAssoc = Readcb(rSt, eVer);
6092 rSt.ReadInt32( m_fcClx );
6093 m_lcbClx = Readcb(rSt, eVer);
6094 rSt.ReadInt32( m_fcPlcfpgdFootnote );
6095 m_lcbPlcfpgdFootnote = Readcb(rSt, eVer);
6096 rSt.ReadInt32( m_fcAutosaveSource );
6097 m_lcbAutosaveSource = Readcb(rSt, eVer);
6098 rSt.ReadInt32( m_fcGrpStAtnOwners );
6099 m_lcbGrpStAtnOwners = Readcb(rSt, eVer);
6100 rSt.ReadInt32( m_fcSttbfAtnbkmk );
6101 m_lcbSttbfAtnbkmk = Readcb(rSt, eVer);
6103 // only skip more shot at Ver67
6104 if (IsSevenMinus(eVer))
6106 if (eVer == ww::eWW1)
6107 rSt.SeekRel(1*sizeof(sal_Int32));
6108 rSt.SeekRel(1*sizeof(sal_Int16));
6110 if (eVer >= ww::eWW2)
6112 rSt.ReadInt16(pnChpFirst_Ver67);
6113 rSt.ReadInt16(pnPapFirst_Ver67);
6115 rSt.ReadInt16(cpnBteChp_Ver67);
6116 rSt.ReadInt16(cpnBtePap_Ver67);
6119 if (eVer > ww::eWW2)
6121 rSt.ReadInt32( m_fcPlcfdoaMom );
6122 rSt.ReadInt32( m_lcbPlcfdoaMom );
6123 rSt.ReadInt32( m_fcPlcfdoaHdr );
6124 rSt.ReadInt32( m_lcbPlcfdoaHdr );
6125 rSt.ReadInt32( m_fcPlcfspaMom );
6126 rSt.ReadInt32( m_lcbPlcfspaMom );
6127 rSt.ReadInt32( m_fcPlcfspaHdr );
6128 rSt.ReadInt32( m_lcbPlcfspaHdr );
6130 rSt.ReadInt32( m_fcPlcfAtnbkf );
6131 rSt.ReadInt32( m_lcbPlcfAtnbkf );
6132 rSt.ReadInt32( m_fcPlcfAtnbkl );
6133 rSt.ReadInt32( m_lcbPlcfAtnbkl );
6134 rSt.ReadInt32( m_fcPms );
6135 rSt.ReadInt32( m_lcbPMS );
6136 rSt.ReadInt32( m_fcFormFieldSttbf );
6137 rSt.ReadInt32( m_lcbFormFieldSttbf );
6138 rSt.ReadInt32( m_fcPlcfendRef );
6139 rSt.ReadInt32( m_lcbPlcfendRef );
6140 rSt.ReadInt32( m_fcPlcfendText );
6141 rSt.ReadInt32( m_lcbPlcfendText );
6142 rSt.ReadInt32( m_fcPlcffldEdn );
6143 rSt.ReadInt32( m_lcbPlcffldEdn );
6144 rSt.ReadInt32( m_fcPlcfpgdEdn );
6145 rSt.ReadInt32( m_lcbPlcfpgdEdn );
6146 rSt.ReadInt32( m_fcDggInfo );
6147 rSt.ReadInt32( m_lcbDggInfo );
6148 rSt.ReadInt32( m_fcSttbfRMark );
6149 rSt.ReadInt32( m_lcbSttbfRMark );
6150 rSt.ReadInt32( m_fcSttbfCaption );
6151 rSt.ReadInt32( m_lcbSttbfCaption );
6152 rSt.ReadInt32( m_fcSttbAutoCaption );
6153 rSt.ReadInt32( m_lcbSttbAutoCaption );
6154 rSt.ReadInt32( m_fcPlcfwkb );
6155 rSt.ReadInt32( m_lcbPlcfwkb );
6156 rSt.ReadInt32( m_fcPlcfspl );
6157 rSt.ReadInt32( m_lcbPlcfspl );
6158 rSt.ReadInt32( m_fcPlcftxbxText );
6159 rSt.ReadInt32( m_lcbPlcftxbxText );
6160 rSt.ReadInt32( m_fcPlcffldTxbx );
6161 rSt.ReadInt32( m_lcbPlcffldTxbx );
6162 rSt.ReadInt32( m_fcPlcfHdrtxbxText );
6163 rSt.ReadInt32( m_lcbPlcfHdrtxbxText );
6164 rSt.ReadInt32( m_fcPlcffldHdrTxbx );
6165 rSt.ReadInt32( m_lcbPlcffldHdrTxbx );
6166 rSt.ReadInt32( m_fcStwUser );
6167 rSt.ReadUInt32( m_lcbStwUser );
6168 rSt.ReadInt32( m_fcSttbttmbd );
6169 rSt.ReadUInt32( m_lcbSttbttmbd );
6172 if( ERRCODE_NONE == rSt.GetError() )
6174 // set bit flag
6175 m_fDot = aBits1 & 0x01 ;
6176 m_fGlsy = ( aBits1 & 0x02 ) >> 1;
6177 m_fComplex = ( aBits1 & 0x04 ) >> 2;
6178 m_fHasPic = ( aBits1 & 0x08 ) >> 3;
6179 m_cQuickSaves = ( aBits1 & 0xf0 ) >> 4;
6180 m_fEncrypted = aBits2 & 0x01 ;
6181 m_fWhichTableStm= ( aBits2 & 0x02 ) >> 1;
6182 m_fReadOnlyRecommended = (aBits2 & 0x4) >> 2;
6183 m_fWriteReservation = (aBits2 & 0x8) >> 3;
6184 m_fExtChar = ( aBits2 & 0x10 ) >> 4;
6185 // dummy = ( aBits2 & 0x20 ) >> 5;
6186 m_fFarEast = ( aBits2 & 0x40 ) >> 6; // #i90932#
6187 // dummy = ( aBits2 & 0x80 ) >> 7;
6190 p.r.n. fill targeted variable with xxx_Ver67
6191 or set flags
6193 if (IsSevenMinus(eVer))
6195 m_pnChpFirst = pnChpFirst_Ver67;
6196 m_pnPapFirst = pnPapFirst_Ver67;
6197 m_cpnBteChp = cpnBteChp_Ver67;
6198 m_cpnBtePap = cpnBtePap_Ver67;
6200 else if (IsEightPlus(eVer))
6202 m_fMac = aVer8Bits1 & 0x01 ;
6203 m_fEmptySpecial = ( aVer8Bits1 & 0x02 ) >> 1;
6204 m_fLoadOverridePage = ( aVer8Bits1 & 0x04 ) >> 2;
6205 m_fFuturesavedUndo = ( aVer8Bits1 & 0x08 ) >> 3;
6206 m_fWord97Saved = ( aVer8Bits1 & 0x10 ) >> 4;
6207 m_fWord2000Saved = ( aVer8Bits1 & 0x20 ) >> 5;
6210 especially for WW8:
6211 identify the values for PLCF and PLF LFO
6212 and PLCF for the textbox break descriptors
6214 tools::Long nOldPos = rSt.Tell();
6216 rSt.Seek( 0x02da );
6217 rSt.ReadInt32( m_fcSttbFnm );
6218 rSt.ReadInt32( m_lcbSttbFnm );
6219 rSt.ReadInt32( m_fcPlcfLst );
6220 rSt.ReadInt32( m_lcbPlcfLst );
6221 rSt.ReadInt32( m_fcPlfLfo );
6222 rSt.ReadInt32( m_lcbPlfLfo );
6223 rSt.ReadInt32( m_fcPlcftxbxBkd );
6224 rSt.ReadInt32( m_lcbPlcftxbxBkd );
6225 rSt.ReadInt32( m_fcPlcfHdrtxbxBkd );
6226 rSt.ReadInt32( m_lcbPlcfHdrtxbxBkd );
6227 if( ERRCODE_NONE != rSt.GetError() )
6229 m_nFibError = ERR_SWG_READ_ERROR;
6232 rSt.Seek( 0x372 ); // fcSttbListNames
6233 rSt.ReadInt32( m_fcSttbListNames );
6234 rSt.ReadInt32( m_lcbSttbListNames );
6236 if (m_cfclcb > 93)
6238 rSt.Seek( 0x382 ); // MagicTables
6239 rSt.ReadInt32( m_fcPlcfTch );
6240 rSt.ReadInt32( m_lcbPlcfTch );
6243 if (m_cfclcb > 113)
6245 rSt.Seek( 0x41A ); // new ATRD
6246 rSt.ReadInt32( m_fcAtrdExtra );
6247 rSt.ReadUInt32( m_lcbAtrdExtra );
6250 // Factoid bookmarks
6251 if (m_cfclcb > 134)
6253 rSt.Seek(0x432);
6254 rSt.ReadInt32(m_fcPlcfBkfFactoid);
6255 rSt.ReadUInt32(m_lcbPlcfBkfFactoid);
6257 rSt.Seek(0x442);
6258 rSt.ReadInt32(m_fcPlcfBklFactoid);
6259 rSt.ReadUInt32(m_lcbPlcfBklFactoid);
6261 rSt.Seek(0x44a);
6262 rSt.ReadInt32(m_fcFactoidData);
6263 rSt.ReadUInt32(m_lcbFactoidData);
6266 if( ERRCODE_NONE != rSt.GetError() )
6267 m_nFibError = ERR_SWG_READ_ERROR;
6269 rSt.Seek( 0x5bc ); // Actual nFib introduced in Word 2003
6270 rSt.ReadUInt16( m_nFib_actual );
6272 rSt.Seek( nOldPos );
6275 else
6277 m_nFibError = ERR_SWG_READ_ERROR; // report error
6281 WW8Fib::WW8Fib(sal_uInt8 nVer, bool bDot):
6282 m_nVersion(nVer), m_fDot(false), m_fGlsy(false), m_fComplex(false), m_fHasPic(false), m_cQuickSaves(0),
6283 m_fEncrypted(false), m_fWhichTableStm(false), m_fReadOnlyRecommended(false),
6284 m_fWriteReservation(false), m_fExtChar(false), m_fFarEast(false), m_fObfuscated(false),
6285 m_fMac(false), m_fEmptySpecial(false), m_fLoadOverridePage(false), m_fFuturesavedUndo(false),
6286 m_fWord97Saved(false), m_fWord2000Saved(false)
6287 // in C++20 with P06831R1 "Default member initializers for bit-fields (revision 1)", the
6288 // above bit-field member initializations can be moved to the class definition
6290 if (8 == nVer)
6292 m_fcMin = 0x800;
6293 m_wIdent = 0xa5ec;
6294 m_nFib = 0x0101;
6295 m_nFibBack = 0xbf;
6296 m_nProduct = 0x204D;
6297 m_fDot = bDot;
6299 m_csw = 0x0e; // Is this really necessary???
6300 m_cfclcb = 0x88; // -""-
6301 m_clw = 0x16; // -""-
6302 m_pnFbpChpFirst = m_pnFbpPapFirst = m_pnFbpLvcFirst = 0x000fffff;
6303 m_fExtChar = true;
6304 m_fWord97Saved = m_fWord2000Saved = true;
6306 // Just a fancy way to write 'Caolan80'.
6307 m_wMagicCreated = 0x6143;
6308 m_wMagicRevised = 0x6C6F;
6309 m_wMagicCreatedPrivate = 0x6E61;
6310 m_wMagicRevisedPrivate = 0x3038;
6312 else
6314 m_fcMin = 0x300;
6315 m_wIdent = 0xa5dc;
6316 m_nFib = m_nFibBack = 0x65;
6317 m_nProduct = 0xc02d;
6320 //If nFib is 0x00D9 or greater, then cQuickSaves MUST be 0xF
6321 m_cQuickSaves = m_nFib >= 0x00D9 ? 0xF : 0;
6323 // --> #i90932#
6324 m_lid = LanguageType(0x409); // LANGUAGE_ENGLISH_US
6326 LanguageType nLang = Application::GetSettings().GetLanguageTag().getLanguageType();
6327 m_fFarEast = MsLangId::isCJK(nLang);
6328 if (m_fFarEast)
6329 m_lidFE = nLang;
6330 else
6331 m_lidFE = m_lid;
6333 LanguageTag aLanguageTag( m_lid );
6334 LocaleDataWrapper aLocaleWrapper( aLanguageTag );
6335 m_nNumDecimalSep = aLocaleWrapper.getNumDecimalSep()[0];
6339 void WW8Fib::WriteHeader(SvStream& rStrm)
6341 bool bVer8 = 8 == m_nVersion;
6343 size_t nUnencryptedHdr = bVer8 ? 0x44 : 0x24;
6344 std::unique_ptr<sal_uInt8[]> pDataPtr( new sal_uInt8[ nUnencryptedHdr ] );
6345 sal_uInt8 *pData = pDataPtr.get();
6346 memset( pData, 0, nUnencryptedHdr );
6348 m_cbMac = rStrm.TellEnd();
6350 Set_UInt16( pData, m_wIdent );
6351 Set_UInt16( pData, m_nFib );
6352 Set_UInt16( pData, m_nProduct );
6353 Set_UInt16( pData, static_cast<sal_uInt16>(m_lid) );
6354 Set_UInt16( pData, m_pnNext );
6356 sal_uInt16 nBits16 = 0;
6357 if( m_fDot ) nBits16 |= 0x0001;
6358 if( m_fGlsy) nBits16 |= 0x0002;
6359 if( m_fComplex ) nBits16 |= 0x0004;
6360 if( m_fHasPic ) nBits16 |= 0x0008;
6361 nBits16 |= (0xf0 & ( m_cQuickSaves << 4 ));
6362 if( m_fEncrypted ) nBits16 |= 0x0100;
6363 if( m_fWhichTableStm ) nBits16 |= 0x0200;
6365 if (m_fReadOnlyRecommended)
6366 nBits16 |= 0x0400;
6367 if (m_fWriteReservation)
6368 nBits16 |= 0x0800;
6370 if( m_fExtChar ) nBits16 |= 0x1000;
6371 if( m_fFarEast ) nBits16 |= 0x4000; // #i90932#
6372 if( m_fObfuscated ) nBits16 |= 0x8000;
6373 Set_UInt16( pData, nBits16 );
6375 Set_UInt16( pData, m_nFibBack );
6376 Set_UInt16( pData, m_nHash );
6377 Set_UInt16( pData, m_nKey );
6378 Set_UInt8( pData, m_envr );
6380 sal_uInt8 nBits8 = 0;
6381 if( bVer8 )
6383 if( m_fMac ) nBits8 |= 0x0001;
6384 if( m_fEmptySpecial ) nBits8 |= 0x0002;
6385 if( m_fLoadOverridePage ) nBits8 |= 0x0004;
6386 if( m_fFuturesavedUndo ) nBits8 |= 0x0008;
6387 if( m_fWord97Saved ) nBits8 |= 0x0010;
6388 if( m_fWord2000Saved ) nBits8 |= 0x0020;
6390 // under Ver67 these are only reserved
6391 Set_UInt8( pData, nBits8 );
6393 Set_UInt16( pData, m_chse );
6394 Set_UInt16( pData, m_chseTables );
6395 Set_UInt32( pData, m_fcMin );
6396 Set_UInt32( pData, m_fcMac );
6398 // insertion for WW8
6400 // Marke: "rgsw" Beginning of the array of shorts
6401 if( bVer8 )
6403 Set_UInt16( pData, m_csw );
6404 Set_UInt16( pData, m_wMagicCreated );
6405 Set_UInt16( pData, m_wMagicRevised );
6406 Set_UInt16( pData, m_wMagicCreatedPrivate );
6407 Set_UInt16( pData, m_wMagicRevisedPrivate );
6408 pData += 9 * sizeof( sal_Int16 );
6409 Set_UInt16( pData, static_cast<sal_uInt16>(m_lidFE) );
6410 Set_UInt16( pData, m_clw );
6413 // end of the insertion for WW8
6415 // Marke: "rglw" Beginning of the array of longs
6416 Set_UInt32( pData, m_cbMac );
6418 rStrm.WriteBytes(pDataPtr.get(), nUnencryptedHdr);
6421 void WW8Fib::Write(SvStream& rStrm)
6423 bool bVer8 = 8 == m_nVersion;
6425 WriteHeader( rStrm );
6427 size_t nUnencryptedHdr = bVer8 ? 0x44 : 0x24;
6429 std::unique_ptr<sal_uInt8[]> pDataPtr( new sal_uInt8[ m_fcMin - nUnencryptedHdr ] );
6430 sal_uInt8 *pData = pDataPtr.get();
6431 memset( pData, 0, m_fcMin - nUnencryptedHdr );
6433 m_cbMac = rStrm.TellEnd();
6435 // ignore 2 longs, because they are unimportant
6436 pData += 2 * sizeof( sal_Int32);
6438 // skipping 2 more longs only at Ver67
6439 if( !bVer8 )
6440 pData += 2 * sizeof( sal_Int32);
6442 Set_UInt32( pData, m_ccpText );
6443 Set_UInt32( pData, m_ccpFootnote );
6444 Set_UInt32( pData, m_ccpHdr );
6445 Set_UInt32( pData, m_ccpMcr );
6446 Set_UInt32( pData, m_ccpAtn );
6447 Set_UInt32( pData, m_ccpEdn );
6448 Set_UInt32( pData, m_ccpTxbx );
6449 Set_UInt32( pData, m_ccpHdrTxbx );
6451 // only skip one more long at Ver67
6452 if( !bVer8 )
6453 pData += 1 * sizeof( sal_Int32);
6455 // insertion for WW8
6456 if( bVer8 )
6458 Set_UInt32( pData, m_pnFbpChpFirst );
6459 Set_UInt32( pData, m_pnChpFirst );
6460 Set_UInt32( pData, m_cpnBteChp );
6461 Set_UInt32( pData, m_pnFbpPapFirst );
6462 Set_UInt32( pData, m_pnPapFirst );
6463 Set_UInt32( pData, m_cpnBtePap );
6464 Set_UInt32( pData, m_pnFbpLvcFirst );
6465 Set_UInt32( pData, m_pnLvcFirst );
6466 Set_UInt32( pData, m_cpnBteLvc );
6467 Set_UInt32( pData, m_fcIslandFirst );
6468 Set_UInt32( pData, m_fcIslandLim );
6469 Set_UInt16( pData, m_cfclcb );
6471 // end of the insertion for WW8
6473 // Marke: "rgfclcb" Beginning of array of FC/LCB pairs.
6474 Set_UInt32( pData, m_fcStshfOrig );
6475 Set_UInt32( pData, m_lcbStshfOrig );
6476 Set_UInt32( pData, m_fcStshf );
6477 Set_UInt32( pData, m_lcbStshf );
6478 Set_UInt32( pData, m_fcPlcffndRef );
6479 Set_UInt32( pData, m_lcbPlcffndRef );
6480 Set_UInt32( pData, m_fcPlcffndText );
6481 Set_UInt32( pData, m_lcbPlcffndText );
6482 Set_UInt32( pData, m_fcPlcfandRef );
6483 Set_UInt32( pData, m_lcbPlcfandRef );
6484 Set_UInt32( pData, m_fcPlcfandText );
6485 Set_UInt32( pData, m_lcbPlcfandText );
6486 Set_UInt32( pData, m_fcPlcfsed );
6487 Set_UInt32( pData, m_lcbPlcfsed );
6488 Set_UInt32( pData, m_fcPlcfpad );
6489 Set_UInt32( pData, m_lcbPlcfpad );
6490 Set_UInt32( pData, m_fcPlcfphe );
6491 Set_UInt32( pData, m_lcbPlcfphe );
6492 Set_UInt32( pData, m_fcSttbfglsy );
6493 Set_UInt32( pData, m_lcbSttbfglsy );
6494 Set_UInt32( pData, m_fcPlcfglsy );
6495 Set_UInt32( pData, m_lcbPlcfglsy );
6496 Set_UInt32( pData, m_fcPlcfhdd );
6497 Set_UInt32( pData, m_lcbPlcfhdd );
6498 Set_UInt32( pData, m_fcPlcfbteChpx );
6499 Set_UInt32( pData, m_lcbPlcfbteChpx );
6500 Set_UInt32( pData, m_fcPlcfbtePapx );
6501 Set_UInt32( pData, m_lcbPlcfbtePapx );
6502 Set_UInt32( pData, m_fcPlcfsea );
6503 Set_UInt32( pData, m_lcbPlcfsea );
6504 Set_UInt32( pData, m_fcSttbfffn );
6505 Set_UInt32( pData, m_lcbSttbfffn );
6506 Set_UInt32( pData, m_fcPlcffldMom );
6507 Set_UInt32( pData, m_lcbPlcffldMom );
6508 Set_UInt32( pData, m_fcPlcffldHdr );
6509 Set_UInt32( pData, m_lcbPlcffldHdr );
6510 Set_UInt32( pData, m_fcPlcffldFootnote );
6511 Set_UInt32( pData, m_lcbPlcffldFootnote );
6512 Set_UInt32( pData, m_fcPlcffldAtn );
6513 Set_UInt32( pData, m_lcbPlcffldAtn );
6514 Set_UInt32( pData, m_fcPlcffldMcr );
6515 Set_UInt32( pData, m_lcbPlcffldMcr );
6516 Set_UInt32( pData, m_fcSttbfbkmk );
6517 Set_UInt32( pData, m_lcbSttbfbkmk );
6518 Set_UInt32( pData, m_fcPlcfbkf );
6519 Set_UInt32( pData, m_lcbPlcfbkf );
6520 Set_UInt32( pData, m_fcPlcfbkl );
6521 Set_UInt32( pData, m_lcbPlcfbkl );
6522 Set_UInt32( pData, m_fcCmds );
6523 Set_UInt32( pData, m_lcbCmds );
6524 Set_UInt32( pData, m_fcPlcfmcr );
6525 Set_UInt32( pData, m_lcbPlcfmcr );
6526 Set_UInt32( pData, m_fcSttbfmcr );
6527 Set_UInt32( pData, m_lcbSttbfmcr );
6528 Set_UInt32( pData, m_fcPrDrvr );
6529 Set_UInt32( pData, m_lcbPrDrvr );
6530 Set_UInt32( pData, m_fcPrEnvPort );
6531 Set_UInt32( pData, m_lcbPrEnvPort );
6532 Set_UInt32( pData, m_fcPrEnvLand );
6533 Set_UInt32( pData, m_lcbPrEnvLand );
6534 Set_UInt32( pData, m_fcWss );
6535 Set_UInt32( pData, m_lcbWss );
6536 Set_UInt32( pData, m_fcDop );
6537 Set_UInt32( pData, m_lcbDop );
6538 Set_UInt32( pData, m_fcSttbfAssoc );
6539 Set_UInt32( pData, m_lcbSttbfAssoc );
6540 Set_UInt32( pData, m_fcClx );
6541 Set_UInt32( pData, m_lcbClx );
6542 Set_UInt32( pData, m_fcPlcfpgdFootnote );
6543 Set_UInt32( pData, m_lcbPlcfpgdFootnote );
6544 Set_UInt32( pData, m_fcAutosaveSource );
6545 Set_UInt32( pData, m_lcbAutosaveSource );
6546 Set_UInt32( pData, m_fcGrpStAtnOwners );
6547 Set_UInt32( pData, m_lcbGrpStAtnOwners );
6548 Set_UInt32( pData, m_fcSttbfAtnbkmk );
6549 Set_UInt32( pData, m_lcbSttbfAtnbkmk );
6551 // only skip one more short at Ver67
6552 if( !bVer8 )
6554 pData += 1*sizeof( sal_Int16);
6555 Set_UInt16( pData, static_cast<sal_uInt16>(m_pnChpFirst) );
6556 Set_UInt16( pData, static_cast<sal_uInt16>(m_pnPapFirst) );
6557 Set_UInt16( pData, static_cast<sal_uInt16>(m_cpnBteChp) );
6558 Set_UInt16( pData, static_cast<sal_uInt16>(m_cpnBtePap) );
6561 Set_UInt32( pData, m_fcPlcfdoaMom ); // only at Ver67, in Ver8 unused
6562 Set_UInt32( pData, m_lcbPlcfdoaMom ); // only at Ver67, in Ver8 unused
6563 Set_UInt32( pData, m_fcPlcfdoaHdr ); // only at Ver67, in Ver8 unused
6564 Set_UInt32( pData, m_lcbPlcfdoaHdr ); // only at Ver67, in Ver8 unused
6566 Set_UInt32( pData, m_fcPlcfspaMom ); // in Ver67 empty reserve
6567 Set_UInt32( pData, m_lcbPlcfspaMom ); // in Ver67 empty reserve
6568 Set_UInt32( pData, m_fcPlcfspaHdr ); // in Ver67 empty reserve
6569 Set_UInt32( pData, m_lcbPlcfspaHdr ); // in Ver67 empty reserve
6571 Set_UInt32( pData, m_fcPlcfAtnbkf );
6572 Set_UInt32( pData, m_lcbPlcfAtnbkf );
6573 Set_UInt32( pData, m_fcPlcfAtnbkl );
6574 Set_UInt32( pData, m_lcbPlcfAtnbkl );
6575 Set_UInt32( pData, m_fcPms );
6576 Set_UInt32( pData, m_lcbPMS );
6577 Set_UInt32( pData, m_fcFormFieldSttbf );
6578 Set_UInt32( pData, m_lcbFormFieldSttbf );
6579 Set_UInt32( pData, m_fcPlcfendRef );
6580 Set_UInt32( pData, m_lcbPlcfendRef );
6581 Set_UInt32( pData, m_fcPlcfendText );
6582 Set_UInt32( pData, m_lcbPlcfendText );
6583 Set_UInt32( pData, m_fcPlcffldEdn );
6584 Set_UInt32( pData, m_lcbPlcffldEdn );
6585 Set_UInt32( pData, m_fcPlcfpgdEdn );
6586 Set_UInt32( pData, m_lcbPlcfpgdEdn );
6587 Set_UInt32( pData, m_fcDggInfo ); // in Ver67 empty reserve
6588 Set_UInt32( pData, m_lcbDggInfo ); // in Ver67 empty reserve
6589 Set_UInt32( pData, m_fcSttbfRMark );
6590 Set_UInt32( pData, m_lcbSttbfRMark );
6591 Set_UInt32( pData, m_fcSttbfCaption );
6592 Set_UInt32( pData, m_lcbSttbfCaption );
6593 Set_UInt32( pData, m_fcSttbAutoCaption );
6594 Set_UInt32( pData, m_lcbSttbAutoCaption );
6595 Set_UInt32( pData, m_fcPlcfwkb );
6596 Set_UInt32( pData, m_lcbPlcfwkb );
6597 Set_UInt32( pData, m_fcPlcfspl ); // in Ver67 empty reserve
6598 Set_UInt32( pData, m_lcbPlcfspl ); // in Ver67 empty reserve
6599 Set_UInt32( pData, m_fcPlcftxbxText );
6600 Set_UInt32( pData, m_lcbPlcftxbxText );
6601 Set_UInt32( pData, m_fcPlcffldTxbx );
6602 Set_UInt32( pData, m_lcbPlcffldTxbx );
6603 Set_UInt32( pData, m_fcPlcfHdrtxbxText );
6604 Set_UInt32( pData, m_lcbPlcfHdrtxbxText );
6605 Set_UInt32( pData, m_fcPlcffldHdrTxbx );
6606 Set_UInt32( pData, m_lcbPlcffldHdrTxbx );
6608 if( bVer8 )
6610 pData += 0x2da - 0x27a; // Pos + Offset (fcPlcfLst - fcStwUser)
6611 Set_UInt32( pData, m_fcSttbFnm);
6612 Set_UInt32( pData, m_lcbSttbFnm);
6613 Set_UInt32( pData, m_fcPlcfLst );
6614 Set_UInt32( pData, m_lcbPlcfLst );
6615 Set_UInt32( pData, m_fcPlfLfo );
6616 Set_UInt32( pData, m_lcbPlfLfo );
6617 Set_UInt32( pData, m_fcPlcftxbxBkd );
6618 Set_UInt32( pData, m_lcbPlcftxbxBkd );
6619 Set_UInt32( pData, m_fcPlcfHdrtxbxBkd );
6620 Set_UInt32( pData, m_lcbPlcfHdrtxbxBkd );
6622 pData += 0x372 - 0x302; // Pos + Offset (fcSttbListNames - fcDocUndo)
6623 Set_UInt32( pData, m_fcSttbListNames );
6624 Set_UInt32( pData, m_lcbSttbListNames );
6626 pData += 0x382 - 0x37A;
6627 Set_UInt32( pData, m_fcPlcfTch );
6628 Set_UInt32( pData, m_lcbPlcfTch );
6630 pData += 0x3FA - 0x38A;
6631 Set_UInt16( pData, sal_uInt16(0x0002));
6632 Set_UInt16( pData, sal_uInt16(0x00D9));
6634 pData += 0x41A - 0x3FE;
6635 Set_UInt32( pData, m_fcAtrdExtra );
6636 Set_UInt32( pData, m_lcbAtrdExtra );
6638 pData += 0x42a - 0x422;
6639 Set_UInt32(pData, m_fcSttbfBkmkFactoid);
6640 Set_UInt32(pData, m_lcbSttbfBkmkFactoid);
6641 Set_UInt32(pData, m_fcPlcfBkfFactoid);
6642 Set_UInt32(pData, m_lcbPlcfBkfFactoid);
6644 pData += 0x442 - 0x43A;
6645 Set_UInt32(pData, m_fcPlcfBklFactoid);
6646 Set_UInt32(pData, m_lcbPlcfBklFactoid);
6647 Set_UInt32(pData, m_fcFactoidData);
6648 Set_UInt32(pData, m_lcbFactoidData);
6650 pData += 0x4BA - 0x452;
6651 Set_UInt32(pData, m_fcPlcffactoid);
6652 Set_UInt32(pData, m_lcbPlcffactoid);
6654 pData += 0x4DA - 0x4c2;
6655 Set_UInt32( pData, m_fcHplxsdr );
6656 Set_UInt32( pData, 0);
6659 rStrm.WriteBytes(pDataPtr.get(), m_fcMin - nUnencryptedHdr);
6662 rtl_TextEncoding WW8Fib::GetFIBCharset(sal_uInt16 chs, LanguageType nLidLocale)
6664 OSL_ENSURE(chs <= 0x100, "overflowed winword charset set");
6665 if (chs == 0x0100)
6666 return RTL_TEXTENCODING_APPLE_ROMAN;
6667 if (chs == 0 && static_cast<sal_uInt16>(nLidLocale) >= 999)
6670 nLidLocale:
6671 language stamp -- localized version In pre-WinWord 2.0 files this
6672 value was the nLocale. If value is < 999, then it is the nLocale,
6673 otherwise it is the lid.
6675 css::lang::Locale aLocale(LanguageTag::convertToLocale(nLidLocale));
6676 return msfilter::util::getBestTextEncodingFromLocale(aLocale);
6678 return rtl_getTextEncodingFromWindowsCharset(static_cast<sal_uInt8>(chs));
6681 MSOFactoidType::MSOFactoidType()
6682 : m_nId(0)
6686 namespace MSOPBString
6688 static OUString Read(SvStream& rStream)
6690 OUString aRet;
6692 sal_uInt16 nBuf(0);
6693 rStream.ReadUInt16(nBuf);
6694 sal_uInt16 nCch = nBuf & 0x7fff; // Bits 1..15.
6695 bool bAnsiString = (nBuf & (1 << 15)) >> 15; // 16th bit.
6696 if (bAnsiString)
6697 aRet = OStringToOUString(read_uInt8s_ToOString(rStream, nCch), RTL_TEXTENCODING_ASCII_US);
6698 else
6699 aRet = read_uInt16s_ToOUString(rStream, nCch);
6701 return aRet;
6704 static void Write(const OUString& rString, SvStream& rStream)
6706 sal_uInt16 nBuf = 0;
6707 nBuf |= rString.getLength(); // cch, 0..14th bits.
6708 nBuf |= 0x8000; // fAnsiString, 15th bit.
6709 rStream.WriteUInt16(nBuf);
6710 SwWW8Writer::WriteString8(rStream, rString, false, RTL_TEXTENCODING_ASCII_US);
6714 void MSOFactoidType::Read(SvStream& rStream)
6716 sal_uInt32 cbFactoid(0);
6717 rStream.ReadUInt32(cbFactoid);
6718 rStream.ReadUInt32(m_nId);
6719 m_aUri = MSOPBString::Read(rStream);
6720 m_aTag = MSOPBString::Read(rStream);
6721 MSOPBString::Read(rStream); // rgbDownloadURL
6724 void MSOFactoidType::Write(WW8Export& rExport)
6726 SvStream& rStream = *rExport.pTableStrm;
6728 SvMemoryStream aStream;
6729 aStream.WriteUInt32(m_nId); // id
6730 MSOPBString::Write(m_aUri, aStream);
6731 MSOPBString::Write(m_aTag, aStream);
6732 MSOPBString::Write("", aStream); // rgbDownloadURL
6733 rStream.WriteUInt32(aStream.Tell());
6734 aStream.Seek(0);
6735 rStream.WriteStream(aStream);
6738 void MSOPropertyBagStore::Read(SvStream& rStream)
6740 sal_uInt32 cFactoidType(0);
6741 rStream.ReadUInt32(cFactoidType);
6742 for (sal_uInt32 i = 0; i < cFactoidType && rStream.good(); ++i)
6744 MSOFactoidType aFactoidType;
6745 aFactoidType.Read(rStream);
6746 m_aFactoidTypes.push_back(aFactoidType);
6748 sal_uInt16 cbHdr(0);
6749 rStream.ReadUInt16(cbHdr);
6750 SAL_WARN_IF(cbHdr != 0xc, "sw.ww8", "MSOPropertyBagStore::Read: unexpected cbHdr");
6751 sal_uInt16 nVer(0);
6752 rStream.ReadUInt16(nVer);
6753 SAL_WARN_IF(nVer != 0x0100, "sw.ww8", "MSOPropertyBagStore::Read: unexpected nVer");
6754 rStream.SeekRel(4); // cfactoid
6755 sal_uInt32 nCste(0);
6756 rStream.ReadUInt32(nCste);
6758 //each string has a 2 byte len record at the start
6759 const size_t nMaxPossibleRecords = rStream.remainingSize() / sizeof(sal_uInt16);
6760 if (nCste > nMaxPossibleRecords)
6762 SAL_WARN("sw.ww8", nCste << " records claimed, but max possible is " << nMaxPossibleRecords);
6763 nCste = nMaxPossibleRecords;
6766 for (sal_uInt32 i = 0; i < nCste; ++i)
6768 OUString aString = MSOPBString::Read(rStream);
6769 m_aStringTable.push_back(aString);
6773 void MSOPropertyBagStore::Write(WW8Export& rExport)
6775 SvStream& rStream = *rExport.pTableStrm;
6776 rStream.WriteUInt32(m_aFactoidTypes.size()); // cFactoidType
6777 for (MSOFactoidType& rType : m_aFactoidTypes)
6778 rType.Write(rExport);
6779 rStream.WriteUInt16(0xc); // cbHdr
6780 rStream.WriteUInt16(0x0100); // sVer
6781 rStream.WriteUInt32(0); // cfactoid
6782 rStream.WriteUInt32(m_aStringTable.size()); // cste
6783 for (const OUString& rString : m_aStringTable)
6784 MSOPBString::Write(rString, rStream);
6787 MSOProperty::MSOProperty()
6788 : m_nKey(0)
6789 , m_nValue(0)
6793 void MSOProperty::Read(SvStream& rStream)
6795 rStream.ReadUInt32(m_nKey);
6796 rStream.ReadUInt32(m_nValue);
6799 void MSOProperty::Write(SvStream& rStream)
6801 rStream.WriteUInt32(m_nKey);
6802 rStream.WriteUInt32(m_nValue);
6805 MSOPropertyBag::MSOPropertyBag()
6806 : m_nId(0)
6810 bool MSOPropertyBag::Read(SvStream& rStream)
6812 rStream.ReadUInt16(m_nId);
6813 sal_uInt16 cProp(0);
6814 rStream.ReadUInt16(cProp);
6815 if (!rStream.good())
6816 return false;
6817 rStream.SeekRel(2); // cbUnknown
6818 //each MSOProperty is 8 bytes in size
6819 const size_t nMaxPossibleRecords = rStream.remainingSize() / 8;
6820 if (cProp > nMaxPossibleRecords)
6822 SAL_WARN("sw.ww8", cProp << " records claimed, but max possible is " << nMaxPossibleRecords);
6823 cProp = nMaxPossibleRecords;
6825 for (sal_uInt16 i = 0; i < cProp && rStream.good(); ++i)
6827 MSOProperty aProperty;
6828 aProperty.Read(rStream);
6829 m_aProperties.push_back(aProperty);
6831 return rStream.good();
6834 void MSOPropertyBag::Write(WW8Export& rExport)
6836 SvStream& rStream = *rExport.pTableStrm;
6837 rStream.WriteUInt16(m_nId);
6838 rStream.WriteUInt16(m_aProperties.size());
6839 rStream.WriteUInt16(0); // cbUnknown
6840 for (MSOProperty& rProperty : m_aProperties)
6841 rProperty.Write(rStream);
6844 void WW8SmartTagData::Read(SvStream& rStream, WW8_FC fcFactoidData, sal_uInt32 lcbFactoidData)
6846 sal_uInt64 nOldPosition = rStream.Tell();
6847 if (!checkSeek(rStream, fcFactoidData))
6848 return;
6850 m_aPropBagStore.Read(rStream);
6851 while (rStream.good() && rStream.Tell() < fcFactoidData + lcbFactoidData)
6853 MSOPropertyBag aPropertyBag;
6854 if (!aPropertyBag.Read(rStream))
6855 break;
6856 m_aPropBags.push_back(aPropertyBag);
6859 rStream.Seek(nOldPosition);
6862 void WW8SmartTagData::Write(WW8Export& rExport)
6864 m_aPropBagStore.Write(rExport);
6865 for (MSOPropertyBag& rPropertyBag : m_aPropBags)
6866 rPropertyBag.Write(rExport);
6869 WW8Style::WW8Style(SvStream& rStream, WW8Fib& rFibPara)
6870 : m_rFib(rFibPara), m_rStream(rStream), m_cstd(0), m_cbSTDBaseInFile(0), m_fStdStylenamesWritten(0)
6871 , m_stiMaxWhenSaved(0), m_istdMaxFixedWhenSaved(0), m_nVerBuiltInNamesWhenSaved(0)
6872 , m_ftcAsci(0), m_ftcFE(0), m_ftcOther(0), m_ftcBi(0)
6874 if (!checkSeek(m_rStream, m_rFib.m_fcStshf))
6875 return;
6877 sal_uInt16 cbStshi = 0; // 2 bytes size of the following STSHI structure
6878 sal_uInt32 nRemaining = m_rFib.m_lcbStshf;
6879 const sal_uInt32 nMinValidStshi = 4;
6881 if (m_rFib.GetFIBVersion() <= ww::eWW2)
6883 cbStshi = 0;
6884 m_cstd = 256;
6886 else
6888 if (m_rFib.m_nFib < 67) // old Version ? (need to find this again to fix)
6889 cbStshi = nMinValidStshi;
6890 else // new version
6892 if (nRemaining < sizeof(cbStshi))
6893 return;
6894 // reads the length of the structure in the file
6895 m_rStream.ReadUInt16( cbStshi );
6896 nRemaining-=2;
6900 cbStshi = std::min(static_cast<sal_uInt32>(cbStshi), nRemaining);
6901 if (cbStshi < nMinValidStshi)
6902 return;
6904 const sal_uInt16 nRead = cbStshi;
6907 m_rStream.ReadUInt16( m_cstd );
6909 m_rStream.ReadUInt16( m_cbSTDBaseInFile );
6911 if( 6 > nRead ) break;
6913 sal_uInt16 a16Bit;
6914 m_rStream.ReadUInt16( a16Bit );
6915 m_fStdStylenamesWritten = a16Bit & 0x0001;
6917 if( 8 > nRead ) break;
6918 m_rStream.ReadUInt16( m_stiMaxWhenSaved );
6920 if( 10 > nRead ) break;
6921 m_rStream.ReadUInt16( m_istdMaxFixedWhenSaved );
6923 if( 12 > nRead ) break;
6924 m_rStream.ReadUInt16( m_nVerBuiltInNamesWhenSaved );
6926 if( 14 > nRead ) break;
6927 m_rStream.ReadUInt16( m_ftcAsci );
6929 if( 16 > nRead ) break;
6930 m_rStream.ReadUInt16( m_ftcFE );
6932 if ( 18 > nRead ) break;
6933 m_rStream.ReadUInt16( m_ftcOther );
6935 m_ftcBi = m_ftcOther;
6937 if ( 20 > nRead ) break;
6938 m_rStream.ReadUInt16( m_ftcBi );
6940 // p.r.n. ignore the rest
6941 if( 20 < nRead )
6942 m_rStream.SeekRel( nRead-20 );
6944 while( false ); // trick: the block above will be passed through exactly one time
6945 // and that's why we can early exit with "break".
6947 nRemaining -= cbStshi;
6949 //There will be stshi.cstd (cbSTD, STD) pairs in the file following the
6950 //STSHI. Note that styles can be empty, i.e. cbSTD == 0
6951 const sal_uInt32 nMinRecordSize = sizeof(sal_uInt16);
6952 const sal_uInt16 nMaxPossibleRecords = nRemaining/nMinRecordSize;
6954 OSL_ENSURE(m_cstd <= nMaxPossibleRecords,
6955 "allegedly more styles that available data");
6956 m_cstd = std::min(m_cstd, nMaxPossibleRecords);
6959 // Read1STDFixed() reads a style. If the style is completely existent,
6960 // so it has no empty slot, we should allocate memory and a pointer should
6961 // reference to STD (perhaps filled with 0). If the slot is empty,
6962 // it will return a null pointer.
6963 std::unique_ptr<WW8_STD> WW8Style::Read1STDFixed(sal_uInt16& rSkip)
6965 std::unique_ptr<WW8_STD> pStd;
6967 sal_uInt16 cbStd(0);
6968 m_rStream.ReadUInt16(cbStd); // read length
6970 const sal_uInt16 nRead = m_cbSTDBaseInFile;
6971 if( cbStd >= m_cbSTDBaseInFile )
6973 // Fixed part completely available
6975 // read fixed part of STD
6976 pStd.reset(new WW8_STD);
6977 memset( pStd.get(), 0, sizeof( *pStd ) );
6981 if( 2 > nRead ) break;
6983 sal_uInt16 a16Bit = 0;
6984 m_rStream.ReadUInt16( a16Bit );
6985 pStd->sti = a16Bit & 0x0fff ;
6986 pStd->fScratch = sal_uInt16(0 != ( a16Bit & 0x1000 ));
6987 pStd->fInvalHeight = sal_uInt16(0 != ( a16Bit & 0x2000 ));
6988 pStd->fHasUpe = sal_uInt16(0 != ( a16Bit & 0x4000 ));
6989 pStd->fMassCopy = sal_uInt16(0 != ( a16Bit & 0x8000 ));
6991 if( 4 > nRead ) break;
6992 a16Bit = 0;
6993 m_rStream.ReadUInt16( a16Bit );
6994 pStd->sgc = a16Bit & 0x000f ;
6995 pStd->istdBase = ( a16Bit & 0xfff0 ) >> 4;
6997 if( 6 > nRead ) break;
6998 a16Bit = 0;
6999 m_rStream.ReadUInt16( a16Bit );
7000 pStd->cupx = a16Bit & 0x000f ;
7001 pStd->istdNext = ( a16Bit & 0xfff0 ) >> 4;
7003 if( 8 > nRead ) break;
7004 m_rStream.ReadUInt16( pStd->bchUpe );
7006 // from Ver8 this two fields should be added:
7007 if(10 > nRead ) break;
7008 a16Bit = 0;
7009 m_rStream.ReadUInt16( a16Bit );
7010 pStd->fAutoRedef = a16Bit & 0x0001 ;
7011 pStd->fHidden = ( a16Bit & 0x0002 ) >> 1;
7012 // You never know: cautionary skipped
7013 if (nRead > 10)
7015 auto nSkip = std::min<sal_uInt64>(nRead - 10, m_rStream.remainingSize());
7016 m_rStream.Seek(m_rStream.Tell() + nSkip);
7019 while( false ); // trick: the block above will passed through exactly one time
7020 // and can be left early with a "break"
7022 if (!m_rStream.good() || !nRead)
7024 pStd.reset(); // report error with NULL
7027 rSkip = cbStd - m_cbSTDBaseInFile;
7029 else
7030 { // Fixed part too short
7031 if( cbStd )
7032 m_rStream.SeekRel( cbStd ); // skip leftovers
7033 rSkip = 0;
7035 return pStd;
7038 std::unique_ptr<WW8_STD> WW8Style::Read1Style(sal_uInt16& rSkip, OUString* pString)
7040 // Attention: MacWord-Documents have their Stylenames
7041 // always in ANSI, even if eStructCharSet == CHARSET_MAC !!
7043 std::unique_ptr<WW8_STD> pStd = Read1STDFixed(rSkip); // read STD
7045 // string desired?
7046 if( pString )
7047 { // real style?
7048 if ( pStd )
7050 sal_Int32 nLenStringBytes = 0;
7051 switch( m_rFib.m_nVersion )
7053 case 6:
7054 case 7:
7055 // read pascal string
7056 *pString = read_uInt8_BeltAndBracesString(m_rStream, RTL_TEXTENCODING_MS_1252);
7057 // leading len and trailing zero --> 2
7058 nLenStringBytes = pString->getLength() + 2;
7059 break;
7060 case 8:
7061 // handle Unicode-String with leading length short and
7062 // trailing zero
7063 if (TestBeltAndBraces(m_rStream))
7065 *pString = read_uInt16_BeltAndBracesString(m_rStream);
7066 nLenStringBytes = (pString->getLength() + 2) * 2;
7068 else
7071 #i8114#
7072 This is supposed to be impossible, it's just supposed
7073 to be 16 bit count followed by the string and ending
7074 in a 0 short. But "Lotus SmartSuite Product: Word Pro"
7075 is creating invalid style names in ww7- format. So we
7076 use the belt and braces of the ms strings to see if
7077 they are not corrupt. If they are then we try them as
7078 8bit ones
7080 *pString = read_uInt8_BeltAndBracesString(m_rStream,RTL_TEXTENCODING_MS_1252);
7081 // leading len and trailing zero --> 2
7082 nLenStringBytes = pString->getLength() + 2;
7084 break;
7085 default:
7086 OSL_ENSURE(false, "It was forgotten to code nVersion!");
7087 break;
7089 if (nLenStringBytes > rSkip)
7091 SAL_WARN("sw.ww8", "WW8Style structure corrupt");
7092 nLenStringBytes = rSkip;
7094 rSkip -= nLenStringBytes;
7096 else
7097 pString->clear(); // can not return a name
7099 return pStd;
7102 namespace {
7103 const sal_uInt16 maxStrSize = 65;
7105 struct WW8_FFN_Ver6
7107 WW8_FFN_BASE base;
7108 // from Ver6
7109 char szFfn[maxStrSize]; // 0x6 or 0x40 from Ver8 on zero terminated string that
7110 // records name of font.
7111 // Maximal size of szFfn is 65 characters.
7112 // Attention: This array can also be smaller!!!
7113 // Possibly followed by a second sz which records the
7114 // name of an alternate font to use if the first named
7115 // font does not exist on this system.
7120 // #i43762# check font name for illegal characters
7121 static void lcl_checkFontname( OUString& sString )
7123 // for efficiency, we'd like to use String methods as far as possible.
7124 // Hence, we will:
7125 // 1) convert all invalid chars to \u0001
7126 // 2) then erase all \u0001 chars (if anywhere found), and
7127 // 3) erase leading/trailing ';', in case a font name was
7128 // completely removed
7130 // convert all invalid chars to \u0001
7131 OUStringBuffer aBuf(sString);
7132 const sal_Int32 nLen = aBuf.getLength();
7133 bool bFound = false;
7134 for ( sal_Int32 n = 0; n < nLen; ++n )
7136 if ( aBuf[n] < 0x20 )
7138 aBuf[n] = 1;
7139 bFound = true;
7142 sString = aBuf.makeStringAndClear();
7144 // if anything was found, remove \u0001 + leading/trailing ';'
7145 if( bFound )
7147 sString = comphelper::string::strip(sString.replaceAll("\001", ""), ';');
7151 namespace
7153 sal_uInt16 calcMaxFonts(sal_uInt8 *p, sal_Int32 nFFn)
7155 // Figure out the max number of fonts defined here
7156 sal_uInt16 nMax = 0;
7157 sal_Int32 nRemaining = nFFn;
7158 while (nRemaining)
7160 //p[0] is cbFfnM1, the alleged total length of FFN - 1.
7161 //i.e. length after cbFfnM1
7162 const sal_uInt16 cbFfnM1 = *p++;
7163 --nRemaining;
7165 if (cbFfnM1 > nRemaining)
7166 break;
7168 nMax++;
7169 nRemaining -= cbFfnM1;
7170 p += cbFfnM1;
7172 return nMax;
7175 template<typename T> bool readU8(
7176 sal_uInt8 const * p, std::size_t offset, sal_uInt8 const * pEnd,
7177 T * value)
7179 assert(p <= pEnd);
7180 assert(value != nullptr);
7181 if (offset >= o3tl::make_unsigned(pEnd - p)) {
7182 return false;
7184 *value = p[offset];
7185 return true;
7188 bool readS16(
7189 sal_uInt8 const * p, std::size_t offset, sal_uInt8 const * pEnd,
7190 short * value)
7192 assert(p <= pEnd);
7193 assert(value != nullptr);
7194 if (offset > o3tl::make_unsigned(pEnd - p)
7195 || static_cast<std::size_t>(pEnd - p) - offset < 2)
7197 return false;
7199 *value = unsigned(p[offset]) + (unsigned(p[offset + 1]) << 8);
7200 return true;
7203 sal_Int32 getStringLength(
7204 sal_uInt8 const * p, std::size_t offset, sal_uInt8 const * pEnd)
7206 assert(p <= pEnd);
7207 assert(pEnd - p <= SAL_MAX_INT32);
7208 if (offset >= o3tl::make_unsigned(pEnd - p)) {
7209 return -1;
7211 void const * p2 = std::memchr(
7212 p + offset, 0, static_cast<std::size_t>(pEnd - p) - offset);
7213 if (p2 == nullptr) {
7214 return -1;
7216 return static_cast<sal_uInt8 const *>(p2) - (p + offset);
7220 WW8Fonts::WW8Fonts( SvStream& rSt, WW8Fib const & rFib )
7222 // Attention: MacWord-Documents have their Fontnames
7223 // always in ANSI, even if eStructCharSet == CHARSET_MAC !!
7224 if( rFib.m_lcbSttbfffn <= 2 )
7226 OSL_ENSURE( false, "font table is broken! (rFib.lcbSttbfffn < 2)" );
7227 return;
7230 if (!checkSeek(rSt, rFib.m_fcSttbfffn))
7231 return;
7233 sal_Int32 nFFn = rFib.m_lcbSttbfffn - 2;
7235 const sal_uInt64 nMaxPossible = rSt.remainingSize();
7236 if (o3tl::make_unsigned(nFFn) > nMaxPossible)
7238 SAL_WARN("sw.ww8", "FFN structure longer than available data");
7239 nFFn = nMaxPossible;
7242 // allocate Font Array
7243 std::vector<sal_uInt8> aA(nFFn);
7244 memset(aA.data(), 0, nFFn);
7246 ww::WordVersion eVersion = rFib.GetFIBVersion();
7248 sal_uInt16 nMax(0);
7249 if( eVersion >= ww::eWW8 )
7251 // bVer8: read the count of strings in nMax
7252 rSt.ReadUInt16(nMax);
7255 // Ver8: skip undefined uint16
7256 // Ver67: skip the herein stored total byte of structure
7257 // - we already got that information in rFib.lcbSttbfffn
7258 rSt.SeekRel( 2 );
7260 // read all font information
7261 nFFn = rSt.ReadBytes(aA.data(), nFFn);
7262 sal_uInt8 * const pEnd = aA.data() + nFFn;
7263 const sal_uInt16 nCalcMax = calcMaxFonts(aA.data(), nFFn);
7265 if (eVersion < ww::eWW8)
7266 nMax = nCalcMax;
7267 else
7269 //newer versions include supportive count of fonts, so take min of that
7270 //and calced max
7271 nMax = std::min(nMax, nCalcMax);
7274 if (nMax)
7276 // allocate Index Array
7277 m_aFontA.resize(nMax);
7278 WW8_FFN* p = m_aFontA.data();
7280 if( eVersion <= ww::eWW2 )
7282 sal_uInt8 const * pVer2 = aA.data();
7283 sal_uInt16 i = 0;
7284 for(; i<nMax; ++i, ++p)
7286 if (!readU8(
7287 pVer2, offsetof(WW8_FFN_BASE, cbFfnM1), pEnd,
7288 &p->aFFNBase.cbFfnM1))
7290 break;
7293 p->aFFNBase.prg = 0;
7294 p->aFFNBase.fTrueType = 0;
7295 p->aFFNBase.ff = 0;
7297 if (!(readU8(pVer2, 1, pEnd, &p->aFFNBase.wWeight)
7298 && readU8(pVer2, 2, pEnd, &p->aFFNBase.chs)))
7300 break;
7303 #i8726# 7- seems to encode the name in the same encoding as
7304 the font, e.g load the doc in 97 and save to see the unicode
7305 ver of the asian fontnames in that example to confirm.
7307 rtl_TextEncoding eEnc = WW8Fib::GetFIBCharset(p->aFFNBase.chs, rFib.m_lid);
7308 if ((eEnc == RTL_TEXTENCODING_SYMBOL) || (eEnc == RTL_TEXTENCODING_DONTKNOW))
7309 eEnc = RTL_TEXTENCODING_MS_1252;
7311 sal_Int32 n = getStringLength(pVer2, 1 + 2, pEnd);
7312 if (n == -1) {
7313 break;
7315 p->sFontname = OUString(
7316 reinterpret_cast<char const *>(pVer2 + 1 + 2), n, eEnc);
7317 pVer2 = pVer2 + p->aFFNBase.cbFfnM1 + 1;
7319 nMax = i;
7321 else if( eVersion < ww::eWW8 )
7323 sal_uInt8 const * pVer6 = aA.data();
7324 sal_uInt16 i = 0;
7325 for(; i<nMax; ++i, ++p)
7327 if (!readU8(
7328 pVer6, offsetof(WW8_FFN_BASE, cbFfnM1), pEnd,
7329 &p->aFFNBase.cbFfnM1))
7331 break;
7333 sal_uInt8 c2;
7334 if (!readU8(pVer6, 1, pEnd, &c2)) {
7335 break;
7338 p->aFFNBase.prg = c2 & 0x02;
7339 p->aFFNBase.fTrueType = (c2 & 0x04) >> 2;
7340 // skip a reserve bit
7341 p->aFFNBase.ff = (c2 & 0x70) >> 4;
7343 if (!(readS16(
7344 pVer6, offsetof(WW8_FFN_BASE, wWeight), pEnd,
7345 &p->aFFNBase.wWeight)
7346 && readU8(
7347 pVer6, offsetof(WW8_FFN_BASE, chs), pEnd, &p->aFFNBase.chs)
7348 && readU8(
7349 pVer6, offsetof(WW8_FFN_BASE, ibszAlt), pEnd,
7350 &p->aFFNBase.ibszAlt)))
7352 break;
7355 #i8726# 7- seems to encode the name in the same encoding as
7356 the font, e.g load the doc in 97 and save to see the unicode
7357 ver of the asian fontnames in that example to confirm.
7359 rtl_TextEncoding eEnc = WW8Fib::GetFIBCharset(p->aFFNBase.chs, rFib.m_lid);
7360 if ((eEnc == RTL_TEXTENCODING_SYMBOL) || (eEnc == RTL_TEXTENCODING_DONTKNOW))
7361 eEnc = RTL_TEXTENCODING_MS_1252;
7362 sal_Int32 n = getStringLength(
7363 pVer6, offsetof(WW8_FFN_Ver6, szFfn), pEnd);
7364 if (n == -1) {
7365 break;
7367 p->sFontname = OUString(
7368 reinterpret_cast<char const *>(
7369 pVer6 + offsetof(WW8_FFN_Ver6, szFfn)),
7370 n, eEnc);
7371 if (p->aFFNBase.ibszAlt && p->aFFNBase.ibszAlt < maxStrSize) //don't start after end of string
7373 n = getStringLength(
7374 pVer6, offsetof(WW8_FFN_Ver6, szFfn) + p->aFFNBase.ibszAlt,
7375 pEnd);
7376 if (n == -1) {
7377 break;
7379 p->sFontname += ";" + OUString(
7380 reinterpret_cast<char const *>(
7381 pVer6 + offsetof(WW8_FFN_Ver6, szFfn) + p->aFFNBase.ibszAlt),
7382 n, eEnc);
7384 else
7386 //#i18369# if it's a symbol font set Symbol as fallback
7387 if (
7388 RTL_TEXTENCODING_SYMBOL == WW8Fib::GetFIBCharset(p->aFFNBase.chs, rFib.m_lid)
7389 && p->sFontname!="Symbol"
7392 p->sFontname += ";Symbol";
7395 pVer6 = pVer6 + p->aFFNBase.cbFfnM1 + 1;
7397 nMax = i;
7399 else
7401 //count of bytes in minimum FontFamilyInformation payload
7402 const sal_uInt8 cbMinFFNPayload = 41;
7403 sal_uInt16 nValidFonts = 0;
7404 sal_Int32 nRemainingFFn = nFFn;
7405 sal_uInt8* pRaw = aA.data();
7406 for (sal_uInt16 i=0; i < nMax && nRemainingFFn; ++i, ++p)
7408 //pRaw[0] is cbFfnM1, the alleged total length of FFN - 1
7409 //i.e. length after cbFfnM1
7410 sal_uInt8 cbFfnM1 = *pRaw++;
7411 --nRemainingFFn;
7413 if (cbFfnM1 > nRemainingFFn)
7414 break;
7416 if (cbFfnM1 < cbMinFFNPayload)
7417 break;
7419 p->aFFNBase.cbFfnM1 = cbFfnM1;
7421 sal_uInt8 *pVer8 = pRaw;
7423 sal_uInt8 c2 = *pVer8++;
7424 --cbFfnM1;
7426 p->aFFNBase.prg = c2 & 0x02;
7427 p->aFFNBase.fTrueType = (c2 & 0x04) >> 2;
7428 // skip a reserve bit
7429 p->aFFNBase.ff = (c2 & 0x70) >> 4;
7431 p->aFFNBase.wWeight = SVBT16ToUInt16(*reinterpret_cast<SVBT16*>(pVer8));
7432 pVer8+=2;
7433 cbFfnM1-=2;
7435 p->aFFNBase.chs = *pVer8++;
7436 --cbFfnM1;
7438 p->aFFNBase.ibszAlt = *pVer8++;
7439 --cbFfnM1;
7441 pVer8 += 10; //PANOSE
7442 cbFfnM1-=10;
7443 pVer8 += 24; //FONTSIGNATURE
7444 cbFfnM1-=24;
7446 assert(cbFfnM1 >= 2);
7448 sal_uInt8 nMaxNullTerminatedPossible = cbFfnM1/2 - 1;
7449 sal_Unicode *pPrimary = reinterpret_cast<sal_Unicode*>(pVer8);
7450 pPrimary[nMaxNullTerminatedPossible] = 0;
7451 #ifdef OSL_BIGENDIAN
7452 swapEndian(pPrimary);
7453 #endif
7454 p->sFontname = pPrimary;
7455 if (p->aFFNBase.ibszAlt && p->aFFNBase.ibszAlt < nMaxNullTerminatedPossible)
7457 sal_Unicode *pSecondary = pPrimary + p->aFFNBase.ibszAlt;
7458 #ifdef OSL_BIGENDIAN
7459 swapEndian(pSecondary);
7460 #endif
7461 p->sFontname += OUStringLiteral(u";") + pSecondary;
7464 // #i43762# check font name for illegal characters
7465 lcl_checkFontname( p->sFontname );
7467 // set pointer one font back to original array
7468 pRaw += p->aFFNBase.cbFfnM1;
7469 nRemainingFFn -= p->aFFNBase.cbFfnM1;
7470 ++nValidFonts;
7472 OSL_ENSURE(nMax == nValidFonts, "Font count differs with availability");
7473 nMax = std::min(nMax, nValidFonts);
7476 m_aFontA.resize(nMax);
7477 m_aFontA.shrink_to_fit();
7480 const WW8_FFN* WW8Fonts::GetFont( sal_uInt16 nNum ) const
7482 if (nNum >= m_aFontA.size())
7483 return nullptr;
7485 return &m_aFontA[nNum];
7488 // Search after a header/footer for an index in the ww list from header/footer
7490 // specials for WinWord6 and -7:
7492 // 1) At the start of reading we must build WWPLCF_HdFt with Fib and Dop
7493 // 2) The main text must be read sequentially over all sections
7494 // 3) For every header/footer in the main text, we must call UpdateIndex()
7495 // exactly once with the parameter from the attribute.
7496 // (per section can be maximally one). This call must take place *after*
7497 // the last call from GetTextPos().
7498 // 4) GetTextPos() can be called with exactly one flag
7499 // out of WW8_{FOOTER,HEADER}_{ODD,EVEN,FIRST} (Do not change!)
7500 // -> maybe we can get a right result then
7502 WW8PLCF_HdFt::WW8PLCF_HdFt( SvStream* pSt, WW8Fib const & rFib, WW8Dop const & rDop )
7503 : aPLCF(*pSt, rFib.m_fcPlcfhdd , rFib.m_lcbPlcfhdd , 0)
7505 nIdxOffset = 0;
7508 This dop.grpfIhdt has a bit set for each special
7509 footnote *and endnote!!* separator,continuation separator, and
7510 continuation notice entry, the documentation does not mention the
7511 endnote separators, the documentation also gets the index numbers
7512 backwards when specifying which bits to test. The bottom six bits
7513 of this value must be tested and skipped over. Each section's
7514 grpfIhdt is then tested for the existence of the appropriate headers
7515 and footers, at the end of each section the nIdxOffset must be updated
7516 to point to the beginning of the next section's group of headers and
7517 footers in this PLCF, UpdateIndex does that task.
7519 for( sal_uInt8 nI = 0x1; nI <= 0x20; nI <<= 1 )
7520 if( nI & rDop.grpfIhdt ) // bit set?
7521 nIdxOffset++;
7524 bool WW8PLCF_HdFt::GetTextPos(sal_uInt8 grpfIhdt, sal_uInt8 nWhich, WW8_CP& rStart,
7525 WW8_CP& rLen)
7527 sal_uInt8 nI = 0x01;
7528 short nIdx = nIdxOffset;
7529 while (true)
7531 if( nI & nWhich )
7532 break; // found
7533 if( grpfIhdt & nI )
7534 nIdx++; // uninteresting Header / Footer
7535 nI <<= 1; // text next bit
7536 if( nI > 0x20 )
7537 return false; // not found
7539 // nIdx is HdFt-Index
7540 WW8_CP nEnd;
7541 void* pData;
7543 aPLCF.SetIdx( nIdx ); // Lookup suitable CP
7544 aPLCF.Get( rStart, nEnd, pData );
7545 if (nEnd < rStart)
7547 SAL_WARN("sw.ww8", "End " << nEnd << " before Start " << rStart);
7548 return false;
7551 bool bFail = o3tl::checked_sub(nEnd, rStart, rLen);
7552 if (bFail)
7554 SAL_WARN("sw.ww8", "broken offset, ignoring");
7555 return false;
7558 aPLCF.advance();
7560 return true;
7563 void WW8PLCF_HdFt::GetTextPosExact(short nIdx, WW8_CP& rStart, WW8_CP& rLen)
7565 WW8_CP nEnd;
7566 void* pData;
7568 aPLCF.SetIdx( nIdx ); // Lookup suitable CP
7569 aPLCF.Get( rStart, nEnd, pData );
7570 if (nEnd < rStart)
7572 SAL_WARN("sw.ww8", "End " << nEnd << " before Start " << rStart);
7573 rLen = 0;
7574 return;
7576 if (o3tl::checked_sub(nEnd, rStart, rLen))
7578 SAL_WARN("sw.ww8", "GetTextPosExact overflow");
7579 rLen = 0;
7583 void WW8PLCF_HdFt::UpdateIndex( sal_uInt8 grpfIhdt )
7585 // Caution: Description is not correct
7586 for( sal_uInt8 nI = 0x01; nI <= 0x20; nI <<= 1 )
7587 if( nI & grpfIhdt )
7588 nIdxOffset++;
7591 WW8Dop::WW8Dop(SvStream& rSt, sal_Int16 nFib, sal_Int32 nPos, sal_uInt32 nSize):
7592 fFacingPages(false), fWidowControl(false), fPMHMainDoc(false), grfSuppression(0), fpc(0),
7593 grpfIhdt(0), rncFootnote(0), nFootnote(0), fOutlineDirtySave(false), fOnlyMacPics(false),
7594 fOnlyWinPics(false), fLabelDoc(false), fHyphCapitals(false), fAutoHyphen(false),
7595 fFormNoFields(false), fLinkStyles(false), fRevMarking(false), fBackup(false),
7596 fExactCWords(false), fPagHidden(false), fPagResults(false), fLockAtn(false),
7597 fMirrorMargins(false), fReadOnlyRecommended(false), fDfltTrueType(false),
7598 fPagSuppressTopSpacing(false), fProtEnabled(false), fDispFormFieldSel(false), fRMView(false),
7599 fRMPrint(false), fWriteReservation(false), fLockRev(false), fEmbedFonts(false),
7600 copts_fNoTabForInd(false), copts_fNoSpaceRaiseLower(false), copts_fSupressSpbfAfterPgBrk(false),
7601 copts_fWrapTrailSpaces(false), copts_fMapPrintTextColor(false), copts_fNoColumnBalance(false),
7602 copts_fConvMailMergeEsc(false), copts_fSupressTopSpacing(false),
7603 copts_fOrigWordTableRules(false), copts_fTransparentMetafiles(false),
7604 copts_fShowBreaksInFrames(false), copts_fSwapBordersFacingPgs(false), copts_fExpShRtn(false),
7605 rncEdn(0), nEdn(0), epc(0), fPrintFormData(false), fSaveFormData(false), fShadeFormData(false),
7606 fWCFootnoteEdn(false), wvkSaved(0), wScaleSaved(0), zkSaved(0), fRotateFontW6(false),
7607 iGutterPos(false), fNoTabForInd(false), fNoSpaceRaiseLower(false),
7608 fSupressSpbfAfterPageBreak(false), fWrapTrailSpaces(false), fMapPrintTextColor(false),
7609 fNoColumnBalance(false), fConvMailMergeEsc(false), fSupressTopSpacing(false),
7610 fOrigWordTableRules(false), fTransparentMetafiles(false), fShowBreaksInFrames(false),
7611 fSwapBordersFacingPgs(false), fCompatibilityOptions_Unknown1_13(false), fExpShRtn(false),
7612 fCompatibilityOptions_Unknown1_15(false), fCompatibilityOptions_Unknown1_16(false),
7613 fSuppressTopSpacingMac5(false), fTruncDxaExpand(false), fPrintBodyBeforeHdr(false),
7614 fNoLeading(false), fCompatibilityOptions_Unknown1_21(false), fMWSmallCaps(false),
7615 fCompatibilityOptions_Unknown1_23(false), fCompatibilityOptions_Unknown1_24(false),
7616 fCompatibilityOptions_Unknown1_25(false), fCompatibilityOptions_Unknown1_26(false),
7617 fCompatibilityOptions_Unknown1_27(false), fCompatibilityOptions_Unknown1_28(false),
7618 fCompatibilityOptions_Unknown1_29(false), fCompatibilityOptions_Unknown1_30(false),
7619 fCompatibilityOptions_Unknown1_31(false), fUsePrinterMetrics(false), lvl(0), fHtmlDoc(false),
7620 fSnapBorder(false), fIncludeHeader(false), fIncludeFooter(false), fForcePageSizePag(false),
7621 fMinFontSizePag(false), fHaveVersions(false), fAutoVersion(false),
7622 fCompatibilityOptions_Unknown2_1(false), fCompatibilityOptions_Unknown2_2(false),
7623 fDontUseHTMLAutoSpacing(false), fCompatibilityOptions_Unknown2_4(false),
7624 fCompatibilityOptions_Unknown2_5(false), fCompatibilityOptions_Unknown2_6(false),
7625 fCompatibilityOptions_Unknown2_7(false), fCompatibilityOptions_Unknown2_8(false),
7626 fCompatibilityOptions_Unknown2_9(false), fCompatibilityOptions_Unknown2_10(false),
7627 fCompatibilityOptions_Unknown2_11(false), fCompatibilityOptions_Unknown2_12(false),
7628 fCompatibilityOptions_Unknown2_13(false), fCompatibilityOptions_Unknown2_14(false),
7629 fCompatibilityOptions_Unknown2_15(false), fCompatibilityOptions_Unknown2_16(false),
7630 fCompatibilityOptions_Unknown2_17(false), fCompatibilityOptions_Unknown2_18(false),
7631 fCompatibilityOptions_Unknown2_19(false), fCompatibilityOptions_Unknown2_20(false),
7632 fCompatibilityOptions_Unknown2_21(false), fCompatibilityOptions_Unknown2_22(false),
7633 fCompatibilityOptions_Unknown2_23(false), fCompatibilityOptions_Unknown2_24(false),
7634 fCompatibilityOptions_Unknown2_25(false), fCompatibilityOptions_Unknown2_26(false),
7635 fCompatibilityOptions_Unknown2_27(false), fCompatibilityOptions_Unknown2_28(false),
7636 fCompatibilityOptions_Unknown2_29(false), fCompatibilityOptions_Unknown2_30(false),
7637 fCompatibilityOptions_Unknown2_31(false), fCompatibilityOptions_Unknown2_32(false),
7638 fUnknown3(0), fUseBackGroundInAllmodes(false), fDoNotEmbedSystemFont(false), fWordCompat(false),
7639 fLiveRecover(false), fEmbedFactoids(false), fFactoidXML(false), fFactoidAllDone(false),
7640 fFolioPrint(false), fReverseFolio(false), iTextLineEnding(0), fHideFcc(false),
7641 fAcetateShowMarkup(false), fAcetateShowAtn(false), fAcetateShowInsDel(false),
7642 fAcetateShowProps(false)
7643 // in C++20 with P06831R1 "Default member initializers for bit-fields (revision 1)", the
7644 // above bit-field member initializations can be moved to the class definition
7646 fDontUseHTMLAutoSpacing = true; //default
7647 fAcetateShowAtn = true; //default
7648 const sal_uInt32 nMaxDopSize = 0x268;
7649 std::unique_ptr<sal_uInt8[]> pDataPtr( new sal_uInt8[ nMaxDopSize ] );
7650 sal_uInt8* pData = pDataPtr.get();
7652 sal_uInt32 nRead = std::min(nMaxDopSize, nSize);
7653 if (nSize < 2 || !checkSeek(rSt, nPos) || nRead != rSt.ReadBytes(pData, nRead))
7654 nDopError = ERR_SWG_READ_ERROR; // report error
7655 else
7657 if (nMaxDopSize > nRead)
7658 memset( pData + nRead, 0, nMaxDopSize - nRead );
7660 // interpret the data
7661 sal_uInt32 a32Bit;
7662 sal_uInt16 a16Bit;
7663 sal_uInt8 a8Bit;
7665 a16Bit = Get_UShort( pData ); // 0 0x00
7666 fFacingPages = 0 != ( a16Bit & 0x0001 ) ;
7667 fWidowControl = 0 != ( a16Bit & 0x0002 ) ;
7668 fPMHMainDoc = 0 != ( a16Bit & 0x0004 ) ;
7669 grfSuppression = ( a16Bit & 0x0018 ) >> 3;
7670 fpc = ( a16Bit & 0x0060 ) >> 5;
7671 grpfIhdt = ( a16Bit & 0xff00 ) >> 8;
7673 a16Bit = Get_UShort( pData ); // 2 0x02
7674 rncFootnote = a16Bit & 0x0003 ;
7675 nFootnote = ( a16Bit & ~0x0003 ) >> 2 ;
7677 a8Bit = Get_Byte( pData ); // 4 0x04
7678 fOutlineDirtySave = 0 != ( a8Bit & 0x01 );
7680 a8Bit = Get_Byte( pData ); // 5 0x05
7681 fOnlyMacPics = 0 != ( a8Bit & 0x01 );
7682 fOnlyWinPics = 0 != ( a8Bit & 0x02 );
7683 fLabelDoc = 0 != ( a8Bit & 0x04 );
7684 fHyphCapitals = 0 != ( a8Bit & 0x08 );
7685 fAutoHyphen = 0 != ( a8Bit & 0x10 );
7686 fFormNoFields = 0 != ( a8Bit & 0x20 );
7687 fLinkStyles = 0 != ( a8Bit & 0x40 );
7688 fRevMarking = 0 != ( a8Bit & 0x80 );
7690 a8Bit = Get_Byte( pData ); // 6 0x06
7691 fBackup = 0 != ( a8Bit & 0x01 );
7692 fExactCWords = 0 != ( a8Bit & 0x02 );
7693 fPagHidden = 0 != ( a8Bit & 0x04 );
7694 fPagResults = 0 != ( a8Bit & 0x08 );
7695 fLockAtn = 0 != ( a8Bit & 0x10 );
7696 fMirrorMargins = 0 != ( a8Bit & 0x20 );
7697 fReadOnlyRecommended = 0 != ( a8Bit & 0x40 );
7698 fDfltTrueType = 0 != ( a8Bit & 0x80 );
7700 a8Bit = Get_Byte( pData ); // 7 0x07
7701 fPagSuppressTopSpacing = 0 != ( a8Bit & 0x01 );
7702 fProtEnabled = 0 != ( a8Bit & 0x02 );
7703 fDispFormFieldSel = 0 != ( a8Bit & 0x04 );
7704 fRMView = 0 != ( a8Bit & 0x08 );
7705 fRMPrint = 0 != ( a8Bit & 0x10 );
7706 fWriteReservation = 0 != ( a8Bit & 0x20 );
7707 fLockRev = 0 != ( a8Bit & 0x40 );
7708 fEmbedFonts = 0 != ( a8Bit & 0x80 );
7710 a8Bit = Get_Byte( pData ); // 8 0x08
7711 copts_fNoTabForInd = 0 != ( a8Bit & 0x01 );
7712 copts_fNoSpaceRaiseLower = 0 != ( a8Bit & 0x02 );
7713 copts_fSupressSpbfAfterPgBrk = 0 != ( a8Bit & 0x04 );
7714 copts_fWrapTrailSpaces = 0 != ( a8Bit & 0x08 );
7715 copts_fMapPrintTextColor = 0 != ( a8Bit & 0x10 );
7716 copts_fNoColumnBalance = 0 != ( a8Bit & 0x20 );
7717 copts_fConvMailMergeEsc = 0 != ( a8Bit & 0x40 );
7718 copts_fSupressTopSpacing = 0 != ( a8Bit & 0x80 );
7720 a8Bit = Get_Byte( pData ); // 9 0x09
7721 copts_fOrigWordTableRules = 0 != ( a8Bit & 0x01 );
7722 copts_fTransparentMetafiles = 0 != ( a8Bit & 0x02 );
7723 copts_fShowBreaksInFrames = 0 != ( a8Bit & 0x04 );
7724 copts_fSwapBordersFacingPgs = 0 != ( a8Bit & 0x08 );
7725 copts_fExpShRtn = 0 != ( a8Bit & 0x20 ); // #i56856#
7727 dxaTab = Get_Short( pData ); // 10 0x0a
7728 wSpare = Get_UShort( pData ); // 12 0x0c
7729 dxaHotZ = Get_UShort( pData ); // 14 0x0e
7730 cConsecHypLim = Get_UShort( pData ); // 16 0x10
7731 wSpare2 = Get_UShort( pData ); // 18 0x12
7732 dttmCreated = Get_Long( pData ); // 20 0x14
7733 dttmRevised = Get_Long( pData ); // 24 0x18
7734 dttmLastPrint = Get_Long( pData ); // 28 0x1c
7735 nRevision = Get_Short( pData ); // 32 0x20
7736 tmEdited = Get_Long( pData ); // 34 0x22
7737 cWords = Get_Long( pData ); // 38 0x26
7738 cCh = Get_Long( pData ); // 42 0x2a
7739 cPg = Get_Short( pData ); // 46 0x2e
7740 cParas = Get_Long( pData ); // 48 0x30
7742 a16Bit = Get_UShort( pData ); // 52 0x34
7743 rncEdn = a16Bit & 0x0003 ;
7744 nEdn = ( a16Bit & ~0x0003 ) >> 2;
7746 a16Bit = Get_UShort( pData ); // 54 0x36
7747 epc = a16Bit & 0x0003 ;
7748 nfcFootnoteRef = ( a16Bit & 0x003c ) >> 2;
7749 nfcEdnRef = ( a16Bit & 0x03c0 ) >> 6;
7750 fPrintFormData = 0 != ( a16Bit & 0x0400 );
7751 fSaveFormData = 0 != ( a16Bit & 0x0800 );
7752 fShadeFormData = 0 != ( a16Bit & 0x1000 );
7753 fWCFootnoteEdn = 0 != ( a16Bit & 0x8000 );
7755 cLines = Get_Long( pData ); // 56 0x38
7756 cWordsFootnoteEnd = Get_Long( pData ); // 60 0x3c
7757 cChFootnoteEdn = Get_Long( pData ); // 64 0x40
7758 cPgFootnoteEdn = Get_Short( pData ); // 68 0x44
7759 cParasFootnoteEdn = Get_Long( pData ); // 70 0x46
7760 cLinesFootnoteEdn = Get_Long( pData ); // 74 0x4a
7761 lKeyProtDoc = Get_Long( pData ); // 78 0x4e
7763 a16Bit = Get_UShort( pData ); // 82 0x52
7764 wvkSaved = a16Bit & 0x0007 ;
7765 wScaleSaved = ( a16Bit & 0x0ff8 ) >> 3 ;
7766 zkSaved = ( a16Bit & 0x3000 ) >> 12;
7767 fRotateFontW6 = ( a16Bit & 0x4000 ) >> 14;
7768 iGutterPos = ( a16Bit & 0x8000 ) >> 15;
7770 if (nFib >= 103) // Word 6/32bit, 95, 97, 2000, 2002, 2003, 2007
7772 a32Bit = Get_ULong( pData ); // 84 0x54
7773 SetCompatibilityOptions(a32Bit);
7776 //#i22436#, for all WW7- documents
7777 if (nFib <= 104) // Word 95
7778 fUsePrinterMetrics = true;
7780 if (nFib > 105) // Word 97, 2000, 2002, 2003, 2007
7782 adt = Get_Short( pData ); // 88 0x58
7784 doptypography.ReadFromMem(pData); // 90 0x5a
7786 memcpy( &dogrid, pData, sizeof( WW8_DOGRID )); // 400 0x190
7787 pData += sizeof( WW8_DOGRID );
7789 a16Bit = Get_UShort( pData ); // 410 0x19a
7790 // the following 9 bit are uninteresting
7791 fHtmlDoc = ( a16Bit & 0x0200 ) >> 9 ;
7792 fSnapBorder = ( a16Bit & 0x0800 ) >> 11 ;
7793 fIncludeHeader = ( a16Bit & 0x1000 ) >> 12 ;
7794 fIncludeFooter = ( a16Bit & 0x2000 ) >> 13 ;
7795 fForcePageSizePag = ( a16Bit & 0x4000 ) >> 14 ;
7796 fMinFontSizePag = ( a16Bit & 0x8000 ) >> 15 ;
7798 a16Bit = Get_UShort( pData ); // 412 0x19c
7799 fHaveVersions = 0 != ( a16Bit & 0x0001 );
7800 fAutoVersion = 0 != ( a16Bit & 0x0002 );
7802 pData += 12; // 414 0x19e
7804 cChWS = Get_Long( pData ); // 426 0x1aa
7805 cChWSFootnoteEdn = Get_Long( pData ); // 430 0x1ae
7806 grfDocEvents = Get_Long( pData ); // 434 0x1b2
7808 pData += 4+30+8; // 438 0x1b6; 442 0x1ba; 472 0x1d8; 476 0x1dc
7810 cDBC = Get_Long( pData ); // 480 0x1e0
7811 cDBCFootnoteEdn = Get_Long( pData ); // 484 0x1e4
7813 pData += 1 * sizeof( sal_Int32); // 488 0x1e8
7815 nfcFootnoteRef = Get_Short( pData ); // 492 0x1ec
7816 nfcEdnRef = Get_Short( pData ); // 494 0x1ee
7817 hpsZoomFontPag = Get_Short( pData ); // 496 0x1f0
7818 dywDispPag = Get_Short( pData ); // 498 0x1f2
7820 if (nRead >= 516)
7822 //500 -> 508, Appear to be repeated here in 2000+
7823 pData += 8; // 500 0x1f4
7824 a32Bit = Get_Long( pData ); // 508 0x1fc
7825 SetCompatibilityOptions(a32Bit);
7826 a32Bit = Get_Long( pData ); // 512 0x200
7828 // i#78591#
7829 SetCompatibilityOptions2(a32Bit);
7831 if (nRead >= 550)
7833 pData += 32;
7834 a16Bit = Get_UShort( pData );
7835 fDoNotEmbedSystemFont = ( a16Bit & 0x0001 );
7836 fWordCompat = ( a16Bit & 0x0002 ) >> 1;
7837 fLiveRecover = ( a16Bit & 0x0004 ) >> 2;
7838 fEmbedFactoids = ( a16Bit & 0x0008 ) >> 3;
7839 fFactoidXML = ( a16Bit & 0x00010 ) >> 4;
7840 fFactoidAllDone = ( a16Bit & 0x0020 ) >> 5;
7841 fFolioPrint = ( a16Bit & 0x0040 ) >> 6;
7842 fReverseFolio = ( a16Bit & 0x0080 ) >> 7;
7843 iTextLineEnding = ( a16Bit & 0x0700 ) >> 8;
7844 fHideFcc = ( a16Bit & 0x0800 ) >> 11;
7845 fAcetateShowMarkup = ( a16Bit & 0x1000 ) >> 12;
7846 fAcetateShowAtn = ( a16Bit & 0x2000 ) >> 13;
7847 fAcetateShowInsDel = ( a16Bit & 0x4000 ) >> 14;
7848 fAcetateShowProps = ( a16Bit & 0x8000 ) >> 15;
7850 if (nRead >= 600)
7852 pData += 48;
7853 a16Bit = Get_Short(pData);
7854 fUseBackGroundInAllmodes = (a16Bit & 0x0080) >> 7;
7860 WW8Dop::WW8Dop():
7861 fFacingPages(false), fWidowControl(true), fPMHMainDoc(false), grfSuppression(0), fpc(1),
7862 grpfIhdt(0), rncFootnote(0), nFootnote(1), fOutlineDirtySave(true), fOnlyMacPics(false),
7863 fOnlyWinPics(false), fLabelDoc(false), fHyphCapitals(true), fAutoHyphen(false),
7864 fFormNoFields(false), fLinkStyles(false), fRevMarking(false), fBackup(true),
7865 fExactCWords(false), fPagHidden(true), fPagResults(true), fLockAtn(false),
7866 fMirrorMargins(false), fReadOnlyRecommended(false), fDfltTrueType(true),
7867 fPagSuppressTopSpacing(false), fProtEnabled(false), fDispFormFieldSel(false), fRMView(true),
7868 fRMPrint(true), fWriteReservation(false), fLockRev(false), fEmbedFonts(false),
7869 copts_fNoTabForInd(false), copts_fNoSpaceRaiseLower(false), copts_fSupressSpbfAfterPgBrk(false),
7870 copts_fWrapTrailSpaces(false), copts_fMapPrintTextColor(false), copts_fNoColumnBalance(false),
7871 copts_fConvMailMergeEsc(false), copts_fSupressTopSpacing(false),
7872 copts_fOrigWordTableRules(false), copts_fTransparentMetafiles(false),
7873 copts_fShowBreaksInFrames(false), copts_fSwapBordersFacingPgs(false), copts_fExpShRtn(false),
7874 dxaTab(0x2d0), dxaHotZ(0x168), nRevision(1),
7875 rncEdn(0), nEdn(1), epc(3), fPrintFormData(false), fSaveFormData(false), fShadeFormData(true),
7876 fWCFootnoteEdn(false), wvkSaved(2), wScaleSaved(100), zkSaved(0), fRotateFontW6(false),
7877 iGutterPos(false), fNoTabForInd(false), fNoSpaceRaiseLower(false),
7878 fSupressSpbfAfterPageBreak(false), fWrapTrailSpaces(false), fMapPrintTextColor(false),
7879 fNoColumnBalance(false), fConvMailMergeEsc(false), fSupressTopSpacing(false),
7880 fOrigWordTableRules(false), fTransparentMetafiles(false), fShowBreaksInFrames(false),
7881 fSwapBordersFacingPgs(false), fCompatibilityOptions_Unknown1_13(false), fExpShRtn(false),
7882 fCompatibilityOptions_Unknown1_15(false), fCompatibilityOptions_Unknown1_16(false),
7883 fSuppressTopSpacingMac5(false), fTruncDxaExpand(false), fPrintBodyBeforeHdr(false),
7884 fNoLeading(true), fCompatibilityOptions_Unknown1_21(false), fMWSmallCaps(false),
7885 fCompatibilityOptions_Unknown1_23(false), fCompatibilityOptions_Unknown1_24(false),
7886 fCompatibilityOptions_Unknown1_25(false), fCompatibilityOptions_Unknown1_26(false),
7887 fCompatibilityOptions_Unknown1_27(false), fCompatibilityOptions_Unknown1_28(false),
7888 fCompatibilityOptions_Unknown1_29(false), fCompatibilityOptions_Unknown1_30(false),
7889 fCompatibilityOptions_Unknown1_31(false), fUsePrinterMetrics(true), lvl(9), fHtmlDoc(false),
7890 fSnapBorder(false), fIncludeHeader(true), fIncludeFooter(true), fForcePageSizePag(false),
7891 fMinFontSizePag(false), fHaveVersions(false), fAutoVersion(false),
7892 cChWS(0), cChWSFootnoteEdn(0), cDBC(0), cDBCFootnoteEdn(0), nfcEdnRef(2),
7893 fCompatibilityOptions_Unknown2_1(false), fCompatibilityOptions_Unknown2_2(false),
7894 fDontUseHTMLAutoSpacing(false), fCompatibilityOptions_Unknown2_4(false),
7895 fCompatibilityOptions_Unknown2_5(false), fCompatibilityOptions_Unknown2_6(false),
7896 fCompatibilityOptions_Unknown2_7(false), fCompatibilityOptions_Unknown2_8(false),
7897 fCompatibilityOptions_Unknown2_9(false), fCompatibilityOptions_Unknown2_10(false),
7898 fCompatibilityOptions_Unknown2_11(false), fCompatibilityOptions_Unknown2_12(false),
7899 fCompatibilityOptions_Unknown2_13(false), fCompatibilityOptions_Unknown2_14(false),
7900 fCompatibilityOptions_Unknown2_15(false), fCompatibilityOptions_Unknown2_16(false),
7901 fCompatibilityOptions_Unknown2_17(false), fCompatibilityOptions_Unknown2_18(false),
7902 fCompatibilityOptions_Unknown2_19(false), fCompatibilityOptions_Unknown2_20(false),
7903 fCompatibilityOptions_Unknown2_21(false), fCompatibilityOptions_Unknown2_22(false),
7904 fCompatibilityOptions_Unknown2_23(false), fCompatibilityOptions_Unknown2_24(false),
7905 fCompatibilityOptions_Unknown2_25(false), fCompatibilityOptions_Unknown2_26(false),
7906 fCompatibilityOptions_Unknown2_27(false), fCompatibilityOptions_Unknown2_28(false),
7907 fCompatibilityOptions_Unknown2_29(false), fCompatibilityOptions_Unknown2_30(false),
7908 fCompatibilityOptions_Unknown2_31(false), fCompatibilityOptions_Unknown2_32(false),
7909 fUnknown3(0), fUseBackGroundInAllmodes(false), fDoNotEmbedSystemFont(false), fWordCompat(false),
7910 fLiveRecover(false), fEmbedFactoids(false), fFactoidXML(false), fFactoidAllDone(false),
7911 fFolioPrint(false), fReverseFolio(false), iTextLineEnding(0), fHideFcc(false),
7912 fAcetateShowMarkup(false), fAcetateShowAtn(true), fAcetateShowInsDel(false),
7913 fAcetateShowProps(false)
7914 // in C++20 with P06831R1 "Default member initializers for bit-fields (revision 1)", the
7915 // above bit-field member initializations can be moved to the class definition
7918 Writer acts like this all the time at the moment, ideally we need an
7919 option for these two as well to import word docs that are not like
7920 this by default
7922 // put in initialization list
7923 // fNoLeading = true;
7924 //fUsePrinterMetrics = true;
7927 void WW8Dop::SetCompatibilityOptions(sal_uInt32 a32Bit)
7929 fNoTabForInd = ( a32Bit & 0x00000001 ) ;
7930 fNoSpaceRaiseLower = ( a32Bit & 0x00000002 ) >> 1 ;
7931 fSupressSpbfAfterPageBreak = ( a32Bit & 0x00000004 ) >> 2 ;
7932 fWrapTrailSpaces = ( a32Bit & 0x00000008 ) >> 3 ;
7933 fMapPrintTextColor = ( a32Bit & 0x00000010 ) >> 4 ;
7934 fNoColumnBalance = ( a32Bit & 0x00000020 ) >> 5 ;
7935 fConvMailMergeEsc = ( a32Bit & 0x00000040 ) >> 6 ;
7936 fSupressTopSpacing = ( a32Bit & 0x00000080 ) >> 7 ;
7937 fOrigWordTableRules = ( a32Bit & 0x00000100 ) >> 8 ;
7938 fTransparentMetafiles = ( a32Bit & 0x00000200 ) >> 9 ;
7939 fShowBreaksInFrames = ( a32Bit & 0x00000400 ) >> 10 ;
7940 fSwapBordersFacingPgs = ( a32Bit & 0x00000800 ) >> 11 ;
7941 fCompatibilityOptions_Unknown1_13 = ( a32Bit & 0x00001000 ) >> 12 ;
7942 fExpShRtn = ( a32Bit & 0x00002000 ) >> 13 ; // #i56856#
7943 fCompatibilityOptions_Unknown1_15 = ( a32Bit & 0x00004000 ) >> 14 ;
7944 fCompatibilityOptions_Unknown1_16 = ( a32Bit & 0x00008000 ) >> 15 ;
7945 fSuppressTopSpacingMac5 = ( a32Bit & 0x00010000 ) >> 16 ;
7946 fTruncDxaExpand = ( a32Bit & 0x00020000 ) >> 17 ;
7947 fPrintBodyBeforeHdr = ( a32Bit & 0x00040000 ) >> 18 ;
7948 fNoLeading = ( a32Bit & 0x00080000 ) >> 19 ;
7949 fCompatibilityOptions_Unknown1_21 = ( a32Bit & 0x00100000 ) >> 20 ;
7950 fMWSmallCaps = ( a32Bit & 0x00200000 ) >> 21 ;
7951 fCompatibilityOptions_Unknown1_23 = ( a32Bit & 0x00400000 ) >> 22 ;
7952 fCompatibilityOptions_Unknown1_24 = ( a32Bit & 0x00800800 ) >> 23 ;
7953 fCompatibilityOptions_Unknown1_25 = ( a32Bit & 0x01000000 ) >> 24 ;
7954 fCompatibilityOptions_Unknown1_26 = ( a32Bit & 0x02000000 ) >> 25 ;
7955 fCompatibilityOptions_Unknown1_27 = ( a32Bit & 0x04000000 ) >> 26 ;
7956 fCompatibilityOptions_Unknown1_28 = ( a32Bit & 0x08000000 ) >> 27 ;
7957 fCompatibilityOptions_Unknown1_29 = ( a32Bit & 0x10000000 ) >> 28 ;
7958 fCompatibilityOptions_Unknown1_30 = ( a32Bit & 0x20000000 ) >> 29 ;
7959 fCompatibilityOptions_Unknown1_31 = ( a32Bit & 0x40000000 ) >> 30 ;
7961 fUsePrinterMetrics = ( a32Bit & 0x80000000 ) >> 31 ;
7964 sal_uInt32 WW8Dop::GetCompatibilityOptions() const
7966 sal_uInt32 a32Bit = 0;
7967 if (fNoTabForInd) a32Bit |= 0x00000001;
7968 if (fNoSpaceRaiseLower) a32Bit |= 0x00000002;
7969 if (fSupressSpbfAfterPageBreak) a32Bit |= 0x00000004;
7970 if (fWrapTrailSpaces) a32Bit |= 0x00000008;
7971 if (fMapPrintTextColor) a32Bit |= 0x00000010;
7972 if (fNoColumnBalance) a32Bit |= 0x00000020;
7973 if (fConvMailMergeEsc) a32Bit |= 0x00000040;
7974 if (fSupressTopSpacing) a32Bit |= 0x00000080;
7975 if (fOrigWordTableRules) a32Bit |= 0x00000100;
7976 if (fTransparentMetafiles) a32Bit |= 0x00000200;
7977 if (fShowBreaksInFrames) a32Bit |= 0x00000400;
7978 if (fSwapBordersFacingPgs) a32Bit |= 0x00000800;
7979 if (fCompatibilityOptions_Unknown1_13) a32Bit |= 0x00001000;
7980 if (fExpShRtn) a32Bit |= 0x00002000; // #i56856#
7981 if (fCompatibilityOptions_Unknown1_15) a32Bit |= 0x00004000;
7982 if (fCompatibilityOptions_Unknown1_16) a32Bit |= 0x00008000;
7983 if (fSuppressTopSpacingMac5) a32Bit |= 0x00010000;
7984 if (fTruncDxaExpand) a32Bit |= 0x00020000;
7985 if (fPrintBodyBeforeHdr) a32Bit |= 0x00040000;
7986 if (fNoLeading) a32Bit |= 0x00080000;
7987 if (fCompatibilityOptions_Unknown1_21) a32Bit |= 0x00100000;
7988 if (fMWSmallCaps) a32Bit |= 0x00200000;
7989 if (fCompatibilityOptions_Unknown1_23) a32Bit |= 0x00400000;
7990 if (fCompatibilityOptions_Unknown1_24) a32Bit |= 0x00800000;
7991 if (fCompatibilityOptions_Unknown1_25) a32Bit |= 0x01000000;
7992 if (fCompatibilityOptions_Unknown1_26) a32Bit |= 0x02000000;
7993 if (fCompatibilityOptions_Unknown1_27) a32Bit |= 0x04000000;
7994 if (fCompatibilityOptions_Unknown1_28) a32Bit |= 0x08000000;
7995 if (fCompatibilityOptions_Unknown1_29) a32Bit |= 0x10000000;
7996 if (fCompatibilityOptions_Unknown1_30) a32Bit |= 0x20000000;
7997 if (fCompatibilityOptions_Unknown1_31) a32Bit |= 0x40000000;
7998 if (fUsePrinterMetrics) a32Bit |= 0x80000000;
7999 return a32Bit;
8002 // i#78591#
8003 void WW8Dop::SetCompatibilityOptions2(sal_uInt32 a32Bit)
8005 fCompatibilityOptions_Unknown2_1 = ( a32Bit & 0x00000001 );
8006 fCompatibilityOptions_Unknown2_2 = ( a32Bit & 0x00000002 ) >> 1 ;
8007 fDontUseHTMLAutoSpacing = ( a32Bit & 0x00000004 ) >> 2 ;
8008 fCompatibilityOptions_Unknown2_4 = ( a32Bit & 0x00000008 ) >> 3 ;
8009 fCompatibilityOptions_Unknown2_5 = ( a32Bit & 0x00000010 ) >> 4 ;
8010 fCompatibilityOptions_Unknown2_6 = ( a32Bit & 0x00000020 ) >> 5 ;
8011 fCompatibilityOptions_Unknown2_7 = ( a32Bit & 0x00000040 ) >> 6 ;
8012 fCompatibilityOptions_Unknown2_8 = ( a32Bit & 0x00000080 ) >> 7 ;
8013 fCompatibilityOptions_Unknown2_9 = ( a32Bit & 0x00000100 ) >> 8 ;
8014 fCompatibilityOptions_Unknown2_10 = ( a32Bit & 0x00000200 ) >> 9 ;
8015 fCompatibilityOptions_Unknown2_11 = ( a32Bit & 0x00000400 ) >> 10 ;
8016 fCompatibilityOptions_Unknown2_12 = ( a32Bit & 0x00000800 ) >> 11 ;
8017 fCompatibilityOptions_Unknown2_13 = ( a32Bit & 0x00001000 ) >> 12 ;
8018 fCompatibilityOptions_Unknown2_14 = ( a32Bit & 0x00002000 ) >> 13 ;
8019 fCompatibilityOptions_Unknown2_15 = ( a32Bit & 0x00004000 ) >> 14 ;
8020 fCompatibilityOptions_Unknown2_16 = ( a32Bit & 0x00008000 ) >> 15 ;
8021 fCompatibilityOptions_Unknown2_17 = ( a32Bit & 0x00010000 ) >> 16 ;
8022 fCompatibilityOptions_Unknown2_18 = ( a32Bit & 0x00020000 ) >> 17 ;
8023 fCompatibilityOptions_Unknown2_19 = ( a32Bit & 0x00040000 ) >> 18 ;
8024 fCompatibilityOptions_Unknown2_20 = ( a32Bit & 0x00080000 ) >> 19 ;
8025 fCompatibilityOptions_Unknown2_21 = ( a32Bit & 0x00100000 ) >> 20 ;
8026 fCompatibilityOptions_Unknown2_22 = ( a32Bit & 0x00200000 ) >> 21 ;
8027 fCompatibilityOptions_Unknown2_23 = ( a32Bit & 0x00400000 ) >> 22 ;
8028 fCompatibilityOptions_Unknown2_24 = ( a32Bit & 0x00800800 ) >> 23 ;
8029 fCompatibilityOptions_Unknown2_25 = ( a32Bit & 0x01000800 ) >> 24 ;
8030 fCompatibilityOptions_Unknown2_26 = ( a32Bit & 0x02000800 ) >> 25 ;
8031 fCompatibilityOptions_Unknown2_27 = ( a32Bit & 0x04000800 ) >> 26 ;
8032 fCompatibilityOptions_Unknown2_28 = ( a32Bit & 0x08000800 ) >> 27 ;
8033 fCompatibilityOptions_Unknown2_29 = ( a32Bit & 0x10000800 ) >> 28 ;
8034 fCompatibilityOptions_Unknown2_30 = ( a32Bit & 0x20000800 ) >> 29 ;
8035 fCompatibilityOptions_Unknown2_31 = ( a32Bit & 0x40000800 ) >> 30 ;
8036 fCompatibilityOptions_Unknown2_32 = ( a32Bit & 0x80000000 ) >> 31 ;
8039 sal_uInt32 WW8Dop::GetCompatibilityOptions2() const
8041 sal_uInt32 a32Bit = 0;
8042 if (fCompatibilityOptions_Unknown2_1) a32Bit |= 0x00000001;
8043 if (fCompatibilityOptions_Unknown2_2) a32Bit |= 0x00000002;
8044 if (fDontUseHTMLAutoSpacing) a32Bit |= 0x00000004;
8045 if (fCompatibilityOptions_Unknown2_4) a32Bit |= 0x00000008;
8046 if (fCompatibilityOptions_Unknown2_5) a32Bit |= 0x00000010;
8047 if (fCompatibilityOptions_Unknown2_6) a32Bit |= 0x00000020;
8048 if (fCompatibilityOptions_Unknown2_7) a32Bit |= 0x00000040;
8049 if (fCompatibilityOptions_Unknown2_8) a32Bit |= 0x00000080;
8050 if (fCompatibilityOptions_Unknown2_9) a32Bit |= 0x00000100;
8051 if (fCompatibilityOptions_Unknown2_10) a32Bit |= 0x00000200;
8052 if (fCompatibilityOptions_Unknown2_11) a32Bit |= 0x00000400;
8053 if (fCompatibilityOptions_Unknown2_12) a32Bit |= 0x00000800;
8054 if (fCompatibilityOptions_Unknown2_13) a32Bit |= 0x00001000;
8055 //#i42909# set thai "line breaking rules" compatibility option
8056 // pflin, wonder whether bUseThaiLineBreakingRules is correct
8057 // when importing word document.
8058 if (bUseThaiLineBreakingRules) a32Bit |= 0x00002000;
8059 else if (fCompatibilityOptions_Unknown2_14) a32Bit |= 0x00002000;
8060 if (fCompatibilityOptions_Unknown2_15) a32Bit |= 0x00004000;
8061 if (fCompatibilityOptions_Unknown2_16) a32Bit |= 0x00008000;
8062 if (fCompatibilityOptions_Unknown2_17) a32Bit |= 0x00010000;
8063 if (fCompatibilityOptions_Unknown2_18) a32Bit |= 0x00020000;
8064 if (fCompatibilityOptions_Unknown2_19) a32Bit |= 0x00040000;
8065 if (fCompatibilityOptions_Unknown2_20) a32Bit |= 0x00080000;
8066 if (fCompatibilityOptions_Unknown2_21) a32Bit |= 0x00100000;
8067 if (fCompatibilityOptions_Unknown2_22) a32Bit |= 0x00200000;
8068 if (fCompatibilityOptions_Unknown2_23) a32Bit |= 0x00400000;
8069 if (fCompatibilityOptions_Unknown2_24) a32Bit |= 0x00800000;
8070 if (fCompatibilityOptions_Unknown2_25) a32Bit |= 0x01000000;
8071 if (fCompatibilityOptions_Unknown2_26) a32Bit |= 0x02000000;
8072 if (fCompatibilityOptions_Unknown2_27) a32Bit |= 0x04000000;
8073 if (fCompatibilityOptions_Unknown2_28) a32Bit |= 0x08000000;
8074 if (fCompatibilityOptions_Unknown2_29) a32Bit |= 0x10000000;
8075 if (fCompatibilityOptions_Unknown2_30) a32Bit |= 0x20000000;
8076 if (fCompatibilityOptions_Unknown2_31) a32Bit |= 0x40000000;
8077 if (fCompatibilityOptions_Unknown2_32) a32Bit |= 0x80000000;
8078 return a32Bit;
8081 void WW8Dop::Write(SvStream& rStrm, WW8Fib& rFib) const
8083 const int nMaxDopLen = 610;
8084 sal_uInt32 nLen = 8 == rFib.m_nVersion ? nMaxDopLen : 84;
8085 rFib.m_fcDop = rStrm.Tell();
8086 rFib.m_lcbDop = nLen;
8088 sal_uInt8 aData[ nMaxDopLen ] = {};
8089 sal_uInt8* pData = aData;
8091 // analyse the data
8092 sal_uInt16 a16Bit;
8093 sal_uInt8 a8Bit;
8095 a16Bit = 0; // 0 0x00
8096 if (fFacingPages)
8097 a16Bit |= 0x0001;
8098 if (fWidowControl)
8099 a16Bit |= 0x0002;
8100 if (fPMHMainDoc)
8101 a16Bit |= 0x0004;
8102 a16Bit |= ( 0x0018 & (grfSuppression << 3));
8103 a16Bit |= ( 0x0060 & (fpc << 5));
8104 a16Bit |= ( 0xff00 & (grpfIhdt << 8));
8105 Set_UInt16( pData, a16Bit );
8107 a16Bit = 0; // 2 0x02
8108 a16Bit |= ( 0x0003 & rncFootnote );
8109 a16Bit |= ( ~0x0003 & (nFootnote << 2));
8110 Set_UInt16( pData, a16Bit );
8112 a8Bit = 0; // 4 0x04
8113 if( fOutlineDirtySave ) a8Bit |= 0x01;
8114 Set_UInt8( pData, a8Bit );
8116 a8Bit = 0; // 5 0x05
8117 if( fOnlyMacPics ) a8Bit |= 0x01;
8118 if( fOnlyWinPics ) a8Bit |= 0x02;
8119 if( fLabelDoc ) a8Bit |= 0x04;
8120 if( fHyphCapitals ) a8Bit |= 0x08;
8121 if( fAutoHyphen ) a8Bit |= 0x10;
8122 if( fFormNoFields ) a8Bit |= 0x20;
8123 if( fLinkStyles ) a8Bit |= 0x40;
8124 if( fRevMarking ) a8Bit |= 0x80;
8125 Set_UInt8( pData, a8Bit );
8127 a8Bit = 0; // 6 0x06
8128 if( fBackup ) a8Bit |= 0x01;
8129 if( fExactCWords ) a8Bit |= 0x02;
8130 if( fPagHidden ) a8Bit |= 0x04;
8131 if( fPagResults ) a8Bit |= 0x08;
8132 if( fLockAtn ) a8Bit |= 0x10;
8133 if( fMirrorMargins ) a8Bit |= 0x20;
8134 if( fReadOnlyRecommended ) a8Bit |= 0x40;
8135 if( fDfltTrueType ) a8Bit |= 0x80;
8136 Set_UInt8( pData, a8Bit );
8138 a8Bit = 0; // 7 0x07
8139 if( fPagSuppressTopSpacing ) a8Bit |= 0x01;
8140 if( fProtEnabled ) a8Bit |= 0x02;
8141 if( fDispFormFieldSel ) a8Bit |= 0x04;
8142 if( fRMView ) a8Bit |= 0x08;
8143 if( fRMPrint ) a8Bit |= 0x10;
8144 if( fWriteReservation ) a8Bit |= 0x20;
8145 if( fLockRev ) a8Bit |= 0x40;
8146 if( fEmbedFonts ) a8Bit |= 0x80;
8147 Set_UInt8( pData, a8Bit );
8149 a8Bit = 0; // 8 0x08
8150 if( copts_fNoTabForInd ) a8Bit |= 0x01;
8151 if( copts_fNoSpaceRaiseLower ) a8Bit |= 0x02;
8152 if( copts_fSupressSpbfAfterPgBrk ) a8Bit |= 0x04;
8153 if( copts_fWrapTrailSpaces ) a8Bit |= 0x08;
8154 if( copts_fMapPrintTextColor ) a8Bit |= 0x10;
8155 if( copts_fNoColumnBalance ) a8Bit |= 0x20;
8156 if( copts_fConvMailMergeEsc ) a8Bit |= 0x40;
8157 if( copts_fSupressTopSpacing ) a8Bit |= 0x80;
8158 Set_UInt8( pData, a8Bit );
8160 a8Bit = 0; // 9 0x09
8161 if( copts_fOrigWordTableRules ) a8Bit |= 0x01;
8162 if( copts_fTransparentMetafiles ) a8Bit |= 0x02;
8163 if( copts_fShowBreaksInFrames ) a8Bit |= 0x04;
8164 if( copts_fSwapBordersFacingPgs ) a8Bit |= 0x08;
8165 if( copts_fExpShRtn ) a8Bit |= 0x20; // #i56856#
8166 Set_UInt8( pData, a8Bit );
8168 Set_UInt16( pData, dxaTab ); // 10 0x0a
8169 Set_UInt16( pData, wSpare ); // 12 0x0c
8170 Set_UInt16( pData, dxaHotZ ); // 14 0x0e
8171 Set_UInt16( pData, cConsecHypLim ); // 16 0x10
8172 Set_UInt16( pData, wSpare2 ); // 18 0x12
8173 Set_UInt32( pData, dttmCreated ); // 20 0x14
8174 Set_UInt32( pData, dttmRevised ); // 24 0x18
8175 Set_UInt32( pData, dttmLastPrint ); // 28 0x1c
8176 Set_UInt16( pData, nRevision ); // 32 0x20
8177 Set_UInt32( pData, tmEdited ); // 34 0x22
8178 Set_UInt32( pData, cWords ); // 38 0x26
8179 Set_UInt32( pData, cCh ); // 42 0x2a
8180 Set_UInt16( pData, cPg ); // 46 0x2e
8181 Set_UInt32( pData, cParas ); // 48 0x30
8183 a16Bit = 0; // 52 0x34
8184 a16Bit |= ( 0x0003 & rncEdn );
8185 a16Bit |= (~0x0003 & ( nEdn << 2));
8186 Set_UInt16( pData, a16Bit );
8188 a16Bit = 0; // 54 0x36
8189 a16Bit |= (0x0003 & epc );
8190 a16Bit |= (0x003c & (nfcFootnoteRef << 2));
8191 a16Bit |= (0x03c0 & (nfcEdnRef << 6));
8192 if( fPrintFormData ) a16Bit |= 0x0400;
8193 if( fSaveFormData ) a16Bit |= 0x0800;
8194 if( fShadeFormData ) a16Bit |= 0x1000;
8195 if( fWCFootnoteEdn ) a16Bit |= 0x8000;
8196 Set_UInt16( pData, a16Bit );
8198 Set_UInt32( pData, cLines ); // 56 0x38
8199 Set_UInt32( pData, cWordsFootnoteEnd ); // 60 0x3c
8200 Set_UInt32( pData, cChFootnoteEdn ); // 64 0x40
8201 Set_UInt16( pData, cPgFootnoteEdn ); // 68 0x44
8202 Set_UInt32( pData, cParasFootnoteEdn ); // 70 0x46
8203 Set_UInt32( pData, cLinesFootnoteEdn ); // 74 0x4a
8204 Set_UInt32( pData, lKeyProtDoc ); // 78 0x4e
8206 a16Bit = 0; // 82 0x52
8207 if (wvkSaved)
8208 a16Bit |= 0x0007;
8209 a16Bit |= (0x0ff8 & (wScaleSaved << 3));
8210 a16Bit |= (0x3000 & (zkSaved << 12));
8211 Set_UInt16( pData, a16Bit );
8213 if( 8 == rFib.m_nVersion )
8215 Set_UInt32(pData, GetCompatibilityOptions()); // 84 0x54
8217 Set_UInt16( pData, adt ); // 88 0x58
8219 doptypography.WriteToMem(pData); // 400 0x190
8221 memcpy( pData, &dogrid, sizeof( WW8_DOGRID ));
8222 pData += sizeof( WW8_DOGRID );
8224 a16Bit = 0x12; // set lvl to 9 // 410 0x19a
8225 if( fHtmlDoc ) a16Bit |= 0x0200;
8226 if( fSnapBorder ) a16Bit |= 0x0800;
8227 if( fIncludeHeader ) a16Bit |= 0x1000;
8228 if( fIncludeFooter ) a16Bit |= 0x2000;
8229 if( fForcePageSizePag ) a16Bit |= 0x4000;
8230 if( fMinFontSizePag ) a16Bit |= 0x8000;
8231 Set_UInt16( pData, a16Bit );
8233 a16Bit = 0; // 412 0x19c
8234 if( fHaveVersions ) a16Bit |= 0x0001;
8235 if( fAutoVersion ) a16Bit |= 0x0002;
8236 Set_UInt16( pData, a16Bit );
8238 pData += 12; // 414 0x19e
8240 Set_UInt32( pData, cChWS ); // 426 0x1aa
8241 Set_UInt32( pData, cChWSFootnoteEdn ); // 430 0x1ae
8242 Set_UInt32( pData, grfDocEvents ); // 434 0x1b2
8244 pData += 4+30+8; // 438 0x1b6; 442 0x1ba; 472 0x1d8; 476 0x1dc
8246 Set_UInt32( pData, cDBC ); // 480 0x1e0
8247 Set_UInt32( pData, cDBCFootnoteEdn ); // 484 0x1e4
8249 pData += 1 * sizeof( sal_Int32); // 488 0x1e8
8251 Set_UInt16( pData, nfcFootnoteRef ); // 492 0x1ec
8252 Set_UInt16( pData, nfcEdnRef ); // 494 0x1ee
8253 Set_UInt16( pData, hpsZoomFontPag ); // 496 0x1f0
8254 Set_UInt16( pData, dywDispPag ); // 498 0x1f2
8256 //500 -> 508, Appear to be repeated here in 2000+
8257 pData += 8;
8258 Set_UInt32(pData, GetCompatibilityOptions());
8259 Set_UInt32(pData, GetCompatibilityOptions2());
8260 pData += 32;
8262 a16Bit = 0;
8263 if (fEmbedFactoids)
8264 a16Bit |= 0x8;
8265 if (fAcetateShowMarkup)
8266 a16Bit |= 0x1000;
8267 //Word XP at least requires fAcetateShowMarkup to honour fAcetateShowAtn
8268 if (fAcetateShowAtn)
8270 a16Bit |= 0x1000;
8271 a16Bit |= 0x2000;
8273 Set_UInt16(pData, a16Bit);
8275 pData += 48;
8276 a16Bit = 0x0080;
8277 Set_UInt16(pData, a16Bit);
8279 rStrm.WriteBytes(aData, nLen);
8282 void WW8DopTypography::ReadFromMem(sal_uInt8 *&pData)
8284 sal_uInt16 a16Bit = Get_UShort(pData);
8285 m_fKerningPunct = (a16Bit & 0x0001);
8286 m_iJustification = (a16Bit & 0x0006) >> 1;
8287 m_iLevelOfKinsoku = (a16Bit & 0x0018) >> 3;
8288 m_f2on1 = (a16Bit & 0x0020) >> 5;
8289 m_reserved1 = (a16Bit & 0x03C0) >> 6;
8290 m_reserved2 = (a16Bit & 0xFC00) >> 10;
8292 m_cchFollowingPunct = Get_Short(pData);
8293 m_cchLeadingPunct = Get_Short(pData);
8295 sal_Int16 i;
8296 for (i=0; i < nMaxFollowing; ++i)
8297 m_rgxchFPunct[i] = Get_Short(pData);
8298 for (i=0; i < nMaxLeading; ++i)
8299 m_rgxchLPunct[i] = Get_Short(pData);
8301 if (m_cchFollowingPunct >= 0 && m_cchFollowingPunct < nMaxFollowing)
8302 m_rgxchFPunct[m_cchFollowingPunct]=0;
8303 else
8304 m_rgxchFPunct[nMaxFollowing - 1]=0;
8306 if (m_cchLeadingPunct >= 0 && m_cchLeadingPunct < nMaxLeading)
8307 m_rgxchLPunct[m_cchLeadingPunct]=0;
8308 else
8309 m_rgxchLPunct[nMaxLeading - 1]=0;
8313 void WW8DopTypography::WriteToMem(sal_uInt8 *&pData) const
8315 sal_uInt16 a16Bit = sal_uInt16(m_fKerningPunct);
8316 a16Bit |= (m_iJustification << 1) & 0x0006;
8317 a16Bit |= (m_iLevelOfKinsoku << 3) & 0x0018;
8318 a16Bit |= (int(m_f2on1) << 5) & 0x0020;
8319 a16Bit |= (m_reserved1 << 6) & 0x03C0;
8320 a16Bit |= (m_reserved2 << 10) & 0xFC00;
8321 Set_UInt16(pData,a16Bit);
8323 Set_UInt16(pData,m_cchFollowingPunct);
8324 Set_UInt16(pData,m_cchLeadingPunct);
8326 sal_Int16 i;
8327 for (i=0; i < nMaxFollowing; ++i)
8328 Set_UInt16(pData,m_rgxchFPunct[i]);
8329 for (i=0; i < nMaxLeading; ++i)
8330 Set_UInt16(pData,m_rgxchLPunct[i]);
8333 LanguageType WW8DopTypography::GetConvertedLang() const
8335 LanguageType nLang;
8336 //I have assumed people's republic/taiwan == simplified/traditional
8338 //This isn't a documented issue, so we might have it all wrong,
8339 //i.e. i.e. what's with the powers of two ?
8342 One example of 3 for reserved1 which was really Japanese, perhaps last bit
8343 is for some other use ?, or redundant. If more examples trigger the assert
8344 we might be able to figure it out.
8346 switch(m_reserved1 & 0xE)
8348 case 2: //Japan
8349 nLang = LANGUAGE_JAPANESE;
8350 break;
8351 case 4: //Chinese (People's Republic)
8352 nLang = LANGUAGE_CHINESE_SIMPLIFIED;
8353 break;
8354 case 6: //Korean
8355 nLang = LANGUAGE_KOREAN;
8356 break;
8357 case 8: //Chinese (Taiwan)
8358 nLang = LANGUAGE_CHINESE_TRADITIONAL;
8359 break;
8360 default:
8361 OSL_ENSURE(false, "Unknown MS Asian Typography language, report");
8362 nLang = LANGUAGE_CHINESE_SIMPLIFIED_LEGACY;
8363 break;
8364 case 0:
8365 //And here we have the possibility that it says 2, but it's really
8366 //a bug and only japanese level 2 has been selected after a custom
8367 //version was chosen on last save!
8368 nLang = LANGUAGE_JAPANESE;
8369 break;
8371 return nLang;
8374 // Sprms
8376 sal_uInt16 wwSprmParser::GetSprmTailLen(sal_uInt16 nId, const sal_uInt8* pSprm, sal_Int32 nRemLen)
8377 const
8379 SprmInfo aSprm = GetSprmInfo(nId);
8380 sal_uInt16 nL = 0; // number of Bytes to read
8382 //sprmPChgTabs
8383 switch( nId )
8385 case 23:
8386 case 0xC615:
8387 if( pSprm[1 + mnDelta] != 255 )
8388 nL = static_cast< sal_uInt16 >(pSprm[1 + mnDelta] + aSprm.nLen);
8389 else
8391 sal_uInt8 nDelIdx = 2 + mnDelta;
8392 sal_uInt8 nDel = nDelIdx < nRemLen ? pSprm[nDelIdx] : 0;
8393 sal_uInt8 nInsIdx = 3 + mnDelta + 4 * nDel;
8394 sal_uInt8 nIns = nInsIdx < nRemLen ? pSprm[nInsIdx] : 0;
8396 nL = 2 + 4 * nDel + 3 * nIns;
8398 break;
8399 case 0xD608:
8401 sal_uInt8 nIndex = 1 + mnDelta;
8402 if (nIndex + 1 >= nRemLen)
8404 SAL_WARN("sw.ww8", "sprm longer than remaining bytes, doc or parser is wrong");
8405 nL = 0;
8407 else
8408 nL = SVBT16ToUInt16(&pSprm[nIndex]);
8409 break;
8411 default:
8412 switch (aSprm.nVari)
8414 case L_FIX:
8415 nL = aSprm.nLen; // Excl. Token
8416 break;
8417 case L_VAR:
8418 // Variable 1-Byte Length?
8419 // Excl. Token + Var-Lengthbyte
8420 nL = static_cast< sal_uInt16 >(pSprm[1 + mnDelta] + aSprm.nLen);
8421 break;
8422 case L_VAR2:
8424 // Variable 2-Byte Length?
8425 // Excl. Token + Var-Lengthbyte
8426 sal_uInt8 nIndex = 1 + mnDelta;
8427 sal_uInt16 nCount;
8428 if (nIndex + 1 >= nRemLen)
8430 SAL_WARN("sw.ww8", "sprm longer than remaining bytes, doc or parser is wrong");
8431 nCount = 0;
8433 else
8434 nCount = SVBT16ToUInt16(&pSprm[nIndex]);
8435 nL = static_cast< sal_uInt16 >(nCount + aSprm.nLen - 1);
8436 break;
8438 default:
8439 OSL_ENSURE(false, "Unknown sprm variant");
8440 break;
8442 break;
8444 return nL;
8447 // one or two bytes at the beginning at the sprm id
8448 sal_uInt16 wwSprmParser::GetSprmId(const sal_uInt8* pSp) const
8450 OSL_ENSURE(pSp, "Why GetSprmId with pSp of 0");
8451 if (!pSp)
8452 return 0;
8454 sal_uInt16 nId = 0;
8456 if (ww::IsSevenMinus(meVersion))
8458 nId = *pSp; // [0..0xff]
8460 else
8462 nId = SVBT16ToUInt16(pSp);
8463 if (0x0800 > nId)
8464 nId = 0;
8467 return nId;
8470 // with tokens and length byte
8471 sal_Int32 wwSprmParser::GetSprmSize(sal_uInt16 nId, const sal_uInt8* pSprm, sal_Int32 nRemLen) const
8473 return GetSprmTailLen(nId, pSprm, nRemLen) + 1 + mnDelta + SprmDataOfs(nId);
8476 sal_uInt8 wwSprmParser::SprmDataOfs(sal_uInt16 nId) const
8478 return GetSprmInfo(nId).nVari;
8481 sal_Int32 wwSprmParser::DistanceToData(sal_uInt16 nId) const
8483 return 1 + mnDelta + SprmDataOfs(nId);
8486 SprmResult wwSprmParser::findSprmData(sal_uInt16 nId, sal_uInt8* pSprms,
8487 sal_Int32 nLen) const
8489 while (nLen >= MinSprmLen())
8491 const sal_uInt16 nCurrentId = GetSprmId(pSprms);
8492 // set pointer to data
8493 sal_Int32 nSize = GetSprmSize(nCurrentId, pSprms, nLen);
8495 bool bValid = nSize <= nLen;
8497 SAL_WARN_IF(!bValid, "sw.ww8",
8498 "sprm 0x" << std::hex << nCurrentId << std::dec << " longer than remaining bytes, " <<
8499 nSize << " vs " << nLen << "doc or parser is wrong");
8501 if (nCurrentId == nId && bValid) // Sprm found
8503 sal_Int32 nFixedLen = DistanceToData(nId);
8504 return SprmResult(pSprms + nFixedLen, nSize - nFixedLen);
8507 //Clip to available size if wrong
8508 nSize = std::min(nSize, nLen);
8509 pSprms += nSize;
8510 nLen -= nSize;
8512 // Sprm not found
8513 return SprmResult();
8516 SEPr::SEPr() :
8517 bkc(2), fTitlePage(0), fAutoPgn(0), nfcPgn(0), fUnlocked(0), cnsPgn(0),
8518 fPgnRestart(0), fEndNote(1), lnc(0), grpfIhdt(0), nLnnMod(0), dxaLnn(0),
8519 dxaPgn(720), dyaPgn(720), fLBetween(0), vjc(0), dmBinFirst(0),
8520 dmBinOther(0), dmPaperReq(0), fPropRMark(0), ibstPropRMark(0),
8521 dttmPropRMark(0), dxtCharSpace(0), dyaLinePitch(0), clm(0), reserved1(0),
8522 dmOrientPage(0), iHeadingPgn(0), pgnStart(1), lnnMin(0), wTextFlow(0),
8523 reserved2(0), pgbApplyTo(0), pgbPageDepth(0), pgbOffsetFrom(0),
8524 xaPage(lLetterWidth), yaPage(lLetterHeight), xaPageNUp(lLetterWidth), yaPageNUp(lLetterHeight),
8525 dxaLeft(1800), dxaRight(1800), dyaTop(1440), dyaBottom(1440), dzaGutter(0),
8526 dyaHdrTop(720), dyaHdrBottom(720), ccolM1(0), fEvenlySpaced(1),
8527 reserved3(0), fBiDi(0), fFacingCol(0), fRTLGutter(0), fRTLAlignment(0),
8528 dxaColumns(720), dxaColumnWidth(0), dmOrientFirst(0), fLayout(0),
8529 reserved4(0)
8533 bool checkRead(SvStream &rSt, void *pDest, sal_uInt32 nLength)
8535 return (rSt.ReadBytes(pDest, nLength) == static_cast<std::size_t>(nLength));
8538 #ifdef OSL_BIGENDIAN
8539 void swapEndian(sal_Unicode *pString)
8541 for (sal_Unicode *pWork = pString; *pWork; ++pWork)
8542 *pWork = OSL_SWAPWORD(*pWork);
8544 #endif
8546 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */