android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / filter / ww8 / ww8scan.cxx
blob517a14a5f02db5c28a174e5eb9529a7c8f79dae6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
21 #include "ww8scan.hxx"
22 #include "ww8par.hxx"
24 #include <cassert>
25 #include <cstddef>
26 #include <cstring>
27 #include <algorithm>
29 #include <i18nlangtag/mslangid.hxx>
30 #include "sprmids.hxx"
31 #include <rtl/tencinfo.h>
32 #include <sal/macros.h>
33 #include <sal/log.hxx>
34 #include <osl/diagnose.h>
36 #include <swerror.h>
38 #include <comphelper/string.hxx>
39 #include <unotools/localedatawrapper.hxx>
40 #include <i18nlangtag/lang.h>
41 #include <o3tl/safeint.hxx>
42 #include <tools/stream.hxx>
44 #include <vcl/settings.hxx>
45 #include <vcl/svapp.hxx>
47 #ifdef DEBUGSPRMREADER
48 #include <stdio.h>
49 #endif
51 using namespace ::com::sun::star::lang;
53 namespace
55 /**
56 winword strings are typically Belt and Braces strings preceded with a
57 pascal style count, and ending with a c style 0 terminator. 16bit chars
58 and count for ww8+ and 8bit chars and count for ww7-. The count and 0
59 can be checked for integrity to catch errors (e.g. lotus created
60 documents) where in error 8bit strings are used instead of 16bits
61 strings for style names.
63 bool TestBeltAndBraces(SvStream& rStrm)
65 bool bRet = false;
66 sal_uInt32 nOldPos = rStrm.Tell();
67 sal_uInt16 nBelt(0);
68 rStrm.ReadUInt16( nBelt );
69 nBelt *= sizeof(sal_Unicode);
70 if (rStrm.good() && (rStrm.remainingSize() >= (nBelt + sizeof(sal_Unicode))))
72 rStrm.SeekRel(nBelt);
73 if (rStrm.good())
75 sal_Unicode cBraces(0);
76 rStrm.ReadUtf16( cBraces );
77 if (rStrm.good() && cBraces == 0)
78 bRet = true;
81 rStrm.Seek(nOldPos);
82 return bRet;
86 const wwSprmSearcher *wwSprmParser::GetWW2SprmSearcher()
88 //double lock me
89 // WW2 Sprms
90 static const SprmInfoRow aSprms[] =
92 { 0, { 0, L_FIX} }, // "Default-sprm", will be skipped
93 { 2, { 1, L_FIX} }, // "sprmPIstd", pap.istd (style code)
94 { 3, { 0, L_VAR} }, // "sprmPIstdPermute pap.istd permutation
95 { 4, { 1, L_FIX} }, // "sprmPIncLv1" pap.istddifference
96 { 5, { 1, L_FIX} }, // "sprmPJc" pap.jc (justification)
97 { 6, { 1, L_FIX} }, // "sprmPFSideBySide" pap.fSideBySide
98 { 7, { 1, L_FIX} }, // "sprmPFKeep" pap.fKeep
99 { 8, { 1, L_FIX} }, // "sprmPFKeepFollow " pap.fKeepFollow
100 { 9, { 1, L_FIX} }, // "sprmPPageBreakBefore" pap.fPageBreakBefore
101 { 10, { 1, L_FIX} }, // "sprmPBrcl" pap.brcl
102 { 11, { 1, L_FIX} }, // "sprmPBrcp" pap.brcp
103 { 12, { 1, L_FIX} }, // "sprmPNfcSeqNumb" pap.nfcSeqNumb
104 { 13, { 1, L_FIX} }, // "sprmPNoSeqNumb" pap.nnSeqNumb
105 { 14, { 1, L_FIX} }, // "sprmPFNoLineNumb" pap.fNoLnn
106 { 15, { 0, L_VAR} }, // "?sprmPChgTabsPapx" pap.itbdMac, ...
107 { 16, { 2, L_FIX} }, // "sprmPDxaRight" pap.dxaRight
108 { 17, { 2, L_FIX} }, // "sprmPDxaLeft" pap.dxaLeft
109 { 18, { 2, L_FIX} }, // "sprmPNest" pap.dxaLeft
110 { 19, { 2, L_FIX} }, // "sprmPDxaLeft1" pap.dxaLeft1
111 { 20, { 2, L_FIX} }, // "sprmPDyaLine" pap.lspd an LSPD
112 { 21, { 2, L_FIX} }, // "sprmPDyaBefore" pap.dyaBefore
113 { 22, { 2, L_FIX} }, // "sprmPDyaAfter" pap.dyaAfter
114 { 23, { 0, L_VAR} }, // "?sprmPChgTabs" pap.itbdMac, pap.rgdxaTab, ...
115 { 24, { 1, L_FIX} }, // "sprmPFInTable" pap.fInTable
116 { 25, { 1, L_FIX} }, // "sprmPTtp" pap.fTtp
117 { 26, { 2, L_FIX} }, // "sprmPDxaAbs" pap.dxaAbs
118 { 27, { 2, L_FIX} }, // "sprmPDyaAbs" pap.dyaAbs
119 { 28, { 2, L_FIX} }, // "sprmPDxaWidth" pap.dxaWidth
120 { 29, { 1, L_FIX} }, // "sprmPPc" pap.pcHorz, pap.pcVert
121 { 30, { 2, L_FIX} }, // "sprmPBrcTop10" pap.brcTop BRC10
122 { 31, { 2, L_FIX} }, // "sprmPBrcLeft10" pap.brcLeft BRC10
123 { 32, { 2, L_FIX} }, // "sprmPBrcBottom10" pap.brcBottom BRC10
124 { 33, { 2, L_FIX} }, // "sprmPBrcRight10" pap.brcRight BRC10
125 { 34, { 2, L_FIX} }, // "sprmPBrcBetween10" pap.brcBetween BRC10
126 { 35, { 2, L_FIX} }, // "sprmPBrcBar10" pap.brcBar BRC10
127 { 36, { 2, L_FIX} }, // "sprmPFromText10" pap.dxaFromText dxa
128 { 37, { 1, L_FIX} }, // "sprmPWr" pap.wr wr
129 { 38, { 2, L_FIX} }, // "sprmPBrcTop" pap.brcTop BRC
130 { 39, { 2, L_FIX} }, // "sprmPBrcLeft" pap.brcLeft BRC
131 { 40, { 2, L_FIX} }, // "sprmPBrcBottom" pap.brcBottom BRC
132 { 41, { 2, L_FIX} }, // "sprmPBrcRight" pap.brcRight BRC
133 { 42, { 2, L_FIX} }, // "sprmPBrcBetween" pap.brcBetween BRC
134 { 43, { 2, L_FIX} }, // "sprmPBrcBar" pap.brcBar BRC word
135 { 44, { 1, L_FIX} }, // "sprmPFNoAutoHyph" pap.fNoAutoHyph
136 { 45, { 2, L_FIX} }, // "sprmPWHeightAbs" pap.wHeightAbs w
137 { 46, { 2, L_FIX} }, // "sprmPDcs" pap.dcs DCS
138 { 47, { 2, L_FIX} }, // "sprmPShd" pap.shd SHD
139 { 48, { 2, L_FIX} }, // "sprmPDyaFromText" pap.dyaFromText dya
140 { 49, { 2, L_FIX} }, // "sprmPDxaFromText" pap.dxaFromText dxa
141 { 50, { 1, L_FIX} }, // "sprmPFBiDi" pap.fBiDi 0 or 1 byte
142 { 51, { 1, L_FIX} }, // "sprmPFWidowControl" pap.fWidowControl 0 or 1 byte
143 { 52, { 0, L_FIX} }, // "?sprmPRuler 52"
144 { 53, { 1, L_FIX} }, // "sprmCFStrikeRM" chp.fRMarkDel 1 or 0 bit
145 { 54, { 1, L_FIX} }, // "sprmCFRMark" chp.fRMark 1 or 0 bit
146 { 55, { 1, L_FIX} }, // "sprmCFFieldVanish" chp.fFieldVanish 1 or 0 bit
147 { 57, { 0, L_VAR} }, // "sprmCDefault" whole CHP
148 { 58, { 0, L_FIX} }, // "sprmCPlain" whole CHP
149 { 60, { 1, L_FIX} }, // "sprmCFBold" chp.fBold 0,1, 128, or 129
150 { 61, { 1, L_FIX} }, // "sprmCFItalic" chp.fItalic 0,1, 128, or 129
151 { 62, { 1, L_FIX} }, // "sprmCFStrike" chp.fStrike 0,1, 128, or 129
152 { 63, { 1, L_FIX} }, // "sprmCFOutline" chp.fOutline 0,1, 128, or 129
153 { 64, { 1, L_FIX} }, // "sprmCFShadow" chp.fShadow 0,1, 128, or 129
154 { 65, { 1, L_FIX} }, // "sprmCFSmallCaps" chp.fSmallCaps 0,1, 128, or 129
155 { 66, { 1, L_FIX} }, // "sprmCFCaps" chp.fCaps 0,1, 128, or 129
156 { 67, { 1, L_FIX} }, // "sprmCFVanish" chp.fVanish 0,1, 128, or 129
157 { 68, { 2, L_FIX} }, // "sprmCFtc" chp.ftc ftc word
158 { 69, { 1, L_FIX} }, // "sprmCKul" chp.kul kul byte
159 { 70, { 3, L_FIX} }, // "sprmCSizePos" chp.hps, chp.hpsPos
160 { 71, { 2, L_FIX} }, // "sprmCDxaSpace" chp.dxaSpace dxa
161 { 72, { 2, L_FIX} }, // "sprmCLid" chp.lid LID
162 { 73, { 1, L_FIX} }, // "sprmCIco" chp.ico ico byte
163 { 74, { 1, L_FIX} }, // "sprmCHps" chp.hps hps !word!
164 { 75, { 1, L_FIX} }, // "sprmCHpsInc" chp.hps
165 { 76, { 1, L_FIX} }, // "sprmCHpsPos" chp.hpsPos hps !word!
166 { 77, { 1, L_FIX} }, // "sprmCHpsPosAdj" chp.hpsPos hps
167 { 78, { 0, L_VAR} }, // "?sprmCMajority" chp.fBold, chp.fItalic, ...
168 { 80, { 1, L_FIX} }, // "sprmCFBoldBi" chp.fBoldBi
169 { 81, { 1, L_FIX} }, // "sprmCFItalicBi" chp.fItalicBi
170 { 82, { 2, L_FIX} }, // "sprmCFtcBi" chp.ftcBi
171 { 83, { 2, L_FIX} }, // "sprmClidBi" chp.lidBi
172 { 84, { 1, L_FIX} }, // "sprmCIcoBi" chp.icoBi
173 { 85, { 1, L_FIX} }, // "sprmCHpsBi" chp.hpsBi
174 { 86, { 1, L_FIX} }, // "sprmCFBiDi" chp.fBiDi
175 { 87, { 1, L_FIX} }, // "sprmCFDiacColor" chp.fDiacUSico
176 { 94, { 1, L_FIX} }, // "sprmPicBrcl" pic.brcl brcl (see PIC definition)
177 { 95, {12, L_VAR} }, // "sprmPicScale" pic.mx, pic.my, pic.dxaCropleft,
178 { 96, { 2, L_FIX} }, // "sprmPicBrcTop" pic.brcTop BRC word
179 { 97, { 2, L_FIX} }, // "sprmPicBrcLeft" pic.brcLeft BRC word
180 { 98, { 2, L_FIX} }, // "sprmPicBrcBottom" pic.brcBottom BRC word
181 { 99, { 2, L_FIX} }, // "sprmPicBrcRight" pic.brcRight BRC word
182 {112, { 1, L_FIX} }, // "sprmSFRTLGutter", set to one if gutter is on
183 {114, { 1, L_FIX} }, // "sprmSFBiDi" ;;;
184 {115, { 2, L_FIX} }, // "sprmSDmBinFirst" sep.dmBinFirst word
185 {116, { 2, L_FIX} }, // "sprmSDmBinOther" sep.dmBinOther word
186 {117, { 1, L_FIX} }, // "sprmSBkc" sep.bkc bkc byte
187 {118, { 1, L_FIX} }, // "sprmSFTitlePage" sep.fTitlePage 0 or 1 byte
188 {119, { 2, L_FIX} }, // "sprmSCcolumns" sep.ccolM1 # of cols - 1 word
189 {120, { 2, L_FIX} }, // "sprmSDxaColumns" sep.dxaColumns dxa word
190 {121, { 1, L_FIX} }, // "sprmSFAutoPgn" sep.fAutoPgn obsolete byte
191 {122, { 1, L_FIX} }, // "sprmSNfcPgn" sep.nfcPgn nfc byte
192 {123, { 2, L_FIX} }, // "sprmSDyaPgn" sep.dyaPgn dya short
193 {124, { 2, L_FIX} }, // "sprmSDxaPgn" sep.dxaPgn dya short
194 {125, { 1, L_FIX} }, // "sprmSFPgnRestart" sep.fPgnRestart 0 or 1 byte
195 {126, { 1, L_FIX} }, // "sprmSFEndnote" sep.fEndnote 0 or 1 byte
196 {127, { 1, L_FIX} }, // "sprmSLnc" sep.lnc lnc byte
197 {128, { 1, L_FIX} }, // "sprmSGprfIhdt" sep.grpfIhdt grpfihdt
198 {129, { 2, L_FIX} }, // "sprmSNLnnMod" sep.nLnnMod non-neg int. word
199 {130, { 2, L_FIX} }, // "sprmSDxaLnn" sep.dxaLnn dxa word
200 {131, { 2, L_FIX} }, // "sprmSDyaHdrTop" sep.dyaHdrTop dya word
201 {132, { 2, L_FIX} }, // "sprmSDyaHdrBottom" sep.dyaHdrBottom dya word
202 {133, { 1, L_FIX} }, // "sprmSLBetween" sep.fLBetween 0 or 1 byte
203 {134, { 1, L_FIX} }, // "sprmSVjc" sep.vjc vjc byte
204 {135, { 2, L_FIX} }, // "sprmSLnnMin" sep.lnnMin lnn word
205 {136, { 2, L_FIX} }, // "sprmSPgnStart" sep.pgnStart pgn word
206 {137, { 1, L_FIX} }, // "sprmSBOrientation" sep.dmOrientPage dm byte
207 {138, { 1, L_FIX} }, // "sprmSFFacingCol" ;;;
208 {139, { 2, L_FIX} }, // "sprmSXaPage" sep.xaPage xa word
209 {140, { 2, L_FIX} }, // "sprmSYaPage" sep.yaPage ya word
210 {141, { 2, L_FIX} }, // "sprmSDxaLeft" sep.dxaLeft dxa word
211 {142, { 2, L_FIX} }, // "sprmSDxaRight" sep.dxaRight dxa word
212 {143, { 2, L_FIX} }, // "sprmSDyaTop" sep.dyaTop dya word
213 {144, { 2, L_FIX} }, // "sprmSDyaBottom" sep.dyaBottom dya word
214 {145, { 2, L_FIX} }, // "sprmSDzaGutter" sep.dzaGutter dza word
215 {146, { 2, L_FIX} }, // "sprmTJc" tap.jc jc (low order byte is significant)
216 {147, { 2, L_FIX} }, // "sprmTDxaLeft" tap.rgdxaCenter dxa word
217 {148, { 2, L_FIX} }, // "sprmTDxaGapHalf" tap.dxaGapHalf, tap.rgdxaCenter
218 {149, { 1, L_FIX} }, // "sprmTFBiDi" ;;;
219 {152, { 0, L_VAR2} },// "sprmTDefTable10" tap.rgdxaCenter, tap.rgtc complex
220 {153, { 2, L_FIX} }, // "sprmTDyaRowHeight" tap.dyaRowHeight dya word
221 {154, { 0, L_VAR2} },// "sprmTDefTable" tap.rgtc complex
222 {155, { 1, L_VAR} }, // "sprmTDefTableShd" tap.rgshd complex
223 {157, { 5, L_FIX} }, // "sprmTSetBrc" tap.rgtc[].rgbrc complex 5 bytes
224 {158, { 4, L_FIX} }, // "sprmTInsert" tap.rgdxaCenter,tap.rgtc complex
225 {159, { 2, L_FIX} }, // "sprmTDelete" tap.rgdxaCenter, tap.rgtc complex
226 {160, { 4, L_FIX} }, // "sprmTDxaCol" tap.rgdxaCenter complex
227 {161, { 2, L_FIX} }, // "sprmTMerge" tap.fFirstMerged, tap.fMerged complex
228 {162, { 2, L_FIX} }, // "sprmTSplit" tap.fFirstMerged, tap.fMerged complex
229 {163, { 5, L_FIX} }, // "sprmTSetBrc10" tap.rgtc[].rgbrc complex 5 bytes
230 {164, { 4, L_FIX} }, // "sprmTSetShd", tap.rgshd complex 4 bytes
233 static wwSprmSearcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
234 return &aSprmSrch;
237 const wwSprmSearcher *wwSprmParser::GetWW6SprmSearcher(const WW8Fib& rFib)
239 //double lock me
240 // WW7- Sprms
241 static const SprmInfoRow aSprms[] =
243 { 0, { 0, L_FIX} }, // "Default-sprm", is skipped
244 {NS_sprm::v6::sprmPIstd, { 2, L_FIX} }, // pap.istd (style code)
245 {NS_sprm::v6::sprmPIstdPermute, { 3, L_VAR} }, // pap.istd permutation
246 {NS_sprm::v6::sprmPIncLv1, { 1, L_FIX} }, // pap.istddifference
247 {NS_sprm::v6::sprmPJc, { 1, L_FIX} }, // pap.jc (justification)
248 {NS_sprm::v6::sprmPFSideBySide, { 1, L_FIX} }, // pap.fSideBySide
249 {NS_sprm::v6::sprmPFKeep, { 1, L_FIX} }, // pap.fKeep
250 {NS_sprm::v6::sprmPFKeepFollow, { 1, L_FIX} }, // pap.fKeepFollow
251 {NS_sprm::v6::sprmPPageBreakBefore, { 1, L_FIX} }, // pap.fPageBreakBefore
252 {NS_sprm::v6::sprmPBrcl, { 1, L_FIX} }, // pap.brcl
253 {NS_sprm::v6::sprmPBrcp, { 1, L_FIX} }, // pap.brcp
254 {NS_sprm::v6::sprmPAnld, { 0, L_VAR} }, // pap.anld (ANLD structure)
255 {NS_sprm::v6::sprmPNLvlAnm, { 1, L_FIX} }, // pap.nLvlAnm nn
256 {NS_sprm::v6::sprmPFNoLineNumb, { 1, L_FIX} }, // pap.fNoLnn
257 {NS_sprm::v6::sprmPChgTabsPapx, { 0, L_VAR} }, // pap.itbdMac, ...
258 {NS_sprm::v6::sprmPDxaRight, { 2, L_FIX} }, // pap.dxaRight
259 {NS_sprm::v6::sprmPDxaLeft, { 2, L_FIX} }, // pap.dxaLeft
260 {NS_sprm::v6::sprmPNest, { 2, L_FIX} }, // pap.dxaLeft
261 {NS_sprm::v6::sprmPDxaLeft1, { 2, L_FIX} }, // pap.dxaLeft1
262 {NS_sprm::v6::sprmPDyaLine, { 4, L_FIX} }, // pap.lspd an LSPD
263 {NS_sprm::v6::sprmPDyaBefore, { 2, L_FIX} }, // pap.dyaBefore
264 {NS_sprm::v6::sprmPDyaAfter, { 2, L_FIX} }, // pap.dyaAfter
265 {NS_sprm::v6::sprmPChgTabs, { 0, L_VAR} }, // pap.itbdMac, pap.rgdxaTab, ...
266 {NS_sprm::v6::sprmPFInTable, { 1, L_FIX} }, // pap.fInTable
267 {NS_sprm::v6::sprmPTtp, { 1, L_FIX} }, // pap.fTtp
268 {NS_sprm::v6::sprmPDxaAbs, { 2, L_FIX} }, // pap.dxaAbs
269 {NS_sprm::v6::sprmPDyaAbs, { 2, L_FIX} }, // pap.dyaAbs
270 {NS_sprm::v6::sprmPDxaWidth, { 2, L_FIX} }, // pap.dxaWidth
271 {NS_sprm::v6::sprmPPc, { 1, L_FIX} }, // pap.pcHorz, pap.pcVert
272 {NS_sprm::v6::sprmPBrcTop10, { 2, L_FIX} }, // pap.brcTop BRC10
273 {NS_sprm::v6::sprmPBrcLeft10, { 2, L_FIX} }, // pap.brcLeft BRC10
274 {NS_sprm::v6::sprmPBrcBottom10, { 2, L_FIX} }, // pap.brcBottom BRC10
275 {NS_sprm::v6::sprmPBrcRight10, { 2, L_FIX} }, // pap.brcRight BRC10
276 {NS_sprm::v6::sprmPBrcBetween10, { 2, L_FIX} }, // pap.brcBetween BRC10
277 {NS_sprm::v6::sprmPBrcBar10, { 2, L_FIX} }, // pap.brcBar BRC10
278 {NS_sprm::v6::sprmPFromText10, { 2, L_FIX} }, // pap.dxaFromText dxa
279 {NS_sprm::v6::sprmPWr, { 1, L_FIX} }, // pap.wr wr
280 {NS_sprm::v6::sprmPBrcTop, { 2, L_FIX} }, // pap.brcTop BRC
281 {NS_sprm::v6::sprmPBrcLeft, { 2, L_FIX} }, // pap.brcLeft BRC
282 {NS_sprm::v6::sprmPBrcBottom, { 2, L_FIX} }, // pap.brcBottom BRC
283 {NS_sprm::v6::sprmPBrcRight, { 2, L_FIX} }, // pap.brcRight BRC
284 {NS_sprm::v6::sprmPBrcBetween, { 2, L_FIX} }, // pap.brcBetween BRC
285 {NS_sprm::v6::sprmPBrcBar, { 2, L_FIX} }, // pap.brcBar BRC word
286 {NS_sprm::v6::sprmPFNoAutoHyph, { 1, L_FIX} }, // pap.fNoAutoHyph
287 {NS_sprm::v6::sprmPWHeightAbs, { 2, L_FIX} }, // pap.wHeightAbs w
288 {NS_sprm::v6::sprmPDcs, { 2, L_FIX} }, // pap.dcs DCS
289 {NS_sprm::v6::sprmPShd, { 2, L_FIX} }, // pap.shd SHD
290 {NS_sprm::v6::sprmPDyaFromText, { 2, L_FIX} }, // pap.dyaFromText dya
291 {NS_sprm::v6::sprmPDxaFromText, { 2, L_FIX} }, // pap.dxaFromText dxa
292 {NS_sprm::v6::sprmPFLocked, { 1, L_FIX} }, // pap.fLocked 0 or 1 byte
293 {NS_sprm::v6::sprmPFWidowControl, { 1, L_FIX} }, // pap.fWidowControl 0 or 1 byte
294 {NS_sprm::v6::sprmPRuler, { 0, L_FIX} },
295 { 64, { 0, L_VAR} }, // rtl property ?
296 {NS_sprm::v6::sprmCFStrikeRM, { 1, L_FIX} }, // chp.fRMarkDel 1 or 0 bit
297 {NS_sprm::v6::sprmCFRMark, { 1, L_FIX} }, // chp.fRMark 1 or 0 bit
298 {NS_sprm::v6::sprmCFFldVanish, { 1, L_FIX} }, // chp.fFieldVanish 1 or 0 bit
299 {NS_sprm::v6::sprmCPicLocation, { 0, L_VAR} }, // chp.fcPic and chp.fSpec
300 {NS_sprm::v6::sprmCIbstRMark, { 2, L_FIX} }, // chp.ibstRMark index into sttbRMark
301 {NS_sprm::v6::sprmCDttmRMark, { 4, L_FIX} }, // chp.dttm DTTM long
302 {NS_sprm::v6::sprmCFData, { 1, L_FIX} }, // chp.fData 1 or 0 bit
303 {NS_sprm::v6::sprmCRMReason, { 2, L_FIX} }, // chp.idslRMReason an index to a table
304 {NS_sprm::v6::sprmCChse, { 3, L_FIX} }, // chp.fChsDiff and chp.chse
305 {NS_sprm::v6::sprmCSymbol, { 0, L_VAR} }, // chp.fSpec, chp.chSym and chp.ftcSym
306 {NS_sprm::v6::sprmCFOle2, { 1, L_FIX} }, // chp.fOle2 1 or 0 bit
307 { 77, { 0, L_VAR} }, // unknown
308 { 79, { 0, L_VAR} }, // unknown
309 {NS_sprm::v6::sprmCIstd, { 2, L_FIX} }, // chp.istd istd, see stylesheet definition
310 {NS_sprm::v6::sprmCIstdPermute, { 0, L_VAR} }, // chp.istd permutation vector
311 {NS_sprm::v6::sprmCDefault, { 0, L_VAR} }, // whole CHP
312 {NS_sprm::v6::sprmCPlain, { 0, L_FIX} }, // whole CHP
313 {NS_sprm::v6::sprmCFBold, { 1, L_FIX} }, // chp.fBold 0,1, 128, or 129
314 {NS_sprm::v6::sprmCFItalic, { 1, L_FIX} }, // chp.fItalic 0,1, 128, or 129
315 {NS_sprm::v6::sprmCFStrike, { 1, L_FIX} }, // chp.fStrike 0,1, 128, or 129
316 {NS_sprm::v6::sprmCFOutline, { 1, L_FIX} }, // chp.fOutline 0,1, 128, or 129
317 {NS_sprm::v6::sprmCFShadow, { 1, L_FIX} }, // chp.fShadow 0,1, 128, or 129
318 {NS_sprm::v6::sprmCFSmallCaps, { 1, L_FIX} }, // chp.fSmallCaps 0,1, 128, or 129
319 {NS_sprm::v6::sprmCFCaps, { 1, L_FIX} }, // chp.fCaps 0,1, 128, or 129
320 {NS_sprm::v6::sprmCFVanish, { 1, L_FIX} }, // chp.fVanish 0,1, 128, or 129
321 {NS_sprm::v6::sprmCFtc, { 2, L_FIX} }, // chp.ftc ftc word
322 {NS_sprm::v6::sprmCKul, { 1, L_FIX} }, // chp.kul kul byte
323 {NS_sprm::v6::sprmCSizePos, { 3, L_FIX} }, // chp.hps, chp.hpsPos
324 {NS_sprm::v6::sprmCDxaSpace, { 2, L_FIX} }, // chp.dxaSpace dxa
325 {NS_sprm::v6::sprmCLid, { 2, L_FIX} }, // chp.lid LID
326 {NS_sprm::v6::sprmCIco, { 1, L_FIX} }, // chp.ico ico byte
327 {NS_sprm::v6::sprmCHps, { 2, L_FIX} }, // chp.hps hps !word!
328 {NS_sprm::v6::sprmCHpsInc, { 1, L_FIX} }, // chp.hps
329 {NS_sprm::v6::sprmCHpsPos, { 2, L_FIX} }, // chp.hpsPos hps !word!
330 {NS_sprm::v6::sprmCHpsPosAdj, { 1, L_FIX} }, // chp.hpsPos hps
331 {NS_sprm::v6::sprmCMajority, { 0, L_VAR} }, // chp.fBold, chp.fItalic, ...
332 {NS_sprm::v6::sprmCIss, { 1, L_FIX} }, // chp.iss iss
333 {NS_sprm::v6::sprmCHpsNew50, { 0, L_VAR} }, // chp.hps hps variable width
334 {NS_sprm::v6::sprmCHpsInc1, { 0, L_VAR} }, // chp.hps complex
335 {NS_sprm::v6::sprmCHpsKern, { 2, L_FIX} }, // chp.hpsKern hps
336 {NS_sprm::v6::sprmCMajority50, { 0, L_VAR} }, // chp.fBold, chp.fItalic, ...
337 {NS_sprm::v6::sprmCHpsMul, { 2, L_FIX} }, // chp.hps percentage to grow hps
338 {NS_sprm::v6::sprmCCondHyhen, { 2, L_FIX} }, // chp.ysri ysri
339 {111, { 0, L_VAR} }, // sprmCFBoldBi or font code
340 {112, { 0, L_VAR} }, // sprmCFItalicBi or font code
341 {113, { 0, L_VAR} }, // ww7 rtl font
342 {114, { 0, L_VAR} }, // ww7 lid
343 {115, { 0, L_VAR} }, // ww7 CJK font
344 {116, { 0, L_VAR} }, // ww7 fontsize
345 {NS_sprm::v6::sprmCFSpec, { 1, L_FIX} }, // chp.fSpec 1 or 0 bit
346 {NS_sprm::v6::sprmCFObj, { 1, L_FIX} }, // chp.fObj 1 or 0 bit
347 {NS_sprm::v6::sprmPicBrcl, { 1, L_FIX} }, // pic.brcl brcl (see PIC definition)
348 {NS_sprm::v6::sprmPicScale, {12, L_VAR} }, // pic.mx, pic.my, pic.dxaCropleft,
349 {NS_sprm::v6::sprmPicBrcTop, { 2, L_FIX} }, // pic.brcTop BRC word
350 {NS_sprm::v6::sprmPicBrcLeft, { 2, L_FIX} }, // pic.brcLeft BRC word
351 {NS_sprm::v6::sprmPicBrcBottom, { 2, L_FIX} }, // pic.brcBottom BRC word
352 {NS_sprm::v6::sprmPicBrcRight, { 2, L_FIX} }, // pic.brcRight BRC word
353 {NS_sprm::v6::sprmSScnsPgn, { 1, L_FIX} }, // sep.cnsPgn cns byte
354 {NS_sprm::v6::sprmSiHeadingPgn, { 1, L_FIX} }, // sep.iHeadingPgn
355 {NS_sprm::v6::sprmSOlstAnm, { 0, L_VAR} }, // sep.olstAnm OLST variable length
356 {NS_sprm::v6::sprmSDxaColWidth, { 3, L_FIX} }, // sep.rgdxaColWidthSpacing complex
357 {NS_sprm::v6::sprmSDxaColSpacing, { 3, L_FIX} }, // sep.rgdxaColWidthSpacing
358 {NS_sprm::v6::sprmSFEvenlySpaced, { 1, L_FIX} }, // sep.fEvenlySpaced 1 or 0
359 {NS_sprm::v6::sprmSFProtected, { 1, L_FIX} }, // sep.fUnlocked 1 or 0 byte
360 {NS_sprm::v6::sprmSDmBinFirst, { 2, L_FIX} }, // sep.dmBinFirst word
361 {NS_sprm::v6::sprmSDmBinOther, { 2, L_FIX} }, // sep.dmBinOther word
362 {NS_sprm::v6::sprmSBkc, { 1, L_FIX} }, // sep.bkc bkc byte
363 {NS_sprm::v6::sprmSFTitlePage, { 1, L_FIX} }, // sep.fTitlePage 0 or 1 byte
364 {NS_sprm::v6::sprmSCcolumns, { 2, L_FIX} }, // sep.ccolM1 # of cols - 1 word
365 {NS_sprm::v6::sprmSDxaColumns, { 2, L_FIX} }, // sep.dxaColumns dxa word
366 {NS_sprm::v6::sprmSFAutoPgn, { 1, L_FIX} }, // sep.fAutoPgn obsolete byte
367 {NS_sprm::v6::sprmSNfcPgn, { 1, L_FIX} }, // sep.nfcPgn nfc byte
368 {NS_sprm::v6::sprmSDyaPgn, { 2, L_FIX} }, // sep.dyaPgn dya short
369 {NS_sprm::v6::sprmSDxaPgn, { 2, L_FIX} }, // sep.dxaPgn dya short
370 {NS_sprm::v6::sprmSFPgnRestart, { 1, L_FIX} }, // sep.fPgnRestart 0 or 1 byte
371 {NS_sprm::v6::sprmSFEndnote, { 1, L_FIX} }, // sep.fEndnote 0 or 1 byte
372 {NS_sprm::v6::sprmSLnc, { 1, L_FIX} }, // sep.lnc lnc byte
373 {NS_sprm::v6::sprmSGprfIhdt, { 1, L_FIX} }, // sep.grpfIhdt grpfihdt
374 {NS_sprm::v6::sprmSNLnnMod, { 2, L_FIX} }, // sep.nLnnMod non-neg int. word
375 {NS_sprm::v6::sprmSDxaLnn, { 2, L_FIX} }, // sep.dxaLnn dxa word
376 {NS_sprm::v6::sprmSDyaHdrTop, { 2, L_FIX} }, // sep.dyaHdrTop dya word
377 {NS_sprm::v6::sprmSDyaHdrBottom, { 2, L_FIX} }, // sep.dyaHdrBottom dya word
378 {NS_sprm::v6::sprmSLBetween, { 1, L_FIX} }, // sep.fLBetween 0 or 1 byte
379 {NS_sprm::v6::sprmSVjc, { 1, L_FIX} }, // sep.vjc vjc byte
380 {NS_sprm::v6::sprmSLnnMin, { 2, L_FIX} }, // sep.lnnMin lnn word
381 {NS_sprm::v6::sprmSPgnStart, { 2, L_FIX} }, // sep.pgnStart pgn word
382 {NS_sprm::v6::sprmSBOrientation, { 1, L_FIX} }, // sep.dmOrientPage dm byte
383 {NS_sprm::v6::sprmSBCustomize, { 0, L_FIX} },
384 {NS_sprm::v6::sprmSXaPage, { 2, L_FIX} }, // sep.xaPage xa word
385 {NS_sprm::v6::sprmSYaPage, { 2, L_FIX} }, // sep.yaPage ya word
386 {NS_sprm::v6::sprmSDxaLeft, { 2, L_FIX} }, // sep.dxaLeft dxa word
387 {NS_sprm::v6::sprmSDxaRight, { 2, L_FIX} }, // sep.dxaRight dxa word
388 {NS_sprm::v6::sprmSDyaTop, { 2, L_FIX} }, // sep.dyaTop dya word
389 {NS_sprm::v6::sprmSDyaBottom, { 2, L_FIX} }, // sep.dyaBottom dya word
390 {NS_sprm::v6::sprmSDzaGutter, { 2, L_FIX} }, // sep.dzaGutter dza word
391 {NS_sprm::v6::sprmSDMPaperReq, { 2, L_FIX} }, // sep.dmPaperReq dm word
392 {179, { 0, L_VAR} }, // rtl property ?
393 {181, { 0, L_VAR} }, // rtl property ?
394 {NS_sprm::v6::sprmTJc, { 2, L_FIX} }, // tap.jc jc (low order byte is significant)
395 {NS_sprm::v6::sprmTDxaLeft, { 2, L_FIX} }, // tap.rgdxaCenter dxa word
396 {NS_sprm::v6::sprmTDxaGapHalf, { 2, L_FIX} }, // tap.dxaGapHalf, tap.rgdxaCenter
397 {NS_sprm::v6::sprmTFCantSplit, { 1, L_FIX} }, // tap.fCantSplit 1 or 0 byte
398 {NS_sprm::v6::sprmTTableHeader, { 1, L_FIX} }, // tap.fTableHeader 1 or 0 byte
399 {NS_sprm::v6::sprmTTableBorders, {12, L_FIX} }, // tap.rgbrcTable complex 12 bytes
400 {NS_sprm::v6::sprmTDefTable10, { 0, L_VAR2} }, // tap.rgdxaCenter, tap.rgtc complex
401 {NS_sprm::v6::sprmTDyaRowHeight, { 2, L_FIX} }, // tap.dyaRowHeight dya word
402 {NS_sprm::v6::sprmTDefTable, { 0, L_VAR2} }, // tap.rgtc complex
403 {NS_sprm::v6::sprmTDefTableShd, { 1, L_VAR} }, // tap.rgshd complex
404 {NS_sprm::v6::sprmTTlp, { 4, L_FIX} }, // tap.tlp TLP 4 bytes
405 {NS_sprm::v6::sprmTSetBrc, { 5, L_FIX} }, // tap.rgtc[].rgbrc complex 5 bytes
406 {NS_sprm::v6::sprmTInsert, { 4, L_FIX} }, // tap.rgdxaCenter,tap.rgtc complex
407 {NS_sprm::v6::sprmTDelete, { 2, L_FIX} }, // tap.rgdxaCenter, tap.rgtc complex
408 {NS_sprm::v6::sprmTDxaCol, { 4, L_FIX} }, // tap.rgdxaCenter complex
409 {NS_sprm::v6::sprmTMerge, { 2, L_FIX} }, // tap.fFirstMerged, tap.fMerged complex
410 {NS_sprm::v6::sprmTSplit, { 2, L_FIX} }, // tap.fFirstMerged, tap.fMerged complex
411 {NS_sprm::v6::sprmTSetBrc10, { 5, L_FIX} }, // tap.rgtc[].rgbrc complex 5 bytes
412 {NS_sprm::v6::sprmTSetShd, { 4, L_FIX} }, // tap.rgshd complex 4 bytes
413 {207, { 0, L_VAR} } // rtl property ?
416 if (rFib.m_wIdent >= 0xa697 && rFib.m_wIdent <= 0xa699)
418 //see Read_AmbiguousSPRM for this oddity
419 static wwSprmSearcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms), true);
420 return &aSprmSrch;
423 static wwSprmSearcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
424 return &aSprmSrch;
427 void wwSprmSearcher::patchCJKVariant()
429 for (sal_uInt16 nId = 111; nId <= 113; ++nId)
431 SprmInfo& amb1 = map_[nId];
432 amb1.nLen = 2;
433 amb1.nVari = wwSprmParser::L_FIX;
437 template <class Sprm> static constexpr SprmInfoRow InfoRow()
439 return { Sprm::val, { Sprm::len, Sprm::varlen ? wwSprmParser::L_VAR : wwSprmParser::L_FIX } };
442 const wwSprmSearcher *wwSprmParser::GetWW8SprmSearcher()
444 //double lock me
445 //WW8+ Sprms
446 static const SprmInfoRow aSprms[] =
448 { 0, { 0, L_FIX} }, // "Default-sprm"/ is skipped
449 InfoRow<NS_sprm::PIstd>(), // pap.istd;istd (style code);short;
450 InfoRow<NS_sprm::PIstdPermute>(), // pap.istd;permutation vector
451 InfoRow<NS_sprm::PIncLvl>(), // pap.istd, pap.lvl;difference
452 // between istd of base PAP and istd of PAP to be
453 // produced
454 InfoRow<NS_sprm::PJc80>(), // pap.jc;jc (justification);byte;
455 {NS_sprm::LN_PFSideBySide, { 1, L_FIX} }, // "sprmPFSideBySide" pap.fSideBySide;0 or 1;byte;
456 InfoRow<NS_sprm::PFKeep>(), // pap.fKeep;0 or 1;byte;
457 InfoRow<NS_sprm::PFKeepFollow>(), // pap.fKeepFollow;0 or 1;byte;
458 InfoRow<NS_sprm::PFPageBreakBefore>(), // pap.fPageBreakBefore;
459 // 0 or 1
460 {NS_sprm::LN_PBrcl, { 1, L_FIX} }, // "sprmPBrcl" pap.brcl;brcl;byte;
461 {NS_sprm::LN_PBrcp, { 1, L_FIX} }, // "sprmPBrcp" pap.brcp;brcp;byte;
462 InfoRow<NS_sprm::PIlvl>(), // pap.ilvl;ilvl;byte;
463 InfoRow<NS_sprm::PIlfo>(), // pap.ilfo;ilfo (list index) ;short;
464 InfoRow<NS_sprm::PFNoLineNumb>(), // pap.fNoLnn;0 or 1;byte;
465 InfoRow<NS_sprm::PChgTabsPapx>(), // pap.itbdMac, pap.rgdxaTab,
466 // pap.rgtbd;complex
467 InfoRow<NS_sprm::PDxaRight80>(), // pap.dxaRight;dxa;word;
468 InfoRow<NS_sprm::PDxaLeft80>(), // pap.dxaLeft;dxa;word;
469 InfoRow<NS_sprm::PNest80>(), // pap.dxaLeft;dxa
470 InfoRow<NS_sprm::PDxaLeft180>(), // pap.dxaLeft1;dxa;word;
471 InfoRow<NS_sprm::PDyaLine>(), // pap.lspd;an LSPD, a long word
472 // structure consisting of a short of dyaLine
473 // followed by a short of fMultLinespace
474 InfoRow<NS_sprm::PDyaBefore>(), // pap.dyaBefore;dya;word;
475 InfoRow<NS_sprm::PDyaAfter>(), // pap.dyaAfter;dya;word;
476 InfoRow<NS_sprm::PChgTabs>(), // pap.itbdMac, pap.rgdxaTab,
477 // pap.rgtbd;complex
478 InfoRow<NS_sprm::PFInTable>(), // pap.fInTable;0 or 1;byte;
479 InfoRow<NS_sprm::PFTtp>(), // pap.fTtp;0 or 1;byte;
480 InfoRow<NS_sprm::PDxaAbs>(), // pap.dxaAbs;dxa;word;
481 InfoRow<NS_sprm::PDyaAbs>(), // pap.dyaAbs;dya;word;
482 InfoRow<NS_sprm::PDxaWidth>(), // pap.dxaWidth;dxa;word;
483 InfoRow<NS_sprm::PPc>(), // pap.pcHorz, pap.pcVert;complex
484 {NS_sprm::LN_PBrcTop10, { 2, L_FIX} }, // "sprmPBrcTop10" pap.brcTop;BRC10;word;
485 {NS_sprm::LN_PBrcLeft10, { 2, L_FIX} }, // "sprmPBrcLeft10" pap.brcLeft;BRC10;word;
486 {NS_sprm::LN_PBrcBottom10, { 2, L_FIX} }, // "sprmPBrcBottom10" pap.brcBottom;BRC10;word;
487 {NS_sprm::LN_PBrcRight10, { 2, L_FIX} }, // "sprmPBrcRight10" pap.brcRight;BRC10;word;
488 {NS_sprm::LN_PBrcBetween10, { 2, L_FIX} }, // "sprmPBrcBetween10" pap.brcBetween;BRC10;word;
489 {NS_sprm::LN_PBrcBar10, { 2, L_FIX} }, // "sprmPBrcBar10" pap.brcBar;BRC10;word;
490 {NS_sprm::LN_PDxaFromText10, { 2, L_FIX} }, // "sprmPDxaFromText10" pap.dxaFromText;dxa;word;
491 InfoRow<NS_sprm::PWr>(), // pap.wr;wr
492 InfoRow<NS_sprm::PBrcTop80>(), // pap.brcTop;BRC;long;
493 InfoRow<NS_sprm::PBrcLeft80>(), // pap.brcLeft;BRC;long;
494 InfoRow<NS_sprm::PBrcBottom80>(), // pap.brcBottom;BRC;long;
495 InfoRow<NS_sprm::PBrcRight80>(), // pap.brcRight;BRC;long;
496 InfoRow<NS_sprm::PBrcBetween80>(), // pap.brcBetween;BRC;long;
497 InfoRow<NS_sprm::PBrcBar80>(), // pap.brcBar;BRC;long;
498 InfoRow<NS_sprm::PFNoAutoHyph>(), // pap.fNoAutoHyph;0 or 1;byte;
499 InfoRow<NS_sprm::PWHeightAbs>(), // pap.wHeightAbs;w;word;
500 InfoRow<NS_sprm::PDcs>(), // pap.dcs;DCS;short;
501 InfoRow<NS_sprm::PShd80>(), // pap.shd;SHD;word;
502 InfoRow<NS_sprm::PDyaFromText>(), // pap.dyaFromText;dya;word;
503 InfoRow<NS_sprm::PDxaFromText>(), // pap.dxaFromText;dxa;word;
504 InfoRow<NS_sprm::PFLocked>(), // pap.fLocked;0 or 1;byte;
505 InfoRow<NS_sprm::PFWidowControl>(), // pap.fWidowControl;0 or 1
506 {NS_sprm::LN_PRuler, { 0, L_VAR} }, // "sprmPRuler" ;;variable length;
507 InfoRow<NS_sprm::PFKinsoku>(), // pap.fKinsoku;0 or 1;byte;
508 InfoRow<NS_sprm::PFWordWrap>(), // pap.fWordWrap;0 or 1;byte;
509 InfoRow<NS_sprm::PFOverflowPunct>(), // pap.fOverflowPunct;0 or 1
510 InfoRow<NS_sprm::PFTopLinePunct>(), // pap.fTopLinePunct;0 or 1
511 InfoRow<NS_sprm::PFAutoSpaceDE>(), // pap.fAutoSpaceDE;0 or 1
512 InfoRow<NS_sprm::PFAutoSpaceDN>(), // pap.fAutoSpaceDN;0 or 1
513 InfoRow<NS_sprm::PWAlignFont>(), // pap.wAlignFont;iFa
514 InfoRow<NS_sprm::PFrameTextFlow>(), // pap.fVertical pap.fBackward
515 // pap.fRotateFont;complex
516 {NS_sprm::LN_PISnapBaseLine, { 1, L_FIX} }, // "sprmPISnapBaseLine" obsolete: not applicable in
517 // Word97 and later versions;
518 {NS_sprm::LN_PAnld, { 0, L_VAR} }, // "sprmPAnld" pap.anld;;variable length;
519 {NS_sprm::LN_PPropRMark, { 0, L_VAR} }, // "sprmPPropRMark" pap.fPropRMark;complex
520 InfoRow<NS_sprm::POutLvl>(), // pap.lvl;has no effect if pap.istd
521 // is < 1 or is > 9
522 InfoRow<NS_sprm::PFBiDi>(), // ;;byte;
523 InfoRow<NS_sprm::PFNumRMIns>(), // pap.fNumRMIns;1 or 0;bit;
524 {NS_sprm::LN_PCrLf, { 1, L_FIX} }, // "sprmPCrLf" ;;byte;
525 InfoRow<NS_sprm::PNumRM>(), // pap.numrm;;variable length;
526 {NS_sprm::LN_PHugePapx, { 4, L_FIX} }, // "sprmPHugePapx" fc in the data stream to locate
527 // the huge grpprl
528 InfoRow<NS_sprm::PHugePapx>(), // fc in the data stream to locate
529 // the huge grpprl
530 InfoRow<NS_sprm::PFUsePgsuSettings>(), // pap.fUsePgsuSettings;
531 // 1 or 0
532 InfoRow<NS_sprm::PFAdjustRight>(), // pap.fAdjustRight;1 or 0;byte;
533 InfoRow<NS_sprm::CFRMarkDel>(), // chp.fRMarkDel;1 or 0;bit;
534 InfoRow<NS_sprm::CFRMarkIns>(), // chp.fRMark;1 or 0;bit;
535 InfoRow<NS_sprm::CFFldVanish>(), // chp.fFieldVanish;1 or 0;bit;
536 InfoRow<NS_sprm::CPicLocation>(), // chp.fcPic and chp.fSpec;
537 InfoRow<NS_sprm::CIbstRMark>(), // chp.ibstRMark;index into
538 // sttbRMark
539 InfoRow<NS_sprm::CDttmRMark>(), // chp.dttmRMark;DTTM;long;
540 InfoRow<NS_sprm::CFData>(), // chp.fData;1 or 0;bit;
541 InfoRow<NS_sprm::CIdslRMark>(), // chp.idslRMReason;an index to a
542 // table of strings defined in Word 6.0
543 // executables;short;
544 {NS_sprm::LN_CChs, { 1, L_FIX} }, // "sprmCChs" chp.fChsDiff and chp.chse;
545 InfoRow<NS_sprm::CSymbol>(), // chp.fSpec, chp.xchSym and
546 // chp.ftcSym
547 InfoRow<NS_sprm::CFOle2>(), // chp.fOle2;1 or 0;bit;
548 {NS_sprm::LN_CIdCharType, { 0, L_FIX} }, // "sprmCIdCharType" obsolete: not applicable in
549 // Word97 and later versions;
550 InfoRow<NS_sprm::CHighlight>(), // chp.fHighlight,
551 // chp.icoHighlight;ico (fHighlight is set to 1 iff
552 // ico is not 0)
553 {NS_sprm::LN_CObjLocation, { 4, L_FIX} }, // "sprmCObjLocation" chp.fcObj;FC;long;
554 {NS_sprm::LN_CFFtcAsciSymb, { 0, L_FIX} }, // "sprmCFFtcAsciSymb" ;;;
555 InfoRow<NS_sprm::CIstd>(), // chp.istd;istd, see stylesheet def
556 InfoRow<NS_sprm::CIstdPermute>(), // chp.istd;permutation vector
557 {NS_sprm::LN_CDefault, { 0, L_VAR} }, // "sprmCDefault" whole CHP;none;variable length;
558 InfoRow<NS_sprm::CPlain>(), // whole CHP;none;0;
559 InfoRow<NS_sprm::CKcd>(), // ;;;
560 InfoRow<NS_sprm::CFBold>(), // chp.fBold;0,1, 128, or 129
561 InfoRow<NS_sprm::CFItalic>(), // chp.fItalic;0,1, 128, or 129
562 InfoRow<NS_sprm::CFStrike>(), // chp.fStrike;0,1, 128, or 129
563 InfoRow<NS_sprm::CFOutline>(), // chp.fOutline;0,1, 128, or 129
564 InfoRow<NS_sprm::CFShadow>(), // chp.fShadow;0,1, 128, or 129
565 InfoRow<NS_sprm::CFSmallCaps>(), // chp.fSmallCaps;0,1, 128, or 129
566 InfoRow<NS_sprm::CFCaps>(), // chp.fCaps;0,1, 128, or 129
567 InfoRow<NS_sprm::CFVanish>(), // chp.fVanish;0,1, 128, or 129
568 {NS_sprm::LN_CFtcDefault, { 2, L_FIX} }, // "sprmCFtcDefault" ;ftc, only used internally
569 InfoRow<NS_sprm::CKul>(), // chp.kul;kul;byte;
570 {NS_sprm::LN_CSizePos, { 3, L_FIX} }, // "sprmCSizePos" chp.hps, chp.hpsPos;3 bytes;
571 InfoRow<NS_sprm::CDxaSpace>(), // chp.dxaSpace;dxa;word;
572 {NS_sprm::LN_CLid, { 2, L_FIX} }, // "sprmCLid" ;only used internally never stored
573 InfoRow<NS_sprm::CIco>(), // chp.ico;ico;byte;
574 InfoRow<NS_sprm::CHps>(), // chp.hps;hps
575 {NS_sprm::LN_CHpsInc, { 1, L_FIX} }, // "sprmCHpsInc" chp.hps;
576 InfoRow<NS_sprm::CHpsPos>(), // chp.hpsPos;hps;short; (doc wrong)
577 {NS_sprm::LN_CHpsPosAdj, { 1, L_FIX} }, // "sprmCHpsPosAdj" chp.hpsPos;hps
578 InfoRow<NS_sprm::CMajority>(), // chp.fBold, chp.fItalic,
579 // chp.fSmallCaps, chp.fVanish, chp.fStrike,
580 // chp.fCaps, chp.rgftc, chp.hps, chp.hpsPos,
581 // chp.kul, chp.dxaSpace, chp.ico,
582 // chp.rglid;complex;variable length, length byte
583 // plus size of following grpprl;
584 InfoRow<NS_sprm::CIss>(), // chp.iss;iss;byte;
585 {NS_sprm::LN_CHpsNew50, { 0, L_VAR} }, // "sprmCHpsNew50" chp.hps;hps;variable width
586 {NS_sprm::LN_CHpsInc1, { 0, L_VAR} }, // "sprmCHpsInc1" chp.hps;complex
587 InfoRow<NS_sprm::CHpsKern>(), // chp.hpsKern;hps;short;
588 {NS_sprm::LN_CMajority50, { 2, L_FIX} }, // "sprmCMajority50" chp.fBold, chp.fItalic,
589 // chp.fSmallCaps, chp.fVanish, chp.fStrike,
590 // chp.fCaps, chp.ftc, chp.hps, chp.hpsPos, chp.kul,
591 // chp.dxaSpace, chp.ico,;complex
592 {NS_sprm::LN_CHpsMul, { 2, L_FIX} }, // "sprmCHpsMul" chp.hps;percentage to grow hps
593 InfoRow<NS_sprm::CHresi>(), // chp.ysri;ysri;short;
594 InfoRow<NS_sprm::CRgFtc0>(), // chp.rgftc[0];ftc for ASCII text
595 InfoRow<NS_sprm::CRgFtc1>(), // chp.rgftc[1];ftc for Far East text
596 InfoRow<NS_sprm::CRgFtc2>(), // chp.rgftc[2];ftc for non-FE text
597 InfoRow<NS_sprm::CCharScale>(),
598 InfoRow<NS_sprm::CFDStrike>(), // chp.fDStrike;;byte;
599 InfoRow<NS_sprm::CFImprint>(), // chp.fImprint;1 or 0;bit;
600 InfoRow<NS_sprm::CFSpec>(), // chp.fSpec ;1 or 0;bit;
601 InfoRow<NS_sprm::CFObj>(), // chp.fObj;1 or 0;bit;
602 InfoRow<NS_sprm::CPropRMark90>(), // chp.fPropRMark,
603 // chp.ibstPropRMark, chp.dttmPropRMark;Complex
604 InfoRow<NS_sprm::CFEmboss>(), // chp.fEmboss;1 or 0;bit;
605 InfoRow<NS_sprm::CSfxText>(), // chp.sfxtText;text animation;byte;
606 InfoRow<NS_sprm::CFBiDi>(), // ;;;
607 {NS_sprm::LN_CFDiacColor, { 1, L_FIX} }, // "sprmCFDiacColor" ;;;
608 InfoRow<NS_sprm::CFBoldBi>(), // ;;;
609 InfoRow<NS_sprm::CFItalicBi>(), // ;;;
610 InfoRow<NS_sprm::CFtcBi>(),
611 InfoRow<NS_sprm::CLidBi>(), // ;;;
612 InfoRow<NS_sprm::CIcoBi>(), // ;;;
613 InfoRow<NS_sprm::CHpsBi>(), // ;;;
614 InfoRow<NS_sprm::CDispFldRMark>(), // chp.fDispFieldRMark,
615 // chp.ibstDispFieldRMark, chp.dttmDispFieldRMark ;
616 InfoRow<NS_sprm::CIbstRMarkDel>(), // chp.ibstRMarkDel;index into
617 // sttbRMark;short;
618 InfoRow<NS_sprm::CDttmRMarkDel>(), // chp.dttmRMarkDel;DTTM;long;
619 InfoRow<NS_sprm::CBrc80>(), // chp.brc;BRC;long;
620 InfoRow<NS_sprm::CShd80>(), // chp.shd;SHD;short;
621 InfoRow<NS_sprm::CIdslRMarkDel>(), // chp.idslRMReasonDel;an index
622 // to a table of strings defined in Word 6.0
623 // executables;short;
624 InfoRow<NS_sprm::CFUsePgsuSettings>(),
625 // chp.fUsePgsuSettings;1 or 0
626 {NS_sprm::LN_CCpg, { 2, L_FIX} }, // "sprmCCpg" ;;word;
627 InfoRow<NS_sprm::CRgLid0_80>(), // chp.rglid[0];LID: for non-FE text
628 InfoRow<NS_sprm::CRgLid1_80>(), // chp.rglid[1];LID: for Far East text
629 InfoRow<NS_sprm::CIdctHint>(), // chp.idctHint;IDCT:
630 {NS_sprm::LN_PicBrcl, { 1, L_FIX} }, // "sprmPicBrcl" pic.brcl;brcl (see PIC definition)
631 {NS_sprm::LN_PicScale, { 0, L_VAR} }, // "sprmPicScale" pic.mx, pic.my, pic.dxaCropleft,
632 // pic.dyaCropTop pic.dxaCropRight,
633 // pic.dyaCropBottom;Complex
634 InfoRow<NS_sprm::PicBrcTop80>(), // pic.brcTop;BRC;long;
635 InfoRow<NS_sprm::PicBrcLeft80>(), // pic.brcLeft;BRC;long;
636 InfoRow<NS_sprm::PicBrcBottom80>(), // pic.brcBottom;BRC;long;
637 InfoRow<NS_sprm::PicBrcRight80>(), // pic.brcRight;BRC;long;
638 InfoRow<NS_sprm::ScnsPgn>(), // sep.cnsPgn;cns;byte;
639 InfoRow<NS_sprm::SiHeadingPgn>(), // sep.iHeadingPgn;heading number
640 // level;byte;
641 {NS_sprm::LN_SOlstAnm, { 0, L_VAR} }, // "sprmSOlstAnm" sep.olstAnm;OLST;variable length;
642 InfoRow<NS_sprm::SDxaColWidth>(), // sep.rgdxaColWidthSpacing;
643 InfoRow<NS_sprm::SDxaColSpacing>(), // sep.rgdxaColWidthSpacing;
644 // complex
645 InfoRow<NS_sprm::SFEvenlySpaced>(), // sep.fEvenlySpaced;1 or 0
646 InfoRow<NS_sprm::SFProtected>(), // sep.fUnlocked;1 or 0;byte;
647 InfoRow<NS_sprm::SDmBinFirst>(), // sep.dmBinFirst;;word;
648 InfoRow<NS_sprm::SDmBinOther>(), // sep.dmBinOther;;word;
649 InfoRow<NS_sprm::SBkc>(), // sep.bkc;bkc;byte;
650 InfoRow<NS_sprm::SFTitlePage>(), // sep.fTitlePage;0 or 1;byte;
651 InfoRow<NS_sprm::SCcolumns>(), // sep.ccolM1;# of cols - 1;word;
652 InfoRow<NS_sprm::SDxaColumns>(), // sep.dxaColumns;dxa;word;
653 {NS_sprm::LN_SFAutoPgn, { 1, L_FIX} }, // "sprmSFAutoPgn" sep.fAutoPgn;obsolete;byte;
654 InfoRow<NS_sprm::SNfcPgn>(), // sep.nfcPgn;nfc;byte;
655 {NS_sprm::LN_SDyaPgn, { 2, L_FIX} }, // "sprmSDyaPgn" sep.dyaPgn;dya;short;
656 {NS_sprm::LN_SDxaPgn, { 2, L_FIX} }, // "sprmSDxaPgn" sep.dxaPgn;dya;short;
657 InfoRow<NS_sprm::SFPgnRestart>(), // sep.fPgnRestart;0 or 1;byte;
658 InfoRow<NS_sprm::SFEndnote>(), // sep.fEndnote;0 or 1;byte;
659 InfoRow<NS_sprm::SLnc>(), // sep.lnc;lnc;byte;
660 {NS_sprm::LN_SGprfIhdt, { 1, L_FIX} }, // "sprmSGprfIhdt" sep.grpfIhdt;grpfihdt
661 InfoRow<NS_sprm::SNLnnMod>(), // sep.nLnnMod;non-neg int.;word;
662 InfoRow<NS_sprm::SDxaLnn>(), // sep.dxaLnn;dxa;word;
663 InfoRow<NS_sprm::SDyaHdrTop>(), // sep.dyaHdrTop;dya;word;
664 InfoRow<NS_sprm::SDyaHdrBottom>(), // sep.dyaHdrBottom;dya;word;
665 InfoRow<NS_sprm::SLBetween>(), // sep.fLBetween;0 or 1;byte;
666 InfoRow<NS_sprm::SVjc>(), // sep.vjc;vjc;byte;
667 InfoRow<NS_sprm::SLnnMin>(), // sep.lnnMin;lnn;word;
668 InfoRow<NS_sprm::SPgnStart97>(), // sep.pgnStart;pgn;word;
669 InfoRow<NS_sprm::SBOrientation>(), // sep.dmOrientPage;dm;byte;
670 {NS_sprm::LN_SBCustomize, { 1, L_FIX} }, // "sprmSBCustomize" ;;;
671 InfoRow<NS_sprm::SXaPage>(), // sep.xaPage;xa;word;
672 InfoRow<NS_sprm::SYaPage>(), // sep.yaPage;ya;word;
673 InfoRow<NS_sprm::SDxaLeft>(), // sep.dxaLeft;dxa;word;
674 InfoRow<NS_sprm::SDxaRight>(), // sep.dxaRight;dxa;word;
675 InfoRow<NS_sprm::SDyaTop>(), // sep.dyaTop;dya;word;
676 InfoRow<NS_sprm::SDyaBottom>(), // sep.dyaBottom;dya;word;
677 InfoRow<NS_sprm::SDzaGutter>(), // sep.dzaGutter;dza;word;
678 InfoRow<NS_sprm::SDmPaperReq>(), // sep.dmPaperReq;dm;word;
679 {NS_sprm::LN_SPropRMark, { 0, L_VAR} }, // "sprmSPropRMark" sep.fPropRMark,
680 // sep.ibstPropRMark, sep.dttmPropRMark ;complex
681 InfoRow<NS_sprm::SFBiDi>(), // ;;;
682 {NS_sprm::LN_SFFacingCol, { 1, L_FIX} }, // "sprmSFFacingCol" ;;;
683 InfoRow<NS_sprm::SFRTLGutter>(), //, set to one if gutter is on
684 // right
685 InfoRow<NS_sprm::SBrcTop80>(), // sep.brcTop;BRC;long;
686 InfoRow<NS_sprm::SBrcLeft80>(), // sep.brcLeft;BRC;long;
687 InfoRow<NS_sprm::SBrcBottom80>(), // sep.brcBottom;BRC;long;
688 InfoRow<NS_sprm::SBrcRight80>(), // sep.brcRight;BRC;long;
689 InfoRow<NS_sprm::SPgbProp>(), // sep.pgbProp;;word;
690 InfoRow<NS_sprm::SDxtCharSpace>(), // sep.dxtCharSpace;dxt;long;
691 InfoRow<NS_sprm::SDyaLinePitch>(),
692 // sep.dyaLinePitch;dya; WRONG:long; RIGHT:short; !
693 InfoRow<NS_sprm::SClm>(), // ;;;
694 InfoRow<NS_sprm::STextFlow>(), // sep.wTextFlow;complex
695 InfoRow<NS_sprm::TJc90>(), // tap.jc;jc;word (low order byte is
696 // significant);
697 InfoRow<NS_sprm::TDxaLeft>(), // tap.rgdxaCenter
698 InfoRow<NS_sprm::TDxaGapHalf>(), // tap.dxaGapHalf,
699 // tap.rgdxaCenter
700 InfoRow<NS_sprm::TFCantSplit90>(), // tap.fCantSplit90;1 or 0;byte;
701 InfoRow<NS_sprm::TTableHeader>(), // tap.fTableHeader;1 or 0;byte;
702 InfoRow<NS_sprm::TFCantSplit>(), // tap.fCantSplit;1 or 0;byte;
703 InfoRow<NS_sprm::TTableBorders80>(), // tap.rgbrcTable;complex
704 {NS_sprm::LN_TDefTable10, { 0, L_VAR2} }, // "sprmTDefTable10" tap.rgdxaCenter,
705 // tap.rgtc;complex
706 InfoRow<NS_sprm::TDyaRowHeight>(), // tap.dyaRowHeight;dya;word;
707 {NS_sprm::LN_TDefTable, { 0, L_VAR2} }, // "sprmTDefTable" tap.rgtc;complex
708 InfoRow<NS_sprm::TDefTableShd80>(), // tap.rgshd;complex
709 InfoRow<NS_sprm::TTlp>(), // tap.tlp;TLP;4 bytes;
710 InfoRow<NS_sprm::TFBiDi>(), // ;;;
711 {NS_sprm::LN_THTMLProps, { 1, L_FIX} }, // "sprmTHTMLProps" ;;;
712 InfoRow<NS_sprm::TSetBrc80>(), // tap.rgtc[].rgbrc;complex
713 InfoRow<NS_sprm::TInsert>(), // tap.rgdxaCenter, tap.rgtc;complex
714 InfoRow<NS_sprm::TDelete>(), // tap.rgdxaCenter, tap.rgtc;complex
715 InfoRow<NS_sprm::TDxaCol>(), // tap.rgdxaCenter;complex
716 InfoRow<NS_sprm::TMerge>(), // tap.fFirstMerged, tap.fMerged;
717 InfoRow<NS_sprm::TSplit>(), // tap.fFirstMerged, tap.fMerged;
718 {NS_sprm::LN_TSetBrc10, { 0, L_VAR} }, // "sprmTSetBrc10" tap.rgtc[].rgbrc;complex
719 {NS_sprm::LN_TSetShd80, { 0, L_VAR} }, // "sprmTSetShd80" tap.rgshd;complex
720 {NS_sprm::LN_TSetShdOdd80, { 0, L_VAR} }, // "sprmTSetShdOdd80" tap.rgshd;complex
721 InfoRow<NS_sprm::TTextFlow>(), // tap.rgtc[].fVerticaltap,
722 // rgtc[].fBackwardtap, rgtc[].fRotateFont;0 or 10
723 // or 10 or 1;word;
724 {NS_sprm::LN_TDiagLine, { 1, L_FIX} }, // "sprmTDiagLine" ;;;
725 InfoRow<NS_sprm::TVertMerge>(), // tap.rgtc[].vertMerge
726 InfoRow<NS_sprm::TVertAlign>(), // tap.rgtc[].vertAlign
727 InfoRow<NS_sprm::CFELayout>(),
728 InfoRow<NS_sprm::PItap>(), // undocumented
729 InfoRow<NS_sprm::TTableWidth>(), // undocumented
730 InfoRow<NS_sprm::TDefTableShd>(),
731 InfoRow<NS_sprm::TTableBorders>(),
732 InfoRow<NS_sprm::TBrcTopCv>(), // undocumented
733 InfoRow<NS_sprm::TBrcLeftCv>(), // undocumented
734 InfoRow<NS_sprm::TBrcBottomCv>(), // undocumented
735 InfoRow<NS_sprm::TBrcRightCv>(), // undocumented
736 InfoRow<NS_sprm::TCellPadding>(), // undocumented
737 InfoRow<NS_sprm::TCellPaddingDefault>(), // undocumented
738 {0xD238, { 0, L_VAR} }, // undocumented sep
739 InfoRow<NS_sprm::PBrcTop>(),
740 InfoRow<NS_sprm::PBrcLeft>(),
741 InfoRow<NS_sprm::PBrcBottom>(),
742 InfoRow<NS_sprm::PBrcRight>(),
743 InfoRow<NS_sprm::PBrcBetween>(),
744 InfoRow<NS_sprm::TWidthIndent>(), // undocumented
745 InfoRow<NS_sprm::CRgLid0>(), // chp.rglid[0];LID: for non-FE text
746 InfoRow<NS_sprm::CRgLid1>(), // chp.rglid[1];LID: for Far East text
747 {0x6463, { 4, L_FIX} }, // undocumented
748 InfoRow<NS_sprm::PJc>(), // undoc, must be asian version of "sprmPJc"
749 InfoRow<NS_sprm::PDxaRight>(), // undoc, must be asian version of "sprmPDxaRight"
750 InfoRow<NS_sprm::PDxaLeft>(), // undoc, must be asian version of "sprmPDxaLeft"
751 InfoRow<NS_sprm::PDxaLeft1>(), // undoc, must be asian version of "sprmPDxaLeft1"
752 InfoRow<NS_sprm::TFAutofit>(), // undocumented
753 InfoRow<NS_sprm::TPc>(), // undocumented
754 InfoRow<NS_sprm::SRsid>(), // undocumented, sep, perhaps related to textgrids ?
755 InfoRow<NS_sprm::SFpc>(), // undocumented, sep
756 InfoRow<NS_sprm::PFInnerTableCell>(), // undocumented, subtable "sprmPFInTable" equiv ?
757 InfoRow<NS_sprm::PFInnerTtp>(), // undocumented, subtable "sprmPFTtp" equiv ?
758 InfoRow<NS_sprm::TDxaAbs>(), // undocumented
759 InfoRow<NS_sprm::TDyaAbs>(), // undocumented
760 InfoRow<NS_sprm::TDxaFromText>(), // undocumented
761 InfoRow<NS_sprm::CRsidProp>(), // undocumented
762 InfoRow<NS_sprm::CRsidText>(), // undocumented
763 InfoRow<NS_sprm::CCv>(), // text colour
764 InfoRow<NS_sprm::PShd>(), // undocumented, para back colour
765 InfoRow<NS_sprm::PRsid>(), // undocumented
766 InfoRow<NS_sprm::PTableProps>(), // undocumented
767 InfoRow<NS_sprm::TWidthBefore>(), // undocumented
768 InfoRow<NS_sprm::TSetShdTable>(), // undocumented, something to do with colour.
769 InfoRow<NS_sprm::TDefTableShdRaw>(), // undocumented, something to do with colour.
770 InfoRow<NS_sprm::CShd>(), // text backcolour
771 InfoRow<NS_sprm::SRncFtn>(), // undocumented, sep
772 InfoRow<NS_sprm::PFDyaBeforeAuto>(), // undocumented, para autobefore
773 InfoRow<NS_sprm::PFDyaAfterAuto>(), // undocumented, para autoafter
774 // "sprmPFContextualSpacing", don't add space between para of the same style
775 InfoRow<NS_sprm::PFContextualSpacing>(),
778 static wwSprmSearcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
779 return &aSprmSrch;
782 wwSprmParser::wwSprmParser(const WW8Fib& rFib) : meVersion(rFib.GetFIBVersion())
784 OSL_ENSURE((meVersion >= ww::eWW1 && meVersion <= ww::eWW8),
785 "Impossible value for version");
787 mnDelta = (ww::IsSevenMinus(meVersion)) ? 0 : 1;
789 if (meVersion <= ww::eWW2)
790 mpKnownSprms = GetWW2SprmSearcher();
791 else if (meVersion < ww::eWW8)
792 mpKnownSprms = GetWW6SprmSearcher(rFib);
793 else
794 mpKnownSprms = GetWW8SprmSearcher();
797 SprmInfo wwSprmParser::GetSprmInfo(sal_uInt16 nId) const
799 const SprmInfo* pFound = mpKnownSprms->search(nId);
800 if (pFound != nullptr)
802 return *pFound;
805 OSL_ENSURE(ww::IsEightPlus(meVersion),
806 "Unknown ww7- sprm, dangerous, report to development");
808 //All the unknown ww7 sprms appear to be variable (which makes sense)
809 SprmInfo aSrch = { 0, L_VAR };
810 if (ww::IsEightPlus(meVersion)) //We can recover perfectly in this case
812 aSrch.nVari = L_FIX;
813 switch (nId >> 13)
815 case 0:
816 case 1:
817 aSrch.nLen = 1;
818 break;
819 case 2:
820 aSrch.nLen = 2;
821 break;
822 case 3:
823 aSrch.nLen = 4;
824 break;
825 case 4:
826 case 5:
827 aSrch.nLen = 2;
828 break;
829 case 6:
830 aSrch.nLen = 0;
831 aSrch.nVari = L_VAR;
832 break;
833 case 7:
834 default:
835 aSrch.nLen = 3;
836 break;
839 return aSrch;
842 //-end
844 static sal_uInt8 Get_Byte( sal_uInt8 *& p )
846 sal_uInt8 n = *p;
847 p += 1;
848 return n;
851 static sal_uInt16 Get_UShort( sal_uInt8 *& p )
853 const sal_uInt16 n = SVBT16ToUInt16( *reinterpret_cast<SVBT16*>(p) );
854 p += 2;
855 return n;
858 static sal_Int16 Get_Short( sal_uInt8 *& p )
860 return Get_UShort(p);
863 static sal_uInt32 Get_ULong( sal_uInt8 *& p )
865 sal_uInt32 n = SVBT32ToUInt32( *reinterpret_cast<SVBT32*>(p) );
866 p += 4;
867 return n;
870 static sal_Int32 Get_Long( sal_uInt8 *& p )
872 return Get_ULong(p);
875 WW8SprmIter::WW8SprmIter(const sal_uInt8* pSprms_, sal_Int32 nLen_,
876 const wwSprmParser &rParser)
877 : mrSprmParser(rParser), m_pSprms( pSprms_), m_nRemLen( nLen_)
879 UpdateMyMembers();
882 void WW8SprmIter::SetSprms(const sal_uInt8* pSprms_, sal_Int32 nLen_)
884 m_pSprms = pSprms_;
885 m_nRemLen = nLen_;
886 UpdateMyMembers();
889 void WW8SprmIter::advance()
891 if (m_nRemLen > 0 )
893 sal_uInt16 nSize = m_nCurrentSize;
894 if (nSize > m_nRemLen)
895 nSize = m_nRemLen;
896 m_pSprms += nSize;
897 m_nRemLen -= nSize;
898 UpdateMyMembers();
902 void WW8SprmIter::UpdateMyMembers()
904 bool bValid = (m_pSprms && m_nRemLen >= mrSprmParser.MinSprmLen());
906 if (bValid)
908 m_nCurrentId = mrSprmParser.GetSprmId(m_pSprms);
909 m_nCurrentSize = mrSprmParser.GetSprmSize(m_nCurrentId, m_pSprms, m_nRemLen);
910 m_pCurrentParams = m_pSprms + mrSprmParser.DistanceToData(m_nCurrentId);
911 bValid = m_nCurrentSize <= m_nRemLen;
912 SAL_WARN_IF(!bValid, "sw.ww8", "sprm longer than remaining bytes, doc or parser is wrong");
915 if (!bValid)
917 m_nCurrentId = 0;
918 m_pCurrentParams = nullptr;
919 m_nCurrentSize = 0;
920 m_nRemLen = 0;
924 SprmResult WW8SprmIter::FindSprm(sal_uInt16 nId, bool bFindFirst, const sal_uInt8* pNextByteMatch)
926 SprmResult aRet;
928 while (GetSprms())
930 if (GetCurrentId() == nId)
932 sal_Int32 nFixedLen = mrSprmParser.DistanceToData(nId);
933 sal_Int32 nL = mrSprmParser.GetSprmSize(nId, GetSprms(), GetRemLen());
934 SprmResult aSprmResult(GetCurrentParams(), nL - nFixedLen);
935 // typically pNextByteMatch is nullptr and we just return the first match
936 // very occasionally we want one with a specific following byte
937 if ( !pNextByteMatch || (aSprmResult.nRemainingData >= 1 && *aSprmResult.pSprm == *pNextByteMatch) )
939 if ( bFindFirst )
940 return aSprmResult;
941 aRet = aSprmResult;
944 advance();
947 return aRet;
950 // temporary test
951 // WW8PLCFx_PCDAttrs cling to WW8PLCF_Pcd and therefore do not have their own iterators.
952 // All methods relating to iterators are therefore dummies.
953 WW8PLCFx_PCDAttrs::WW8PLCFx_PCDAttrs(const WW8Fib& rFib,
954 WW8PLCFx_PCD* pPLCFx_PCD, const WW8ScannerBase* pBase)
955 : WW8PLCFx(rFib, true), m_pPcdI(pPLCFx_PCD->GetPLCFIter()),
956 m_pPcd(pPLCFx_PCD), mrGrpprls(pBase->m_aPieceGrpprls)
960 sal_uInt32 WW8PLCFx_PCDAttrs::GetIdx() const
962 return 0;
965 void WW8PLCFx_PCDAttrs::SetIdx(sal_uInt32)
969 bool WW8PLCFx_PCDAttrs::SeekPos(WW8_CP )
971 return true;
974 void WW8PLCFx_PCDAttrs::advance()
978 WW8_CP WW8PLCFx_PCDAttrs::Where()
980 return m_pPcd ? m_pPcd->Where() : WW8_CP_MAX;
983 void WW8PLCFx_PCDAttrs::GetSprms(WW8PLCFxDesc* p)
985 void* pData;
987 p->bRealLineEnd = false;
988 if ( !m_pPcdI || !m_pPcdI->Get(p->nStartPos, p->nEndPos, pData) )
990 // PLCF fully processed
991 p->nStartPos = p->nEndPos = WW8_CP_MAX;
992 p->pMemPos = nullptr;
993 p->nSprmsLen = 0;
994 return;
997 const sal_uInt16 nPrm = SVBT16ToUInt16( static_cast<WW8_PCD*>(pData)->prm );
998 if ( nPrm & 1 )
1000 // PRM Variant 2
1001 const sal_uInt16 nSprmIdx = nPrm >> 1;
1003 if( nSprmIdx >= mrGrpprls.size() )
1005 // Invalid Index
1006 p->nStartPos = p->nEndPos = WW8_CP_MAX;
1007 p->pMemPos = nullptr;
1008 p->nSprmsLen = 0;
1009 return;
1011 const sal_uInt8* pSprms = mrGrpprls[ nSprmIdx ].get();
1013 p->nSprmsLen = SVBT16ToUInt16( pSprms ); // Length
1014 pSprms += 2;
1015 p->pMemPos = pSprms; // Position
1017 else
1019 // SPRM is stored directly into members var
1021 These are the attr that are in the piece-table instead of in the text!
1024 if (IsSevenMinus(GetFIBVersion()))
1026 m_aShortSprm[0] = static_cast<sal_uInt8>( ( nPrm & 0xfe) >> 1 );
1027 m_aShortSprm[1] = static_cast<sal_uInt8>( nPrm >> 8 );
1028 p->nSprmsLen = nPrm ? 2 : 0; // length
1030 // store Position of internal mini storage in Data Pointer
1031 p->pMemPos = m_aShortSprm;
1033 else
1035 p->pMemPos = nullptr;
1036 p->nSprmsLen = 0;
1037 sal_uInt8 nSprmListIdx = static_cast<sal_uInt8>((nPrm & 0xfe) >> 1);
1038 if( nSprmListIdx )
1040 // process Sprm Id Matching as explained in MS Documentation
1042 // ''Property Modifier(variant 1) (PRM)''
1043 // see file: s62f39.htm
1045 // Since Sprm is 7 bits, rgsprmPrm can hold 0x80 entries.
1046 static const sal_uInt16 aSprmId[0x80] =
1048 // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1049 0x0000,0x0000,0x0000,0x0000,
1050 // sprmPIncLvl, sprmPJc, sprmPFSideBySide, sprmPFKeep
1051 0x2402,0x2403,NS_sprm::LN_PFSideBySide,0x2405,
1052 // sprmPFKeepFollow, sprmPFPageBreakBefore, sprmPBrcl,
1053 // sprmPBrcp
1054 0x2406,0x2407,NS_sprm::LN_PBrcl,NS_sprm::LN_PBrcp,
1055 // sprmPIlvl, sprmNoop, sprmPFNoLineNumb, sprmNoop
1056 0x260A,0x0000,0x240C,0x0000,
1057 // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1058 0x0000,0x0000,0x0000,0x0000,
1059 // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1060 0x0000,0x0000,0x0000,0x0000,
1061 // sprmPFInTable, sprmPFTtp, sprmNoop, sprmNoop
1062 0x2416,0x2417,0x0000,0x0000,
1063 // sprmNoop, sprmPPc, sprmNoop, sprmNoop
1064 0x0000,0x261B,0x0000,0x0000,
1065 // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1066 0x0000,0x0000,0x0000,0x0000,
1067 // sprmNoop, sprmPWr, sprmNoop, sprmNoop
1068 0x0000,0x2423,0x0000,0x0000,
1069 // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1070 0x0000,0x0000,0x0000,0x0000,
1071 // sprmPFNoAutoHyph, sprmNoop, sprmNoop, sprmNoop
1072 0x242A,0x0000,0x0000,0x0000,
1073 // sprmNoop, sprmNoop, sprmPFLocked, sprmPFWidowControl
1074 0x0000,0x0000,0x2430,0x2431,
1075 // sprmNoop, sprmPFKinsoku, sprmPFWordWrap,
1076 // sprmPFOverflowPunct
1077 0x0000,0x2433,0x2434,0x2435,
1078 // sprmPFTopLinePunct, sprmPFAutoSpaceDE,
1079 // sprmPFAutoSpaceDN, sprmNoop
1080 0x2436,0x2437,0x2438,0x0000,
1081 // sprmNoop, sprmPISnapBaseLine, sprmNoop, sprmNoop
1082 0x0000,NS_sprm::LN_PISnapBaseLine,0x000,0x0000,
1083 // sprmNoop, sprmCFStrikeRM, sprmCFRMark, sprmCFFieldVanish
1084 0x0000,0x0800,0x0801,0x0802,
1085 // sprmNoop, sprmNoop, sprmNoop, sprmCFData
1086 0x0000,0x0000,0x0000,0x0806,
1087 // sprmNoop, sprmNoop, sprmNoop, sprmCFOle2
1088 0x0000,0x0000,0x0000,0x080A,
1089 // sprmNoop, sprmCHighlight, sprmCFEmboss, sprmCSfxText
1090 0x0000,0x2A0C,0x0858,0x2859,
1091 // sprmNoop, sprmNoop, sprmNoop, sprmCPlain
1092 0x0000,0x0000,0x0000,0x2A33,
1093 // sprmNoop, sprmCFBold, sprmCFItalic, sprmCFStrike
1094 0x0000,0x0835,0x0836,0x0837,
1095 // sprmCFOutline, sprmCFShadow, sprmCFSmallCaps, sprmCFCaps,
1096 0x0838,0x0839,0x083a,0x083b,
1097 // sprmCFVanish, sprmNoop, sprmCKul, sprmNoop,
1098 0x083C,0x0000,0x2A3E,0x0000,
1099 // sprmNoop, sprmNoop, sprmCIco, sprmNoop,
1100 0x0000,0x0000,0x2A42,0x0000,
1101 // sprmCHpsInc, sprmNoop, sprmCHpsPosAdj, sprmNoop,
1102 NS_sprm::LN_CHpsInc,0x0000,NS_sprm::LN_CHpsPosAdj,0x0000,
1103 // sprmCIss, sprmNoop, sprmNoop, sprmNoop,
1104 0x2A48,0x0000,0x0000,0x0000,
1105 // sprmNoop, sprmNoop, sprmNoop, sprmNoop,
1106 0x0000,0x0000,0x0000,0x0000,
1107 // sprmNoop, sprmNoop, sprmNoop, sprmCFDStrike,
1108 0x0000,0x0000,0x0000,0x2A53,
1109 // sprmCFImprint, sprmCFSpec, sprmCFObj, sprmPicBrcl,
1110 0x0854,0x0855,0x0856,NS_sprm::LN_PicBrcl,
1111 // sprmPOutLvl, sprmPFBiDi, sprmNoop, sprmNoop,
1112 0x2640,0x2441,0x0000,0x0000,
1113 // sprmNoop, sprmNoop, sprmPPnbrRMarkNot
1114 0x0000,0x0000,0x0000,0x0000
1117 // find real Sprm Id:
1118 const sal_uInt16 nSprmId = aSprmId[ nSprmListIdx ];
1120 if( nSprmId )
1122 // move Sprm Id and Sprm Param to internal mini storage:
1123 m_aShortSprm[0] = static_cast<sal_uInt8>( nSprmId & 0x00ff) ;
1124 m_aShortSprm[1] = static_cast<sal_uInt8>( ( nSprmId & 0xff00) >> 8 );
1125 m_aShortSprm[2] = static_cast<sal_uInt8>( nPrm >> 8 );
1127 // store Sprm Length in member:
1128 p->nSprmsLen = nPrm ? 3 : 0;
1130 // store Position of internal mini storage in Data Pointer
1131 p->pMemPos = m_aShortSprm;
1138 WW8PLCFx_PCD::WW8PLCFx_PCD(const WW8Fib& rFib, WW8PLCFpcd* pPLCFpcd,
1139 WW8_CP nStartCp, bool bVer67P)
1140 : WW8PLCFx(rFib, false), m_nClipStart(-1)
1142 // construct own iterator
1143 m_pPcdI.reset( new WW8PLCFpcd_Iter(*pPLCFpcd, nStartCp) );
1144 m_bVer67= bVer67P;
1147 WW8PLCFx_PCD::~WW8PLCFx_PCD()
1151 sal_uInt32 WW8PLCFx_PCD::GetIMax() const
1153 return m_pPcdI ? m_pPcdI->GetIMax() : 0;
1156 sal_uInt32 WW8PLCFx_PCD::GetIdx() const
1158 return m_pPcdI ? m_pPcdI->GetIdx() : 0;
1161 void WW8PLCFx_PCD::SetIdx(sal_uInt32 nIdx)
1163 if (m_pPcdI)
1164 m_pPcdI->SetIdx( nIdx );
1167 bool WW8PLCFx_PCD::SeekPos(WW8_CP nCpPos)
1169 return m_pPcdI && m_pPcdI->SeekPos( nCpPos );
1172 WW8_CP WW8PLCFx_PCD::Where()
1174 return m_pPcdI ? m_pPcdI->Where() : WW8_CP_MAX;
1177 tools::Long WW8PLCFx_PCD::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
1179 void* pData;
1180 rLen = 0;
1182 if ( !m_pPcdI || !m_pPcdI->Get(rStart, rEnd, pData) )
1184 rStart = rEnd = WW8_CP_MAX;
1185 return -1;
1187 return m_pPcdI->GetIdx();
1190 void WW8PLCFx_PCD::advance()
1192 OSL_ENSURE(m_pPcdI , "missing pPcdI");
1193 if (m_pPcdI)
1194 m_pPcdI->advance();
1197 WW8_FC WW8PLCFx_PCD::CurrentPieceStartCp2Fc( WW8_CP nCp )
1199 WW8_CP nCpStart, nCpEnd;
1200 void* pData;
1202 if ( !m_pPcdI->Get(nCpStart, nCpEnd, pData) )
1204 OSL_ENSURE( false, "CurrentPieceStartCp2Fc() with false Cp found (1)" );
1205 return WW8_FC_MAX;
1208 OSL_ENSURE( nCp >= nCpStart && nCp < nCpEnd,
1209 "AktPieceCp2Fc() with false Cp found (2)" );
1211 if( nCp < nCpStart )
1212 nCp = nCpStart;
1213 if( nCp >= nCpEnd )
1214 nCp = nCpEnd - 1;
1216 bool bIsUnicode = false;
1217 WW8_FC nFC = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
1218 if( !m_bVer67 )
1219 nFC = WW8PLCFx_PCD::TransformPieceAddress( nFC, bIsUnicode );
1221 WW8_CP nDistance;
1222 bool bFail = o3tl::checked_sub(nCp, nCpStart, nDistance);
1223 if (bFail)
1225 SAL_WARN("sw.ww8", "broken offset, ignoring");
1226 return WW8_FC_MAX;
1229 if (bIsUnicode)
1231 bFail = o3tl::checked_multiply<WW8_CP>(nDistance, 2, nDistance);
1232 if (bFail)
1234 SAL_WARN("sw.ww8", "broken offset, ignoring");
1235 return WW8_FC_MAX;
1239 WW8_FC nRet;
1240 bFail = o3tl::checked_add(nFC, nDistance, nRet);
1241 if (bFail)
1243 SAL_WARN("sw.ww8", "broken offset, ignoring");
1244 return WW8_FC_MAX;
1247 return nRet;
1250 void WW8PLCFx_PCD::CurrentPieceFc2Cp( WW8_CP& rStartPos, WW8_CP& rEndPos,
1251 const WW8ScannerBase *pSBase )
1253 //No point going anywhere with this
1254 if ((rStartPos == WW8_CP_MAX) && (rEndPos == WW8_CP_MAX))
1255 return;
1257 rStartPos = pSBase->WW8Fc2Cp( rStartPos );
1258 rEndPos = pSBase->WW8Fc2Cp( rEndPos );
1261 WW8_CP WW8PLCFx_PCD::CurrentPieceStartFc2Cp( WW8_FC nStartPos )
1263 WW8_CP nCpStart, nCpEnd;
1264 void* pData;
1265 if ( !m_pPcdI->Get( nCpStart, nCpEnd, pData ) )
1267 OSL_ENSURE( false, "CurrentPieceStartFc2Cp() - error" );
1268 return WW8_CP_MAX;
1270 bool bIsUnicode = false;
1271 sal_Int32 nFcStart = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
1272 if( !m_bVer67 )
1273 nFcStart = WW8PLCFx_PCD::TransformPieceAddress( nFcStart, bIsUnicode );
1275 sal_Int32 nUnicodeFactor = bIsUnicode ? 2 : 1;
1277 if( nStartPos < nFcStart )
1278 nStartPos = nFcStart;
1280 WW8_CP nCpLen;
1281 bool bFail = o3tl::checked_sub(nCpEnd, nCpStart, nCpLen);
1282 if (bFail)
1284 SAL_WARN("sw.ww8", "broken offset, ignoring");
1285 return WW8_CP_MAX;
1288 WW8_CP nCpLenBytes;
1289 bFail = o3tl::checked_multiply(nCpLen, nUnicodeFactor, nCpLenBytes);
1290 if (bFail)
1292 SAL_WARN("sw.ww8", "broken offset, ignoring");
1293 return WW8_CP_MAX;
1296 WW8_FC nFcLen;
1297 bFail = o3tl::checked_add(nFcStart, nCpLenBytes, nFcLen);
1298 if (bFail)
1300 SAL_WARN("sw.ww8", "broken offset, ignoring");
1301 return WW8_CP_MAX;
1304 WW8_FC nFcEnd;
1305 bFail = o3tl::checked_add(nFcStart, nFcLen, nFcEnd);
1306 if (bFail)
1308 SAL_WARN("sw.ww8", "broken offset, ignoring");
1309 return WW8_CP_MAX;
1313 if (nStartPos >= nFcEnd)
1314 nStartPos = nFcEnd - (1 * nUnicodeFactor);
1316 WW8_FC nFcDiff = (nStartPos - nFcStart) / nUnicodeFactor;
1318 WW8_FC nCpRet;
1319 bFail = o3tl::checked_add(nCpStart, nFcDiff, nCpRet);
1320 if (bFail)
1322 SAL_WARN("sw.ww8", "broken offset, ignoring");
1323 return WW8_CP_MAX;
1326 return nCpRet;
1329 // Helper routines for all
1331 // Convert BRC from WW6 to WW8 format
1332 WW8_BRC::WW8_BRC(const WW8_BRCVer6& brcVer6)
1334 sal_uInt8 _dptLineWidth = brcVer6.dxpLineWidth(),
1335 _brcType = brcVer6.brcType();
1337 if (_dptLineWidth > 5) // this signifies dashed(6) or dotted(7) line
1339 _brcType = _dptLineWidth;
1340 _dptLineWidth = 1;
1342 _dptLineWidth *= 6; // convert units from 0.75pt to 1/8pt
1344 *this = WW8_BRC(_dptLineWidth, _brcType, brcVer6.ico(), brcVer6.dxpSpace(),
1345 brcVer6.fShadow(), false);
1348 // Convert BRC from WW8 to WW9 format
1349 WW8_BRCVer9::WW8_BRCVer9(const WW8_BRC& brcVer8)
1351 if (brcVer8.isNil()) {
1352 UInt32ToSVBT32(0, aBits1);
1353 UInt32ToSVBT32(0xffffffff, aBits2);
1355 else
1357 sal_uInt32 _cv = brcVer8.ico() == 0 ? 0xff000000 // "auto" colour
1358 : wwUtility::RGBToBGR(SwWW8ImplReader::GetCol(brcVer8.ico()));
1359 *this = WW8_BRCVer9(_cv, brcVer8.dptLineWidth(), brcVer8.brcType(),
1360 brcVer8.dptSpace(), brcVer8.fShadow(), brcVer8.fFrame());
1364 short WW8_BRC::DetermineBorderProperties(short *pSpace) const
1366 WW8_BRCVer9 brcVer9(*this);
1367 return brcVer9.DetermineBorderProperties(pSpace);
1370 short WW8_BRCVer9::DetermineBorderProperties(short *pSpace) const
1373 Word does not factor the width of the border into the width/height
1374 stored in the information for graphic/table/object widths, so we need
1375 to figure out this extra width here and utilize the returned size in
1376 our calculations
1378 short nMSTotalWidth;
1380 //Specification in 8ths of a point, 1 Point = 20 Twips, so by 2.5
1381 nMSTotalWidth = static_cast<short>(dptLineWidth()) * 20 / 8;
1383 //Figure out the real size of the border according to word
1384 switch (brcType())
1386 //Note that codes over 25 are undocumented, and I can't create
1387 //these 4 here in the wild.
1388 case 2:
1389 case 4:
1390 case 5:
1391 case 22:
1392 OSL_FAIL("Can't create these from the menus, please report");
1393 break;
1394 default:
1395 case 23: //Only 3pt in the menus, but honours the size setting.
1396 break;
1397 case 10:
1399 triple line is five times the width of an ordinary line,
1400 except that the smallest 1/4 point size appears to have
1401 exactly the same total border width as a 3/4 point size
1402 ordinary line, i.e. three times the nominal line width. The
1403 second smallest 1/2 point size appears to have exactly the
1404 total border width as a 2 1/4 border, i.e 4.5 times the size.
1406 if (nMSTotalWidth == 5)
1407 nMSTotalWidth*=3;
1408 else if (nMSTotalWidth == 10)
1409 nMSTotalWidth = nMSTotalWidth*9/2;
1410 else
1411 nMSTotalWidth*=5;
1412 break;
1413 case 20:
1415 wave, the dimensions appear to be created by the drawing of
1416 the wave, so we have only two possibilities in the menus, 3/4
1417 point is equal to solid 3 point. This calculation seems to
1418 match well to results.
1420 nMSTotalWidth +=45;
1421 break;
1422 case 21:
1424 double wave, the dimensions appear to be created by the
1425 drawing of the wave, so we have only one possibilities in the
1426 menus, that of 3/4 point is equal to solid 3 point. This
1427 calculation seems to match well to results.
1429 nMSTotalWidth += 45*2;
1430 break;
1433 if (pSpace)
1434 *pSpace = static_cast<short>(dptSpace()) * 20; // convert from points to twips
1435 return nMSTotalWidth;
1439 * WW8Cp2Fc is a good method, a CP always maps to a FC
1440 * WW8Fc2Cp on the other hand is more dubious, a random FC
1441 * may not map to a valid CP. Try and avoid WW8Fc2Cp where
1442 * possible
1444 WW8_CP WW8ScannerBase::WW8Fc2Cp( WW8_FC nFcPos ) const
1446 WW8_CP nFallBackCpEnd = WW8_CP_MAX;
1447 if( nFcPos == WW8_FC_MAX )
1448 return nFallBackCpEnd;
1450 bool bIsUnicode;
1451 if (m_pWw8Fib->m_nVersion >= 8)
1452 bIsUnicode = false;
1453 else
1454 bIsUnicode = m_pWw8Fib->m_fExtChar;
1456 if( m_pPieceIter ) // Complex File ?
1458 sal_uInt32 nOldPos = m_pPieceIter->GetIdx();
1460 for (m_pPieceIter->SetIdx(0);
1461 m_pPieceIter->GetIdx() < m_pPieceIter->GetIMax(); m_pPieceIter->advance())
1463 WW8_CP nCpStart, nCpEnd;
1464 void* pData;
1465 if( !m_pPieceIter->Get( nCpStart, nCpEnd, pData ) )
1466 { // outside PLCFfpcd ?
1467 OSL_ENSURE( false, "PLCFpcd-WW8Fc2Cp() went wrong" );
1468 break;
1470 sal_Int32 nFcStart = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
1471 if (m_pWw8Fib->m_nVersion >= 8)
1473 nFcStart = WW8PLCFx_PCD::TransformPieceAddress( nFcStart,
1474 bIsUnicode );
1476 else
1478 bIsUnicode = m_pWw8Fib->m_fExtChar;
1481 sal_Int32 nLen;
1482 if (o3tl::checked_sub(nCpEnd, nCpStart, nLen))
1484 SAL_WARN("sw.ww8", "broken offset, ignoring");
1485 return WW8_CP_MAX;
1487 if (bIsUnicode)
1489 if (o3tl::checked_multiply<WW8_CP>(nLen, 2, nLen))
1491 SAL_WARN("sw.ww8", "broken offset, ignoring");
1492 return WW8_CP_MAX;
1497 If this cp is inside this piece, or it's the last piece and we are
1498 on the very last cp of that piece
1500 if (nFcPos >= nFcStart)
1502 // found
1503 WW8_FC nFcDiff;
1504 if (o3tl::checked_sub(nFcPos, nFcStart, nFcDiff))
1506 SAL_WARN("sw.ww8", "broken offset, ignoring");
1507 return WW8_CP_MAX;
1509 if (bIsUnicode)
1510 nFcDiff /= 2;
1511 WW8_CP nTempCp;
1512 if (o3tl::checked_add(nCpStart, nFcDiff, nTempCp))
1514 SAL_WARN("sw.ww8", "broken offset, ignoring");
1515 return WW8_CP_MAX;
1517 WW8_FC nFcEnd;
1518 if (o3tl::checked_add(nFcStart, nLen, nFcEnd))
1520 SAL_WARN("sw.ww8", "broken offset, ignoring");
1521 return WW8_CP_MAX;
1523 if (nFcPos < nFcEnd)
1525 m_pPieceIter->SetIdx( nOldPos );
1526 return nTempCp;
1528 else if (nFcPos == nFcEnd)
1530 //Keep this cp as its on a piece boundary because we might
1531 //need it if tests fail
1532 nFallBackCpEnd = nTempCp;
1536 // not found
1537 m_pPieceIter->SetIdx( nOldPos ); // not found
1539 If it was not found, then this is because it has fallen between two
1540 stools, i.e. either it is the last cp/fc of the last piece, or it is
1541 the last cp/fc of a disjoint piece.
1543 return nFallBackCpEnd;
1546 WW8_FC nFcDiff;
1547 if (o3tl::checked_sub(nFcPos, m_pWw8Fib->m_fcMin, nFcDiff))
1549 SAL_WARN("sw.ww8", "broken offset, ignoring");
1550 return WW8_CP_MAX;
1553 // No complex file
1554 if (!bIsUnicode)
1555 nFallBackCpEnd = nFcDiff;
1556 else
1557 nFallBackCpEnd = (nFcDiff + 1) / 2;
1559 return nFallBackCpEnd;
1562 // the fib of WinWord2 has a last entry of cpnBtePap of 2 byte sized type PN at
1563 // offset 324
1564 const int nSmallestPossibleFib = 326;
1566 WW8_FC WW8ScannerBase::WW8Cp2Fc(WW8_CP nCpPos, bool* pIsUnicode,
1567 WW8_CP* pNextPieceCp, bool* pTestFlag) const
1569 if( pTestFlag )
1570 *pTestFlag = true;
1571 if( WW8_CP_MAX == nCpPos )
1572 return WW8_CP_MAX;
1574 bool bIsUnicode;
1575 if( !pIsUnicode )
1576 pIsUnicode = &bIsUnicode;
1578 if (m_pWw8Fib->m_nVersion >= 8)
1579 *pIsUnicode = false;
1580 else
1581 *pIsUnicode = m_pWw8Fib->m_fExtChar;
1583 WW8_FC nRet;
1585 if( m_pPieceIter )
1587 // Complex File
1588 if( pNextPieceCp )
1589 *pNextPieceCp = WW8_CP_MAX;
1591 if( !m_pPieceIter->SeekPos( nCpPos ) )
1593 if( pTestFlag )
1594 *pTestFlag = false;
1595 else {
1596 OSL_ENSURE( false, "Handed over wrong CP to WW8Cp2Fc()" );
1598 return WW8_FC_MAX;
1600 WW8_CP nCpStart, nCpEnd;
1601 void* pData;
1602 if( !m_pPieceIter->Get( nCpStart, nCpEnd, pData ) )
1604 if( pTestFlag )
1605 *pTestFlag = false;
1606 else {
1607 OSL_ENSURE( false, "PLCFfpcd-Get went wrong" );
1609 return WW8_FC_MAX;
1611 if( pNextPieceCp )
1612 *pNextPieceCp = nCpEnd;
1614 nRet = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
1615 if (m_pWw8Fib->m_nVersion >= 8)
1616 nRet = WW8PLCFx_PCD::TransformPieceAddress( nRet, *pIsUnicode );
1617 else
1618 *pIsUnicode = m_pWw8Fib->m_fExtChar;
1620 WW8_CP nCpLen;
1621 bool bFail = o3tl::checked_sub(nCpPos, nCpStart, nCpLen);
1622 if (bFail)
1624 SAL_WARN("sw.ww8", "broken offset, ignoring");
1625 return WW8_CP_MAX;
1628 if (*pIsUnicode)
1630 bFail = o3tl::checked_multiply<WW8_CP>(nCpLen, 2, nCpLen);
1631 if (bFail)
1633 SAL_WARN("sw.ww8", "broken offset, ignoring");
1634 return WW8_CP_MAX;
1638 bFail = o3tl::checked_add(nRet, nCpLen, nRet);
1639 if (bFail)
1641 SAL_WARN("sw.ww8", "broken offset, ignoring");
1642 return WW8_CP_MAX;
1645 return nRet;
1648 if (*pIsUnicode)
1650 const bool bFail = o3tl::checked_multiply<WW8_CP>(nCpPos, 2, nCpPos);
1651 if (bFail)
1653 SAL_WARN("sw.ww8", "broken offset, ignoring");
1654 return WW8_CP_MAX;
1658 // No complex file
1659 const bool bFail = o3tl::checked_add(m_pWw8Fib->m_fcMin, nCpPos, nRet);
1660 if (bFail)
1662 SAL_WARN("sw.ww8", "broken offset, ignoring");
1663 return WW8_CP_MAX;
1666 // the text and the fib share the same stream, if the text is inside the fib
1667 // then it's definitely a bad offset. The smallest FIB supported is that of
1668 // WW2 which is 326 bytes in size
1669 if (nRet < nSmallestPossibleFib)
1671 SAL_WARN("sw.ww8", "broken offset, ignoring");
1672 return WW8_CP_MAX;
1675 return nRet;
1678 std::unique_ptr<WW8PLCFpcd> WW8ScannerBase::OpenPieceTable( SvStream* pStr, const WW8Fib* pWwF )
1680 if ( ((8 > m_pWw8Fib->m_nVersion) && !pWwF->m_fComplex) || !pWwF->m_lcbClx )
1681 return nullptr;
1683 if (pWwF->m_lcbClx < 0)
1684 return nullptr;
1686 WW8_FC nClxPos = pWwF->m_fcClx;
1688 if (!checkSeek(*pStr, nClxPos))
1689 return nullptr;
1691 sal_Int32 nClxLen = pWwF->m_lcbClx;
1692 sal_Int32 nLeft = nClxLen;
1694 while (true)
1696 sal_uInt8 clxt(2);
1697 pStr->ReadUChar( clxt );
1698 nLeft--;
1699 if( 2 == clxt) // PLCFfpcd ?
1700 break; // PLCFfpcd found
1701 sal_uInt16 nLen(0);
1702 pStr->ReadUInt16( nLen );
1703 nLeft -= 2 + nLen;
1704 if( nLeft < 0 )
1705 return nullptr; // gone wrong
1706 if( 1 == clxt ) // clxtGrpprl ?
1708 if (m_aPieceGrpprls.size() == SHRT_MAX)
1709 return nullptr;
1710 if (nLen > pStr->remainingSize())
1711 return nullptr;
1712 std::unique_ptr<sal_uInt8[]> p(new sal_uInt8[nLen+2]); // allocate
1713 ShortToSVBT16(nLen, p.get()); // add length
1714 if (!checkRead(*pStr, p.get()+2, nLen)) // read grpprl
1716 return nullptr;
1718 m_aPieceGrpprls.push_back(std::move(p)); // add to array
1720 else
1722 nLen = std::min<sal_uInt64>(nLen, pStr->remainingSize());
1723 pStr->Seek(pStr->Tell() + nLen); // non-Grpprl left
1727 // read Piece Table PLCF
1728 sal_Int32 nPLCFfLen(0);
1729 if (pWwF->GetFIBVersion() <= ww::eWW2)
1731 sal_Int16 nWordTwoLen(0);
1732 pStr->ReadInt16( nWordTwoLen );
1733 nPLCFfLen = nWordTwoLen;
1735 else
1736 pStr->ReadInt32( nPLCFfLen );
1737 OSL_ENSURE( 65536 > nPLCFfLen, "PLCFfpcd above 64 k" );
1738 return std::make_unique<WW8PLCFpcd>( pStr, pStr->Tell(), nPLCFfLen, 8 );
1741 WW8ScannerBase::WW8ScannerBase( SvStream* pSt, SvStream* pTableSt,
1742 SvStream* pDataSt, WW8Fib* pWwFib )
1743 : m_pWw8Fib(pWwFib)
1745 m_pPiecePLCF = OpenPieceTable( pTableSt, m_pWw8Fib ); // Complex
1746 if( m_pPiecePLCF )
1748 m_pPieceIter.reset(new WW8PLCFpcd_Iter( *m_pPiecePLCF ));
1749 m_pPLCFx_PCD.reset( new WW8PLCFx_PCD(*pWwFib, m_pPiecePLCF.get(), 0,
1750 IsSevenMinus(m_pWw8Fib->GetFIBVersion())));
1751 m_pPLCFx_PCDAttrs.reset(new WW8PLCFx_PCDAttrs(*pWwFib,
1752 m_pPLCFx_PCD.get(), this));
1754 else
1756 m_pPieceIter = nullptr;
1757 m_pPLCFx_PCD = nullptr;
1758 m_pPLCFx_PCDAttrs = nullptr;
1761 // pChpPLCF and pPapPLCF may NOT be created before pPLCFx_PCD !!
1762 m_pChpPLCF.reset(new WW8PLCFx_Cp_FKP( pSt, pTableSt, pDataSt, *this, CHP )); // CHPX
1763 m_pPapPLCF.reset(new WW8PLCFx_Cp_FKP( pSt, pTableSt, pDataSt, *this, PAP )); // PAPX
1765 m_pSepPLCF.reset(new WW8PLCFx_SEPX( pSt, pTableSt, *pWwFib, 0 )); // SEPX
1767 // Footnotes
1768 m_pFootnotePLCF.reset(new WW8PLCFx_SubDoc( pTableSt, *pWwFib, 0,
1769 pWwFib->m_fcPlcffndRef, pWwFib->m_lcbPlcffndRef, pWwFib->m_fcPlcffndText,
1770 pWwFib->m_lcbPlcffndText, 2 ));
1771 // Endnotes
1772 m_pEdnPLCF.reset(new WW8PLCFx_SubDoc( pTableSt, *pWwFib, 0,
1773 pWwFib->m_fcPlcfendRef, pWwFib->m_lcbPlcfendRef, pWwFib->m_fcPlcfendText,
1774 pWwFib->m_lcbPlcfendText, 2 ));
1775 // Comments
1776 m_pAndPLCF.reset(new WW8PLCFx_SubDoc( pTableSt, *pWwFib, 0,
1777 pWwFib->m_fcPlcfandRef, pWwFib->m_lcbPlcfandRef, pWwFib->m_fcPlcfandText,
1778 pWwFib->m_lcbPlcfandText, IsSevenMinus(pWwFib->GetFIBVersion()) ? 20 : 30));
1780 // Fields Main Text
1781 m_pFieldPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_MAINTEXT));
1782 // Fields Header / Footer
1783 m_pFieldHdFtPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_HDFT));
1784 // Fields Footnote
1785 m_pFieldFootnotePLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_FTN));
1786 // Fields Endnote
1787 m_pFieldEdnPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_EDN));
1788 // Fields Comments
1789 m_pFieldAndPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_AND));
1790 // Fields in Textboxes in Main Text
1791 m_pFieldTxbxPLCF.reset(new WW8PLCFx_FLD(pTableSt, *pWwFib, MAN_TXBX));
1792 // Fields in Textboxes in Header / Footer
1793 m_pFieldTxbxHdFtPLCF.reset(new WW8PLCFx_FLD(pTableSt,*pWwFib,MAN_TXBX_HDFT));
1795 // Note: 6 stands for "6 OR 7", 7 stands for "ONLY 7"
1796 switch( m_pWw8Fib->m_nVersion )
1798 case 6:
1799 case 7:
1800 if( pWwFib->m_fcPlcfdoaMom && pWwFib->m_lcbPlcfdoaMom )
1802 m_pMainFdoa.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfdoaMom,
1803 pWwFib->m_lcbPlcfdoaMom, 6 ));
1805 if( pWwFib->m_fcPlcfdoaHdr && pWwFib->m_lcbPlcfdoaHdr )
1807 m_pHdFtFdoa.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfdoaHdr,
1808 pWwFib->m_lcbPlcfdoaHdr, 6 ));
1810 break;
1811 case 8:
1812 if( pWwFib->m_fcPlcfspaMom && pWwFib->m_lcbPlcfspaMom )
1814 m_pMainFdoa.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfspaMom,
1815 pWwFib->m_lcbPlcfspaMom, 26 ));
1817 if( pWwFib->m_fcPlcfspaHdr && pWwFib->m_lcbPlcfspaHdr )
1819 m_pHdFtFdoa.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfspaHdr,
1820 pWwFib->m_lcbPlcfspaHdr, 26 ));
1822 // PLCF for TextBox break-descriptors in the main text
1823 if( pWwFib->m_fcPlcftxbxBkd && pWwFib->m_lcbPlcftxbxBkd )
1825 m_pMainTxbxBkd.reset(new WW8PLCFspecial( pTableSt,
1826 pWwFib->m_fcPlcftxbxBkd, pWwFib->m_lcbPlcftxbxBkd, 0));
1828 // PLCF for TextBox break-descriptors in Header/Footer range
1829 if( pWwFib->m_fcPlcfHdrtxbxBkd && pWwFib->m_lcbPlcfHdrtxbxBkd )
1831 m_pHdFtTxbxBkd.reset(new WW8PLCFspecial( pTableSt,
1832 pWwFib->m_fcPlcfHdrtxbxBkd, pWwFib->m_lcbPlcfHdrtxbxBkd, 0));
1834 // Sub table cp positions
1835 if (pWwFib->m_fcPlcfTch && pWwFib->m_lcbPlcfTch)
1837 m_pMagicTables.reset(new WW8PLCFspecial( pTableSt,
1838 pWwFib->m_fcPlcfTch, pWwFib->m_lcbPlcfTch, 4));
1840 // Sub document cp positions
1841 if (pWwFib->m_fcPlcfwkb && pWwFib->m_lcbPlcfwkb)
1843 m_pSubdocs.reset(new WW8PLCFspecial( pTableSt,
1844 pWwFib->m_fcPlcfwkb, pWwFib->m_lcbPlcfwkb, 12));
1846 // Extended ATRD
1847 if (pWwFib->m_fcAtrdExtra && pWwFib->m_lcbAtrdExtra)
1849 sal_uInt64 const nOldPos = pTableSt->Tell();
1850 if (checkSeek(*pTableSt, pWwFib->m_fcAtrdExtra) && (pTableSt->remainingSize() >= pWwFib->m_lcbAtrdExtra))
1852 m_pExtendedAtrds.reset( new sal_uInt8[pWwFib->m_lcbAtrdExtra] );
1853 pWwFib->m_lcbAtrdExtra = pTableSt->ReadBytes(m_pExtendedAtrds.get(), pWwFib->m_lcbAtrdExtra);
1855 else
1856 pWwFib->m_lcbAtrdExtra = 0;
1857 pTableSt->Seek(nOldPos);
1860 break;
1861 default:
1862 OSL_ENSURE( false, "nVersion not implemented!" );
1863 break;
1866 // PLCF for TextBox stories in main text
1867 sal_uInt32 nLenTxBxS = (8 > m_pWw8Fib->m_nVersion) ? 0 : 22;
1868 if( pWwFib->m_fcPlcftxbxText && pWwFib->m_lcbPlcftxbxText )
1870 m_pMainTxbx.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcftxbxText,
1871 pWwFib->m_lcbPlcftxbxText, nLenTxBxS ));
1874 // PLCF for TextBox stories in Header/Footer range
1875 if( pWwFib->m_fcPlcfHdrtxbxText && pWwFib->m_lcbPlcfHdrtxbxText )
1877 m_pHdFtTxbx.reset(new WW8PLCFspecial( pTableSt, pWwFib->m_fcPlcfHdrtxbxText,
1878 pWwFib->m_lcbPlcfHdrtxbxText, nLenTxBxS ));
1881 m_pBook.reset(new WW8PLCFx_Book(pTableSt, *pWwFib));
1882 m_pAtnBook.reset(new WW8PLCFx_AtnBook(pTableSt, *pWwFib));
1883 m_pFactoidBook.reset(new WW8PLCFx_FactoidBook(pTableSt, *pWwFib));
1886 WW8ScannerBase::~WW8ScannerBase()
1888 m_aPieceGrpprls.clear();
1889 m_pPLCFx_PCDAttrs.reset();
1890 m_pPLCFx_PCD.reset();
1891 m_pPieceIter.reset();
1892 m_pPiecePLCF.reset();
1893 m_pFactoidBook.reset();
1894 m_pAtnBook.reset();
1895 m_pBook.reset();
1896 m_pFieldEdnPLCF.reset();
1897 m_pFieldFootnotePLCF.reset();
1898 m_pFieldAndPLCF.reset();
1899 m_pFieldHdFtPLCF.reset();
1900 m_pFieldPLCF.reset();
1901 m_pFieldTxbxPLCF.reset();
1902 m_pFieldTxbxHdFtPLCF.reset();
1903 m_pEdnPLCF.reset();
1904 m_pFootnotePLCF.reset();
1905 m_pAndPLCF.reset();
1906 m_pSepPLCF.reset();
1907 m_pPapPLCF.reset();
1908 m_pChpPLCF.reset();
1909 m_pMainFdoa.reset();
1910 m_pHdFtFdoa.reset();
1911 m_pMainTxbx.reset();
1912 m_pMainTxbxBkd.reset();
1913 m_pHdFtTxbx.reset();
1914 m_pHdFtTxbxBkd.reset();
1915 m_pMagicTables.reset();
1916 m_pSubdocs.reset();
1919 // Fields
1921 static bool WW8SkipField(WW8PLCFspecial& rPLCF)
1923 void* pData;
1924 WW8_CP nP;
1926 if (!rPLCF.Get(nP, pData)) // End of PLCFspecial?
1927 return false;
1929 rPLCF.advance();
1931 if((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) != 0x13 ) // No beginning?
1932 return true; // Do not terminate on error
1934 if( !rPLCF.Get( nP, pData ) )
1935 return false;
1937 while((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x13 )
1939 // still new (nested) beginnings ?
1940 WW8SkipField( rPLCF ); // nested Field in description
1941 if( !rPLCF.Get( nP, pData ) )
1942 return false;
1945 if((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x14 )
1948 // Field Separator ?
1949 rPLCF.advance();
1951 if( !rPLCF.Get( nP, pData ) )
1952 return false;
1954 while ((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x13)
1956 // still new (nested) beginnings?
1957 WW8SkipField( rPLCF ); // nested Field in Results
1958 if( !rPLCF.Get( nP, pData ) )
1959 return false;
1962 rPLCF.advance();
1964 return true;
1967 static bool WW8GetFieldPara(WW8PLCFspecial& rPLCF, WW8FieldDesc& rF)
1969 void* pData;
1970 sal_uInt32 nOldIdx = rPLCF.GetIdx();
1972 rF.nLen = rF.nId = rF.nOpt = 0;
1973 rF.bCodeNest = rF.bResNest = false;
1975 if (!rPLCF.Get(rF.nSCode, pData) || rF.nSCode < 0) // end of PLCFspecial?
1976 goto Err;
1978 rPLCF.advance();
1980 if (!pData || (static_cast<sal_uInt8*>(pData)[0] & 0x1f) != 0x13) // No beginning?
1981 goto Err;
1983 rF.nId = static_cast<sal_uInt8*>(pData)[1];
1985 if( !rPLCF.Get( rF.nLCode, pData ) )
1986 goto Err;
1988 if (rF.nLCode < rF.nSCode)
1989 goto Err;
1991 rF.nSRes = rF.nLCode; // Default
1992 rF.nSCode++; // without markers
1993 rF.nLCode -= rF.nSCode; // Pos -> length
1995 while((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x13 )
1997 // still new (nested) beginnings ?
1998 WW8SkipField( rPLCF ); // nested Field in description
1999 rF.bCodeNest = true;
2000 if (!rPLCF.Get(rF.nSRes, pData) || rF.nSRes < 0)
2001 goto Err;
2004 if ((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x14 ) // Field Separator?
2006 rPLCF.advance();
2008 if (!rPLCF.Get(rF.nLRes, pData) || rF.nLRes < 0)
2009 goto Err;
2011 while((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x13 )
2013 // still new (nested) beginnings ?
2014 WW8SkipField( rPLCF ); // nested Field in results
2015 rF.bResNest = true;
2016 if (!rPLCF.Get(rF.nLRes, pData) || rF.nLRes < 0)
2017 goto Err;
2019 WW8_CP nTmp;
2020 if (o3tl::checked_sub<WW8_CP>(rF.nLRes, rF.nSCode, nTmp))
2022 rF.nLen = 0;
2023 goto Err;
2025 if (o3tl::checked_add<WW8_CP>(nTmp, 2, rF.nLen)) // nLRes is still the final position
2027 rF.nLen = 0;
2028 goto Err;
2030 rF.nLRes -= rF.nSRes; // now: nLRes = length
2031 if (o3tl::checked_add<WW8_CP>(rF.nSRes, 1, rF.nSRes)) // Endpos including Markers
2033 rF.nLen = 0;
2034 goto Err;
2036 rF.nLRes--;
2037 }else{
2038 rF.nLRes = 0; // no result found
2039 WW8_CP nTmp;
2040 if (o3tl::checked_sub<WW8_CP>(rF.nSRes, rF.nSCode, nTmp))
2042 rF.nLen = 0;
2043 goto Err;
2045 if (o3tl::checked_add<WW8_CP>(nTmp, 2, rF.nLen)) // total length
2047 rF.nLen = 0;
2048 goto Err;
2052 if (rF.nLen < 0)
2054 rF.nLen = 0;
2055 goto Err;
2058 rPLCF.advance();
2059 if((static_cast<sal_uInt8*>(pData)[0] & 0x1f ) == 0x15 )
2061 // Field end ?
2062 // INDEX-Field has set Bit7?
2063 rF.nOpt = static_cast<sal_uInt8*>(pData)[1]; // yes -> copy flags
2064 }else{
2065 rF.nId = 0; // no -> Field invalid
2068 rPLCF.SetIdx( nOldIdx );
2069 return true;
2070 Err:
2071 rPLCF.SetIdx( nOldIdx );
2072 return false;
2075 OUString read_uInt8_BeltAndBracesString(SvStream& rStrm, rtl_TextEncoding eEnc)
2077 const OUString aRet = read_uInt8_lenPrefixed_uInt8s_ToOUString(rStrm, eEnc);
2078 rStrm.SeekRel(sizeof(sal_uInt8)); // skip null-byte at end
2079 return aRet;
2082 OUString read_uInt16_BeltAndBracesString(SvStream& rStrm)
2084 const OUString aRet = read_uInt16_PascalString(rStrm);
2085 rStrm.SeekRel(sizeof(sal_Unicode)); // skip null-byte at end
2086 return aRet;
2089 sal_Int32 WW8ScannerBase::WW8ReadString( SvStream& rStrm, OUString& rStr,
2090 WW8_CP nCurrentStartCp, tools::Long nTotalLen, rtl_TextEncoding eEnc ) const
2092 // Read in plain text, which can extend over several pieces
2093 rStr.clear();
2095 if (nCurrentStartCp < 0 || nTotalLen < 0)
2096 return 0;
2098 WW8_CP nBehindTextCp = nCurrentStartCp + nTotalLen;
2099 WW8_CP nNextPieceCp = nBehindTextCp; // Initialization, important for Ver6
2100 tools::Long nTotalRead = 0;
2103 bool bIsUnicode(false), bPosOk(false);
2104 WW8_FC fcAct = WW8Cp2Fc(nCurrentStartCp,&bIsUnicode,&nNextPieceCp,&bPosOk);
2106 // Probably aimed beyond file end, doesn't matter!
2107 if( !bPosOk )
2108 break;
2110 bool bValid = checkSeek(rStrm, fcAct);
2111 if (!bValid)
2112 break;
2114 WW8_CP nEnd = (nNextPieceCp < nBehindTextCp) ? nNextPieceCp
2115 : nBehindTextCp;
2116 WW8_CP nLen;
2117 const bool bFail = o3tl::checked_sub(nEnd, nCurrentStartCp, nLen);
2118 if (bFail)
2119 break;
2121 if( 0 >= nLen )
2122 break;
2124 rStr += bIsUnicode
2125 ? read_uInt16s_ToOUString(rStrm, nLen)
2126 : read_uInt8s_ToOUString(rStrm, nLen, eEnc);
2128 nTotalRead += nLen;
2129 nCurrentStartCp += nLen;
2130 if ( nTotalRead != rStr.getLength() )
2131 break;
2133 while( nTotalRead < nTotalLen );
2135 return rStr.getLength();
2138 WW8PLCFspecial::WW8PLCFspecial(SvStream* pSt, sal_uInt32 nFilePos,
2139 sal_uInt32 nPLCF, sal_uInt32 nStruct)
2140 : m_nIdx(0), m_nStru(nStruct)
2142 const sal_uInt32 nValidMin=4;
2144 sal_uInt64 const nOldPos = pSt->Tell();
2146 bool bValid = checkSeek(*pSt, nFilePos);
2147 std::size_t nRemainingSize = pSt->remainingSize();
2148 if( nRemainingSize < nValidMin || nPLCF < nValidMin )
2149 bValid = false;
2150 nPLCF = bValid ? std::min(nRemainingSize, static_cast<std::size_t>(nPLCF)) : nValidMin;
2152 // Pointer to Pos- and Struct-array
2153 m_pPLCF_PosArray.reset( new sal_Int32[ ( nPLCF + 3 ) / 4 ] );
2154 m_pPLCF_PosArray[0] = 0;
2156 nPLCF = bValid ? pSt->ReadBytes(m_pPLCF_PosArray.get(), nPLCF) : nValidMin;
2158 nPLCF = std::max(nPLCF, nValidMin);
2160 m_nIMax = ( nPLCF - 4 ) / ( 4 + nStruct );
2161 #ifdef OSL_BIGENDIAN
2162 for( m_nIdx = 0; m_nIdx <= m_nIMax; m_nIdx++ )
2163 m_pPLCF_PosArray[m_nIdx] = OSL_SWAPDWORD( m_pPLCF_PosArray[m_nIdx] );
2164 m_nIdx = 0;
2165 #endif // OSL_BIGENDIAN
2166 if( nStruct ) // Pointer to content array
2167 m_pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&m_pPLCF_PosArray[m_nIMax + 1]);
2168 else
2169 m_pPLCF_Contents = nullptr; // no content
2171 pSt->Seek(nOldPos);
2174 // WW8PLCFspecial::SeekPos() sets WW8PLCFspecial to position nPos, while also the entry is used
2175 // that begins before nPos and ends after nPos.
2176 // Suitable for normal attributes. However, the beginning of the attribute is not corrected onto
2177 // the position nPos.
2178 bool WW8PLCFspecial::SeekPos(tools::Long nP)
2180 if( nP < m_pPLCF_PosArray[0] )
2182 m_nIdx = 0;
2183 return false; // Not found: nP less than smallest entry
2186 // Search from beginning?
2187 if ((m_nIdx < 1) || (nP < m_pPLCF_PosArray[m_nIdx - 1]))
2188 m_nIdx = 1;
2190 tools::Long nI = m_nIdx;
2191 tools::Long nEnd = m_nIMax;
2193 for(int n = (1==m_nIdx ? 1 : 2); n; --n )
2195 for( ; nI <=nEnd; ++nI)
2196 { // search with an index that is incremented by 1
2197 if( nP < m_pPLCF_PosArray[nI] )
2198 { // found position
2199 m_nIdx = nI - 1; // nI - 1 is the correct index
2200 return true; // done
2203 nI = 1;
2204 nEnd = m_nIdx-1;
2206 m_nIdx = m_nIMax; // not found, greater than all entries
2207 return false;
2210 // WW8PLCFspecial::SeekPosExact() like SeekPos(), but it is ensured that no attribute is cut,
2211 // i.e. the next given attribute begins at or after nPos.
2212 // Is used for fields and bookmarks.
2213 bool WW8PLCFspecial::SeekPosExact(tools::Long nP)
2215 if( nP < m_pPLCF_PosArray[0] )
2217 m_nIdx = 0;
2218 return false; // Not found: nP less than smallest entry
2220 // Search from beginning?
2221 if( nP <=m_pPLCF_PosArray[m_nIdx] )
2222 m_nIdx = 0;
2224 tools::Long nI = m_nIdx ? m_nIdx-1 : 0;
2225 tools::Long nEnd = m_nIMax;
2227 for(int n = (0==m_nIdx ? 1 : 2); n; --n )
2229 for( ; nI < nEnd; ++nI)
2231 if( nP <=m_pPLCF_PosArray[nI] )
2232 { // found position
2233 m_nIdx = nI; // nI is the correct index
2234 return true; // done
2237 nI = 0;
2238 nEnd = m_nIdx;
2240 m_nIdx = m_nIMax; // Not found, greater than all entries
2241 return false;
2244 bool WW8PLCFspecial::Get(WW8_CP& rPos, void*& rpValue) const
2246 return GetData( m_nIdx, rPos, rpValue );
2249 bool WW8PLCFspecial::GetData(tools::Long nInIdx, WW8_CP& rPos, void*& rpValue) const
2251 if ( nInIdx >= m_nIMax )
2253 rPos = WW8_CP_MAX;
2254 return false;
2256 rPos = m_pPLCF_PosArray[nInIdx];
2257 rpValue = m_pPLCF_Contents ? static_cast<void*>(&m_pPLCF_Contents[nInIdx * m_nStru]) : nullptr;
2258 return true;
2261 // WW8PLCF e.g. for SEPX
2262 // Ctor for *others* than Fkps
2263 // With nStartPos < 0, the first element of PLCFs will be taken
2264 WW8PLCF::WW8PLCF(SvStream& rSt, WW8_FC nFilePos, sal_Int32 nPLCF, int nStruct,
2265 WW8_CP nStartPos) : m_nIdx(0), m_nStru(nStruct)
2267 if (nPLCF < 0)
2269 SAL_WARN("sw.ww8", "broken WW8PLCF, ignoring");
2270 nPLCF = 0;
2272 else
2273 m_nIMax = (nPLCF - 4) / (4 + nStruct);
2275 ReadPLCF(rSt, nFilePos, nPLCF);
2277 if( nStartPos >= 0 )
2278 SeekPos( nStartPos );
2281 // Ctor *only* for Fkps
2282 // The last 2 parameters are needed for PLCF.Chpx and PLCF.Papx.
2283 // If ncpN != 0, then an incomplete PLCF will be completed. This is always required for WW6 with
2284 // lack of resources and for WordPad (W95).
2285 // With nStartPos < 0, the first element of the PLCFs is taken.
2286 WW8PLCF::WW8PLCF(SvStream& rSt, WW8_FC nFilePos, sal_Int32 nPLCF, int nStruct,
2287 WW8_CP nStartPos, sal_Int32 nPN, sal_Int32 ncpN): m_nIdx(0),
2288 m_nStru(nStruct)
2290 if (nPLCF < 0)
2292 SAL_WARN("sw.ww8", "broken WW8PLCF, ignoring");
2293 m_nIMax = SAL_MAX_INT32;
2295 else
2296 m_nIMax = (nPLCF - 4) / (4 + nStruct);
2298 if( m_nIMax >= ncpN )
2299 ReadPLCF(rSt, nFilePos, nPLCF);
2300 else
2301 GeneratePLCF(rSt, nPN, ncpN);
2303 if( nStartPos >= 0 )
2304 SeekPos( nStartPos );
2307 void WW8PLCF::ReadPLCF(SvStream& rSt, WW8_FC nFilePos, sal_uInt32 nPLCF)
2309 sal_uInt64 const nOldPos = rSt.Tell();
2310 bool bValid = nPLCF != 0 && checkSeek(rSt, nFilePos)
2311 && (rSt.remainingSize() >= nPLCF);
2313 if (bValid)
2315 // Pointer to Pos-array
2316 const size_t nEntries = (nPLCF + 3) / 4;
2317 m_pPLCF_PosArray.reset(new WW8_CP[nEntries]);
2318 bValid = checkRead(rSt, m_pPLCF_PosArray.get(), nPLCF);
2319 size_t nBytesAllocated = nEntries * sizeof(WW8_CP);
2320 if (bValid && nPLCF != nBytesAllocated)
2322 sal_uInt8* pStartBlock = reinterpret_cast<sal_uInt8*>(m_pPLCF_PosArray.get());
2323 memset(pStartBlock + nPLCF, 0, nBytesAllocated - nPLCF);
2327 if (bValid)
2329 #ifdef OSL_BIGENDIAN
2330 for( m_nIdx = 0; m_nIdx <= m_nIMax; m_nIdx++ )
2331 m_pPLCF_PosArray[m_nIdx] = OSL_SWAPDWORD( m_pPLCF_PosArray[m_nIdx] );
2332 m_nIdx = 0;
2333 #endif // OSL_BIGENDIAN
2334 // Pointer to content array
2335 m_pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&m_pPLCF_PosArray[m_nIMax + 1]);
2337 TruncToSortedRange();
2340 OSL_ENSURE(bValid, "Document has corrupt PLCF, ignoring it");
2342 if (!bValid)
2343 MakeFailedPLCF();
2345 rSt.Seek(nOldPos);
2348 void WW8PLCF::MakeFailedPLCF()
2350 m_nIMax = 0;
2351 m_pPLCF_PosArray.reset( new WW8_CP[2] );
2352 m_pPLCF_PosArray[0] = m_pPLCF_PosArray[1] = WW8_CP_MAX;
2353 m_pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&m_pPLCF_PosArray[m_nIMax + 1]);
2356 namespace
2358 sal_Int32 TruncToSortedRange(const sal_Int32* pPLCF_PosArray, sal_Int32 nIMax)
2360 //Docs state that: ... all Plcs ... are sorted in ascending order.
2361 //So ensure that here for broken documents.
2362 for (auto nI = 0; nI < nIMax; ++nI)
2364 if (pPLCF_PosArray[nI] > pPLCF_PosArray[nI+1])
2366 SAL_WARN("sw.ww8", "Document has unsorted PLCF, truncated to sorted portion");
2367 nIMax = nI;
2368 break;
2371 return nIMax;
2375 void WW8PLCFpcd::TruncToSortedRange()
2377 m_nIMax = ::TruncToSortedRange(m_pPLCF_PosArray.get(), m_nIMax);
2380 void WW8PLCF::TruncToSortedRange()
2382 m_nIMax = ::TruncToSortedRange(m_pPLCF_PosArray.get(), m_nIMax);
2385 void WW8PLCF::GeneratePLCF(SvStream& rSt, sal_Int32 nPN, sal_Int32 ncpN)
2387 OSL_ENSURE( m_nIMax < ncpN, "Pcl.Fkp: Why is PLCF too big?" );
2389 bool failure = false;
2390 m_nIMax = ncpN;
2392 if ((m_nIMax < 1) || (m_nIMax > (WW8_CP_MAX - 4) / (4 + m_nStru)) || nPN < 0)
2393 failure = true;
2395 if (!failure)
2397 // Check arguments to ShortToSVBT16 in loop below will all be valid:
2398 sal_Int32 nResult;
2399 failure = o3tl::checked_add(nPN, ncpN, nResult) || nResult > SAL_MAX_UINT16;
2402 if (!failure)
2404 size_t nSiz = (4 + m_nStru) * m_nIMax + 4;
2405 size_t nElems = ( nSiz + 3 ) / 4;
2406 m_pPLCF_PosArray.reset( new WW8_CP[ nElems ] ); // Pointer to Pos-array
2408 for (sal_Int32 i = 0; i < ncpN && !failure; ++i)
2410 failure = true;
2411 // construct FC entries
2412 // first FC entry of each Fkp
2413 if (!checkSeek(rSt, (nPN + i) << 9))
2414 break;
2416 WW8_CP nFc(0);
2417 rSt.ReadInt32( nFc );
2418 m_pPLCF_PosArray[i] = nFc;
2420 failure = bool(rSt.GetError());
2424 if (!failure)
2428 failure = true;
2430 std::size_t nLastFkpPos = nPN + m_nIMax - 1;
2431 nLastFkpPos = nLastFkpPos << 9;
2432 // number of FC entries of last Fkp
2433 if (!checkSeek(rSt, nLastFkpPos + 511))
2434 break;
2436 sal_uInt8 nb(0);
2437 rSt.ReadUChar( nb );
2438 // last FC entry of last Fkp
2439 if (!checkSeek(rSt, nLastFkpPos + nb * 4))
2440 break;
2442 WW8_CP nFc(0);
2443 rSt.ReadInt32( nFc );
2444 m_pPLCF_PosArray[m_nIMax] = nFc; // end of the last Fkp
2446 failure = bool(rSt.GetError());
2447 } while(false);
2450 if (!failure)
2452 // Pointer to content array
2453 m_pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&m_pPLCF_PosArray[m_nIMax + 1]);
2454 sal_uInt8* p = m_pPLCF_Contents;
2456 for (sal_Int32 i = 0; i < ncpN; ++i) // construct PNs
2458 ShortToSVBT16(o3tl::narrowing<sal_uInt16>(nPN + i), p);
2459 p += m_nStru;
2463 SAL_WARN_IF(failure, "sw.ww8", "Document has corrupt PLCF, ignoring it");
2465 if (failure)
2466 MakeFailedPLCF();
2469 bool WW8PLCF::SeekPos(WW8_CP nPos)
2471 WW8_CP nP = nPos;
2473 if( nP < m_pPLCF_PosArray[0] )
2475 m_nIdx = 0;
2476 // not found: nPos less than smallest entry
2477 return false;
2480 // Search from beginning?
2481 if ((m_nIdx < 1) || (nP < m_pPLCF_PosArray[m_nIdx - 1]))
2482 m_nIdx = 1;
2484 sal_Int32 nI = m_nIdx;
2485 sal_Int32 nEnd = m_nIMax;
2487 for(int n = (1==m_nIdx ? 1 : 2); n; --n )
2489 for( ; nI <=nEnd; ++nI) // search with an index that is incremented by 1
2491 if( nP < m_pPLCF_PosArray[nI] ) // found position
2493 m_nIdx = nI - 1; // nI - 1 is the correct index
2494 return true; // done
2497 nI = 1;
2498 nEnd = m_nIdx-1;
2501 m_nIdx = m_nIMax; // not found, greater than all entries
2502 return false;
2505 bool WW8PLCF::Get(WW8_CP& rStart, WW8_CP& rEnd, void*& rpValue) const
2507 if ( m_nIdx >= m_nIMax )
2509 rStart = rEnd = WW8_CP_MAX;
2510 return false;
2512 rStart = m_pPLCF_PosArray[ m_nIdx ];
2513 rEnd = m_pPLCF_PosArray[ m_nIdx + 1 ];
2514 rpValue = static_cast<void*>(&m_pPLCF_Contents[m_nIdx * m_nStru]);
2515 return true;
2518 WW8_CP WW8PLCF::Where() const
2520 if ( m_nIdx >= m_nIMax )
2521 return WW8_CP_MAX;
2523 return m_pPLCF_PosArray[m_nIdx];
2526 WW8PLCFpcd::WW8PLCFpcd(SvStream* pSt, sal_uInt32 nFilePos,
2527 sal_uInt32 nPLCF, sal_uInt32 nStruct)
2528 : m_nStru( nStruct )
2530 const sal_uInt32 nValidMin=4;
2532 sal_uInt64 const nOldPos = pSt->Tell();
2534 bool bValid = checkSeek(*pSt, nFilePos);
2535 std::size_t nRemainingSize = pSt->remainingSize();
2536 if( nRemainingSize < nValidMin || nPLCF < nValidMin )
2537 bValid = false;
2538 nPLCF = bValid ? std::min(nRemainingSize, static_cast<std::size_t>(nPLCF)) : nValidMin;
2540 m_pPLCF_PosArray.reset( new WW8_CP[ ( nPLCF + 3 ) / 4 ] ); // Pointer to Pos-array
2541 m_pPLCF_PosArray[0] = 0;
2543 nPLCF = bValid ? pSt->ReadBytes(m_pPLCF_PosArray.get(), nPLCF) : nValidMin;
2544 nPLCF = std::max(nPLCF, nValidMin);
2546 m_nIMax = ( nPLCF - 4 ) / ( 4 + nStruct );
2547 #ifdef OSL_BIGENDIAN
2548 for( tools::Long nI = 0; nI <= m_nIMax; nI++ )
2549 m_pPLCF_PosArray[nI] = OSL_SWAPDWORD( m_pPLCF_PosArray[nI] );
2550 #endif // OSL_BIGENDIAN
2552 // Pointer to content array
2553 m_pPLCF_Contents = reinterpret_cast<sal_uInt8*>(&m_pPLCF_PosArray[m_nIMax + 1]);
2554 TruncToSortedRange();
2556 pSt->Seek( nOldPos );
2559 // If nStartPos < 0, the first element of PLCFs will be taken
2560 WW8PLCFpcd_Iter::WW8PLCFpcd_Iter( WW8PLCFpcd& rPLCFpcd, tools::Long nStartPos )
2561 :m_rPLCF( rPLCFpcd ), m_nIdx( 0 )
2563 if( nStartPos >= 0 )
2564 SeekPos( nStartPos );
2567 bool WW8PLCFpcd_Iter::SeekPos(tools::Long nPos)
2569 tools::Long nP = nPos;
2571 if( nP < m_rPLCF.m_pPLCF_PosArray[0] )
2573 m_nIdx = 0;
2574 return false; // not found: nPos less than smallest entry
2576 // Search from beginning?
2577 if ((m_nIdx < 1) || (nP < m_rPLCF.m_pPLCF_PosArray[m_nIdx - 1]))
2578 m_nIdx = 1;
2580 tools::Long nI = m_nIdx;
2581 tools::Long nEnd = m_rPLCF.m_nIMax;
2583 for(int n = (1==m_nIdx ? 1 : 2); n; --n )
2585 for( ; nI <=nEnd; ++nI)
2586 { // search with an index that is incremented by 1
2587 if( nP < m_rPLCF.m_pPLCF_PosArray[nI] )
2588 { // found position
2589 m_nIdx = nI - 1; // nI - 1 is the correct index
2590 return true; // done
2593 nI = 1;
2594 nEnd = m_nIdx-1;
2596 m_nIdx = m_rPLCF.m_nIMax; // not found, greater than all entries
2597 return false;
2600 bool WW8PLCFpcd_Iter::Get(WW8_CP& rStart, WW8_CP& rEnd, void*& rpValue) const
2602 if( m_nIdx >= m_rPLCF.m_nIMax )
2604 rStart = rEnd = WW8_CP_MAX;
2605 return false;
2607 rStart = m_rPLCF.m_pPLCF_PosArray[m_nIdx];
2608 rEnd = m_rPLCF.m_pPLCF_PosArray[m_nIdx + 1];
2609 rpValue = static_cast<void*>(&m_rPLCF.m_pPLCF_Contents[m_nIdx * m_rPLCF.m_nStru]);
2610 return true;
2613 sal_Int32 WW8PLCFpcd_Iter::Where() const
2615 if ( m_nIdx >= m_rPLCF.m_nIMax )
2616 return SAL_MAX_INT32;
2618 return m_rPLCF.m_pPLCF_PosArray[m_nIdx];
2621 bool WW8PLCFx_Fc_FKP::WW8Fkp::Entry::operator<
2622 (const WW8PLCFx_Fc_FKP::WW8Fkp::Entry& rSecond) const
2624 return (mnFC < rSecond.mnFC);
2627 static bool IsReplaceAllSprm(sal_uInt16 nSpId)
2629 return (NS_sprm::LN_PHugePapx == nSpId || 0x6646 == nSpId);
2632 static bool IsExpandableSprm(sal_uInt16 nSpId)
2634 return 0x646B == nSpId;
2637 void WW8PLCFx_Fc_FKP::WW8Fkp::FillEntry(WW8PLCFx_Fc_FKP::WW8Fkp::Entry &rEntry,
2638 std::size_t nDataOffset, sal_uInt16 nLen)
2640 bool bValidPos = (nDataOffset < sizeof(maRawData));
2642 OSL_ENSURE(bValidPos, "sprm sequence offset is out of range, ignoring");
2644 if (!bValidPos)
2646 rEntry.mnLen = 0;
2647 return;
2650 const sal_uInt16 nAvailableData = sizeof(maRawData)-nDataOffset;
2651 OSL_ENSURE(nLen <= nAvailableData, "sprm sequence len is out of range, clipping");
2652 rEntry.mnLen = std::min(nLen, nAvailableData);
2653 rEntry.mpData = maRawData + nDataOffset;
2656 WW8PLCFx_Fc_FKP::WW8Fkp::WW8Fkp(const WW8Fib& rFib, SvStream* pSt,
2657 SvStream* pDataSt, tools::Long _nFilePos, tools::Long nItemSiz, ePLCFT ePl,
2658 WW8_FC nStartFc)
2659 : m_nItemSize(nItemSiz), m_nFilePos(_nFilePos), mnIdx(0), m_ePLCF(ePl)
2660 , mnMustRemainCached(0), maSprmParser(rFib)
2662 memset(maRawData, 0, 512);
2664 const ww::WordVersion eVersion = rFib.GetFIBVersion();
2666 sal_uInt64 const nOldPos = pSt->Tell();
2668 bool bCouldSeek = checkSeek(*pSt, m_nFilePos);
2669 bool bCouldRead = bCouldSeek && checkRead(*pSt, maRawData, 512);
2671 mnIMax = bCouldRead ? maRawData[511] : 0;
2673 sal_uInt8 *pStart = maRawData;
2674 // Offset-Location in maRawData
2675 const size_t nRawDataStart = (mnIMax + 1) * 4;
2677 for (mnIdx = 0; mnIdx < mnIMax; ++mnIdx)
2679 const size_t nRawDataOffset = nRawDataStart + mnIdx * m_nItemSize;
2681 //clip to available data, corrupt fkp
2682 if (nRawDataOffset >= 511)
2684 mnIMax = mnIdx;
2685 break;
2688 unsigned int nOfs = maRawData[nRawDataOffset] * 2;
2689 // nOfs in [0..0xff*2=510]
2691 Entry aEntry(Get_Long(pStart));
2693 if (nOfs)
2695 switch (m_ePLCF)
2697 case CHP:
2699 aEntry.mnLen = maRawData[nOfs];
2701 //len byte
2702 std::size_t nDataOffset = nOfs + 1;
2704 FillEntry(aEntry, nDataOffset, aEntry.mnLen);
2706 if (aEntry.mnLen && eVersion <= ww::eWW2)
2708 Word2CHPX aChpx = ReadWord2Chpx(*pSt, m_nFilePos + nOfs + 1, static_cast< sal_uInt8 >(aEntry.mnLen));
2709 std::vector<sal_uInt8> aSprms = ChpxToSprms(aChpx);
2710 aEntry.mnLen = static_cast< sal_uInt16 >(aSprms.size());
2711 if (aEntry.mnLen)
2713 aEntry.mpData = new sal_uInt8[aEntry.mnLen];
2714 memcpy(aEntry.mpData, aSprms.data(), aEntry.mnLen);
2715 aEntry.mbMustDelete = true;
2718 break;
2720 case PAP:
2722 sal_uInt8 nDelta = 0;
2724 aEntry.mnLen = maRawData[nOfs];
2725 if (IsEightPlus(eVersion) && !aEntry.mnLen)
2727 aEntry.mnLen = maRawData[nOfs+1];
2728 nDelta++;
2730 aEntry.mnLen *= 2;
2732 //stylecode, std/istd
2733 if (eVersion <= ww::eWW2)
2735 if (aEntry.mnLen >= 1)
2737 aEntry.mnIStd = *(maRawData+nOfs+1+nDelta);
2738 aEntry.mnLen--; //style code
2739 if (aEntry.mnLen >= 6)
2741 aEntry.mnLen-=6; //PHE
2742 //skip stc, len byte + 6 byte PHE
2743 unsigned int nOffset = nOfs + 8;
2744 if (nOffset >= 511) //Bad offset
2745 aEntry.mnLen=0;
2746 if (aEntry.mnLen) //start is ok
2748 if (nOffset + aEntry.mnLen > 512) //Bad end, clip
2749 aEntry.mnLen = 512 - nOffset;
2750 aEntry.mpData = maRawData + nOffset;
2753 else
2754 aEntry.mnLen=0; //Too short
2757 else
2759 if (aEntry.mnLen >= 2)
2761 //len byte + optional extra len byte
2762 std::size_t nDataOffset = nOfs + 1 + nDelta;
2763 aEntry.mnIStd = nDataOffset <= sizeof(maRawData)-sizeof(aEntry.mnIStd) ?
2764 SVBT16ToUInt16(maRawData+nDataOffset) : 0;
2765 aEntry.mnLen-=2; //istd
2766 if (aEntry.mnLen)
2768 //additional istd
2769 nDataOffset += sizeof(aEntry.mnIStd);
2771 FillEntry(aEntry, nDataOffset, aEntry.mnLen);
2774 else
2775 aEntry.mnLen=0; //Too short, ignore
2778 const sal_uInt16 nSpId = aEntry.mnLen
2779 ? maSprmParser.GetSprmId(aEntry.mpData) : 0;
2782 If we replace then we throw away the old data, if we
2783 are expanding, then we tack the old data onto the end
2784 of the new data
2786 const bool bExpand = IsExpandableSprm(nSpId);
2787 const sal_uInt8* pStartData
2788 = aEntry.mpData == nullptr ? nullptr : aEntry.mpData + 2;
2789 const sal_uInt8* pLastValidDataPos = maRawData + 512 - sizeof(sal_uInt32);
2790 if (pStartData != nullptr && pStartData > pLastValidDataPos)
2791 pStartData = nullptr;
2792 if ((IsReplaceAllSprm(nSpId) || bExpand) && pStartData)
2794 sal_uInt32 nCurr = pDataSt->Tell();
2795 sal_uInt32 nPos = SVBT32ToUInt32(pStartData);
2796 sal_uInt16 nLen(0);
2798 bool bOk = checkSeek(*pDataSt, nPos);
2799 if (bOk)
2801 pDataSt->ReadUInt16( nLen );
2802 bOk = nLen <= pDataSt->remainingSize();
2805 if (bOk)
2807 const sal_uInt16 nOrigLen = bExpand ? aEntry.mnLen : 0;
2808 sal_uInt8 *pOrigData = bExpand ? aEntry.mpData : nullptr;
2810 aEntry.mnLen = nLen;
2811 aEntry.mpData =
2812 new sal_uInt8[aEntry.mnLen + nOrigLen];
2813 aEntry.mbMustDelete = true;
2814 aEntry.mnLen =
2815 pDataSt->ReadBytes(aEntry.mpData, aEntry.mnLen);
2817 pDataSt->Seek( nCurr );
2819 if (pOrigData)
2821 memcpy(aEntry.mpData + aEntry.mnLen,
2822 pOrigData, nOrigLen);
2823 aEntry.mnLen = aEntry.mnLen + nOrigLen;
2828 break;
2829 default:
2830 OSL_FAIL("sweet god, what have you done!");
2831 break;
2835 maEntries.push_back(aEntry);
2837 #ifdef DEBUGSPRMREADER
2839 sal_Int32 nLen;
2840 sal_uInt8* pSprms = GetLenAndIStdAndSprms( nLen );
2841 WW8SprmIter aIter(pSprms, nLen, maSprmParser);
2842 while (aIter.GetSprms())
2844 fprintf(stderr, "id is %x\n", aIter.GetCurrentId());
2845 aIter.advance();
2848 #endif
2851 //one more FC than grrpl entries
2852 maEntries.emplace_back(Get_Long(pStart));
2854 //we expect them sorted, but it appears possible for them to arrive unsorted
2855 std::stable_sort(maEntries.begin(), maEntries.end());
2857 mnIdx = 0;
2859 if (nStartFc >= 0)
2860 SeekPos(nStartFc);
2862 pSt->Seek(nOldPos);
2865 WW8PLCFx_Fc_FKP::WW8Fkp::Entry::Entry(const Entry &rEntry)
2866 : mnFC(rEntry.mnFC), mnLen(rEntry.mnLen), mnIStd(rEntry.mnIStd),
2867 mbMustDelete(rEntry.mbMustDelete)
2869 if (mbMustDelete)
2871 mpData = new sal_uInt8[mnLen];
2872 memcpy(mpData, rEntry.mpData, mnLen);
2874 else
2875 mpData = rEntry.mpData;
2878 WW8PLCFx_Fc_FKP::WW8Fkp::Entry&
2879 WW8PLCFx_Fc_FKP::WW8Fkp::Entry::operator=(const Entry &rEntry)
2881 if (this == &rEntry)
2882 return *this;
2884 if (mbMustDelete)
2885 delete[] mpData;
2887 mnFC = rEntry.mnFC;
2888 mnLen = rEntry.mnLen;
2889 mnIStd = rEntry.mnIStd;
2890 mbMustDelete = rEntry.mbMustDelete;
2892 if (rEntry.mbMustDelete)
2894 mpData = new sal_uInt8[mnLen];
2895 memcpy(mpData, rEntry.mpData, mnLen);
2897 else
2898 mpData = rEntry.mpData;
2900 return *this;
2903 WW8PLCFx_Fc_FKP::WW8Fkp::Entry::~Entry()
2905 if (mbMustDelete)
2906 delete[] mpData;
2909 void WW8PLCFx_Fc_FKP::WW8Fkp::Reset(WW8_FC nFc)
2911 SetIdx(0);
2912 if (nFc >= 0)
2913 SeekPos(nFc);
2916 bool WW8PLCFx_Fc_FKP::WW8Fkp::SeekPos(WW8_FC nFc)
2918 if (nFc < maEntries[0].mnFC)
2920 mnIdx = 0;
2921 return false; // not found: nPos less than smallest entry
2924 // Search from beginning?
2925 if ((mnIdx < 1) || (nFc < maEntries[mnIdx - 1].mnFC))
2926 mnIdx = 1;
2928 sal_uInt8 nI = mnIdx;
2929 sal_uInt8 nEnd = mnIMax;
2931 for(sal_uInt8 n = (1==mnIdx ? 1 : 2); n; --n )
2933 for( ; nI <=nEnd; ++nI)
2934 { // search with an index that is incremented by 1
2935 if (nFc < maEntries[nI].mnFC)
2936 { // found position
2937 mnIdx = nI - 1; // nI - 1 is the correct index
2938 return true; // done
2941 nI = 1;
2942 nEnd = mnIdx-1;
2944 mnIdx = mnIMax; // not found, greater than all entries
2945 return false;
2948 sal_uInt8* WW8PLCFx_Fc_FKP::WW8Fkp::Get(WW8_FC& rStart, WW8_FC& rEnd, sal_Int32& rLen)
2949 const
2951 rLen = 0;
2953 if (mnIdx >= mnIMax)
2955 rStart = WW8_FC_MAX;
2956 return nullptr;
2959 rStart = maEntries[mnIdx].mnFC;
2960 rEnd = maEntries[mnIdx + 1].mnFC;
2962 sal_uInt8* pSprms = GetLenAndIStdAndSprms( rLen );
2963 return pSprms;
2966 void WW8PLCFx_Fc_FKP::WW8Fkp::SetIdx(sal_uInt8 nI)
2968 if (nI < mnIMax)
2970 mnIdx = nI;
2974 sal_uInt8* WW8PLCFx_Fc_FKP::WW8Fkp::GetLenAndIStdAndSprms(sal_Int32& rLen) const
2976 rLen = maEntries[mnIdx].mnLen;
2977 return maEntries[mnIdx].mpData;
2980 SprmResult WW8PLCFx_Fc_FKP::WW8Fkp::HasSprm( sal_uInt16 nId, bool bFindFirst )
2982 if (mnIdx >= mnIMax)
2983 return SprmResult();
2985 sal_Int32 nLen;
2986 sal_uInt8* pSprms = GetLenAndIStdAndSprms( nLen );
2988 WW8SprmIter aIter(pSprms, nLen, maSprmParser);
2989 return aIter.FindSprm(nId, bFindFirst);
2992 void WW8PLCFx_Fc_FKP::WW8Fkp::HasSprm(sal_uInt16 nId,
2993 std::vector<SprmResult> &rResult)
2995 if (mnIdx >= mnIMax)
2996 return;
2998 sal_Int32 nLen;
2999 sal_uInt8* pSprms = GetLenAndIStdAndSprms( nLen );
3001 WW8SprmIter aIter(pSprms, nLen, maSprmParser);
3003 while(aIter.GetSprms())
3005 if (aIter.GetCurrentId() == nId)
3007 sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId);
3008 sal_Int32 nL = maSprmParser.GetSprmSize(nId, aIter.GetSprms(), aIter.GetRemLen());
3009 rResult.emplace_back(aIter.GetCurrentParams(), nL - nFixedLen);
3011 aIter.advance();
3015 ww::WordVersion WW8PLCFx::GetFIBVersion() const
3017 return mrFib.GetFIBVersion();
3020 void WW8PLCFx::GetSprms( WW8PLCFxDesc* p )
3022 OSL_ENSURE( false, "Called wrong GetSprms" );
3023 p->nStartPos = p->nEndPos = WW8_CP_MAX;
3024 p->pMemPos = nullptr;
3025 p->nSprmsLen = 0;
3026 p->bRealLineEnd = false;
3029 tools::Long WW8PLCFx::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
3031 OSL_ENSURE( false, "Called wrong GetNoSprms" );
3032 rStart = rEnd = WW8_CP_MAX;
3033 rLen = 0;
3034 return 0;
3037 // ...Idx2: Default: ignore
3038 sal_uInt32 WW8PLCFx::GetIdx2() const
3040 return 0;
3043 void WW8PLCFx::SetIdx2(sal_uInt32)
3047 namespace {
3049 class SamePos
3051 private:
3052 tools::Long mnPo;
3053 public:
3054 explicit SamePos(tools::Long nPo) : mnPo(nPo) {}
3055 bool operator()(const std::unique_ptr<WW8PLCFx_Fc_FKP::WW8Fkp>& pFkp)
3056 {return mnPo == pFkp->GetFilePos();}
3061 bool WW8PLCFx_Fc_FKP::NewFkp()
3063 WW8_CP nPLCFStart, nPLCFEnd;
3064 void* pPage;
3066 static const int WW8FkpSizeTabVer2[ PLCF_END ] =
3068 1, 1, 0 /*, 0, 0, 0*/
3070 static const int WW8FkpSizeTabVer6[ PLCF_END ] =
3072 1, 7, 0 /*, 0, 0, 0*/
3074 static const int WW8FkpSizeTabVer8[ PLCF_END ] =
3076 1, 13, 0 /*, 0, 0, 0*/
3078 const int* pFkpSizeTab;
3080 switch (GetFIBVersion())
3082 case ww::eWW1:
3083 case ww::eWW2:
3084 pFkpSizeTab = WW8FkpSizeTabVer2;
3085 break;
3086 case ww::eWW6:
3087 case ww::eWW7:
3088 pFkpSizeTab = WW8FkpSizeTabVer6;
3089 break;
3090 case ww::eWW8:
3091 pFkpSizeTab = WW8FkpSizeTabVer8;
3092 break;
3093 default:
3094 // program error!
3095 OSL_ENSURE( false, "nVersion not implemented!" );
3096 return false;
3099 if (!m_pPLCF->Get( nPLCFStart, nPLCFEnd, pPage ))
3101 m_pFkp = nullptr;
3102 return false; // PLCF completely processed
3104 m_pPLCF->advance();
3105 tools::Long nPo = SVBT16ToUInt16( static_cast<sal_uInt8 *>(pPage) );
3106 nPo <<= 9; // shift as LONG
3108 tools::Long nCurrentFkpFilePos = m_pFkp ? m_pFkp->GetFilePos() : -1;
3109 if (nCurrentFkpFilePos == nPo)
3110 m_pFkp->Reset(GetStartFc());
3111 else
3113 auto aIter =
3114 std::find_if(maFkpCache.begin(), maFkpCache.end(), SamePos(nPo));
3115 if (aIter != maFkpCache.end())
3117 m_pFkp = aIter->get();
3118 m_pFkp->Reset(GetStartFc());
3120 else
3122 m_pFkp = new WW8Fkp(GetFIB(), m_pFKPStrm, m_pDataStrm, nPo,
3123 pFkpSizeTab[ m_ePLCF ], m_ePLCF, GetStartFc());
3124 maFkpCache.push_back(std::unique_ptr<WW8Fkp>(m_pFkp));
3126 if (maFkpCache.size() > eMaxCache)
3128 WW8Fkp* pCachedFkp = maFkpCache.front().get();
3129 if (!pCachedFkp->IsMustRemainCache())
3131 maFkpCache.pop_front();
3137 SetStartFc( -1 ); // only the first time
3138 return true;
3141 WW8PLCFx_Fc_FKP::WW8PLCFx_Fc_FKP(SvStream* pSt, SvStream* pTableSt,
3142 SvStream* pDataSt, const WW8Fib& rFib, ePLCFT ePl, WW8_FC nStartFcL)
3143 : WW8PLCFx(rFib, true), m_pFKPStrm(pSt), m_pDataStrm(pDataSt)
3144 , m_pFkp(nullptr), m_ePLCF(ePl)
3146 SetStartFc(nStartFcL);
3147 tools::Long nLenStruct = (8 > rFib.m_nVersion) ? 2 : 4;
3148 if (ePl == CHP)
3150 m_pPLCF.reset(new WW8PLCF(*pTableSt, rFib.m_fcPlcfbteChpx, rFib.m_lcbPlcfbteChpx,
3151 nLenStruct, GetStartFc(), rFib.m_pnChpFirst, rFib.m_cpnBteChp));
3153 else
3155 m_pPLCF.reset(new WW8PLCF(*pTableSt, rFib.m_fcPlcfbtePapx, rFib.m_lcbPlcfbtePapx,
3156 nLenStruct, GetStartFc(), rFib.m_pnPapFirst, rFib.m_cpnBtePap));
3160 WW8PLCFx_Fc_FKP::~WW8PLCFx_Fc_FKP()
3162 maFkpCache.clear();
3163 m_pPLCF.reset();
3164 m_pPCDAttrs.reset();
3167 sal_uInt32 WW8PLCFx_Fc_FKP::GetIdx() const
3169 sal_uInt32 u = m_pPLCF->GetIdx() << 8;
3170 if (m_pFkp)
3171 u |= m_pFkp->GetIdx();
3172 return u;
3175 void WW8PLCFx_Fc_FKP::SetIdx(sal_uInt32 nIdx)
3177 if( !( nIdx & 0xffffff00L ) )
3179 m_pPLCF->SetIdx( nIdx >> 8 );
3180 m_pFkp = nullptr;
3182 else
3183 { // there was a Fkp
3184 // Set PLCF one position back to retrieve the address of the Fkp
3185 m_pPLCF->SetIdx( ( nIdx >> 8 ) - 1 );
3186 if (NewFkp()) // read Fkp again
3188 sal_uInt8 nFkpIdx = static_cast<sal_uInt8>(nIdx & 0xff);
3189 m_pFkp->SetIdx(nFkpIdx); // set Fkp-Pos again
3194 bool WW8PLCFx_Fc_FKP::SeekPos(WW8_FC nFcPos)
3196 // StartPos for next Where()
3197 SetStartFc( nFcPos );
3199 // find StartPos for next pPLCF->Get()
3200 bool bRet = m_pPLCF->SeekPos(nFcPos);
3202 // make FKP invalid?
3203 WW8_CP nPLCFStart, nPLCFEnd;
3204 void* pPage;
3205 if( m_pFkp && m_pPLCF->Get( nPLCFStart, nPLCFEnd, pPage ) )
3207 tools::Long nPo = SVBT16ToUInt16( static_cast<sal_uInt8 *>(pPage) );
3208 nPo <<= 9; // shift as LONG
3209 if (nPo != m_pFkp->GetFilePos())
3210 m_pFkp = nullptr;
3211 else
3212 m_pFkp->SeekPos( nFcPos );
3214 return bRet;
3217 WW8_FC WW8PLCFx_Fc_FKP::Where()
3219 if( !m_pFkp && !NewFkp() )
3220 return WW8_FC_MAX;
3221 WW8_FC nP = m_pFkp ? m_pFkp->Where() : WW8_FC_MAX;
3222 if( nP != WW8_FC_MAX )
3223 return nP;
3225 m_pFkp = nullptr; // FKP finished -> get new
3226 return Where(); // easiest way: do it recursively
3229 sal_uInt8* WW8PLCFx_Fc_FKP::GetSprmsAndPos(WW8_FC& rStart, WW8_FC& rEnd, sal_Int32& rLen)
3231 rLen = 0; // Default
3232 rStart = rEnd = WW8_FC_MAX;
3234 if( !m_pFkp ) // Fkp not there ?
3236 if( !NewFkp() )
3237 return nullptr;
3240 sal_uInt8* pPos = m_pFkp ? m_pFkp->Get( rStart, rEnd, rLen ) : nullptr;
3241 if( rStart == WW8_FC_MAX ) //Not found
3242 return nullptr;
3243 return pPos;
3246 void WW8PLCFx_Fc_FKP::advance()
3248 if( !m_pFkp && !NewFkp() )
3249 return;
3251 if (!m_pFkp)
3252 return;
3254 m_pFkp->advance();
3255 if( m_pFkp->Where() == WW8_FC_MAX )
3256 (void)NewFkp();
3259 sal_uInt16 WW8PLCFx_Fc_FKP::GetIstd() const
3261 return m_pFkp ? m_pFkp->GetIstd() : 0xFFFF;
3264 void WW8PLCFx_Fc_FKP::GetPCDSprms( WW8PLCFxDesc& rDesc )
3266 rDesc.pMemPos = nullptr;
3267 rDesc.nSprmsLen = 0;
3268 if( m_pPCDAttrs )
3270 if( !m_pFkp )
3272 OSL_FAIL("+Problem: GetPCDSprms: NewFkp necessary (not possible!)" );
3273 if( !NewFkp() )
3274 return;
3276 m_pPCDAttrs->GetSprms(&rDesc);
3280 SprmResult WW8PLCFx_Fc_FKP::HasSprm(sal_uInt16 nId, bool bFindFirst)
3282 // const would be nicer, but for that, NewFkp() would need to be replaced or eliminated
3283 if( !m_pFkp )
3285 OSL_FAIL( "+Motz: HasSprm: NewFkp needed ( no const possible )" );
3286 // happens in BugDoc 31722
3287 if( !NewFkp() )
3288 return SprmResult();
3291 if (!m_pFkp)
3292 return SprmResult();
3294 SprmResult aRes = m_pFkp->HasSprm(nId, bFindFirst);
3296 if (!aRes.pSprm)
3298 WW8PLCFxDesc aDesc;
3299 GetPCDSprms( aDesc );
3301 if (aDesc.pMemPos)
3303 WW8SprmIter aIter(aDesc.pMemPos, aDesc.nSprmsLen,
3304 m_pFkp->GetSprmParser());
3305 aRes = aIter.FindSprm(nId, bFindFirst);
3309 return aRes;
3312 void WW8PLCFx_Fc_FKP::HasSprm(sal_uInt16 nId, std::vector<SprmResult> &rResult)
3314 // const would be nicer, but for that, NewFkp() would need to be replaced or eliminated
3315 if (!m_pFkp)
3317 OSL_FAIL( "+Motz: HasSprm: NewFkp needed ( no const possible )" );
3318 // happens in BugDoc 31722
3319 if( !NewFkp() )
3320 return;
3323 if (!m_pFkp)
3324 return;
3326 m_pFkp->HasSprm(nId, rResult);
3328 WW8PLCFxDesc aDesc;
3329 GetPCDSprms( aDesc );
3331 if (!aDesc.pMemPos)
3332 return;
3334 const wwSprmParser &rSprmParser = m_pFkp->GetSprmParser();
3335 WW8SprmIter aIter(aDesc.pMemPos, aDesc.nSprmsLen, rSprmParser);
3336 while(aIter.GetSprms())
3338 if (aIter.GetCurrentId() == nId)
3340 sal_Int32 nFixedLen = rSprmParser.DistanceToData(nId);
3341 sal_Int32 nL = rSprmParser.GetSprmSize(nId, aIter.GetSprms(), aIter.GetRemLen());
3342 rResult.emplace_back(aIter.GetCurrentParams(), nL - nFixedLen);
3344 aIter.advance();
3348 WW8PLCFx_Cp_FKP::WW8PLCFx_Cp_FKP( SvStream* pSt, SvStream* pTableSt,
3349 SvStream* pDataSt, const WW8ScannerBase& rBase, ePLCFT ePl )
3350 : WW8PLCFx_Fc_FKP(pSt, pTableSt, pDataSt, *rBase.m_pWw8Fib, ePl,
3351 rBase.WW8Cp2Fc(0)), m_rSBase(rBase), m_nAttrStart(-1), m_nAttrEnd(-1),
3352 m_bLineEnd(false),
3353 m_bComplex( (7 < rBase.m_pWw8Fib->m_nVersion) || rBase.m_pWw8Fib->m_fComplex )
3355 ResetAttrStartEnd();
3357 if (m_rSBase.m_pPiecePLCF)
3358 m_pPcd.reset( new WW8PLCFx_PCD(GetFIB(), rBase.m_pPiecePLCF.get(), 0, IsSevenMinus(GetFIBVersion())) );
3361 Make a copy of the piece attributes for so that the calls to HasSprm on a
3362 Fc_FKP will be able to take into account the current piece attributes,
3363 despite the fact that such attributes can only be found through a cp based
3364 mechanism.
3366 if (m_pPcd)
3368 m_pPCDAttrs.reset( m_rSBase.m_pPLCFx_PCDAttrs ? new WW8PLCFx_PCDAttrs(
3369 *m_rSBase.m_pWw8Fib, m_pPcd.get(), &m_rSBase) : nullptr);
3372 m_pPieceIter = m_rSBase.m_pPieceIter.get();
3375 WW8PLCFx_Cp_FKP::~WW8PLCFx_Cp_FKP()
3379 void WW8PLCFx_Cp_FKP::ResetAttrStartEnd()
3381 m_nAttrStart = -1;
3382 m_nAttrEnd = -1;
3383 m_bLineEnd = false;
3386 sal_uInt32 WW8PLCFx_Cp_FKP::GetPCDIdx() const
3388 return m_pPcd ? m_pPcd->GetIdx() : 0;
3391 bool WW8PLCFx_Cp_FKP::SeekPos(WW8_CP nCpPos)
3393 if( m_pPcd ) // Complex
3395 if( !m_pPcd->SeekPos( nCpPos ) ) // set piece
3396 return false;
3397 if (m_pPCDAttrs && !m_pPCDAttrs->GetIter()->SeekPos(nCpPos))
3398 return false;
3399 return WW8PLCFx_Fc_FKP::SeekPos(m_pPcd->CurrentPieceStartCp2Fc(nCpPos));
3401 // NO piece table !!!
3402 return WW8PLCFx_Fc_FKP::SeekPos( m_rSBase.WW8Cp2Fc(nCpPos) );
3405 WW8_CP WW8PLCFx_Cp_FKP::Where()
3407 WW8_FC nFc = WW8PLCFx_Fc_FKP::Where();
3408 if( m_pPcd )
3409 return m_pPcd->CurrentPieceStartFc2Cp( nFc ); // identify piece
3410 return m_rSBase.WW8Fc2Cp( nFc ); // NO piece table !!!
3413 void WW8PLCFx_Cp_FKP::GetSprms(WW8PLCFxDesc* p)
3415 WW8_CP nOrigCp = p->nStartPos;
3417 if (!GetDirty()) //Normal case
3419 p->pMemPos = WW8PLCFx_Fc_FKP::GetSprmsAndPos(p->nStartPos, p->nEndPos,
3420 p->nSprmsLen);
3422 else
3425 For the odd case where we have a location in a fastsaved file which
3426 does not have an entry in the FKP, perhaps its para end is in the next
3427 piece, or perhaps the cp just doesn't exist at all in this document.
3428 AdvSprm doesn't know so it sets the PLCF as dirty and we figure out
3429 in this method what the situation is
3431 It doesn't exist then the piece iterator will not be able to find it.
3432 Otherwise our cool fastsave algorithm can be brought to bear on the
3433 problem.
3435 if( !m_pPieceIter )
3436 return;
3437 const sal_uInt32 nOldPos = m_pPieceIter->GetIdx();
3438 bool bOk = m_pPieceIter->SeekPos(nOrigCp);
3439 m_pPieceIter->SetIdx(nOldPos);
3440 if (!bOk)
3441 return;
3444 if( m_pPcd ) // piece table available
3446 // Init ( no ++ called, yet )
3447 if( (m_nAttrStart > m_nAttrEnd) || (m_nAttrStart == -1) )
3449 p->bRealLineEnd = (m_ePLCF == PAP);
3451 if ( ((m_ePLCF == PAP ) || (m_ePLCF == CHP)) && (nOrigCp != WW8_CP_MAX) )
3453 bool bIsUnicode=false;
3455 To find the end of a paragraph for a character in a
3456 complex format file.
3458 It is necessary to know the piece that contains the
3459 character and the FC assigned to the character.
3462 //We set the piece iterator to the piece that contains the
3463 //character, now we have the correct piece for this character
3464 sal_uInt32 nOldPos = m_pPieceIter->GetIdx();
3465 p->nStartPos = nOrigCp;
3466 m_pPieceIter->SeekPos( p->nStartPos);
3468 //This is the FC assigned to the character, but we already
3469 //have the result of the next stage, so we can skip this step
3470 //WW8_FC nStartFc = rSBase.WW8Cp2Fc(p->nStartPos, &bIsUnicode);
3473 Using the FC of the character, first search the FKP that
3474 describes the character to find the smallest FC in the rgfc
3475 that is larger than the character FC.
3477 //But the search has already been done, the next largest FC is
3478 //p->nEndPos.
3479 WW8_FC nOldEndPos = p->nEndPos;
3482 If the FC found in the FKP is less than or equal to the limit
3483 FC of the piece, the end of the paragraph that contains the
3484 character is at the FKP FC minus 1.
3486 WW8_CP nCpStart, nCpEnd;
3487 void* pData=nullptr;
3488 bool bOk = m_pPieceIter->Get(nCpStart, nCpEnd, pData);
3490 if (!bOk)
3492 m_pPieceIter->SetIdx(nOldPos);
3493 return;
3496 WW8_FC nLimitFC = SVBT32ToUInt32( static_cast<WW8_PCD*>(pData)->fc );
3497 WW8_FC nBeginLimitFC = nLimitFC;
3498 if (IsEightPlus(GetFIBVersion()))
3500 nBeginLimitFC =
3501 WW8PLCFx_PCD::TransformPieceAddress(nLimitFC,
3502 bIsUnicode);
3505 WW8_CP nCpLen;
3506 bool bFail = o3tl::checked_sub(nCpEnd, nCpStart, nCpLen);
3507 if (bFail)
3509 SAL_WARN("sw.ww8", "broken offset, ignoring");
3510 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3511 m_pPieceIter->SetIdx(nOldPos);
3512 return;
3515 if (bIsUnicode)
3517 bFail = o3tl::checked_multiply<WW8_CP>(nCpLen, 2, nCpLen);
3518 if (bFail)
3520 SAL_WARN("sw.ww8", "broken offset, ignoring");
3521 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3522 m_pPieceIter->SetIdx(nOldPos);
3523 return;
3527 bFail = o3tl::checked_add(nBeginLimitFC, nCpLen, nLimitFC);
3528 if (bFail)
3530 SAL_WARN("sw.ww8", "broken offset, ignoring");
3531 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3532 m_pPieceIter->SetIdx(nOldPos);
3533 return;
3536 if (nOldEndPos <= nLimitFC)
3538 bFail = o3tl::checked_sub(nLimitFC, nOldEndPos, nCpLen);
3539 if (bFail)
3541 SAL_WARN("sw.ww8", "broken offset, ignoring");
3542 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3543 m_pPieceIter->SetIdx(nOldPos);
3544 return;
3547 nCpLen /= (bIsUnicode ? 2 : 1);
3549 bFail = o3tl::checked_sub(nCpEnd, nCpLen, p->nEndPos);
3550 if (bFail)
3552 SAL_WARN("sw.ww8", "broken offset, ignoring");
3553 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3554 m_pPieceIter->SetIdx(nOldPos);
3555 return;
3558 else
3560 p->nEndPos = nCpEnd;
3561 if (m_ePLCF != CHP)
3564 If the FKP FC that was found was greater than the FC
3565 of the end of the piece, scan piece by piece toward
3566 the end of the document until a piece is found that
3567 contains a paragraph end mark.
3571 It's possible to check if a piece contains a paragraph
3572 mark by using the FC of the beginning of the piece to
3573 search in the FKPs for the smallest FC in the FKP rgfc
3574 that is greater than the FC of the beginning of the
3575 piece. If the FC found is less than or equal to the
3576 limit FC of the piece, then the character that ends
3577 the paragraph is the character immediately before the
3578 FKP fc
3581 m_pPieceIter->advance();
3583 for (;m_pPieceIter->GetIdx() < m_pPieceIter->GetIMax();
3584 m_pPieceIter->advance())
3586 if( !m_pPieceIter->Get( nCpStart, nCpEnd, pData ) )
3588 OSL_ENSURE( false, "piece iter broken!" );
3589 break;
3591 bIsUnicode = false;
3592 sal_Int32 nFcStart=SVBT32ToUInt32(static_cast<WW8_PCD*>(pData)->fc);
3594 if (IsEightPlus(GetFIBVersion()))
3596 nFcStart =
3597 WW8PLCFx_PCD::TransformPieceAddress(
3598 nFcStart,bIsUnicode );
3601 bFail = o3tl::checked_sub(nCpEnd, nCpStart, nCpLen);
3602 if (bFail)
3604 SAL_WARN("sw.ww8", "broken offset, ignoring");
3605 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3606 continue;
3609 if (bIsUnicode)
3611 bFail = o3tl::checked_multiply<WW8_CP>(nCpLen, 2, nCpLen);
3612 if (bFail)
3614 SAL_WARN("sw.ww8", "broken offset, ignoring");
3615 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3616 continue;
3620 bFail = o3tl::checked_add(nFcStart, nCpLen, nLimitFC);
3621 if (bFail)
3623 SAL_WARN("sw.ww8", "broken offset, ignoring");
3624 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3625 continue;
3628 //if it doesn't exist, skip it
3629 if (!SeekPos(nCpStart))
3630 continue;
3632 WW8_FC nOne,nSmallest;
3633 p->pMemPos = WW8PLCFx_Fc_FKP::GetSprmsAndPos(nOne,
3634 nSmallest, p->nSprmsLen);
3636 if (nSmallest <= nLimitFC)
3638 WW8_CP nCpDiff;
3639 bFail = o3tl::checked_sub(nLimitFC, nSmallest, nCpDiff);
3640 if (bFail)
3642 SAL_WARN("sw.ww8", "broken offset, ignoring");
3643 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3644 continue;
3646 if (bIsUnicode)
3647 nCpDiff /= 2;
3649 WW8_CP nEndPos;
3650 bFail = o3tl::checked_sub(nCpEnd, nCpDiff, nEndPos);
3651 if (bFail)
3653 SAL_WARN("sw.ww8", "broken offset, ignoring");
3654 p->nStartPos = p->nEndPos = WW8_FC_MAX;
3655 continue;
3658 OSL_ENSURE(nEndPos >= p->nStartPos, "EndPos before StartPos");
3660 if (nEndPos >= p->nStartPos)
3661 p->nEndPos = nEndPos;
3663 break;
3668 m_pPieceIter->SetIdx( nOldPos );
3670 else
3671 WW8PLCFx_PCD::CurrentPieceFc2Cp( p->nStartPos, p->nEndPos,&m_rSBase );
3673 else
3675 p->nStartPos = m_nAttrStart;
3676 p->nEndPos = m_nAttrEnd;
3677 p->bRealLineEnd = m_bLineEnd;
3680 else // NO piece table !!!
3682 p->nStartPos = m_rSBase.WW8Fc2Cp( p->nStartPos );
3683 p->nEndPos = m_rSBase.WW8Fc2Cp( p->nEndPos );
3684 p->bRealLineEnd = m_ePLCF == PAP;
3688 void WW8PLCFx_Cp_FKP::advance()
3690 WW8PLCFx_Fc_FKP::advance();
3691 // !pPcd: emergency break
3692 if ( !m_bComplex || !m_pPcd )
3693 return;
3695 if( GetPCDIdx() >= m_pPcd->GetIMax() ) // End of PLCF
3697 m_nAttrStart = m_nAttrEnd = WW8_CP_MAX;
3698 return;
3701 sal_Int32 nFkpLen; // Fkp entry
3702 // get Fkp entry
3703 WW8PLCFx_Fc_FKP::GetSprmsAndPos(m_nAttrStart, m_nAttrEnd, nFkpLen);
3705 WW8PLCFx_PCD::CurrentPieceFc2Cp( m_nAttrStart, m_nAttrEnd, &m_rSBase );
3706 m_bLineEnd = (m_ePLCF == PAP);
3709 WW8PLCFx_SEPX::WW8PLCFx_SEPX(SvStream* pSt, SvStream* pTableSt,
3710 const WW8Fib& rFib, WW8_CP nStartCp)
3711 : WW8PLCFx(rFib, true), maSprmParser(rFib),
3712 m_pStrm(pSt), m_nArrMax(256), m_nSprmSiz(0)
3714 if (rFib.m_lcbPlcfsed)
3715 m_pPLCF.reset( new WW8PLCF(*pTableSt, rFib.m_fcPlcfsed, rFib.m_lcbPlcfsed,
3716 GetFIBVersion() <= ww::eWW2 ? 6 : 12, nStartCp) );
3718 m_pSprms.reset( new sal_uInt8[m_nArrMax] ); // maximum length
3721 WW8PLCFx_SEPX::~WW8PLCFx_SEPX()
3725 sal_uInt32 WW8PLCFx_SEPX::GetIdx() const
3727 return m_pPLCF ? m_pPLCF->GetIdx() : 0;
3730 void WW8PLCFx_SEPX::SetIdx(sal_uInt32 nIdx)
3732 if( m_pPLCF ) m_pPLCF->SetIdx( nIdx );
3735 bool WW8PLCFx_SEPX::SeekPos(WW8_CP nCpPos)
3737 return m_pPLCF && m_pPLCF->SeekPos( nCpPos );
3740 WW8_CP WW8PLCFx_SEPX::Where()
3742 return m_pPLCF ? m_pPLCF->Where() : 0;
3745 void WW8PLCFx_SEPX::GetSprms(WW8PLCFxDesc* p)
3747 if( !m_pPLCF ) return;
3749 void* pData;
3751 p->bRealLineEnd = false;
3752 if (!m_pPLCF->Get( p->nStartPos, p->nEndPos, pData ))
3754 p->nStartPos = p->nEndPos = WW8_CP_MAX; // PLCF completely processed
3755 p->pMemPos = nullptr;
3756 p->nSprmsLen = 0;
3758 else
3760 sal_uInt32 nPo = SVBT32ToUInt32( static_cast<sal_uInt8*>(pData)+2 );
3761 if (nPo == 0xFFFFFFFF || !checkSeek(*m_pStrm, nPo))
3763 p->nStartPos = p->nEndPos = WW8_CP_MAX; // Sepx empty
3764 p->pMemPos = nullptr;
3765 p->nSprmsLen = 0;
3767 else
3769 // read len
3770 if (GetFIBVersion() <= ww::eWW2) // eWW6 ?, docs say yes, but...
3772 sal_uInt8 nSiz(0);
3773 m_pStrm->ReadUChar( nSiz );
3774 m_nSprmSiz = nSiz;
3776 else
3778 m_pStrm->ReadUInt16( m_nSprmSiz );
3781 std::size_t nRemaining = m_pStrm->remainingSize();
3782 if (m_nSprmSiz > nRemaining)
3783 m_nSprmSiz = nRemaining;
3785 if( m_nSprmSiz > m_nArrMax )
3786 { // does not fit
3787 m_nArrMax = m_nSprmSiz; // Get more memory
3788 m_pSprms.reset( new sal_uInt8[m_nArrMax] );
3790 m_nSprmSiz = m_pStrm->ReadBytes(m_pSprms.get(), m_nSprmSiz); // read Sprms
3792 p->nSprmsLen = m_nSprmSiz;
3793 p->pMemPos = m_pSprms.get(); // return Position
3798 void WW8PLCFx_SEPX::advance()
3800 if (m_pPLCF)
3801 m_pPLCF->advance();
3804 SprmResult WW8PLCFx_SEPX::HasSprm(sal_uInt16 nId) const
3806 return HasSprm(nId, m_pSprms.get(), m_nSprmSiz);
3809 SprmResult WW8PLCFx_SEPX::HasSprm( sal_uInt16 nId, const sal_uInt8* pOtherSprms,
3810 tools::Long nOtherSprmSiz ) const
3812 SprmResult aRet;
3813 if (m_pPLCF)
3815 WW8SprmIter aIter(pOtherSprms, nOtherSprmSiz, maSprmParser);
3816 aRet = aIter.FindSprm(nId, /*bFindFirst=*/true);
3818 return aRet;
3821 bool WW8PLCFx_SEPX::Find4Sprms(sal_uInt16 nId1,sal_uInt16 nId2,sal_uInt16 nId3,sal_uInt16 nId4,
3822 SprmResult& r1, SprmResult& r2, SprmResult& r3, SprmResult& r4) const
3824 if( !m_pPLCF )
3825 return false;
3827 bool bFound = false;
3829 sal_uInt8* pSp = m_pSprms.get();
3830 size_t i = 0;
3831 while (i + maSprmParser.MinSprmLen() <= m_nSprmSiz)
3833 // Sprm found?
3834 const sal_uInt16 nCurrentId = maSprmParser.GetSprmId(pSp);
3835 sal_Int32 nRemLen = m_nSprmSiz - i;
3836 const sal_Int32 x = maSprmParser.GetSprmSize(nCurrentId, pSp, nRemLen);
3837 bool bValid = x <= nRemLen;
3838 if (!bValid)
3840 SAL_WARN("sw.ww8", "sprm longer than remaining bytes, doc or parser is wrong");
3841 break;
3843 bool bOk = true;
3844 if( nCurrentId == nId1 )
3846 sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId1);
3847 r1 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3849 else if( nCurrentId == nId2 )
3851 sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId2);
3852 r2 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3854 else if( nCurrentId == nId3 )
3856 sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId3);
3857 r3 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3859 else if( nCurrentId == nId4 )
3861 sal_Int32 nFixedLen = maSprmParser.DistanceToData(nId4);
3862 r4 = SprmResult(pSp + nFixedLen, x - nFixedLen);
3864 else
3865 bOk = false;
3866 bFound |= bOk;
3867 // increment pointer so that it points to next SPRM
3868 i += x;
3869 pSp += x;
3871 return bFound;
3874 SprmResult WW8PLCFx_SEPX::HasSprm( sal_uInt16 nId, sal_uInt8 n2nd ) const
3876 SprmResult aRet;
3877 if (m_pPLCF)
3879 WW8SprmIter aIter(m_pSprms.get(), m_nSprmSiz, maSprmParser);
3880 aRet = aIter.FindSprm(nId, /*bFindFirst=*/true, &n2nd);
3882 return aRet;
3885 WW8PLCFx_SubDoc::WW8PLCFx_SubDoc(SvStream* pSt, const WW8Fib& rFib,
3886 WW8_CP nStartCp, tools::Long nFcRef, tools::Long nLenRef, tools::Long nFcText, tools::Long nLenText,
3887 tools::Long nStruct)
3888 : WW8PLCFx(rFib, true)
3890 if( nLenRef && nLenText )
3892 m_pRef.reset(new WW8PLCF(*pSt, nFcRef, nLenRef, nStruct, nStartCp));
3893 m_pText.reset(new WW8PLCF(*pSt, nFcText, nLenText, 0, nStartCp));
3897 WW8PLCFx_SubDoc::~WW8PLCFx_SubDoc()
3899 m_pRef.reset();
3900 m_pText.reset();
3903 sal_uInt32 WW8PLCFx_SubDoc::GetIdx() const
3905 // Probably pText ... no need for it
3906 if( m_pRef )
3907 return ( m_pRef->GetIdx() << 16 | m_pText->GetIdx() );
3908 return 0;
3911 void WW8PLCFx_SubDoc::SetIdx(sal_uInt32 nIdx)
3913 if( m_pRef )
3915 m_pRef->SetIdx( nIdx >> 16 );
3916 // Probably pText ... no need for it
3917 m_pText->SetIdx( nIdx & 0xFFFF );
3921 bool WW8PLCFx_SubDoc::SeekPos( WW8_CP nCpPos )
3923 return m_pRef && m_pRef->SeekPos( nCpPos );
3926 WW8_CP WW8PLCFx_SubDoc::Where()
3928 return m_pRef ? m_pRef->Where() : WW8_CP_MAX;
3931 void WW8PLCFx_SubDoc::GetSprms(WW8PLCFxDesc* p)
3933 p->nStartPos = p->nEndPos = WW8_CP_MAX;
3934 p->pMemPos = nullptr;
3935 p->nSprmsLen = 0;
3936 p->bRealLineEnd = false;
3938 if (!m_pRef)
3939 return;
3941 sal_uInt32 nNr = m_pRef->GetIdx();
3943 void *pData;
3944 WW8_CP nFoo;
3945 if (!m_pRef->Get(p->nStartPos, nFoo, pData))
3947 p->nEndPos = p->nStartPos = WW8_CP_MAX;
3948 return;
3951 if (o3tl::checked_add<WW8_CP>(p->nStartPos, 1, p->nEndPos))
3953 SAL_WARN("sw.ww8", "broken offset, ignoring");
3954 p->nEndPos = p->nStartPos = WW8_CP_MAX;
3955 return;
3958 if (!m_pText)
3959 return;
3961 m_pText->SetIdx(nNr);
3963 if (!m_pText->Get(p->nCp2OrIdx, p->nSprmsLen, pData))
3965 p->nEndPos = p->nStartPos = WW8_CP_MAX;
3966 p->nSprmsLen = 0;
3967 return;
3970 if (p->nCp2OrIdx < 0 || p->nCp2OrIdx > p->nSprmsLen)
3972 SAL_WARN("sw.ww8", "Document has invalid Cp or Idx, ignoring it");
3973 p->nEndPos = p->nStartPos = WW8_CP_MAX;
3974 p->nSprmsLen = 0;
3975 return;
3978 p->nSprmsLen -= p->nCp2OrIdx;
3981 void WW8PLCFx_SubDoc::advance()
3983 if (m_pRef && m_pText)
3985 m_pRef->advance();
3986 m_pText->advance();
3990 // fields
3991 WW8PLCFx_FLD::WW8PLCFx_FLD( SvStream* pSt, const WW8Fib& rMyFib, short nType)
3992 : WW8PLCFx(rMyFib, true), m_rFib(rMyFib)
3994 WW8_FC nFc;
3995 sal_Int32 nLen;
3997 switch( nType )
3999 case MAN_HDFT:
4000 nFc = m_rFib.m_fcPlcffldHdr;
4001 nLen = m_rFib.m_lcbPlcffldHdr;
4002 break;
4003 case MAN_FTN:
4004 nFc = m_rFib.m_fcPlcffldFootnote;
4005 nLen = m_rFib.m_lcbPlcffldFootnote;
4006 break;
4007 case MAN_EDN:
4008 nFc = m_rFib.m_fcPlcffldEdn;
4009 nLen = m_rFib.m_lcbPlcffldEdn;
4010 break;
4011 case MAN_AND:
4012 nFc = m_rFib.m_fcPlcffldAtn;
4013 nLen = m_rFib.m_lcbPlcffldAtn;
4014 break;
4015 case MAN_TXBX:
4016 nFc = m_rFib.m_fcPlcffldTxbx;
4017 nLen = m_rFib.m_lcbPlcffldTxbx;
4018 break;
4019 case MAN_TXBX_HDFT:
4020 nFc = m_rFib.m_fcPlcffldHdrTxbx;
4021 nLen = m_rFib.m_lcbPlcffldHdrTxbx;
4022 break;
4023 default:
4024 nFc = m_rFib.m_fcPlcffldMom;
4025 nLen = m_rFib.m_lcbPlcffldMom;
4026 break;
4029 if( nLen )
4030 m_pPLCF.reset( new WW8PLCFspecial( pSt, nFc, nLen, 2 ) );
4033 WW8PLCFx_FLD::~WW8PLCFx_FLD()
4037 sal_uInt32 WW8PLCFx_FLD::GetIdx() const
4039 return m_pPLCF ? m_pPLCF->GetIdx() : 0;
4042 void WW8PLCFx_FLD::SetIdx(sal_uInt32 nIdx)
4044 if( m_pPLCF )
4045 m_pPLCF->SetIdx( nIdx );
4048 bool WW8PLCFx_FLD::SeekPos(WW8_CP nCpPos)
4050 return m_pPLCF && m_pPLCF->SeekPosExact( nCpPos );
4053 WW8_CP WW8PLCFx_FLD::Where()
4055 return m_pPLCF ? m_pPLCF->Where() : WW8_CP_MAX;
4058 bool WW8PLCFx_FLD::StartPosIsFieldStart()
4060 void* pData;
4061 sal_Int32 nTest;
4062 return m_pPLCF && m_pPLCF->Get(nTest, pData) && ((static_cast<sal_uInt8*>(pData)[0] & 0x1f) == 0x13);
4065 bool WW8PLCFx_FLD::EndPosIsFieldEnd(WW8_CP& nCP)
4067 bool bRet = false;
4069 if (m_pPLCF)
4071 tools::Long n = m_pPLCF->GetIdx();
4073 m_pPLCF->advance();
4075 void* pData;
4076 sal_Int32 nTest;
4077 if ( m_pPLCF->Get(nTest, pData) && ((static_cast<sal_uInt8*>(pData)[0] & 0x1f) == 0x15) )
4079 nCP = nTest;
4080 bRet = true;
4083 m_pPLCF->SetIdx(n);
4086 return bRet;
4089 void WW8PLCFx_FLD::GetSprms(WW8PLCFxDesc* p)
4091 p->nStartPos = p->nEndPos = WW8_CP_MAX;
4092 p->pMemPos = nullptr;
4093 p->nSprmsLen = 0;
4094 p->bRealLineEnd = false;
4096 if (!m_pPLCF)
4098 p->nStartPos = WW8_CP_MAX; // there are no fields
4099 return;
4102 tools::Long n = m_pPLCF->GetIdx();
4104 sal_Int32 nP;
4105 void *pData;
4106 if (!m_pPLCF->Get(nP, pData)) // end of PLCFspecial?
4108 p->nStartPos = WW8_CP_MAX; // PLCF completely processed
4109 return;
4112 p->nStartPos = nP;
4114 m_pPLCF->advance();
4115 if (!m_pPLCF->Get(nP, pData)) // end of PLCFspecial?
4117 p->nStartPos = WW8_CP_MAX; // PLCF completely processed
4118 return;
4121 p->nEndPos = nP;
4123 m_pPLCF->SetIdx(n);
4125 p->nCp2OrIdx = m_pPLCF->GetIdx();
4128 void WW8PLCFx_FLD::advance()
4130 SAL_WARN_IF(!m_pPLCF, "sw.ww8", "Call without PLCFspecial field");
4131 if( !m_pPLCF )
4132 return;
4133 m_pPLCF->advance();
4136 bool WW8PLCFx_FLD::GetPara(tools::Long nIdx, WW8FieldDesc& rF)
4138 SAL_WARN_IF(!m_pPLCF, "sw.ww8", "Call without PLCFspecial field");
4139 if( !m_pPLCF )
4140 return false;
4142 tools::Long n = m_pPLCF->GetIdx();
4143 m_pPLCF->SetIdx(nIdx);
4145 bool bOk = WW8GetFieldPara(*m_pPLCF, rF);
4147 m_pPLCF->SetIdx(n);
4148 return bOk;
4151 // WW8PLCF_Book
4152 void WW8ReadSTTBF(bool bVer8, SvStream& rStrm, sal_uInt32 nStart, sal_Int32 nLen,
4153 sal_uInt16 nExtraLen, rtl_TextEncoding eCS, std::vector<OUString> &rArray,
4154 std::vector<ww::bytes>* pExtraArray, std::vector<OUString>* pValueArray)
4156 if (nLen==0) // Handle Empty STTBF
4157 return;
4159 sal_uInt64 const nOldPos = rStrm.Tell();
4160 if (checkSeek(rStrm, nStart))
4162 sal_uInt16 nLen2(0);
4163 rStrm.ReadUInt16( nLen2 ); // bVer67: total length of structure
4164 // bVer8 : count of strings
4166 if( bVer8 )
4168 sal_uInt16 nStrings(0);
4169 bool bUnicode = (0xFFFF == nLen2);
4170 if (bUnicode)
4171 rStrm.ReadUInt16( nStrings );
4172 else
4173 nStrings = nLen2;
4175 rStrm.ReadUInt16( nExtraLen );
4177 const size_t nMinStringLen = bUnicode ? sizeof(sal_uInt16) : sizeof(sal_uInt8);
4178 const size_t nMinRecordSize = nExtraLen + nMinStringLen;
4179 assert(nMinRecordSize != 0 && "impossible to be zero");
4180 const size_t nMaxPossibleStrings = rStrm.remainingSize() / nMinRecordSize;
4181 if (nStrings > nMaxPossibleStrings)
4183 SAL_WARN("sw.ww8", "STTBF claims " << nStrings << " entries, but only " << nMaxPossibleStrings << " are possible");
4184 nStrings = nMaxPossibleStrings;
4187 if (nExtraLen && nStrings)
4189 const size_t nMaxExtraLen = (rStrm.remainingSize() - (nStrings * nMinStringLen)) / nStrings;
4190 if (nExtraLen > nMaxExtraLen)
4192 SAL_WARN("sw.ww8", "STTBF claims " << nMaxExtraLen << " extra len, but only " << nMaxExtraLen << " are possible");
4193 nExtraLen = nMaxExtraLen;
4197 for (sal_uInt16 i=0; i < nStrings; ++i)
4199 if (bUnicode)
4200 rArray.push_back(read_uInt16_PascalString(rStrm));
4201 else
4203 OString aTmp = read_uInt8_lenPrefixed_uInt8s_ToOString(rStrm);
4204 rArray.push_back(OStringToOUString(aTmp, eCS));
4207 // Skip the extra data
4208 if (nExtraLen)
4210 if (pExtraArray)
4212 ww::bytes extraData(nExtraLen);
4213 rStrm.ReadBytes(extraData.data(), nExtraLen);
4214 pExtraArray->push_back(extraData);
4216 else
4217 rStrm.SeekRel( nExtraLen );
4220 // read the value of the document variables, if requested.
4221 if (pValueArray)
4223 for (sal_uInt16 i=0; i < nStrings; ++i)
4225 if( bUnicode )
4226 pValueArray->push_back(read_uInt16_PascalString(rStrm));
4227 else
4229 OString aTmp = read_uInt8_lenPrefixed_uInt8s_ToOString(rStrm);
4230 pValueArray->push_back(OStringToOUString(aTmp, eCS));
4235 else
4237 if( nLen2 != nLen )
4239 OSL_ENSURE(nLen2 == nLen,
4240 "Fib length and read length are different");
4241 if (nLen > SAL_MAX_UINT16)
4242 nLen = SAL_MAX_UINT16;
4243 else if (nLen < 2 )
4244 nLen = 2;
4245 nLen2 = o3tl::narrowing<sal_uInt16>(nLen);
4247 sal_uLong nRead = 0;
4248 for( nLen2 -= 2; nRead < nLen2; )
4250 sal_uInt8 nBChar(0);
4251 rStrm.ReadUChar( nBChar );
4252 ++nRead;
4253 if (nBChar)
4255 OString aTmp = read_uInt8s_ToOString(rStrm, nBChar);
4256 nRead += aTmp.getLength();
4257 rArray.push_back(OStringToOUString(aTmp, eCS));
4259 else
4260 rArray.emplace_back();
4262 // Skip the extra data (for bVer67 versions this must come from
4263 // external knowledge)
4264 if (nExtraLen)
4266 if (pExtraArray)
4268 ww::bytes extraData(nExtraLen);
4269 rStrm.ReadBytes(extraData.data(), nExtraLen);
4270 pExtraArray->push_back(extraData);
4272 else
4273 rStrm.SeekRel( nExtraLen );
4274 nRead+=nExtraLen;
4279 rStrm.Seek(nOldPos);
4282 WW8PLCFx_Book::WW8PLCFx_Book(SvStream* pTableSt, const WW8Fib& rFib)
4283 : WW8PLCFx(rFib, false), m_nIsEnd(0), m_nBookmarkId(1)
4285 if( !rFib.m_fcPlcfbkf || !rFib.m_lcbPlcfbkf || !rFib.m_fcPlcfbkl ||
4286 !rFib.m_lcbPlcfbkl || !rFib.m_fcSttbfbkmk || !rFib.m_lcbSttbfbkmk )
4288 m_nIMax = 0;
4290 else
4292 m_pBook[0].reset( new WW8PLCFspecial(pTableSt,rFib.m_fcPlcfbkf,rFib.m_lcbPlcfbkf,4) );
4294 m_pBook[1].reset( new WW8PLCFspecial(pTableSt,rFib.m_fcPlcfbkl,rFib.m_lcbPlcfbkl,0) );
4296 rtl_TextEncoding eStructChrSet = WW8Fib::GetFIBCharset(rFib.m_chseTables, rFib.m_lid);
4298 WW8ReadSTTBF( (7 < rFib.m_nVersion), *pTableSt, rFib.m_fcSttbfbkmk,
4299 rFib.m_lcbSttbfbkmk, 0, eStructChrSet, m_aBookNames );
4301 m_nIMax = m_aBookNames.size();
4303 if( m_pBook[0]->GetIMax() < m_nIMax ) // Count of Bookmarks
4304 m_nIMax = m_pBook[0]->GetIMax();
4305 if( m_pBook[1]->GetIMax() < m_nIMax )
4306 m_nIMax = m_pBook[1]->GetIMax();
4307 m_aStatus.resize(m_nIMax);
4311 WW8PLCFx_Book::~WW8PLCFx_Book()
4315 sal_uInt32 WW8PLCFx_Book::GetIdx() const
4317 return m_nIMax ? m_pBook[0]->GetIdx() : 0;
4320 void WW8PLCFx_Book::SetIdx(sal_uInt32 nI)
4322 if( m_nIMax )
4323 m_pBook[0]->SetIdx( nI );
4326 sal_uInt32 WW8PLCFx_Book::GetIdx2() const
4328 return m_nIMax ? ( m_pBook[1]->GetIdx() | ( m_nIsEnd ? 0x80000000 : 0 ) ) : 0;
4331 void WW8PLCFx_Book::SetIdx2(sal_uInt32 nI)
4333 if( m_nIMax )
4335 m_pBook[1]->SetIdx( nI & 0x7fffffff );
4336 m_nIsEnd = o3tl::narrowing<sal_uInt16>( ( nI >> 31 ) & 1 ); // 0 or 1
4340 bool WW8PLCFx_Book::SeekPos(WW8_CP nCpPos)
4342 if( !m_pBook[0] )
4343 return false;
4345 bool bOk = m_pBook[0]->SeekPosExact( nCpPos );
4346 bOk &= m_pBook[1]->SeekPosExact( nCpPos );
4347 m_nIsEnd = 0;
4349 return bOk;
4352 WW8_CP WW8PLCFx_Book::Where()
4354 return m_pBook[m_nIsEnd]->Where();
4357 tools::Long WW8PLCFx_Book::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
4359 void* pData;
4360 rEnd = WW8_CP_MAX;
4361 rLen = 0;
4363 if (!m_pBook[0] || !m_pBook[1] || !m_nIMax || (m_pBook[m_nIsEnd]->GetIdx()) >= m_nIMax)
4365 rStart = rEnd = WW8_CP_MAX;
4366 return -1;
4369 (void)m_pBook[m_nIsEnd]->Get( rStart, pData ); // query position
4370 return m_pBook[m_nIsEnd]->GetIdx();
4373 // The operator ++ has a pitfall: If 2 bookmarks adjoin each other,
4374 // we should first go to the end of the first one
4375 // and then to the beginning of the second one.
4376 // But if 2 bookmarks with the length of 0 lie on top of each other,
4377 // we *must* first find the start and end of each bookmark.
4378 // The case of: ][
4379 // [...]
4380 // ][
4381 // is not solved yet.
4382 // Because I must jump back and forth in the start- and end-indices then.
4383 // This would require one more index or bitfield to remember
4384 // the already processed bookmarks.
4386 void WW8PLCFx_Book::advance()
4388 if( !(m_pBook[0] && m_pBook[1] && m_nIMax) )
4389 return;
4391 (*m_pBook[m_nIsEnd]).advance();
4393 sal_uLong l0 = m_pBook[0]->Where();
4394 sal_uLong l1 = m_pBook[1]->Where();
4395 if( l0 < l1 )
4396 m_nIsEnd = 0;
4397 else if( l1 < l0 )
4398 m_nIsEnd = 1;
4399 else
4401 const void * p = m_pBook[0]->GetData(m_pBook[0]->GetIdx());
4402 tools::Long nPairFor = (p == nullptr) ? 0 : SVBT16ToUInt16(*static_cast<SVBT16 const *>(p));
4403 if (nPairFor == m_pBook[1]->GetIdx())
4404 m_nIsEnd = 0;
4405 else
4406 m_nIsEnd = m_nIsEnd ? 0 : 1;
4410 tools::Long WW8PLCFx_Book::GetLen() const
4412 if( m_nIsEnd )
4414 OSL_ENSURE( false, "Incorrect call (1) of PLCF_Book::GetLen()" );
4415 return 0;
4417 void * p;
4418 WW8_CP nStartPos;
4419 if( !m_pBook[0]->Get( nStartPos, p ) )
4421 OSL_ENSURE( false, "Incorrect call (2) of PLCF_Book::GetLen()" );
4422 return 0;
4424 const sal_uInt16 nEndIdx = SVBT16ToUInt16( *static_cast<SVBT16*>(p) );
4425 tools::Long nNum = m_pBook[1]->GetPos( nEndIdx );
4426 nNum -= nStartPos;
4427 return nNum;
4430 void WW8PLCFx_Book::SetStatus(sal_uInt16 nIndex, eBookStatus eStat)
4432 SAL_WARN_IF(nIndex >= m_nIMax, "sw.ww8",
4433 "bookmark index " << nIndex << " invalid");
4434 eBookStatus eStatus = m_aStatus.at(nIndex);
4435 m_aStatus[nIndex] = static_cast<eBookStatus>(eStatus | eStat);
4438 eBookStatus WW8PLCFx_Book::GetStatus() const
4440 if (m_aStatus.empty())
4441 return BOOK_NORMAL;
4442 tools::Long nEndIdx = GetHandle();
4443 return ( nEndIdx < m_nIMax ) ? m_aStatus[nEndIdx] : BOOK_NORMAL;
4446 tools::Long WW8PLCFx_Book::GetHandle() const
4448 if( !m_pBook[0] || !m_pBook[1] )
4449 return LONG_MAX;
4451 if( m_nIsEnd )
4452 return m_pBook[1]->GetIdx();
4453 else
4455 if (const void* p = m_pBook[0]->GetData(m_pBook[0]->GetIdx()))
4456 return SVBT16ToUInt16( *static_cast<SVBT16 const *>(p) );
4457 else
4458 return LONG_MAX;
4462 OUString WW8PLCFx_Book::GetBookmark(tools::Long nStart,tools::Long nEnd, sal_uInt16 &nIndex)
4464 bool bFound = false;
4465 sal_uInt16 i = 0;
4466 if (m_pBook[0] && m_pBook[1])
4468 WW8_CP nStartCurrent, nEndCurrent;
4469 while (sal::static_int_cast<decltype(m_aBookNames)::size_type>(i) < m_aBookNames.size())
4471 void* p;
4472 sal_uInt16 nEndIdx;
4474 if( m_pBook[0]->GetData( i, nStartCurrent, p ) && p )
4475 nEndIdx = SVBT16ToUInt16( *static_cast<SVBT16*>(p) );
4476 else
4478 OSL_ENSURE( false, "Bookmark-EndIdx not readable" );
4479 nEndIdx = i;
4482 nEndCurrent = m_pBook[1]->GetPos( nEndIdx );
4484 if ((nStartCurrent >= nStart) && (nEndCurrent <= nEnd))
4486 nIndex = i;
4487 bFound=true;
4488 break;
4490 ++i;
4493 return bFound ? m_aBookNames[i] : OUString();
4496 OUString WW8PLCFx_Book::GetUniqueBookmarkName(const OUString &rSuggestedName)
4498 OUString aRet(rSuggestedName.isEmpty() ? OUString("Unnamed") : rSuggestedName);
4499 size_t i = 0;
4500 while (i < m_aBookNames.size())
4502 if (aRet == m_aBookNames[i])
4504 sal_Int32 len = aRet.getLength();
4505 sal_Int32 p = len - 1;
4506 while (p > 0 && aRet[p] >= '0' && aRet[p] <= '9')
4507 --p;
4508 aRet = aRet.subView(0, p+1) + OUString::number(m_nBookmarkId++);
4509 i = 0; // start search from beginning
4511 else
4512 ++i;
4514 return aRet;
4517 void WW8PLCFx_Book::MapName(OUString& rName)
4519 if( !m_pBook[0] || !m_pBook[1] )
4520 return;
4522 size_t i = 0;
4523 while (i < m_aBookNames.size())
4525 if (rName.equalsIgnoreAsciiCase(m_aBookNames[i]))
4527 rName = m_aBookNames[i];
4528 break;
4530 ++i;
4534 const OUString* WW8PLCFx_Book::GetName() const
4536 const OUString *pRet = nullptr;
4537 if (!m_nIsEnd && (m_pBook[0]->GetIdx() < m_nIMax))
4538 pRet = &(m_aBookNames[m_pBook[0]->GetIdx()]);
4539 return pRet;
4542 WW8PLCFx_AtnBook::WW8PLCFx_AtnBook(SvStream* pTableSt, const WW8Fib& rFib)
4543 : WW8PLCFx(rFib, /*bSprm=*/false),
4544 m_bIsEnd(false)
4546 if (!rFib.m_fcPlcfAtnbkf || !rFib.m_lcbPlcfAtnbkf || !rFib.m_fcPlcfAtnbkl || !rFib.m_lcbPlcfAtnbkl)
4548 m_nIMax = 0;
4550 else
4552 m_pBook[0].reset( new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfAtnbkf, rFib.m_lcbPlcfAtnbkf, 4) );
4553 m_pBook[1].reset( new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfAtnbkl, rFib.m_lcbPlcfAtnbkl, 0) );
4555 m_nIMax = m_pBook[0]->GetIMax();
4556 if (m_pBook[1]->GetIMax() < m_nIMax)
4557 m_nIMax = m_pBook[1]->GetIMax();
4561 WW8PLCFx_AtnBook::~WW8PLCFx_AtnBook()
4565 sal_uInt32 WW8PLCFx_AtnBook::GetIdx() const
4567 return m_nIMax ? m_pBook[0]->GetIdx() : 0;
4570 void WW8PLCFx_AtnBook::SetIdx(sal_uInt32 nI)
4572 if( m_nIMax )
4573 m_pBook[0]->SetIdx( nI );
4576 sal_uInt32 WW8PLCFx_AtnBook::GetIdx2() const
4578 if (m_nIMax)
4579 return m_pBook[1]->GetIdx() | ( m_bIsEnd ? 0x80000000 : 0 );
4580 else
4581 return 0;
4584 void WW8PLCFx_AtnBook::SetIdx2(sal_uInt32 nI)
4586 if( m_nIMax )
4588 m_pBook[1]->SetIdx( nI & 0x7fffffff );
4589 m_bIsEnd = static_cast<bool>(( nI >> 31 ) & 1);
4593 bool WW8PLCFx_AtnBook::SeekPos(WW8_CP nCpPos)
4595 if (!m_pBook[0])
4596 return false;
4598 bool bOk = m_pBook[0]->SeekPosExact(nCpPos);
4599 bOk &= m_pBook[1]->SeekPosExact(nCpPos);
4600 m_bIsEnd = false;
4602 return bOk;
4605 WW8_CP WW8PLCFx_AtnBook::Where()
4607 return m_pBook[static_cast<int>(m_bIsEnd)]->Where();
4610 tools::Long WW8PLCFx_AtnBook::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
4612 void* pData;
4613 rEnd = WW8_CP_MAX;
4614 rLen = 0;
4616 if (!m_pBook[0] || !m_pBook[1] || !m_nIMax || (m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx()) >= m_nIMax)
4618 rStart = rEnd = WW8_CP_MAX;
4619 return -1;
4622 (void)m_pBook[static_cast<int>(m_bIsEnd)]->Get(rStart, pData);
4623 return m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx();
4626 void WW8PLCFx_AtnBook::advance()
4628 if( !(m_pBook[0] && m_pBook[1] && m_nIMax) )
4629 return;
4631 (*m_pBook[static_cast<int>(m_bIsEnd)]).advance();
4633 sal_uLong l0 = m_pBook[0]->Where();
4634 sal_uLong l1 = m_pBook[1]->Where();
4635 if( l0 < l1 )
4636 m_bIsEnd = false;
4637 else if( l1 < l0 )
4638 m_bIsEnd = true;
4639 else
4641 const void * p = m_pBook[0]->GetData(m_pBook[0]->GetIdx());
4642 tools::Long nPairFor = (p == nullptr) ? 0 : SVBT16ToUInt16(*static_cast<SVBT16 const *>(p));
4643 if (nPairFor == m_pBook[1]->GetIdx())
4644 m_bIsEnd = false;
4645 else
4646 m_bIsEnd = !m_bIsEnd;
4650 tools::Long WW8PLCFx_AtnBook::getHandle() const
4652 if (!m_pBook[0] || !m_pBook[1])
4653 return LONG_MAX;
4655 if (m_bIsEnd)
4656 return m_pBook[1]->GetIdx();
4657 else
4659 if (const void* p = m_pBook[0]->GetData(m_pBook[0]->GetIdx()))
4660 return SVBT16ToUInt16(*static_cast<const SVBT16*>(p));
4661 else
4662 return LONG_MAX;
4666 bool WW8PLCFx_AtnBook::getIsEnd() const
4668 return m_bIsEnd;
4671 WW8PLCFx_FactoidBook::WW8PLCFx_FactoidBook(SvStream* pTableSt, const WW8Fib& rFib)
4672 : WW8PLCFx(rFib, /*bSprm=*/false),
4673 m_bIsEnd(false)
4675 if (!rFib.m_fcPlcfBkfFactoid || !rFib.m_lcbPlcfBkfFactoid || !rFib.m_fcPlcfBklFactoid || !rFib.m_lcbPlcfBklFactoid)
4677 m_nIMax = 0;
4679 else
4681 m_pBook[0].reset(new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfBkfFactoid, rFib.m_lcbPlcfBkfFactoid, 6));
4682 m_pBook[1].reset(new WW8PLCFspecial(pTableSt, rFib.m_fcPlcfBklFactoid, rFib.m_lcbPlcfBklFactoid, 4));
4684 m_nIMax = m_pBook[0]->GetIMax();
4685 if (m_pBook[1]->GetIMax() < m_nIMax)
4686 m_nIMax = m_pBook[1]->GetIMax();
4690 WW8PLCFx_FactoidBook::~WW8PLCFx_FactoidBook()
4694 sal_uInt32 WW8PLCFx_FactoidBook::GetIdx() const
4696 return m_nIMax ? m_pBook[0]->GetIdx() : 0;
4699 void WW8PLCFx_FactoidBook::SetIdx(sal_uInt32 nI)
4701 if (m_nIMax)
4702 m_pBook[0]->SetIdx(nI);
4705 sal_uInt32 WW8PLCFx_FactoidBook::GetIdx2() const
4707 if (m_nIMax)
4708 return m_pBook[1]->GetIdx() | (m_bIsEnd ? 0x80000000 : 0);
4709 else
4710 return 0;
4713 void WW8PLCFx_FactoidBook::SetIdx2(sal_uInt32 nI)
4715 if (m_nIMax)
4717 m_pBook[1]->SetIdx(nI & 0x7fffffff);
4718 m_bIsEnd = static_cast<bool>((nI >> 31) & 1);
4722 bool WW8PLCFx_FactoidBook::SeekPos(WW8_CP nCpPos)
4724 if (!m_pBook[0])
4725 return false;
4727 bool bOk = m_pBook[0]->SeekPosExact(nCpPos);
4728 bOk &= m_pBook[1]->SeekPosExact(nCpPos);
4729 m_bIsEnd = false;
4731 return bOk;
4734 WW8_CP WW8PLCFx_FactoidBook::Where()
4736 return m_pBook[static_cast<int>(m_bIsEnd)]->Where();
4739 tools::Long WW8PLCFx_FactoidBook::GetNoSprms(WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen)
4741 void* pData;
4742 rEnd = WW8_CP_MAX;
4743 rLen = 0;
4745 if (!m_pBook[0] || !m_pBook[1] || !m_nIMax || (m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx()) >= m_nIMax)
4747 rStart = rEnd = WW8_CP_MAX;
4748 return -1;
4751 (void)m_pBook[static_cast<int>(m_bIsEnd)]->Get(rStart, pData);
4752 return m_pBook[static_cast<int>(m_bIsEnd)]->GetIdx();
4755 void WW8PLCFx_FactoidBook::advance()
4757 if (!(m_pBook[0] && m_pBook[1] && m_nIMax))
4758 return;
4760 (*m_pBook[static_cast<int>(m_bIsEnd)]).advance();
4762 sal_uLong l0 = m_pBook[0]->Where();
4763 sal_uLong l1 = m_pBook[1]->Where();
4764 if (l0 < l1)
4765 m_bIsEnd = false;
4766 else if (l1 < l0)
4767 m_bIsEnd = true;
4768 else
4770 const void * p = m_pBook[0]->GetData(m_pBook[0]->GetIdx());
4771 tools::Long nPairFor = (p == nullptr) ? 0 : SVBT16ToUInt16(*static_cast<SVBT16 const *>(p));
4772 if (nPairFor == m_pBook[1]->GetIdx())
4773 m_bIsEnd = false;
4774 else
4775 m_bIsEnd = !m_bIsEnd;
4779 tools::Long WW8PLCFx_FactoidBook::getHandle() const
4781 if (!m_pBook[0] || !m_pBook[1])
4782 return LONG_MAX;
4784 if (m_bIsEnd)
4785 return m_pBook[1]->GetIdx();
4786 else
4788 if (const void* p = m_pBook[0]->GetData(m_pBook[0]->GetIdx()))
4789 return SVBT16ToUInt16(*static_cast<const SVBT16*>(p));
4790 else
4791 return LONG_MAX;
4795 bool WW8PLCFx_FactoidBook::getIsEnd() const
4797 return m_bIsEnd;
4800 // In the end of a paragraph in WW6 the attribute extends after the <CR>.
4801 // This will be reset by one character to be used with SW,
4802 // if we don't expect trouble thereby.
4803 void WW8PLCFMan::AdjustEnds( WW8PLCFxDesc& rDesc )
4805 // might be necessary to do this for pChp and/or pSep as well,
4806 // but its definitely the case for paragraphs that EndPos > StartPos
4807 // for a well formed paragraph as those always have a paragraph
4808 // <cr> in them
4809 if (&rDesc == m_pPap && rDesc.bRealLineEnd)
4811 if (rDesc.nStartPos == rDesc.nEndPos && rDesc.nEndPos != WW8_CP_MAX)
4813 SAL_WARN("sw.ww8", "WW8PLCFxDesc End same as Start, abandoning to avoid looping");
4814 rDesc.nEndPos = WW8_CP_MAX;
4818 //Store old end position for supercool new property finder that uses
4819 //cp instead of fc's as nature intended
4820 rDesc.nOrigEndPos = rDesc.nEndPos;
4821 rDesc.nOrigStartPos = rDesc.nStartPos;
4824 Normally given ^XXX{para end}^ we don't actually insert a para end
4825 character into the document, so we clip the para end property one to the
4826 left to make the para properties end when the paragraph text does. In a
4827 drawing textbox we actually do insert a para end character, so we don't
4828 clip it. Making the para end properties end after the para end char.
4830 if (GetDoingDrawTextBox())
4831 return;
4833 if ( (&rDesc == m_pPap) && rDesc.bRealLineEnd )
4835 if ( m_pPap->nEndPos != WW8_CP_MAX ) // Para adjust
4837 m_nLineEnd = m_pPap->nEndPos;// nLineEnd points *after* the <CR>
4838 m_pPap->nEndPos--; // shorten paragraph end by one character
4840 // Is there already a sep end, which points to the current paragraph end?
4841 // Then we also must shorten by one character
4842 if( m_pSep->nEndPos == m_nLineEnd )
4843 m_pSep->nEndPos--;
4846 else if (&rDesc == m_pSep)
4848 // Sep Adjust if end Char-Attr == paragraph end ...
4849 if( (rDesc.nEndPos == m_nLineEnd) && (rDesc.nEndPos > rDesc.nStartPos) )
4850 rDesc.nEndPos--; // ... then shorten by one character
4854 void WW8PLCFxDesc::ReduceByOffset()
4856 SAL_WARN_IF(WW8_CP_MAX != nStartPos && nStartPos > nEndPos, "sw.ww8",
4857 "End " << nEndPos << " before Start " << nStartPos);
4859 if( nStartPos != WW8_CP_MAX )
4862 ##516##,##517##
4863 Force the property change to happen at the beginning of this
4864 subdocument, same as in GetNewNoSprms, except that the target type is
4865 attributes attached to a piece that might span subdocument boundaries
4867 if (nCpOfs > nStartPos)
4868 nStartPos = 0;
4869 else
4870 nStartPos -= nCpOfs;
4872 if (nEndPos != WW8_CP_MAX)
4874 if (nCpOfs > nEndPos)
4876 SAL_WARN("sw.ww8", "broken subdocument piece entry");
4877 nEndPos = WW8_CP_MAX;
4879 else
4880 nEndPos -= nCpOfs;
4884 void WW8PLCFMan::GetNewSprms( WW8PLCFxDesc& rDesc )
4886 rDesc.pPLCFx->GetSprms(&rDesc);
4887 rDesc.ReduceByOffset();
4889 rDesc.bFirstSprm = true;
4890 AdjustEnds( rDesc );
4891 rDesc.nOrigSprmsLen = rDesc.nSprmsLen;
4894 void WW8PLCFMan::GetNewNoSprms( WW8PLCFxDesc& rDesc )
4896 rDesc.nCp2OrIdx = rDesc.pPLCFx->GetNoSprms(rDesc.nStartPos, rDesc.nEndPos,
4897 rDesc.nSprmsLen);
4899 SAL_WARN_IF(WW8_CP_MAX != rDesc.nStartPos && rDesc.nStartPos > rDesc.nEndPos, "sw.ww8",
4900 "End " << rDesc.nEndPos << " before Start " << rDesc.nStartPos);
4902 rDesc.ReduceByOffset();
4904 rDesc.bFirstSprm = true;
4905 rDesc.nOrigSprmsLen = rDesc.nSprmsLen;
4908 sal_uInt16 WW8PLCFMan::GetId(const WW8PLCFxDesc* p) const
4910 sal_uInt16 nId = 0; // Id = 0 for empty attributes
4912 if (p == m_pField)
4913 nId = eFLD;
4914 else if (p == m_pFootnote)
4915 nId = eFTN;
4916 else if (p == m_pEdn)
4917 nId = eEDN;
4918 else if (p == m_pAnd)
4919 nId = eAND;
4920 else if (p->nSprmsLen >= maSprmParser.MinSprmLen())
4921 nId = maSprmParser.GetSprmId(p->pMemPos);
4923 return nId;
4926 WW8PLCFMan::WW8PLCFMan(const WW8ScannerBase* pBase, ManTypes nType, tools::Long nStartCp,
4927 bool bDoingDrawTextBox)
4928 : maSprmParser(*pBase->m_pWw8Fib),
4929 m_nLineEnd(WW8_CP_MAX),
4930 mbDoingDrawTextBox(bDoingDrawTextBox)
4932 m_pWwFib = pBase->m_pWw8Fib;
4934 m_nManType = nType;
4936 if( MAN_MAINTEXT == nType )
4938 // search order of the attributes
4939 m_nPLCF = MAN_PLCF_COUNT;
4940 m_pField = &m_aD[0];
4941 m_pBkm = &m_aD[1];
4942 m_pEdn = &m_aD[2];
4943 m_pFootnote = &m_aD[3];
4944 m_pAnd = &m_aD[4];
4946 m_pPcd = pBase->m_pPLCFx_PCD ? &m_aD[5] : nullptr;
4947 //pPcdA index == pPcd index + 1
4948 m_pPcdA = pBase->m_pPLCFx_PCDAttrs ? &m_aD[6] : nullptr;
4950 m_pChp = &m_aD[7];
4951 m_pPap = &m_aD[8];
4952 m_pSep = &m_aD[9];
4953 m_pAtnBkm = &m_aD[10];
4954 m_pFactoidBkm = &m_aD[11];
4956 m_pSep->pPLCFx = pBase->m_pSepPLCF.get();
4957 m_pFootnote->pPLCFx = pBase->m_pFootnotePLCF.get();
4958 m_pEdn->pPLCFx = pBase->m_pEdnPLCF.get();
4959 m_pBkm->pPLCFx = pBase->m_pBook.get();
4960 m_pAnd->pPLCFx = pBase->m_pAndPLCF.get();
4961 m_pAtnBkm->pPLCFx = pBase->m_pAtnBook.get();
4962 m_pFactoidBkm->pPLCFx = pBase->m_pFactoidBook.get();
4965 else
4967 // search order of the attributes
4968 m_nPLCF = 7;
4969 m_pField = &m_aD[0];
4970 m_pBkm = pBase->m_pBook ? &m_aD[1] : nullptr;
4972 m_pPcd = pBase->m_pPLCFx_PCD ? &m_aD[2] : nullptr;
4973 //pPcdA index == pPcd index + 1
4974 m_pPcdA= pBase->m_pPLCFx_PCDAttrs ? &m_aD[3] : nullptr;
4976 m_pChp = &m_aD[4];
4977 m_pPap = &m_aD[5];
4978 m_pSep = &m_aD[6]; // Dummy
4980 m_pAnd = m_pAtnBkm = m_pFactoidBkm = m_pFootnote = m_pEdn = nullptr; // not used at SpezText
4983 m_pChp->pPLCFx = pBase->m_pChpPLCF.get();
4984 m_pPap->pPLCFx = pBase->m_pPapPLCF.get();
4985 if( m_pPcd )
4986 m_pPcd->pPLCFx = pBase->m_pPLCFx_PCD.get();
4987 if( m_pPcdA )
4988 m_pPcdA->pPLCFx= pBase->m_pPLCFx_PCDAttrs.get();
4989 if( m_pBkm )
4990 m_pBkm->pPLCFx = pBase->m_pBook.get();
4992 m_pMagicTables = pBase->m_pMagicTables.get();
4993 m_pSubdocs = pBase->m_pSubdocs.get();
4994 m_pExtendedAtrds = pBase->m_pExtendedAtrds.get();
4996 switch( nType ) // field initialization
4998 case MAN_HDFT:
4999 m_pField->pPLCFx = pBase->m_pFieldHdFtPLCF.get();
5000 m_pFdoa = pBase->m_pHdFtFdoa.get();
5001 m_pTxbx = pBase->m_pHdFtTxbx.get();
5002 m_pTxbxBkd = pBase->m_pHdFtTxbxBkd.get();
5003 break;
5004 case MAN_FTN:
5005 m_pField->pPLCFx = pBase->m_pFieldFootnotePLCF.get();
5006 m_pFdoa = m_pTxbx = m_pTxbxBkd = nullptr;
5007 break;
5008 case MAN_EDN:
5009 m_pField->pPLCFx = pBase->m_pFieldEdnPLCF.get();
5010 m_pFdoa = m_pTxbx = m_pTxbxBkd = nullptr;
5011 break;
5012 case MAN_AND:
5013 m_pField->pPLCFx = pBase->m_pFieldAndPLCF.get();
5014 m_pFdoa = m_pTxbx = m_pTxbxBkd = nullptr;
5015 break;
5016 case MAN_TXBX:
5017 m_pField->pPLCFx = pBase->m_pFieldTxbxPLCF.get();
5018 m_pTxbx = pBase->m_pMainTxbx.get();
5019 m_pTxbxBkd = pBase->m_pMainTxbxBkd.get();
5020 m_pFdoa = nullptr;
5021 break;
5022 case MAN_TXBX_HDFT:
5023 m_pField->pPLCFx = pBase->m_pFieldTxbxHdFtPLCF.get();
5024 m_pTxbx = pBase->m_pHdFtTxbx.get();
5025 m_pTxbxBkd = pBase->m_pHdFtTxbxBkd.get();
5026 m_pFdoa = nullptr;
5027 break;
5028 default:
5029 m_pField->pPLCFx = pBase->m_pFieldPLCF.get();
5030 m_pFdoa = pBase->m_pMainFdoa.get();
5031 m_pTxbx = pBase->m_pMainTxbx.get();
5032 m_pTxbxBkd = pBase->m_pMainTxbxBkd.get();
5033 break;
5036 WW8_CP cp = 0;
5037 m_pWwFib->GetBaseCp(nType, &cp); //TODO: check return value
5038 m_nCpO = cp;
5040 if( nStartCp || m_nCpO )
5041 SeekPos( nStartCp ); // adjust PLCFe at text StartPos
5043 // initialization to the member vars Low-Level
5044 GetChpPLCF()->ResetAttrStartEnd();
5045 GetPapPLCF()->ResetAttrStartEnd();
5046 for( sal_uInt16 i=0; i < m_nPLCF; ++i)
5048 WW8PLCFxDesc* p = &m_aD[i];
5051 ##516##,##517##
5052 For subdocuments we modify the cp of properties to be relative to
5053 the beginning of subdocuments, we should also do the same for
5054 piecetable changes, and piecetable properties, otherwise a piece
5055 change that happens in a subdocument is lost.
5057 p->nCpOfs = ( p == m_pChp || p == m_pPap || p == m_pBkm || p == m_pPcd ||
5058 p == m_pPcdA ) ? m_nCpO : 0;
5060 p->nCp2OrIdx = 0;
5061 p->bFirstSprm = false;
5062 p->xIdStack.reset();
5064 if ((p == m_pChp) || (p == m_pPap))
5065 p->nStartPos = p->nEndPos = nStartCp;
5066 else
5067 p->nStartPos = p->nEndPos = WW8_CP_MAX;
5070 // initialization to the member vars High-Level
5071 for( sal_uInt16 i=0; i<m_nPLCF; ++i){
5072 WW8PLCFxDesc* p = &m_aD[i];
5074 if( !p->pPLCFx )
5076 p->nStartPos = p->nEndPos = WW8_CP_MAX;
5077 continue;
5080 if( p->pPLCFx->IsSprm() )
5082 // Careful: nEndPos must be
5083 p->xIdStack.emplace();
5084 if ((p == m_pChp) || (p == m_pPap))
5086 WW8_CP nTemp = p->nEndPos+p->nCpOfs;
5087 p->pMemPos = nullptr;
5088 p->nSprmsLen = 0;
5089 p->nStartPos = nTemp;
5090 if (!(*p->pPLCFx).SeekPos(p->nStartPos))
5091 p->nEndPos = p->nStartPos = WW8_CP_MAX;
5092 else
5093 GetNewSprms( *p );
5095 else
5096 GetNewSprms( *p ); // initialized at all PLCFs
5098 else if( p->pPLCFx )
5099 GetNewNoSprms( *p );
5103 WW8PLCFMan::~WW8PLCFMan()
5105 for( sal_uInt16 i=0; i<m_nPLCF; i++)
5106 m_aD[i].xIdStack.reset();
5109 // 0. which attr class,
5110 // 1. if it's an attr start,
5111 // 2. CP, where is next attr change
5112 sal_uInt16 WW8PLCFMan::WhereIdx(bool *const pbStart, WW8_CP *const pPos) const
5114 OSL_ENSURE(m_nPLCF,"What the hell");
5115 WW8_CP nNext = WW8_CP_MAX; // search order:
5116 sal_uInt16 nNextIdx = m_nPLCF;// first ending found ( CHP, PAP, ( SEP ) ),
5117 bool bStart = true; // now find beginnings ( ( SEP ), PAP, CHP )
5118 const WW8PLCFxDesc* pD;
5119 for (sal_uInt16 i=0; i < m_nPLCF; ++i)
5121 pD = &m_aD[i];
5122 if (pD != m_pPcdA)
5124 if( (pD->nEndPos < nNext) && (pD->nStartPos == WW8_CP_MAX) )
5126 // otherwise start = end
5127 nNext = pD->nEndPos;
5128 nNextIdx = i;
5129 bStart = false;
5133 for (sal_uInt16 i=m_nPLCF; i > 0; --i)
5135 pD = &m_aD[i-1];
5136 if (pD != m_pPcdA && pD->nStartPos < nNext )
5138 nNext = pD->nStartPos;
5139 nNextIdx = i-1;
5140 bStart = true;
5143 if( pPos )
5144 *pPos = nNext;
5145 if( pbStart )
5146 *pbStart = bStart;
5147 return nNextIdx;
5150 // gives the CP pos of the next attr change
5151 WW8_CP WW8PLCFMan::Where() const
5153 WW8_CP l;
5154 WhereIdx(nullptr, &l);
5155 return l;
5158 void WW8PLCFMan::SeekPos( tools::Long nNewCp )
5160 m_pChp->pPLCFx->SeekPos( nNewCp + m_nCpO ); // create new attr
5161 m_pPap->pPLCFx->SeekPos( nNewCp + m_nCpO );
5162 m_pField->pPLCFx->SeekPos( nNewCp );
5163 if( m_pPcd )
5164 m_pPcd->pPLCFx->SeekPos( nNewCp + m_nCpO );
5165 if( m_pBkm )
5166 m_pBkm->pPLCFx->SeekPos( nNewCp + m_nCpO );
5169 void WW8PLCFMan::SaveAllPLCFx( WW8PLCFxSaveAll& rSave ) const
5171 sal_uInt16 n=0;
5172 if( m_pPcd )
5173 m_pPcd->Save( rSave.aS[n++] );
5174 if( m_pPcdA )
5175 m_pPcdA->Save( rSave.aS[n++] );
5177 for(sal_uInt16 i=0; i<m_nPLCF; ++i)
5178 if( m_pPcd != &m_aD[i] && m_pPcdA != &m_aD[i] )
5179 m_aD[i].Save( rSave.aS[n++] );
5182 void WW8PLCFMan::RestoreAllPLCFx( const WW8PLCFxSaveAll& rSave )
5184 sal_uInt16 n=0;
5185 if( m_pPcd )
5186 m_pPcd->Restore( rSave.aS[n++] );
5187 if( m_pPcdA )
5188 m_pPcdA->Restore( rSave.aS[n++] );
5190 for(sal_uInt16 i=0; i<m_nPLCF; ++i)
5191 if( m_pPcd != &m_aD[i] && m_pPcdA != &m_aD[i] )
5192 m_aD[i].Restore( rSave.aS[n++] );
5195 namespace
5197 bool IsSizeLegal(tools::Long nSprmLen, sal_Int32 nSprmsLen)
5199 if (nSprmLen > nSprmsLen)
5201 SAL_WARN("sw.ww8", "Short sprm, len " << nSprmLen << " claimed, max possible is " << nSprmsLen);
5202 return false;
5204 return true;
5208 bool WW8PLCFMan::IsSprmLegalForCategory(sal_uInt16 nSprmId, short nIdx) const
5210 const WW8PLCFxDesc* p = &m_aD[nIdx];
5211 if (p != m_pSep) // just check sep for now
5212 return true;
5214 bool bRet;
5215 ww::WordVersion eVersion = maSprmParser.GetFIBVersion();
5216 if (eVersion <= ww::eWW2)
5217 bRet = nSprmId >= 112 && nSprmId <= 145;
5218 else if (eVersion < ww::eWW8)
5219 bRet = nSprmId >= NS_sprm::v6::sprmSScnsPgn && nSprmId <= NS_sprm::v6::sprmSDMPaperReq;
5220 else
5223 Sprm bits: 10-12 sgc sprm group; type of sprm (PAP, CHP, etc)
5225 sgc value type of sprm
5226 1 PAP
5227 2 CHP
5228 3 PIC
5229 4 SEP
5230 5 TAP
5232 auto nSGC = ((nSprmId & 0x1C00) >> 10);
5233 bRet = nSGC == 4;
5235 if (!bRet)
5236 SAL_INFO("sw.ww8", "sprm, id " << nSprmId << " wrong category for section properties");
5237 return bRet;
5240 void WW8PLCFMan::GetSprmStart( short nIdx, WW8PLCFManResult* pRes ) const
5242 memset( pRes, 0, sizeof( WW8PLCFManResult ) );
5244 // verifying !!!
5246 pRes->nMemLen = 0;
5248 const WW8PLCFxDesc* p = &m_aD[nIdx];
5250 // first Sprm in a Group
5251 if( p->bFirstSprm )
5253 if( p == m_pPap )
5254 pRes->nFlags |= MAN_MASK_NEW_PAP;
5255 else if( p == m_pSep )
5256 pRes->nFlags |= MAN_MASK_NEW_SEP;
5258 pRes->pMemPos = p->pMemPos;
5259 pRes->nSprmId = GetId(p);
5260 pRes->nCp2OrIdx = p->nCp2OrIdx;
5261 if ((p == m_pFootnote) || (p == m_pEdn) || (p == m_pAnd))
5262 pRes->nMemLen = p->nSprmsLen;
5263 else if (p->nSprmsLen >= maSprmParser.MinSprmLen()) //normal
5265 // Length of actual sprm
5266 pRes->nMemLen = maSprmParser.GetSprmSize(pRes->nSprmId, pRes->pMemPos, p->nSprmsLen);
5267 if (!IsSizeLegal(pRes->nMemLen, p->nSprmsLen) || !IsSprmLegalForCategory(pRes->nSprmId, nIdx))
5269 pRes->nSprmId = 0;
5274 void WW8PLCFMan::GetSprmEnd( short nIdx, WW8PLCFManResult* pRes ) const
5276 memset( pRes, 0, sizeof( WW8PLCFManResult ) );
5278 const WW8PLCFxDesc* p = &m_aD[nIdx];
5280 if (!(p->xIdStack->empty()))
5281 pRes->nSprmId = p->xIdStack->top(); // get end position
5282 else
5284 OSL_ENSURE( false, "No Id on the Stack" );
5285 pRes->nSprmId = 0;
5289 void WW8PLCFMan::GetNoSprmStart( short nIdx, WW8PLCFManResult* pRes ) const
5291 const WW8PLCFxDesc* p = &m_aD[nIdx];
5293 pRes->nCpPos = p->nStartPos;
5294 pRes->nMemLen = p->nSprmsLen;
5295 pRes->nCp2OrIdx = p->nCp2OrIdx;
5297 if( p == m_pField )
5298 pRes->nSprmId = eFLD;
5299 else if( p == m_pFootnote )
5300 pRes->nSprmId = eFTN;
5301 else if( p == m_pEdn )
5302 pRes->nSprmId = eEDN;
5303 else if( p == m_pBkm )
5304 pRes->nSprmId = eBKN;
5305 else if (p == m_pAtnBkm)
5306 pRes->nSprmId = eATNBKN;
5307 else if (p == m_pFactoidBkm)
5308 pRes->nSprmId = eFACTOIDBKN;
5309 else if( p == m_pAnd )
5310 pRes->nSprmId = eAND;
5311 else if( p == m_pPcd )
5313 //We slave the piece table attributes to the piece table, the piece
5314 //table attribute iterator contains the sprms for this piece.
5315 GetSprmStart( nIdx+1, pRes );
5317 else
5318 pRes->nSprmId = 0; // default: not found
5321 void WW8PLCFMan::GetNoSprmEnd( short nIdx, WW8PLCFManResult* pRes ) const
5323 pRes->nMemLen = -1; // end tag
5325 if( &m_aD[nIdx] == m_pBkm )
5326 pRes->nSprmId = eBKN;
5327 else if (&m_aD[nIdx] == m_pAtnBkm)
5328 pRes->nSprmId = eATNBKN;
5329 else if (&m_aD[nIdx] == m_pFactoidBkm)
5330 pRes->nSprmId = eFACTOIDBKN;
5331 else if( &m_aD[nIdx] == m_pPcd )
5333 //We slave the piece table attributes to the piece table, the piece
5334 //table attribute iterator contains the sprms for this piece.
5335 GetSprmEnd( nIdx+1, pRes );
5337 else
5338 pRes->nSprmId = 0;
5341 void WW8PLCFMan::TransferOpenSprms(std::stack<sal_uInt16> &rStack)
5343 for (sal_uInt16 i = 0; i < m_nPLCF; ++i)
5345 WW8PLCFxDesc* p = &m_aD[i];
5346 if (!p || !p->xIdStack)
5347 continue;
5348 while (!p->xIdStack->empty())
5350 rStack.push(p->xIdStack->top());
5351 p->xIdStack->pop();
5356 void WW8PLCFMan::AdvSprm(short nIdx, bool bStart)
5358 WW8PLCFxDesc* p = &m_aD[nIdx]; // determine sprm class(!)
5360 p->bFirstSprm = false;
5361 if( bStart )
5363 const sal_uInt16 nLastId = GetId(p);
5365 const sal_uInt16 nLastAttribStarted = IsSprmLegalForCategory(nLastId, nIdx) ? nLastId : 0;
5367 p->xIdStack->push(nLastAttribStarted); // remember Id for attribute end
5369 if( p->nSprmsLen )
5370 { /*
5371 Check, if we have to process more sprm(s).
5373 if( p->pMemPos )
5375 // Length of last sprm
5376 const sal_Int32 nSprmL = maSprmParser.GetSprmSize(nLastId, p->pMemPos, p->nSprmsLen);
5378 // Reduce length of all sprms by length of last sprm
5379 p->nSprmsLen -= nSprmL;
5381 // pos of next possible sprm
5382 if (p->nSprmsLen < maSprmParser.MinSprmLen())
5384 // preventively set to 0, because the end follows!
5385 p->pMemPos = nullptr;
5386 p->nSprmsLen = 0;
5388 else
5389 p->pMemPos += nSprmL;
5391 else
5392 p->nSprmsLen = 0;
5394 if (p->nSprmsLen < maSprmParser.MinSprmLen())
5395 p->nStartPos = WW8_CP_MAX; // the ending follows
5397 else
5399 if (!(p->xIdStack->empty()))
5400 p->xIdStack->pop();
5401 if (p->xIdStack->empty())
5403 if ( (p == m_pChp) || (p == m_pPap) )
5405 p->pMemPos = nullptr;
5406 p->nSprmsLen = 0;
5407 p->nStartPos = p->nOrigEndPos+p->nCpOfs;
5410 On failed seek we have run out of sprms, probably. But if it's
5411 a fastsaved file (has pPcd) then we may be just in a sprm free
5412 gap between pieces that have them, so set dirty flag in sprm
5413 finder to consider than.
5415 if (!(*p->pPLCFx).SeekPos(p->nStartPos))
5417 p->nEndPos = WW8_CP_MAX;
5418 p->pPLCFx->SetDirty(true);
5420 if (!p->pPLCFx->GetDirty() || m_pPcd)
5421 GetNewSprms( *p );
5422 p->pPLCFx->SetDirty(false);
5425 #i2325#
5426 To get the character and paragraph properties you first get
5427 the pap and chp and then apply the fastsaved pPcd properties
5428 to the range. If a pap or chp starts inside the pPcd range
5429 then we must bring the current pPcd range to a halt so as to
5430 end those sprms, then the pap/chp will be processed, and then
5431 we must force a restart of the pPcd on that pap/chp starting
5432 boundary. Doing that effectively means that the pPcd sprms will
5433 be applied to the new range. Not doing it means that the pPcd
5434 sprms will only be applied to the first pap/chp set of
5435 properties contained in the pap/chp range.
5437 So we bring the pPcd to a halt on this location here, by
5438 settings its end to the current start, then store the starting
5439 position of the current range to clipstart. The pPcd sprms
5440 will end as normal (albeit earlier than originally expected),
5441 and the existence of a clipstart will force the pPcd iterator
5442 to reread the current set of sprms instead of advancing to its
5443 next set. Then the clipstart will be set as the starting
5444 position which will force them to be applied directly after
5445 the pap and chps.
5447 if (m_pPcd && ((p->nStartPos > m_pPcd->nStartPos) ||
5448 (m_pPcd->nStartPos == WW8_CP_MAX)) &&
5449 (m_pPcd->nEndPos != p->nStartPos))
5451 m_pPcd->nEndPos = p->nStartPos;
5452 static_cast<WW8PLCFx_PCD *>(m_pPcd->pPLCFx)->SetClipStart(
5453 p->nStartPos);
5457 else
5459 p->pPLCFx->advance(); // next Group of Sprms
5460 p->pMemPos = nullptr; // !!!
5461 p->nSprmsLen = 0;
5462 GetNewSprms( *p );
5464 SAL_WARN_IF(p->nStartPos > p->nEndPos, "sw.ww8",
5465 "End " << p->nEndPos << " before Start " << p->nStartPos);
5470 void WW8PLCFMan::AdvNoSprm(short nIdx, bool bStart)
5473 For the case of a piece table we slave the piece table attribute iterator
5474 to the piece table and access it through that only. They are two separate
5475 structures, but act together as one logical one. The attributes only go
5476 to the next entry when the piece changes
5478 WW8PLCFxDesc* p = &m_aD[nIdx];
5480 if( p == m_pPcd )
5482 AdvSprm(nIdx+1,bStart);
5483 if( bStart )
5484 p->nStartPos = m_aD[nIdx+1].nStartPos;
5485 else
5487 if (m_aD[nIdx+1].xIdStack->empty())
5489 WW8PLCFx_PCD *pTemp = static_cast<WW8PLCFx_PCD*>(m_pPcd->pPLCFx);
5491 #i2325#
5492 As per normal, go on to the next set of properties, i.e. we
5493 have traversed over to the next piece. With a clipstart set
5494 we are being told to reread the current piece sprms so as to
5495 reapply them to a new chp or pap range.
5497 if (pTemp->GetClipStart() == -1)
5498 p->pPLCFx->advance();
5499 p->pMemPos = nullptr;
5500 p->nSprmsLen = 0;
5501 GetNewSprms( m_aD[nIdx+1] );
5502 GetNewNoSprms( *p );
5503 if (pTemp->GetClipStart() != -1)
5506 #i2325#, now we will force our starting position to the
5507 clipping start so as to force the application of these
5508 sprms after the current pap/chp sprms so as to apply the
5509 fastsave sprms to the current range.
5511 p->nStartPos = pTemp->GetClipStart();
5512 pTemp->SetClipStart(-1);
5517 else
5518 { // NoSprm without end
5519 p->pPLCFx->advance();
5520 p->pMemPos = nullptr; // MemPos invalid
5521 p->nSprmsLen = 0;
5522 GetNewNoSprms( *p );
5526 void WW8PLCFMan::advance()
5528 bool bStart;
5529 const sal_uInt16 nIdx = WhereIdx(&bStart);
5530 if (nIdx < m_nPLCF)
5532 WW8PLCFxDesc* p = &m_aD[nIdx];
5534 p->bFirstSprm = true; // Default
5536 if( p->pPLCFx->IsSprm() )
5537 AdvSprm( nIdx, bStart );
5538 else // NoSprm
5539 AdvNoSprm( nIdx, bStart );
5543 // return true for the beginning of an attribute or error,
5544 // false for the end of an attribute
5545 // remaining return values are delivered to the caller from WW8PclxManResults.
5546 bool WW8PLCFMan::Get(WW8PLCFManResult* pRes) const
5548 memset( pRes, 0, sizeof( WW8PLCFManResult ) );
5549 bool bStart;
5550 const sal_uInt16 nIdx = WhereIdx(&bStart);
5552 if( nIdx >= m_nPLCF )
5554 OSL_ENSURE( false, "Position not found" );
5555 return true;
5558 if( m_aD[nIdx].pPLCFx->IsSprm() )
5560 if( bStart )
5562 GetSprmStart( nIdx, pRes );
5563 return true;
5565 else
5567 GetSprmEnd( nIdx, pRes );
5568 return false;
5571 else
5573 if( bStart )
5575 GetNoSprmStart( nIdx, pRes );
5576 return true;
5578 else
5580 GetNoSprmEnd( nIdx, pRes );
5581 return false;
5586 sal_uInt16 WW8PLCFMan::GetColl() const
5588 if( m_pPap->pPLCFx )
5589 return m_pPap->pPLCFx->GetIstd();
5590 else
5592 OSL_ENSURE( false, "GetColl without PLCF_Pap" );
5593 return 0;
5597 WW8PLCFx_FLD* WW8PLCFMan::GetField() const
5599 return static_cast<WW8PLCFx_FLD*>(m_pField->pPLCFx);
5602 SprmResult WW8PLCFMan::HasParaSprm( sal_uInt16 nId ) const
5604 return static_cast<WW8PLCFx_Cp_FKP*>(m_pPap->pPLCFx)->HasSprm( nId );
5607 SprmResult WW8PLCFMan::HasCharSprm( sal_uInt16 nId ) const
5609 return static_cast<WW8PLCFx_Cp_FKP*>(m_pChp->pPLCFx)->HasSprm( nId );
5612 void WW8PLCFMan::HasCharSprm(sal_uInt16 nId,
5613 std::vector<SprmResult> &rResult) const
5615 static_cast<WW8PLCFx_Cp_FKP*>(m_pChp->pPLCFx)->HasSprm(nId, rResult);
5618 void WW8PLCFx::Save( WW8PLCFxSave1& rSave ) const
5620 rSave.nPLCFxPos = GetIdx();
5621 rSave.nPLCFxPos2 = GetIdx2();
5622 rSave.nPLCFxMemOfs = 0;
5623 rSave.nStartFC = GetStartFc();
5626 void WW8PLCFx::Restore( const WW8PLCFxSave1& rSave )
5628 SetIdx( rSave.nPLCFxPos );
5629 SetIdx2( rSave.nPLCFxPos2 );
5630 SetStartFc( rSave.nStartFC );
5633 sal_uInt32 WW8PLCFx_Cp_FKP::GetIdx2() const
5635 return GetPCDIdx();
5638 void WW8PLCFx_Cp_FKP::SetIdx2(sal_uInt32 nIdx)
5640 if( m_pPcd )
5641 m_pPcd->SetIdx( nIdx );
5644 void WW8PLCFx_Cp_FKP::Save( WW8PLCFxSave1& rSave ) const
5646 if (m_pFkp)
5647 m_pFkp->IncMustRemainCache();
5648 WW8PLCFx::Save( rSave );
5650 rSave.nAttrStart = m_nAttrStart;
5651 rSave.nAttrEnd = m_nAttrEnd;
5652 rSave.bLineEnd = m_bLineEnd;
5655 void WW8PLCFx_Cp_FKP::Restore( const WW8PLCFxSave1& rSave )
5657 WW8PLCFx::Restore( rSave );
5659 m_nAttrStart = rSave.nAttrStart;
5660 m_nAttrEnd = rSave.nAttrEnd;
5661 m_bLineEnd = rSave.bLineEnd;
5663 if (m_pFkp)
5664 m_pFkp->DecMustRemainCache();
5667 void WW8PLCFxDesc::Save( WW8PLCFxSave1& rSave ) const
5669 if( !pPLCFx )
5670 return;
5672 pPLCFx->Save( rSave );
5673 if( !pPLCFx->IsSprm() )
5674 return;
5676 WW8PLCFxDesc aD;
5677 aD.nStartPos = nOrigStartPos+nCpOfs;
5678 aD.nCpOfs = rSave.nCpOfs = nCpOfs;
5679 if (!(pPLCFx->SeekPos(aD.nStartPos)))
5681 aD.nEndPos = WW8_CP_MAX;
5682 pPLCFx->SetDirty(true);
5684 pPLCFx->GetSprms(&aD);
5685 pPLCFx->SetDirty(false);
5686 aD.ReduceByOffset();
5687 rSave.nStartCp = aD.nStartPos;
5688 rSave.nPLCFxMemOfs = nOrigSprmsLen - nSprmsLen;
5691 void WW8PLCFxDesc::Restore( const WW8PLCFxSave1& rSave )
5693 if( !pPLCFx )
5694 return;
5696 pPLCFx->Restore( rSave );
5697 if( !pPLCFx->IsSprm() )
5698 return;
5700 WW8PLCFxDesc aD;
5701 aD.nStartPos = rSave.nStartCp+rSave.nCpOfs;
5702 nCpOfs = aD.nCpOfs = rSave.nCpOfs;
5703 if (!(pPLCFx->SeekPos(aD.nStartPos)))
5705 aD.nEndPos = WW8_CP_MAX;
5706 pPLCFx->SetDirty(true);
5708 pPLCFx->GetSprms(&aD);
5709 pPLCFx->SetDirty(false);
5710 aD.ReduceByOffset();
5712 if (nOrigSprmsLen > aD.nSprmsLen)
5714 //two entries exist for the same offset, cut and run
5715 SAL_WARN("sw.ww8", "restored properties don't match saved properties, bailing out");
5716 nSprmsLen = 0;
5717 pMemPos = nullptr;
5719 else
5721 nSprmsLen = nOrigSprmsLen - rSave.nPLCFxMemOfs;
5722 pMemPos = aD.pMemPos == nullptr ? nullptr : aD.pMemPos + rSave.nPLCFxMemOfs;
5726 namespace
5728 sal_uInt32 Readcb(SvStream& rSt, ww::WordVersion eVer)
5730 if (eVer <= ww::eWW2)
5732 sal_uInt16 nShort(0);
5733 rSt.ReadUInt16(nShort);
5734 return nShort;
5736 else
5738 sal_uInt32 nLong(0);
5739 rSt.ReadUInt32(nLong);
5740 return nLong;
5745 bool WW8Fib::GetBaseCp(ManTypes nType, WW8_CP * cp) const
5747 assert(cp != nullptr);
5748 WW8_CP nOffset = 0;
5750 switch (nType)
5752 case MAN_TXBX_HDFT:
5753 if (m_ccpTxbx < 0) {
5754 return false;
5756 nOffset = m_ccpTxbx;
5757 [[fallthrough]];
5758 case MAN_TXBX:
5759 if (m_ccpEdn < 0 || m_ccpEdn > std::numeric_limits<WW8_CP>::max() - nOffset) {
5760 return false;
5762 nOffset += m_ccpEdn;
5763 [[fallthrough]];
5764 case MAN_EDN:
5765 if (m_ccpAtn < 0 || m_ccpAtn > std::numeric_limits<WW8_CP>::max() - nOffset) {
5766 return false;
5768 nOffset += m_ccpAtn;
5769 [[fallthrough]];
5770 case MAN_AND:
5771 if (m_ccpMcr < 0 || m_ccpMcr > std::numeric_limits<WW8_CP>::max() - nOffset) {
5772 return false;
5774 nOffset += m_ccpMcr;
5776 // fall through
5778 A subdocument of this kind (MAN_MACRO) probably exists in some defunct
5779 version of MSWord, but now ccpMcr is always 0. If some example that
5780 uses this comes to light, this is the likely calculation required
5782 case MAN_MACRO:
5784 if (m_ccpHdr < 0 || m_ccpHdr > std::numeric_limits<WW8_CP>::max() - nOffset) {
5785 return false;
5787 nOffset += m_ccpHdr;
5788 [[fallthrough]];
5789 case MAN_HDFT:
5790 if (m_ccpFootnote < 0 || m_ccpFootnote > std::numeric_limits<WW8_CP>::max() - nOffset) {
5791 return false;
5793 nOffset += m_ccpFootnote;
5794 [[fallthrough]];
5795 case MAN_FTN:
5796 if (m_ccpText < 0 || m_ccpText > std::numeric_limits<WW8_CP>::max() - nOffset) {
5797 return false;
5799 nOffset += m_ccpText;
5800 [[fallthrough]];
5801 case MAN_MAINTEXT:
5802 break;
5804 *cp = nOffset;
5805 return true;
5808 ww::WordVersion WW8Fib::GetFIBVersion() const
5810 ww::WordVersion eVer = ww::eWW8;
5812 * Word for Windows 2 I think (1.X might work too if anyone has an example.
5814 * 0xA59B for Word 1 for Windows
5815 * 0xA59C for Word 1 for OS/2 "PM Word"
5817 * Various pages claim that the fileformats of Word 1 and 2 for Windows are
5818 * equivalent to Word for Macintosh 4 and 5. On the other hand
5820 * wIdents for Word for Mac versions...
5821 * 0xFE32 for Word 1
5822 * 0xFE34 for Word 3
5823 * 0xFE37 for Word 4 et 5.
5825 * and this document
5826 * http://cmsdoc.cern.ch/documents/docformat/CMS_CERN_LetterHead.word is
5827 * claimed to be "Word 5 for Mac" by Office etc and has that wIdent, but
5828 * its format isn't the same as that of Word 2 for windows. Nor is it
5829 * the same as that of Word for DOS/PCWord 5
5831 if (m_wIdent == 0xa59b || m_wIdent == 0xa59c)
5832 eVer = ww::eWW1;
5833 else if (m_wIdent == 0xa5db)
5834 eVer = ww::eWW2;
5835 else
5837 switch (m_nVersion)
5839 case 6:
5840 eVer = ww::eWW6;
5841 break;
5842 case 7:
5843 eVer = ww::eWW7;
5844 break;
5845 case 8:
5846 eVer = ww::eWW8;
5847 break;
5850 return eVer;
5853 WW8Fib::WW8Fib(SvStream& rSt, sal_uInt8 nWantedVersion, sal_uInt32 nOffset):
5854 m_fDot(false), m_fGlsy(false), m_fComplex(false), m_fHasPic(false), m_cQuickSaves(0),
5855 m_fEncrypted(false), m_fWhichTableStm(false), m_fReadOnlyRecommended(false),
5856 m_fWriteReservation(false), m_fExtChar(false), m_fFarEast(false), m_fObfuscated(false),
5857 m_fMac(false), m_fEmptySpecial(false), m_fLoadOverridePage(false), m_fFuturesavedUndo(false),
5858 m_fWord97Saved(false), m_fWord2000Saved(false)
5859 // in C++20 with P06831R1 "Default member initializers for bit-fields (revision 1)", the
5860 // above bit-field member initializations can be moved to the class definition
5862 // See [MS-DOC] 2.5.15 "How to read the FIB".
5863 rSt.Seek( nOffset );
5865 note desired number, identify file version number
5866 and check against desired number!
5868 m_nVersion = nWantedVersion;
5869 rSt.ReadUInt16( m_wIdent );
5870 rSt.ReadUInt16( m_nFib );
5871 rSt.ReadUInt16( m_nProduct );
5872 if( ERRCODE_NONE != rSt.GetError() )
5874 sal_Int16 nFibMin;
5875 sal_Int16 nFibMax;
5876 // note: 6 stands for "6 OR 7", 7 stands for "ONLY 7"
5877 switch( m_nVersion )
5879 case 6:
5880 nFibMin = 0x0065; // from 101 WinWord 6.0
5881 // 102 "
5882 // and 103 WinWord 6.0 for Macintosh
5883 // 104 "
5884 nFibMax = 0x0069; // to 105 WinWord 95
5885 break;
5886 case 7:
5887 nFibMin = 0x0069; // from 105 WinWord 95
5888 nFibMax = 0x0069; // to 105 WinWord 95
5889 break;
5890 case 8:
5891 nFibMin = 0x006A; // from 106 WinWord 97
5892 nFibMax = 0x00c1; // to 193 WinWord 97 (?)
5893 break;
5894 default:
5895 nFibMin = 0; // program error!
5896 nFibMax = 0;
5897 m_nFib = 1;
5898 OSL_ENSURE( false, "nVersion not implemented!" );
5899 break;
5901 if ( (m_nFib < nFibMin) || (m_nFib > nFibMax) )
5903 m_nFibError = ERR_SWG_READ_ERROR; // report error
5904 return;
5908 ww::WordVersion eVer = GetFIBVersion();
5910 // helper vars for Ver67:
5911 sal_Int16 pnChpFirst_Ver67=0;
5912 sal_Int16 pnPapFirst_Ver67=0;
5913 sal_Int16 cpnBteChp_Ver67=0;
5914 sal_Int16 cpnBtePap_Ver67=0;
5916 // read FIB
5917 sal_uInt16 nTmpLid = 0;
5918 rSt.ReadUInt16(nTmpLid);
5919 m_lid = LanguageType(nTmpLid);
5920 rSt.ReadInt16( m_pnNext );
5921 sal_uInt8 aBits1(0);
5922 rSt.ReadUChar( aBits1 );
5923 sal_uInt8 aBits2(0);
5924 rSt.ReadUChar( aBits2 );
5925 rSt.ReadUInt16( m_nFibBack );
5926 rSt.ReadUInt16( m_nHash );
5927 rSt.ReadUInt16( m_nKey );
5928 rSt.ReadUChar( m_envr );
5929 sal_uInt8 aVer8Bits1(0); // only used starting with WinWord 8
5930 rSt.ReadUChar( aVer8Bits1 ); // only have an empty reserve field under Ver67
5931 // content from aVer8Bits1
5933 // sal_uInt8 fMac :1;
5934 // sal_uInt8 fEmptySpecial :1;
5935 // sal_uInt8 fLoadOverridePage :1;
5936 // sal_uInt8 fFuturesavedUndo :1;
5937 // sal_uInt8 fWord97Saved :1;
5938 // sal_uInt8 :3;
5939 rSt.ReadUInt16( m_chse );
5940 rSt.ReadUInt16( m_chseTables );
5941 rSt.ReadInt32( m_fcMin );
5942 rSt.ReadInt32( m_fcMac );
5944 // insertion for WW8
5945 if (IsEightPlus(eVer))
5947 rSt.ReadUInt16( m_csw );
5949 // Marke: "rgsw" Beginning of the array of shorts
5950 rSt.ReadUInt16( m_wMagicCreated );
5951 rSt.ReadUInt16( m_wMagicRevised );
5952 rSt.ReadUInt16( m_wMagicCreatedPrivate );
5953 rSt.ReadUInt16( m_wMagicRevisedPrivate );
5954 rSt.SeekRel( 9 * sizeof( sal_Int16 ) );
5957 // these are the 9 unused fields:
5958 && (bVer67 || WW8ReadINT16( rSt, pnFbpChpFirst_W6 )) // 1
5959 && (bVer67 || WW8ReadINT16( rSt, pnChpFirst_W6 )) // 2
5960 && (bVer67 || WW8ReadINT16( rSt, cpnBteChp_W6 )) // 3
5961 && (bVer67 || WW8ReadINT16( rSt, pnFbpPapFirst_W6 )) // 4
5962 && (bVer67 || WW8ReadINT16( rSt, pnPapFirst_W6 )) // 5
5963 && (bVer67 || WW8ReadINT16( rSt, cpnBtePap_W6 )) // 6
5964 && (bVer67 || WW8ReadINT16( rSt, pnFbpLvcFirst_W6 )) // 7
5965 && (bVer67 || WW8ReadINT16( rSt, pnLvcFirst_W6 )) // 8
5966 && (bVer67 || WW8ReadINT16( rSt, cpnBteLvc_W6 )) // 9
5968 sal_uInt16 nTmpFE = 0;
5969 rSt.ReadUInt16(nTmpFE);
5970 m_lidFE = LanguageType(nTmpFE);
5971 rSt.ReadUInt16( m_clw );
5974 // end of the insertion for WW8
5976 // Marke: "rglw" Beginning of the array of longs
5977 rSt.ReadInt32( m_cbMac );
5979 // ignore 2 longs, because they are unimportant
5980 rSt.SeekRel( 2 * sizeof( sal_Int32) );
5982 // skipping 2 more longs only at Ver67
5983 if (IsSevenMinus(eVer))
5984 rSt.SeekRel( 2 * sizeof( sal_Int32) );
5986 rSt.ReadInt32( m_ccpText );
5987 rSt.ReadInt32( m_ccpFootnote );
5988 rSt.ReadInt32( m_ccpHdr );
5989 rSt.ReadInt32( m_ccpMcr );
5990 rSt.ReadInt32( m_ccpAtn );
5991 rSt.ReadInt32( m_ccpEdn );
5992 rSt.ReadInt32( m_ccpTxbx );
5993 rSt.ReadInt32( m_ccpHdrTxbx );
5995 // only skip one more long at Ver67
5996 if (IsSevenMinus(eVer))
5997 rSt.SeekRel( 1 * sizeof( sal_Int32) );
5998 else
6000 // insertion for WW8
6001 rSt.ReadInt32( m_pnFbpChpFirst );
6002 rSt.ReadInt32( m_pnChpFirst );
6003 rSt.ReadInt32( m_cpnBteChp );
6004 rSt.ReadInt32( m_pnFbpPapFirst );
6005 rSt.ReadInt32( m_pnPapFirst );
6006 rSt.ReadInt32( m_cpnBtePap );
6007 rSt.ReadInt32( m_pnFbpLvcFirst );
6008 rSt.ReadInt32( m_pnLvcFirst );
6009 rSt.ReadInt32( m_cpnBteLvc );
6010 rSt.ReadInt32( m_fcIslandFirst );
6011 rSt.ReadInt32( m_fcIslandLim );
6012 rSt.ReadUInt16( m_cfclcb );
6014 // Read cswNew to find out if nFib should be ignored.
6015 sal_uInt32 nPos = rSt.Tell();
6016 rSt.SeekRel(m_cfclcb * 8);
6017 if (rSt.good() && rSt.remainingSize() >= 2)
6019 rSt.ReadUInt16(m_cswNew);
6021 rSt.Seek(nPos);
6024 // end of the insertion for WW8
6026 // Marke: "rgfclcb" Beginning of array of FC/LCB pairs.
6027 rSt.ReadInt32( m_fcStshfOrig );
6028 m_lcbStshfOrig = Readcb(rSt, eVer);
6029 rSt.ReadInt32( m_fcStshf );
6030 m_lcbStshf = Readcb(rSt, eVer);
6031 rSt.ReadInt32( m_fcPlcffndRef );
6032 m_lcbPlcffndRef = Readcb(rSt, eVer);
6033 rSt.ReadInt32( m_fcPlcffndText );
6034 m_lcbPlcffndText = Readcb(rSt, eVer);
6035 rSt.ReadInt32( m_fcPlcfandRef );
6036 m_lcbPlcfandRef = Readcb(rSt, eVer);
6037 rSt.ReadInt32( m_fcPlcfandText );
6038 m_lcbPlcfandText = Readcb(rSt, eVer);
6039 rSt.ReadInt32( m_fcPlcfsed );
6040 m_lcbPlcfsed = Readcb(rSt, eVer);
6041 rSt.ReadInt32( m_fcPlcfpad );
6042 m_lcbPlcfpad = Readcb(rSt, eVer);
6043 rSt.ReadInt32( m_fcPlcfphe );
6044 m_lcbPlcfphe = Readcb(rSt, eVer);
6045 rSt.ReadInt32( m_fcSttbfglsy );
6046 m_lcbSttbfglsy = Readcb(rSt, eVer);
6047 rSt.ReadInt32( m_fcPlcfglsy );
6048 m_lcbPlcfglsy = Readcb(rSt, eVer);
6049 rSt.ReadInt32( m_fcPlcfhdd );
6050 m_lcbPlcfhdd = Readcb(rSt, eVer);
6051 rSt.ReadInt32( m_fcPlcfbteChpx );
6052 m_lcbPlcfbteChpx = Readcb(rSt, eVer);
6053 rSt.ReadInt32( m_fcPlcfbtePapx );
6054 m_lcbPlcfbtePapx = Readcb(rSt, eVer);
6055 rSt.ReadInt32( m_fcPlcfsea );
6056 m_lcbPlcfsea = Readcb(rSt, eVer);
6057 rSt.ReadInt32( m_fcSttbfffn );
6058 m_lcbSttbfffn = Readcb(rSt, eVer);
6059 rSt.ReadInt32( m_fcPlcffldMom );
6060 m_lcbPlcffldMom = Readcb(rSt, eVer);
6061 rSt.ReadInt32( m_fcPlcffldHdr );
6062 m_lcbPlcffldHdr = Readcb(rSt, eVer);
6063 rSt.ReadInt32( m_fcPlcffldFootnote );
6064 m_lcbPlcffldFootnote = Readcb(rSt, eVer);
6065 rSt.ReadInt32( m_fcPlcffldAtn );
6066 m_lcbPlcffldAtn = Readcb(rSt, eVer);
6067 rSt.ReadInt32( m_fcPlcffldMcr );
6068 m_lcbPlcffldMcr = Readcb(rSt, eVer);
6069 rSt.ReadInt32( m_fcSttbfbkmk );
6070 m_lcbSttbfbkmk = Readcb(rSt, eVer);
6071 rSt.ReadInt32( m_fcPlcfbkf );
6072 m_lcbPlcfbkf = Readcb(rSt, eVer);
6073 rSt.ReadInt32( m_fcPlcfbkl );
6074 m_lcbPlcfbkl = Readcb(rSt, eVer);
6075 rSt.ReadInt32( m_fcCmds );
6076 m_lcbCmds = Readcb(rSt, eVer);
6077 rSt.ReadInt32( m_fcPlcfmcr );
6078 m_lcbPlcfmcr = Readcb(rSt, eVer);
6079 rSt.ReadInt32( m_fcSttbfmcr );
6080 m_lcbSttbfmcr = Readcb(rSt, eVer);
6081 if (eVer >= ww::eWW2)
6083 rSt.ReadInt32( m_fcPrDrvr );
6084 m_lcbPrDrvr = Readcb(rSt, eVer);
6085 rSt.ReadInt32( m_fcPrEnvPort );
6086 m_lcbPrEnvPort = Readcb(rSt, eVer);
6087 rSt.ReadInt32( m_fcPrEnvLand );
6088 m_lcbPrEnvLand = Readcb(rSt, eVer);
6090 else
6092 rSt.ReadInt32( m_fcPrEnvPort );
6093 m_lcbPrEnvPort = Readcb(rSt, eVer);
6095 rSt.ReadInt32( m_fcWss );
6096 m_lcbWss = Readcb(rSt, eVer);
6097 rSt.ReadInt32( m_fcDop );
6098 m_lcbDop = Readcb(rSt, eVer);
6099 rSt.ReadInt32( m_fcSttbfAssoc );
6100 m_lcbSttbfAssoc = Readcb(rSt, eVer);
6101 rSt.ReadInt32( m_fcClx );
6102 m_lcbClx = Readcb(rSt, eVer);
6103 rSt.ReadInt32( m_fcPlcfpgdFootnote );
6104 m_lcbPlcfpgdFootnote = Readcb(rSt, eVer);
6105 rSt.ReadInt32( m_fcAutosaveSource );
6106 m_lcbAutosaveSource = Readcb(rSt, eVer);
6107 rSt.ReadInt32( m_fcGrpStAtnOwners );
6108 m_lcbGrpStAtnOwners = Readcb(rSt, eVer);
6109 rSt.ReadInt32( m_fcSttbfAtnbkmk );
6110 m_lcbSttbfAtnbkmk = Readcb(rSt, eVer);
6112 // only skip more shot at Ver67
6113 if (IsSevenMinus(eVer))
6115 if (eVer == ww::eWW1)
6116 rSt.SeekRel(1*sizeof(sal_Int32));
6117 rSt.SeekRel(1*sizeof(sal_Int16));
6119 if (eVer >= ww::eWW2)
6121 rSt.ReadInt16(pnChpFirst_Ver67);
6122 rSt.ReadInt16(pnPapFirst_Ver67);
6124 rSt.ReadInt16(cpnBteChp_Ver67);
6125 rSt.ReadInt16(cpnBtePap_Ver67);
6128 if (eVer > ww::eWW2)
6130 rSt.ReadInt32( m_fcPlcfdoaMom );
6131 rSt.ReadInt32( m_lcbPlcfdoaMom );
6132 rSt.ReadInt32( m_fcPlcfdoaHdr );
6133 rSt.ReadInt32( m_lcbPlcfdoaHdr );
6134 rSt.ReadInt32( m_fcPlcfspaMom );
6135 rSt.ReadInt32( m_lcbPlcfspaMom );
6136 rSt.ReadInt32( m_fcPlcfspaHdr );
6137 rSt.ReadInt32( m_lcbPlcfspaHdr );
6139 rSt.ReadInt32( m_fcPlcfAtnbkf );
6140 rSt.ReadInt32( m_lcbPlcfAtnbkf );
6141 rSt.ReadInt32( m_fcPlcfAtnbkl );
6142 rSt.ReadInt32( m_lcbPlcfAtnbkl );
6143 rSt.ReadInt32( m_fcPms );
6144 rSt.ReadInt32( m_lcbPMS );
6145 rSt.ReadInt32( m_fcFormFieldSttbf );
6146 rSt.ReadInt32( m_lcbFormFieldSttbf );
6147 rSt.ReadInt32( m_fcPlcfendRef );
6148 rSt.ReadInt32( m_lcbPlcfendRef );
6149 rSt.ReadInt32( m_fcPlcfendText );
6150 rSt.ReadInt32( m_lcbPlcfendText );
6151 rSt.ReadInt32( m_fcPlcffldEdn );
6152 rSt.ReadInt32( m_lcbPlcffldEdn );
6153 rSt.ReadInt32( m_fcPlcfpgdEdn );
6154 rSt.ReadInt32( m_lcbPlcfpgdEdn );
6155 rSt.ReadInt32( m_fcDggInfo );
6156 rSt.ReadInt32( m_lcbDggInfo );
6157 rSt.ReadInt32( m_fcSttbfRMark );
6158 rSt.ReadInt32( m_lcbSttbfRMark );
6159 rSt.ReadInt32( m_fcSttbfCaption );
6160 rSt.ReadInt32( m_lcbSttbfCaption );
6161 rSt.ReadInt32( m_fcSttbAutoCaption );
6162 rSt.ReadInt32( m_lcbSttbAutoCaption );
6163 rSt.ReadInt32( m_fcPlcfwkb );
6164 rSt.ReadInt32( m_lcbPlcfwkb );
6165 rSt.ReadInt32( m_fcPlcfspl );
6166 rSt.ReadInt32( m_lcbPlcfspl );
6167 rSt.ReadInt32( m_fcPlcftxbxText );
6168 rSt.ReadInt32( m_lcbPlcftxbxText );
6169 rSt.ReadInt32( m_fcPlcffldTxbx );
6170 rSt.ReadInt32( m_lcbPlcffldTxbx );
6171 rSt.ReadInt32( m_fcPlcfHdrtxbxText );
6172 rSt.ReadInt32( m_lcbPlcfHdrtxbxText );
6173 rSt.ReadInt32( m_fcPlcffldHdrTxbx );
6174 rSt.ReadInt32( m_lcbPlcffldHdrTxbx );
6175 rSt.ReadInt32( m_fcStwUser );
6176 rSt.ReadUInt32( m_lcbStwUser );
6177 rSt.ReadInt32( m_fcSttbttmbd );
6178 rSt.ReadUInt32( m_lcbSttbttmbd );
6181 if( ERRCODE_NONE == rSt.GetError() )
6183 // set bit flag
6184 m_fDot = aBits1 & 0x01 ;
6185 m_fGlsy = ( aBits1 & 0x02 ) >> 1;
6186 m_fComplex = ( aBits1 & 0x04 ) >> 2;
6187 m_fHasPic = ( aBits1 & 0x08 ) >> 3;
6188 m_cQuickSaves = ( aBits1 & 0xf0 ) >> 4;
6189 m_fEncrypted = aBits2 & 0x01 ;
6190 m_fWhichTableStm= ( aBits2 & 0x02 ) >> 1;
6191 m_fReadOnlyRecommended = (aBits2 & 0x4) >> 2;
6192 m_fWriteReservation = (aBits2 & 0x8) >> 3;
6193 m_fExtChar = ( aBits2 & 0x10 ) >> 4;
6194 // dummy = ( aBits2 & 0x20 ) >> 5;
6195 m_fFarEast = ( aBits2 & 0x40 ) >> 6; // #i90932#
6196 // dummy = ( aBits2 & 0x80 ) >> 7;
6199 p.r.n. fill targeted variable with xxx_Ver67
6200 or set flags
6202 if (IsSevenMinus(eVer))
6204 m_pnChpFirst = pnChpFirst_Ver67;
6205 m_pnPapFirst = pnPapFirst_Ver67;
6206 m_cpnBteChp = cpnBteChp_Ver67;
6207 m_cpnBtePap = cpnBtePap_Ver67;
6209 else if (IsEightPlus(eVer))
6211 m_fMac = aVer8Bits1 & 0x01 ;
6212 m_fEmptySpecial = ( aVer8Bits1 & 0x02 ) >> 1;
6213 m_fLoadOverridePage = ( aVer8Bits1 & 0x04 ) >> 2;
6214 m_fFuturesavedUndo = ( aVer8Bits1 & 0x08 ) >> 3;
6215 m_fWord97Saved = ( aVer8Bits1 & 0x10 ) >> 4;
6216 m_fWord2000Saved = ( aVer8Bits1 & 0x20 ) >> 5;
6219 especially for WW8:
6220 identify the values for PLCF and PLF LFO
6221 and PLCF for the textbox break descriptors
6223 sal_uInt64 nOldPos = rSt.Tell();
6225 rSt.Seek( 0x02da );
6226 rSt.ReadInt32( m_fcSttbFnm );
6227 rSt.ReadInt32( m_lcbSttbFnm );
6228 rSt.ReadInt32( m_fcPlcfLst );
6229 rSt.ReadInt32( m_lcbPlcfLst );
6230 rSt.ReadInt32( m_fcPlfLfo );
6231 rSt.ReadInt32( m_lcbPlfLfo );
6232 rSt.ReadInt32( m_fcPlcftxbxBkd );
6233 rSt.ReadInt32( m_lcbPlcftxbxBkd );
6234 rSt.ReadInt32( m_fcPlcfHdrtxbxBkd );
6235 rSt.ReadInt32( m_lcbPlcfHdrtxbxBkd );
6236 if( ERRCODE_NONE != rSt.GetError() )
6238 m_nFibError = ERR_SWG_READ_ERROR;
6241 rSt.Seek( 0x372 ); // fcSttbListNames
6242 rSt.ReadInt32( m_fcSttbListNames );
6243 rSt.ReadInt32( m_lcbSttbListNames );
6245 if (m_cfclcb > 93)
6247 rSt.Seek( 0x382 ); // MagicTables
6248 rSt.ReadInt32( m_fcPlcfTch );
6249 rSt.ReadInt32( m_lcbPlcfTch );
6252 if (m_cfclcb > 113)
6254 rSt.Seek( 0x41A ); // new ATRD
6255 rSt.ReadInt32( m_fcAtrdExtra );
6256 rSt.ReadUInt32( m_lcbAtrdExtra );
6259 // Factoid bookmarks
6260 if (m_cfclcb > 134)
6262 rSt.Seek(0x432);
6263 rSt.ReadInt32(m_fcPlcfBkfFactoid);
6264 rSt.ReadUInt32(m_lcbPlcfBkfFactoid);
6266 rSt.Seek(0x442);
6267 rSt.ReadInt32(m_fcPlcfBklFactoid);
6268 rSt.ReadUInt32(m_lcbPlcfBklFactoid);
6270 rSt.Seek(0x44a);
6271 rSt.ReadInt32(m_fcFactoidData);
6272 rSt.ReadUInt32(m_lcbFactoidData);
6275 if( ERRCODE_NONE != rSt.GetError() )
6276 m_nFibError = ERR_SWG_READ_ERROR;
6278 rSt.Seek( 0x5bc ); // Actual nFib introduced in Word 2003
6279 rSt.ReadUInt16( m_nFib_actual );
6281 rSt.Seek( nOldPos );
6284 else
6286 m_nFibError = ERR_SWG_READ_ERROR; // report error
6290 WW8Fib::WW8Fib(sal_uInt8 nVer, bool bDot):
6291 m_nVersion(nVer), m_fDot(false), m_fGlsy(false), m_fComplex(false), m_fHasPic(false), m_cQuickSaves(0),
6292 m_fEncrypted(false), m_fWhichTableStm(false), m_fReadOnlyRecommended(false),
6293 m_fWriteReservation(false), m_fExtChar(false), m_fFarEast(false), m_fObfuscated(false),
6294 m_fMac(false), m_fEmptySpecial(false), m_fLoadOverridePage(false), m_fFuturesavedUndo(false),
6295 m_fWord97Saved(false), m_fWord2000Saved(false)
6296 // in C++20 with P06831R1 "Default member initializers for bit-fields (revision 1)", the
6297 // above bit-field member initializations can be moved to the class definition
6299 if (8 == nVer)
6301 m_fcMin = 0x800;
6302 m_wIdent = 0xa5ec;
6303 m_nFib = 0x0101;
6304 m_nFibBack = 0xbf;
6305 m_nProduct = 0x204D;
6306 m_fDot = bDot;
6308 m_csw = 0x0e; // Is this really necessary???
6309 m_cfclcb = 0x88; // -""-
6310 m_clw = 0x16; // -""-
6311 m_pnFbpChpFirst = m_pnFbpPapFirst = m_pnFbpLvcFirst = 0x000fffff;
6312 m_fExtChar = true;
6313 m_fWord97Saved = m_fWord2000Saved = true;
6315 // Just a fancy way to write 'Caolan80'.
6316 m_wMagicCreated = 0x6143;
6317 m_wMagicRevised = 0x6C6F;
6318 m_wMagicCreatedPrivate = 0x6E61;
6319 m_wMagicRevisedPrivate = 0x3038;
6321 else
6323 m_fcMin = 0x300;
6324 m_wIdent = 0xa5dc;
6325 m_nFib = m_nFibBack = 0x65;
6326 m_nProduct = 0xc02d;
6329 //If nFib is 0x00D9 or greater, then cQuickSaves MUST be 0xF
6330 m_cQuickSaves = m_nFib >= 0x00D9 ? 0xF : 0;
6332 // --> #i90932#
6333 m_lid = LanguageType(0x409); // LANGUAGE_ENGLISH_US
6335 LanguageType nLang = Application::GetSettings().GetLanguageTag().getLanguageType();
6336 m_fFarEast = MsLangId::isCJK(nLang);
6337 if (m_fFarEast)
6338 m_lidFE = nLang;
6339 else
6340 m_lidFE = m_lid;
6342 LanguageTag aLanguageTag( m_lid );
6343 LocaleDataWrapper aLocaleWrapper( std::move(aLanguageTag) );
6344 m_nNumDecimalSep = aLocaleWrapper.getNumDecimalSep()[0];
6348 void WW8Fib::WriteHeader(SvStream& rStrm)
6350 bool bVer8 = 8 == m_nVersion;
6352 size_t nUnencryptedHdr = bVer8 ? 0x44 : 0x24;
6353 std::unique_ptr<sal_uInt8[]> pDataPtr( new sal_uInt8[ nUnencryptedHdr ] );
6354 sal_uInt8 *pData = pDataPtr.get();
6355 memset( pData, 0, nUnencryptedHdr );
6357 m_cbMac = rStrm.TellEnd();
6359 Set_UInt16( pData, m_wIdent );
6360 Set_UInt16( pData, m_nFib );
6361 Set_UInt16( pData, m_nProduct );
6362 Set_UInt16( pData, static_cast<sal_uInt16>(m_lid) );
6363 Set_UInt16( pData, m_pnNext );
6365 sal_uInt16 nBits16 = 0;
6366 if( m_fDot ) nBits16 |= 0x0001;
6367 if( m_fGlsy) nBits16 |= 0x0002;
6368 if( m_fComplex ) nBits16 |= 0x0004;
6369 if( m_fHasPic ) nBits16 |= 0x0008;
6370 nBits16 |= (0xf0 & ( m_cQuickSaves << 4 ));
6371 if( m_fEncrypted ) nBits16 |= 0x0100;
6372 if( m_fWhichTableStm ) nBits16 |= 0x0200;
6374 if (m_fReadOnlyRecommended)
6375 nBits16 |= 0x0400;
6376 if (m_fWriteReservation)
6377 nBits16 |= 0x0800;
6379 if( m_fExtChar ) nBits16 |= 0x1000;
6380 if( m_fFarEast ) nBits16 |= 0x4000; // #i90932#
6381 if( m_fObfuscated ) nBits16 |= 0x8000;
6382 Set_UInt16( pData, nBits16 );
6384 Set_UInt16( pData, m_nFibBack );
6385 Set_UInt16( pData, m_nHash );
6386 Set_UInt16( pData, m_nKey );
6387 Set_UInt8( pData, m_envr );
6389 sal_uInt8 nBits8 = 0;
6390 if( bVer8 )
6392 if( m_fMac ) nBits8 |= 0x0001;
6393 if( m_fEmptySpecial ) nBits8 |= 0x0002;
6394 if( m_fLoadOverridePage ) nBits8 |= 0x0004;
6395 if( m_fFuturesavedUndo ) nBits8 |= 0x0008;
6396 if( m_fWord97Saved ) nBits8 |= 0x0010;
6397 if( m_fWord2000Saved ) nBits8 |= 0x0020;
6399 // under Ver67 these are only reserved
6400 Set_UInt8( pData, nBits8 );
6402 Set_UInt16( pData, m_chse );
6403 Set_UInt16( pData, m_chseTables );
6404 Set_UInt32( pData, m_fcMin );
6405 Set_UInt32( pData, m_fcMac );
6407 // insertion for WW8
6409 // Marke: "rgsw" Beginning of the array of shorts
6410 if( bVer8 )
6412 Set_UInt16( pData, m_csw );
6413 Set_UInt16( pData, m_wMagicCreated );
6414 Set_UInt16( pData, m_wMagicRevised );
6415 Set_UInt16( pData, m_wMagicCreatedPrivate );
6416 Set_UInt16( pData, m_wMagicRevisedPrivate );
6417 pData += 9 * sizeof( sal_Int16 );
6418 Set_UInt16( pData, static_cast<sal_uInt16>(m_lidFE) );
6419 Set_UInt16( pData, m_clw );
6422 // end of the insertion for WW8
6424 // Marke: "rglw" Beginning of the array of longs
6425 Set_UInt32( pData, m_cbMac );
6427 rStrm.WriteBytes(pDataPtr.get(), nUnencryptedHdr);
6430 void WW8Fib::Write(SvStream& rStrm)
6432 bool bVer8 = 8 == m_nVersion;
6434 WriteHeader( rStrm );
6436 size_t nUnencryptedHdr = bVer8 ? 0x44 : 0x24;
6438 std::unique_ptr<sal_uInt8[]> pDataPtr( new sal_uInt8[ m_fcMin - nUnencryptedHdr ] );
6439 sal_uInt8 *pData = pDataPtr.get();
6440 memset( pData, 0, m_fcMin - nUnencryptedHdr );
6442 m_cbMac = rStrm.TellEnd();
6444 // ignore 2 longs, because they are unimportant
6445 pData += 2 * sizeof( sal_Int32);
6447 // skipping 2 more longs only at Ver67
6448 if( !bVer8 )
6449 pData += 2 * sizeof( sal_Int32);
6451 Set_UInt32( pData, m_ccpText );
6452 Set_UInt32( pData, m_ccpFootnote );
6453 Set_UInt32( pData, m_ccpHdr );
6454 Set_UInt32( pData, m_ccpMcr );
6455 Set_UInt32( pData, m_ccpAtn );
6456 Set_UInt32( pData, m_ccpEdn );
6457 Set_UInt32( pData, m_ccpTxbx );
6458 Set_UInt32( pData, m_ccpHdrTxbx );
6460 // only skip one more long at Ver67
6461 if( !bVer8 )
6462 pData += 1 * sizeof( sal_Int32);
6464 // insertion for WW8
6465 if( bVer8 )
6467 Set_UInt32( pData, m_pnFbpChpFirst );
6468 Set_UInt32( pData, m_pnChpFirst );
6469 Set_UInt32( pData, m_cpnBteChp );
6470 Set_UInt32( pData, m_pnFbpPapFirst );
6471 Set_UInt32( pData, m_pnPapFirst );
6472 Set_UInt32( pData, m_cpnBtePap );
6473 Set_UInt32( pData, m_pnFbpLvcFirst );
6474 Set_UInt32( pData, m_pnLvcFirst );
6475 Set_UInt32( pData, m_cpnBteLvc );
6476 Set_UInt32( pData, m_fcIslandFirst );
6477 Set_UInt32( pData, m_fcIslandLim );
6478 Set_UInt16( pData, m_cfclcb );
6480 // end of the insertion for WW8
6482 // Marke: "rgfclcb" Beginning of array of FC/LCB pairs.
6483 Set_UInt32( pData, m_fcStshfOrig );
6484 Set_UInt32( pData, m_lcbStshfOrig );
6485 Set_UInt32( pData, m_fcStshf );
6486 Set_UInt32( pData, m_lcbStshf );
6487 Set_UInt32( pData, m_fcPlcffndRef );
6488 Set_UInt32( pData, m_lcbPlcffndRef );
6489 Set_UInt32( pData, m_fcPlcffndText );
6490 Set_UInt32( pData, m_lcbPlcffndText );
6491 Set_UInt32( pData, m_fcPlcfandRef );
6492 Set_UInt32( pData, m_lcbPlcfandRef );
6493 Set_UInt32( pData, m_fcPlcfandText );
6494 Set_UInt32( pData, m_lcbPlcfandText );
6495 Set_UInt32( pData, m_fcPlcfsed );
6496 Set_UInt32( pData, m_lcbPlcfsed );
6497 Set_UInt32( pData, m_fcPlcfpad );
6498 Set_UInt32( pData, m_lcbPlcfpad );
6499 Set_UInt32( pData, m_fcPlcfphe );
6500 Set_UInt32( pData, m_lcbPlcfphe );
6501 Set_UInt32( pData, m_fcSttbfglsy );
6502 Set_UInt32( pData, m_lcbSttbfglsy );
6503 Set_UInt32( pData, m_fcPlcfglsy );
6504 Set_UInt32( pData, m_lcbPlcfglsy );
6505 Set_UInt32( pData, m_fcPlcfhdd );
6506 Set_UInt32( pData, m_lcbPlcfhdd );
6507 Set_UInt32( pData, m_fcPlcfbteChpx );
6508 Set_UInt32( pData, m_lcbPlcfbteChpx );
6509 Set_UInt32( pData, m_fcPlcfbtePapx );
6510 Set_UInt32( pData, m_lcbPlcfbtePapx );
6511 Set_UInt32( pData, m_fcPlcfsea );
6512 Set_UInt32( pData, m_lcbPlcfsea );
6513 Set_UInt32( pData, m_fcSttbfffn );
6514 Set_UInt32( pData, m_lcbSttbfffn );
6515 Set_UInt32( pData, m_fcPlcffldMom );
6516 Set_UInt32( pData, m_lcbPlcffldMom );
6517 Set_UInt32( pData, m_fcPlcffldHdr );
6518 Set_UInt32( pData, m_lcbPlcffldHdr );
6519 Set_UInt32( pData, m_fcPlcffldFootnote );
6520 Set_UInt32( pData, m_lcbPlcffldFootnote );
6521 Set_UInt32( pData, m_fcPlcffldAtn );
6522 Set_UInt32( pData, m_lcbPlcffldAtn );
6523 Set_UInt32( pData, m_fcPlcffldMcr );
6524 Set_UInt32( pData, m_lcbPlcffldMcr );
6525 Set_UInt32( pData, m_fcSttbfbkmk );
6526 Set_UInt32( pData, m_lcbSttbfbkmk );
6527 Set_UInt32( pData, m_fcPlcfbkf );
6528 Set_UInt32( pData, m_lcbPlcfbkf );
6529 Set_UInt32( pData, m_fcPlcfbkl );
6530 Set_UInt32( pData, m_lcbPlcfbkl );
6531 Set_UInt32( pData, m_fcCmds );
6532 Set_UInt32( pData, m_lcbCmds );
6533 Set_UInt32( pData, m_fcPlcfmcr );
6534 Set_UInt32( pData, m_lcbPlcfmcr );
6535 Set_UInt32( pData, m_fcSttbfmcr );
6536 Set_UInt32( pData, m_lcbSttbfmcr );
6537 Set_UInt32( pData, m_fcPrDrvr );
6538 Set_UInt32( pData, m_lcbPrDrvr );
6539 Set_UInt32( pData, m_fcPrEnvPort );
6540 Set_UInt32( pData, m_lcbPrEnvPort );
6541 Set_UInt32( pData, m_fcPrEnvLand );
6542 Set_UInt32( pData, m_lcbPrEnvLand );
6543 Set_UInt32( pData, m_fcWss );
6544 Set_UInt32( pData, m_lcbWss );
6545 Set_UInt32( pData, m_fcDop );
6546 Set_UInt32( pData, m_lcbDop );
6547 Set_UInt32( pData, m_fcSttbfAssoc );
6548 Set_UInt32( pData, m_lcbSttbfAssoc );
6549 Set_UInt32( pData, m_fcClx );
6550 Set_UInt32( pData, m_lcbClx );
6551 Set_UInt32( pData, m_fcPlcfpgdFootnote );
6552 Set_UInt32( pData, m_lcbPlcfpgdFootnote );
6553 Set_UInt32( pData, m_fcAutosaveSource );
6554 Set_UInt32( pData, m_lcbAutosaveSource );
6555 Set_UInt32( pData, m_fcGrpStAtnOwners );
6556 Set_UInt32( pData, m_lcbGrpStAtnOwners );
6557 Set_UInt32( pData, m_fcSttbfAtnbkmk );
6558 Set_UInt32( pData, m_lcbSttbfAtnbkmk );
6560 // only skip one more short at Ver67
6561 if( !bVer8 )
6563 pData += 1*sizeof( sal_Int16);
6564 Set_UInt16( pData, o3tl::narrowing<sal_uInt16>(m_pnChpFirst) );
6565 Set_UInt16( pData, o3tl::narrowing<sal_uInt16>(m_pnPapFirst) );
6566 Set_UInt16( pData, o3tl::narrowing<sal_uInt16>(m_cpnBteChp) );
6567 Set_UInt16( pData, o3tl::narrowing<sal_uInt16>(m_cpnBtePap) );
6570 Set_UInt32( pData, m_fcPlcfdoaMom ); // only at Ver67, in Ver8 unused
6571 Set_UInt32( pData, m_lcbPlcfdoaMom ); // only at Ver67, in Ver8 unused
6572 Set_UInt32( pData, m_fcPlcfdoaHdr ); // only at Ver67, in Ver8 unused
6573 Set_UInt32( pData, m_lcbPlcfdoaHdr ); // only at Ver67, in Ver8 unused
6575 Set_UInt32( pData, m_fcPlcfspaMom ); // in Ver67 empty reserve
6576 Set_UInt32( pData, m_lcbPlcfspaMom ); // in Ver67 empty reserve
6577 Set_UInt32( pData, m_fcPlcfspaHdr ); // in Ver67 empty reserve
6578 Set_UInt32( pData, m_lcbPlcfspaHdr ); // in Ver67 empty reserve
6580 Set_UInt32( pData, m_fcPlcfAtnbkf );
6581 Set_UInt32( pData, m_lcbPlcfAtnbkf );
6582 Set_UInt32( pData, m_fcPlcfAtnbkl );
6583 Set_UInt32( pData, m_lcbPlcfAtnbkl );
6584 Set_UInt32( pData, m_fcPms );
6585 Set_UInt32( pData, m_lcbPMS );
6586 Set_UInt32( pData, m_fcFormFieldSttbf );
6587 Set_UInt32( pData, m_lcbFormFieldSttbf );
6588 Set_UInt32( pData, m_fcPlcfendRef );
6589 Set_UInt32( pData, m_lcbPlcfendRef );
6590 Set_UInt32( pData, m_fcPlcfendText );
6591 Set_UInt32( pData, m_lcbPlcfendText );
6592 Set_UInt32( pData, m_fcPlcffldEdn );
6593 Set_UInt32( pData, m_lcbPlcffldEdn );
6594 Set_UInt32( pData, m_fcPlcfpgdEdn );
6595 Set_UInt32( pData, m_lcbPlcfpgdEdn );
6596 Set_UInt32( pData, m_fcDggInfo ); // in Ver67 empty reserve
6597 Set_UInt32( pData, m_lcbDggInfo ); // in Ver67 empty reserve
6598 Set_UInt32( pData, m_fcSttbfRMark );
6599 Set_UInt32( pData, m_lcbSttbfRMark );
6600 Set_UInt32( pData, m_fcSttbfCaption );
6601 Set_UInt32( pData, m_lcbSttbfCaption );
6602 Set_UInt32( pData, m_fcSttbAutoCaption );
6603 Set_UInt32( pData, m_lcbSttbAutoCaption );
6604 Set_UInt32( pData, m_fcPlcfwkb );
6605 Set_UInt32( pData, m_lcbPlcfwkb );
6606 Set_UInt32( pData, m_fcPlcfspl ); // in Ver67 empty reserve
6607 Set_UInt32( pData, m_lcbPlcfspl ); // in Ver67 empty reserve
6608 Set_UInt32( pData, m_fcPlcftxbxText );
6609 Set_UInt32( pData, m_lcbPlcftxbxText );
6610 Set_UInt32( pData, m_fcPlcffldTxbx );
6611 Set_UInt32( pData, m_lcbPlcffldTxbx );
6612 Set_UInt32( pData, m_fcPlcfHdrtxbxText );
6613 Set_UInt32( pData, m_lcbPlcfHdrtxbxText );
6614 Set_UInt32( pData, m_fcPlcffldHdrTxbx );
6615 Set_UInt32( pData, m_lcbPlcffldHdrTxbx );
6617 if( bVer8 )
6619 pData += 0x2da - 0x27a; // Pos + Offset (fcPlcfLst - fcStwUser)
6620 Set_UInt32( pData, m_fcSttbFnm);
6621 Set_UInt32( pData, m_lcbSttbFnm);
6622 Set_UInt32( pData, m_fcPlcfLst );
6623 Set_UInt32( pData, m_lcbPlcfLst );
6624 Set_UInt32( pData, m_fcPlfLfo );
6625 Set_UInt32( pData, m_lcbPlfLfo );
6626 Set_UInt32( pData, m_fcPlcftxbxBkd );
6627 Set_UInt32( pData, m_lcbPlcftxbxBkd );
6628 Set_UInt32( pData, m_fcPlcfHdrtxbxBkd );
6629 Set_UInt32( pData, m_lcbPlcfHdrtxbxBkd );
6631 pData += 0x372 - 0x302; // Pos + Offset (fcSttbListNames - fcDocUndo)
6632 Set_UInt32( pData, m_fcSttbListNames );
6633 Set_UInt32( pData, m_lcbSttbListNames );
6635 pData += 0x382 - 0x37A;
6636 Set_UInt32( pData, m_fcPlcfTch );
6637 Set_UInt32( pData, m_lcbPlcfTch );
6639 pData += 0x3FA - 0x38A;
6640 Set_UInt16( pData, sal_uInt16(0x0002));
6641 Set_UInt16( pData, sal_uInt16(0x00D9));
6643 pData += 0x41A - 0x3FE;
6644 Set_UInt32( pData, m_fcAtrdExtra );
6645 Set_UInt32( pData, m_lcbAtrdExtra );
6647 pData += 0x42a - 0x422;
6648 Set_UInt32(pData, m_fcSttbfBkmkFactoid);
6649 Set_UInt32(pData, m_lcbSttbfBkmkFactoid);
6650 Set_UInt32(pData, m_fcPlcfBkfFactoid);
6651 Set_UInt32(pData, m_lcbPlcfBkfFactoid);
6653 pData += 0x442 - 0x43A;
6654 Set_UInt32(pData, m_fcPlcfBklFactoid);
6655 Set_UInt32(pData, m_lcbPlcfBklFactoid);
6656 Set_UInt32(pData, m_fcFactoidData);
6657 Set_UInt32(pData, m_lcbFactoidData);
6659 pData += 0x4BA - 0x452;
6660 Set_UInt32(pData, m_fcPlcffactoid);
6661 Set_UInt32(pData, m_lcbPlcffactoid);
6663 pData += 0x4DA - 0x4c2;
6664 Set_UInt32( pData, m_fcHplxsdr );
6665 Set_UInt32( pData, 0);
6668 rStrm.WriteBytes(pDataPtr.get(), m_fcMin - nUnencryptedHdr);
6671 rtl_TextEncoding WW8Fib::GetFIBCharset(sal_uInt16 chs, LanguageType nLidLocale)
6673 OSL_ENSURE(chs <= 0x100, "overflowed winword charset set");
6674 if (chs == 0x0100)
6675 return RTL_TEXTENCODING_APPLE_ROMAN;
6676 if (chs == 0 && static_cast<sal_uInt16>(nLidLocale) >= 999)
6679 nLidLocale:
6680 language stamp -- localized version In pre-WinWord 2.0 files this
6681 value was the nLocale. If value is < 999, then it is the nLocale,
6682 otherwise it is the lid.
6684 css::lang::Locale aLocale(LanguageTag::convertToLocale(nLidLocale));
6685 return msfilter::util::getBestTextEncodingFromLocale(aLocale);
6687 return rtl_getTextEncodingFromWindowsCharset(static_cast<sal_uInt8>(chs));
6690 MSOFactoidType::MSOFactoidType()
6691 : m_nId(0)
6695 namespace MSOPBString
6697 static OUString Read(SvStream& rStream)
6699 OUString aRet;
6701 sal_uInt16 nBuf(0);
6702 rStream.ReadUInt16(nBuf);
6703 sal_uInt16 nCch = nBuf & 0x7fff; // Bits 1..15.
6704 bool bAnsiString = (nBuf & (1 << 15)) >> 15; // 16th bit.
6705 if (bAnsiString)
6706 aRet = OStringToOUString(read_uInt8s_ToOString(rStream, nCch), RTL_TEXTENCODING_ASCII_US);
6707 else
6708 aRet = read_uInt16s_ToOUString(rStream, nCch);
6710 return aRet;
6713 static void Write(std::u16string_view aString, SvStream& rStream)
6715 sal_uInt16 nBuf = 0;
6716 nBuf |= sal_Int32(aString.size()); // cch, 0..14th bits.
6717 nBuf |= 0x8000; // fAnsiString, 15th bit.
6718 rStream.WriteUInt16(nBuf);
6719 SwWW8Writer::WriteString8(rStream, aString, false, RTL_TEXTENCODING_ASCII_US);
6723 void MSOFactoidType::Read(SvStream& rStream)
6725 sal_uInt32 cbFactoid(0);
6726 rStream.ReadUInt32(cbFactoid);
6727 rStream.ReadUInt32(m_nId);
6728 m_aUri = MSOPBString::Read(rStream);
6729 m_aTag = MSOPBString::Read(rStream);
6730 MSOPBString::Read(rStream); // rgbDownloadURL
6733 void MSOFactoidType::Write(WW8Export& rExport)
6735 SvStream& rStream = *rExport.m_pTableStrm;
6737 SvMemoryStream aStream;
6738 aStream.WriteUInt32(m_nId); // id
6739 MSOPBString::Write(m_aUri, aStream);
6740 MSOPBString::Write(m_aTag, aStream);
6741 MSOPBString::Write(u"", aStream); // rgbDownloadURL
6742 rStream.WriteUInt32(aStream.Tell());
6743 aStream.Seek(0);
6744 rStream.WriteStream(aStream);
6747 void MSOPropertyBagStore::Read(SvStream& rStream)
6749 sal_uInt32 cFactoidType(0);
6750 rStream.ReadUInt32(cFactoidType);
6751 for (sal_uInt32 i = 0; i < cFactoidType && rStream.good(); ++i)
6753 MSOFactoidType aFactoidType;
6754 aFactoidType.Read(rStream);
6755 m_aFactoidTypes.push_back(aFactoidType);
6757 sal_uInt16 cbHdr(0);
6758 rStream.ReadUInt16(cbHdr);
6759 SAL_WARN_IF(cbHdr != 0xc, "sw.ww8", "MSOPropertyBagStore::Read: unexpected cbHdr");
6760 sal_uInt16 nVer(0);
6761 rStream.ReadUInt16(nVer);
6762 SAL_WARN_IF(nVer != 0x0100, "sw.ww8", "MSOPropertyBagStore::Read: unexpected nVer");
6763 rStream.SeekRel(4); // cfactoid
6764 sal_uInt32 nCste(0);
6765 rStream.ReadUInt32(nCste);
6767 //each string has a 2 byte len record at the start
6768 const size_t nMaxPossibleRecords = rStream.remainingSize() / sizeof(sal_uInt16);
6769 if (nCste > nMaxPossibleRecords)
6771 SAL_WARN("sw.ww8", nCste << " records claimed, but max possible is " << nMaxPossibleRecords);
6772 nCste = nMaxPossibleRecords;
6775 for (sal_uInt32 i = 0; i < nCste; ++i)
6777 OUString aString = MSOPBString::Read(rStream);
6778 m_aStringTable.push_back(aString);
6782 void MSOPropertyBagStore::Write(WW8Export& rExport)
6784 SvStream& rStream = *rExport.m_pTableStrm;
6785 rStream.WriteUInt32(m_aFactoidTypes.size()); // cFactoidType
6786 for (MSOFactoidType& rType : m_aFactoidTypes)
6787 rType.Write(rExport);
6788 rStream.WriteUInt16(0xc); // cbHdr
6789 rStream.WriteUInt16(0x0100); // sVer
6790 rStream.WriteUInt32(0); // cfactoid
6791 rStream.WriteUInt32(m_aStringTable.size()); // cste
6792 for (const OUString& rString : m_aStringTable)
6793 MSOPBString::Write(rString, rStream);
6796 MSOProperty::MSOProperty()
6797 : m_nKey(0)
6798 , m_nValue(0)
6802 void MSOProperty::Read(SvStream& rStream)
6804 rStream.ReadUInt32(m_nKey);
6805 rStream.ReadUInt32(m_nValue);
6808 void MSOProperty::Write(SvStream& rStream)
6810 rStream.WriteUInt32(m_nKey);
6811 rStream.WriteUInt32(m_nValue);
6814 MSOPropertyBag::MSOPropertyBag()
6815 : m_nId(0)
6819 bool MSOPropertyBag::Read(SvStream& rStream)
6821 rStream.ReadUInt16(m_nId);
6822 sal_uInt16 cProp(0);
6823 rStream.ReadUInt16(cProp);
6824 if (!rStream.good())
6825 return false;
6826 rStream.SeekRel(2); // cbUnknown
6827 //each MSOProperty is 8 bytes in size
6828 const size_t nMaxPossibleRecords = rStream.remainingSize() / 8;
6829 if (cProp > nMaxPossibleRecords)
6831 SAL_WARN("sw.ww8", cProp << " records claimed, but max possible is " << nMaxPossibleRecords);
6832 cProp = nMaxPossibleRecords;
6834 for (sal_uInt16 i = 0; i < cProp && rStream.good(); ++i)
6836 MSOProperty aProperty;
6837 aProperty.Read(rStream);
6838 m_aProperties.push_back(aProperty);
6840 return rStream.good();
6843 void MSOPropertyBag::Write(WW8Export& rExport)
6845 SvStream& rStream = *rExport.m_pTableStrm;
6846 rStream.WriteUInt16(m_nId);
6847 rStream.WriteUInt16(m_aProperties.size());
6848 rStream.WriteUInt16(0); // cbUnknown
6849 for (MSOProperty& rProperty : m_aProperties)
6850 rProperty.Write(rStream);
6853 void WW8SmartTagData::Read(SvStream& rStream, WW8_FC fcFactoidData, sal_uInt32 lcbFactoidData)
6855 sal_uInt64 nOldPosition = rStream.Tell();
6856 if (!checkSeek(rStream, fcFactoidData))
6857 return;
6859 m_aPropBagStore.Read(rStream);
6860 while (rStream.good() && rStream.Tell() < fcFactoidData + lcbFactoidData)
6862 MSOPropertyBag aPropertyBag;
6863 if (!aPropertyBag.Read(rStream))
6864 break;
6865 m_aPropBags.push_back(aPropertyBag);
6868 rStream.Seek(nOldPosition);
6871 void WW8SmartTagData::Write(WW8Export& rExport)
6873 m_aPropBagStore.Write(rExport);
6874 for (MSOPropertyBag& rPropertyBag : m_aPropBags)
6875 rPropertyBag.Write(rExport);
6878 WW8Style::WW8Style(SvStream& rStream, WW8Fib& rFibPara)
6879 : m_rFib(rFibPara), m_rStream(rStream), m_cstd(0), m_cbSTDBaseInFile(0), m_fStdStylenamesWritten(0)
6880 , m_stiMaxWhenSaved(0), m_istdMaxFixedWhenSaved(0), m_nVerBuiltInNamesWhenSaved(0)
6881 , m_ftcAsci(0), m_ftcFE(0), m_ftcOther(0), m_ftcBi(0)
6883 if (!checkSeek(m_rStream, m_rFib.m_fcStshf))
6884 return;
6886 sal_uInt16 cbStshi = 0; // 2 bytes size of the following STSHI structure
6887 sal_uInt32 nRemaining = m_rFib.m_lcbStshf;
6888 const sal_uInt32 nMinValidStshi = 4;
6890 if (m_rFib.GetFIBVersion() <= ww::eWW2)
6892 cbStshi = 0;
6893 m_cstd = 256;
6895 else
6897 if (m_rFib.m_nFib < 67) // old Version ? (need to find this again to fix)
6898 cbStshi = nMinValidStshi;
6899 else // new version
6901 if (nRemaining < sizeof(cbStshi))
6902 return;
6903 // reads the length of the structure in the file
6904 m_rStream.ReadUInt16( cbStshi );
6905 nRemaining-=2;
6909 cbStshi = std::min(static_cast<sal_uInt32>(cbStshi), nRemaining);
6910 if (cbStshi < nMinValidStshi)
6911 return;
6913 const sal_uInt16 nRead = cbStshi;
6916 m_rStream.ReadUInt16( m_cstd );
6918 m_rStream.ReadUInt16( m_cbSTDBaseInFile );
6920 if( 6 > nRead ) break;
6922 sal_uInt16 a16Bit;
6923 m_rStream.ReadUInt16( a16Bit );
6924 m_fStdStylenamesWritten = a16Bit & 0x0001;
6926 if( 8 > nRead ) break;
6927 m_rStream.ReadUInt16( m_stiMaxWhenSaved );
6929 if( 10 > nRead ) break;
6930 m_rStream.ReadUInt16( m_istdMaxFixedWhenSaved );
6932 if( 12 > nRead ) break;
6933 m_rStream.ReadUInt16( m_nVerBuiltInNamesWhenSaved );
6935 if( 14 > nRead ) break;
6936 m_rStream.ReadUInt16( m_ftcAsci );
6938 if( 16 > nRead ) break;
6939 m_rStream.ReadUInt16( m_ftcFE );
6941 if ( 18 > nRead ) break;
6942 m_rStream.ReadUInt16( m_ftcOther );
6944 m_ftcBi = m_ftcOther;
6946 if ( 20 > nRead ) break;
6947 m_rStream.ReadUInt16( m_ftcBi );
6949 // p.r.n. ignore the rest
6950 if( 20 < nRead )
6951 m_rStream.SeekRel( nRead-20 );
6953 while( false ); // trick: the block above will be passed through exactly one time
6954 // and that's why we can early exit with "break".
6956 nRemaining -= cbStshi;
6958 //There will be stshi.cstd (cbSTD, STD) pairs in the file following the
6959 //STSHI. Note that styles can be empty, i.e. cbSTD == 0
6960 const sal_uInt32 nMinRecordSize = sizeof(sal_uInt16);
6961 const sal_uInt16 nMaxPossibleRecords = nRemaining/nMinRecordSize;
6963 OSL_ENSURE(m_cstd <= nMaxPossibleRecords,
6964 "allegedly more styles that available data");
6965 m_cstd = o3tl::sanitizing_min(m_cstd, nMaxPossibleRecords);
6968 // Read1STDFixed() reads a style. If the style is completely existent,
6969 // so it has no empty slot, we should allocate memory and a pointer should
6970 // reference to STD (perhaps filled with 0). If the slot is empty,
6971 // it will return a null pointer.
6972 std::unique_ptr<WW8_STD> WW8Style::Read1STDFixed(sal_uInt16& rSkip)
6974 if (m_rStream.remainingSize() < 2)
6976 rSkip = 0;
6977 return nullptr;
6980 std::unique_ptr<WW8_STD> pStd;
6982 sal_uInt16 cbStd(0);
6983 m_rStream.ReadUInt16(cbStd); // read length
6985 const sal_uInt16 nRead = m_cbSTDBaseInFile;
6986 if( cbStd >= m_cbSTDBaseInFile )
6988 // Fixed part completely available
6990 // read fixed part of STD
6991 pStd.reset(new WW8_STD);
6992 memset( pStd.get(), 0, sizeof( *pStd ) );
6996 if( 2 > nRead ) break;
6998 sal_uInt16 a16Bit = 0;
6999 m_rStream.ReadUInt16( a16Bit );
7000 pStd->sti = a16Bit & 0x0fff ;
7001 pStd->fScratch = sal_uInt16(0 != ( a16Bit & 0x1000 ));
7002 pStd->fInvalHeight = sal_uInt16(0 != ( a16Bit & 0x2000 ));
7003 pStd->fHasUpe = sal_uInt16(0 != ( a16Bit & 0x4000 ));
7004 pStd->fMassCopy = sal_uInt16(0 != ( a16Bit & 0x8000 ));
7006 if( 4 > nRead ) break;
7007 a16Bit = 0;
7008 m_rStream.ReadUInt16( a16Bit );
7009 pStd->sgc = a16Bit & 0x000f ;
7010 pStd->istdBase = ( a16Bit & 0xfff0 ) >> 4;
7012 if( 6 > nRead ) break;
7013 a16Bit = 0;
7014 m_rStream.ReadUInt16( a16Bit );
7015 pStd->cupx = a16Bit & 0x000f ;
7016 pStd->istdNext = ( a16Bit & 0xfff0 ) >> 4;
7018 if( 8 > nRead ) break;
7019 m_rStream.ReadUInt16( pStd->bchUpe );
7021 // from Ver8 this two fields should be added:
7022 if(10 > nRead ) break;
7023 a16Bit = 0;
7024 m_rStream.ReadUInt16( a16Bit );
7025 pStd->fAutoRedef = a16Bit & 0x0001 ;
7026 pStd->fHidden = ( a16Bit & 0x0002 ) >> 1;
7027 // You never know: cautionary skipped
7028 if (nRead > 10)
7030 auto nSkip = std::min<sal_uInt64>(nRead - 10, m_rStream.remainingSize());
7031 m_rStream.Seek(m_rStream.Tell() + nSkip);
7034 while( false ); // trick: the block above will passed through exactly one time
7035 // and can be left early with a "break"
7037 if (!m_rStream.good() || !nRead)
7039 pStd.reset(); // report error with NULL
7042 rSkip = cbStd - m_cbSTDBaseInFile;
7044 else
7045 { // Fixed part too short
7046 if( cbStd )
7047 m_rStream.SeekRel( cbStd ); // skip leftovers
7048 rSkip = 0;
7050 return pStd;
7053 std::unique_ptr<WW8_STD> WW8Style::Read1Style(sal_uInt16& rSkip, OUString* pString)
7055 // Attention: MacWord-Documents have their Stylenames
7056 // always in ANSI, even if eStructCharSet == CHARSET_MAC !!
7058 std::unique_ptr<WW8_STD> pStd = Read1STDFixed(rSkip); // read STD
7060 // string desired?
7061 if( pString )
7062 { // real style?
7063 if ( pStd )
7065 sal_Int32 nLenStringBytes = 0;
7066 switch( m_rFib.m_nVersion )
7068 case 6:
7069 case 7:
7070 // read pascal string
7071 *pString = read_uInt8_BeltAndBracesString(m_rStream, RTL_TEXTENCODING_MS_1252);
7072 // leading len and trailing zero --> 2
7073 nLenStringBytes = pString->getLength() + 2;
7074 break;
7075 case 8:
7076 // handle Unicode-String with leading length short and
7077 // trailing zero
7078 if (TestBeltAndBraces(m_rStream))
7080 *pString = read_uInt16_BeltAndBracesString(m_rStream);
7081 nLenStringBytes = (pString->getLength() + 2) * 2;
7083 else
7086 #i8114#
7087 This is supposed to be impossible, it's just supposed
7088 to be 16 bit count followed by the string and ending
7089 in a 0 short. But "Lotus SmartSuite Product: Word Pro"
7090 is creating invalid style names in ww7- format. So we
7091 use the belt and braces of the ms strings to see if
7092 they are not corrupt. If they are then we try them as
7093 8bit ones
7095 *pString = read_uInt8_BeltAndBracesString(m_rStream,RTL_TEXTENCODING_MS_1252);
7096 // leading len and trailing zero --> 2
7097 nLenStringBytes = pString->getLength() + 2;
7099 break;
7100 default:
7101 OSL_ENSURE(false, "It was forgotten to code nVersion!");
7102 break;
7104 if (nLenStringBytes > rSkip)
7106 SAL_WARN("sw.ww8", "WW8Style structure corrupt");
7107 nLenStringBytes = rSkip;
7109 rSkip -= nLenStringBytes;
7111 else
7112 pString->clear(); // can not return a name
7114 return pStd;
7117 namespace {
7118 const sal_uInt16 maxStrSize = 65;
7120 struct WW8_FFN_Ver6
7122 WW8_FFN_BASE base;
7123 // from Ver6
7124 char szFfn[maxStrSize]; // 0x6 or 0x40 from Ver8 on zero terminated string that
7125 // records name of font.
7126 // Maximal size of szFfn is 65 characters.
7127 // Attention: This array can also be smaller!!!
7128 // Possibly followed by a second sz which records the
7129 // name of an alternate font to use if the first named
7130 // font does not exist on this system.
7135 // #i43762# check font name for illegal characters
7136 static void lcl_checkFontname( OUString& sString )
7138 // for efficiency, we'd like to use String methods as far as possible.
7139 // Hence, we will:
7140 // 1) convert all invalid chars to \u0001
7141 // 2) then erase all \u0001 chars (if anywhere found), and
7142 // 3) erase leading/trailing ';', in case a font name was
7143 // completely removed
7145 // convert all invalid chars to \u0001
7146 OUStringBuffer aBuf(sString);
7147 const sal_Int32 nLen = aBuf.getLength();
7148 bool bFound = false;
7149 for ( sal_Int32 n = 0; n < nLen; ++n )
7151 if ( aBuf[n] < 0x20 )
7153 aBuf[n] = 1;
7154 bFound = true;
7157 sString = aBuf.makeStringAndClear();
7159 // if anything was found, remove \u0001 + leading/trailing ';'
7160 if( bFound )
7162 sString = comphelper::string::strip(sString.replaceAll("\001", ""), ';');
7166 namespace
7168 sal_uInt16 calcMaxFonts(sal_uInt8 *p, sal_Int32 nFFn)
7170 // Figure out the max number of fonts defined here
7171 sal_uInt16 nMax = 0;
7172 sal_Int32 nRemaining = nFFn;
7173 while (nRemaining)
7175 //p[0] is cbFfnM1, the alleged total length of FFN - 1.
7176 //i.e. length after cbFfnM1
7177 const sal_uInt16 cbFfnM1 = *p++;
7178 --nRemaining;
7180 if (cbFfnM1 > nRemaining)
7181 break;
7183 nMax++;
7184 nRemaining -= cbFfnM1;
7185 p += cbFfnM1;
7187 return nMax;
7190 template<typename T> bool readU8(
7191 sal_uInt8 const * p, std::size_t offset, sal_uInt8 const * pEnd,
7192 T * value)
7194 assert(p <= pEnd);
7195 assert(value != nullptr);
7196 if (offset >= o3tl::make_unsigned(pEnd - p)) {
7197 return false;
7199 *value = p[offset];
7200 return true;
7203 bool readS16(
7204 sal_uInt8 const * p, std::size_t offset, sal_uInt8 const * pEnd,
7205 short * value)
7207 assert(p <= pEnd);
7208 assert(value != nullptr);
7209 if (offset > o3tl::make_unsigned(pEnd - p)
7210 || static_cast<std::size_t>(pEnd - p) - offset < 2)
7212 return false;
7214 *value = unsigned(p[offset]) + (unsigned(p[offset + 1]) << 8);
7215 return true;
7218 sal_Int32 getStringLengthWithMax(
7219 sal_uInt8 const * p, std::size_t offset, sal_uInt8 const * pEnd, std::size_t maxchars)
7221 assert(p <= pEnd);
7222 assert(pEnd - p <= SAL_MAX_INT32);
7223 if (offset >= o3tl::make_unsigned(pEnd - p)) {
7224 return -1;
7226 std::size_t nbytes = static_cast<std::size_t>(pEnd - p) - offset;
7227 std::size_t nsearch = std::min(nbytes, maxchars + 1);
7228 void const * p2 = std::memchr(p + offset, 0, nsearch);
7229 if (p2 == nullptr) {
7230 return -1;
7232 return static_cast<sal_uInt8 const *>(p2) - (p + offset);
7236 WW8Fonts::WW8Fonts( SvStream& rSt, WW8Fib const & rFib )
7238 // Attention: MacWord-Documents have their Fontnames
7239 // always in ANSI, even if eStructCharSet == CHARSET_MAC !!
7240 if( rFib.m_lcbSttbfffn <= 2 )
7242 OSL_ENSURE( false, "font table is broken! (rFib.lcbSttbfffn < 2)" );
7243 return;
7246 if (!checkSeek(rSt, rFib.m_fcSttbfffn))
7247 return;
7249 sal_Int32 nFFn = rFib.m_lcbSttbfffn - 2;
7251 const sal_uInt64 nMaxPossible = rSt.remainingSize();
7252 if (o3tl::make_unsigned(nFFn) > nMaxPossible)
7254 SAL_WARN("sw.ww8", "FFN structure longer than available data");
7255 nFFn = nMaxPossible;
7258 // allocate Font Array
7259 std::vector<sal_uInt8> aA(nFFn);
7260 memset(aA.data(), 0, nFFn);
7262 ww::WordVersion eVersion = rFib.GetFIBVersion();
7264 sal_uInt16 nMax(0);
7265 if( eVersion >= ww::eWW8 )
7267 // bVer8: read the count of strings in nMax
7268 rSt.ReadUInt16(nMax);
7271 // Ver8: skip undefined uint16
7272 // Ver67: skip the herein stored total byte of structure
7273 // - we already got that information in rFib.lcbSttbfffn
7274 rSt.SeekRel( 2 );
7276 // read all font information
7277 nFFn = rSt.ReadBytes(aA.data(), nFFn);
7278 sal_uInt8 * const pEnd = aA.data() + nFFn;
7279 const sal_uInt16 nCalcMax = calcMaxFonts(aA.data(), nFFn);
7281 if (eVersion < ww::eWW8)
7282 nMax = nCalcMax;
7283 else
7285 //newer versions include supportive count of fonts, so take min of that
7286 //and calced max
7287 nMax = std::min(nMax, nCalcMax);
7290 if (nMax)
7292 // allocate Index Array
7293 m_aFontA.resize(nMax);
7294 WW8_FFN* p = m_aFontA.data();
7296 if( eVersion <= ww::eWW2 )
7298 sal_uInt8 const * pVer2 = aA.data();
7299 sal_uInt16 i = 0;
7300 for(; i<nMax; ++i, ++p)
7302 if (!readU8(
7303 pVer2, offsetof(WW8_FFN_BASE, cbFfnM1), pEnd,
7304 &p->aFFNBase.cbFfnM1))
7306 break;
7309 p->aFFNBase.prg = 0;
7310 p->aFFNBase.fTrueType = 0;
7311 p->aFFNBase.ff = 0;
7313 if (!(readU8(pVer2, 1, pEnd, &p->aFFNBase.wWeight)
7314 && readU8(pVer2, 2, pEnd, &p->aFFNBase.chs)))
7316 break;
7319 #i8726# 7- seems to encode the name in the same encoding as
7320 the font, e.g load the doc in 97 and save to see the unicode
7321 ver of the asian fontnames in that example to confirm.
7323 rtl_TextEncoding eEnc = WW8Fib::GetFIBCharset(p->aFFNBase.chs, rFib.m_lid);
7324 if ((eEnc == RTL_TEXTENCODING_SYMBOL) || (eEnc == RTL_TEXTENCODING_DONTKNOW))
7325 eEnc = RTL_TEXTENCODING_MS_1252;
7327 const size_t nStringOffset = 1 + 2;
7328 sal_Int32 n = getStringLengthWithMax(pVer2, nStringOffset, pEnd, maxStrSize);
7329 if (n == -1) {
7330 break;
7332 p->sFontname = OUString(
7333 reinterpret_cast<char const *>(pVer2 + nStringOffset), n, eEnc);
7334 pVer2 = pVer2 + p->aFFNBase.cbFfnM1 + 1;
7336 nMax = i;
7338 else if( eVersion < ww::eWW8 )
7340 sal_uInt8 const * pVer6 = aA.data();
7341 sal_uInt16 i = 0;
7342 for(; i<nMax; ++i, ++p)
7344 if (!readU8(
7345 pVer6, offsetof(WW8_FFN_BASE, cbFfnM1), pEnd,
7346 &p->aFFNBase.cbFfnM1))
7348 break;
7350 sal_uInt8 c2;
7351 if (!readU8(pVer6, 1, pEnd, &c2)) {
7352 break;
7355 p->aFFNBase.prg = c2 & 0x02;
7356 p->aFFNBase.fTrueType = (c2 & 0x04) >> 2;
7357 // skip a reserve bit
7358 p->aFFNBase.ff = (c2 & 0x70) >> 4;
7360 if (!(readS16(
7361 pVer6, offsetof(WW8_FFN_BASE, wWeight), pEnd,
7362 &p->aFFNBase.wWeight)
7363 && readU8(
7364 pVer6, offsetof(WW8_FFN_BASE, chs), pEnd, &p->aFFNBase.chs)
7365 && readU8(
7366 pVer6, offsetof(WW8_FFN_BASE, ibszAlt), pEnd,
7367 &p->aFFNBase.ibszAlt)))
7369 break;
7372 #i8726# 7- seems to encode the name in the same encoding as
7373 the font, e.g load the doc in 97 and save to see the unicode
7374 ver of the asian fontnames in that example to confirm.
7376 rtl_TextEncoding eEnc = WW8Fib::GetFIBCharset(p->aFFNBase.chs, rFib.m_lid);
7377 if ((eEnc == RTL_TEXTENCODING_SYMBOL) || (eEnc == RTL_TEXTENCODING_DONTKNOW))
7378 eEnc = RTL_TEXTENCODING_MS_1252;
7379 const size_t nStringOffset = offsetof(WW8_FFN_Ver6, szFfn);
7380 sal_Int32 n = getStringLengthWithMax(pVer6, nStringOffset, pEnd, maxStrSize);
7381 if (n == -1) {
7382 break;
7384 p->sFontname = OUString(reinterpret_cast<char const*>(pVer6 + nStringOffset), n, eEnc);
7385 if (p->aFFNBase.ibszAlt && p->aFFNBase.ibszAlt < maxStrSize) //don't start after end of string
7387 const size_t nAltStringOffset = offsetof(WW8_FFN_Ver6, szFfn) + p->aFFNBase.ibszAlt;
7388 n = getStringLengthWithMax(pVer6, nAltStringOffset, pEnd, maxStrSize);
7389 if (n == -1) {
7390 break;
7392 p->sFontname += ";" + OUString(reinterpret_cast<char const*>(pVer6 + nAltStringOffset),
7393 n, eEnc);
7395 else
7397 //#i18369# if it's a symbol font set Symbol as fallback
7398 if (
7399 RTL_TEXTENCODING_SYMBOL == WW8Fib::GetFIBCharset(p->aFFNBase.chs, rFib.m_lid)
7400 && p->sFontname!="Symbol"
7403 p->sFontname += ";Symbol";
7406 pVer6 = pVer6 + p->aFFNBase.cbFfnM1 + 1;
7408 nMax = i;
7410 else
7412 //count of bytes in minimum FontFamilyInformation payload
7413 const sal_uInt8 cbMinFFNPayload = 41;
7414 sal_uInt16 nValidFonts = 0;
7415 sal_Int32 nRemainingFFn = nFFn;
7416 sal_uInt8* pRaw = aA.data();
7417 for (sal_uInt16 i=0; i < nMax && nRemainingFFn; ++i, ++p)
7419 //pRaw[0] is cbFfnM1, the alleged total length of FFN - 1
7420 //i.e. length after cbFfnM1
7421 sal_uInt8 cbFfnM1 = *pRaw++;
7422 --nRemainingFFn;
7424 if (cbFfnM1 > nRemainingFFn)
7425 break;
7427 if (cbFfnM1 < cbMinFFNPayload)
7428 break;
7430 p->aFFNBase.cbFfnM1 = cbFfnM1;
7432 sal_uInt8 *pVer8 = pRaw;
7434 sal_uInt8 c2 = *pVer8++;
7435 --cbFfnM1;
7437 p->aFFNBase.prg = c2 & 0x02;
7438 p->aFFNBase.fTrueType = (c2 & 0x04) >> 2;
7439 // skip a reserve bit
7440 p->aFFNBase.ff = (c2 & 0x70) >> 4;
7442 p->aFFNBase.wWeight = SVBT16ToUInt16(*reinterpret_cast<SVBT16*>(pVer8));
7443 pVer8+=2;
7444 cbFfnM1-=2;
7446 p->aFFNBase.chs = *pVer8++;
7447 --cbFfnM1;
7449 p->aFFNBase.ibszAlt = *pVer8++;
7450 --cbFfnM1;
7452 pVer8 += 10; //PANOSE
7453 cbFfnM1-=10;
7454 pVer8 += 24; //FONTSIGNATURE
7455 cbFfnM1-=24;
7457 assert(cbFfnM1 >= 2);
7459 sal_uInt8 nMaxNullTerminatedPossible = cbFfnM1/2 - 1;
7460 sal_Unicode *pPrimary = reinterpret_cast<sal_Unicode*>(pVer8);
7461 pPrimary[nMaxNullTerminatedPossible] = 0;
7462 #ifdef OSL_BIGENDIAN
7463 swapEndian(pPrimary);
7464 #endif
7465 p->sFontname = pPrimary;
7466 if (p->aFFNBase.ibszAlt && p->aFFNBase.ibszAlt < nMaxNullTerminatedPossible)
7468 sal_Unicode *pSecondary = pPrimary + p->aFFNBase.ibszAlt;
7469 #ifdef OSL_BIGENDIAN
7470 swapEndian(pSecondary);
7471 #endif
7472 p->sFontname += OUString::Concat(";") + pSecondary;
7475 // #i43762# check font name for illegal characters
7476 lcl_checkFontname( p->sFontname );
7478 // set pointer one font back to original array
7479 pRaw += p->aFFNBase.cbFfnM1;
7480 nRemainingFFn -= p->aFFNBase.cbFfnM1;
7481 ++nValidFonts;
7483 OSL_ENSURE(nMax == nValidFonts, "Font count differs with availability");
7484 nMax = std::min(nMax, nValidFonts);
7487 m_aFontA.resize(nMax);
7488 m_aFontA.shrink_to_fit();
7491 const WW8_FFN* WW8Fonts::GetFont( sal_uInt16 nNum ) const
7493 if (nNum >= m_aFontA.size())
7494 return nullptr;
7496 return &m_aFontA[nNum];
7499 // Search after a header/footer for an index in the ww list from header/footer
7501 // specials for WinWord6 and -7:
7503 // 1) At the start of reading we must build WWPLCF_HdFt with Fib and Dop
7504 // 2) The main text must be read sequentially over all sections
7505 // 3) For every header/footer in the main text, we must call UpdateIndex()
7506 // exactly once with the parameter from the attribute.
7507 // (per section can be maximally one). This call must take place *after*
7508 // the last call from GetTextPos().
7509 // 4) GetTextPos() can be called with exactly one flag
7510 // out of WW8_{FOOTER,HEADER}_{ODD,EVEN,FIRST} (Do not change!)
7511 // -> maybe we can get a right result then
7513 WW8PLCF_HdFt::WW8PLCF_HdFt( SvStream* pSt, WW8Fib const & rFib, WW8Dop const & rDop )
7514 : m_aPLCF(*pSt, rFib.m_fcPlcfhdd , rFib.m_lcbPlcfhdd , 0)
7516 m_nIdxOffset = 0;
7519 This dop.grpfIhdt has a bit set for each special
7520 footnote *and endnote!!* separator,continuation separator, and
7521 continuation notice entry, the documentation does not mention the
7522 endnote separators, the documentation also gets the index numbers
7523 backwards when specifying which bits to test. The bottom six bits
7524 of this value must be tested and skipped over. Each section's
7525 grpfIhdt is then tested for the existence of the appropriate headers
7526 and footers, at the end of each section the nIdxOffset must be updated
7527 to point to the beginning of the next section's group of headers and
7528 footers in this PLCF, UpdateIndex does that task.
7530 for( sal_uInt8 nI = 0x1; nI <= 0x20; nI <<= 1 )
7531 if( nI & rDop.grpfIhdt ) // bit set?
7532 m_nIdxOffset++;
7535 bool WW8PLCF_HdFt::GetTextPos(sal_uInt8 grpfIhdt, sal_uInt8 nWhich, WW8_CP& rStart,
7536 WW8_CP& rLen)
7538 sal_uInt8 nI = 0x01;
7539 short nIdx = m_nIdxOffset;
7540 while (true)
7542 if( nI & nWhich )
7543 break; // found
7544 if( grpfIhdt & nI )
7545 nIdx++; // uninteresting Header / Footer
7546 nI <<= 1; // text next bit
7547 if( nI > 0x20 )
7548 return false; // not found
7550 // nIdx is HdFt-Index
7551 WW8_CP nEnd;
7552 void* pData;
7554 m_aPLCF.SetIdx( nIdx ); // Lookup suitable CP
7555 m_aPLCF.Get( rStart, nEnd, pData );
7556 if (nEnd < rStart)
7558 SAL_WARN("sw.ww8", "End " << nEnd << " before Start " << rStart);
7559 return false;
7562 bool bFail = o3tl::checked_sub(nEnd, rStart, rLen);
7563 if (bFail)
7565 SAL_WARN("sw.ww8", "broken offset, ignoring");
7566 return false;
7569 m_aPLCF.advance();
7571 return true;
7574 void WW8PLCF_HdFt::GetTextPosExact(short nIdx, WW8_CP& rStart, WW8_CP& rLen)
7576 WW8_CP nEnd;
7577 void* pData;
7579 m_aPLCF.SetIdx( nIdx ); // Lookup suitable CP
7580 m_aPLCF.Get( rStart, nEnd, pData );
7581 if (nEnd < rStart)
7583 SAL_WARN("sw.ww8", "End " << nEnd << " before Start " << rStart);
7584 rLen = 0;
7585 return;
7587 if (o3tl::checked_sub(nEnd, rStart, rLen))
7589 SAL_WARN("sw.ww8", "GetTextPosExact overflow");
7590 rLen = 0;
7594 void WW8PLCF_HdFt::UpdateIndex( sal_uInt8 grpfIhdt )
7596 // Caution: Description is not correct
7597 for( sal_uInt8 nI = 0x01; nI <= 0x20; nI <<= 1 )
7598 if( nI & grpfIhdt )
7599 m_nIdxOffset++;
7602 WW8Dop::WW8Dop(SvStream& rSt, sal_Int16 nFib, sal_Int32 nPos, sal_uInt32 nSize):
7603 fFacingPages(false), fWidowControl(false), fPMHMainDoc(false), grfSuppression(0), fpc(0),
7604 grpfIhdt(0), rncFootnote(0), nFootnote(0), fOutlineDirtySave(false), fOnlyMacPics(false),
7605 fOnlyWinPics(false), fLabelDoc(false), fHyphCapitals(false), fAutoHyphen(false),
7606 fFormNoFields(false), fLinkStyles(false), fRevMarking(false), fBackup(false),
7607 fExactCWords(false), fPagHidden(false), fPagResults(false), fLockAtn(false),
7608 fMirrorMargins(false), fReadOnlyRecommended(false), fDfltTrueType(false),
7609 fPagSuppressTopSpacing(false), fProtEnabled(false), fDispFormFieldSel(false), fRMView(false),
7610 fRMPrint(false), fWriteReservation(false), fLockRev(false), fEmbedFonts(false),
7611 copts_fNoTabForInd(false), copts_fNoSpaceRaiseLower(false), copts_fSuppressSpbfAfterPgBrk(false),
7612 copts_fWrapTrailSpaces(false), copts_fMapPrintTextColor(false), copts_fNoColumnBalance(false),
7613 copts_fConvMailMergeEsc(false), copts_fSuppressTopSpacing(false),
7614 copts_fOrigWordTableRules(false), copts_fTransparentMetafiles(false),
7615 copts_fShowBreaksInFrames(false), copts_fSwapBordersFacingPgs(false), copts_fExpShRtn(false),
7616 rncEdn(0), nEdn(0), epc(0), fPrintFormData(false), fSaveFormData(false), fShadeFormData(false),
7617 fWCFootnoteEdn(false), wvkSaved(0), wScaleSaved(0), zkSaved(0), fRotateFontW6(false),
7618 iGutterPos(false), fNoTabForInd(false), fNoSpaceRaiseLower(false),
7619 fSuppressSpbfAfterPageBreak(false), fWrapTrailSpaces(false), fMapPrintTextColor(false),
7620 fNoColumnBalance(false), fConvMailMergeEsc(false), fSuppressTopSpacing(false),
7621 fOrigWordTableRules(false), fTransparentMetafiles(false), fShowBreaksInFrames(false),
7622 fSwapBordersFacingPgs(false), fCompatibilityOptions_Unknown1_13(false), fExpShRtn(false),
7623 fCompatibilityOptions_Unknown1_15(false), fCompatibilityOptions_Unknown1_16(false),
7624 fSuppressTopSpacingMac5(false), fTruncDxaExpand(false), fPrintBodyBeforeHdr(false),
7625 fNoLeading(false), fCompatibilityOptions_Unknown1_21(false), fMWSmallCaps(false),
7626 fCompatibilityOptions_Unknown1_23(false), fCompatibilityOptions_Unknown1_24(false),
7627 fCompatibilityOptions_Unknown1_25(false), fCompatibilityOptions_Unknown1_26(false),
7628 fCompatibilityOptions_Unknown1_27(false), fCompatibilityOptions_Unknown1_28(false),
7629 fCompatibilityOptions_Unknown1_29(false), fCompatibilityOptions_Unknown1_30(false),
7630 fCompatibilityOptions_Unknown1_31(false), fUsePrinterMetrics(false), lvl(0), fHtmlDoc(false),
7631 fSnapBorder(false), fIncludeHeader(false), fIncludeFooter(false), fForcePageSizePag(false),
7632 fMinFontSizePag(false), fHaveVersions(false), fAutoVersion(false),
7633 fCompatibilityOptions_Unknown2_1(false), fCompatibilityOptions_Unknown2_2(false),
7634 fDontUseHTMLAutoSpacing(false), fCompatibilityOptions_Unknown2_4(false),
7635 fCompatibilityOptions_Unknown2_5(false), fCompatibilityOptions_Unknown2_6(false),
7636 fCompatibilityOptions_Unknown2_7(false), fCompatibilityOptions_Unknown2_8(false),
7637 fCompatibilityOptions_Unknown2_9(false), fCompatibilityOptions_Unknown2_10(false),
7638 fDontBreakWrappedTables(false), fCompatibilityOptions_Unknown2_12(false),
7639 fCompatibilityOptions_Unknown2_13(false), fCompatibilityOptions_Unknown2_14(false),
7640 fCompatibilityOptions_Unknown2_15(false), fCompatibilityOptions_Unknown2_16(false),
7641 fCompatibilityOptions_Unknown2_17(false), fCompatibilityOptions_Unknown2_18(false),
7642 fCompatibilityOptions_Unknown2_19(false), fCompatibilityOptions_Unknown2_20(false),
7643 fCompatibilityOptions_Unknown2_21(false), fCompatibilityOptions_Unknown2_22(false),
7644 fCompatibilityOptions_Unknown2_23(false), fCompatibilityOptions_Unknown2_24(false),
7645 fCompatibilityOptions_Unknown2_25(false), fCompatibilityOptions_Unknown2_26(false),
7646 fCompatibilityOptions_Unknown2_27(false), fCompatibilityOptions_Unknown2_28(false),
7647 fCompatibilityOptions_Unknown2_29(false), fCompatibilityOptions_Unknown2_30(false),
7648 fCompatibilityOptions_Unknown2_31(false), fCompatibilityOptions_Unknown2_32(false),
7649 fUnknown3(0), fUseBackGroundInAllmodes(false), fDoNotEmbedSystemFont(false), fWordCompat(false),
7650 fLiveRecover(false), fEmbedFactoids(false), fFactoidXML(false), fFactoidAllDone(false),
7651 fFolioPrint(false), fReverseFolio(false), iTextLineEnding(0), fHideFcc(false),
7652 fAcetateShowMarkup(false), fAcetateShowAtn(false), fAcetateShowInsDel(false),
7653 fAcetateShowProps(false)
7654 // in C++20 with P06831R1 "Default member initializers for bit-fields (revision 1)", the
7655 // above bit-field member initializations can be moved to the class definition
7657 fDontUseHTMLAutoSpacing = true; //default
7658 fAcetateShowAtn = true; //default
7659 const sal_uInt32 nMaxDopSize = 0x268;
7660 std::unique_ptr<sal_uInt8[]> pDataPtr( new sal_uInt8[ nMaxDopSize ] );
7661 sal_uInt8* pData = pDataPtr.get();
7663 sal_uInt32 nRead = std::min(nMaxDopSize, nSize);
7664 if (nSize < 2 || !checkSeek(rSt, nPos) || nRead != rSt.ReadBytes(pData, nRead))
7665 nDopError = ERR_SWG_READ_ERROR; // report error
7666 else
7668 if (nMaxDopSize > nRead)
7669 memset( pData + nRead, 0, nMaxDopSize - nRead );
7671 // interpret the data
7672 sal_uInt32 a32Bit;
7673 sal_uInt16 a16Bit;
7674 sal_uInt8 a8Bit;
7676 a16Bit = Get_UShort( pData ); // 0 0x00
7677 fFacingPages = 0 != ( a16Bit & 0x0001 ) ;
7678 fWidowControl = 0 != ( a16Bit & 0x0002 ) ;
7679 fPMHMainDoc = 0 != ( a16Bit & 0x0004 ) ;
7680 grfSuppression = ( a16Bit & 0x0018 ) >> 3;
7681 fpc = ( a16Bit & 0x0060 ) >> 5;
7682 grpfIhdt = ( a16Bit & 0xff00 ) >> 8;
7684 a16Bit = Get_UShort( pData ); // 2 0x02
7685 rncFootnote = a16Bit & 0x0003 ;
7686 nFootnote = ( a16Bit & ~0x0003 ) >> 2 ;
7688 a8Bit = Get_Byte( pData ); // 4 0x04
7689 fOutlineDirtySave = 0 != ( a8Bit & 0x01 );
7691 a8Bit = Get_Byte( pData ); // 5 0x05
7692 fOnlyMacPics = 0 != ( a8Bit & 0x01 );
7693 fOnlyWinPics = 0 != ( a8Bit & 0x02 );
7694 fLabelDoc = 0 != ( a8Bit & 0x04 );
7695 fHyphCapitals = 0 != ( a8Bit & 0x08 );
7696 fAutoHyphen = 0 != ( a8Bit & 0x10 );
7697 fFormNoFields = 0 != ( a8Bit & 0x20 );
7698 fLinkStyles = 0 != ( a8Bit & 0x40 );
7699 fRevMarking = 0 != ( a8Bit & 0x80 );
7701 a8Bit = Get_Byte( pData ); // 6 0x06
7702 fBackup = 0 != ( a8Bit & 0x01 );
7703 fExactCWords = 0 != ( a8Bit & 0x02 );
7704 fPagHidden = 0 != ( a8Bit & 0x04 );
7705 fPagResults = 0 != ( a8Bit & 0x08 );
7706 fLockAtn = 0 != ( a8Bit & 0x10 );
7707 fMirrorMargins = 0 != ( a8Bit & 0x20 );
7708 fReadOnlyRecommended = 0 != ( a8Bit & 0x40 );
7709 fDfltTrueType = 0 != ( a8Bit & 0x80 );
7711 a8Bit = Get_Byte( pData ); // 7 0x07
7712 fPagSuppressTopSpacing = 0 != ( a8Bit & 0x01 );
7713 fProtEnabled = 0 != ( a8Bit & 0x02 );
7714 fDispFormFieldSel = 0 != ( a8Bit & 0x04 );
7715 fRMView = 0 != ( a8Bit & 0x08 );
7716 fRMPrint = 0 != ( a8Bit & 0x10 );
7717 fWriteReservation = 0 != ( a8Bit & 0x20 );
7718 fLockRev = 0 != ( a8Bit & 0x40 );
7719 fEmbedFonts = 0 != ( a8Bit & 0x80 );
7721 a8Bit = Get_Byte( pData ); // 8 0x08
7722 copts_fNoTabForInd = 0 != ( a8Bit & 0x01 );
7723 copts_fNoSpaceRaiseLower = 0 != ( a8Bit & 0x02 );
7724 copts_fSuppressSpbfAfterPgBrk = 0 != ( a8Bit & 0x04 );
7725 copts_fWrapTrailSpaces = 0 != ( a8Bit & 0x08 );
7726 copts_fMapPrintTextColor = 0 != ( a8Bit & 0x10 );
7727 copts_fNoColumnBalance = 0 != ( a8Bit & 0x20 );
7728 copts_fConvMailMergeEsc = 0 != ( a8Bit & 0x40 );
7729 copts_fSuppressTopSpacing = 0 != ( a8Bit & 0x80 );
7731 a8Bit = Get_Byte( pData ); // 9 0x09
7732 copts_fOrigWordTableRules = 0 != ( a8Bit & 0x01 );
7733 copts_fTransparentMetafiles = 0 != ( a8Bit & 0x02 );
7734 copts_fShowBreaksInFrames = 0 != ( a8Bit & 0x04 );
7735 copts_fSwapBordersFacingPgs = 0 != ( a8Bit & 0x08 );
7736 copts_fExpShRtn = 0 != ( a8Bit & 0x20 ); // #i56856#
7738 dxaTab = Get_Short( pData ); // 10 0x0a
7739 wSpare = Get_UShort( pData ); // 12 0x0c
7740 dxaHotZ = Get_UShort( pData ); // 14 0x0e
7741 cConsecHypLim = Get_UShort( pData ); // 16 0x10
7742 wSpare2 = Get_UShort( pData ); // 18 0x12
7743 dttmCreated = Get_Long( pData ); // 20 0x14
7744 dttmRevised = Get_Long( pData ); // 24 0x18
7745 dttmLastPrint = Get_Long( pData ); // 28 0x1c
7746 nRevision = Get_Short( pData ); // 32 0x20
7747 tmEdited = Get_Long( pData ); // 34 0x22
7748 cWords = Get_Long( pData ); // 38 0x26
7749 cCh = Get_Long( pData ); // 42 0x2a
7750 cPg = Get_Short( pData ); // 46 0x2e
7751 cParas = Get_Long( pData ); // 48 0x30
7753 a16Bit = Get_UShort( pData ); // 52 0x34
7754 rncEdn = a16Bit & 0x0003 ;
7755 nEdn = ( a16Bit & ~0x0003 ) >> 2;
7757 a16Bit = Get_UShort( pData ); // 54 0x36
7758 epc = a16Bit & 0x0003 ;
7759 nfcFootnoteRef = ( a16Bit & 0x003c ) >> 2;
7760 nfcEdnRef = ( a16Bit & 0x03c0 ) >> 6;
7761 fPrintFormData = 0 != ( a16Bit & 0x0400 );
7762 fSaveFormData = 0 != ( a16Bit & 0x0800 );
7763 fShadeFormData = 0 != ( a16Bit & 0x1000 );
7764 fWCFootnoteEdn = 0 != ( a16Bit & 0x8000 );
7766 cLines = Get_Long( pData ); // 56 0x38
7767 cWordsFootnoteEnd = Get_Long( pData ); // 60 0x3c
7768 cChFootnoteEdn = Get_Long( pData ); // 64 0x40
7769 cPgFootnoteEdn = Get_Short( pData ); // 68 0x44
7770 cParasFootnoteEdn = Get_Long( pData ); // 70 0x46
7771 cLinesFootnoteEdn = Get_Long( pData ); // 74 0x4a
7772 lKeyProtDoc = Get_Long( pData ); // 78 0x4e
7774 a16Bit = Get_UShort( pData ); // 82 0x52
7775 wvkSaved = a16Bit & 0x0007 ;
7776 wScaleSaved = ( a16Bit & 0x0ff8 ) >> 3 ;
7777 zkSaved = ( a16Bit & 0x3000 ) >> 12;
7778 fRotateFontW6 = ( a16Bit & 0x4000 ) >> 14;
7779 iGutterPos = ( a16Bit & 0x8000 ) >> 15;
7781 if (nFib >= 103) // Word 6/32bit, 95, 97, 2000, 2002, 2003, 2007
7783 a32Bit = Get_ULong( pData ); // 84 0x54
7784 SetCompatibilityOptions(a32Bit);
7787 //#i22436#, for all WW7- documents
7788 if (nFib <= 104) // Word 95
7789 fUsePrinterMetrics = true;
7791 if (nFib > 105) // Word 97, 2000, 2002, 2003, 2007
7793 adt = Get_Short( pData ); // 88 0x58
7795 doptypography.ReadFromMem(pData); // 90 0x5a
7797 memcpy( &dogrid, pData, sizeof( WW8_DOGRID )); // 400 0x190
7798 pData += sizeof( WW8_DOGRID );
7800 a16Bit = Get_UShort( pData ); // 410 0x19a
7801 // the following 9 bit are uninteresting
7802 fHtmlDoc = ( a16Bit & 0x0200 ) >> 9 ;
7803 fSnapBorder = ( a16Bit & 0x0800 ) >> 11 ;
7804 fIncludeHeader = ( a16Bit & 0x1000 ) >> 12 ;
7805 fIncludeFooter = ( a16Bit & 0x2000 ) >> 13 ;
7806 fForcePageSizePag = ( a16Bit & 0x4000 ) >> 14 ;
7807 fMinFontSizePag = ( a16Bit & 0x8000 ) >> 15 ;
7809 a16Bit = Get_UShort( pData ); // 412 0x19c
7810 fHaveVersions = 0 != ( a16Bit & 0x0001 );
7811 fAutoVersion = 0 != ( a16Bit & 0x0002 );
7813 pData += 12; // 414 0x19e
7815 cChWS = Get_Long( pData ); // 426 0x1aa
7816 cChWSFootnoteEdn = Get_Long( pData ); // 430 0x1ae
7817 grfDocEvents = Get_Long( pData ); // 434 0x1b2
7819 pData += 4+30+8; // 438 0x1b6; 442 0x1ba; 472 0x1d8; 476 0x1dc
7821 cDBC = Get_Long( pData ); // 480 0x1e0
7822 cDBCFootnoteEdn = Get_Long( pData ); // 484 0x1e4
7824 pData += 1 * sizeof( sal_Int32); // 488 0x1e8
7826 nfcFootnoteRef = Get_Short( pData ); // 492 0x1ec
7827 nfcEdnRef = Get_Short( pData ); // 494 0x1ee
7828 hpsZoomFontPag = Get_Short( pData ); // 496 0x1f0
7829 dywDispPag = Get_Short( pData ); // 498 0x1f2
7831 if (nRead >= 516)
7833 //500 -> 508, Appear to be repeated here in 2000+
7834 pData += 8; // 500 0x1f4
7835 a32Bit = Get_Long( pData ); // 508 0x1fc
7836 SetCompatibilityOptions(a32Bit);
7837 a32Bit = Get_Long( pData ); // 512 0x200
7839 // i#78591#
7840 SetCompatibilityOptions2(a32Bit);
7842 if (nRead >= 550)
7844 pData += 32;
7845 a16Bit = Get_UShort( pData );
7846 fDoNotEmbedSystemFont = ( a16Bit & 0x0001 );
7847 fWordCompat = ( a16Bit & 0x0002 ) >> 1;
7848 fLiveRecover = ( a16Bit & 0x0004 ) >> 2;
7849 fEmbedFactoids = ( a16Bit & 0x0008 ) >> 3;
7850 fFactoidXML = ( a16Bit & 0x00010 ) >> 4;
7851 fFactoidAllDone = ( a16Bit & 0x0020 ) >> 5;
7852 fFolioPrint = ( a16Bit & 0x0040 ) >> 6;
7853 fReverseFolio = ( a16Bit & 0x0080 ) >> 7;
7854 iTextLineEnding = ( a16Bit & 0x0700 ) >> 8;
7855 fHideFcc = ( a16Bit & 0x0800 ) >> 11;
7856 fAcetateShowMarkup = ( a16Bit & 0x1000 ) >> 12;
7857 fAcetateShowAtn = ( a16Bit & 0x2000 ) >> 13;
7858 fAcetateShowInsDel = ( a16Bit & 0x4000 ) >> 14;
7859 fAcetateShowProps = ( a16Bit & 0x8000 ) >> 15;
7861 if (nRead >= 600)
7863 pData += 48;
7864 a16Bit = Get_Short(pData);
7865 fUseBackGroundInAllmodes = (a16Bit & 0x0080) >> 7;
7871 WW8Dop::WW8Dop():
7872 fFacingPages(false), fWidowControl(true), fPMHMainDoc(false), grfSuppression(0), fpc(1),
7873 grpfIhdt(0), rncFootnote(0), nFootnote(1), fOutlineDirtySave(true), fOnlyMacPics(false),
7874 fOnlyWinPics(false), fLabelDoc(false), fHyphCapitals(true), fAutoHyphen(false),
7875 fFormNoFields(false), fLinkStyles(false), fRevMarking(false), fBackup(true),
7876 fExactCWords(false), fPagHidden(true), fPagResults(true), fLockAtn(false),
7877 fMirrorMargins(false), fReadOnlyRecommended(false), fDfltTrueType(true),
7878 fPagSuppressTopSpacing(false), fProtEnabled(false), fDispFormFieldSel(false), fRMView(true),
7879 fRMPrint(true), fWriteReservation(false), fLockRev(false), fEmbedFonts(false),
7880 copts_fNoTabForInd(false), copts_fNoSpaceRaiseLower(false), copts_fSuppressSpbfAfterPgBrk(false),
7881 copts_fWrapTrailSpaces(false), copts_fMapPrintTextColor(false), copts_fNoColumnBalance(false),
7882 copts_fConvMailMergeEsc(false), copts_fSuppressTopSpacing(false),
7883 copts_fOrigWordTableRules(false), copts_fTransparentMetafiles(false),
7884 copts_fShowBreaksInFrames(false), copts_fSwapBordersFacingPgs(false), copts_fExpShRtn(false),
7885 dxaTab(0x2d0), dxaHotZ(0x168), nRevision(1),
7886 rncEdn(0), nEdn(1), epc(3), fPrintFormData(false), fSaveFormData(false), fShadeFormData(true),
7887 fWCFootnoteEdn(false), wvkSaved(2), wScaleSaved(100), zkSaved(0), fRotateFontW6(false),
7888 iGutterPos(false), fNoTabForInd(false), fNoSpaceRaiseLower(false),
7889 fSuppressSpbfAfterPageBreak(false), fWrapTrailSpaces(false), fMapPrintTextColor(false),
7890 fNoColumnBalance(false), fConvMailMergeEsc(false), fSuppressTopSpacing(false),
7891 fOrigWordTableRules(false), fTransparentMetafiles(false), fShowBreaksInFrames(false),
7892 fSwapBordersFacingPgs(false), fCompatibilityOptions_Unknown1_13(false), fExpShRtn(false),
7893 fCompatibilityOptions_Unknown1_15(false), fCompatibilityOptions_Unknown1_16(false),
7894 fSuppressTopSpacingMac5(false), fTruncDxaExpand(false), fPrintBodyBeforeHdr(false),
7895 fNoLeading(true), fCompatibilityOptions_Unknown1_21(false), fMWSmallCaps(false),
7896 fCompatibilityOptions_Unknown1_23(false), fCompatibilityOptions_Unknown1_24(false),
7897 fCompatibilityOptions_Unknown1_25(false), fCompatibilityOptions_Unknown1_26(false),
7898 fCompatibilityOptions_Unknown1_27(false), fCompatibilityOptions_Unknown1_28(false),
7899 fCompatibilityOptions_Unknown1_29(false), fCompatibilityOptions_Unknown1_30(false),
7900 fCompatibilityOptions_Unknown1_31(false), fUsePrinterMetrics(true), lvl(9), fHtmlDoc(false),
7901 fSnapBorder(false), fIncludeHeader(true), fIncludeFooter(true), fForcePageSizePag(false),
7902 fMinFontSizePag(false), fHaveVersions(false), fAutoVersion(false),
7903 cChWS(0), cChWSFootnoteEdn(0), cDBC(0), cDBCFootnoteEdn(0), nfcEdnRef(2),
7904 fCompatibilityOptions_Unknown2_1(false), fCompatibilityOptions_Unknown2_2(false),
7905 fDontUseHTMLAutoSpacing(false), fCompatibilityOptions_Unknown2_4(false),
7906 fCompatibilityOptions_Unknown2_5(false), fCompatibilityOptions_Unknown2_6(false),
7907 fCompatibilityOptions_Unknown2_7(false), fCompatibilityOptions_Unknown2_8(false),
7908 fCompatibilityOptions_Unknown2_9(false), fCompatibilityOptions_Unknown2_10(false),
7909 fDontBreakWrappedTables(false), fCompatibilityOptions_Unknown2_12(false),
7910 fCompatibilityOptions_Unknown2_13(false), fCompatibilityOptions_Unknown2_14(false),
7911 fCompatibilityOptions_Unknown2_15(false), fCompatibilityOptions_Unknown2_16(false),
7912 fCompatibilityOptions_Unknown2_17(false), fCompatibilityOptions_Unknown2_18(false),
7913 fCompatibilityOptions_Unknown2_19(false), fCompatibilityOptions_Unknown2_20(false),
7914 fCompatibilityOptions_Unknown2_21(false), fCompatibilityOptions_Unknown2_22(false),
7915 fCompatibilityOptions_Unknown2_23(false), fCompatibilityOptions_Unknown2_24(false),
7916 fCompatibilityOptions_Unknown2_25(false), fCompatibilityOptions_Unknown2_26(false),
7917 fCompatibilityOptions_Unknown2_27(false), fCompatibilityOptions_Unknown2_28(false),
7918 fCompatibilityOptions_Unknown2_29(false), fCompatibilityOptions_Unknown2_30(false),
7919 fCompatibilityOptions_Unknown2_31(false), fCompatibilityOptions_Unknown2_32(false),
7920 fUnknown3(0), fUseBackGroundInAllmodes(false), fDoNotEmbedSystemFont(false), fWordCompat(false),
7921 fLiveRecover(false), fEmbedFactoids(false), fFactoidXML(false), fFactoidAllDone(false),
7922 fFolioPrint(false), fReverseFolio(false), iTextLineEnding(0), fHideFcc(false),
7923 fAcetateShowMarkup(false), fAcetateShowAtn(true), fAcetateShowInsDel(false),
7924 fAcetateShowProps(false)
7925 // in C++20 with P06831R1 "Default member initializers for bit-fields (revision 1)", the
7926 // above bit-field member initializations can be moved to the class definition
7929 Writer acts like this all the time at the moment, ideally we need an
7930 option for these two as well to import word docs that are not like
7931 this by default
7933 // put in initialization list
7934 // fNoLeading = true;
7935 //fUsePrinterMetrics = true;
7938 void WW8Dop::SetCompatibilityOptions(sal_uInt32 a32Bit)
7940 fNoTabForInd = ( a32Bit & 0x00000001 ) ;
7941 fNoSpaceRaiseLower = ( a32Bit & 0x00000002 ) >> 1 ;
7942 fSuppressSpbfAfterPageBreak = ( a32Bit & 0x00000004 ) >> 2 ;
7943 fWrapTrailSpaces = ( a32Bit & 0x00000008 ) >> 3 ;
7944 fMapPrintTextColor = ( a32Bit & 0x00000010 ) >> 4 ;
7945 fNoColumnBalance = ( a32Bit & 0x00000020 ) >> 5 ;
7946 fConvMailMergeEsc = ( a32Bit & 0x00000040 ) >> 6 ;
7947 fSuppressTopSpacing = ( a32Bit & 0x00000080 ) >> 7 ;
7948 fOrigWordTableRules = ( a32Bit & 0x00000100 ) >> 8 ;
7949 fTransparentMetafiles = ( a32Bit & 0x00000200 ) >> 9 ;
7950 fShowBreaksInFrames = ( a32Bit & 0x00000400 ) >> 10 ;
7951 fSwapBordersFacingPgs = ( a32Bit & 0x00000800 ) >> 11 ;
7952 fCompatibilityOptions_Unknown1_13 = ( a32Bit & 0x00001000 ) >> 12 ;
7953 fExpShRtn = ( a32Bit & 0x00002000 ) >> 13 ; // #i56856#
7954 fCompatibilityOptions_Unknown1_15 = ( a32Bit & 0x00004000 ) >> 14 ;
7955 fCompatibilityOptions_Unknown1_16 = ( a32Bit & 0x00008000 ) >> 15 ;
7956 fSuppressTopSpacingMac5 = ( a32Bit & 0x00010000 ) >> 16 ;
7957 fTruncDxaExpand = ( a32Bit & 0x00020000 ) >> 17 ;
7958 fPrintBodyBeforeHdr = ( a32Bit & 0x00040000 ) >> 18 ;
7959 fNoLeading = ( a32Bit & 0x00080000 ) >> 19 ;
7960 fCompatibilityOptions_Unknown1_21 = ( a32Bit & 0x00100000 ) >> 20 ;
7961 fMWSmallCaps = ( a32Bit & 0x00200000 ) >> 21 ;
7962 fCompatibilityOptions_Unknown1_23 = ( a32Bit & 0x00400000 ) >> 22 ;
7963 fCompatibilityOptions_Unknown1_24 = ( a32Bit & 0x00800800 ) >> 23 ;
7964 fCompatibilityOptions_Unknown1_25 = ( a32Bit & 0x01000000 ) >> 24 ;
7965 fCompatibilityOptions_Unknown1_26 = ( a32Bit & 0x02000000 ) >> 25 ;
7966 fCompatibilityOptions_Unknown1_27 = ( a32Bit & 0x04000000 ) >> 26 ;
7967 fCompatibilityOptions_Unknown1_28 = ( a32Bit & 0x08000000 ) >> 27 ;
7968 fCompatibilityOptions_Unknown1_29 = ( a32Bit & 0x10000000 ) >> 28 ;
7969 fCompatibilityOptions_Unknown1_30 = ( a32Bit & 0x20000000 ) >> 29 ;
7970 fCompatibilityOptions_Unknown1_31 = ( a32Bit & 0x40000000 ) >> 30 ;
7972 fUsePrinterMetrics = ( a32Bit & 0x80000000 ) >> 31 ;
7975 sal_uInt32 WW8Dop::GetCompatibilityOptions() const
7977 sal_uInt32 a32Bit = 0;
7978 if (fNoTabForInd) a32Bit |= 0x00000001;
7979 if (fNoSpaceRaiseLower) a32Bit |= 0x00000002;
7980 if (fSuppressSpbfAfterPageBreak) a32Bit |= 0x00000004;
7981 if (fWrapTrailSpaces) a32Bit |= 0x00000008;
7982 if (fMapPrintTextColor) a32Bit |= 0x00000010;
7983 if (fNoColumnBalance) a32Bit |= 0x00000020;
7984 if (fConvMailMergeEsc) a32Bit |= 0x00000040;
7985 if (fSuppressTopSpacing) a32Bit |= 0x00000080;
7986 if (fOrigWordTableRules) a32Bit |= 0x00000100;
7987 if (fTransparentMetafiles) a32Bit |= 0x00000200;
7988 if (fShowBreaksInFrames) a32Bit |= 0x00000400;
7989 if (fSwapBordersFacingPgs) a32Bit |= 0x00000800;
7990 if (fCompatibilityOptions_Unknown1_13) a32Bit |= 0x00001000;
7991 if (fExpShRtn) a32Bit |= 0x00002000; // #i56856#
7992 if (fCompatibilityOptions_Unknown1_15) a32Bit |= 0x00004000;
7993 if (fCompatibilityOptions_Unknown1_16) a32Bit |= 0x00008000;
7994 if (fSuppressTopSpacingMac5) a32Bit |= 0x00010000;
7995 if (fTruncDxaExpand) a32Bit |= 0x00020000;
7996 if (fPrintBodyBeforeHdr) a32Bit |= 0x00040000;
7997 if (fNoLeading) a32Bit |= 0x00080000;
7998 if (fCompatibilityOptions_Unknown1_21) a32Bit |= 0x00100000;
7999 if (fMWSmallCaps) a32Bit |= 0x00200000;
8000 if (fCompatibilityOptions_Unknown1_23) a32Bit |= 0x00400000;
8001 if (fCompatibilityOptions_Unknown1_24) a32Bit |= 0x00800000;
8002 if (fCompatibilityOptions_Unknown1_25) a32Bit |= 0x01000000;
8003 if (fCompatibilityOptions_Unknown1_26) a32Bit |= 0x02000000;
8004 if (fCompatibilityOptions_Unknown1_27) a32Bit |= 0x04000000;
8005 if (fCompatibilityOptions_Unknown1_28) a32Bit |= 0x08000000;
8006 if (fCompatibilityOptions_Unknown1_29) a32Bit |= 0x10000000;
8007 if (fCompatibilityOptions_Unknown1_30) a32Bit |= 0x20000000;
8008 if (fCompatibilityOptions_Unknown1_31) a32Bit |= 0x40000000;
8009 if (fUsePrinterMetrics) a32Bit |= 0x80000000;
8010 return a32Bit;
8013 // i#78591#
8014 void WW8Dop::SetCompatibilityOptions2(sal_uInt32 a32Bit)
8016 fCompatibilityOptions_Unknown2_1 = ( a32Bit & 0x00000001 );
8017 fCompatibilityOptions_Unknown2_2 = ( a32Bit & 0x00000002 ) >> 1 ;
8018 fDontUseHTMLAutoSpacing = ( a32Bit & 0x00000004 ) >> 2 ;
8019 fCompatibilityOptions_Unknown2_4 = ( a32Bit & 0x00000008 ) >> 3 ;
8020 fCompatibilityOptions_Unknown2_5 = ( a32Bit & 0x00000010 ) >> 4 ;
8021 fCompatibilityOptions_Unknown2_6 = ( a32Bit & 0x00000020 ) >> 5 ;
8022 fCompatibilityOptions_Unknown2_7 = ( a32Bit & 0x00000040 ) >> 6 ;
8023 fCompatibilityOptions_Unknown2_8 = ( a32Bit & 0x00000080 ) >> 7 ;
8024 fCompatibilityOptions_Unknown2_9 = ( a32Bit & 0x00000100 ) >> 8 ;
8025 fCompatibilityOptions_Unknown2_10 = ( a32Bit & 0x00000200 ) >> 9 ;
8026 fDontBreakWrappedTables = ( a32Bit & 0x00000400 ) >> 10 ;
8027 fCompatibilityOptions_Unknown2_12 = ( a32Bit & 0x00000800 ) >> 11 ;
8028 fCompatibilityOptions_Unknown2_13 = ( a32Bit & 0x00001000 ) >> 12 ;
8029 fCompatibilityOptions_Unknown2_14 = ( a32Bit & 0x00002000 ) >> 13 ;
8030 fCompatibilityOptions_Unknown2_15 = ( a32Bit & 0x00004000 ) >> 14 ;
8031 fCompatibilityOptions_Unknown2_16 = ( a32Bit & 0x00008000 ) >> 15 ;
8032 fCompatibilityOptions_Unknown2_17 = ( a32Bit & 0x00010000 ) >> 16 ;
8033 fCompatibilityOptions_Unknown2_18 = ( a32Bit & 0x00020000 ) >> 17 ;
8034 fCompatibilityOptions_Unknown2_19 = ( a32Bit & 0x00040000 ) >> 18 ;
8035 fCompatibilityOptions_Unknown2_20 = ( a32Bit & 0x00080000 ) >> 19 ;
8036 fCompatibilityOptions_Unknown2_21 = ( a32Bit & 0x00100000 ) >> 20 ;
8037 fCompatibilityOptions_Unknown2_22 = ( a32Bit & 0x00200000 ) >> 21 ;
8038 fCompatibilityOptions_Unknown2_23 = ( a32Bit & 0x00400000 ) >> 22 ;
8039 fCompatibilityOptions_Unknown2_24 = ( a32Bit & 0x00800800 ) >> 23 ;
8040 fCompatibilityOptions_Unknown2_25 = ( a32Bit & 0x01000800 ) >> 24 ;
8041 fCompatibilityOptions_Unknown2_26 = ( a32Bit & 0x02000800 ) >> 25 ;
8042 fCompatibilityOptions_Unknown2_27 = ( a32Bit & 0x04000800 ) >> 26 ;
8043 fCompatibilityOptions_Unknown2_28 = ( a32Bit & 0x08000800 ) >> 27 ;
8044 fCompatibilityOptions_Unknown2_29 = ( a32Bit & 0x10000800 ) >> 28 ;
8045 fCompatibilityOptions_Unknown2_30 = ( a32Bit & 0x20000800 ) >> 29 ;
8046 fCompatibilityOptions_Unknown2_31 = ( a32Bit & 0x40000800 ) >> 30 ;
8047 fCompatibilityOptions_Unknown2_32 = ( a32Bit & 0x80000000 ) >> 31 ;
8050 sal_uInt32 WW8Dop::GetCompatibilityOptions2() const
8052 sal_uInt32 a32Bit = 0;
8053 if (fCompatibilityOptions_Unknown2_1) a32Bit |= 0x00000001;
8054 if (fCompatibilityOptions_Unknown2_2) a32Bit |= 0x00000002;
8055 if (fDontUseHTMLAutoSpacing) a32Bit |= 0x00000004;
8056 if (fCompatibilityOptions_Unknown2_4) a32Bit |= 0x00000008;
8057 if (fCompatibilityOptions_Unknown2_5) a32Bit |= 0x00000010;
8058 if (fCompatibilityOptions_Unknown2_6) a32Bit |= 0x00000020;
8059 if (fCompatibilityOptions_Unknown2_7) a32Bit |= 0x00000040;
8060 if (fCompatibilityOptions_Unknown2_8) a32Bit |= 0x00000080;
8061 if (fCompatibilityOptions_Unknown2_9) a32Bit |= 0x00000100;
8062 if (fCompatibilityOptions_Unknown2_10) a32Bit |= 0x00000200;
8063 if (fDontBreakWrappedTables) a32Bit |= 0x00000400;
8064 if (fCompatibilityOptions_Unknown2_12) a32Bit |= 0x00000800;
8065 if (fCompatibilityOptions_Unknown2_13) a32Bit |= 0x00001000;
8066 //#i42909# set thai "line breaking rules" compatibility option
8067 // pflin, wonder whether bUseThaiLineBreakingRules is correct
8068 // when importing word document.
8069 if (bUseThaiLineBreakingRules) a32Bit |= 0x00002000;
8070 else if (fCompatibilityOptions_Unknown2_14) a32Bit |= 0x00002000;
8071 if (fCompatibilityOptions_Unknown2_15) a32Bit |= 0x00004000;
8072 if (fCompatibilityOptions_Unknown2_16) a32Bit |= 0x00008000;
8073 if (fCompatibilityOptions_Unknown2_17) a32Bit |= 0x00010000;
8074 if (fCompatibilityOptions_Unknown2_18) a32Bit |= 0x00020000;
8075 if (fCompatibilityOptions_Unknown2_19) a32Bit |= 0x00040000;
8076 if (fCompatibilityOptions_Unknown2_20) a32Bit |= 0x00080000;
8077 if (fCompatibilityOptions_Unknown2_21) a32Bit |= 0x00100000;
8078 if (fCompatibilityOptions_Unknown2_22) a32Bit |= 0x00200000;
8079 if (fCompatibilityOptions_Unknown2_23) a32Bit |= 0x00400000;
8080 if (fCompatibilityOptions_Unknown2_24) a32Bit |= 0x00800000;
8081 if (fCompatibilityOptions_Unknown2_25) a32Bit |= 0x01000000;
8082 if (fCompatibilityOptions_Unknown2_26) a32Bit |= 0x02000000;
8083 if (fCompatibilityOptions_Unknown2_27) a32Bit |= 0x04000000;
8084 if (fCompatibilityOptions_Unknown2_28) a32Bit |= 0x08000000;
8085 if (fCompatibilityOptions_Unknown2_29) a32Bit |= 0x10000000;
8086 if (fCompatibilityOptions_Unknown2_30) a32Bit |= 0x20000000;
8087 if (fCompatibilityOptions_Unknown2_31) a32Bit |= 0x40000000;
8088 if (fCompatibilityOptions_Unknown2_32) a32Bit |= 0x80000000;
8089 return a32Bit;
8092 void WW8Dop::Write(SvStream& rStrm, WW8Fib& rFib) const
8094 const int nMaxDopLen = 610;
8095 sal_uInt32 nLen = 8 == rFib.m_nVersion ? nMaxDopLen : 84;
8096 rFib.m_fcDop = rStrm.Tell();
8097 rFib.m_lcbDop = nLen;
8099 sal_uInt8 aData[ nMaxDopLen ] = {};
8100 sal_uInt8* pData = aData;
8102 // analyse the data
8103 sal_uInt16 a16Bit;
8104 sal_uInt8 a8Bit;
8106 a16Bit = 0; // 0 0x00
8107 if (fFacingPages)
8108 a16Bit |= 0x0001;
8109 if (fWidowControl)
8110 a16Bit |= 0x0002;
8111 if (fPMHMainDoc)
8112 a16Bit |= 0x0004;
8113 a16Bit |= ( 0x0018 & (grfSuppression << 3));
8114 a16Bit |= ( 0x0060 & (fpc << 5));
8115 a16Bit |= ( 0xff00 & (grpfIhdt << 8));
8116 Set_UInt16( pData, a16Bit );
8118 a16Bit = 0; // 2 0x02
8119 a16Bit |= ( 0x0003 & rncFootnote );
8120 a16Bit |= ( ~0x0003 & (nFootnote << 2));
8121 Set_UInt16( pData, a16Bit );
8123 a8Bit = 0; // 4 0x04
8124 if( fOutlineDirtySave ) a8Bit |= 0x01;
8125 Set_UInt8( pData, a8Bit );
8127 a8Bit = 0; // 5 0x05
8128 if( fOnlyMacPics ) a8Bit |= 0x01;
8129 if( fOnlyWinPics ) a8Bit |= 0x02;
8130 if( fLabelDoc ) a8Bit |= 0x04;
8131 if( fHyphCapitals ) a8Bit |= 0x08;
8132 if( fAutoHyphen ) a8Bit |= 0x10;
8133 if( fFormNoFields ) a8Bit |= 0x20;
8134 if( fLinkStyles ) a8Bit |= 0x40;
8135 if( fRevMarking ) a8Bit |= 0x80;
8136 Set_UInt8( pData, a8Bit );
8138 a8Bit = 0; // 6 0x06
8139 if( fBackup ) a8Bit |= 0x01;
8140 if( fExactCWords ) a8Bit |= 0x02;
8141 if( fPagHidden ) a8Bit |= 0x04;
8142 if( fPagResults ) a8Bit |= 0x08;
8143 if( fLockAtn ) a8Bit |= 0x10;
8144 if( fMirrorMargins ) a8Bit |= 0x20;
8145 if( fReadOnlyRecommended ) a8Bit |= 0x40;
8146 if( fDfltTrueType ) a8Bit |= 0x80;
8147 Set_UInt8( pData, a8Bit );
8149 a8Bit = 0; // 7 0x07
8150 if( fPagSuppressTopSpacing ) a8Bit |= 0x01;
8151 if( fProtEnabled ) a8Bit |= 0x02;
8152 if( fDispFormFieldSel ) a8Bit |= 0x04;
8153 if( fRMView ) a8Bit |= 0x08;
8154 if( fRMPrint ) a8Bit |= 0x10;
8155 if( fWriteReservation ) a8Bit |= 0x20;
8156 if( fLockRev ) a8Bit |= 0x40;
8157 if( fEmbedFonts ) a8Bit |= 0x80;
8158 Set_UInt8( pData, a8Bit );
8160 a8Bit = 0; // 8 0x08
8161 if( copts_fNoTabForInd ) a8Bit |= 0x01;
8162 if( copts_fNoSpaceRaiseLower ) a8Bit |= 0x02;
8163 if( copts_fSuppressSpbfAfterPgBrk ) a8Bit |= 0x04;
8164 if( copts_fWrapTrailSpaces ) a8Bit |= 0x08;
8165 if( copts_fMapPrintTextColor ) a8Bit |= 0x10;
8166 if( copts_fNoColumnBalance ) a8Bit |= 0x20;
8167 if( copts_fConvMailMergeEsc ) a8Bit |= 0x40;
8168 if( copts_fSuppressTopSpacing ) a8Bit |= 0x80;
8169 Set_UInt8( pData, a8Bit );
8171 a8Bit = 0; // 9 0x09
8172 if( copts_fOrigWordTableRules ) a8Bit |= 0x01;
8173 if( copts_fTransparentMetafiles ) a8Bit |= 0x02;
8174 if( copts_fShowBreaksInFrames ) a8Bit |= 0x04;
8175 if( copts_fSwapBordersFacingPgs ) a8Bit |= 0x08;
8176 if( copts_fExpShRtn ) a8Bit |= 0x20; // #i56856#
8177 Set_UInt8( pData, a8Bit );
8179 Set_UInt16( pData, dxaTab ); // 10 0x0a
8180 Set_UInt16( pData, wSpare ); // 12 0x0c
8181 Set_UInt16( pData, dxaHotZ ); // 14 0x0e
8182 Set_UInt16( pData, cConsecHypLim ); // 16 0x10
8183 Set_UInt16( pData, wSpare2 ); // 18 0x12
8184 Set_UInt32( pData, dttmCreated ); // 20 0x14
8185 Set_UInt32( pData, dttmRevised ); // 24 0x18
8186 Set_UInt32( pData, dttmLastPrint ); // 28 0x1c
8187 Set_UInt16( pData, nRevision ); // 32 0x20
8188 Set_UInt32( pData, tmEdited ); // 34 0x22
8189 Set_UInt32( pData, cWords ); // 38 0x26
8190 Set_UInt32( pData, cCh ); // 42 0x2a
8191 Set_UInt16( pData, cPg ); // 46 0x2e
8192 Set_UInt32( pData, cParas ); // 48 0x30
8194 a16Bit = 0; // 52 0x34
8195 a16Bit |= ( 0x0003 & rncEdn );
8196 a16Bit |= (~0x0003 & ( nEdn << 2));
8197 Set_UInt16( pData, a16Bit );
8199 a16Bit = 0; // 54 0x36
8200 a16Bit |= (0x0003 & epc );
8201 a16Bit |= (0x003c & (nfcFootnoteRef << 2));
8202 a16Bit |= (0x03c0 & (nfcEdnRef << 6));
8203 if( fPrintFormData ) a16Bit |= 0x0400;
8204 if( fSaveFormData ) a16Bit |= 0x0800;
8205 if( fShadeFormData ) a16Bit |= 0x1000;
8206 if( fWCFootnoteEdn ) a16Bit |= 0x8000;
8207 Set_UInt16( pData, a16Bit );
8209 Set_UInt32( pData, cLines ); // 56 0x38
8210 Set_UInt32( pData, cWordsFootnoteEnd ); // 60 0x3c
8211 Set_UInt32( pData, cChFootnoteEdn ); // 64 0x40
8212 Set_UInt16( pData, cPgFootnoteEdn ); // 68 0x44
8213 Set_UInt32( pData, cParasFootnoteEdn ); // 70 0x46
8214 Set_UInt32( pData, cLinesFootnoteEdn ); // 74 0x4a
8215 Set_UInt32( pData, lKeyProtDoc ); // 78 0x4e
8217 a16Bit = 0; // 82 0x52
8218 if (wvkSaved)
8219 a16Bit |= 0x0007;
8220 a16Bit |= (0x0ff8 & (wScaleSaved << 3));
8221 a16Bit |= (0x3000 & (zkSaved << 12));
8222 if (iGutterPos)
8224 // Last bit: gutter at top.
8225 a16Bit |= 0x8000;
8227 Set_UInt16( pData, a16Bit );
8229 if( 8 == rFib.m_nVersion )
8231 Set_UInt32(pData, GetCompatibilityOptions()); // 84 0x54
8233 Set_UInt16( pData, adt ); // 88 0x58
8235 doptypography.WriteToMem(pData); // 400 0x190
8237 memcpy( pData, &dogrid, sizeof( WW8_DOGRID ));
8238 pData += sizeof( WW8_DOGRID );
8240 a16Bit = 0x12; // set lvl to 9 // 410 0x19a
8241 if( fHtmlDoc ) a16Bit |= 0x0200;
8242 if( fSnapBorder ) a16Bit |= 0x0800;
8243 if( fIncludeHeader ) a16Bit |= 0x1000;
8244 if( fIncludeFooter ) a16Bit |= 0x2000;
8245 if( fForcePageSizePag ) a16Bit |= 0x4000;
8246 if( fMinFontSizePag ) a16Bit |= 0x8000;
8247 Set_UInt16( pData, a16Bit );
8249 a16Bit = 0; // 412 0x19c
8250 if( fHaveVersions ) a16Bit |= 0x0001;
8251 if( fAutoVersion ) a16Bit |= 0x0002;
8252 Set_UInt16( pData, a16Bit );
8254 pData += 12; // 414 0x19e
8256 Set_UInt32( pData, cChWS ); // 426 0x1aa
8257 Set_UInt32( pData, cChWSFootnoteEdn ); // 430 0x1ae
8258 Set_UInt32( pData, grfDocEvents ); // 434 0x1b2
8260 pData += 4+30+8; // 438 0x1b6; 442 0x1ba; 472 0x1d8; 476 0x1dc
8262 Set_UInt32( pData, cDBC ); // 480 0x1e0
8263 Set_UInt32( pData, cDBCFootnoteEdn ); // 484 0x1e4
8265 pData += 1 * sizeof( sal_Int32); // 488 0x1e8
8267 Set_UInt16( pData, nfcFootnoteRef ); // 492 0x1ec
8268 Set_UInt16( pData, nfcEdnRef ); // 494 0x1ee
8269 Set_UInt16( pData, hpsZoomFontPag ); // 496 0x1f0
8270 Set_UInt16( pData, dywDispPag ); // 498 0x1f2
8272 //500 -> 508, Appear to be repeated here in 2000+
8273 pData += 8;
8274 Set_UInt32(pData, GetCompatibilityOptions());
8275 Set_UInt32(pData, GetCompatibilityOptions2());
8276 pData += 32;
8278 a16Bit = 0;
8279 if (fEmbedFactoids)
8280 a16Bit |= 0x8;
8281 if (fAcetateShowMarkup)
8282 a16Bit |= 0x1000;
8283 //Word XP at least requires fAcetateShowMarkup to honour fAcetateShowAtn
8284 if (fAcetateShowAtn)
8286 a16Bit |= 0x1000;
8287 a16Bit |= 0x2000;
8289 Set_UInt16(pData, a16Bit);
8291 pData += 48;
8292 a16Bit = 0x0080;
8293 Set_UInt16(pData, a16Bit);
8295 rStrm.WriteBytes(aData, nLen);
8298 void WW8DopTypography::ReadFromMem(sal_uInt8 *&pData)
8300 sal_uInt16 a16Bit = Get_UShort(pData);
8301 m_fKerningPunct = (a16Bit & 0x0001);
8302 m_iJustification = (a16Bit & 0x0006) >> 1;
8303 m_iLevelOfKinsoku = (a16Bit & 0x0018) >> 3;
8304 m_f2on1 = (a16Bit & 0x0020) >> 5;
8305 m_reserved1 = (a16Bit & 0x03C0) >> 6;
8306 m_reserved2 = (a16Bit & 0xFC00) >> 10;
8308 m_cchFollowingPunct = Get_Short(pData);
8309 m_cchLeadingPunct = Get_Short(pData);
8311 sal_Int16 i;
8312 for (i=0; i < nMaxFollowing; ++i)
8313 m_rgxchFPunct[i] = Get_Short(pData);
8314 for (i=0; i < nMaxLeading; ++i)
8315 m_rgxchLPunct[i] = Get_Short(pData);
8317 if (m_cchFollowingPunct >= 0 && m_cchFollowingPunct < nMaxFollowing)
8318 m_rgxchFPunct[m_cchFollowingPunct]=0;
8319 else
8320 m_rgxchFPunct[nMaxFollowing - 1]=0;
8322 if (m_cchLeadingPunct >= 0 && m_cchLeadingPunct < nMaxLeading)
8323 m_rgxchLPunct[m_cchLeadingPunct]=0;
8324 else
8325 m_rgxchLPunct[nMaxLeading - 1]=0;
8329 void WW8DopTypography::WriteToMem(sal_uInt8 *&pData) const
8331 sal_uInt16 a16Bit = sal_uInt16(m_fKerningPunct);
8332 a16Bit |= (m_iJustification << 1) & 0x0006;
8333 a16Bit |= (m_iLevelOfKinsoku << 3) & 0x0018;
8334 a16Bit |= (int(m_f2on1) << 5) & 0x0020;
8335 a16Bit |= (m_reserved1 << 6) & 0x03C0;
8336 a16Bit |= (m_reserved2 << 10) & 0xFC00;
8337 Set_UInt16(pData,a16Bit);
8339 Set_UInt16(pData,m_cchFollowingPunct);
8340 Set_UInt16(pData,m_cchLeadingPunct);
8342 sal_Int16 i;
8343 for (i=0; i < nMaxFollowing; ++i)
8344 Set_UInt16(pData,m_rgxchFPunct[i]);
8345 for (i=0; i < nMaxLeading; ++i)
8346 Set_UInt16(pData,m_rgxchLPunct[i]);
8349 LanguageType WW8DopTypography::GetConvertedLang() const
8351 LanguageType nLang;
8352 //I have assumed people's republic/taiwan == simplified/traditional
8354 //This isn't a documented issue, so we might have it all wrong,
8355 //i.e. i.e. what's with the powers of two ?
8358 One example of 3 for reserved1 which was really Japanese, perhaps last bit
8359 is for some other use ?, or redundant. If more examples trigger the assert
8360 we might be able to figure it out.
8362 switch(m_reserved1 & 0xE)
8364 case 2: //Japan
8365 nLang = LANGUAGE_JAPANESE;
8366 break;
8367 case 4: //Chinese (People's Republic)
8368 nLang = LANGUAGE_CHINESE_SIMPLIFIED;
8369 break;
8370 case 6: //Korean
8371 nLang = LANGUAGE_KOREAN;
8372 break;
8373 case 8: //Chinese (Taiwan)
8374 nLang = LANGUAGE_CHINESE_TRADITIONAL;
8375 break;
8376 default:
8377 OSL_ENSURE(false, "Unknown MS Asian Typography language, report");
8378 nLang = LANGUAGE_CHINESE_SIMPLIFIED_LEGACY;
8379 break;
8380 case 0:
8381 //And here we have the possibility that it says 2, but it's really
8382 //a bug and only japanese level 2 has been selected after a custom
8383 //version was chosen on last save!
8384 nLang = LANGUAGE_JAPANESE;
8385 break;
8387 return nLang;
8390 // Sprms
8392 sal_uInt16 wwSprmParser::GetSprmTailLen(sal_uInt16 nId, const sal_uInt8* pSprm, sal_Int32 nRemLen)
8393 const
8395 SprmInfo aSprm = GetSprmInfo(nId);
8396 sal_uInt16 nL = 0; // number of Bytes to read
8398 //sprmPChgTabs
8399 switch( nId )
8401 case 23:
8402 case 0xC615:
8403 if( pSprm[1 + mnDelta] != 255 )
8404 nL = static_cast< sal_uInt16 >(pSprm[1 + mnDelta] + aSprm.nLen);
8405 else
8407 sal_uInt8 nDelIdx = 2 + mnDelta;
8408 sal_uInt8 nDel = nDelIdx < nRemLen ? pSprm[nDelIdx] : 0;
8409 sal_uInt8 nInsIdx = 3 + mnDelta + 4 * nDel;
8410 sal_uInt8 nIns = nInsIdx < nRemLen ? pSprm[nInsIdx] : 0;
8412 nL = 2 + 4 * nDel + 3 * nIns;
8414 break;
8415 default:
8416 switch (aSprm.nVari)
8418 case L_FIX:
8419 nL = aSprm.nLen; // Excl. Token
8420 break;
8421 case L_VAR:
8422 // Variable 1-Byte Length
8423 // parameter length (i.e. excluding token and length byte)
8424 nL = static_cast< sal_uInt16 >(pSprm[1 + mnDelta] + aSprm.nLen);
8425 break;
8426 case L_VAR2:
8428 // Variable 2-Byte Length
8429 // For sprmTDefTable and sprmTDefTable10, the length of the
8430 // parameter plus 1 is recorded in the two bytes beginning
8431 // at offset (WW7-) 1 or (WW8+) 2
8432 sal_uInt8 nIndex = 1 + mnDelta;
8433 sal_uInt16 nCount;
8434 if (nIndex + 1 >= nRemLen)
8436 SAL_WARN("sw.ww8", "sprm longer than remaining bytes, doc or parser is wrong");
8437 nCount = 0;
8439 else
8441 nCount = SVBT16ToUInt16(&pSprm[nIndex]);
8442 SAL_WARN_IF(nCount < 1, "sw.ww8", "length should have been at least 1");
8443 if (nCount)
8444 --nCount;
8446 nL = static_cast<sal_uInt16>(nCount + aSprm.nLen);
8447 break;
8449 default:
8450 OSL_ENSURE(false, "Unknown sprm variant");
8451 break;
8453 break;
8455 return nL;
8458 // one or two bytes at the beginning at the sprm id
8459 sal_uInt16 wwSprmParser::GetSprmId(const sal_uInt8* pSp) const
8461 OSL_ENSURE(pSp, "Why GetSprmId with pSp of 0");
8462 if (!pSp)
8463 return 0;
8465 sal_uInt16 nId = 0;
8467 if (ww::IsSevenMinus(meVersion))
8469 nId = *pSp; // [0..0xff]
8471 else
8473 nId = SVBT16ToUInt16(pSp);
8474 if (0x0800 > nId)
8475 nId = 0;
8478 return nId;
8481 // with tokens and length byte
8482 sal_Int32 wwSprmParser::GetSprmSize(sal_uInt16 nId, const sal_uInt8* pSprm, sal_Int32 nRemLen) const
8484 return GetSprmTailLen(nId, pSprm, nRemLen) + 1 + mnDelta + SprmDataOfs(nId);
8487 sal_uInt8 wwSprmParser::SprmDataOfs(sal_uInt16 nId) const
8489 return GetSprmInfo(nId).nVari;
8492 sal_Int32 wwSprmParser::DistanceToData(sal_uInt16 nId) const
8494 return 1 + mnDelta + SprmDataOfs(nId);
8497 SprmResult wwSprmParser::findSprmData(sal_uInt16 nId, sal_uInt8* pSprms,
8498 sal_Int32 nLen) const
8500 while (nLen >= MinSprmLen())
8502 const sal_uInt16 nCurrentId = GetSprmId(pSprms);
8503 // set pointer to data
8504 sal_Int32 nSize = GetSprmSize(nCurrentId, pSprms, nLen);
8506 bool bValid = nSize <= nLen;
8508 SAL_WARN_IF(!bValid, "sw.ww8",
8509 "sprm 0x" << std::hex << nCurrentId << std::dec << " longer than remaining bytes, " <<
8510 nSize << " vs " << nLen << "doc or parser is wrong");
8512 if (nCurrentId == nId && bValid) // Sprm found
8514 sal_Int32 nFixedLen = DistanceToData(nId);
8515 return SprmResult(pSprms + nFixedLen, nSize - nFixedLen);
8518 //Clip to available size if wrong
8519 nSize = std::min(nSize, nLen);
8520 pSprms += nSize;
8521 nLen -= nSize;
8523 // Sprm not found
8524 return SprmResult();
8527 SEPr::SEPr() :
8528 bkc(2), fTitlePage(0), fAutoPgn(0), nfcPgn(0), fUnlocked(0), cnsPgn(0),
8529 fPgnRestart(0), fEndNote(1), lnc(0), grpfIhdt(0), nLnnMod(0), dxaLnn(0),
8530 dxaPgn(720), dyaPgn(720), fLBetween(0), vjc(0), dmBinFirst(0),
8531 dmBinOther(0), dmPaperReq(0), fPropRMark(0), ibstPropRMark(0),
8532 dttmPropRMark(0), dxtCharSpace(0), dyaLinePitch(0), clm(0), reserved1(0),
8533 dmOrientPage(0), iHeadingPgn(0), pgnStart(1), lnnMin(0), wTextFlow(0),
8534 reserved2(0), pgbApplyTo(0), pgbPageDepth(0), pgbOffsetFrom(0),
8535 xaPage(lLetterWidth), yaPage(lLetterHeight), xaPageNUp(lLetterWidth), yaPageNUp(lLetterHeight),
8536 dxaLeft(1800), dxaRight(1800), dyaTop(1440), dyaBottom(1440), dzaGutter(0),
8537 dyaHdrTop(720), dyaHdrBottom(720), ccolM1(0), fEvenlySpaced(1),
8538 reserved3(0), fBiDi(0), fFacingCol(0), fRTLGutter(0), fRTLAlignment(0),
8539 dxaColumns(720), dxaColumnWidth(0), dmOrientFirst(0), fLayout(0),
8540 reserved4(0)
8544 bool checkRead(SvStream &rSt, void *pDest, sal_uInt32 nLength)
8546 return (rSt.ReadBytes(pDest, nLength) == static_cast<std::size_t>(nLength));
8549 #ifdef OSL_BIGENDIAN
8550 void swapEndian(sal_Unicode *pString)
8552 for (sal_Unicode *pWork = pString; *pWork; ++pWork)
8553 *pWork = OSL_SWAPWORD(*pWork);
8555 #endif
8557 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */