xref: /aoo41x/main/sw/source/filter/ww8/ww8scan.cxx (revision 1d37a3e2)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
27 #include "ww8scan.hxx"
28 
29 
30 #include <functional>
31 #include <algorithm>
32 
33 #include <string.h>         // memset()
34 #include <rtl/tencinfo.h>
35 
36 #ifdef DUMP
37 
38 #define ERR_SWG_READ_ERROR 1234
39 #define ASSERT( a, b )
40 
41 #else                       // dump
42 #include <swerror.h>        // ERR_WW6_...
43 #include <swtypes.hxx>      // DELETEZ
44 
45 #endif                      // dump
46 #include <tools/debug.hxx>
47 #include <i18npool/lang.h>
48 #include <vcl/svapp.hxx>    // Application  #i90932#
49 
50 #include <stdio.h>
51 
52 #define ASSERT_RET_ON_FAIL( aCon, aError, aRet ) \
53     ASSERT(aCon, aError); \
54     if (!(aCon)) \
55         return aRet;
56 
57 //-begin
58 namespace SL
59 {
60 #   define IMPLCONSTSTRINGARRAY(X) const char a##X[] = "" #X ""
61     IMPLCONSTSTRINGARRAY(ObjectPool);
62     IMPLCONSTSTRINGARRAY(1Table);
63     IMPLCONSTSTRINGARRAY(0Table);
64     IMPLCONSTSTRINGARRAY(Data);
65     IMPLCONSTSTRINGARRAY(CheckBox);
66     IMPLCONSTSTRINGARRAY(ListBox);
67     IMPLCONSTSTRINGARRAY(TextBox);
68     IMPLCONSTSTRINGARRAY(TextField);
69     IMPLCONSTSTRINGARRAY(MSMacroCmds);
70 }
71 
72 template<class C> bool wwString<C>::TestBeltAndBraces(const SvStream& rStrm)
73 {
74     bool bRet = false;
75     sal_uInt32 nOldPos = rStrm.Tell();
76     SvStream &rMutableStrm = const_cast<SvStream &>(rStrm);
77     sal_uInt32 nLen = rMutableStrm.Seek(STREAM_SEEK_TO_END);
78     rMutableStrm.Seek(nOldPos);
79     C nBelt;
80     rMutableStrm >> nBelt;
81     nBelt *= sizeof(C);
82     if (nOldPos + sizeof(C) + nBelt + sizeof(C) <= nLen &&
83         !rStrm.GetError() && !rStrm.IsEof())
84     {
85         rMutableStrm.SeekRel(nBelt);
86         if (!rStrm.GetError())
87         {
88             C cBraces;
89             rMutableStrm >> cBraces;
90             if (!rMutableStrm.GetError() && cBraces == 0)
91                 bRet = true;
92         }
93     }
94     rMutableStrm.Seek(nOldPos);
95     return bRet;
96 }
97 
98 inline bool operator==(const SprmInfo &rFirst, const SprmInfo &rSecond)
99 {
100     return (rFirst.nId == rSecond.nId);
101 }
102 
103 const wwSprmSearcher *wwSprmParser::GetWW2SprmSearcher()
104 {
105     //double lock me
106     // WW7- Sprms
107     static const SprmInfo aSprms[] =
108     {
109         {  0, 0, L_FIX}, // "Default-sprm",  wird uebersprungen
110         {  2, 1, L_FIX}, // "sprmPIstd",  pap.istd (style code)
111         {  3, 0, L_VAR}, // "sprmPIstdPermute pap.istd permutation
112         {  4, 1, L_FIX}, // "sprmPIncLv1" pap.istddifference
113         {  5, 1, L_FIX}, // "sprmPJc" pap.jc (justification)
114         {  6, 1, L_FIX}, // "sprmPFSideBySide" pap.fSideBySide
115         {  7, 1, L_FIX}, // "sprmPFKeep" pap.fKeep
116         {  8, 1, L_FIX}, // "sprmPFKeepFollow " pap.fKeepFollow
117         {  9, 1, L_FIX}, // "sprmPPageBreakBefore" pap.fPageBreakBefore
118         { 10, 1, L_FIX}, // "sprmPBrcl" pap.brcl
119         { 11, 1, L_FIX}, // "sprmPBrcp" pap.brcp
120         { 12, 1, L_FIX}, // "sprmPNfcSeqNumb" pap.nfcSeqNumb
121         { 13, 1, L_FIX}, // "sprmPNoSeqNumb" pap.nnSeqNumb
122         { 14, 1, L_FIX}, // "sprmPFNoLineNumb" pap.fNoLnn
123         { 15, 0, L_VAR}, // "?sprmPChgTabsPapx" pap.itbdMac, ...
124         { 16, 2, L_FIX}, // "sprmPDxaRight" pap.dxaRight
125         { 17, 2, L_FIX}, // "sprmPDxaLeft" pap.dxaLeft
126         { 18, 2, L_FIX}, // "sprmPNest" pap.dxaLeft
127         { 19, 2, L_FIX}, // "sprmPDxaLeft1" pap.dxaLeft1
128         { 20, 2, L_FIX}, // "sprmPDyaLine" pap.lspd an LSPD
129         { 21, 2, L_FIX}, // "sprmPDyaBefore" pap.dyaBefore
130         { 22, 2, L_FIX}, // "sprmPDyaAfter" pap.dyaAfter
131         { 23, 0, L_VAR}, // "?sprmPChgTabs" pap.itbdMac, pap.rgdxaTab, ...
132         { 24, 1, L_FIX}, // "sprmPFInTable" pap.fInTable
133         { 25, 1, L_FIX}, // "sprmPTtp" pap.fTtp
134         { 26, 2, L_FIX}, // "sprmPDxaAbs" pap.dxaAbs
135         { 27, 2, L_FIX}, // "sprmPDyaAbs" pap.dyaAbs
136         { 28, 2, L_FIX}, // "sprmPDxaWidth" pap.dxaWidth
137         { 29, 1, L_FIX}, // "sprmPPc" pap.pcHorz, pap.pcVert
138         { 30, 2, L_FIX}, // "sprmPBrcTop10" pap.brcTop BRC10
139         { 31, 2, L_FIX}, // "sprmPBrcLeft10" pap.brcLeft BRC10
140         { 32, 2, L_FIX}, // "sprmPBrcBottom10" pap.brcBottom BRC10
141         { 33, 2, L_FIX}, // "sprmPBrcRight10" pap.brcRight BRC10
142         { 34, 2, L_FIX}, // "sprmPBrcBetween10" pap.brcBetween BRC10
143         { 35, 2, L_FIX}, // "sprmPBrcBar10" pap.brcBar BRC10
144         { 36, 2, L_FIX}, // "sprmPFromText10" pap.dxaFromText dxa
145         { 37, 1, L_FIX}, // "sprmPWr" pap.wr wr
146         { 38, 2, L_FIX}, // "sprmPBrcTop" pap.brcTop BRC
147         { 39, 2, L_FIX}, // "sprmPBrcLeft" pap.brcLeft BRC
148         { 40, 2, L_FIX}, // "sprmPBrcBottom" pap.brcBottom BRC
149         { 41, 2, L_FIX}, // "sprmPBrcRight" pap.brcRight BRC
150         { 42, 2, L_FIX}, // "sprmPBrcBetween" pap.brcBetween BRC
151         { 43, 2, L_FIX}, // "sprmPBrcBar" pap.brcBar BRC word
152         { 44, 1, L_FIX}, // "sprmPFNoAutoHyph" pap.fNoAutoHyph
153         { 45, 2, L_FIX}, // "sprmPWHeightAbs" pap.wHeightAbs w
154         { 46, 2, L_FIX}, // "sprmPDcs" pap.dcs DCS
155         { 47, 2, L_FIX}, // "sprmPShd" pap.shd SHD
156         { 48, 2, L_FIX}, // "sprmPDyaFromText" pap.dyaFromText dya
157         { 49, 2, L_FIX}, // "sprmPDxaFromText" pap.dxaFromText dxa
158         { 50, 1, L_FIX}, // "sprmPFBiDi" pap.fBiDi 0 or 1 byte
159         { 51, 1, L_FIX}, // "sprmPFWidowControl" pap.fWidowControl 0 or 1 byte
160         { 52, 0, L_FIX}, // "?sprmPRuler 52"
161         { 53, 1, L_FIX}, // "sprmCFStrikeRM" chp.fRMarkDel 1 or 0 bit
162         { 54, 1, L_FIX}, // "sprmCFRMark" chp.fRMark 1 or 0 bit
163         { 55, 1, L_FIX}, // "sprmCFFldVanish" chp.fFldVanish 1 or 0 bit
164         { 57, 0, L_VAR}, // "sprmCDefault" whole CHP
165         { 58, 0, L_FIX}, // "sprmCPlain" whole CHP
166         { 60, 1, L_FIX}, // "sprmCFBold" chp.fBold 0,1, 128, or 129
167         { 61, 1, L_FIX}, // "sprmCFItalic" chp.fItalic 0,1, 128, or 129
168         { 62, 1, L_FIX}, // "sprmCFStrike" chp.fStrike 0,1, 128, or 129
169         { 63, 1, L_FIX}, // "sprmCFOutline" chp.fOutline 0,1, 128, or 129
170         { 64, 1, L_FIX}, // "sprmCFShadow" chp.fShadow 0,1, 128, or 129
171         { 65, 1, L_FIX}, // "sprmCFSmallCaps" chp.fSmallCaps 0,1, 128, or 129
172         { 66, 1, L_FIX}, // "sprmCFCaps" chp.fCaps 0,1, 128, or 129
173         { 67, 1, L_FIX}, // "sprmCFVanish" chp.fVanish 0,1, 128, or 129
174         { 68, 2, L_FIX}, // "sprmCFtc" chp.ftc ftc word
175         { 69, 1, L_FIX}, // "sprmCKul" chp.kul kul byte
176         { 70, 3, L_FIX}, // "sprmCSizePos" chp.hps, chp.hpsPos
177         { 71, 2, L_FIX}, // "sprmCDxaSpace" chp.dxaSpace dxa
178         { 72, 2, L_FIX}, // "sprmCLid" chp.lid LID
179         { 73, 1, L_FIX}, // "sprmCIco" chp.ico ico byte
180         { 74, 1, L_FIX}, // "sprmCHps" chp.hps hps !word!
181         { 75, 1, L_FIX}, // "sprmCHpsInc" chp.hps
182         { 76, 1, L_FIX}, // "sprmCHpsPos" chp.hpsPos hps !word!
183         { 77, 1, L_FIX}, // "sprmCHpsPosAdj" chp.hpsPos hps
184         { 78, 0, L_VAR}, // "?sprmCMajority" chp.fBold, chp.fItalic, ...
185         { 80, 1, L_FIX}, // "sprmCFBoldBi" chp.fBoldBi
186         { 81, 1, L_FIX}, // "sprmCFItalicBi" chp.fItalicBi
187         { 82, 2, L_FIX}, // "sprmCFtcBi" chp.ftcBi
188         { 83, 2, L_FIX}, // "sprmClidBi" chp.lidBi
189         { 84, 1, L_FIX}, // "sprmCIcoBi" chp.icoBi
190         { 85, 1, L_FIX}, // "sprmCHpsBi" chp.hpsBi
191         { 86, 1, L_FIX}, // "sprmCFBiDi" chp.fBiDi
192         { 87, 1, L_FIX}, // "sprmCFDiacColor" chp.fDiacUSico
193         { 94, 1, L_FIX}, // "sprmPicBrcl" pic.brcl brcl (see PIC definition)
194         { 95,12, L_VAR}, // "sprmPicScale" pic.mx, pic.my, pic.dxaCropleft,
195         { 96, 2, L_FIX}, // "sprmPicBrcTop" pic.brcTop BRC word
196         { 97, 2, L_FIX}, // "sprmPicBrcLeft" pic.brcLeft BRC word
197         { 98, 2, L_FIX}, // "sprmPicBrcBottom" pic.brcBottom BRC word
198         { 99, 2, L_FIX}, // "sprmPicBrcRight" pic.brcRight BRC word
199         {112, 1, L_FIX}, // "sprmSFRTLGutter", set to one if gutter is on
200         {114, 1, L_FIX}, // "sprmSFBiDi" ;;;
201         {115, 2, L_FIX}, // "sprmSDmBinFirst" sep.dmBinFirst  word
202         {116, 2, L_FIX}, // "sprmSDmBinOther" sep.dmBinOther  word
203         {117, 1, L_FIX}, // "sprmSBkc" sep.bkc bkc byte
204         {118, 1, L_FIX}, // "sprmSFTitlePage" sep.fTitlePage 0 or 1 byte
205         {119, 2, L_FIX}, // "sprmSCcolumns" sep.ccolM1 # of cols - 1 word
206         {120, 2, L_FIX}, // "sprmSDxaColumns" sep.dxaColumns dxa word
207         {121, 1, L_FIX}, // "sprmSFAutoPgn" sep.fAutoPgn obsolete byte
208         {122, 1, L_FIX}, // "sprmSNfcPgn" sep.nfcPgn nfc byte
209         {123, 2, L_FIX}, // "sprmSDyaPgn" sep.dyaPgn dya short
210         {124, 2, L_FIX}, // "sprmSDxaPgn" sep.dxaPgn dya short
211         {125, 1, L_FIX}, // "sprmSFPgnRestart" sep.fPgnRestart 0 or 1 byte
212         {126, 1, L_FIX}, // "sprmSFEndnote" sep.fEndnote 0 or 1 byte
213         {127, 1, L_FIX}, // "sprmSLnc" sep.lnc lnc byte
214         {128, 1, L_FIX}, // "sprmSGprfIhdt" sep.grpfIhdt grpfihdt
215         {129, 2, L_FIX}, // "sprmSNLnnMod" sep.nLnnMod non-neg int. word
216         {130, 2, L_FIX}, // "sprmSDxaLnn" sep.dxaLnn dxa word
217         {131, 2, L_FIX}, // "sprmSDyaHdrTop" sep.dyaHdrTop dya word
218         {132, 2, L_FIX}, // "sprmSDyaHdrBottom" sep.dyaHdrBottom dya word
219         {133, 1, L_FIX}, // "sprmSLBetween" sep.fLBetween 0 or 1 byte
220         {134, 1, L_FIX}, // "sprmSVjc" sep.vjc vjc byte
221         {135, 2, L_FIX}, // "sprmSLnnMin" sep.lnnMin lnn word
222         {136, 2, L_FIX}, // "sprmSPgnStart" sep.pgnStart pgn word
223         {137, 1, L_FIX}, // "sprmSBOrientation" sep.dmOrientPage dm byte
224         {138, 1, L_FIX}, // "sprmSFFacingCol" ;;;
225         {139, 2, L_FIX}, // "sprmSXaPage" sep.xaPage xa word
226         {140, 2, L_FIX}, // "sprmSYaPage" sep.yaPage ya word
227         {141, 2, L_FIX}, // "sprmSDxaLeft" sep.dxaLeft dxa word
228         {142, 2, L_FIX}, // "sprmSDxaRight" sep.dxaRight dxa word
229         {143, 2, L_FIX}, // "sprmSDyaTop" sep.dyaTop dya word
230         {144, 2, L_FIX}, // "sprmSDyaBottom" sep.dyaBottom dya word
231         {145, 2, L_FIX}, // "sprmSDzaGutter" sep.dzaGutter dza word
232         {146, 2, L_FIX}, // "sprmTJc" tap.jc jc (low order byte is significant)
233         {147, 2, L_FIX}, // "sprmTDxaLeft" tap.rgdxaCenter dxa word
234         {148, 2, L_FIX}, // "sprmTDxaGapHalf" tap.dxaGapHalf, tap.rgdxaCenter
235         {149, 1, L_FIX}, // "sprmTFBiDi" ;;;
236         {152, 0, L_VAR}, // "sprmTDefTable10" tap.rgdxaCenter, tap.rgtc complex
237         {153, 2, L_FIX}, // "sprmTDyaRowHeight" tap.dyaRowHeight dya word
238         {154, 0, L_VAR2},// "sprmTDefTable" tap.rgtc complex
239         {155, 1, L_VAR}, // "sprmTDefTableShd" tap.rgshd complex
240         {157, 5, L_FIX}, // "sprmTSetBrc" tap.rgtc[].rgbrc complex 5 bytes
241         {158, 4, L_FIX}, // "sprmTInsert" tap.rgdxaCenter,tap.rgtc complex
242         {159, 2, L_FIX}, // "sprmTDelete" tap.rgdxaCenter, tap.rgtc complex
243         {160, 4, L_FIX}, // "sprmTDxaCol" tap.rgdxaCenter complex
244         {161, 2, L_FIX}, // "sprmTMerge" tap.fFirstMerged, tap.fMerged complex
245         {162, 2, L_FIX}, // "sprmTSplit" tap.fFirstMerged, tap.fMerged complex
246         {163, 5, L_FIX}, // "sprmTSetBrc10" tap.rgtc[].rgbrc complex 5 bytes
247         {164, 4, L_FIX}, // "sprmTSetShd", tap.rgshd complex 4 bytes
248     };
249 
250     static wwSprmSearcher aSprmSrch(aSprms, sizeof(aSprms) / sizeof(aSprms[0]));
251     return &aSprmSrch;
252 };
253 
254 
255 const wwSprmSearcher *wwSprmParser::GetWW6SprmSearcher()
256 {
257     //double lock me
258     // WW7- Sprms
259     static const SprmInfo aSprms[] =
260     {
261         {  0, 0, L_FIX}, // "Default-sprm",  wird uebersprungen
262         {  2, 2, L_FIX}, // "sprmPIstd",  pap.istd (style code)
263         {  3, 3, L_VAR}, // "sprmPIstdPermute pap.istd permutation
264         {  4, 1, L_FIX}, // "sprmPIncLv1" pap.istddifference
265         {  5, 1, L_FIX}, // "sprmPJc" pap.jc (justification)
266         {  6, 1, L_FIX}, // "sprmPFSideBySide" pap.fSideBySide
267         {  7, 1, L_FIX}, // "sprmPFKeep" pap.fKeep
268         {  8, 1, L_FIX}, // "sprmPFKeepFollow " pap.fKeepFollow
269         {  9, 1, L_FIX}, // "sprmPPageBreakBefore" pap.fPageBreakBefore
270         { 10, 1, L_FIX}, // "sprmPBrcl" pap.brcl
271         { 11, 1, L_FIX}, // "sprmPBrcp" pap.brcp
272         { 12, 0, L_VAR}, // "sprmPAnld" pap.anld (ANLD structure)
273         { 13, 1, L_FIX}, // "sprmPNLvlAnm" pap.nLvlAnm nn
274         { 14, 1, L_FIX}, // "sprmPFNoLineNumb" pap.fNoLnn
275         { 15, 0, L_VAR}, // "?sprmPChgTabsPapx" pap.itbdMac, ...
276         { 16, 2, L_FIX}, // "sprmPDxaRight" pap.dxaRight
277         { 17, 2, L_FIX}, // "sprmPDxaLeft" pap.dxaLeft
278         { 18, 2, L_FIX}, // "sprmPNest" pap.dxaLeft
279         { 19, 2, L_FIX}, // "sprmPDxaLeft1" pap.dxaLeft1
280         { 20, 4, L_FIX}, // "sprmPDyaLine" pap.lspd an LSPD
281         { 21, 2, L_FIX}, // "sprmPDyaBefore" pap.dyaBefore
282         { 22, 2, L_FIX}, // "sprmPDyaAfter" pap.dyaAfter
283         { 23, 0, L_VAR}, // "?sprmPChgTabs" pap.itbdMac, pap.rgdxaTab, ...
284         { 24, 1, L_FIX}, // "sprmPFInTable" pap.fInTable
285         { 25, 1, L_FIX}, // "sprmPTtp" pap.fTtp
286         { 26, 2, L_FIX}, // "sprmPDxaAbs" pap.dxaAbs
287         { 27, 2, L_FIX}, // "sprmPDyaAbs" pap.dyaAbs
288         { 28, 2, L_FIX}, // "sprmPDxaWidth" pap.dxaWidth
289         { 29, 1, L_FIX}, // "sprmPPc" pap.pcHorz, pap.pcVert
290         { 30, 2, L_FIX}, // "sprmPBrcTop10" pap.brcTop BRC10
291         { 31, 2, L_FIX}, // "sprmPBrcLeft10" pap.brcLeft BRC10
292         { 32, 2, L_FIX}, // "sprmPBrcBottom10" pap.brcBottom BRC10
293         { 33, 2, L_FIX}, // "sprmPBrcRight10" pap.brcRight BRC10
294         { 34, 2, L_FIX}, // "sprmPBrcBetween10" pap.brcBetween BRC10
295         { 35, 2, L_FIX}, // "sprmPBrcBar10" pap.brcBar BRC10
296         { 36, 2, L_FIX}, // "sprmPFromText10" pap.dxaFromText dxa
297         { 37, 1, L_FIX}, // "sprmPWr" pap.wr wr
298         { 38, 2, L_FIX}, // "sprmPBrcTop" pap.brcTop BRC
299         { 39, 2, L_FIX}, // "sprmPBrcLeft" pap.brcLeft BRC
300         { 40, 2, L_FIX}, // "sprmPBrcBottom" pap.brcBottom BRC
301         { 41, 2, L_FIX}, // "sprmPBrcRight" pap.brcRight BRC
302         { 42, 2, L_FIX}, // "sprmPBrcBetween" pap.brcBetween BRC
303         { 43, 2, L_FIX}, // "sprmPBrcBar" pap.brcBar BRC word
304         { 44, 1, L_FIX}, // "sprmPFNoAutoHyph" pap.fNoAutoHyph
305         { 45, 2, L_FIX}, // "sprmPWHeightAbs" pap.wHeightAbs w
306         { 46, 2, L_FIX}, // "sprmPDcs" pap.dcs DCS
307         { 47, 2, L_FIX}, // "sprmPShd" pap.shd SHD
308         { 48, 2, L_FIX}, // "sprmPDyaFromText" pap.dyaFromText dya
309         { 49, 2, L_FIX}, // "sprmPDxaFromText" pap.dxaFromText dxa
310         { 50, 1, L_FIX}, // "sprmPFLocked" pap.fLocked 0 or 1 byte
311         { 51, 1, L_FIX}, // "sprmPFWidowControl" pap.fWidowControl 0 or 1 byte
312         { 52, 0, L_FIX}, // "?sprmPRuler 52"
313         { 64, 0, L_VAR}, // rtl property ?
314         { 65, 1, L_FIX}, // "sprmCFStrikeRM" chp.fRMarkDel 1 or 0 bit
315         { 66, 1, L_FIX}, // "sprmCFRMark" chp.fRMark 1 or 0 bit
316         { 67, 1, L_FIX}, // "sprmCFFldVanish" chp.fFldVanish 1 or 0 bit
317         { 68, 0, L_VAR}, // "sprmCPicLocation" chp.fcPic and chp.fSpec
318         { 69, 2, L_FIX}, // "sprmCIbstRMark" chp.ibstRMark index into sttbRMark
319         { 70, 4, L_FIX}, // "sprmCDttmRMark" chp.dttm DTTM long
320         { 71, 1, L_FIX}, // "sprmCFData" chp.fData 1 or 0 bit
321         { 72, 2, L_FIX}, // "sprmCRMReason" chp.idslRMReason an index to a table
322         { 73, 3, L_FIX}, // "sprmCChse" chp.fChsDiff and chp.chse
323         { 74, 0, L_VAR}, // "sprmCSymbol" chp.fSpec, chp.chSym and chp.ftcSym
324         { 75, 1, L_FIX}, // "sprmCFOle2" chp.fOle2 1 or 0   bit
325         { 77, 0, L_VAR}, // unknown
326         { 79, 0, L_VAR}, // unknown
327         { 80, 2, L_FIX}, // "sprmCIstd" chp.istd istd, see stylesheet definition
328         { 81, 0, L_VAR}, // "sprmCIstdPermute" chp.istd permutation vector
329         { 82, 0, L_VAR}, // "sprmCDefault" whole CHP
330         { 83, 0, L_FIX}, // "sprmCPlain" whole CHP
331         { 85, 1, L_FIX}, // "sprmCFBold" chp.fBold 0,1, 128, or 129
332         { 86, 1, L_FIX}, // "sprmCFItalic" chp.fItalic 0,1, 128, or 129
333         { 87, 1, L_FIX}, // "sprmCFStrike" chp.fStrike 0,1, 128, or 129
334         { 88, 1, L_FIX}, // "sprmCFOutline" chp.fOutline 0,1, 128, or 129
335         { 89, 1, L_FIX}, // "sprmCFShadow" chp.fShadow 0,1, 128, or 129
336         { 90, 1, L_FIX}, // "sprmCFSmallCaps" chp.fSmallCaps 0,1, 128, or 129
337         { 91, 1, L_FIX}, // "sprmCFCaps" chp.fCaps 0,1, 128, or 129
338         { 92, 1, L_FIX}, // "sprmCFVanish" chp.fVanish 0,1, 128, or 129
339         { 93, 2, L_FIX}, // "sprmCFtc" chp.ftc ftc word
340         { 94, 1, L_FIX}, // "sprmCKul" chp.kul kul byte
341         { 95, 3, L_FIX}, // "sprmCSizePos" chp.hps, chp.hpsPos
342         { 96, 2, L_FIX}, // "sprmCDxaSpace" chp.dxaSpace dxa
343         { 97, 2, L_FIX}, // "sprmCLid" chp.lid LID
344         { 98, 1, L_FIX}, // "sprmCIco" chp.ico ico byte
345         { 99, 2, L_FIX}, // "sprmCHps" chp.hps hps !word!
346         {100, 1, L_FIX}, // "sprmCHpsInc" chp.hps
347         {101, 2, L_FIX}, // "sprmCHpsPos" chp.hpsPos hps !word!
348         {102, 1, L_FIX}, // "sprmCHpsPosAdj" chp.hpsPos hps
349         {103, 0, L_VAR}, // "?sprmCMajority" chp.fBold, chp.fItalic, ...
350         {104, 1, L_FIX}, // "sprmCIss" chp.iss iss
351         {105, 0, L_VAR}, // "sprmCHpsNew50" chp.hps hps variable width
352         {106, 0, L_VAR}, // "sprmCHpsInc1" chp.hps complex
353         {107, 2, L_FIX}, // "sprmCHpsKern" chp.hpsKern hps
354         {108, 0, L_VAR}, // "sprmCMajority50" chp.fBold, chp.fItalic, ...
355         {109, 2, L_FIX}, // "sprmCHpsMul" chp.hps percentage to grow hps
356         {110, 2, L_FIX}, // "sprmCCondHyhen" chp.ysri ysri
357         {111, 2, L_FIX}, // rtl bold
358         {112, 2, L_FIX}, // rtl italic
359         {113, 0, L_VAR}, // rtl property ?
360         {115, 0, L_VAR}, // rtl property ?
361         {116, 0, L_VAR}, // unknown
362         {117, 1, L_FIX}, // "sprmCFSpec" chp.fSpec  1 or 0 bit
363         {118, 1, L_FIX}, // "sprmCFObj" chp.fObj 1 or 0 bit
364         {119, 1, L_FIX}, // "sprmPicBrcl" pic.brcl brcl (see PIC definition)
365         {120,12, L_VAR}, // "sprmPicScale" pic.mx, pic.my, pic.dxaCropleft,
366         {121, 2, L_FIX}, // "sprmPicBrcTop" pic.brcTop BRC word
367         {122, 2, L_FIX}, // "sprmPicBrcLeft" pic.brcLeft BRC word
368         {123, 2, L_FIX}, // "sprmPicBrcBottom" pic.brcBottom BRC word
369         {124, 2, L_FIX}, // "sprmPicBrcRight" pic.brcRight BRC word
370         {131, 1, L_FIX}, // "sprmSScnsPgn" sep.cnsPgn cns byte
371         {132, 1, L_FIX}, // "sprmSiHeadingPgn" sep.iHeadingPgn
372         {133, 0, L_VAR}, // "sprmSOlstAnm" sep.olstAnm OLST variable length
373         {136, 3, L_FIX}, // "sprmSDxaColWidth" sep.rgdxaColWidthSpacing complex
374         {137, 3, L_FIX}, // "sprmSDxaColSpacing" sep.rgdxaColWidthSpacing
375         {138, 1, L_FIX}, // "sprmSFEvenlySpaced" sep.fEvenlySpaced 1 or 0
376         {139, 1, L_FIX}, // "sprmSFProtected" sep.fUnlocked 1 or 0 byte
377         {140, 2, L_FIX}, // "sprmSDmBinFirst" sep.dmBinFirst  word
378         {141, 2, L_FIX}, // "sprmSDmBinOther" sep.dmBinOther  word
379         {142, 1, L_FIX}, // "sprmSBkc" sep.bkc bkc byte
380         {143, 1, L_FIX}, // "sprmSFTitlePage" sep.fTitlePage 0 or 1 byte
381         {144, 2, L_FIX}, // "sprmSCcolumns" sep.ccolM1 # of cols - 1 word
382         {145, 2, L_FIX}, // "sprmSDxaColumns" sep.dxaColumns dxa word
383         {146, 1, L_FIX}, // "sprmSFAutoPgn" sep.fAutoPgn obsolete byte
384         {147, 1, L_FIX}, // "sprmSNfcPgn" sep.nfcPgn nfc byte
385         {148, 2, L_FIX}, // "sprmSDyaPgn" sep.dyaPgn dya short
386         {149, 2, L_FIX}, // "sprmSDxaPgn" sep.dxaPgn dya short
387         {150, 1, L_FIX}, // "sprmSFPgnRestart" sep.fPgnRestart 0 or 1 byte
388         {151, 1, L_FIX}, // "sprmSFEndnote" sep.fEndnote 0 or 1 byte
389         {152, 1, L_FIX}, // "sprmSLnc" sep.lnc lnc byte
390         {153, 1, L_FIX}, // "sprmSGprfIhdt" sep.grpfIhdt grpfihdt
391         {154, 2, L_FIX}, // "sprmSNLnnMod" sep.nLnnMod non-neg int. word
392         {155, 2, L_FIX}, // "sprmSDxaLnn" sep.dxaLnn dxa word
393         {156, 2, L_FIX}, // "sprmSDyaHdrTop" sep.dyaHdrTop dya word
394         {157, 2, L_FIX}, // "sprmSDyaHdrBottom" sep.dyaHdrBottom dya word
395         {158, 1, L_FIX}, // "sprmSLBetween" sep.fLBetween 0 or 1 byte
396         {159, 1, L_FIX}, // "sprmSVjc" sep.vjc vjc byte
397         {160, 2, L_FIX}, // "sprmSLnnMin" sep.lnnMin lnn word
398         {161, 2, L_FIX}, // "sprmSPgnStart" sep.pgnStart pgn word
399         {162, 1, L_FIX}, // "sprmSBOrientation" sep.dmOrientPage dm byte
400         {163, 0, L_FIX}, // "?SprmSBCustomize 163"
401         {164, 2, L_FIX}, // "sprmSXaPage" sep.xaPage xa word
402         {165, 2, L_FIX}, // "sprmSYaPage" sep.yaPage ya word
403         {166, 2, L_FIX}, // "sprmSDxaLeft" sep.dxaLeft dxa word
404         {167, 2, L_FIX}, // "sprmSDxaRight" sep.dxaRight dxa word
405         {168, 2, L_FIX}, // "sprmSDyaTop" sep.dyaTop dya word
406         {169, 2, L_FIX}, // "sprmSDyaBottom" sep.dyaBottom dya word
407         {170, 2, L_FIX}, // "sprmSDzaGutter" sep.dzaGutter dza word
408         {171, 2, L_FIX}, // "sprmSDMPaperReq" sep.dmPaperReq dm word
409         {179, 0, L_VAR}, // rtl property ?
410         {181, 0, L_VAR}, // rtl property ?
411         {182, 2, L_FIX}, // "sprmTJc" tap.jc jc (low order byte is significant)
412         {183, 2, L_FIX}, // "sprmTDxaLeft" tap.rgdxaCenter dxa word
413         {184, 2, L_FIX}, // "sprmTDxaGapHalf" tap.dxaGapHalf, tap.rgdxaCenter
414         {185, 1, L_FIX}, // "sprmTFCantSplit" tap.fCantSplit 1 or 0 byte
415         {186, 1, L_FIX}, // "sprmTTableHeader" tap.fTableHeader 1 or 0 byte
416         {187,12, L_FIX}, // "sprmTTableBorders" tap.rgbrcTable complex 12 bytes
417         {188, 0, L_VAR}, // "sprmTDefTable10" tap.rgdxaCenter, tap.rgtc complex
418         {189, 2, L_FIX}, // "sprmTDyaRowHeight" tap.dyaRowHeight dya word
419         {190, 0, L_VAR2},// "sprmTDefTable" tap.rgtc complex
420         {191, 1, L_VAR}, // "sprmTDefTableShd" tap.rgshd complex
421         {192, 4, L_FIX}, // "sprmTTlp" tap.tlp TLP 4 bytes
422         {193, 5, L_FIX}, // "sprmTSetBrc" tap.rgtc[].rgbrc complex 5 bytes
423         {194, 4, L_FIX}, // "sprmTInsert" tap.rgdxaCenter,tap.rgtc complex
424         {195, 2, L_FIX}, // "sprmTDelete" tap.rgdxaCenter, tap.rgtc complex
425         {196, 4, L_FIX}, // "sprmTDxaCol" tap.rgdxaCenter complex
426         {197, 2, L_FIX}, // "sprmTMerge" tap.fFirstMerged, tap.fMerged complex
427         {198, 2, L_FIX}, // "sprmTSplit" tap.fFirstMerged, tap.fMerged complex
428         {199, 5, L_FIX}, // "sprmTSetBrc10" tap.rgtc[].rgbrc complex 5 bytes
429         {200, 4, L_FIX}, // "sprmTSetShd", tap.rgshd complex 4 bytes
430         {207, 0, L_VAR}  // rtl property ?
431     };
432 
433     static wwSprmSearcher aSprmSrch(aSprms, sizeof(aSprms) / sizeof(aSprms[0]));
434     return &aSprmSrch;
435 };
436 
437 const wwSprmSearcher *wwSprmParser::GetWW8SprmSearcher()
438 {
439     //double lock me
440     //WW8+ Sprms
441     static const SprmInfo aSprms[] =
442     {
443         {     0, 0, L_FIX}, // "Default-sprm"/ wird uebersprungen
444         {0x4600, 2, L_FIX}, // "sprmPIstd" pap.istd;istd (style code);short;
445         {0xC601, 0, L_VAR}, // "sprmPIstdPermute" pap.istd;permutation vector
446         {0x2602, 1, L_FIX}, // "sprmPIncLvl" pap.istd, pap.lvl;difference
447                             // between istd of base PAP and istd of PAP to be
448                             // produced
449         {0x2403, 1, L_FIX}, // "sprmPJc" pap.jc;jc (justification);byte;
450         {0x2404, 1, L_FIX}, // "sprmPFSideBySide" pap.fSideBySide;0 or 1;byte;
451         {0x2405, 1, L_FIX}, // "sprmPFKeep" pap.fKeep;0 or 1;byte;
452         {0x2406, 1, L_FIX}, // "sprmPFKeepFollow" pap.fKeepFollow;0 or 1;byte;
453         {0x2407, 1, L_FIX}, // "sprmPFPageBreakBefore" pap.fPageBreakBefore;
454                             // 0 or 1
455         {0x2408, 1, L_FIX}, // "sprmPBrcl" pap.brcl;brcl;byte;
456         {0x2409, 1, L_FIX}, // "sprmPBrcp" pap.brcp;brcp;byte;
457         {0x260A, 1, L_FIX}, // "sprmPIlvl" pap.ilvl;ilvl;byte;
458         {0x460B, 2, L_FIX}, // "sprmPIlfo" pap.ilfo;ilfo (list index) ;short;
459         {0x240C, 1, L_FIX}, // "sprmPFNoLineNumb" pap.fNoLnn;0 or 1;byte;
460         {0xC60D, 0, L_VAR}, // "sprmPChgTabsPapx" pap.itbdMac, pap.rgdxaTab,
461                             // pap.rgtbd;complex
462         {0x840E, 2, L_FIX}, // "sprmPDxaRight" pap.dxaRight;dxa;word;
463         {0x840F, 2, L_FIX}, // "sprmPDxaLeft" pap.dxaLeft;dxa;word;
464         {0x4610, 2, L_FIX}, // "sprmPNest" pap.dxaLeft;dxa
465         {0x8411, 2, L_FIX}, // "sprmPDxaLeft1" pap.dxaLeft1;dxa;word;
466         {0x6412, 4, L_FIX}, // "sprmPDyaLine" pap.lspd;an LSPD, a long word
467                             // structure consisting of a short of dyaLine
468                             // followed by a short of fMultLinespace
469         {0xA413, 2, L_FIX}, // "sprmPDyaBefore" pap.dyaBefore;dya;word;
470         {0xA414, 2, L_FIX}, // "sprmPDyaAfter" pap.dyaAfter;dya;word;
471         {0xC615, 0, L_VAR}, // "sprmPChgTabs" pap.itbdMac, pap.rgdxaTab,
472                             // pap.rgtbd;complex
473         {0x2416, 1, L_FIX}, // "sprmPFInTable" pap.fInTable;0 or 1;byte;
474         {0x2417, 1, L_FIX}, // "sprmPFTtp" pap.fTtp;0 or 1;byte;
475         {0x8418, 2, L_FIX}, // "sprmPDxaAbs" pap.dxaAbs;dxa;word;
476         {0x8419, 2, L_FIX}, // "sprmPDyaAbs" pap.dyaAbs;dya;word;
477         {0x841A, 2, L_FIX}, // "sprmPDxaWidth" pap.dxaWidth;dxa;word;
478         {0x261B, 1, L_FIX}, // "sprmPPc" pap.pcHorz, pap.pcVert;complex
479         {0x461C, 2, L_FIX}, // "sprmPBrcTop10" pap.brcTop;BRC10;word;
480         {0x461D, 2, L_FIX}, // "sprmPBrcLeft10" pap.brcLeft;BRC10;word;
481         {0x461E, 2, L_FIX}, // "sprmPBrcBottom10" pap.brcBottom;BRC10;word;
482         {0x461F, 2, L_FIX}, // "sprmPBrcRight10" pap.brcRight;BRC10;word;
483         {0x4620, 2, L_FIX}, // "sprmPBrcBetween10" pap.brcBetween;BRC10;word;
484         {0x4621, 2, L_FIX}, // "sprmPBrcBar10" pap.brcBar;BRC10;word;
485         {0x4622, 2, L_FIX}, // "sprmPDxaFromText10" pap.dxaFromText;dxa;word;
486         {0x2423, 1, L_FIX}, // "sprmPWr" pap.wr;wr
487         {0x6424, 4, L_FIX}, // "sprmPBrcTop" pap.brcTop;BRC;long;
488         {0x6425, 4, L_FIX}, // "sprmPBrcLeft" pap.brcLeft;BRC;long;
489         {0x6426, 4, L_FIX}, // "sprmPBrcBottom" pap.brcBottom;BRC;long;
490         {0x6427, 4, L_FIX}, // "sprmPBrcRight" pap.brcRight;BRC;long;
491         {0x6428, 4, L_FIX}, // "sprmPBrcBetween" pap.brcBetween;BRC;long;
492         {0x6629, 4, L_FIX}, // "sprmPBrcBar" pap.brcBar;BRC;long;
493         {0x242A, 1, L_FIX}, // "sprmPFNoAutoHyph" pap.fNoAutoHyph;0 or 1;byte;
494         {0x442B, 2, L_FIX}, // "sprmPWHeightAbs" pap.wHeightAbs;w;word;
495         {0x442C, 2, L_FIX}, // "sprmPDcs" pap.dcs;DCS;short;
496         {0x442D, 2, L_FIX}, // "sprmPShd" pap.shd;SHD;word;
497         {0x842E, 2, L_FIX}, // "sprmPDyaFromText" pap.dyaFromText;dya;word;
498         {0x842F, 2, L_FIX}, // "sprmPDxaFromText" pap.dxaFromText;dxa;word;
499         {0x2430, 1, L_FIX}, // "sprmPFLocked" pap.fLocked;0 or 1;byte;
500         {0x2431, 1, L_FIX}, // "sprmPFWidowControl" pap.fWidowControl;0 or 1
501         {0xC632, 0, L_VAR}, // "sprmPRuler" ;;variable length;
502         {0x2433, 1, L_FIX}, // "sprmPFKinsoku" pap.fKinsoku;0 or 1;byte;
503         {0x2434, 1, L_FIX}, // "sprmPFWordWrap" pap.fWordWrap;0 or 1;byte;
504         {0x2435, 1, L_FIX}, // "sprmPFOverflowPunct" pap.fOverflowPunct;0 or 1
505         {0x2436, 1, L_FIX}, // "sprmPFTopLinePunct" pap.fTopLinePunct;0 or 1
506         {0x2437, 1, L_FIX}, // "sprmPFAutoSpaceDE" pap.fAutoSpaceDE;0 or 1
507         {0x2438, 1, L_FIX}, // "sprmPFAutoSpaceDN" pap.fAutoSpaceDN;0 or 1
508         {0x4439, 2, L_FIX}, // "sprmPWAlignFont" pap.wAlignFont;iFa
509         {0x443A, 2, L_FIX}, // "sprmPFrameTextFlow" pap.fVertical pap.fBackward
510                             // pap.fRotateFont;complex
511         {0x243B, 1, L_FIX}, // "sprmPISnapBaseLine" obsolete: not applicable in
512                             // Word97 and later versions;
513         {0xC63E, 0, L_VAR}, // "sprmPAnld" pap.anld;;variable length;
514         {0xC63F, 0, L_VAR}, // "sprmPPropRMark" pap.fPropRMark;complex
515         {0x2640, 1, L_FIX}, // "sprmPOutLvl" pap.lvl;has no effect if pap.istd
516                             // is < 1 or is > 9
517         {0x2441, 1, L_FIX}, // "sprmPFBiDi" ;;byte;
518         {0x2443, 1, L_FIX}, // "sprmPFNumRMIns" pap.fNumRMIns;1 or 0;bit;
519         {0x2444, 1, L_FIX}, // "sprmPCrLf" ;;byte;
520         {0xC645, 0, L_VAR}, // "sprmPNumRM" pap.numrm;;variable length;
521         {0x6645, 4, L_FIX}, // "sprmPHugePapx" fc in the data stream to locate
522                             // the huge grpprl
523         {0x6646, 4, L_FIX}, // "sprmPHugePapx" fc in the data stream to locate
524                             // the huge grpprl
525         {0x2447, 1, L_FIX}, // "sprmPFUsePgsuSettings" pap.fUsePgsuSettings;
526                             // 1 or 0
527         {0x2448, 1, L_FIX}, // "sprmPFAdjustRight" pap.fAdjustRight;1 or 0;byte;
528         {0x0800, 1, L_FIX}, // "sprmCFRMarkDel" chp.fRMarkDel;1 or 0;bit;
529         {0x0801, 1, L_FIX}, // "sprmCFRMark" chp.fRMark;1 or 0;bit;
530         {0x0802, 1, L_FIX}, // "sprmCFFldVanish" chp.fFldVanish;1 or 0;bit;
531         {0x6A03, 4, L_FIX}, // "sprmCPicLocation" chp.fcPic and chp.fSpec;
532         {0x4804, 2, L_FIX}, // "sprmCIbstRMark" chp.ibstRMark;index into
533                             // sttbRMark
534         {0x6805, 4, L_FIX}, // "sprmCDttmRMark" chp.dttmRMark;DTTM;long;
535         {0x0806, 1, L_FIX}, // "sprmCFData" chp.fData;1 or 0;bit;
536         {0x4807, 2, L_FIX}, // "sprmCIdslRMark" chp.idslRMReason;an index to a
537                             // table of strings defined in Word 6.0
538                             // executables;short;
539         {0xEA08, 1, L_FIX}, // "sprmCChs" chp.fChsDiff and chp.chse;
540         {0x6A09, 4, L_FIX}, // "sprmCSymbol" chp.fSpec, chp.xchSym and
541                             // chp.ftcSym
542         {0x080A, 1, L_FIX}, // "sprmCFOle2" chp.fOle2;1 or 0;bit;
543         {0x480B, 0, L_FIX}, // "sprmCIdCharType" obsolete: not applicable in
544                             // Word97 and later versions;;;
545         {0x2A0C, 1, L_FIX}, // "sprmCHighlight" chp.fHighlight,
546                             // chp.icoHighlight;ico (fHighlight is set to 1 iff
547                             // ico is not 0)
548         {0x680E, 4, L_FIX}, // "sprmCObjLocation" chp.fcObj;FC;long;
549         {0x2A10, 0, L_FIX}, // "sprmCFFtcAsciSymb" ;;;
550         {0x4A30, 2, L_FIX}, // "sprmCIstd" chp.istd;istd, see stylesheet def
551         {0xCA31, 0, L_VAR}, // "sprmCIstdPermute" chp.istd;permutation vector
552         {0x2A32, 0, L_VAR}, // "sprmCDefault" whole CHP;none;variable length;
553         {0x2A33, 0, L_FIX}, // "sprmCPlain" whole CHP;none;0;
554         {0x2A34, 1, L_FIX}, // "sprmCKcd" ;;;
555         {0x0835, 1, L_FIX}, // "sprmCFBold" chp.fBold;0,1, 128, or 129
556         {0x0836, 1, L_FIX}, // "sprmCFItalic" chp.fItalic;0,1, 128, or 129
557         {0x0837, 1, L_FIX}, // "sprmCFStrike" chp.fStrike;0,1, 128, or 129
558         {0x0838, 1, L_FIX}, // "sprmCFOutline" chp.fOutline;0,1, 128, or 129
559         {0x0839, 1, L_FIX}, // "sprmCFShadow" chp.fShadow;0,1, 128, or 129
560         {0x083A, 1, L_FIX}, // "sprmCFSmallCaps" chp.fSmallCaps;0,1, 128, or 129
561         {0x083B, 1, L_FIX}, // "sprmCFCaps" chp.fCaps;0,1, 128, or 129
562         {0x083C, 1, L_FIX}, // "sprmCFVanish" chp.fVanish;0,1, 128, or 129
563         {0x4A3D, 2, L_FIX}, // "sprmCFtcDefault" ;ftc, only used internally
564         {0x2A3E, 1, L_FIX}, // "sprmCKul" chp.kul;kul;byte;
565         {0xEA3F, 3, L_FIX}, // "sprmCSizePos" chp.hps, chp.hpsPos;3 bytes;
566         {0x8840, 2, L_FIX}, // "sprmCDxaSpace" chp.dxaSpace;dxa;word;
567         {0x4A41, 2, L_FIX}, // "sprmCLid" ;only used internally never stored
568         {0x2A42, 1, L_FIX}, // "sprmCIco" chp.ico;ico;byte;
569         {0x4A43, 2, L_FIX}, // "sprmCHps" chp.hps;hps
570         {0x2A44, 1, L_FIX}, // "sprmCHpsInc" chp.hps;
571         {0x4845, 2, L_FIX}, // "sprmCHpsPos" chp.hpsPos;hps;short; (doc wrong)
572         {0x2A46, 1, L_FIX}, // "sprmCHpsPosAdj" chp.hpsPos;hps
573         {0xCA47, 0, L_VAR}, // "sprmCMajority" chp.fBold, chp.fItalic,
574                             // chp.fSmallCaps, chp.fVanish, chp.fStrike,
575                             // chp.fCaps, chp.rgftc, chp.hps, chp.hpsPos,
576                             // chp.kul, chp.dxaSpace, chp.ico,
577                             // chp.rglid;complex;variable length, length byte
578                             // plus size of following grpprl;
579         {0x2A48, 1, L_FIX}, // "sprmCIss" chp.iss;iss;byte;
580         {0xCA49, 0, L_VAR}, // "sprmCHpsNew50" chp.hps;hps;variable width
581         {0xCA4A, 0, L_VAR}, // "sprmCHpsInc1" chp.hps;complex
582         {0x484B, 2, L_FIX}, // "sprmCHpsKern" chp.hpsKern;hps;short;
583         {0xCA4C, 2, L_FIX}, // "sprmCMajority50" chp.fBold, chp.fItalic,
584                             // chp.fSmallCaps, chp.fVanish, chp.fStrike,
585                             // chp.fCaps, chp.ftc, chp.hps, chp.hpsPos, chp.kul,
586                             // chp.dxaSpace, chp.ico,;complex
587         {0x4A4D, 2, L_FIX}, // "sprmCHpsMul" chp.hps;percentage to grow hps
588         {0x484E, 2, L_FIX}, // "sprmCYsri" chp.ysri;ysri;short;
589         {0x4A4F, 2, L_FIX}, // "sprmCRgFtc0" chp.rgftc[0];ftc for ASCII text
590         {0x4A50, 2, L_FIX}, // "sprmCRgFtc1" chp.rgftc[1];ftc for Far East text
591         {0x4A51, 2, L_FIX}, // "sprmCRgFtc2" chp.rgftc[2];ftc for non-FE text
592         {0x4852, 2, L_FIX}, // "sprmCCharScale"
593         {0x2A53, 1, L_FIX}, // "sprmCFDStrike" chp.fDStrike;;byte;
594         {0x0854, 1, L_FIX}, // "sprmCFImprint" chp.fImprint;1 or 0;bit;
595         {0x0855, 1, L_FIX}, // "sprmCFSpec" chp.fSpec ;1 or 0;bit;
596         {0x0856, 1, L_FIX}, // "sprmCFObj" chp.fObj;1 or 0;bit;
597         {0xCA57, 0, L_VAR}, // "sprmCPropRMark" chp.fPropRMark,
598                             // chp.ibstPropRMark, chp.dttmPropRMark;Complex
599         {0x0858, 1, L_FIX}, // "sprmCFEmboss" chp.fEmboss;1 or 0;bit;
600         {0x2859, 1, L_FIX}, // "sprmCSfxText" chp.sfxtText;text animation;byte;
601         {0x085A, 1, L_FIX}, // "sprmCFBiDi" ;;;
602         {0x085B, 1, L_FIX}, // "sprmCFDiacColor" ;;;
603         {0x085C, 1, L_FIX}, // "sprmCFBoldBi" ;;;
604         {0x085D, 1, L_FIX}, // "sprmCFItalicBi" ;;;
605         {0x4A5E, 2, L_FIX},
606         {0x485F, 2, L_FIX}, // "sprmCLidBi" ;;;
607         {0x4A60, 1, L_FIX}, // "sprmCIcoBi" ;;;
608         {0x4A61, 2, L_FIX}, // "sprmCHpsBi" ;;;
609         {0xCA62, 0, L_VAR}, // "sprmCDispFldRMark" chp.fDispFldRMark,
610                             // chp.ibstDispFldRMark, chp.dttmDispFldRMark ;
611         {0x4863, 2, L_FIX}, // "sprmCIbstRMarkDel" chp.ibstRMarkDel;index into
612                             // sttbRMark;short;
613         {0x6864, 4, L_FIX}, // "sprmCDttmRMarkDel" chp.dttmRMarkDel;DTTM;long;
614         {0x6865, 4, L_FIX}, // "sprmCBrc" chp.brc;BRC;long;
615         {0x4866, 2, L_FIX}, // "sprmCShd" chp.shd;SHD;short;
616         {0x4867, 2, L_FIX}, // "sprmCIdslRMarkDel" chp.idslRMReasonDel;an index
617                             // to a table of strings defined in Word 6.0
618                             // executables;short;
619         {0x0868, 1, L_FIX}, // "sprmCFUsePgsuSettings"
620                             // chp.fUsePgsuSettings;1 or 0
621         {0x486B, 2, L_FIX}, // "sprmCCpg" ;;word;
622         {0x486D, 2, L_FIX}, // "sprmCRgLid0" chp.rglid[0];LID: for non-FE text
623         {0x486E, 2, L_FIX}, // "sprmCRgLid1" chp.rglid[1];LID: for Far East text
624         {0x286F, 1, L_FIX}, // "sprmCIdctHint" chp.idctHint;IDCT:
625         {0x2E00, 1, L_FIX}, // "sprmPicBrcl" pic.brcl;brcl (see PIC definition)
626         {0xCE01, 0, L_VAR}, // "sprmPicScale" pic.mx, pic.my, pic.dxaCropleft,
627                             // pic.dyaCropTop pic.dxaCropRight,
628                             // pic.dyaCropBottom;Complex
629         {0x6C02, 4, L_FIX}, // "sprmPicBrcTop" pic.brcTop;BRC;long;
630         {0x6C03, 4, L_FIX}, // "sprmPicBrcLeft" pic.brcLeft;BRC;long;
631         {0x6C04, 4, L_FIX}, // "sprmPicBrcBottom" pic.brcBottom;BRC;long;
632         {0x6C05, 4, L_FIX}, // "sprmPicBrcRight" pic.brcRight;BRC;long;
633         {0x3000, 1, L_FIX}, // "sprmScnsPgn" sep.cnsPgn;cns;byte;
634         {0x3001, 1, L_FIX}, // "sprmSiHeadingPgn" sep.iHeadingPgn;heading number
635                             // level;byte;
636         {0xD202, 0, L_VAR}, // "sprmSOlstAnm" sep.olstAnm;OLST;variable length;
637         {0xF203, 3, L_FIX}, // "sprmSDxaColWidth" sep.rgdxaColWidthSpacing;
638         {0xF204, 3, L_FIX}, // "sprmSDxaColSpacing" sep.rgdxaColWidthSpacing;
639                             // complex
640         {0x3005, 1, L_FIX}, // "sprmSFEvenlySpaced" sep.fEvenlySpaced;1 or 0
641         {0x3006, 1, L_FIX}, // "sprmSFProtected" sep.fUnlocked;1 or 0;byte;
642         {0x5007, 2, L_FIX}, // "sprmSDmBinFirst" sep.dmBinFirst;;word;
643         {0x5008, 2, L_FIX}, // "sprmSDmBinOther" sep.dmBinOther;;word;
644         {0x3009, 1, L_FIX}, // "sprmSBkc" sep.bkc;bkc;byte;
645         {0x300A, 1, L_FIX}, // "sprmSFTitlePage" sep.fTitlePage;0 or 1;byte;
646         {0x500B, 2, L_FIX}, // "sprmSCcolumns" sep.ccolM1;# of cols - 1;word;
647         {0x900C, 2, L_FIX}, // "sprmSDxaColumns" sep.dxaColumns;dxa;word;
648         {0x300D, 1, L_FIX}, // "sprmSFAutoPgn" sep.fAutoPgn;obsolete;byte;
649         {0x300E, 1, L_FIX}, // "sprmSNfcPgn" sep.nfcPgn;nfc;byte;
650         {0xB00F, 2, L_FIX}, // "sprmSDyaPgn" sep.dyaPgn;dya;short;
651         {0xB010, 2, L_FIX}, // "sprmSDxaPgn" sep.dxaPgn;dya;short;
652         {0x3011, 1, L_FIX}, // "sprmSFPgnRestart" sep.fPgnRestart;0 or 1;byte;
653         {0x3012, 1, L_FIX}, // "sprmSFEndnote" sep.fEndnote;0 or 1;byte;
654         {0x3013, 1, L_FIX}, // "sprmSLnc" sep.lnc;lnc;byte;
655         {0x3014, 1, L_FIX}, // "sprmSGprfIhdt" sep.grpfIhdt;grpfihdt
656         {0x5015, 2, L_FIX}, // "sprmSNLnnMod" sep.nLnnMod;non-neg int.;word;
657         {0x9016, 2, L_FIX}, // "sprmSDxaLnn" sep.dxaLnn;dxa;word;
658         {0xB017, 2, L_FIX}, // "sprmSDyaHdrTop" sep.dyaHdrTop;dya;word;
659         {0xB018, 2, L_FIX}, // "sprmSDyaHdrBottom" sep.dyaHdrBottom;dya;word;
660         {0x3019, 1, L_FIX}, // "sprmSLBetween" sep.fLBetween;0 or 1;byte;
661         {0x301A, 1, L_FIX}, // "sprmSVjc" sep.vjc;vjc;byte;
662         {0x501B, 2, L_FIX}, // "sprmSLnnMin" sep.lnnMin;lnn;word;
663         {0x501C, 2, L_FIX}, // "sprmSPgnStart" sep.pgnStart;pgn;word;
664         {0x301D, 1, L_FIX}, // "sprmSBOrientation" sep.dmOrientPage;dm;byte;
665         {0x301E, 1, L_FIX}, // "sprmSBCustomize" ;;;
666         {0xB01F, 2, L_FIX}, // "sprmSXaPage" sep.xaPage;xa;word;
667         {0xB020, 2, L_FIX}, // "sprmSYaPage" sep.yaPage;ya;word;
668         {0xB021, 2, L_FIX}, // "sprmSDxaLeft" sep.dxaLeft;dxa;word;
669         {0xB022, 2, L_FIX}, // "sprmSDxaRight" sep.dxaRight;dxa;word;
670         {0x9023, 2, L_FIX}, // "sprmSDyaTop" sep.dyaTop;dya;word;
671         {0x9024, 2, L_FIX}, // "sprmSDyaBottom" sep.dyaBottom;dya;word;
672         {0xB025, 2, L_FIX}, // "sprmSDzaGutter" sep.dzaGutter;dza;word;
673         {0x5026, 2, L_FIX}, // "sprmSDmPaperReq" sep.dmPaperReq;dm;word;
674         {0xD227, 0, L_VAR}, // "sprmSPropRMark" sep.fPropRMark,
675                             // sep.ibstPropRMark, sep.dttmPropRMark ;complex
676         {0x3228, 1, L_FIX}, // "sprmSFBiDi" ;;;
677         {0x3229, 1, L_FIX}, // "sprmSFFacingCol" ;;;
678         {0x322A, 1, L_FIX}, // "sprmSFRTLGutter", set to one if gutter is on
679                             // right
680         {0x702B, 4, L_FIX}, // "sprmSBrcTop" sep.brcTop;BRC;long;
681         {0x702C, 4, L_FIX}, // "sprmSBrcLeft" sep.brcLeft;BRC;long;
682         {0x702D, 4, L_FIX}, // "sprmSBrcBottom" sep.brcBottom;BRC;long;
683         {0x702E, 4, L_FIX}, // "sprmSBrcRight" sep.brcRight;BRC;long;
684         {0x522F, 2, L_FIX}, // "sprmSPgbProp" sep.pgbProp;;word;
685         {0x7030, 4, L_FIX}, // "sprmSDxtCharSpace" sep.dxtCharSpace;dxt;long;
686         {0x9031, 2, L_FIX}, // "sprmSDyaLinePitch"
687                             // sep.dyaLinePitch;dya; WRONG:long; RIGHT:short; !
688         {0x5032, 2, L_FIX}, // "sprmSClm" ;;;
689         {0x5033, 2, L_FIX}, // "sprmSTextFlow" sep.wTextFlow;complex
690         {0x5400, 2, L_FIX}, // "sprmTJc" tap.jc;jc;word (low order byte is
691                             // significant);
692         {0x9601, 2, L_FIX}, // "sprmTDxaLeft" tap.rgdxaCenter
693         {0x9602, 2, L_FIX}, // "sprmTDxaGapHalf" tap.dxaGapHalf,
694                             // tap.rgdxaCenter
695         {0x3403, 1, L_FIX}, // "sprmTFCantSplit" tap.fCantSplit;1 or 0;byte;
696         {0x3404, 1, L_FIX}, // "sprmTTableHeader" tap.fTableHeader;1 or 0;byte;
697         {0x3466, 1, L_FIX}, // "sprmTFCantSplit90" tap.fCantSplit90;1 or 0;byte;
698         {0xD605, 0, L_VAR}, // "sprmTTableBorders" tap.rgbrcTable;complex
699         {0xD606, 0, L_VAR}, // "sprmTDefTable10" tap.rgdxaCenter,
700                             // tap.rgtc;complex
701         {0x9407, 2, L_FIX}, // "sprmTDyaRowHeight" tap.dyaRowHeight;dya;word;
702         {0xD608, 0, L_VAR}, // "sprmTDefTable" tap.rgtc;complex
703         {0xD609, 0, L_VAR}, // "sprmTDefTableShd" tap.rgshd;complex
704         {0x740A, 4, L_FIX}, // "sprmTTlp" tap.tlp;TLP;4 bytes;
705         {0x560B, 2, L_FIX}, // "sprmTFBiDi" ;;;
706         {0x740C, 1, L_FIX}, // "sprmTHTMLProps" ;;;
707         {0xD620, 0, L_VAR}, // "sprmTSetBrc" tap.rgtc[].rgbrc;complex
708         {0x7621, 4, L_FIX}, // "sprmTInsert" tap.rgdxaCenter, tap.rgtc;complex
709         {0x5622, 2, L_FIX}, // "sprmTDelete" tap.rgdxaCenter, tap.rgtc;complex
710         {0x7623, 4, L_FIX}, // "sprmTDxaCol" tap.rgdxaCenter;complex
711         {0x5624, 0, L_VAR}, // "sprmTMerge" tap.fFirstMerged, tap.fMerged;
712         {0x5625, 0, L_VAR}, // "sprmTSplit" tap.fFirstMerged, tap.fMerged;
713         {0xD626, 0, L_VAR}, // "sprmTSetBrc10" tap.rgtc[].rgbrc;complex
714         {0x7627, 0, L_VAR}, // "sprmTSetShd" tap.rgshd;complex
715         {0x7628, 0, L_VAR}, // "sprmTSetShdOdd" tap.rgshd;complex
716         {0x7629, 4, L_FIX}, // "sprmTTextFlow" tap.rgtc[].fVerticaltap,
717                             // rgtc[].fBackwardtap, rgtc[].fRotateFont;0 or 10
718                             // or 10 or 1;word;
719         {0xD62A, 1, L_FIX}, // "sprmTDiagLine" ;;;
720         {0xD62B, 0, L_VAR}, // "sprmTVertMerge" tap.rgtc[].vertMerge
721         {0xD62C, 0, L_VAR}, // "sprmTVertAlign" tap.rgtc[].vertAlign
722         {0xCA78, 0, L_VAR}, // undocumented "sprmCDoubleLine ?"
723         {0x6649, 4, L_FIX}, // undocumented
724         {0xF614, 3, L_FIX}, // undocumented
725         {0xD612, 0, L_VAR}, // undocumented, new background colours.
726         {0xD613, 0, L_VAR}, // undocumented
727         {0xD61A, 0, L_VAR}, // undocumented
728         {0xD61B, 0, L_VAR}, // undocumented
729         {0xD61C, 0, L_VAR}, // undocumented
730         {0xD61D, 0, L_VAR}, // undocumented
731         {0xD632, 0, L_VAR}, // undocumented
732         {0xD634, 0, L_VAR}, // undocumented
733         {0xD238, 0, L_VAR}, // undocumented sep
734         {0xC64E, 0, L_VAR}, // undocumented
735         {0xC64F, 0, L_VAR}, // undocumented
736         {0xC650, 0, L_VAR}, // undocumented
737         {0xC651, 0, L_VAR}, // undocumented
738         {0xF661, 3, L_FIX}, // undocumented
739         {0x4873, 2, L_FIX}, // undocumented
740         {0x4874, 2, L_FIX}, // undocumented
741         {0x6463, 4, L_FIX}, // undocumented
742         {0x2461, 1, L_FIX}, // undoc, must be asian version of "sprmPJc"
743         {0x845D, 2, L_FIX}, // undoc, must be asian version of "sprmPDxaRight"
744         {0x845E, 2, L_FIX}, // undoc, must be asian version of "sprmPDxaLeft"
745         {0x8460, 2, L_FIX}, // undoc, must be asian version of "sprmPDxaLeft1"
746         {0x3615, 1, L_FIX}, // undocumented
747         {0x360D, 1, L_FIX}, // undocumented
748         {0x703A, 4, L_FIX}, // undocumented, sep, perhaps related to textgrids ?
749         {0x303B, 1, L_FIX}, // undocumented, sep
750         {0x244B, 1, L_FIX}, // undocumented, subtable "sprmPFInTable" equiv ?
751         {0x244C, 1, L_FIX}, // undocumented, subtable "sprmPFTtp" equiv ?
752         {0x940E, 2, L_FIX}, // undocumented
753         {0x940F, 2, L_FIX}, // undocumented
754         {0x9410, 2, L_FIX}, // undocumented
755         {0x6815, 4, L_FIX}, // undocumented
756         {0x6816, 4, L_FIX}, // undocumented
757         {0x6870, 4, L_FIX}, // undocumented, text colour
758         {0xC64D, 0, L_VAR}, // undocumented, para back colour
759         {0x6467, 4, L_FIX}, // undocumented
760         {0x646B, 4, L_FIX}, // undocumented
761         {0xF617, 3, L_FIX}, // undocumented
762         {0xD660, 0, L_VAR}, // undocumented, something to do with colour.
763         {0xD670, 0, L_VAR}, // undocumented, something to do with colour.
764         {0xCA71, 0, L_VAR}, // undocumented, text backcolour
765         {0x303C, 1, L_FIX}, // undocumented, sep
766         {0x245B, 1, L_FIX}, // undocumented, para autobefore
767         {0x245C, 1, L_FIX}, // undocumented, para autoafter
768         // undocumented, don't add space between para of the same style
769         {0x246D, 1, L_FIX}
770     };
771 
772     static wwSprmSearcher aSprmSrch(aSprms, sizeof(aSprms) / sizeof(aSprms[0]));
773     return &aSprmSrch;
774 };
775 
776 wwSprmParser::wwSprmParser(ww::WordVersion eVersion) : meVersion(eVersion)
777 {
778     ASSERT((meVersion >= ww::eWW2 && meVersion <= ww::eWW8),
779         "Impossible value for version");
780 
781     mnDelta = (ww::IsSevenMinus(meVersion)) ? 0 : 1;
782 
783     if (meVersion <= ww::eWW2)
784         mpKnownSprms = GetWW2SprmSearcher();
785     else if (meVersion < ww::eWW8)
786         mpKnownSprms = GetWW6SprmSearcher();
787     else
788         mpKnownSprms = GetWW8SprmSearcher();
789 }
790 
791 SprmInfo wwSprmParser::GetSprmInfo(sal_uInt16 nId) const
792 {
793     // Find sprm
794     SprmInfo aSrch={0,0,0};
795     aSrch.nId = nId;
796     const SprmInfo* pFound = mpKnownSprms->search(aSrch);
797     if (pFound == 0)
798     {
799         ASSERT(ww::IsEightPlus(meVersion),
800            "Unknown ww7- sprm, dangerous, report to development");
801 
802         aSrch.nId = 0;
803         aSrch.nLen = 0;
804         //All the unknown ww7 sprms appear to be variable (which makes sense)
805         aSrch.nVari = L_VAR;
806 
807         if (ww::IsEightPlus(meVersion)) //We can recover perfectly in this case
808         {
809             aSrch.nVari = L_FIX;
810             switch (nId >> 13)
811             {
812                 case 0:
813                 case 1:
814                     aSrch.nLen = 1;
815                     break;
816                 case 2:
817                     aSrch.nLen = 2;
818                     break;
819                 case 3:
820                     aSrch.nLen = 4;
821                     break;
822                 case 4:
823                 case 5:
824                     aSrch.nLen = 2;
825                     break;
826                 case 6:
827                     aSrch.nLen = 0;
828                     aSrch.nVari =  L_VAR;
829                     break;
830                 case 7:
831                 default:
832                     aSrch.nLen = 3;
833                     break;
834             }
835         }
836 
837         pFound = &aSrch;
838     }
839     return *pFound;
840 }
841 
842 //-end
843 
844 inline sal_uInt8 Get_Byte( sal_uInt8 *& p )
845 {
846     sal_uInt8 n = SVBT8ToByte( *(SVBT8*)p );
847     p += 1;
848     return n;
849 }
850 
851 inline sal_uInt16 Get_UShort( sal_uInt8 *& p )
852 {
853     sal_uInt16 n = SVBT16ToShort( *(SVBT16*)p );
854     p += 2;
855     return n;
856 }
857 
858 inline short Get_Short( sal_uInt8 *& p )
859 {
860     return Get_UShort(p);
861 }
862 
863 inline sal_uLong Get_ULong( sal_uInt8 *& p )
864 {
865     sal_uLong n = SVBT32ToUInt32( *(SVBT32*)p );
866     p += 4;
867     return n;
868 }
869 
870 inline long Get_Long( sal_uInt8 *& p )
871 {
872     return Get_ULong(p);
873 }
874 
875 WW8SprmIter::WW8SprmIter(const sal_uInt8* pSprms_, long nLen_,
876     const wwSprmParser &rParser)
877     :  mrSprmParser(rParser), pSprms( pSprms_), nRemLen( nLen_)
878 {
879     UpdateMyMembers();
880 }
881 
882 void WW8SprmIter::SetSprms(const sal_uInt8* pSprms_, long nLen_)
883 {
884     pSprms = pSprms_;
885     nRemLen = nLen_;
886     UpdateMyMembers();
887 }
888 
889 const sal_uInt8* WW8SprmIter::operator ++( int )
890 {
891     if (nRemLen > 0 )
892     {
893         if( nRemLen >= nAktSize )
894         {
895             pSprms += nAktSize;
896             nRemLen -= nAktSize;
897             UpdateMyMembers();
898         }
899         else
900         {
901             throw( ::std::exception() );
902         }
903     }
904     return pSprms;
905 }
906 
907 void WW8SprmIter::UpdateMyMembers()
908 {
909     if (pSprms && nRemLen > (mrSprmParser.getVersion()?1:0)) //see #125180#
910     {
911         nAktId = mrSprmParser.GetSprmId(pSprms);
912         pAktParams = pSprms + mrSprmParser.DistanceToData(nAktId);
913         nAktSize = mrSprmParser.GetSprmSize(nAktId, pSprms);
914     }
915     else
916     {
917         nAktId = 0;
918         pAktParams = 0;
919         nAktSize = 0;
920         nRemLen = 0;
921     }
922 }
923 
924 const sal_uInt8* WW8SprmIter::FindSprm(sal_uInt16 nId)
925 {
926     while(GetSprms())
927     {
928         if( GetAktId() == nId )
929             return GetAktParams();              // SPRM found!
930         operator ++(0);
931     }
932 
933     return 0;                                   // SPRM _not_ found
934 }
935 
936 namespace {
937     bool IsPLCFPosArrayValid(
938         const sal_Int32* pPLCFPosArray,
939         const sal_Int32 nMaxIndex )
940     {
941         bool bIsValid = true;
942 
943         WW8_CP nValue = 0;
944         for ( sal_Int32 i = 0; i <= nMaxIndex; ++i )
945         {
946             if ( pPLCFPosArray[i] != 0 && pPLCFPosArray[i] < nValue )
947             {
948                 bIsValid = false;
949                 break;
950             }
951             nValue = pPLCFPosArray[i];
952         }
953 
954         return bIsValid;
955     }
956 }
957 
958 //-----------------------------------------
959 //      temporaerer Test
960 //-----------------------------------------
961 // WW8PLCFx_PCDAttrs halten sich an WW8PLCF_Pcd fest und besitzen deshalb keine
962 // eigenen Iteratoren. Alle sich auf Iteratoren beziehenden Methoden
963 // sind deshalb Dummies.
964 
965 WW8PLCFx_PCDAttrs::WW8PLCFx_PCDAttrs(ww::WordVersion eVersion,
966     WW8PLCFx_PCD* pPLCFx_PCD, const WW8ScannerBase* pBase)
967     : WW8PLCFx(eVersion, true), pPcdI(pPLCFx_PCD->GetPLCFIter()),
968     pPcd(pPLCFx_PCD), pGrpprls(pBase->pPieceGrpprls),
969     nGrpprls(pBase->nPieceGrpprls)
970 {
971 }
972 
973 sal_uLong WW8PLCFx_PCDAttrs::GetIdx() const
974 {
975     return 0;
976 }
977 
978 void WW8PLCFx_PCDAttrs::SetIdx( sal_uLong )
979 {
980 }
981 
982 bool WW8PLCFx_PCDAttrs::SeekPos(WW8_CP )
983 {
984     return true;
985 }
986 
987 WW8PLCFx& WW8PLCFx_PCDAttrs::operator ++( int )
988 {
989     return *this;
990 }
991 
992 WW8_CP WW8PLCFx_PCDAttrs::Where()
993 {
994     return ( pPcd ) ? pPcd->Where() : WW8_CP_MAX;
995 }
996 
997 void WW8PLCFx_PCDAttrs::GetSprms(WW8PLCFxDesc* p)
998 {
999     void* pData;
1000 
1001     p->bRealLineEnd = false;
1002     if ( !pPcdI || !pPcdI->Get(p->nStartPos, p->nEndPos, pData) )
1003     {
1004         // PLCF fully processed
1005         p->nStartPos = p->nEndPos = WW8_CP_MAX;
1006         p->pMemPos = 0;
1007         p->nSprmsLen = 0;
1008         return;
1009     }
1010 
1011     sal_uInt16 nPrm = SVBT16ToShort( ( (WW8_PCD*)pData )->prm );
1012     if ( nPrm & 1 )
1013     {
1014         // PRM Variant 2
1015         sal_uInt16 nSprmIdx = nPrm >> 1;
1016 
1017         if( nSprmIdx >= nGrpprls )
1018         {
1019             // Invalid Index
1020             p->nStartPos = p->nEndPos = WW8_CP_MAX;
1021             p->pMemPos = 0;
1022             p->nSprmsLen = 0;
1023             return;
1024         }
1025         const sal_uInt8* pSprms = pGrpprls[ nSprmIdx ];
1026 
1027         p->nSprmsLen = SVBT16ToShort( pSprms ); // Length
1028         pSprms += 2;
1029         p->pMemPos = pSprms;                    // Position
1030     }
1031     else
1032     {
1033         // PRM Variante 1:  Sprm wird direkt in Member-Var abgelegt
1034         /*
1035             Dies sind die Attr, die in der Piece-Table stehen, statt im Text !
1036         */
1037 
1038         if (IsSevenMinus(GetFIBVersion()))
1039         {
1040             aShortSprm[0] = (sal_uInt8)( ( nPrm & 0xfe) >> 1 );
1041             aShortSprm[1] = (sal_uInt8)(   nPrm         >> 8 );
1042             p->nSprmsLen = ( nPrm ) ? 2 : 0;        // Laenge
1043 
1044             // store Postion of internal mini storage in Data Pointer
1045             p->pMemPos = aShortSprm;
1046         }
1047         else
1048         {
1049             p->pMemPos = 0;
1050             p->nSprmsLen = 0;
1051             sal_uInt8 nSprmListIdx = (sal_uInt8)((nPrm & 0xfe) >> 1);
1052             if( nSprmListIdx )
1053             {
1054                 // process Sprm Id Matching as explained in MS Doku
1055                 //
1056                 // ''Property Modifier(variant 1) (PRM)''
1057                 // see file: s62f39.htm
1058                 //
1059                 // Since isprm is 7 bits, rgsprmPrm can hold 0x80 entries.
1060                 static const sal_uInt16 aSprmId[0x80] =
1061                 {
1062                     // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1063                     0x0000,0x0000,0x0000,0x0000,
1064                     // sprmPIncLvl, sprmPJc, sprmPFSideBySide, sprmPFKeep
1065                     0x2402,0x2403,0x2404,0x2405,
1066                     // sprmPFKeepFollow, sprmPFPageBreakBefore, sprmPBrcl,
1067                     // sprmPBrcp
1068                     0x2406,0x2407,0x2408,0x2409,
1069                     // sprmPIlvl, sprmNoop, sprmPFNoLineNumb, sprmNoop
1070                     0x260A,0x0000,0x240C,0x0000,
1071                     // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1072                     0x0000,0x0000,0x0000,0x0000,
1073                     // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1074                     0x0000,0x0000,0x0000,0x0000,
1075                     // sprmPFInTable, sprmPFTtp, sprmNoop, sprmNoop
1076                     0x2416,0x2417,0x0000,0x0000,
1077                     // sprmNoop, sprmPPc,  sprmNoop, sprmNoop
1078                     0x0000,0x261B,0x0000,0x0000,
1079                     // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1080                     0x0000,0x0000,0x0000,0x0000,
1081                     // sprmNoop, sprmPWr,  sprmNoop, sprmNoop
1082                     0x0000,0x2423,0x0000,0x0000,
1083                     // sprmNoop, sprmNoop, sprmNoop, sprmNoop
1084                     0x0000,0x0000,0x0000,0x0000,
1085                     // sprmPFNoAutoHyph, sprmNoop, sprmNoop, sprmNoop
1086                     0x242A,0x0000,0x0000,0x0000,
1087                     // sprmNoop, sprmNoop, sprmPFLocked, sprmPFWidowControl
1088                     0x0000,0x0000,0x2430,0x2431,
1089                     // sprmNoop, sprmPFKinsoku, sprmPFWordWrap,
1090                     // sprmPFOverflowPunct
1091                     0x0000,0x2433,0x2434,0x2435,
1092                     // sprmPFTopLinePunct, sprmPFAutoSpaceDE,
1093                     // sprmPFAutoSpaceDN, sprmNoop
1094                     0x2436,0x2437,0x2438,0x0000,
1095                     // sprmNoop, sprmPISnapBaseLine, sprmNoop, sprmNoop
1096                     0x0000,0x243B,0x000,0x0000,
1097                     // sprmNoop, sprmCFStrikeRM, sprmCFRMark, sprmCFFldVanish
1098                     0x0000,0x0800,0x0801,0x0802,
1099                     // sprmNoop, sprmNoop, sprmNoop, sprmCFData
1100                     0x0000,0x0000,0x0000,0x0806,
1101                     // sprmNoop, sprmNoop, sprmNoop, sprmCFOle2
1102                     0x0000,0x0000,0x0000,0x080A,
1103                     // sprmNoop, sprmCHighlight, sprmCFEmboss, sprmCSfxText
1104                     0x0000,0x2A0C,0x0858,0x2859,
1105                     // sprmNoop, sprmNoop, sprmNoop, sprmCPlain
1106                     0x0000,0x0000,0x0000,0x2A33,
1107                     // sprmNoop, sprmCFBold, sprmCFItalic, sprmCFStrike
1108                     0x0000,0x0835,0x0836,0x0837,
1109                     // sprmCFOutline, sprmCFShadow, sprmCFSmallCaps, sprmCFCaps,
1110                     0x0838,0x0839,0x083a,0x083b,
1111                     // sprmCFVanish, sprmNoop, sprmCKul, sprmNoop,
1112                     0x083C,0x0000,0x2A3E,0x0000,
1113                     // sprmNoop, sprmNoop, sprmCIco, sprmNoop,
1114                     0x0000,0x0000,0x2A42,0x0000,
1115                     // sprmCHpsInc, sprmNoop, sprmCHpsPosAdj, sprmNoop,
1116                     0x2A44,0x0000,0x2A46,0x0000,
1117                     // sprmCIss, sprmNoop, sprmNoop, sprmNoop,
1118                     0x2A48,0x0000,0x0000,0x0000,
1119                     // sprmNoop, sprmNoop, sprmNoop, sprmNoop,
1120                     0x0000,0x0000,0x0000,0x0000,
1121                     // sprmNoop, sprmNoop, sprmNoop, sprmCFDStrike,
1122                     0x0000,0x0000,0x0000,0x2A53,
1123                     // sprmCFImprint, sprmCFSpec, sprmCFObj, sprmPicBrcl,
1124                     0x0854,0x0855,0x0856,0x2E00,
1125                     // sprmPOutLvl, sprmPFBiDi, sprmNoop, sprmNoop,
1126                     0x2640,0x2441,0x0000,0x0000,
1127                     // sprmNoop, sprmNoop, sprmPPnbrRMarkNot
1128                     0x0000,0x0000,0x0000,0x0000
1129                 };
1130 
1131                 // find real Sprm Id:
1132                 sal_uInt16 nSprmId = aSprmId[ nSprmListIdx ];
1133 
1134                 if( nSprmId )
1135                 {
1136                     // move Sprm Id and Sprm Param to internal mini storage:
1137                     aShortSprm[0] = (sal_uInt8)( ( nSprmId & 0x00ff)      );
1138                     aShortSprm[1] = (sal_uInt8)( ( nSprmId & 0xff00) >> 8 );
1139                     aShortSprm[2] = (sal_uInt8)( nPrm >> 8 );
1140 
1141                     // store Sprm Length in member:
1142                     p->nSprmsLen = ( nPrm ) ? 3 : 0;
1143 
1144                     // store Postion of internal mini storage in Data Pointer
1145                     p->pMemPos = aShortSprm;
1146                 }
1147             }
1148         }
1149     }
1150 }
1151 
1152 //------------------------------------------------------------------------
1153 
1154 WW8PLCFx_PCD::WW8PLCFx_PCD(ww::WordVersion eVersion, WW8PLCFpcd* pPLCFpcd,
1155     WW8_CP nStartCp, bool bVer67P)
1156     : WW8PLCFx(eVersion, false), nClipStart(-1)
1157 {
1158     // eigenen Iterator konstruieren
1159     pPcdI = new WW8PLCFpcd_Iter(*pPLCFpcd, nStartCp);
1160     bVer67= bVer67P;
1161 }
1162 
1163 WW8PLCFx_PCD::~WW8PLCFx_PCD()
1164 {
1165     // pPcd-Dtor which in called from WW8ScannerBase
1166     delete pPcdI;
1167 }
1168 
1169 sal_uLong WW8PLCFx_PCD::GetIMax() const
1170 {
1171     return pPcdI ? pPcdI->GetIMax() : 0;
1172 }
1173 
1174 sal_uLong WW8PLCFx_PCD::GetIdx() const
1175 {
1176     return pPcdI ? pPcdI->GetIdx() : 0;
1177 }
1178 
1179 void WW8PLCFx_PCD::SetIdx( sal_uLong nIdx )
1180 {
1181     if (pPcdI)
1182         pPcdI->SetIdx( nIdx );
1183 }
1184 
1185 bool WW8PLCFx_PCD::SeekPos(WW8_CP nCpPos)
1186 {
1187     return pPcdI ? pPcdI->SeekPos( nCpPos ) : false;
1188 }
1189 
1190 WW8_CP WW8PLCFx_PCD::Where()
1191 {
1192     return pPcdI ? pPcdI->Where() : WW8_CP_MAX;
1193 }
1194 
1195 long WW8PLCFx_PCD::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
1196 {
1197     void* pData;
1198     rLen = 0;
1199 
1200     if ( !pPcdI || !pPcdI->Get(rStart, rEnd, pData) )
1201     {
1202         rStart = rEnd = WW8_CP_MAX;
1203         return -1;
1204     }
1205     return pPcdI->GetIdx();
1206 }
1207 
1208 WW8PLCFx& WW8PLCFx_PCD::operator ++( int )
1209 {
1210     if (pPcdI)
1211         (*pPcdI)++;
1212     else {
1213         ASSERT( !this, "pPcdI fehlt");
1214     }
1215     return *this;
1216 }
1217 
1218 WW8_FC WW8PLCFx_PCD::AktPieceStartCp2Fc( WW8_CP nCp )
1219 {
1220     WW8_CP nCpStart, nCpEnd;
1221     void* pData;
1222 
1223     if ( !pPcdI->Get(nCpStart, nCpEnd, pData) )
1224     {
1225         ASSERT( !this, "AktPieceStartCp2Fc() with false Cp found (1)" );
1226         return WW8_FC_MAX;
1227     }
1228 
1229     ASSERT( nCp >= nCpStart && nCp < nCpEnd,
1230         "AktPieceCp2Fc() with false Cp found (2)" );
1231 
1232     if( nCp < nCpStart )
1233         nCp = nCpStart;
1234     if( nCp >= nCpEnd )
1235         nCp = nCpEnd - 1;
1236 
1237     bool bIsUnicode = false;
1238     WW8_FC nFC = SVBT32ToUInt32( ((WW8_PCD*)pData)->fc );
1239     if( !bVer67 )
1240         nFC = WW8PLCFx_PCD::TransformPieceAddress( nFC, bIsUnicode );
1241 
1242     return nFC + (nCp - nCpStart) * (bIsUnicode ? 2 : 1);
1243 }
1244 
1245 
1246 void WW8PLCFx_PCD::AktPieceFc2Cp( WW8_CP& rStartPos, WW8_CP& rEndPos,
1247     const WW8ScannerBase *pSBase )
1248 {
1249     //No point going anywhere with this
1250     if ((rStartPos == WW8_CP_MAX) && (rEndPos == WW8_CP_MAX))
1251         return;
1252 
1253     rStartPos = pSBase->WW8Fc2Cp( rStartPos );
1254     rEndPos = pSBase->WW8Fc2Cp( rEndPos );
1255 }
1256 
1257 WW8_CP WW8PLCFx_PCD::AktPieceStartFc2Cp( WW8_FC nStartPos )
1258 {
1259     WW8_CP nCpStart, nCpEnd;
1260     void* pData;
1261     if ( !pPcdI->Get( nCpStart, nCpEnd, pData ) )
1262     {
1263         ASSERT( !this, "AktPieceStartFc2Cp() - Fehler" );
1264         return WW8_CP_MAX;
1265     }
1266     bool bIsUnicode = false;
1267     sal_Int32 nFcStart  = SVBT32ToUInt32( ((WW8_PCD*)pData)->fc );
1268     if( !bVer67 )
1269         nFcStart = WW8PLCFx_PCD::TransformPieceAddress( nFcStart, bIsUnicode );
1270 
1271     sal_Int32 nUnicodeFactor = bIsUnicode ? 2 : 1;
1272 
1273     if( nStartPos < nFcStart )
1274         nStartPos = nFcStart;
1275 
1276     if( nStartPos >= nFcStart + (nCpEnd - nCpStart)     * nUnicodeFactor )
1277         nStartPos  = nFcStart + (nCpEnd - nCpStart - 1) * nUnicodeFactor;
1278 
1279     return nCpStart + (nStartPos - nFcStart) / nUnicodeFactor;
1280 }
1281 
1282 //-----------------------------------------
1283 //      Hilfsroutinen fuer alle
1284 //-----------------------------------------
1285 
1286 short WW8_BRC::DetermineBorderProperties(bool bVer67, short *pSpace,
1287     sal_uInt8 *pCol, short *pIdx) const
1288 {
1289     /*
1290         Word does not factor the width of the border into the width/height
1291         stored in the information for graphic/table/object widths, so we need
1292         to figure out this extra width here and utilize the returned size in
1293         our calculations
1294     */
1295     short nMSTotalWidth;
1296     sal_uInt8 nCol;
1297     short nIdx,nSpace;
1298     if( bVer67 )
1299     {
1300         sal_uInt16 aBrc1 = SVBT16ToShort(aBits1);
1301         nCol = static_cast< sal_uInt8 >((aBrc1 >> 6) & 0x1f);   // aBor.ico
1302         nSpace = (aBrc1 & 0xF800) >> 11;
1303 
1304         nMSTotalWidth = aBrc1 & 0x07;
1305         nIdx = (aBrc1 & 0x18) >> 3;
1306         //Dashed/Dotted unsets double/thick
1307         if (nMSTotalWidth > 5)
1308         {
1309             nMSTotalWidth=1;
1310             nIdx = 1;
1311         }
1312         nMSTotalWidth = nMSTotalWidth * nIdx * 15;
1313     }
1314     else
1315     {
1316         nIdx = aBits1[1];
1317         nCol = aBits2[0];   // aBor.ico
1318         nSpace = aBits2[1] & 0x1F; //space between line and object
1319 
1320         //Specification in 8ths of a point, 1 Point = 20 Twips, so by 2.5
1321         nMSTotalWidth  = aBits1[ 0 ] * 20 / 8;
1322 
1323         //Figure out the real size of the border according to word
1324         switch (nIdx)
1325         {
1326             //Note that codes over 25 are undocumented, and I can't create
1327             //these 4 here in the wild.
1328             default:
1329             case 2:
1330             case 4:
1331             case 5:
1332             case 22:
1333                 DBG_WARNING("Can't create these from the menus, please report");
1334             case 1:
1335             case 6:
1336             case 7:
1337             case 8:
1338             case 9:
1339             case 23:    //Only 3pt in the menus, but honours the size setting.
1340                 break;
1341             case 3:
1342                 /*
1343                 double line is three times the width of an ordinary line,
1344                 except for the smallest 1/4 point size which appears to have
1345                 exactly the same total border width as a 1/2 point size
1346                 ordinary line, i.e. twice the nominal line width
1347                 */
1348                 nMSTotalWidth = (nMSTotalWidth == 5) ?
1349                     nMSTotalWidth*2 : nMSTotalWidth*3;
1350                 break;
1351             case 10:
1352                 /*
1353                 triple line is five times the width of an ordinary line,
1354                 except that the smallest 1/4 point size appears to have
1355                 exactly the same total border width as a 3/4 point size
1356                 ordinary line, i.e. three times the nominal line width.  The
1357                 second smallest 1/2 point size appears to have exactly the
1358                 total border width as a 2 1/4 border, i.e 4.5 times the size.
1359                 */
1360                 if (nMSTotalWidth == 5)
1361                     nMSTotalWidth*=3;
1362                 else if (nMSTotalWidth == 10)
1363                     nMSTotalWidth = nMSTotalWidth*9/2;
1364                 else
1365                     nMSTotalWidth*=5;
1366                 break;
1367             case 11:
1368             case 12:
1369                 /*
1370                 small gap thin thick and thick thin appears to have a 3/4
1371                 point line, a 3/4 point gap and a thick line of the specified
1372                 width
1373                 */
1374                 nMSTotalWidth = nMSTotalWidth + 15*2;
1375                 break;
1376             case 13:
1377                 /*
1378                 thin thick thin appears to have two outside 3/4 point lines,
1379                 two 3/4 point gaps and a thick line of the specified width
1380                 */
1381                 nMSTotalWidth = nMSTotalWidth + 15*4;
1382                 break;
1383             case 14:
1384             case 15:
1385                 /*
1386                 medium gap thin thick and thick thin appears to have a line
1387                 50% of the thick line, and an equal sized gap and then the
1388                 thick line of the specified width. But it appears to only
1389                 use one of the existing predefined widths for the thin line,
1390                 so the closest smallest existing border to the halved thick
1391                 line is used.
1392                 */
1393                 switch (nMSTotalWidth)
1394                 {
1395                     case 45:    //2 1/4, closest to half is 1
1396                         nMSTotalWidth += 20 + (nMSTotalWidth-1)/2;
1397                         break;
1398                     case 5:
1399                     case 10:
1400                         nMSTotalWidth += 5;
1401                         break;
1402                     case 15:    //3/4, closest to half is 1/4
1403                         nMSTotalWidth += 5 + (nMSTotalWidth-1)/2;
1404                         break;
1405                     default:
1406                         nMSTotalWidth*=2;
1407                         break;
1408                 }
1409                 break;
1410             case 16:
1411                 /*
1412                 medium gap thin thick thin appears to have a line
1413                 50% of the thick line, and an equal sized gap and then the
1414                 thick line of the specified width. But it appears to only
1415                 use one of the existing predefined widths for the thin
1416                 line, so the closest smallest existing border to the halved
1417                 thick line is used. Though some fudging at smaller sizes is
1418                 still required.
1419                 */
1420                 switch (nMSTotalWidth)
1421                 {
1422                     case 45:    //2 1/4, closest to half is 1
1423                         nMSTotalWidth += nMSTotalWidth + 20 * 2;
1424                         break;
1425                     case 20:
1426                     case 15:
1427                         nMSTotalWidth += nMSTotalWidth + 7 * 2;
1428                         break;
1429                     case 10:
1430                     case 5:
1431                         nMSTotalWidth += 5 + 4;
1432                         break;
1433                     default:
1434                         nMSTotalWidth*=3;
1435                         break;
1436                 }
1437                 break;
1438             case 17:
1439             case 18:
1440                 /*
1441                 large gap thin thick and thick thin appears to have a thick
1442                 line of 1 1/2 pt and a narrow of 3/4 point, with a distance
1443                 between the two of the explicitly set line width
1444                 */
1445                 nMSTotalWidth+=15+30;
1446                 break;
1447             case 19:
1448                 /*
1449                 large gap thin thick thin appears to have a thick line of 1
1450                 1/2 pt and two narrows of 3/4 point, with a distance between
1451                 the two of the explicitly set line width, though the narrowest
1452                 line appears to behave as if it was even smaller
1453                 */
1454                 if (nMSTotalWidth == 5)
1455                     nMSTotalWidth = 3;
1456                 nMSTotalWidth = nMSTotalWidth*2 + 15*2 + 30;
1457                 break;
1458             case 20:
1459                 /*
1460                 wave, the dimensions appear to be created by the drawing of
1461                 the wave, so we have only two possibilites in the menus, 3/4
1462                 point is equal to solid 3 point. This calculation seems to
1463                 match well to results.
1464                 */
1465                 nMSTotalWidth +=45;
1466                 break;
1467             case 21:
1468                 /*
1469                 double wave, the dimensions appear to be created by the
1470                 drawing of the wave, so we have only one possibilites in the
1471                 menus, that of 3/4 point is equal to solid 3 point. This
1472                 calculation seems to match well to results.
1473                 */
1474                 nMSTotalWidth += 45*2;
1475                 break;
1476             case 24:
1477             case 25:
1478                 /*
1479                 emboss and engrave consist of a three lines, the central is of
1480                 the explicit point width, the other two (of equal size to each
1481                 other are the shadows and are either 3/4 pt of 1 1/2 depending
1482                 on if the central line is greater of less than 2 1/4 pt
1483                 */
1484                 if (nMSTotalWidth <= 45)
1485                     nMSTotalWidth += 2*15;
1486                 else
1487                     nMSTotalWidth += 2*30;
1488                 break;
1489         }
1490     }
1491 
1492     if (pIdx)
1493         *pIdx = nIdx;
1494     if (pSpace)
1495         *pSpace = nSpace*20;
1496     if (pCol)
1497         *pCol = nCol;
1498     return nMSTotalWidth;
1499 }
1500 
1501 WW8_CP WW8ScannerBase::WW8Fc2Cp( WW8_FC nFcPos ) const
1502 {
1503     WW8_CP nFallBackCpEnd = WW8_CP_MAX;
1504     if( nFcPos == WW8_FC_MAX )
1505         return nFallBackCpEnd;
1506 
1507     bool bIsUnicode = false;
1508     if( pPieceIter )    // Complex File ?
1509     {
1510         sal_uLong nOldPos = pPieceIter->GetIdx();
1511 
1512         for (pPieceIter->SetIdx(0);
1513             pPieceIter->GetIdx() < pPieceIter->GetIMax();(*pPieceIter)++)
1514         {
1515             WW8_CP nCpStart, nCpEnd;
1516             void* pData;
1517             if( !pPieceIter->Get( nCpStart, nCpEnd, pData ) )
1518             {   // ausserhalb PLCFfpcd ?
1519                 ASSERT( !this, "PLCFpcd-WW8Fc2Cp() ging schief" );
1520                 break;
1521             }
1522             sal_Int32 nFcStart  = SVBT32ToUInt32( ((WW8_PCD*)pData)->fc );
1523             if( 8 <= pWw8Fib->nVersion )
1524             {
1525                 nFcStart = WW8PLCFx_PCD::TransformPieceAddress( nFcStart,
1526                                                                 bIsUnicode );
1527             }
1528             else
1529             {
1530                 if (pWw8Fib->fExtChar)
1531                     bIsUnicode=true;
1532             }
1533             sal_Int32 nLen = (nCpEnd - nCpStart) * (bIsUnicode ? 2 : 1);
1534 
1535             /*
1536             If this cp is inside this piece, or its the last piece and we are
1537             on the very last cp of that piece
1538             */
1539             if (nFcPos >= nFcStart)
1540             {
1541                 // found
1542                 WW8_CP nTempCp =
1543                     nCpStart + ((nFcPos - nFcStart) / (bIsUnicode ? 2 : 1));
1544                 if (nFcPos < nFcStart + nLen)
1545                 {
1546                     pPieceIter->SetIdx( nOldPos );
1547                     return nTempCp;
1548                 }
1549                 else if (nFcPos == nFcStart + nLen)
1550                 {
1551                     //Keep this cp as its on a piece boundary because we might
1552                     //need it if tests fail
1553                     nFallBackCpEnd = nTempCp;
1554                 }
1555             }
1556         }
1557         // not found
1558         pPieceIter->SetIdx( nOldPos );      // not found
1559         /*
1560         If it was not found, then this is because it has fallen between two
1561         stools, i.e. either it is the last cp/fc of the last piece, or it is
1562         the last cp/fc of a disjoint piece.
1563         */
1564         return nFallBackCpEnd;
1565     }
1566     // No complex file
1567     if (pWw8Fib->fExtChar)
1568         bIsUnicode=true;
1569     return ((nFcPos - pWw8Fib->fcMin) / (bIsUnicode ? 2 : 1));
1570 }
1571 
1572 WW8_FC WW8ScannerBase::WW8Cp2Fc(WW8_CP nCpPos, bool* pIsUnicode,
1573     WW8_CP* pNextPieceCp, bool* pTestFlag) const
1574 {
1575     if( pTestFlag )
1576         *pTestFlag = true;
1577     if( WW8_CP_MAX == nCpPos )
1578         return WW8_CP_MAX;
1579 
1580     bool bIsUnicode;
1581     if( !pIsUnicode )
1582         pIsUnicode = &bIsUnicode;
1583 
1584     if( pPieceIter )
1585     {   // Complex File
1586         if( pNextPieceCp )
1587             *pNextPieceCp = WW8_CP_MAX;
1588 
1589         if( !pPieceIter->SeekPos( nCpPos ) )
1590         {
1591             if( pTestFlag )
1592                 *pTestFlag = false;
1593             else {
1594                 ASSERT( !this, "Falscher CP an WW8Cp2Fc() uebergeben" );
1595             }
1596             return WW8_FC_MAX;
1597         }
1598         WW8_CP nCpStart, nCpEnd;
1599         void* pData;
1600         if( !pPieceIter->Get( nCpStart, nCpEnd, pData ) )
1601         {
1602             if( pTestFlag )
1603                 *pTestFlag = false;
1604             else {
1605                 ASSERT( !this, "PLCFfpcd-Get ging schief" );
1606             }
1607             return WW8_FC_MAX;
1608         }
1609         if( pNextPieceCp )
1610             *pNextPieceCp = nCpEnd;
1611 
1612         WW8_FC nRet = SVBT32ToUInt32( ((WW8_PCD*)pData)->fc );
1613         if (8 > pWw8Fib->nVersion)
1614 	    if (pWw8Fib->fExtChar)
1615         	    *pIsUnicode=true;
1616             else
1617                     *pIsUnicode = false;
1618         else
1619             nRet = WW8PLCFx_PCD::TransformPieceAddress( nRet, *pIsUnicode );
1620 
1621 
1622         nRet += (nCpPos - nCpStart) * (*pIsUnicode ? 2 : 1);
1623 
1624         return nRet;
1625     }
1626 
1627     // No complex file
1628     if (pWw8Fib->fExtChar)
1629         *pIsUnicode = true;
1630     else
1631         *pIsUnicode = false;
1632     return pWw8Fib->fcMin + nCpPos * (*pIsUnicode ? 2 : 1);
1633 }
1634 
1635 //-----------------------------------------
1636 //      class WW8ScannerBase
1637 //-----------------------------------------
1638 
1639 WW8PLCFpcd* WW8ScannerBase::OpenPieceTable( SvStream* pStr, const WW8Fib* pWwF )
1640 {
1641     if ( ((8 > pWw8Fib->nVersion) && !pWwF->fComplex) || !pWwF->lcbClx )
1642         return 0;
1643 
1644     WW8_FC nClxPos = pWwF->fcClx;
1645     sal_Int32 nClxLen = pWwF->lcbClx;
1646     sal_Int32 nLeft = nClxLen;
1647     sal_Int16 nGrpprl = 0;
1648     sal_uInt8 clxt;
1649 
1650     pStr->Seek( nClxPos );
1651     while( 1 ) // Zaehle Zahl der Grpprls
1652     {
1653         *pStr >> clxt;
1654         nLeft--;
1655         if( 2 == clxt )                         // PLCFfpcd ?
1656             break;                              // PLCFfpcd gefunden
1657         if( 1 == clxt )                         // clxtGrpprl ?
1658             nGrpprl++;
1659         sal_uInt16 nLen;
1660         *pStr >> nLen;
1661         nLeft -= 2 + nLen;
1662         if( nLeft < 0 )
1663             return 0;                           // schiefgegangen
1664         pStr->SeekRel( nLen );                  // ueberlies grpprl
1665     }
1666     pStr->Seek( nClxPos );
1667     nLeft = nClxLen;
1668     pPieceGrpprls = new sal_uInt8*[nGrpprl + 1];
1669     memset( pPieceGrpprls, 0, ( nGrpprl + 1 ) * sizeof(sal_uInt8 *) );
1670     nPieceGrpprls = nGrpprl;
1671     sal_Int16 nAktGrpprl = 0;                       // lies Grpprls ein
1672     while( 1 )
1673     {
1674         *pStr >> clxt;
1675         nLeft--;
1676         if( 2 == clxt)                          // PLCFfpcd ?
1677             break;                              // PLCFfpcd gefunden
1678         sal_uInt16 nLen;
1679         *pStr >> nLen;
1680         nLeft -= 2 + nLen;
1681         if( nLeft < 0 )
1682             return 0;                           // schiefgegangen
1683         if( 1 == clxt )                         // clxtGrpprl ?
1684         {
1685             sal_uInt8* p = new sal_uInt8[nLen+2];         // alloziere
1686             ShortToSVBT16(nLen, p);             // trage Laenge ein
1687             pStr->Read( p+2, nLen );            // lies grpprl
1688             pPieceGrpprls[nAktGrpprl++] = p;    // trage in Array ein
1689         }
1690         else
1691             pStr->SeekRel( nLen );              // ueberlies nicht-Grpprl
1692     }
1693     // lies Piece Table PLCF ein
1694     sal_Int32 nPLCFfLen;
1695     if (pWwF->GetFIBVersion() <= ww::eWW2)
1696     {
1697         sal_Int16 nWordTwoLen;
1698         *pStr >> nWordTwoLen;
1699         nPLCFfLen = nWordTwoLen;
1700     }
1701     else
1702         *pStr >> nPLCFfLen;
1703     ASSERT( 65536 > nPLCFfLen, "PLCFfpcd ueber 64 k" );
1704     return new WW8PLCFpcd( pStr, pStr->Tell(), nPLCFfLen, 8 );
1705 }
1706 
1707 void WW8ScannerBase::DeletePieceTable()
1708 {
1709     if( pPieceGrpprls )
1710     {
1711         for( sal_uInt8** p = pPieceGrpprls; *p; p++ )
1712             delete[] (*p);
1713         delete[] pPieceGrpprls;
1714         pPieceGrpprls = 0;
1715     }
1716 }
1717 
1718 WW8ScannerBase::WW8ScannerBase( SvStream* pSt, SvStream* pTblSt,
1719     SvStream* pDataSt, const WW8Fib* pWwFib )
1720     : pWw8Fib(pWwFib)
1721     , pChpPLCF( 0 )
1722     , pPapPLCF( 0 )
1723     , pSepPLCF( 0 )
1724     , pFtnPLCF( 0 )
1725     , pEdnPLCF( 0 )
1726     , pAndPLCF( 0 )
1727     , pFldPLCF( 0 )
1728     , pFldHdFtPLCF( 0 )
1729     , pFldTxbxPLCF( 0 )
1730     , pFldTxbxHdFtPLCF( 0 )
1731     , pFldFtnPLCF( 0 )
1732     , pFldEdnPLCF( 0 )
1733     , pFldAndPLCF( 0 )
1734     , pMainFdoa(0)
1735     , pHdFtFdoa(0)
1736     , pMainTxbx(0)
1737     , pMainTxbxBkd(0)
1738     , pHdFtTxbx(0)
1739     , pHdFtTxbxBkd(0)
1740     , pMagicTables(0)
1741     , pSubdocs(0)
1742     , pExtendedAtrds(0)
1743     , pBook( 0 )
1744     , pPiecePLCF( 0 )
1745     , pPieceIter( 0 )
1746     , pPLCFx_PCD( 0 )
1747     , pPLCFx_PCDAttrs( 0 )
1748     , pPieceGrpprls(0)
1749     , nPieceGrpprls( 0 )
1750 {
1751     pPiecePLCF = OpenPieceTable( pTblSt, pWw8Fib );             // Complex
1752     if( pPiecePLCF )
1753     {
1754         pPieceIter = new WW8PLCFpcd_Iter( *pPiecePLCF );
1755         pPLCFx_PCD = new WW8PLCFx_PCD(pWwFib->GetFIBVersion(), pPiecePLCF, 0,
1756             IsSevenMinus(pWw8Fib->GetFIBVersion()));
1757         pPLCFx_PCDAttrs = new WW8PLCFx_PCDAttrs(pWwFib->GetFIBVersion(),
1758             pPLCFx_PCD, this);
1759     }
1760     else
1761     {
1762         pPieceIter = 0;
1763         pPLCFx_PCD = 0;
1764         pPLCFx_PCDAttrs = 0;
1765     }
1766 
1767     // pChpPLCF and pPapPLCF may NOT be created before pPLCFx_PCD !!
1768     pChpPLCF = new WW8PLCFx_Cp_FKP( pSt, pTblSt, pDataSt, *this, CHP ); // CHPX
1769     pPapPLCF = new WW8PLCFx_Cp_FKP( pSt, pTblSt, pDataSt, *this, PAP ); // PAPX
1770 
1771     pSepPLCF = new WW8PLCFx_SEPX(   pSt, pTblSt, *pWwFib, 0 );          // SEPX
1772 
1773     // Footnotes
1774     pFtnPLCF = new WW8PLCFx_SubDoc( pTblSt, pWwFib->GetFIBVersion(), 0,
1775         pWwFib->fcPlcffndRef, pWwFib->lcbPlcffndRef, pWwFib->fcPlcffndTxt,
1776         pWwFib->lcbPlcffndTxt, 2 );
1777     // Endnotes
1778     pEdnPLCF = new WW8PLCFx_SubDoc( pTblSt, pWwFib->GetFIBVersion(), 0,
1779         pWwFib->fcPlcfendRef, pWwFib->lcbPlcfendRef, pWwFib->fcPlcfendTxt,
1780         pWwFib->lcbPlcfendTxt, 2 );
1781     // Anmerkungen
1782     pAndPLCF = new WW8PLCFx_SubDoc( pTblSt, pWwFib->GetFIBVersion(), 0,
1783         pWwFib->fcPlcfandRef, pWwFib->lcbPlcfandRef, pWwFib->fcPlcfandTxt,
1784         pWwFib->lcbPlcfandTxt, IsSevenMinus(pWwFib->GetFIBVersion()) ? 20 : 30);
1785 
1786     // Fields Main Text
1787     pFldPLCF    = new WW8PLCFx_FLD(pTblSt, *pWwFib, MAN_MAINTEXT);
1788     // Fields Header / Footer
1789     pFldHdFtPLCF= new WW8PLCFx_FLD(pTblSt, *pWwFib, MAN_HDFT);
1790     // Fields Footnote
1791     pFldFtnPLCF = new WW8PLCFx_FLD(pTblSt, *pWwFib, MAN_FTN);
1792     // Fields Endnote
1793     pFldEdnPLCF = new WW8PLCFx_FLD(pTblSt, *pWwFib, MAN_EDN);
1794     // Fields Anmerkungen
1795     pFldAndPLCF = new WW8PLCFx_FLD(pTblSt, *pWwFib, MAN_AND);
1796     // Fields in Textboxes in Main Text
1797     pFldTxbxPLCF= new WW8PLCFx_FLD(pTblSt, *pWwFib, MAN_TXBX);
1798     // Fields in Textboxes in Header / Footer
1799     pFldTxbxHdFtPLCF = new WW8PLCFx_FLD(pTblSt,*pWwFib,MAN_TXBX_HDFT);
1800 
1801     // Note: 6 stands for "6 OR 7",  7 stands for "ONLY 7"
1802     switch( pWw8Fib->nVersion )
1803     {
1804         case 6:
1805         case 7:
1806             if( pWwFib->fcPlcfdoaMom && pWwFib->lcbPlcfdoaMom )
1807             {
1808                 pMainFdoa = new WW8PLCFspecial( pTblSt, pWwFib->fcPlcfdoaMom,
1809                     pWwFib->lcbPlcfdoaMom, 6 );
1810             }
1811             if( pWwFib->fcPlcfdoaHdr && pWwFib->lcbPlcfdoaHdr )
1812             {
1813                 pHdFtFdoa = new WW8PLCFspecial( pTblSt, pWwFib->fcPlcfdoaHdr,
1814                 pWwFib->lcbPlcfdoaHdr, 6 );
1815             }
1816             break;
1817         case 8:
1818             if( pWwFib->fcPlcfspaMom && pWwFib->lcbPlcfspaMom )
1819             {
1820                 pMainFdoa = new WW8PLCFspecial( pTblSt, pWwFib->fcPlcfspaMom,
1821                     pWwFib->lcbPlcfspaMom, 26 );
1822             }
1823             if( pWwFib->fcPlcfspaHdr && pWwFib->lcbPlcfspaHdr )
1824             {
1825                 pHdFtFdoa = new WW8PLCFspecial( pTblSt, pWwFib->fcPlcfspaHdr,
1826                     pWwFib->lcbPlcfspaHdr, 26 );
1827             }
1828             // PLCF fuer TextBox-Break-Deskriptoren im Maintext
1829             if( pWwFib->fcPlcftxbxBkd && pWwFib->lcbPlcftxbxBkd )
1830             {
1831                 pMainTxbxBkd = new WW8PLCFspecial( pTblSt,
1832                     pWwFib->fcPlcftxbxBkd, pWwFib->lcbPlcftxbxBkd, 0);
1833             }
1834             // PLCF fuer TextBox-Break-Deskriptoren im Header-/Footer-Bereich
1835             if( pWwFib->fcPlcfHdrtxbxBkd && pWwFib->lcbPlcfHdrtxbxBkd )
1836             {
1837                 pHdFtTxbxBkd = new WW8PLCFspecial( pTblSt,
1838                     pWwFib->fcPlcfHdrtxbxBkd, pWwFib->lcbPlcfHdrtxbxBkd, 0);
1839             }
1840             // Sub table cp positions
1841             if (pWwFib->fcPlcfTch && pWwFib->lcbPlcfTch)
1842             {
1843                 pMagicTables = new WW8PLCFspecial( pTblSt,
1844                     pWwFib->fcPlcfTch, pWwFib->lcbPlcfTch, 4);
1845             }
1846             // Sub document cp positions
1847             if (pWwFib->fcPlcfwkb && pWwFib->lcbPlcfwkb)
1848             {
1849                 pSubdocs = new WW8PLCFspecial( pTblSt,
1850                     pWwFib->fcPlcfwkb, pWwFib->lcbPlcfwkb, 12);
1851             }
1852             // Extended ATRD
1853             if (pWwFib->fcAtrdExtra && pWwFib->lcbAtrdExtra)
1854             {
1855                 pExtendedAtrds = new sal_uInt8[pWwFib->lcbAtrdExtra];
1856                 long nOldPos = pTblSt->Tell();
1857                 pTblSt->Seek(pWwFib->fcAtrdExtra);
1858                 pTblSt->Read(pExtendedAtrds, pWwFib->lcbAtrdExtra);
1859                 pTblSt->Seek(nOldPos);
1860             }
1861 
1862             break;
1863         default:
1864             ASSERT( !this, "Es wurde vergessen, nVersion zu kodieren!" );
1865             break;
1866     }
1867 
1868     // PLCF fuer TextBox-Stories im Maintext
1869     long nLenTxBxS = (8 > pWw8Fib->nVersion) ? 0 : 22;
1870     if( pWwFib->fcPlcftxbxTxt && pWwFib->lcbPlcftxbxTxt )
1871     {
1872         pMainTxbx = new WW8PLCFspecial( pTblSt, pWwFib->fcPlcftxbxTxt,
1873             pWwFib->lcbPlcftxbxTxt, nLenTxBxS );
1874     }
1875 
1876     // PLCF fuer TextBox-Stories im Header-/Footer-Bereich
1877     if( pWwFib->fcPlcfHdrtxbxTxt && pWwFib->lcbPlcfHdrtxbxTxt )
1878     {
1879         pHdFtTxbx = new WW8PLCFspecial( pTblSt, pWwFib->fcPlcfHdrtxbxTxt,
1880             pWwFib->lcbPlcfHdrtxbxTxt, nLenTxBxS );
1881     }
1882 
1883     pBook = new WW8PLCFx_Book(pTblSt, *pWwFib);
1884 }
1885 
1886 bool WW8ScannerBase::IsValid()
1887 {
1888     return ( pPiecePLCF == 0 || pPiecePLCF->IsValid() )
1889            && pChpPLCF->HasValidPLCF()
1890            && pPapPLCF->HasValidPLCF()
1891            && pSepPLCF->HasValidPLCF()
1892            && pFtnPLCF->HasValidPLCF()
1893            && pEdnPLCF->HasValidPLCF()
1894            && pAndPLCF->HasValidPLCF()
1895            && pFldPLCF->HasValidPLCF()
1896            && pFldHdFtPLCF->HasValidPLCF()
1897            && pFldFtnPLCF->HasValidPLCF()
1898            && pFldEdnPLCF->HasValidPLCF()
1899            && pFldAndPLCF->HasValidPLCF()
1900            && pFldTxbxPLCF->HasValidPLCF()
1901            && pFldTxbxHdFtPLCF->HasValidPLCF()
1902            && ( pMainFdoa == 0 || pMainFdoa->IsValid() )
1903            && ( pHdFtFdoa == 0 || pHdFtFdoa->IsValid() )
1904            && ( pMainTxbxBkd == 0 || pMainTxbxBkd->IsValid() )
1905            && ( pHdFtTxbxBkd == 0 || pHdFtTxbxBkd->IsValid() )
1906            && ( pMagicTables == 0 || pMagicTables->IsValid() )
1907            && ( pSubdocs == 0 || pSubdocs->IsValid() )
1908            && ( pHdFtTxbx == 0 || pHdFtTxbx->IsValid() )
1909            && pBook->HasValidPLCF();
1910 }
1911 
1912 WW8ScannerBase::~WW8ScannerBase()
1913 {
1914     DeletePieceTable();
1915     delete pPLCFx_PCDAttrs;
1916     delete pPLCFx_PCD;
1917     delete pPieceIter;
1918     delete pPiecePLCF;
1919     delete pBook;
1920     delete pFldEdnPLCF;
1921     delete pFldFtnPLCF;
1922     delete pFldAndPLCF;
1923     delete pFldHdFtPLCF;
1924     delete pFldPLCF;
1925     delete pFldTxbxPLCF;
1926     delete pFldTxbxHdFtPLCF;
1927     delete pEdnPLCF;
1928     delete pFtnPLCF;
1929     delete pAndPLCF;
1930     delete pSepPLCF;
1931     delete pPapPLCF;
1932     delete pChpPLCF;
1933     // vergessene Schaeflein
1934     delete pMainFdoa;
1935     delete pHdFtFdoa;
1936     delete pMainTxbx;
1937     delete pMainTxbxBkd;
1938     delete pHdFtTxbx;
1939     delete pHdFtTxbxBkd;
1940     delete pMagicTables;
1941     delete pSubdocs;
1942     delete [] pExtendedAtrds;
1943 }
1944 
1945 //-----------------------------------------
1946 //          Fields
1947 //-----------------------------------------
1948 static bool WW8SkipField(WW8PLCFspecial& rPLCF)
1949 {
1950     void* pData;
1951     WW8_CP nP;
1952 
1953     if (!rPLCF.Get(nP, pData))              // Ende des PLCFspecial ?
1954         return false;
1955 
1956     rPLCF++;
1957 
1958     if((((sal_uInt8*)pData)[0] & 0x1f ) != 0x13 )    // Kein Anfang ?
1959         return true;                            // Bei Fehler nicht abbrechen
1960 
1961     if( !rPLCF.Get( nP, pData ) )
1962         return false;
1963 
1964 
1965     while((((sal_uInt8*)pData)[0] & 0x1f ) == 0x13 )
1966     {
1967         // immer noch neue (nested) Anfaenge ?
1968         WW8SkipField( rPLCF );              // nested Field im Beschreibungsteil
1969         if( !rPLCF.Get( nP, pData ) )
1970             return false;
1971     }
1972 
1973     if((((sal_uInt8*)pData)[0] & 0x1f ) == 0x14 )
1974     {
1975 
1976         // Field Separator ?
1977         rPLCF++;
1978 
1979         if( !rPLCF.Get( nP, pData ) )
1980             return false;
1981 
1982         while ((((sal_uInt8*)pData)[0] & 0x1f ) == 0x13)
1983         {
1984             // immer noch neue (nested) Anfaenge ?
1985             WW8SkipField( rPLCF );          // nested Field im Resultatteil
1986             if( !rPLCF.Get( nP, pData ) )
1987                 return false;
1988         }
1989     }
1990     rPLCF++;
1991 
1992     return true;
1993 }
1994 
1995 static bool WW8GetFieldPara(WW8PLCFspecial& rPLCF, WW8FieldDesc& rF)
1996 {
1997     void* pData;
1998     sal_uLong nOldIdx = rPLCF.GetIdx();
1999 
2000     rF.nLen = rF.nId = rF.nOpt = rF.bCodeNest = rF.bResNest = 0;
2001 
2002     if( !rPLCF.Get( rF.nSCode, pData ) )             // Ende des PLCFspecial ?
2003         goto Err;
2004 
2005     rPLCF++;
2006 
2007     if((((sal_uInt8*)pData)[0] & 0x1f ) != 0x13 )        // Kein Anfang ?
2008         goto Err;
2009 
2010     rF.nId = ((sal_uInt8*)pData)[1];
2011 
2012     if( !rPLCF.Get( rF.nLCode, pData ) )
2013         goto Err;
2014 
2015     rF.nSRes = rF.nLCode;                           // Default
2016     rF.nSCode++;                                    // ohne Marken
2017     rF.nLCode -= rF.nSCode;                         // Pos zu Laenge
2018 
2019     while((((sal_uInt8*)pData)[0] & 0x1f ) == 0x13 )
2020     {
2021         // immer noch neue (nested) Anfaenge ?
2022         WW8SkipField( rPLCF );              // nested Field im Beschreibungsteil
2023         rF.bCodeNest = true;
2024         if( !rPLCF.Get( rF.nSRes, pData ) )
2025             goto Err;
2026     }
2027 
2028     if((((sal_uInt8*)pData)[0] & 0x1f ) == 0x14 ){       // Field Separator ?
2029         rPLCF++;
2030 
2031         if( !rPLCF.Get( rF.nLRes, pData ) )
2032             goto Err;
2033 
2034         while((((sal_uInt8*)pData)[0] & 0x1f ) == 0x13 )
2035         {
2036             // immer noch neue (nested) Anfaenge ?
2037             WW8SkipField( rPLCF );              // nested Field im Resultatteil
2038             rF.bResNest = true;
2039             if( !rPLCF.Get( rF.nLRes, pData ) )
2040                 goto Err;
2041         }
2042         rF.nLen = rF.nLRes - rF.nSCode + 2; // nLRes ist noch die Endposition
2043         rF.nLRes -= rF.nSRes;                       // nun: nLRes = Laenge
2044         rF.nSRes++;                                 // Endpos encl. Marken
2045         rF.nLRes--;
2046 
2047     }else{
2048         rF.nLRes = 0;                               // Kein Result vorhanden
2049         rF.nLen = rF.nSRes - rF.nSCode + 2;         // Gesamtlaenge
2050     }
2051 
2052     rPLCF++;
2053     if((((sal_uInt8*)pData)[0] & 0x1f ) == 0x15 )
2054     {
2055         // Field Ende ?
2056         // INDEX-Fld hat Bit7 gesetzt!?!
2057         rF.nOpt = ((sal_uInt8*)pData)[1];                // Ja -> Flags uebernehmen
2058     }else{
2059         rF.nId = 0;                                 // Nein -> Feld ungueltig
2060     }
2061 
2062     rPLCF.SetIdx( nOldIdx );
2063     return true;
2064 Err:
2065     rPLCF.SetIdx( nOldIdx );
2066     return false;
2067 }
2068 
2069 
2070 //-----------------------------------------
2071 
2072 
2073 // WW8ReadPString liest einen Pascal-String ein und gibt ihn zurueck. Der
2074 // Pascal- String hat am Ende ein \0, der aber im Laengenbyte nicht
2075 // mitgezaehlt wird.  Der Speicher fuer den Pascalstring wird alloziert.
2076 String WW8ReadPString(SvStream& rStrm, rtl_TextEncoding eEnc,
2077     bool bAtEndSeekRel1)
2078 {
2079     ByteString aByteStr;
2080     sal_uInt8 b;
2081     rStrm >> b;
2082 
2083     if (b)
2084     {
2085         // Alloc methode automatically sets Zero at the end
2086         sal_Char*  pByteData = aByteStr.AllocBuffer( b );
2087 
2088         sal_uLong nWasRead = rStrm.Read( pByteData, b );
2089         if( nWasRead != b )
2090             aByteStr.ReleaseBufferAccess(static_cast<xub_StrLen>(nWasRead));
2091     }
2092 
2093     if( bAtEndSeekRel1 )
2094         rStrm.SeekRel( 1 ); // ueberspringe das Null-Byte am Ende.
2095 
2096 
2097     return String( aByteStr, eEnc );
2098 }
2099 
2100 String WW8Read_xstz(SvStream& rStrm, sal_uInt16 nChars, bool bAtEndSeekRel1)
2101 {
2102     sal_uInt16 b;
2103 
2104     if( nChars )
2105         b = nChars;
2106     else
2107         rStrm >> b;
2108 
2109     String aStr;
2110     if (b)
2111     {
2112         // Alloc methode automatically sets Zero at the end
2113         sal_Unicode* pData = aStr.AllocBuffer( b );
2114 
2115         sal_uLong nWasRead = rStrm.Read( (sal_Char*)pData, b * 2 );
2116         if( nWasRead != static_cast<sal_uLong>(b*2) )
2117         {
2118             b = static_cast<sal_uInt16>(nWasRead / 2);
2119             aStr.ReleaseBufferAccess( b );
2120             pData = aStr.GetBufferAccess();
2121         }
2122 
2123 #ifdef OSL_BIGENDIAN
2124         sal_uLong n;
2125         sal_Unicode *pWork;
2126         for( n = 0, pWork = pData; n < b; ++n, ++pWork )
2127             *pWork = SWAPSHORT( *pWork );
2128 #endif // ifdef OSL_BIGENDIAN
2129     }
2130 
2131     if( bAtEndSeekRel1 )
2132         rStrm.SeekRel( 2 ); // ueberspringe das Null-Character am Ende.
2133 
2134     return aStr;
2135 }
2136 
2137 sal_uLong SafeReadString(ByteString &rStr,sal_uInt16 nLen,SvStream &rStrm)
2138 {
2139     sal_uLong nWasRead=0;
2140     if (nLen)
2141     {
2142         nWasRead = rStrm.Read( rStr.AllocBuffer( nLen ), nLen);
2143         if( nWasRead != nLen )
2144             rStr.ReleaseBufferAccess(static_cast<xub_StrLen>(nWasRead));
2145     }
2146     return nWasRead;
2147 }
2148 
2149 xub_StrLen WW8ScannerBase::WW8ReadString( SvStream& rStrm, String& rStr,
2150     WW8_CP nAktStartCp, long nTotalLen, rtl_TextEncoding eEnc ) const
2151 {
2152     // Klartext einlesen, der sich ueber mehrere Pieces erstrecken kann
2153     rStr.Erase();
2154 
2155     long nTotalRead = 0;
2156     WW8_CP nBehindTextCp = nAktStartCp + nTotalLen;
2157     WW8_CP nNextPieceCp  = nBehindTextCp; // Initialisierung wichtig fuer Ver6
2158     do
2159     {
2160         bool bIsUnicode, bPosOk;
2161         WW8_FC fcAct = WW8Cp2Fc(nAktStartCp,&bIsUnicode,&nNextPieceCp,&bPosOk);
2162 
2163         // vermutlich uebers Dateiende hinaus gezielt, macht nix!
2164         if( !bPosOk )
2165             break;
2166 
2167         rStrm.Seek( fcAct );
2168 
2169         long nLen = ( (nNextPieceCp < nBehindTextCp) ? nNextPieceCp
2170             : nBehindTextCp ) - nAktStartCp;
2171 
2172         if( 0 >= nLen )
2173             break;
2174 
2175         if( nLen > USHRT_MAX - 1 )
2176             nLen = USHRT_MAX - 1;
2177 
2178         if( bIsUnicode )
2179             rStr.Append(WW8Read_xstz(rStrm, (sal_uInt16)nLen, false));
2180         else
2181         {
2182             // Alloc method automatically sets Zero at the end
2183             ByteString aByteStr;
2184             SafeReadString(aByteStr,(sal_uInt16)nLen,rStrm);
2185             rStr += String( aByteStr, eEnc );
2186         }
2187         nTotalRead  += nLen;
2188         nAktStartCp += nLen;
2189         if ( nTotalRead != rStr.Len() )
2190             break;
2191     }
2192     while( nTotalRead < nTotalLen );
2193 
2194     return rStr.Len();
2195 }
2196 
2197 //-----------------------------------------
2198 //              WW8PLCFspecial
2199 //-----------------------------------------
2200 
2201 // Bei nStartPos < 0 wird das erste Element des PLCFs genommen
2202 WW8PLCFspecial::WW8PLCFspecial(SvStream* pSt, long nFilePos, long nPLCF,
2203     long nStruct, long nStartPos)
2204     : nIdx(0), nStru(nStruct)
2205 {
2206     nIMax = ( nPLCF - 4 ) / ( 4 + nStruct );
2207     // Pointer auf Pos- u. Struct-Array
2208     pPLCF_PosArray = new sal_Int32[ ( nPLCF + 3 ) / 4 ];
2209 
2210     long nOldPos = pSt->Tell();
2211 
2212     pSt->Seek( nFilePos );
2213     pSt->Read( pPLCF_PosArray, nPLCF );
2214 #ifdef OSL_BIGENDIAN
2215     for( nIdx = 0; nIdx <= nIMax; nIdx++ )
2216         pPLCF_PosArray[nIdx] = SWAPLONG( pPLCF_PosArray[nIdx] );
2217     nIdx = 0;
2218 #endif // OSL_BIGENDIAN
2219     if( nStruct ) // Pointer auf Inhalts-Array
2220         pPLCF_Contents = (sal_uInt8*)&pPLCF_PosArray[nIMax + 1];
2221     else
2222         pPLCF_Contents = 0;                         // kein Inhalt
2223     if( nStartPos >= 0 )
2224         SeekPos( nStartPos );
2225 
2226     pSt->Seek( nOldPos );
2227 }
2228 
2229 bool WW8PLCFspecial::IsValid()
2230 {
2231     return IsPLCFPosArrayValid( pPLCF_PosArray, nIMax );
2232 }
2233 
2234 // WW8PLCFspecial::SeekPos() stellt den WW8PLCFspecial auf die Stelle nPos, wobei auch noch der
2235 // Eintrag benutzt wird, der vor nPos beginnt und bis hinter nPos reicht.
2236 // geeignet fuer normale Attribute. Allerdings wird der Attributanfang nicht
2237 // auf die Position nPos korrigiert.
2238 bool WW8PLCFspecial::SeekPos(long nP)
2239 {
2240     if( nP < pPLCF_PosArray[0] )
2241     {
2242         nIdx = 0;
2243         return false;   // Not found: nP unterhalb kleinstem Eintrag
2244     }
2245 
2246     // Search from beginning?
2247     if( (1 > nIdx) || (nP < pPLCF_PosArray[ nIdx-1 ]) )
2248         nIdx = 1;
2249 
2250     long nI   = nIdx ? nIdx : 1;
2251     long nEnd = nIMax;
2252 
2253     for(int n = (1==nIdx ? 1 : 2); n; --n )
2254     {
2255         for( ; nI <=nEnd; ++nI)
2256         {                                   // Suchen mit um 1 erhoehtem Index
2257             if( nP < pPLCF_PosArray[nI] )
2258             {                               // Position gefunden
2259                 nIdx = nI - 1;              // nI - 1 ist der richtige Index
2260                 return true;                // ... und fertig
2261             }
2262         }
2263         nI   = 1;
2264         nEnd = nIdx-1;
2265     }
2266     nIdx = nIMax;               // Nicht gefunden, groesser als alle Eintraege
2267     return false;
2268 }
2269 
2270 // WW8PLCFspecial::SeekPosExact() wie SeekPos(), aber es wird sichergestellt,
2271 // dass kein Attribut angeschnitten wird, d.h. das naechste gelieferte
2272 // Attribut beginnt auf oder hinter nPos. Wird benutzt fuer Felder +
2273 // Bookmarks.
2274 bool WW8PLCFspecial::SeekPosExact(long nP)
2275 {
2276     if( nP < pPLCF_PosArray[0] )
2277     {
2278         nIdx = 0;
2279         return false;       // Not found: nP unterhalb kleinstem Eintrag
2280     }
2281     // Search from beginning?
2282     if( nP <=pPLCF_PosArray[nIdx] )
2283         nIdx = 0;
2284 
2285     long nI   = nIdx ? nIdx-1 : 0;
2286     long nEnd = nIMax;
2287 
2288     for(int n = (0==nIdx ? 1 : 2); n; --n )
2289     {
2290         for( ; nI < nEnd; ++nI)
2291         {
2292             if( nP <=pPLCF_PosArray[nI] )
2293             {                           // Position gefunden
2294                 nIdx = nI;              // nI     ist der richtige Index
2295                 return true;            // ... und fertig
2296             }
2297         }
2298         nI   = 0;
2299         nEnd = nIdx;
2300     }
2301     nIdx = nIMax;               // Not found, groesser als alle Eintraege
2302     return false;
2303 }
2304 
2305 bool WW8PLCFspecial::Get(WW8_CP& rPos, void*& rpValue) const
2306 {
2307     return GetData( nIdx, rPos, rpValue );
2308 }
2309 
2310 bool WW8PLCFspecial::GetData(long nInIdx, WW8_CP& rPos, void*& rpValue) const
2311 {
2312     if ( nInIdx >= nIMax )
2313     {
2314         rPos = WW8_CP_MAX;
2315         return false;
2316     }
2317     rPos = pPLCF_PosArray[nInIdx];
2318     rpValue = pPLCF_Contents ? (void*)&pPLCF_Contents[nInIdx * nStru] : 0;
2319     return true;
2320 }
2321 
2322 //-----------------------------------------
2323 //              WW8PLCF z.B. fuer SEPX
2324 //-----------------------------------------
2325 
2326 // Ctor fuer *andere* als Fkps
2327 // Bei nStartPos < 0 wird das erste Element des PLCFs genommen
2328 WW8PLCF::WW8PLCF(
2329     SvStream* pSt,
2330     WW8_FC nFilePos,
2331     sal_Int32 nPLCF,
2332     int nStruct,
2333     WW8_CP nStartPos )
2334     : pPLCF_PosArray( 0 )
2335     , pPLCF_Contents( 0 )
2336     , nIMax( 0 )
2337     , nIdx( 0 )
2338     , nStru( nStruct )
2339 {
2340     ASSERT( nPLCF, "WW8PLCF: nPLCF ist Null!" );
2341 
2342     nIMax = ( nPLCF - 4 ) / ( 4 + nStruct );
2343 
2344     ReadPLCF( pSt, nFilePos, nPLCF );
2345 
2346     if( nStartPos >= 0 )
2347         SeekPos( nStartPos );
2348 }
2349 
2350 // Ctor *nur* fuer Fkps
2351 // Die letzten 2 Parameter sind fuer PLCF.Chpx und PLCF.Papx noetig.  ist ncpN
2352 // != 0, dann wird ein unvollstaendiger PLCF vervollstaendigt.  Das ist bei
2353 // WW6 bei Resourcenmangel und bei WordPad (W95) immer noetig.  Bei nStartPos
2354 // < 0 wird das erste Element des PLCFs genommen
2355 WW8PLCF::WW8PLCF( SvStream* pSt, WW8_FC nFilePos, sal_Int32 nPLCF, int nStruct,
2356     WW8_CP nStartPos, sal_Int32 nPN, sal_Int32 ncpN ) : pPLCF_PosArray(0), nIdx(0),
2357     nStru(nStruct)
2358 {
2359     nIMax = ( nPLCF - 4 ) / ( 4 + nStruct );
2360 
2361     if( nIMax >= ncpN )
2362         ReadPLCF( pSt, nFilePos, nPLCF );
2363     else
2364         GeneratePLCF( pSt, nPN, ncpN );
2365 
2366     if( nStartPos >= 0 )
2367         SeekPos( nStartPos );
2368 }
2369 
2370 bool WW8PLCF::IsValid()
2371 {
2372     return pPLCF_PosArray == 0
2373            || IsPLCFPosArrayValid( pPLCF_PosArray, nIMax );
2374 }
2375 
2376 void WW8PLCF::ReadPLCF( SvStream* pSt, WW8_FC nFilePos, sal_Int32 nPLCF )
2377 {
2378     bool failure = false;
2379 
2380     // Pointer auf Pos-Array
2381     pPLCF_PosArray = new WW8_CP[ ( nPLCF + 3 ) / 4 ];
2382 
2383     sal_Size nOldPos = pSt->Tell();
2384 
2385     pSt->Seek( nFilePos );
2386     failure = pSt->GetError();
2387 
2388     if (!failure)
2389     {
2390         pSt->Read( pPLCF_PosArray, nPLCF );
2391         failure = pSt->GetError();
2392     }
2393 
2394     if (!failure)
2395     {
2396 #ifdef OSL_BIGENDIAN
2397         for( nIdx = 0; nIdx <= nIMax; nIdx++ )
2398             pPLCF_PosArray[nIdx] = SWAPLONG( pPLCF_PosArray[nIdx] );
2399         nIdx = 0;
2400 #endif // OSL_BIGENDIAN
2401         // Pointer auf Inhalts-Array
2402         pPLCF_Contents = (sal_uInt8*)&pPLCF_PosArray[nIMax + 1];
2403     }
2404 
2405     pSt->Seek( nOldPos );
2406 
2407     ASSERT( !failure, "Document has corrupt PLCF, ignoring it" );
2408 
2409     if (failure)
2410         MakeFailedPLCF();
2411 }
2412 
2413 void WW8PLCF::MakeFailedPLCF()
2414 {
2415     nIMax = 0;
2416     delete[] pPLCF_PosArray;
2417     pPLCF_PosArray = new sal_Int32[2];
2418     pPLCF_PosArray[0] = pPLCF_PosArray[1] = WW8_CP_MAX;
2419     pPLCF_Contents = (sal_uInt8*)&pPLCF_PosArray[nIMax + 1];
2420 }
2421 
2422 void WW8PLCF::GeneratePLCF( SvStream* pSt, sal_Int32 nPN, sal_Int32 ncpN )
2423 {
2424     ASSERT( nIMax < ncpN, "Pcl.Fkp: Warum ist PLCF zu gross ?" );
2425 
2426     bool failure = false;
2427     nIMax = ncpN;
2428 
2429     if ((nIMax < 1) || (nIMax > (WW8_CP_MAX - 4)/6) || ((nPN + ncpN) > USHRT_MAX))
2430         failure = true;
2431 
2432     if (!failure)
2433     {
2434         size_t nSiz = 6 * nIMax + 4;
2435         size_t nElems = ( nSiz + 3 ) / 4;
2436         pPLCF_PosArray = new sal_Int32[ nElems ]; // Pointer auf Pos-Array
2437 
2438         for (sal_Int32 i = 0; i < ncpN && !pSt->GetError(); ++i)
2439         {
2440             // Baue FC-Eintraege
2441             pSt->Seek( ( nPN + i ) << 9 );  // erster FC-Eintrag jedes Fkp
2442             WW8_CP nFc;
2443             *pSt >> nFc;
2444             pPLCF_PosArray[i] = nFc;
2445         }
2446 
2447         failure = pSt->GetError();
2448     }
2449 
2450     if (!failure)
2451     {
2452         sal_Size nLastFkpPos = ( ( nPN + nIMax - 1 ) << 9 );
2453         pSt->Seek( nLastFkpPos + 511 );     // Anz. Fkp-Eintraege des letzten Fkp
2454 
2455         sal_uInt8 nb;
2456         *pSt >> nb;
2457         pSt->Seek( nLastFkpPos + nb * 4 );  // letzer FC-Eintrag des letzten Fkp
2458 
2459         WW8_CP nFc;
2460         *pSt >> nFc;
2461         pPLCF_PosArray[nIMax] = nFc;        // Ende des letzten Fkp
2462 
2463         failure = pSt->GetError();
2464     }
2465 
2466     if (!failure)
2467     {
2468         // Pointer auf Inhalts-Array
2469         pPLCF_Contents = (sal_uInt8*)&pPLCF_PosArray[nIMax + 1];
2470         sal_uInt8* p = pPLCF_Contents;
2471 
2472         for (sal_Int32 i = 0; i < ncpN; ++i)         // Baue PNs
2473         {
2474             ShortToSVBT16(static_cast<sal_uInt16>(nPN + i), p);
2475             p+=2;
2476         }
2477     }
2478 
2479     ASSERT( !failure, "Document has corrupt PLCF, ignoring it" );
2480 
2481     if (failure)
2482         MakeFailedPLCF();
2483 }
2484 
2485 bool WW8PLCF::SeekPos(WW8_CP nPos)
2486 {
2487     WW8_CP nP = nPos;
2488 
2489     if( nP < pPLCF_PosArray[0] )
2490     {
2491         nIdx = 0;
2492         // Nicht gefunden: nPos unterhalb kleinstem Eintrag
2493         return false;
2494     }
2495 
2496     // Search from beginning?
2497     if( (1 > nIdx) || (nP < pPLCF_PosArray[ nIdx-1 ]) )
2498         nIdx = 1;
2499 
2500     sal_Int32 nI   = nIdx ? nIdx : 1;
2501     sal_Int32 nEnd = nIMax;
2502 
2503     for(int n = (1==nIdx ? 1 : 2); n; --n )
2504     {
2505         for( ; nI <=nEnd; ++nI)             // Suchen mit um 1 erhoehtem Index
2506         {
2507             if( nP < pPLCF_PosArray[nI] )   // Position gefunden
2508             {
2509                 nIdx = nI - 1;              // nI - 1 ist der richtige Index
2510                 return true;                // ... und fertig
2511             }
2512         }
2513         nI   = 1;
2514         nEnd = nIdx-1;
2515     }
2516 
2517     nIdx = nIMax;               // Nicht gefunden, groesser als alle Eintraege
2518     return false;
2519 }
2520 
2521 bool WW8PLCF::Get(WW8_CP& rStart, WW8_CP& rEnd, void*& rpValue) const
2522 {
2523     if ( nIdx >= nIMax )
2524     {
2525         rStart = rEnd = WW8_CP_MAX;
2526         return false;
2527     }
2528     rStart = pPLCF_PosArray[ nIdx ];
2529     rEnd   = pPLCF_PosArray[ nIdx + 1 ];
2530     rpValue = (void*)&pPLCF_Contents[nIdx * nStru];
2531     return true;
2532 }
2533 
2534 WW8_CP WW8PLCF::Where() const
2535 {
2536     if ( nIdx >= nIMax )
2537         return WW8_CP_MAX;
2538 
2539     return pPLCF_PosArray[nIdx];
2540 }
2541 
2542 //-----------------------------------------
2543 //              WW8PLCFpcd
2544 //-----------------------------------------
2545 
2546 WW8PLCFpcd::WW8PLCFpcd( SvStream* pSt, long nFilePos, long nPLCF, long nStruct )
2547     :nStru( nStruct )
2548 {
2549     nIMax = ( nPLCF - 4 ) / ( 4 + nStruct );
2550     pPLCF_PosArray = new sal_Int32[ ( nPLCF + 3 ) / 4 ];    // Pointer auf Pos-Array
2551 
2552     long nOldPos = pSt->Tell();
2553 
2554     pSt->Seek( nFilePos );
2555     pSt->Read( pPLCF_PosArray, nPLCF );
2556 #ifdef OSL_BIGENDIAN
2557     for( long nI = 0; nI <= nIMax; nI++ )
2558       pPLCF_PosArray[nI] = SWAPLONG( pPLCF_PosArray[nI] );
2559 #endif // OSL_BIGENDIAN
2560 
2561     // Pointer auf Inhalts-Array
2562     pPLCF_Contents = (sal_uInt8*)&pPLCF_PosArray[nIMax + 1];
2563 
2564     pSt->Seek( nOldPos );
2565 }
2566 
2567 bool WW8PLCFpcd::IsValid()
2568 {
2569     return IsPLCFPosArrayValid( pPLCF_PosArray, nIMax );
2570 }
2571 
2572 // Bei nStartPos < 0 wird das erste Element des PLCFs genommen
2573 WW8PLCFpcd_Iter::WW8PLCFpcd_Iter( WW8PLCFpcd& rPLCFpcd, long nStartPos )
2574     :rPLCF( rPLCFpcd ), nIdx( 0 )
2575 {
2576     if( nStartPos >= 0 )
2577         SeekPos( nStartPos );
2578 }
2579 
2580 bool WW8PLCFpcd_Iter::SeekPos(long nPos)
2581 {
2582     long nP = nPos;
2583 
2584     if( nP < rPLCF.pPLCF_PosArray[0] )
2585     {
2586         nIdx = 0;
2587         return false;       // Nicht gefunden: nPos unterhalb kleinstem Eintrag
2588     }
2589     // Search from beginning?
2590     if( (1 > nIdx) || (nP < rPLCF.pPLCF_PosArray[ nIdx-1 ]) )
2591         nIdx = 1;
2592 
2593     long nI   = nIdx ? nIdx : 1;
2594     long nEnd = rPLCF.nIMax;
2595 
2596     for(int n = (1==nIdx ? 1 : 2); n; --n )
2597     {
2598         for( ; nI <=nEnd; ++nI)
2599         {                               // Suchen mit um 1 erhoehtem Index
2600             if( nP < rPLCF.pPLCF_PosArray[nI] )
2601             {                           // Position gefunden
2602                 nIdx = nI - 1;          // nI - 1 ist der richtige Index
2603                 return true;            // ... und fertig
2604             }
2605         }
2606         nI   = 1;
2607         nEnd = nIdx-1;
2608     }
2609     nIdx = rPLCF.nIMax;         // Nicht gefunden, groesser als alle Eintraege
2610     return false;
2611 }
2612 
2613 bool WW8PLCFpcd_Iter::Get(WW8_CP& rStart, WW8_CP& rEnd, void*& rpValue) const
2614 {
2615     if( nIdx >= rPLCF.nIMax )
2616     {
2617         rStart = rEnd = WW8_CP_MAX;
2618         return false;
2619     }
2620     rStart = rPLCF.pPLCF_PosArray[nIdx];
2621     rEnd = rPLCF.pPLCF_PosArray[nIdx + 1];
2622     rpValue = (void*)&rPLCF.pPLCF_Contents[nIdx * rPLCF.nStru];
2623     return true;
2624 }
2625 
2626 sal_Int32 WW8PLCFpcd_Iter::Where() const
2627 {
2628     if ( nIdx >= rPLCF.nIMax )
2629         return SAL_MAX_INT32;
2630 
2631     return rPLCF.pPLCF_PosArray[nIdx];
2632 }
2633 
2634 //-----------------------------------------
2635 bool WW8PLCFx_Fc_FKP::WW8Fkp::Entry::operator<
2636     (const WW8PLCFx_Fc_FKP::WW8Fkp::Entry& rSecond) const
2637 {
2638     return (mnFC < rSecond.mnFC);
2639 }
2640 
2641 bool IsReplaceAllSprm(sal_uInt16 nSpId)
2642 {
2643     return (0x6645 == nSpId || 0x6646 == nSpId);
2644 }
2645 
2646 bool IsExpandableSprm(sal_uInt16 nSpId)
2647 {
2648     return 0x646B == nSpId;
2649 }
2650 
2651 WW8PLCFx_Fc_FKP::WW8Fkp::WW8Fkp(ww::WordVersion eVersion, SvStream* pSt,
2652     SvStream* pDataSt, long _nFilePos, long nItemSiz, ePLCFT ePl,
2653     WW8_FC nStartFc)
2654     : nItemSize(nItemSiz), nFilePos(_nFilePos),  mnIdx(0), ePLCF(ePl),
2655     maSprmParser(eVersion)
2656 {
2657     long nOldPos = pSt->Tell();
2658 
2659     pSt->Seek(nFilePos);
2660     pSt->Read(maRawData, 512);
2661     mnIMax = maRawData[511];
2662 
2663     sal_uInt8 *pStart = maRawData;
2664     // Pointer to Offset-Location in maRawData
2665     sal_uInt8* pOfs = maRawData + (mnIMax + 1) * 4;
2666 
2667     for (mnIdx = 0; mnIdx < mnIMax; ++mnIdx)
2668     {
2669         unsigned int nOfs = (*(pOfs + mnIdx * nItemSize)) * 2;
2670         Entry aEntry(Get_Long(pStart));
2671 
2672         if (nOfs)
2673         {
2674             switch (ePLCF)
2675             {
2676                 case CHP:
2677                     aEntry.mnLen  = maRawData[nOfs];
2678                     aEntry.mpData = maRawData + nOfs + 1;
2679 
2680                     if (aEntry.mnLen && eVersion == ww::eWW2)
2681                     {
2682                         Word2CHPX aChpx = ReadWord2Chpx(*pSt, nFilePos + nOfs + 1, static_cast< sal_uInt8 >(aEntry.mnLen));
2683                         std::vector<sal_uInt8> aSprms = ChpxToSprms(aChpx);
2684                         aEntry.mnLen = static_cast< sal_uInt16 >(aSprms.size());
2685                         if (aEntry.mnLen)
2686                         {
2687                             aEntry.mpData = new sal_uInt8[aEntry.mnLen];
2688                             memcpy(aEntry.mpData, &(aSprms[0]), aEntry.mnLen);
2689                             aEntry.mbMustDelete = true;
2690                         }
2691                     }
2692 
2693                     break;
2694                 case PAP:
2695                     {
2696                         sal_uInt8 nDelta = 0;
2697 
2698                         aEntry.mnLen = maRawData[nOfs];
2699                         if (IsEightPlus(eVersion) && !aEntry.mnLen)
2700                         {
2701                             aEntry.mnLen = maRawData[nOfs+1];
2702                             nDelta++;
2703                         }
2704 
2705                         aEntry.mnLen *= 2;
2706 
2707                         //stylecode, std/istd
2708                         if (eVersion == ww::eWW2)
2709                         {
2710                             aEntry.mnIStd = *(maRawData+nOfs+1+nDelta);
2711                             aEntry.mnLen--;  //style code
2712                             aEntry.mnLen-=6; //PHE
2713                             //skipi stc, len byte + 6 byte PHE
2714                             aEntry.mpData = maRawData + nOfs + 8;
2715                         }
2716                         else
2717                         {
2718                             aEntry.mnIStd = SVBT16ToShort(maRawData+nOfs+1+nDelta);
2719                             aEntry.mnLen-=2; //istd
2720                             //skip istd, len byte + optional extra len byte
2721                             aEntry.mpData = maRawData + nOfs + 3 + nDelta;
2722                         }
2723 
2724                         sal_uInt16 nSpId = aEntry.mnLen ? maSprmParser.GetSprmId(aEntry.mpData) : 0;
2725 
2726                         /*
2727                          If we replace then we throw away the old data, if we
2728                          are expanding, then we tack the old data onto the end
2729                          of the new data
2730                         */
2731                         bool bExpand = IsExpandableSprm(nSpId);
2732                         if (IsReplaceAllSprm(nSpId) || bExpand)
2733                         {
2734                             sal_uInt16 nOrigLen = bExpand ? aEntry.mnLen : 0;
2735                             sal_uInt8 *pOrigData = bExpand ? aEntry.mpData : 0;
2736 
2737                             sal_uInt32 nCurr = pDataSt->Tell();
2738 
2739                             sal_uInt32 nPos = SVBT32ToUInt32(aEntry.mpData + 2);
2740                             pDataSt->Seek(nPos);
2741                             *pDataSt >> aEntry.mnLen;
2742                             aEntry.mpData =
2743                                 new sal_uInt8[aEntry.mnLen + nOrigLen];
2744                             aEntry.mbMustDelete = true;
2745                             pDataSt->Read(aEntry.mpData, aEntry.mnLen);
2746 
2747                             pDataSt->Seek( nCurr );
2748 
2749                             if (pOrigData)
2750                             {
2751                                 memcpy(aEntry.mpData + aEntry.mnLen,
2752                                     pOrigData, nOrigLen);
2753                                 aEntry.mnLen = aEntry.mnLen + nOrigLen;
2754                             }
2755                         }
2756                     }
2757                     break;
2758                 default:
2759                     ASSERT(false, "sweet god, what have you done!");
2760                     break;
2761             }
2762         }
2763 
2764         maEntries.push_back(aEntry);
2765     }
2766 
2767     //one more FC than grrpl entries
2768     maEntries.push_back(Entry(Get_Long(pStart)));
2769 
2770     //#104773#, we expect them sorted, but it appears possible
2771     //for them to arive unsorted
2772     std::sort(maEntries.begin(), maEntries.end());
2773 
2774     mnIdx = 0;
2775 
2776     if (nStartFc >= 0)
2777         SeekPos(nStartFc);
2778 
2779     pSt->Seek(nOldPos);
2780 }
2781 
2782 WW8PLCFx_Fc_FKP::WW8Fkp::Entry::Entry(const Entry &rEntry)
2783     : mnFC(rEntry.mnFC), mnLen(rEntry.mnLen), mnIStd(rEntry.mnIStd),
2784     mbMustDelete(rEntry.mbMustDelete)
2785 {
2786     if (mbMustDelete)
2787     {
2788         mpData = new sal_uInt8[mnLen];
2789         memcpy(mpData, rEntry.mpData, mnLen);
2790     }
2791     else
2792         mpData = rEntry.mpData;
2793 }
2794 
2795 WW8PLCFx_Fc_FKP::WW8Fkp::Entry&
2796     WW8PLCFx_Fc_FKP::WW8Fkp::Entry::operator=(const Entry &rEntry)
2797 {
2798     if (mbMustDelete)
2799         delete[] mpData;
2800 
2801     mnFC = rEntry.mnFC;
2802     mnLen = rEntry.mnLen;
2803     mnIStd = rEntry.mnIStd;
2804     mbMustDelete = rEntry.mbMustDelete;
2805 
2806     if (mbMustDelete)
2807     {
2808         mpData = new sal_uInt8[mnLen];
2809         memcpy(mpData, rEntry.mpData, mnLen);
2810     }
2811     else
2812         mpData = rEntry.mpData;
2813     return *this;
2814 }
2815 
2816 WW8PLCFx_Fc_FKP::WW8Fkp::Entry::~Entry()
2817 {
2818     if (mbMustDelete)
2819         delete[] mpData;
2820 }
2821 
2822 void WW8PLCFx_Fc_FKP::WW8Fkp::Reset(WW8_FC nFc)
2823 {
2824     SetIdx(0);
2825     if (nFc >= 0)
2826         SeekPos(nFc);
2827 }
2828 
2829 bool WW8PLCFx_Fc_FKP::WW8Fkp::SeekPos(WW8_FC nFc)
2830 {
2831     if (nFc < maEntries[0].mnFC)
2832     {
2833         mnIdx = 0;
2834         return false;       // Nicht gefunden: nPos unterhalb kleinstem Eintrag
2835     }
2836 
2837     // Search from beginning?
2838     if ((1 > mnIdx) || (nFc < maEntries[mnIdx-1].mnFC))
2839         mnIdx = 1;
2840 
2841     sal_uInt8 nI   = mnIdx ? mnIdx : 1;
2842     sal_uInt8 nEnd = mnIMax;
2843 
2844     for(sal_uInt8 n = (1==mnIdx ? 1 : 2); n; --n )
2845     {
2846         for( ; nI <=nEnd; ++nI)
2847         {                               // Suchen mit um 1 erhoehtem Index
2848             if (nFc < maEntries[nI].mnFC)
2849             {                           // Position gefunden
2850                 mnIdx = nI - 1;          // nI - 1 ist der richtige Index
2851                 return true;            // ... und fertig
2852             }
2853         }
2854         nI = 1;
2855         nEnd = mnIdx-1;
2856     }
2857     mnIdx = mnIMax;               // Nicht gefunden, groesser als alle Eintraege
2858     return false;
2859 }
2860 
2861 sal_uInt8* WW8PLCFx_Fc_FKP::WW8Fkp::Get(WW8_FC& rStart, WW8_FC& rEnd, sal_Int32& rLen)
2862     const
2863 {
2864     rLen = 0;
2865 
2866     if (mnIdx >= mnIMax)
2867     {
2868         rStart = WW8_FC_MAX;
2869         return 0;
2870     }
2871 
2872     rStart = maEntries[mnIdx].mnFC;
2873     rEnd   = maEntries[mnIdx + 1].mnFC;
2874 
2875     sal_uInt8* pSprms = GetLenAndIStdAndSprms( rLen );
2876     return pSprms;
2877 }
2878 
2879 bool WW8PLCFx_Fc_FKP::WW8Fkp::SetIdx(sal_uInt8 nI)
2880 {
2881     if (nI < mnIMax)
2882     {
2883         mnIdx = nI;
2884         return true;
2885     }
2886     return false;
2887 }
2888 
2889 sal_uInt8* WW8PLCFx_Fc_FKP::WW8Fkp::GetLenAndIStdAndSprms(sal_Int32& rLen) const
2890 {
2891     rLen = maEntries[mnIdx].mnLen;
2892     return maEntries[mnIdx].mpData;
2893 }
2894 
2895 const sal_uInt8* WW8PLCFx_Fc_FKP::WW8Fkp::HasSprm( sal_uInt16 nId )
2896 {
2897     if (mnIdx >= mnIMax)
2898         return 0;
2899 
2900     sal_Int32 nLen;
2901     sal_uInt8* pSprms = GetLenAndIStdAndSprms( nLen );
2902 
2903     WW8SprmIter aIter(pSprms, nLen, maSprmParser);
2904     return aIter.FindSprm(nId);
2905 }
2906 
2907 bool WW8PLCFx_Fc_FKP::WW8Fkp::HasSprm(sal_uInt16 nId,
2908     std::vector<const sal_uInt8 *> &rResult)
2909 {
2910     if (mnIdx >= mnIMax)
2911        return false;
2912 
2913     sal_Int32 nLen;
2914     sal_uInt8* pSprms = GetLenAndIStdAndSprms( nLen );
2915 
2916     WW8SprmIter aIter(pSprms, nLen, maSprmParser);
2917 
2918     while(aIter.GetSprms())
2919     {
2920         if (aIter.GetAktId() == nId)
2921             rResult.push_back(aIter.GetAktParams());
2922         aIter++;
2923     };
2924     return !rResult.empty();
2925 }
2926 
2927 //-----------------------------------------
2928 void WW8PLCFx::GetSprms( WW8PLCFxDesc* p )
2929 {
2930     ASSERT( !this, "Falsches GetSprms gerufen" );
2931     p->nStartPos = p->nEndPos = WW8_CP_MAX;
2932     p->pMemPos = 0;
2933     p->nSprmsLen = 0;
2934     p->bRealLineEnd = false;
2935     return;
2936 }
2937 
2938 long WW8PLCFx::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
2939 {
2940     ASSERT( !this, "Falsches GetNoSprms gerufen" );
2941     rStart = rEnd = WW8_CP_MAX;
2942     rLen = 0;
2943     return 0;
2944 }
2945 
2946 // ...Idx2: Default: ignorieren
2947 sal_uLong WW8PLCFx::GetIdx2() const
2948 {
2949     return 0;
2950 }
2951 
2952 void WW8PLCFx::SetIdx2(sal_uLong )
2953 {
2954 }
2955 
2956 class SamePos :
2957     public std::unary_function<const WW8PLCFx_Fc_FKP::WW8Fkp *, bool>
2958 {
2959 private:
2960     long mnPo;
2961 public:
2962     SamePos(long nPo) : mnPo(nPo) {};
2963     bool operator()(const WW8PLCFx_Fc_FKP::WW8Fkp *pFkp)
2964         {return mnPo == pFkp->GetFilePos();}
2965 };
2966 
2967 //-----------------------------------------
2968 bool WW8PLCFx_Fc_FKP::NewFkp()
2969 {
2970     WW8_CP nPLCFStart, nPLCFEnd;
2971     void* pPage;
2972 
2973     static const int WW8FkpSizeTabVer2[ PLCF_END ] =
2974     {
2975         1,  1, 0 /*, 0, 0, 0*/
2976     };
2977     static const int WW8FkpSizeTabVer6[ PLCF_END ] =
2978     {
2979         1,  7, 0 /*, 0, 0, 0*/
2980     };
2981     static const int WW8FkpSizeTabVer8[ PLCF_END ] =
2982     {
2983         1, 13, 0 /*, 0, 0, 0*/
2984     };
2985     const int* pFkpSizeTab;
2986 
2987     switch (GetFIBVersion())
2988     {
2989         case ww::eWW2:
2990             pFkpSizeTab = WW8FkpSizeTabVer2;
2991             break;
2992         case ww::eWW6:
2993         case ww::eWW7:
2994             pFkpSizeTab = WW8FkpSizeTabVer6;
2995             break;
2996         case ww::eWW8:
2997             pFkpSizeTab = WW8FkpSizeTabVer8;
2998             break;
2999         default:
3000             // Programm-Fehler!
3001             ASSERT( !this, "Es wurde vergessen, nVersion zu kodieren!" );
3002             return false;
3003     }
3004 
3005     if (!pPLCF->Get( nPLCFStart, nPLCFEnd, pPage ))
3006     {
3007         pFkp = 0;
3008         return false;                           // PLCF fertig abgearbeitet
3009     }
3010     (*pPLCF)++;
3011     long nPo = SVBT16ToShort( (sal_uInt8 *)pPage );
3012     nPo <<= 9;                                  // shift als LONG
3013 
3014     long nAktFkpFilePos = pFkp ? pFkp->GetFilePos() : -1;
3015     if (nAktFkpFilePos == nPo)
3016         pFkp->Reset(GetStartFc()); // #79464# //
3017     else
3018     {
3019         myiter aIter =
3020             std::find_if(maFkpCache.begin(), maFkpCache.end(), SamePos(nPo));
3021         if (aIter != maFkpCache.end())
3022         {
3023             pFkp = *aIter;
3024             pFkp->Reset(GetStartFc());
3025         }
3026         else if (0 != (pFkp = new WW8Fkp(GetFIBVersion(), pFKPStrm, pDataStrm, nPo,
3027             pFkpSizeTab[ ePLCF ], ePLCF, GetStartFc())))
3028         {
3029             maFkpCache.push_back(pFkp);
3030 
3031             if (maFkpCache.size() > eMaxCache)
3032             {
3033                 delete maFkpCache.front();
3034                 maFkpCache.pop_front();
3035             }
3036         }
3037     }
3038 
3039     SetStartFc( -1 );                                   // Nur das erste Mal
3040     return true;
3041 }
3042 
3043 WW8PLCFx_Fc_FKP::WW8PLCFx_Fc_FKP(SvStream* pSt, SvStream* pTblSt,
3044     SvStream* pDataSt, const WW8Fib& rFib, ePLCFT ePl, WW8_FC nStartFcL)
3045     : WW8PLCFx(rFib.GetFIBVersion(), true), pFKPStrm(pSt), pDataStrm(pDataSt),
3046     pFkp(0), ePLCF(ePl), pPCDAttrs(0)
3047 {
3048     SetStartFc(nStartFcL);
3049     long nLenStruct = (8 > rFib.nVersion) ? 2 : 4;
3050     if (ePl == CHP)
3051     {
3052         pPLCF = new WW8PLCF(pTblSt, rFib.fcPlcfbteChpx, rFib.lcbPlcfbteChpx,
3053             nLenStruct, GetStartFc(), rFib.pnChpFirst, rFib.cpnBteChp);
3054     }
3055     else
3056     {
3057         pPLCF = new WW8PLCF(pTblSt, rFib.fcPlcfbtePapx, rFib.lcbPlcfbtePapx,
3058             nLenStruct, GetStartFc(), rFib.pnPapFirst, rFib.cpnBtePap);
3059     }
3060 }
3061 
3062 WW8PLCFx_Fc_FKP::~WW8PLCFx_Fc_FKP()
3063 {
3064     myiter aEnd = maFkpCache.end();
3065     for (myiter aIter = maFkpCache.begin(); aIter != aEnd; ++aIter)
3066         delete *aIter;
3067     delete pPLCF;
3068     delete pPCDAttrs;
3069 }
3070 
3071 bool WW8PLCFx_Fc_FKP::HasValidPLCF()
3072 {
3073     return pPLCF == 0 || pPLCF->IsValid();
3074 }
3075 
3076 sal_uLong WW8PLCFx_Fc_FKP::GetIdx() const
3077 {
3078     sal_uLong u = pPLCF->GetIdx() << 8;
3079     if (pFkp)
3080         u |= pFkp->GetIdx();
3081     return u;
3082 }
3083 
3084 void WW8PLCFx_Fc_FKP::SetIdx( sal_uLong nIdx )
3085 {
3086     if( !( nIdx & 0xffffff00L ) )
3087     {
3088         pPLCF->SetIdx( nIdx >> 8 );
3089         pFkp = 0;
3090     }
3091     else
3092     {                                   //Es gab einen Fkp
3093         //Lese PLCF um 1 Pos zurueck, um die Adresse des Fkp wiederzubekommen
3094         pPLCF->SetIdx( ( nIdx >> 8 ) - 1 );
3095         if (NewFkp())                       // und lese Fkp wieder ein
3096         {
3097             sal_uInt8 nFkpIdx = static_cast<sal_uInt8>(nIdx & 0xff);
3098             pFkp->SetIdx(nFkpIdx);          // Dann stelle Fkp-Pos wieder ein
3099         }
3100     }
3101 }
3102 
3103 bool WW8PLCFx_Fc_FKP::SeekPos(WW8_FC nFcPos)
3104 {
3105     // StartPos for next Where()
3106     SetStartFc( nFcPos );
3107 
3108     // find StartPos for next pPLCF->Get()
3109     bool bRet = pPLCF->SeekPos(nFcPos);
3110 
3111     // make FKP invalid?
3112     WW8_CP nPLCFStart, nPLCFEnd;
3113     void* pPage;
3114     if( pFkp && pPLCF->Get( nPLCFStart, nPLCFEnd, pPage ) )
3115     {
3116         long nPo = SVBT16ToShort( (sal_uInt8 *)pPage );
3117         nPo <<= 9;                                          // shift als LONG
3118         if (nPo != pFkp->GetFilePos())
3119             pFkp = 0;
3120         else
3121             pFkp->SeekPos( nFcPos );
3122     }
3123     return bRet;
3124 }
3125 
3126 WW8_FC WW8PLCFx_Fc_FKP::Where()
3127 {
3128     if( !pFkp )
3129     {
3130         if( !NewFkp() )
3131             return WW8_FC_MAX;
3132     }
3133     WW8_FC nP = pFkp->Where();
3134     if( nP != WW8_FC_MAX )
3135         return nP;
3136 
3137     pFkp = 0;                   // FKP beendet -> hole neuen
3138     return Where();                     // am einfachsten rekursiv
3139 }
3140 
3141 sal_uInt8* WW8PLCFx_Fc_FKP::GetSprmsAndPos(WW8_FC& rStart, WW8_FC& rEnd, sal_Int32& rLen)
3142 {
3143     rLen = 0;                               // Default
3144     rStart = rEnd = WW8_FC_MAX;
3145 
3146     if( !pFkp )     // Fkp not there ?
3147     {
3148         if( !NewFkp() )
3149             return 0;
3150     }
3151 
3152     sal_uInt8* pPos = pFkp->Get( rStart, rEnd, rLen );
3153     if( rStart == WW8_FC_MAX )    //Not found
3154         return 0;
3155     return pPos;
3156 }
3157 
3158 WW8PLCFx& WW8PLCFx_Fc_FKP::operator ++( int )
3159 {
3160     if( !pFkp )
3161     {
3162         if( !NewFkp() )
3163             return *this;
3164     }
3165 
3166     (*pFkp)++;
3167     if( pFkp->Where() == WW8_FC_MAX )
3168         NewFkp();
3169 
3170     return *this;
3171 }
3172 
3173 sal_uInt16 WW8PLCFx_Fc_FKP::GetIstd() const
3174 {
3175     return pFkp ? pFkp->GetIstd() : 0xFFFF;
3176 }
3177 
3178 void WW8PLCFx_Fc_FKP::GetPCDSprms( WW8PLCFxDesc& rDesc )
3179 {
3180     rDesc.pMemPos   = 0;
3181     rDesc.nSprmsLen = 0;
3182     if( pPCDAttrs )
3183     {
3184         if( !pFkp )
3185         {
3186             DBG_WARNING(
3187                 "+Problem: GetPCDSprms: NewFkp necessay (not possible!)" );
3188             if( !NewFkp() )
3189                 return;
3190         }
3191         pPCDAttrs->GetSprms(&rDesc);
3192     }
3193 }
3194 
3195 const sal_uInt8* WW8PLCFx_Fc_FKP::HasSprm( sal_uInt16 nId )
3196 {
3197     // const waere schoener, aber dafuer muesste NewFkp() ersetzt werden oder
3198     // wegfallen
3199     if( !pFkp )
3200     {
3201         DBG_WARNING( "+Motz: HasSprm: NewFkp noetig ( kein const moeglich )" );
3202         // Passiert bei BugDoc 31722
3203         if( !NewFkp() )
3204             return 0;
3205     }
3206 
3207     const sal_uInt8* pRes = pFkp->HasSprm( nId );
3208 
3209     if( !pRes )
3210     {
3211         WW8PLCFxDesc aDesc;
3212         GetPCDSprms( aDesc );
3213 
3214         if (aDesc.pMemPos)
3215         {
3216             WW8SprmIter aIter(aDesc.pMemPos, aDesc.nSprmsLen,
3217                 pFkp->GetSprmParser());
3218             pRes = aIter.FindSprm(nId);
3219         }
3220     }
3221 
3222     return pRes;
3223 }
3224 
3225 bool WW8PLCFx_Fc_FKP::HasSprm(sal_uInt16 nId, std::vector<const sal_uInt8 *> &rResult)
3226 {
3227     // const waere schoener, aber dafuer muesste NewFkp() ersetzt werden oder
3228     // wegfallen
3229     if (!pFkp)
3230     {
3231        DBG_WARNING( "+Motz: HasSprm: NewFkp noetig ( kein const moeglich )" );
3232        // Passiert bei BugDoc 31722
3233        if( !NewFkp() )
3234            return 0;
3235     }
3236 
3237     pFkp->HasSprm(nId, rResult);
3238 
3239     WW8PLCFxDesc aDesc;
3240     GetPCDSprms( aDesc );
3241 
3242     if (aDesc.pMemPos)
3243     {
3244         WW8SprmIter aIter(aDesc.pMemPos, aDesc.nSprmsLen,
3245             pFkp->GetSprmParser());
3246         while(aIter.GetSprms())
3247         {
3248             if (aIter.GetAktId() == nId)
3249                 rResult.push_back(aIter.GetAktParams());
3250             aIter++;
3251         };
3252     }
3253     return !rResult.empty();
3254 }
3255 
3256 //-----------------------------------------
3257 
3258 WW8PLCFx_Cp_FKP::WW8PLCFx_Cp_FKP( SvStream* pSt, SvStream* pTblSt,
3259     SvStream* pDataSt, const WW8ScannerBase& rBase, ePLCFT ePl )
3260     : WW8PLCFx_Fc_FKP(pSt, pTblSt, pDataSt, *rBase.pWw8Fib, ePl,
3261     rBase.WW8Cp2Fc(0)), rSBase(rBase), nAttrStart(-1), nAttrEnd(-1),
3262     bLineEnd(false),
3263     bComplex( (7 < rBase.pWw8Fib->nVersion) || (0 != rBase.pWw8Fib->fComplex) )
3264 {
3265     ResetAttrStartEnd();
3266 
3267     pPcd = rSBase.pPiecePLCF ? new WW8PLCFx_PCD(GetFIBVersion(),
3268         rBase.pPiecePLCF, 0, IsSevenMinus(GetFIBVersion())) : 0;
3269 
3270     /*
3271     Make a copy of the piece attributes for so that the calls to HasSprm on a
3272     Fc_FKP will be able to take into account the current piece attributes,
3273     despite the fact that such attributes can only be found through a cp based
3274     mechanism.
3275     */
3276     if (pPcd)
3277     {
3278         pPCDAttrs = rSBase.pPLCFx_PCDAttrs ? new WW8PLCFx_PCDAttrs(
3279             rSBase.pWw8Fib->GetFIBVersion(), pPcd, &rSBase) : 0;
3280     }
3281 
3282     pPieceIter = rSBase.pPieceIter;
3283 }
3284 
3285 WW8PLCFx_Cp_FKP::~WW8PLCFx_Cp_FKP()
3286 {
3287     delete pPcd;
3288 }
3289 
3290 void WW8PLCFx_Cp_FKP::ResetAttrStartEnd()
3291 {
3292     nAttrStart = -1;
3293     nAttrEnd   = -1;
3294     bLineEnd   = false;
3295 }
3296 
3297 sal_uLong WW8PLCFx_Cp_FKP::GetPCDIMax() const
3298 {
3299     return pPcd ? pPcd->GetIMax() : 0;
3300 }
3301 
3302 sal_uLong WW8PLCFx_Cp_FKP::GetPCDIdx() const
3303 {
3304     return pPcd ? pPcd->GetIdx() : 0;
3305 }
3306 
3307 void WW8PLCFx_Cp_FKP::SetPCDIdx( sal_uLong nIdx )
3308 {
3309     if( pPcd )
3310         pPcd->SetIdx( nIdx );
3311 }
3312 
3313 bool WW8PLCFx_Cp_FKP::SeekPos(WW8_CP nCpPos)
3314 {
3315     if( pPcd )  // Complex
3316     {
3317         if( !pPcd->SeekPos( nCpPos ) )  // Piece setzen
3318             return false;
3319         if (pPCDAttrs && !pPCDAttrs->GetIter()->SeekPos(nCpPos))
3320             return false;
3321         return WW8PLCFx_Fc_FKP::SeekPos(pPcd->AktPieceStartCp2Fc(nCpPos));
3322     }
3323                                     // KEINE Piece-Table !!!
3324     return WW8PLCFx_Fc_FKP::SeekPos( rSBase.WW8Cp2Fc(nCpPos) );
3325 }
3326 
3327 WW8_CP WW8PLCFx_Cp_FKP::Where()
3328 {
3329     WW8_FC nFc = WW8PLCFx_Fc_FKP::Where();
3330     if( pPcd )
3331         return pPcd->AktPieceStartFc2Cp( nFc ); // Piece ermitteln
3332     return rSBase.WW8Fc2Cp( nFc );      // KEINE Piece-Table !!!
3333 }
3334 
3335 void WW8PLCFx_Cp_FKP::GetSprms(WW8PLCFxDesc* p)
3336 {
3337     WW8_CP nOrigCp = p->nStartPos;
3338 
3339     if (!GetDirty())        //Normal case
3340     {
3341         p->pMemPos = WW8PLCFx_Fc_FKP::GetSprmsAndPos(p->nStartPos, p->nEndPos,
3342             p->nSprmsLen);
3343     }
3344     else
3345     {
3346         /*
3347         #93702#
3348         For the odd case where we have a location in a fastsaved file which
3349         does not have an entry in the FKP, perhaps its para end is in the next
3350         piece, or perhaps the cp just doesn't exist at all in this document.
3351         AdvSprm doesn't know so it sets the PLCF as dirty and we figure out
3352         in this method what the situation is
3353 
3354         It doesn't exist then the piece iterator will not be able to find it.
3355         Otherwise our cool fastsave algorithm can be brought to bear on the
3356         problem.
3357         */
3358         if( !pPieceIter )
3359             return;
3360         sal_uLong nOldPos = pPieceIter->GetIdx();
3361         bool bOk = pPieceIter->SeekPos(nOrigCp);
3362         pPieceIter->SetIdx( nOldPos );
3363         if (!bOk)
3364             return;
3365     }
3366 
3367     if( pPcd )  // Piece-Table vorhanden !!!
3368     {
3369         // Init ( noch kein ++ gerufen )
3370         if( (nAttrStart >  nAttrEnd) || (nAttrStart == -1) )
3371         {
3372             p->bRealLineEnd = (ePLCF == PAP);
3373 
3374             if ( ((ePLCF == PAP ) || (ePLCF == CHP)) && (nOrigCp != WW8_CP_MAX) )
3375             {
3376                 bool bIsUnicode=false;
3377                 /*
3378                 To find the end of a paragraph for a character in a
3379                 complex format file.
3380 
3381                 It is necessary to know the piece that contains the
3382                 character and the FC assigned to the character.
3383                 */
3384 
3385                 //We set the piece iterator to the piece that contains the
3386                 //character, now we have the correct piece for this character
3387                 sal_uLong nOldPos = pPieceIter->GetIdx();
3388                 p->nStartPos = nOrigCp;
3389                 pPieceIter->SeekPos( p->nStartPos);
3390 
3391                 //This is the FC assigned to the character, but we already
3392                 //have the result of the next stage, so we can skip this step
3393                 //WW8_FC nStartFc = rSBase.WW8Cp2Fc(p->nStartPos, &bIsUnicode);
3394 
3395                 /*
3396                 Using the FC of the character, first search the FKP that
3397                 describes the character to find the smallest FC in the rgfc
3398                 that is larger than the character FC.
3399                 */
3400                 //But the search has already been done, the next largest FC is
3401                 //p->nEndPos.
3402                 WW8_FC nOldEndPos = p->nEndPos;
3403 
3404                 /*
3405                 If the FC found in the FKP is less than or equal to the limit
3406                 FC of the piece, the end of the paragraph that contains the
3407                 character is at the FKP FC minus 1.
3408                 */
3409                 WW8_CP nCpStart, nCpEnd;
3410                 void* pData=NULL;
3411                 pPieceIter->Get(nCpStart, nCpEnd, pData);
3412 
3413                 WW8_FC nLimitFC = SVBT32ToUInt32( ((WW8_PCD*)pData)->fc );
3414                 WW8_FC nBeginLimitFC = nLimitFC;
3415                 if (IsEightPlus(GetFIBVersion()))
3416                 {
3417                     nBeginLimitFC =
3418                         WW8PLCFx_PCD::TransformPieceAddress(nLimitFC,
3419                         bIsUnicode);
3420                 }
3421 
3422                 nLimitFC = nBeginLimitFC +
3423                     (nCpEnd - nCpStart) * (bIsUnicode ? 2 : 1);
3424 
3425                 if (nOldEndPos <= nLimitFC)
3426                 {
3427                     p->nEndPos = nCpEnd -
3428                         (nLimitFC-nOldEndPos) / (bIsUnicode ? 2 : 1);
3429                 }
3430                 else
3431                 {
3432                     if (ePLCF == CHP)
3433                         p->nEndPos = nCpEnd;
3434                     else
3435                     {
3436                         /*
3437                         If the FKP FC that was found was greater than the FC
3438                         of the end of the piece, scan piece by piece toward
3439                         the end of the document until a piece is found that
3440                         contains a  paragraph end mark.
3441                         */
3442 
3443                         /*
3444                         It's possible to check if a piece contains a paragraph
3445                         mark by using the FC of the beginning of the piece to
3446                         search in the FKPs for the smallest FC in the FKP rgfc
3447                         that is greater than the FC of the beginning of the
3448                         piece. If the FC found is less than or equal to the
3449                         limit FC of the piece, then the character that ends
3450                         the paragraph is the character immediately before the
3451                         FKP fc
3452                         */
3453 
3454                         (*pPieceIter)++;
3455 
3456                         for (;pPieceIter->GetIdx() < pPieceIter->GetIMax();
3457                             (*pPieceIter)++)
3458                         {
3459                             if( !pPieceIter->Get( nCpStart, nCpEnd, pData ) )
3460                             {
3461                                 ASSERT( !this, "piece iter broken!" );
3462                                 break;
3463                             }
3464                             bIsUnicode = false;
3465                             sal_Int32 nFcStart=SVBT32ToUInt32(((WW8_PCD*)pData)->fc);
3466 
3467                             if (IsEightPlus(GetFIBVersion()))
3468                             {
3469                                 nFcStart =
3470                                     WW8PLCFx_PCD::TransformPieceAddress(
3471                                     nFcStart,bIsUnicode );
3472                             }
3473 
3474                             nLimitFC = nFcStart + (nCpEnd - nCpStart) *
3475                                 (bIsUnicode ? 2 : 1);
3476 
3477                             //if it doesn't exist, skip it
3478                             if (!SeekPos(nCpStart))
3479                                 continue;
3480 
3481                             WW8_FC nOne,nSmallest;
3482                             p->pMemPos = WW8PLCFx_Fc_FKP::GetSprmsAndPos(nOne,
3483                                 nSmallest, p->nSprmsLen);
3484 
3485                             if (nSmallest <= nLimitFC)
3486                             {
3487                                 p->nEndPos = nCpEnd -
3488                                     (nLimitFC-nSmallest) / (bIsUnicode ? 2 : 1);
3489                                 break;
3490                             }
3491                         }
3492                     }
3493                 }
3494                 pPieceIter->SetIdx( nOldPos );
3495             }
3496             else
3497                 pPcd->AktPieceFc2Cp( p->nStartPos, p->nEndPos,&rSBase );
3498         }
3499         else
3500         {
3501             p->nStartPos = nAttrStart;
3502             p->nEndPos = nAttrEnd;
3503             p->bRealLineEnd = bLineEnd;
3504         }
3505     }
3506     else        // KEINE Piece-Table !!!
3507     {
3508         p->nStartPos = rSBase.WW8Fc2Cp( p->nStartPos );
3509         p->nEndPos   = rSBase.WW8Fc2Cp( p->nEndPos );
3510         p->bRealLineEnd = ePLCF == PAP;
3511     }
3512 }
3513 
3514 WW8PLCFx& WW8PLCFx_Cp_FKP::operator ++( int )
3515 {
3516     WW8PLCFx_Fc_FKP::operator ++( 0 );
3517     // !pPcd: Notbremse
3518     if ( !bComplex || !pPcd )
3519         return *this;
3520 
3521     if( GetPCDIdx() >= GetPCDIMax() )           // End of PLCF
3522     {
3523         nAttrStart = nAttrEnd = WW8_CP_MAX;
3524         return *this;
3525     }
3526 
3527     sal_Int32 nFkpLen;                               // Fkp-Eintrag
3528     // Fkp-Eintrag holen
3529     WW8PLCFx_Fc_FKP::GetSprmsAndPos(nAttrStart, nAttrEnd, nFkpLen);
3530 
3531     pPcd->AktPieceFc2Cp( nAttrStart, nAttrEnd, &rSBase );
3532     bLineEnd = (ePLCF == PAP);
3533     return *this;
3534 }
3535 
3536 //-----------------------------------------
3537 //-----------------------------------------
3538 
3539 WW8PLCFx_SEPX::WW8PLCFx_SEPX(
3540     SvStream* pSt,
3541     SvStream* pTblSt,
3542     const WW8Fib& rFib,
3543     WW8_CP nStartCp)
3544     : WW8PLCFx(rFib.GetFIBVersion(), true)
3545     , maSprmParser(rFib.GetFIBVersion())
3546     , pStrm(pSt)
3547     , nArrMax(256)
3548     , nSprmSiz(0)
3549 {
3550     pPLCF =   rFib.lcbPlcfsed
3551             ? new WW8PLCF(pTblSt, rFib.fcPlcfsed, rFib.lcbPlcfsed,
3552               GetFIBVersion() <= ww::eWW2 ? 6 : 12, nStartCp)
3553             : 0;
3554 
3555     pSprms = new sal_uInt8[nArrMax];     // maximum length
3556 }
3557 
3558 WW8PLCFx_SEPX::~WW8PLCFx_SEPX()
3559 {
3560     delete pPLCF;
3561     delete[] pSprms;
3562 }
3563 
3564 bool WW8PLCFx_SEPX::HasValidPLCF()
3565 {
3566     return pPLCF == 0 || pPLCF->IsValid();
3567 }
3568 
3569 sal_uLong WW8PLCFx_SEPX::GetIdx() const
3570 {
3571     return pPLCF ? pPLCF->GetIdx() : 0;
3572 }
3573 
3574 void WW8PLCFx_SEPX::SetIdx( sal_uLong nIdx )
3575 {
3576     if( pPLCF ) pPLCF->SetIdx( nIdx );
3577 }
3578 
3579 bool WW8PLCFx_SEPX::SeekPos(WW8_CP nCpPos)
3580 {
3581     return pPLCF ? pPLCF->SeekPos( nCpPos ) : 0;
3582 }
3583 
3584 WW8_CP WW8PLCFx_SEPX::Where()
3585 {
3586     return pPLCF ? pPLCF->Where() : 0;
3587 }
3588 
3589 void WW8PLCFx_SEPX::GetSprms(WW8PLCFxDesc* p)
3590 {
3591     if( !pPLCF ) return;
3592 
3593     void* pData;
3594 
3595     p->bRealLineEnd = false;
3596     if (!pPLCF->Get( p->nStartPos, p->nEndPos, pData ))
3597     {
3598         p->nStartPos = p->nEndPos = WW8_CP_MAX;       // PLCF fertig abgearbeitet
3599         p->pMemPos = 0;
3600         p->nSprmsLen = 0;
3601     }
3602     else
3603     {
3604         sal_uInt32 nPo =  SVBT32ToUInt32( (sal_uInt8*)pData+2 );
3605         if (nPo == 0xFFFFFFFF)
3606         {
3607             p->nStartPos = p->nEndPos = WW8_CP_MAX;   // Sepx empty
3608             p->pMemPos = 0;
3609             p->nSprmsLen = 0;
3610         }
3611         else
3612         {
3613             pStrm->Seek( nPo );
3614 
3615             // read len
3616             if (GetFIBVersion() <= ww::eWW2)	// eWW6 ?, docs say yes, but...
3617             {
3618                 sal_uInt8 nSiz(0);
3619                 *pStrm >> nSiz;
3620                 nSprmSiz = nSiz;
3621             }
3622             else
3623                 *pStrm >> nSprmSiz;
3624 
3625             if( nSprmSiz > nArrMax )
3626             {               // passt nicht
3627                 delete[] pSprms;
3628                 nArrMax = nSprmSiz;                 // Hole mehr Speicher
3629                 pSprms = new sal_uInt8[nArrMax];
3630             }
3631             pStrm->Read( pSprms, nSprmSiz );        // read Sprms
3632 
3633             p->nSprmsLen = nSprmSiz;
3634             p->pMemPos = pSprms;                    // return Position
3635         }
3636     }
3637 }
3638 
3639 WW8PLCFx& WW8PLCFx_SEPX::operator ++( int )
3640 {
3641     if( pPLCF )
3642         (*pPLCF)++;
3643     return *this;
3644 }
3645 
3646 const sal_uInt8* WW8PLCFx_SEPX::HasSprm( sal_uInt16 nId ) const
3647 {
3648     return HasSprm( nId, pSprms, nSprmSiz);
3649 }
3650 
3651 const sal_uInt8* WW8PLCFx_SEPX::HasSprm( sal_uInt16 nId, const sal_uInt8*  pOtherSprms,
3652     long nOtherSprmSiz ) const
3653 {
3654     const sal_uInt8 *pRet = 0;
3655     if (pPLCF)
3656     {
3657         WW8SprmIter aIter(pOtherSprms, nOtherSprmSiz, maSprmParser);
3658         pRet = aIter.FindSprm(nId);
3659     }
3660     return pRet;
3661 }
3662 
3663 bool WW8PLCFx_SEPX::Find4Sprms(sal_uInt16 nId1,sal_uInt16 nId2,sal_uInt16 nId3,sal_uInt16 nId4,
3664     sal_uInt8*& p1, sal_uInt8*& p2, sal_uInt8*& p3, sal_uInt8*& p4) const
3665 {
3666     if( !pPLCF )
3667         return 0;
3668 
3669     bool bFound = false;
3670     p1 = 0;
3671     p2 = 0;
3672     p3 = 0;
3673     p4 = 0;
3674 
3675     sal_uInt8* pSp = pSprms;
3676     sal_uInt16 i=0;
3677     while (i + maSprmParser.MinSprmLen() <= nSprmSiz)
3678     {
3679         // Sprm gefunden?
3680         sal_uInt16 nAktId = maSprmParser.GetSprmId(pSp);
3681         bool bOk = true;
3682         if( nAktId  == nId1 )
3683             p1 = pSp + maSprmParser.DistanceToData(nId1);
3684         else if( nAktId  == nId2 )
3685             p2 = pSp + maSprmParser.DistanceToData(nId2);
3686         else if( nAktId  == nId3 )
3687             p3 = pSp + maSprmParser.DistanceToData(nId3);
3688         else if( nAktId  == nId4 )
3689             p4 = pSp + maSprmParser.DistanceToData(nId4);
3690         else
3691             bOk = false;
3692         bFound |= bOk;
3693         // erhoehe Zeiger, so dass er auf naechsten Sprm zeigt
3694         sal_uInt16 x = maSprmParser.GetSprmSize(nAktId, pSp);
3695         i = i + x;
3696         pSp += x;
3697     }
3698     return bFound;
3699 }
3700 
3701 const sal_uInt8* WW8PLCFx_SEPX::HasSprm( sal_uInt16 nId, sal_uInt8 n2nd ) const
3702 {
3703     if( !pPLCF )
3704         return 0;
3705 
3706     sal_uInt8* pSp = pSprms;
3707 
3708     sal_uInt16 i=0;
3709     while (i + maSprmParser.MinSprmLen() <= nSprmSiz)
3710     {
3711         // Sprm gefunden?
3712         sal_uInt16 nAktId = maSprmParser.GetSprmId(pSp);
3713         if (nAktId == nId)
3714         {
3715             sal_uInt8 *pRet = pSp + maSprmParser.DistanceToData(nId);
3716             if (*pRet == n2nd)
3717                 return pRet;
3718         }
3719         // erhoehe Zeiger, so dass er auf naechsten Sprm zeigt
3720         sal_uInt16 x = maSprmParser.GetSprmSize(nAktId, pSp);
3721         i = i + x;
3722         pSp += x;
3723     }
3724 
3725     return 0;   // Sprm nicht gefunden
3726 }
3727 
3728 //-----------------------------------------
3729 WW8PLCFx_SubDoc::WW8PLCFx_SubDoc(
3730     SvStream* pSt,
3731     ww::WordVersion eVersion,
3732     WW8_CP nStartCp,
3733     long nFcRef,
3734     long nLenRef,
3735     long nFcTxt,
3736     long nLenTxt,
3737     long nStruct)
3738     : WW8PLCFx(eVersion, true)
3739     , pRef(0)
3740     , pTxt(0)
3741 {
3742     if( nLenRef && nLenTxt )
3743     {
3744         pRef = new WW8PLCF( pSt, nFcRef, nLenRef, nStruct, nStartCp );
3745         pTxt = new WW8PLCF( pSt, nFcTxt, nLenTxt, 0, nStartCp );
3746     }
3747 }
3748 
3749 WW8PLCFx_SubDoc::~WW8PLCFx_SubDoc()
3750 {
3751     delete pRef;
3752     delete pTxt;
3753 }
3754 
3755 bool WW8PLCFx_SubDoc::HasValidPLCF()
3756 {
3757     return ( pRef == 0 || pRef->IsValid() )
3758            && ( pTxt == 0 || pTxt->IsValid() );
3759 }
3760 
3761 sal_uLong WW8PLCFx_SubDoc::GetIdx() const
3762 {
3763     // Wahrscheinlich pTxt... nicht noetig
3764     if( pRef )
3765         return ( pRef->GetIdx() << 16 | pTxt->GetIdx() );
3766     return 0;
3767 }
3768 
3769 void WW8PLCFx_SubDoc::SetIdx( sal_uLong nIdx )
3770 {
3771     if( pRef )
3772     {
3773         pRef->SetIdx( nIdx >> 16 );
3774         // Wahrscheinlich pTxt... nicht noetig
3775         pTxt->SetIdx( nIdx & 0xFFFF );
3776     }
3777 }
3778 
3779 bool WW8PLCFx_SubDoc::SeekPos( WW8_CP nCpPos )
3780 {
3781     return ( pRef ) ? pRef->SeekPos( nCpPos ) : false;
3782 }
3783 
3784 WW8_CP WW8PLCFx_SubDoc::Where()
3785 {
3786     return ( pRef ) ? pRef->Where() : WW8_CP_MAX;
3787 }
3788 
3789 void WW8PLCFx_SubDoc::GetSprms(WW8PLCFxDesc* p)
3790 {
3791     p->nStartPos = p->nEndPos = WW8_CP_MAX;
3792     p->pMemPos = 0;
3793     p->nSprmsLen = 0;
3794     p->bRealLineEnd = false;
3795 
3796     if (!pRef)
3797         return;
3798 
3799     sal_uLong nNr = pRef->GetIdx();
3800 
3801     void *pData;
3802     WW8_CP nFoo;
3803     if (!pRef->Get(p->nStartPos, nFoo, pData))
3804     {
3805         p->nEndPos = p->nStartPos = WW8_CP_MAX;
3806         return;
3807     }
3808 
3809     p->nEndPos = p->nStartPos + 1;
3810 
3811     if (!pTxt)
3812         return;
3813 
3814     pTxt->SetIdx(nNr);
3815 
3816     if (!pTxt->Get(p->nCp2OrIdx, p->nSprmsLen, pData))
3817     {
3818         p->nEndPos = p->nStartPos = WW8_CP_MAX;
3819         p->nSprmsLen = 0;
3820         return;
3821     }
3822 
3823     p->nSprmsLen -= p->nCp2OrIdx;
3824 }
3825 
3826 WW8PLCFx& WW8PLCFx_SubDoc::operator ++( int )
3827 {
3828     if( pRef && pTxt )
3829     {
3830         (*pRef)++;
3831         (*pTxt)++;
3832     }
3833     return *this;
3834 }
3835 
3836 //-----------------------------------------
3837 //          Felder
3838 //-----------------------------------------
3839 
3840 WW8PLCFx_FLD::WW8PLCFx_FLD( SvStream* pSt, const WW8Fib& rMyFib, short nType)
3841     : WW8PLCFx(rMyFib.GetFIBVersion(), true), pPLCF(0), rFib(rMyFib)
3842 {
3843     long nFc, nLen;
3844 
3845     switch( nType )
3846     {
3847     case MAN_HDFT:
3848         nFc = rFib.fcPlcffldHdr;
3849         nLen = rFib.lcbPlcffldHdr;
3850         break;
3851     case MAN_FTN:
3852         nFc = rFib.fcPlcffldFtn;
3853         nLen = rFib.lcbPlcffldFtn;
3854         break;
3855     case MAN_EDN:
3856         nFc = rFib.fcPlcffldEdn;
3857         nLen = rFib.lcbPlcffldEdn;
3858         break;
3859     case MAN_AND:
3860         nFc = rFib.fcPlcffldAtn;
3861         nLen = rFib.lcbPlcffldAtn;
3862         break;
3863     case MAN_TXBX:
3864         nFc = rFib.fcPlcffldTxbx;
3865         nLen = rFib.lcbPlcffldTxbx;
3866         break;
3867     case MAN_TXBX_HDFT:
3868         nFc = rFib.fcPlcffldHdrTxbx;
3869         nLen = rFib.lcbPlcffldHdrTxbx;
3870         break;
3871     default:
3872         nFc = rFib.fcPlcffldMom;
3873         nLen = rFib.lcbPlcffldMom;
3874         break;
3875     }
3876 
3877     if( nLen )
3878         pPLCF = new WW8PLCFspecial( pSt, nFc, nLen, 2 );
3879 }
3880 
3881 WW8PLCFx_FLD::~WW8PLCFx_FLD()
3882 {
3883     delete pPLCF;
3884 }
3885 
3886 bool WW8PLCFx_FLD::HasValidPLCF()
3887 {
3888     return pPLCF == 0 || pPLCF->IsValid();
3889 }
3890 
3891 sal_uLong WW8PLCFx_FLD::GetIdx() const
3892 {
3893     return pPLCF ? pPLCF->GetIdx() : 0;
3894 }
3895 
3896 void WW8PLCFx_FLD::SetIdx( sal_uLong nIdx )
3897 {
3898     if( pPLCF )
3899         pPLCF->SetIdx( nIdx );
3900 }
3901 
3902 bool WW8PLCFx_FLD::SeekPos(WW8_CP nCpPos)
3903 {
3904     return pPLCF ? pPLCF->SeekPosExact( nCpPos ) : false;
3905 }
3906 
3907 WW8_CP WW8PLCFx_FLD::Where()
3908 {
3909     return pPLCF ? pPLCF->Where() : WW8_CP_MAX;
3910 }
3911 
3912 bool WW8PLCFx_FLD::StartPosIsFieldStart()
3913 {
3914     void* pData;
3915     sal_Int32 nTest;
3916     if (
3917          (!pPLCF || !pPLCF->Get(nTest, pData) ||
3918          ((((sal_uInt8*)pData)[0] & 0x1f) != 0x13))
3919        )
3920         return false;
3921     return true;
3922 }
3923 
3924 bool WW8PLCFx_FLD::EndPosIsFieldEnd(WW8_CP& nCP)
3925 {
3926     bool bRet = false;
3927 
3928     if (pPLCF)
3929     {
3930         long n = pPLCF->GetIdx();
3931 
3932         (*pPLCF)++;
3933 
3934         void* pData;
3935         sal_Int32 nTest;
3936         if ( pPLCF->Get(nTest, pData) && ((((sal_uInt8*)pData)[0] & 0x1f) == 0x15) )
3937         {
3938             nCP = nTest;
3939             bRet = true;
3940         }
3941 
3942         pPLCF->SetIdx(n);
3943     }
3944 
3945     return bRet;
3946 }
3947 
3948 void WW8PLCFx_FLD::GetSprms(WW8PLCFxDesc* p)
3949 {
3950     p->nStartPos = p->nEndPos = WW8_CP_MAX;
3951     p->pMemPos = 0;
3952     p->nSprmsLen = 0;
3953     p->bRealLineEnd = false;
3954 
3955     if (!pPLCF)
3956     {
3957         p->nStartPos = WW8_CP_MAX;                    // Es gibt keine Felder
3958         return;
3959     }
3960 
3961     long n = pPLCF->GetIdx();
3962 
3963     sal_Int32 nP;
3964     void *pData;
3965     if (!pPLCF->Get(nP, pData))             // Ende des PLCFspecial ?
3966     {
3967         p->nStartPos = WW8_CP_MAX;            // PLCF fertig abgearbeitet
3968         return;
3969     }
3970 
3971     p->nStartPos = nP;
3972 
3973     (*pPLCF)++;
3974     if (!pPLCF->Get(nP, pData))             // Ende des PLCFspecial ?
3975     {
3976         p->nStartPos = WW8_CP_MAX;            // PLCF fertig abgearbeitet
3977         return;
3978     }
3979 
3980     p->nEndPos = nP;
3981 
3982     pPLCF->SetIdx(n);
3983 
3984     p->nCp2OrIdx = pPLCF->GetIdx();
3985 }
3986 
3987 WW8PLCFx& WW8PLCFx_FLD::operator ++( int )
3988 {
3989     (*pPLCF)++;
3990     return *this;
3991 }
3992 
3993 bool WW8PLCFx_FLD::GetPara(long nIdx, WW8FieldDesc& rF)
3994 {
3995     ASSERT( pPLCF, "Aufruf ohne Feld PLCFspecial" );
3996     if( !pPLCF )
3997         return false;
3998 
3999     long n = pPLCF->GetIdx();
4000     pPLCF->SetIdx(nIdx);
4001 
4002     bool bOk = WW8GetFieldPara(*pPLCF, rF);
4003 
4004     pPLCF->SetIdx(n);
4005     return bOk;
4006 }
4007 
4008 //-----------------------------------------
4009 //      class WW8PLCF_Book
4010 //-----------------------------------------
4011 
4012 /*  to be optimized like this:    */
4013 void WW8ReadSTTBF(bool bVer8, SvStream& rStrm, sal_uInt32 nStart, sal_Int32 nLen,
4014     sal_uInt16 nExtraLen, rtl_TextEncoding eCS, std::vector<String> &rArray,
4015     std::vector<ww::bytes>* pExtraArray, ::std::vector<String>* pValueArray)
4016 {
4017     if(nLen==0)     // Handle Empty STTBF
4018         return;
4019 
4020     sal_uLong nOldPos = rStrm.Tell();
4021     rStrm.Seek( nStart );
4022 
4023     sal_uInt16 nLen2;
4024     rStrm >> nLen2; // bVer67: total length of structure
4025                     // bVer8 : count of strings
4026 
4027     if( bVer8 )
4028     {
4029         sal_uInt16 nStrings;
4030         bool bUnicode = (0xFFFF == nLen2);
4031         if( bUnicode )
4032             rStrm >> nStrings;
4033         else
4034             nStrings = nLen2;
4035 
4036         rStrm >> nExtraLen;
4037 
4038         for( sal_uInt16 i=0; i < nStrings; i++ )
4039         {
4040             if( bUnicode )
4041                 rArray.push_back(WW8Read_xstz(rStrm, 0, false));
4042             else
4043             {
4044                 sal_uInt8 nBChar;
4045                 rStrm >> nBChar;
4046                 ByteString aTmp;
4047                 SafeReadString(aTmp,nBChar,rStrm);
4048                 rArray.push_back(String(aTmp, eCS));
4049             }
4050 
4051             // Skip the extra data
4052             if( nExtraLen )
4053             {
4054                 if (pExtraArray)
4055                 {
4056                     ww::bytes extraData;
4057                     sal_uInt8 iTmp;
4058                     for(int j = 0; j < nExtraLen; ++j)
4059                     {
4060                         rStrm >> iTmp;
4061                         extraData.push_back(iTmp);
4062                     }
4063                     pExtraArray->push_back(extraData);
4064                 }
4065                 else
4066                     rStrm.SeekRel( nExtraLen );
4067             }
4068         }
4069 		// #129053# read the value of the document variables, if requested.
4070 		if (pValueArray)
4071 		{
4072 				for( sal_uInt16 i=0; i < nStrings; i++ )
4073 				{
4074 						if( bUnicode )
4075 								pValueArray->push_back(WW8Read_xstz(rStrm, 0, false));
4076 						else
4077 						{
4078 								sal_uInt8 nBChar;
4079 								rStrm >> nBChar;
4080 								ByteString aTmp;
4081 								SafeReadString(aTmp,nBChar,rStrm);
4082 								pValueArray->push_back(String(aTmp, eCS));
4083 						}
4084 				}
4085 		}
4086     }
4087     else
4088     {
4089         sal_uInt8 nBChar;
4090         if( nLen2 != nLen )
4091         {
4092             ASSERT( nLen2 == nLen, "Fib length and read length are different" );
4093             if (nLen > USHRT_MAX)
4094                 nLen = USHRT_MAX;
4095             else if (nLen < 2 )
4096                 nLen = 2;
4097             nLen2 = static_cast<sal_uInt16>(nLen);
4098         }
4099         sal_uLong nRead = 0;
4100         for( nLen2 -= 2; nRead < nLen2;  )
4101         {
4102             rStrm >> nBChar; ++nRead;
4103             if (nBChar)
4104             {
4105                 ByteString aTmp;
4106                 nRead += SafeReadString(aTmp,nBChar,rStrm);
4107                 rArray.push_back(String(aTmp, eCS));
4108             }
4109             else
4110                 rArray.push_back(aEmptyStr);
4111 
4112             // #89125# Skip the extra data (for bVer67 versions this must come
4113             // from external knowledge)
4114             if (nExtraLen)
4115             {
4116                 if (pExtraArray)
4117                 {
4118                     ww::bytes extraData;
4119                     for(int i =0;i < nExtraLen;i++)
4120                     {
4121                         sal_uInt8 iTmp;
4122                         rStrm >> iTmp;
4123                         extraData.push_back(iTmp);
4124                     }
4125                     pExtraArray->push_back(extraData);
4126                 }
4127                 else
4128                     rStrm.SeekRel( nExtraLen );
4129                 nRead+=nExtraLen;
4130             }
4131         }
4132     }
4133     rStrm.Seek( nOldPos );
4134 }
4135 
4136 WW8PLCFx_Book::WW8PLCFx_Book(SvStream* pTblSt, const WW8Fib& rFib)
4137     : WW8PLCFx(rFib.GetFIBVersion(), false), pStatus(0), nIsEnd(0), nBookmarkId(1)
4138 {
4139     if( !rFib.fcPlcfbkf || !rFib.lcbPlcfbkf || !rFib.fcPlcfbkl ||
4140         !rFib.lcbPlcfbkl || !rFib.fcSttbfbkmk || !rFib.lcbSttbfbkmk )
4141     {
4142         pBook[0] = pBook[1] = 0;
4143         nIMax = 0;
4144     }
4145     else
4146     {
4147         pBook[0] = new WW8PLCFspecial(pTblSt,rFib.fcPlcfbkf,rFib.lcbPlcfbkf,4);
4148 
4149         pBook[1] = new WW8PLCFspecial(pTblSt,rFib.fcPlcfbkl,rFib.lcbPlcfbkl,0);
4150 
4151         rtl_TextEncoding eStructChrSet = WW8Fib::GetFIBCharset(rFib.chseTables);
4152 
4153         WW8ReadSTTBF( (7 < rFib.nVersion), *pTblSt, rFib.fcSttbfbkmk,
4154             rFib.lcbSttbfbkmk, 0, eStructChrSet, aBookNames );
4155 
4156         nIMax = aBookNames.size();
4157 
4158         if( pBook[0]->GetIMax() < nIMax )   // Count of Bookmarks
4159             nIMax = pBook[0]->GetIMax();
4160         if( pBook[1]->GetIMax() < nIMax )
4161             nIMax = pBook[1]->GetIMax();
4162         pStatus = new eBookStatus[ nIMax ];
4163         memset( pStatus, 0, nIMax * sizeof( eBookStatus ) );
4164     }
4165 }
4166 
4167 WW8PLCFx_Book::~WW8PLCFx_Book()
4168 {
4169     delete[] pStatus;
4170     delete pBook[1];
4171     delete pBook[0];
4172 }
4173 
4174 bool WW8PLCFx_Book::HasValidPLCF()
4175 {
4176     return ( pBook[0] == 0 || pBook[0]->IsValid() )
4177            && ( pBook[1] == 0 || pBook[1]->IsValid() );
4178 }
4179 
4180 sal_uLong WW8PLCFx_Book::GetIdx() const
4181 {
4182     return nIMax ? pBook[0]->GetIdx() : 0;
4183 }
4184 
4185 void WW8PLCFx_Book::SetIdx( sal_uLong nI )
4186 {
4187     if( nIMax )
4188         pBook[0]->SetIdx( nI );
4189 }
4190 
4191 sal_uLong WW8PLCFx_Book::GetIdx2() const
4192 {
4193     return nIMax ? ( pBook[1]->GetIdx() | ( ( nIsEnd ) ? 0x80000000 : 0 ) ) : 0;
4194 }
4195 
4196 void WW8PLCFx_Book::SetIdx2( sal_uLong nI )
4197 {
4198     if( nIMax )
4199     {
4200         pBook[1]->SetIdx( nI & 0x7fffffff );
4201         nIsEnd = (sal_uInt16)( ( nI >> 31 ) & 1 );  // 0 oder 1
4202     }
4203 }
4204 
4205 bool WW8PLCFx_Book::SeekPos(WW8_CP nCpPos)
4206 {
4207     if( !pBook[0] )
4208         return false;
4209 
4210     bool bOk = pBook[0]->SeekPosExact( nCpPos );
4211     bOk &= pBook[1]->SeekPosExact( nCpPos );
4212     nIsEnd = 0;
4213 
4214     return bOk;
4215 }
4216 
4217 WW8_CP WW8PLCFx_Book::Where()
4218 {
4219     return pBook[nIsEnd]->Where();
4220 }
4221 
4222 long WW8PLCFx_Book::GetNoSprms( WW8_CP& rStart, WW8_CP& rEnd, sal_Int32& rLen )
4223 {
4224     void* pData;
4225     rEnd = WW8_CP_MAX;
4226     rLen = 0;
4227 
4228     if (!pBook[0] || !pBook[1] || !nIMax || (pBook[nIsEnd]->GetIdx()) >= nIMax)
4229     {
4230         rStart = rEnd = WW8_CP_MAX;
4231         return -1;
4232     }
4233 
4234     pBook[nIsEnd]->Get( rStart, pData );    // Pos. abfragen
4235 
4236     return pBook[nIsEnd]->GetIdx();
4237 }
4238 
4239 // Der Operator ++ hat eine Tuecke: Wenn 2 Bookmarks aneinandergrenzen, dann
4240 // sollte erst das Ende des ersten und dann der Anfang des 2. erreicht werden.
4241 // Liegen jedoch 2 Bookmarks der Laenge 0 aufeinander, *muss* von jedem Bookmark
4242 // erst der Anfang und dann das Ende gefunden werden.
4243 // Der Fall: ][
4244 //            [...]
4245 //           ][
4246 // ist noch nicht geloest, dabei muesste ich in den Anfangs- und Endindices
4247 // vor- und zurueckspringen, wobei ein weiterer Index oder ein Bitfeld
4248 // oder etwas aehnliches zum Merken der bereits abgearbeiteten Bookmarks
4249 // noetig wird.
4250 WW8PLCFx& WW8PLCFx_Book::operator ++( int )
4251 {
4252     if( pBook[0] && pBook[1] && nIMax )
4253     {
4254         (*pBook[nIsEnd])++;
4255 
4256         sal_uLong l0 = pBook[0]->Where();
4257         sal_uLong l1 = pBook[1]->Where();
4258         if( l0 < l1 )
4259             nIsEnd = 0;
4260         else if( l1 < l0 )
4261             nIsEnd = 1;
4262         else
4263         {
4264             const void * p = pBook[0]->GetData(pBook[0]->GetIdx());
4265             long nPairFor = (p == NULL)? 0L : SVBT16ToShort(*((SVBT16*) p));
4266             if (nPairFor == pBook[1]->GetIdx())
4267                 nIsEnd = 0;
4268             else
4269                 nIsEnd = ( nIsEnd ) ? 0 : 1;
4270         }
4271     }
4272     return *this;
4273 }
4274 
4275 long WW8PLCFx_Book::GetLen() const
4276 {
4277     if( nIsEnd )
4278     {
4279         ASSERT( !this, "Falscher Aufruf (1) von PLCF_Book::GetLen()" );
4280         return 0;
4281     }
4282     void * p;
4283     WW8_CP nStartPos;
4284     if( !pBook[0]->Get( nStartPos, p ) )
4285     {
4286         ASSERT( !this, "Falscher Aufruf (2) von PLCF_Book::GetLen()" );
4287         return 0;
4288     }
4289     sal_uInt16 nEndIdx = SVBT16ToShort( *((SVBT16*)p) );
4290     long nNum = pBook[1]->GetPos( nEndIdx );
4291     nNum -= nStartPos;
4292     return nNum;
4293 }
4294 
4295 void WW8PLCFx_Book::SetStatus(sal_uInt16 nIndex, eBookStatus eStat )
4296 {
4297     ASSERT(nIndex < nIMax, "set status of non existing bookmark!");
4298     pStatus[nIndex] = (eBookStatus)( pStatus[nIndex] | eStat );
4299 }
4300 
4301 eBookStatus WW8PLCFx_Book::GetStatus() const
4302 {
4303     if( !pStatus )
4304         return BOOK_NORMAL;
4305     long nEndIdx = GetHandle();
4306     return ( nEndIdx < nIMax ) ? pStatus[nEndIdx] : BOOK_NORMAL;
4307 }
4308 
4309 long WW8PLCFx_Book::GetHandle() const
4310 {
4311     if( !pBook[0] || !pBook[1] )
4312         return LONG_MAX;
4313 
4314     if( nIsEnd )
4315         return pBook[1]->GetIdx();
4316     else
4317     {
4318         if (const void* p = pBook[0]->GetData(pBook[0]->GetIdx()))
4319             return SVBT16ToShort( *((SVBT16*)p) );
4320         else
4321             return LONG_MAX;
4322     }
4323 }
4324 
4325 String WW8PLCFx_Book::GetBookmark(long nStart,long nEnd, sal_uInt16 &nIndex)
4326 {
4327     bool bFound = false;
4328     sal_uInt16 i = 0;
4329     if( pBook[0] && pBook[1] )
4330     {
4331         WW8_CP nStartAkt, nEndAkt;
4332         do
4333         {
4334             void* p;
4335             sal_uInt16 nEndIdx;
4336 
4337             if( pBook[0]->GetData( i, nStartAkt, p ) && p )
4338                 nEndIdx = SVBT16ToShort( *((SVBT16*)p) );
4339             else
4340             {
4341                 ASSERT( !this, "Bookmark-EndIdx nicht lesbar" );
4342                 nEndIdx = i;
4343             }
4344 
4345             nEndAkt = pBook[1]->GetPos( nEndIdx );
4346 
4347             if ((nStartAkt >= nStart) && (nEndAkt <= nEnd))
4348             {
4349                 nIndex = i;
4350                 bFound=true;
4351                 break;
4352             }
4353             ++i;
4354         }
4355         while (i < pBook[0]->GetIMax());
4356     }
4357     return bFound ? aBookNames[i] : aEmptyStr;
4358 }
4359 
4360 String WW8PLCFx_Book::GetUniqueBookmarkName(String &suggestedName)
4361 {
4362 	String aRet=(suggestedName.Len()==0?String::CreateFromAscii("Unnamed"):suggestedName);
4363 	unsigned int i=0;
4364 	while(i<aBookNames.size()) {
4365 		String &s=aBookNames[i];
4366 		if (aRet.CompareTo(s)==0) {
4367 			int len=aRet.Len();
4368 			int p=len-1;
4369 			while(p>0 && aRet.GetChar(static_cast<sal_uInt16>(p))>='0' && aRet.GetChar(static_cast<sal_uInt16>(p))<='9')
4370                 p--;
4371 			aRet=String(aRet, 0, static_cast<sal_uInt16>(p+1));
4372 			aRet += String::CreateFromInt32( nBookmarkId++ );
4373 			i=0; // start search from beginning
4374 		} else {
4375 			i++;
4376 		}
4377 	}
4378 	return aRet;
4379 }
4380 
4381 bool WW8PLCFx_Book::MapName(String& rName)
4382 {
4383     if( !pBook[0] || !pBook[1] )
4384         return false;
4385 
4386     bool bFound = false;
4387     sal_uInt16 i = 0;
4388     WW8_CP nStartAkt, nEndAkt;
4389     do
4390     {
4391         void* p;
4392         sal_uInt16 nEndIdx;
4393 
4394         if( pBook[0]->GetData( i, nStartAkt, p ) && p )
4395             nEndIdx = SVBT16ToShort( *((SVBT16*)p) );
4396         else
4397         {
4398             ASSERT( !this, "Bookmark-EndIdx nicht lesbar" );
4399             nEndIdx = i;
4400         }
4401         nEndAkt = pBook[1]->GetPos( nEndIdx );
4402         if (COMPARE_EQUAL == rName.CompareIgnoreCaseToAscii(aBookNames[i]))
4403         {
4404             rName = aBookNames[i];
4405             bFound = true;
4406         }
4407         ++i;
4408     }
4409     while (!bFound && i < pBook[0]->GetIMax());
4410     return bFound;
4411 }
4412 
4413 const String* WW8PLCFx_Book::GetName() const
4414 {
4415     const String *pRet = 0;
4416     if (!nIsEnd && (pBook[0]->GetIdx() < nIMax))
4417         pRet = &(aBookNames[pBook[0]->GetIdx()]);
4418     return pRet;
4419 }
4420 
4421 //-----------------------------------------
4422 //          WW8PLCFMan
4423 //-----------------------------------------
4424 
4425 #ifndef DUMP
4426 
4427 // Am Ende eines Absatzes reichen bei WW6 die Attribute bis hinter das <CR>.
4428 // Das wird fuer die Verwendung mit dem SW um 1 Zeichen zurueckgesetzt, wenn
4429 // dadurch kein AErger zu erwarten ist.
4430 void WW8PLCFMan::AdjustEnds( WW8PLCFxDesc& rDesc )
4431 {
4432     //Store old end position for supercool new property finder that uses
4433     //cp instead of fc's as nature intended
4434     rDesc.nOrigEndPos = rDesc.nEndPos;
4435     rDesc.nOrigStartPos = rDesc.nStartPos;
4436 
4437     /*
4438      Normally given ^XXX{para end}^ we don't actually insert a para end
4439      character into the document, so we clip the para end property one to the
4440      left to make the para properties end when the paragraph text does. In a
4441      drawing textbox we actually do insert a para end character, so we don't
4442      clip it. Making the para end properties end after the para end char.
4443     */
4444     if (GetDoingDrawTextBox())
4445         return;
4446 
4447     if ( (&rDesc == pPap) && rDesc.bRealLineEnd )
4448     {
4449         if ( pPap->nEndPos != WW8_CP_MAX )    // Para adjust
4450         {
4451             nLineEnd = pPap->nEndPos;// nLineEnd zeigt *hinter* das <CR>
4452             pPap->nEndPos--;        // Absatzende um 1 Zeichen verkuerzen
4453 
4454             // gibt es bereits ein CharAttr-Ende das auf das jetzige
4455             // Absatzende zeigt ?  ... dann auch um 1 Zeichen verkuerzen
4456             if (pChp->nEndPos == nLineEnd)
4457                 pChp->nEndPos--;
4458 
4459             // gibt es bereits ein Sep-Ende, das auf das jetzige Absatzende
4460             // zeigt ?  ... dann auch um 1 Zeichen verkuerzen
4461             if( pSep->nEndPos == nLineEnd )
4462                 pSep->nEndPos--;
4463         }
4464     }
4465     else if ( (&rDesc == pChp) || (&rDesc == pSep) )
4466     {
4467         // Char Adjust oder Sep Adjust Wenn Ende Char-Attr == Absatzende ...
4468         if( (rDesc.nEndPos == nLineEnd) && (rDesc.nEndPos > rDesc.nStartPos) )
4469             rDesc.nEndPos--;            // ... dann um 1 Zeichen verkuerzen
4470     }
4471 }
4472 
4473 void WW8PLCFxDesc::ReduceByOffset()
4474 {
4475     ASSERT((WW8_CP_MAX == nStartPos) || (nStartPos <= nEndPos),
4476             "Attr-Anfang und -Ende ueber Kreuz" );
4477 
4478     if( nStartPos != WW8_CP_MAX )
4479     {
4480         /*
4481         ##516##,##517##
4482         Force the property change to happen at the beginning of this
4483         subdocument, same as in GetNewNoSprms, except that the target type is
4484         attributes attached to a piece that might span subdocument boundaries
4485         */
4486         if (nCpOfs > nStartPos)
4487             nStartPos = 0;
4488         else
4489             nStartPos -= nCpOfs;
4490     }
4491     if( nEndPos != WW8_CP_MAX )
4492     {
4493         ASSERT(nCpOfs <= nEndPos,
4494             "oh oh, so much for the subdocument piece theory");
4495         nEndPos   -= nCpOfs;
4496     }
4497 }
4498 
4499 void WW8PLCFMan::GetNewSprms( WW8PLCFxDesc& rDesc )
4500 {
4501     rDesc.pPLCFx->GetSprms(&rDesc);
4502     rDesc.ReduceByOffset();
4503 
4504     rDesc.bFirstSprm = true;
4505     AdjustEnds( rDesc );
4506     rDesc.nOrigSprmsLen = rDesc.nSprmsLen;
4507 }
4508 
4509 void WW8PLCFMan::GetNewNoSprms( WW8PLCFxDesc& rDesc )
4510 {
4511     rDesc.nCp2OrIdx = rDesc.pPLCFx->GetNoSprms(rDesc.nStartPos, rDesc.nEndPos,
4512         rDesc.nSprmsLen);
4513 
4514     ASSERT((WW8_CP_MAX == rDesc.nStartPos) || (rDesc.nStartPos <= rDesc.nEndPos),
4515             "Attr-Anfang und -Ende ueber Kreuz" );
4516 
4517     rDesc.ReduceByOffset();
4518 
4519     rDesc.bFirstSprm = true;
4520     rDesc.nOrigSprmsLen = rDesc.nSprmsLen;
4521 }
4522 
4523 sal_uInt16 WW8PLCFMan::GetId(const WW8PLCFxDesc* p) const
4524 {
4525     sal_uInt16 nId;
4526 
4527     if (p == pFld)
4528         nId = eFLD;
4529     else if (p == pFtn)
4530         nId = eFTN;
4531     else if (p == pEdn)
4532         nId = eEDN;
4533     else if (p == pAnd)
4534         nId = eAND;
4535     else if (p->nSprmsLen > 0)
4536         nId = maSprmParser.GetSprmId(p->pMemPos);
4537     else
4538         nId = 0;        // Id = 0 for empty attributes
4539 
4540     return nId;
4541 }
4542 
4543 WW8PLCFMan::WW8PLCFMan(WW8ScannerBase* pBase, ManTypes nType, long nStartCp,
4544     bool bDoingDrawTextBox)
4545     : maSprmParser(pBase->pWw8Fib->GetFIBVersion()),
4546     mbDoingDrawTextBox(bDoingDrawTextBox)
4547 {
4548     pWwFib = pBase->pWw8Fib;
4549 
4550     nLastWhereIdxCp = 0;
4551     memset( aD, 0, sizeof( aD ) );
4552     nLineEnd = WW8_CP_MAX;
4553     nManType = nType;
4554     sal_uInt16 i;
4555 
4556     if( MAN_MAINTEXT == nType )
4557     {
4558         // Suchreihenfolge der Attribute
4559         nPLCF = MAN_ANZ_PLCF;
4560         pFld = &aD[0];
4561         pBkm = &aD[1];
4562         pEdn = &aD[2];
4563         pFtn = &aD[3];
4564         pAnd = &aD[4];
4565 
4566         pPcd = ( pBase->pPLCFx_PCD ) ? &aD[5] : 0;
4567         //pPcdA index == pPcd index + 1
4568         pPcdA = ( pBase->pPLCFx_PCDAttrs ) ? &aD[6] : 0;
4569 
4570         pChp = &aD[7];
4571         pPap = &aD[8];
4572         pSep = &aD[9];
4573 
4574         pSep->pPLCFx = pBase->pSepPLCF;
4575         pFtn->pPLCFx = pBase->pFtnPLCF;
4576         pEdn->pPLCFx = pBase->pEdnPLCF;
4577         pBkm->pPLCFx = pBase->pBook;
4578         pAnd->pPLCFx = pBase->pAndPLCF;
4579 
4580     }
4581     else
4582     {
4583         // Suchreihenfolge der Attribute
4584         nPLCF = 7;
4585         pFld = &aD[0];
4586         pBkm = ( pBase->pBook ) ? &aD[1] : 0;
4587 
4588         pPcd = ( pBase->pPLCFx_PCD ) ? &aD[2] : 0;
4589         //pPcdA index == pPcd index + 1
4590         pPcdA= ( pBase->pPLCFx_PCDAttrs ) ? &aD[3] : 0;
4591 
4592         pChp = &aD[4];
4593         pPap = &aD[5];
4594         pSep = &aD[6]; // Dummy
4595 
4596         pAnd = pFtn = pEdn = 0;     // unbenutzt bei SpezText
4597     }
4598 
4599     pChp->pPLCFx = pBase->pChpPLCF;
4600     pPap->pPLCFx = pBase->pPapPLCF;
4601     if( pPcd )
4602         pPcd->pPLCFx = pBase->pPLCFx_PCD;
4603     if( pPcdA )
4604         pPcdA->pPLCFx= pBase->pPLCFx_PCDAttrs;
4605     if( pBkm )
4606         pBkm->pPLCFx = pBase->pBook;
4607 
4608     pMagicTables = pBase->pMagicTables;
4609     pSubdocs = pBase->pSubdocs;
4610     pExtendedAtrds = pBase->pExtendedAtrds;
4611 
4612     switch( nType )                 // Feld-Initialisierung
4613     {
4614         case MAN_HDFT:
4615             pFld->pPLCFx = pBase->pFldHdFtPLCF;
4616             pFdoa = pBase->pHdFtFdoa;
4617             pTxbx = pBase->pHdFtTxbx;
4618             pTxbxBkd = pBase->pHdFtTxbxBkd;
4619             break;
4620         case MAN_FTN:
4621             pFld->pPLCFx = pBase->pFldFtnPLCF;
4622             pFdoa = pTxbx = pTxbxBkd = 0;
4623             break;
4624         case MAN_EDN:
4625             pFld->pPLCFx = pBase->pFldEdnPLCF;
4626             pFdoa = pTxbx = pTxbxBkd = 0;
4627             break;
4628         case MAN_AND:
4629             pFld->pPLCFx = pBase->pFldAndPLCF;
4630             pFdoa = pTxbx = pTxbxBkd = 0;
4631             break;
4632         case MAN_TXBX:
4633             pFld->pPLCFx = pBase->pFldTxbxPLCF;
4634             pTxbx = pBase->pMainTxbx;
4635             pTxbxBkd = pBase->pMainTxbxBkd;
4636             pFdoa = 0;
4637             break;
4638         case MAN_TXBX_HDFT:
4639             pFld->pPLCFx = pBase->pFldTxbxHdFtPLCF;
4640             pTxbx = pBase->pHdFtTxbx;
4641             pTxbxBkd = pBase->pHdFtTxbxBkd;
4642             pFdoa = 0;
4643             break;
4644         default:
4645             pFld->pPLCFx = pBase->pFldPLCF;
4646             pFdoa = pBase->pMainFdoa;
4647             pTxbx = pBase->pMainTxbx;
4648             pTxbxBkd = pBase->pMainTxbxBkd;
4649             break;
4650     }
4651 
4652     nCpO = pWwFib->GetBaseCp(nType);
4653 
4654     if( nStartCp || nCpO )
4655         SeekPos( nStartCp );    // PLCFe auf Text-StartPos einstellen
4656 
4657     // initialisieren der Member-Vars Low-Level
4658     GetChpPLCF()->ResetAttrStartEnd();
4659     GetPapPLCF()->ResetAttrStartEnd();
4660     for( i=0; i < nPLCF; i++)
4661     {
4662         WW8PLCFxDesc* p = &aD[i];
4663 
4664         /*
4665         ##516##,##517##
4666         For subdocuments we modify the cp of properties to be relative to
4667         the beginning of subdocuments, we should also do the same for
4668         piecetable changes, and piecetable properties, otherwise a piece
4669         change that happens in a subdocument is lost.
4670         */
4671         p->nCpOfs = ( p == pChp || p == pPap || p == pBkm || p == pPcd ||
4672             p == pPcdA ) ? nCpO : 0;
4673 
4674         p->nCp2OrIdx = 0;
4675         p->bFirstSprm = false;
4676         p->pIdStk = 0;
4677 
4678         if ((p == pChp) || (p == pPap))
4679             p->nStartPos = p->nEndPos = nStartCp;
4680         else
4681             p->nStartPos = p->nEndPos = WW8_CP_MAX;
4682     }
4683 
4684     // initialisieren der Member-Vars High-Level
4685     for( i=0; i<nPLCF; i++){
4686         WW8PLCFxDesc* p = &aD[i];
4687 
4688         if( !p->pPLCFx )
4689         {
4690             p->nStartPos = p->nEndPos = WW8_CP_MAX;
4691             continue;
4692         }
4693 
4694         if( p->pPLCFx->IsSprm() )
4695         {
4696             // Vorsicht: nEndPos muss bereits
4697             p->pIdStk = new std::stack<sal_uInt16>;
4698             if ((p == pChp) || (p == pPap))
4699             {
4700                 WW8_CP nTemp = p->nEndPos+p->nCpOfs;
4701                 p->pMemPos = 0;
4702                 p->nSprmsLen = 0;
4703                 p->nStartPos = nTemp;
4704                 if (!(*p->pPLCFx).SeekPos(p->nStartPos))
4705                     p->nEndPos = p->nStartPos = WW8_CP_MAX;
4706                 else
4707                     GetNewSprms( *p );
4708             }
4709             else
4710                 GetNewSprms( *p );      // bei allen PLCFen initialisiert sein
4711         }
4712         else if( p->pPLCFx )
4713             GetNewNoSprms( *p );
4714     }
4715 }
4716 
4717 WW8PLCFMan::~WW8PLCFMan()
4718 {
4719     for( sal_uInt16 i=0; i<nPLCF; i++)
4720         delete aD[i].pIdStk;
4721 }
4722 
4723 // 0. welche Attr.-Klasse,
4724 // 1. ob ein Attr.-Start ist,
4725 // 2. CP, wo ist naechste Attr.-Aenderung
4726 sal_uInt16 WW8PLCFMan::WhereIdx(bool* pbStart, long* pPos) const
4727 {
4728     ASSERT(nPLCF,"What the hell");
4729     long nNext = LONG_MAX;  // SuchReihenfolge:
4730     sal_uInt16 nNextIdx = nPLCF;// first ending found ( CHP, PAP, ( SEP ) ),
4731     bool bStart = true;     // dann Anfaenge finden ( ( SEP ), PAP, CHP )
4732     sal_uInt16 i;
4733     const WW8PLCFxDesc* pD;
4734     for (i=0; i < nPLCF; i++)
4735     {
4736         pD = &aD[i];
4737         if (pD != pPcdA)
4738         {
4739             if( (pD->nEndPos < nNext) && (pD->nStartPos == WW8_CP_MAX) )
4740             {
4741                 // sonst ist Anfang = Ende
4742                 nNext = pD->nEndPos;
4743                 nNextIdx = i;
4744                 bStart = false;
4745             }
4746         }
4747     }
4748     for (i=nPLCF; i > 0; i--)
4749     {
4750         pD = &aD[i-1];
4751         if (pD != pPcdA)
4752         {
4753             if( pD->nStartPos < nNext )
4754             {
4755                 nNext = pD->nStartPos;
4756                 nNextIdx = i-1;
4757                 bStart = true;
4758             }
4759         }
4760     }
4761     if( pPos )
4762         *pPos = nNext;
4763     if( pbStart )
4764         *pbStart = bStart;
4765     return nNextIdx;
4766 }
4767 
4768 // gibt die CP-Pos der naechsten Attribut-Aenderung zurueck
4769 WW8_CP WW8PLCFMan::Where() const
4770 {
4771     long l;
4772     WhereIdx(0, &l);
4773     return l;
4774 }
4775 
4776 void WW8PLCFMan::SeekPos( long nNewCp )
4777 {
4778     pChp->pPLCFx->SeekPos( nNewCp + nCpO ); // Attribute neu
4779     pPap->pPLCFx->SeekPos( nNewCp + nCpO ); // aufsetzen
4780     pFld->pPLCFx->SeekPos( nNewCp );
4781     if( pPcd )
4782         pPcd->pPLCFx->SeekPos( nNewCp + nCpO );
4783     if( pBkm )
4784         pBkm->pPLCFx->SeekPos( nNewCp + nCpO );
4785 }
4786 
4787 void WW8PLCFMan::SaveAllPLCFx( WW8PLCFxSaveAll& rSave ) const
4788 {
4789     sal_uInt16 i, n=0;
4790     if( pPcd )
4791         pPcd->Save(  rSave.aS[n++] );
4792     if( pPcdA )
4793         pPcdA->Save( rSave.aS[n++] );
4794 
4795     for(i=0; i<nPLCF; ++i)
4796         if( pPcd != &aD[i] && pPcdA != &aD[i] )
4797             aD[i].Save( rSave.aS[n++] );
4798 }
4799 
4800 void WW8PLCFMan::RestoreAllPLCFx( const WW8PLCFxSaveAll& rSave )
4801 {
4802     sal_uInt16 i, n=0;
4803     if( pPcd )
4804         pPcd->Restore(  rSave.aS[n++] );
4805     if( pPcdA )
4806         pPcdA->Restore( rSave.aS[n++] );
4807 
4808     for(i=0; i<nPLCF; ++i)
4809         if( pPcd != &aD[i] && pPcdA != &aD[i] )
4810             aD[i].Restore( rSave.aS[n++] );
4811 }
4812 
4813 void WW8PLCFMan::GetSprmStart( short nIdx, WW8PLCFManResult* pRes ) const
4814 {
4815     memset( pRes, 0, sizeof( WW8PLCFManResult ) );
4816 
4817     // Pruefen !!!
4818 
4819     pRes->nMemLen = 0;
4820 
4821     const WW8PLCFxDesc* p = &aD[nIdx];
4822 
4823     // first Sprm in a Group
4824     if( p->bFirstSprm )
4825     {
4826         if( p == pPap )
4827             pRes->nFlags |= MAN_MASK_NEW_PAP;
4828         else if( p == pSep )
4829             pRes->nFlags |= MAN_MASK_NEW_SEP;
4830     }
4831     pRes->pMemPos = p->pMemPos;
4832     pRes->nSprmId = GetId(p);
4833     pRes->nCp2OrIdx = p->nCp2OrIdx;
4834     if ((p == pFtn) || (p == pEdn) || (p == pAnd))
4835         pRes->nMemLen = p->nSprmsLen;
4836     else if (p->nSprmsLen)  //Normal
4837     {
4838         // Length of actual sprm
4839         pRes->nMemLen = maSprmParser.GetSprmSize(pRes->nSprmId, pRes->pMemPos);
4840     }
4841 }
4842 
4843 void WW8PLCFMan::GetSprmEnd( short nIdx, WW8PLCFManResult* pRes ) const
4844 {
4845     memset( pRes, 0, sizeof( WW8PLCFManResult ) );
4846 
4847     const WW8PLCFxDesc* p = &aD[nIdx];
4848 
4849     if (!(p->pIdStk->empty()))
4850         pRes->nSprmId = p->pIdStk->top();       // get end position
4851     else
4852     {
4853         ASSERT( !this, "No Id on the Stack" );
4854         pRes->nSprmId = 0;
4855     }
4856 }
4857 
4858 void WW8PLCFMan::GetNoSprmStart( short nIdx, WW8PLCFManResult* pRes ) const
4859 {
4860     const WW8PLCFxDesc* p = &aD[nIdx];
4861 
4862     pRes->nCpPos = p->nStartPos;
4863     pRes->nMemLen = p->nSprmsLen;
4864     pRes->nCp2OrIdx = p->nCp2OrIdx;
4865 
4866     if( p == pFld )
4867         pRes->nSprmId = eFLD;
4868     else if( p == pFtn )
4869         pRes->nSprmId = eFTN;
4870     else if( p == pEdn )
4871         pRes->nSprmId = eEDN;
4872     else if( p == pBkm )
4873         pRes->nSprmId = eBKN;
4874     else if( p == pAnd )
4875         pRes->nSprmId = eAND;
4876     else if( p == pPcd )
4877     {
4878         //We slave the piece table attributes to the piece table, the piece
4879         //table attribute iterator contains the sprms for this piece.
4880         GetSprmStart( nIdx+1, pRes );
4881     }
4882     else
4883         pRes->nSprmId = 0;          // default: not found
4884 }
4885 
4886 void WW8PLCFMan::GetNoSprmEnd( short nIdx, WW8PLCFManResult* pRes ) const
4887 {
4888     pRes->nMemLen = -1;     // Ende-Kennzeichen
4889 
4890     if( &aD[nIdx] == pBkm )
4891         pRes->nSprmId = eBKN;
4892     else if( &aD[nIdx] == pPcd )
4893     {
4894         //We slave the piece table attributes to the piece table, the piece
4895         //table attribute iterator contains the sprms for this piece.
4896         GetSprmEnd( nIdx+1, pRes );
4897     }
4898     else
4899         pRes->nSprmId = 0;
4900 }
4901 
4902 bool WW8PLCFMan::TransferOpenSprms(std::stack<sal_uInt16> &rStack)
4903 {
4904     for (int i = 0; i < nPLCF; ++i)
4905     {
4906         WW8PLCFxDesc* p = &aD[i];
4907         if (!p || !p->pIdStk)
4908             continue;
4909         while (!p->pIdStk->empty())
4910         {
4911             rStack.push(p->pIdStk->top());
4912             p->pIdStk->pop();
4913         }
4914     }
4915     return rStack.empty();
4916 }
4917 
4918 void WW8PLCFMan::AdvSprm(short nIdx, bool bStart)
4919 {
4920     WW8PLCFxDesc* p = &aD[nIdx];    // Sprm-Klasse(!) ermitteln
4921 
4922     p->bFirstSprm = false;
4923     if( bStart )
4924     {
4925         sal_uInt16 nLastId = GetId(p);
4926         p->pIdStk->push(nLastId);   // merke Id fuer Attribut-Ende
4927 
4928         if( p->nSprmsLen )
4929         {   /*
4930                 Pruefe, ob noch Sprm(s) abzuarbeiten sind
4931             */
4932             if( p->pMemPos )
4933             {
4934                 // Length of last sprm
4935                 sal_uInt16 nSprmL = maSprmParser.GetSprmSize(nLastId, p->pMemPos);
4936 
4937                 // Gesamtlaenge Sprms um SprmLaenge verringern
4938                 p->nSprmsLen -= nSprmL;
4939 
4940                 // Pos des evtl. naechsten Sprm
4941                 if (p->nSprmsLen < maSprmParser.MinSprmLen())
4942                 {
4943                     // sicherheitshalber auf Null setzen, da Enden folgen!
4944                     p->pMemPos = 0;
4945                     p->nSprmsLen = 0;
4946                 }
4947                 else
4948                     p->pMemPos += nSprmL;
4949             }
4950             else
4951                 p->nSprmsLen = 0;
4952         }
4953         if (p->nSprmsLen < maSprmParser.MinSprmLen())
4954             p->nStartPos = WW8_CP_MAX;    // es folgen Enden
4955     }
4956     else
4957     {
4958         if (!(p->pIdStk->empty()))
4959             p->pIdStk->pop();
4960         if (p->pIdStk->empty())
4961         {
4962             if ( (p == pChp) || (p == pPap) )
4963             {
4964                 p->pMemPos = 0;
4965                 p->nSprmsLen = 0;
4966                 p->nStartPos = p->nOrigEndPos+p->nCpOfs;
4967 
4968                 /*
4969                 #93702#
4970                 On failed seek we have run out of sprms, probably.  But if its
4971                 a fastsaved file (has pPcd) then we may be just in a sprm free
4972                 gap between pieces that have them, so set dirty flag in sprm
4973                 finder to consider than.
4974                 */
4975                 if (!(*p->pPLCFx).SeekPos(p->nStartPos))
4976                 {
4977                     p->nEndPos = WW8_CP_MAX;
4978                     p->pPLCFx->SetDirty(true);
4979                 }
4980                 if (!p->pPLCFx->GetDirty() || pPcd)
4981                     GetNewSprms( *p );
4982                 p->pPLCFx->SetDirty(false);
4983 
4984                 /*
4985                 #i2325#
4986                 To get the character and paragraph properties you first get
4987                 the pap and chp and then apply the fastsaved pPcd properties
4988                 to the range. If a pap or chp starts inside the pPcd range
4989                 then we must bring the current pPcd range to a halt so as to
4990                 end those sprms, then the pap/chp will be processed, and then
4991                 we must force a restart of the pPcd on that pap/chp starting
4992                 boundary. Doing that effectively means that the pPcd sprms will
4993                 be applied to the new range. Not doing it means that the pPcd
4994                 sprms will only be applied to the first pap/chp set of
4995                 properties contained in the pap/chp range.
4996 
4997                 So we bring the pPcd to a halt on this location here, by
4998                 settings its end to the current start, then store the starting
4999                 position of the current range to clipstart. The pPcd sprms
5000                 will end as normal (albeit earlier than originally expected),
5001                 and the existance of a clipstart will force the pPcd iterater
5002                 to reread the current set of sprms instead of advancing to its
5003                 next set. Then the clipstart will be set as the starting
5004                 position which will force them to be applied directly after
5005                 the pap and chps.
5006                 */
5007                 if (pPcd && ((p->nStartPos > pPcd->nStartPos) ||
5008                     (pPcd->nStartPos == WW8_CP_MAX)) &&
5009                     (pPcd->nEndPos != p->nStartPos))
5010                 {
5011                     pPcd->nEndPos = p->nStartPos;
5012                     ((WW8PLCFx_PCD *)(pPcd->pPLCFx))->SetClipStart(
5013                         p->nStartPos);
5014                 }
5015 
5016             }
5017             else
5018             {
5019                 (*p->pPLCFx)++;     // next Group of Sprms
5020                 p->pMemPos = 0;     // !!!
5021                 p->nSprmsLen = 0;
5022                 GetNewSprms( *p );
5023             }
5024             ASSERT( p->nStartPos <= p->nEndPos, "Attribut ueber Kreuz" );
5025         }
5026     }
5027 }
5028 
5029 void WW8PLCFMan::AdvNoSprm(short nIdx, bool bStart)
5030 {
5031     /*
5032     For the case of a piece table we slave the piece table attribute iterator
5033     to the piece table and access it through that only. They are two seperate
5034     structures, but act together as one logical one. The attributes only go
5035     to the next entry when the piece changes
5036     */
5037     WW8PLCFxDesc* p = &aD[nIdx];
5038 
5039     if( p == pPcd )
5040     {
5041         AdvSprm(nIdx+1,bStart);
5042         if( bStart )
5043             p->nStartPos = aD[nIdx+1].nStartPos;
5044         else
5045         {
5046             if (aD[nIdx+1].pIdStk->empty())
5047             {
5048                 WW8PLCFx_PCD *pTemp = (WW8PLCFx_PCD*)(pPcd->pPLCFx);
5049                 /*
5050                 #i2325#
5051                 As per normal, go on to the next set of properties, i.e. we
5052                 have traversed over to the next piece.  With a clipstart set
5053                 we are being told to reread the current piece sprms so as to
5054                 reapply them to a new chp or pap range.
5055                 */
5056                 if (pTemp->GetClipStart() == -1)
5057                     (*p->pPLCFx)++;
5058                 p->pMemPos = 0;
5059                 p->nSprmsLen = 0;
5060                 GetNewSprms( aD[nIdx+1] );
5061                 GetNewNoSprms( *p );
5062                 if (pTemp->GetClipStart() != -1)
5063                 {
5064                     /*
5065                     #i2325#, now we will force our starting position to the
5066                     clipping start so as to force the application of these
5067                     sprms after the current pap/chp sprms so as to apply the
5068                     fastsave sprms to the current range.
5069                     */
5070                     p->nStartPos = pTemp->GetClipStart();
5071                     pTemp->SetClipStart(-1);
5072                 }
5073             }
5074         }
5075     }
5076     else
5077     {                                  // NoSprm ohne Ende
5078         (*p->pPLCFx)++;
5079         p->pMemPos = 0;                     // MemPos ungueltig
5080         p->nSprmsLen = 0;
5081         GetNewNoSprms( *p );
5082     }
5083 }
5084 
5085 WW8PLCFMan& WW8PLCFMan::operator ++(int)
5086 {
5087     bool bStart;
5088     sal_uInt16 nIdx = WhereIdx(&bStart);
5089     if (nIdx < nPLCF)
5090     {
5091         WW8PLCFxDesc* p = &aD[nIdx];
5092 
5093         p->bFirstSprm = true;                       // Default
5094 
5095         if( p->pPLCFx->IsSprm() )
5096             AdvSprm( nIdx, bStart );
5097         else                                        // NoSprm
5098             AdvNoSprm( nIdx, bStart );
5099     }
5100     return *this;
5101 }
5102 
5103 // Rueckgabe true fuer Anfang eines Attributes oder Fehler,
5104 //           false fuer Ende d. Attr
5105 // Restliche Rueckgabewerte werden in der vom Aufrufer zu stellenden Struktur
5106 // WW8PclxManResults geliefert.
5107 bool WW8PLCFMan::Get(WW8PLCFManResult* pRes) const
5108 {
5109     memset( pRes, 0, sizeof( WW8PLCFManResult ) );
5110     bool bStart;
5111     sal_uInt16 nIdx = WhereIdx(&bStart);
5112 
5113     if( nIdx >= nPLCF )
5114     {
5115         ASSERT( !this, "Position not found" );
5116         return true;
5117     }
5118 
5119     if( aD[nIdx].pPLCFx->IsSprm() )
5120     {
5121         if( bStart )
5122         {
5123             GetSprmStart( nIdx, pRes );
5124             return true;
5125         }
5126         else
5127         {
5128             GetSprmEnd( nIdx, pRes );
5129             return false;
5130         }
5131     }
5132     else
5133     {
5134         if( bStart )
5135         {
5136             GetNoSprmStart( nIdx, pRes );
5137             return true;
5138         }
5139         else
5140         {
5141             GetNoSprmEnd( nIdx, pRes );
5142             return false;
5143         }
5144     }
5145 }
5146 
5147 sal_uInt16 WW8PLCFMan::GetColl() const
5148 {
5149     if( pPap->pPLCFx )
5150         return  pPap->pPLCFx->GetIstd();
5151     else
5152     {
5153         ASSERT( !this, "GetColl ohne PLCF_Pap" );
5154         return 0;
5155     }
5156 }
5157 
5158 WW8PLCFx_FLD* WW8PLCFMan::GetFld() const
5159 {
5160     return (WW8PLCFx_FLD*)pFld->pPLCFx;
5161 }
5162 
5163 const sal_uInt8* WW8PLCFMan::HasParaSprm( sal_uInt16 nId ) const
5164 {
5165     return ((WW8PLCFx_Cp_FKP*)pPap->pPLCFx)->HasSprm( nId );
5166 }
5167 
5168 const sal_uInt8* WW8PLCFMan::HasCharSprm( sal_uInt16 nId ) const
5169 {
5170     return ((WW8PLCFx_Cp_FKP*)pChp->pPLCFx)->HasSprm( nId );
5171 }
5172 
5173 bool WW8PLCFMan::HasCharSprm(sal_uInt16 nId,
5174     std::vector<const sal_uInt8 *> &rResult) const
5175 {
5176     return ((WW8PLCFx_Cp_FKP*)pChp->pPLCFx)->HasSprm(nId, rResult);
5177 }
5178 
5179 #endif // !DUMP
5180 
5181 void WW8PLCFx::Save( WW8PLCFxSave1& rSave ) const
5182 {
5183     rSave.nPLCFxPos    = GetIdx();
5184     rSave.nPLCFxPos2   = GetIdx2();
5185     rSave.nPLCFxMemOfs = 0;
5186     rSave.nStartFC     = GetStartFc();
5187 }
5188 
5189 void WW8PLCFx::Restore( const WW8PLCFxSave1& rSave )
5190 {
5191     SetIdx(     rSave.nPLCFxPos  );
5192     SetIdx2(    rSave.nPLCFxPos2 );
5193     SetStartFc( rSave.nStartFC   );
5194 }
5195 
5196 sal_uLong WW8PLCFx_Cp_FKP::GetIdx2() const
5197 {
5198     return GetPCDIdx();
5199 }
5200 
5201 void WW8PLCFx_Cp_FKP::SetIdx2( sal_uLong nIdx )
5202 {
5203     SetPCDIdx( nIdx );
5204 }
5205 
5206 void WW8PLCFx_Cp_FKP::Save( WW8PLCFxSave1& rSave ) const
5207 {
5208     WW8PLCFx::Save( rSave );
5209 
5210     rSave.nAttrStart = nAttrStart;
5211     rSave.nAttrEnd   = nAttrEnd;
5212     rSave.bLineEnd   = bLineEnd;
5213 }
5214 
5215 void WW8PLCFx_Cp_FKP::Restore( const WW8PLCFxSave1& rSave )
5216 {
5217     WW8PLCFx::Restore( rSave );
5218 
5219     nAttrStart = rSave.nAttrStart;
5220     nAttrEnd   = rSave.nAttrEnd;
5221     bLineEnd   = rSave.bLineEnd;
5222 }
5223 
5224 void WW8PLCFxDesc::Save( WW8PLCFxSave1& rSave ) const
5225 {
5226     if( pPLCFx )
5227     {
5228         pPLCFx->Save( rSave );
5229         if( pPLCFx->IsSprm() )
5230         {
5231             WW8PLCFxDesc aD;
5232             aD.nStartPos = nOrigStartPos+nCpOfs;
5233             aD.nCpOfs = rSave.nCpOfs = nCpOfs;
5234             if (!(pPLCFx->SeekPos(aD.nStartPos)))
5235             {
5236                 aD.nEndPos = WW8_CP_MAX;
5237                 pPLCFx->SetDirty(true);
5238             }
5239             pPLCFx->GetSprms(&aD);
5240             pPLCFx->SetDirty(false);
5241             aD.ReduceByOffset();
5242             rSave.nStartCp = aD.nStartPos;
5243             rSave.nPLCFxMemOfs = nOrigSprmsLen - nSprmsLen;
5244         }
5245     }
5246 }
5247 
5248 void WW8PLCFxDesc::Restore( const WW8PLCFxSave1& rSave )
5249 {
5250     if( pPLCFx )
5251     {
5252         pPLCFx->Restore( rSave );
5253         if( pPLCFx->IsSprm() )
5254         {
5255             WW8PLCFxDesc aD;
5256             aD.nStartPos = rSave.nStartCp+rSave.nCpOfs;
5257             nCpOfs = aD.nCpOfs = rSave.nCpOfs;
5258             if (!(pPLCFx->SeekPos(aD.nStartPos)))
5259             {
5260                 aD.nEndPos = WW8_CP_MAX;
5261                 pPLCFx->SetDirty(true);
5262             }
5263             pPLCFx->GetSprms(&aD);
5264             pPLCFx->SetDirty(false);
5265             aD.ReduceByOffset();
5266             pMemPos = aD.pMemPos + rSave.nPLCFxMemOfs;
5267         }
5268     }
5269 }
5270 
5271 //-----------------------------------------
5272 
5273 namespace
5274 {
5275     sal_uInt32 Readcb(SvStream& rSt, ww::WordVersion eVer)
5276     {
5277         if (eVer <= ww::eWW2)
5278         {
5279             sal_uInt16 nShort;
5280             rSt >> nShort;
5281             return nShort;
5282         }
5283         else
5284         {
5285             sal_uInt32 nLong;
5286             rSt >> nLong;
5287             return nLong;
5288         }
5289     }
5290 }
5291 
5292 WW8_CP WW8Fib::GetBaseCp(ManTypes nType) const
5293 {
5294     WW8_CP nOffset = 0;
5295 
5296     switch( nType )
5297     {
5298         default:
5299         case MAN_MAINTEXT:
5300             break;
5301         case MAN_FTN:
5302             nOffset = ccpText;
5303             break;
5304         case MAN_HDFT:
5305             nOffset = ccpText + ccpFtn;
5306             break;
5307 /*
5308  * A subdocument of this kind probably exists in some defunct version
5309  * of MSWord, but now ccpMcr is always 0
5310  */
5311 #if 0
5312         case MAN_MACRO:
5313             nOffset = ccpText + ccpFtn + ccpHdr;
5314             break;
5315 #endif
5316         case MAN_AND:
5317             nOffset = ccpText + ccpFtn + ccpHdr + ccpMcr;
5318             break;
5319         case MAN_EDN:
5320             nOffset = ccpText + ccpFtn + ccpHdr + ccpMcr + ccpAtn;
5321             break;
5322         case MAN_TXBX:
5323             nOffset = ccpText + ccpFtn + ccpHdr + ccpMcr + ccpAtn + ccpEdn;
5324             break;
5325         case MAN_TXBX_HDFT:
5326             nOffset = ccpText + ccpFtn + ccpHdr + ccpMcr + ccpAtn + ccpEdn +
5327                 ccpTxbx;
5328             break;
5329     }
5330     return nOffset;
5331 }
5332 
5333 ww::WordVersion WW8Fib::GetFIBVersion() const
5334 {
5335     ww::WordVersion eVer = ww::eWW8;
5336     if (wIdent == 0xa5db)
5337         eVer = ww::eWW2;
5338     else
5339     {
5340         switch (nVersion)
5341         {
5342             case 6:
5343                 eVer = ww::eWW6;
5344                 break;
5345             case 7:
5346                 eVer = ww::eWW7;
5347                 break;
5348             case 8:
5349                 eVer = ww::eWW8;
5350                 break;
5351         }
5352     }
5353     return eVer;
5354 }
5355 
5356 WW8Fib::WW8Fib(SvStream& rSt, sal_uInt8 nWantedVersion, sal_uInt32 nOffset)
5357     : nFibError( 0 )
5358 {
5359     memset(this, 0, sizeof(*this));
5360     sal_uInt8 aBits1;
5361     sal_uInt8 aBits2;
5362     sal_uInt8 aVer8Bits1;    // nur ab WinWord 8 benutzt
5363     rSt.Seek( nOffset );
5364     /*
5365         Wunsch-Nr vermerken, File-Versionsnummer ermitteln
5366         und gegen Wunsch-Nr. checken !
5367     */
5368     nVersion = nWantedVersion;
5369     rSt >> wIdent;
5370     rSt >> nFib;
5371     rSt >> nProduct;
5372     if( 0 != rSt.GetError() )
5373     {
5374         sal_Int16 nFibMin;
5375         sal_Int16 nFibMax;
5376         // note: 6 stands for "6 OR 7",  7 stands for "ONLY 7"
5377         switch( nVersion )
5378         {
5379             case 6:
5380                 nFibMin = 0x0065;   // von 101 WinWord 6.0
5381                                     //     102    "
5382                                     // und 103 WinWord 6.0 fuer Macintosh
5383                                     //     104    "
5384                 nFibMax = 0x0069;   // bis 105 WinWord 95
5385                 break;
5386             case 7:
5387                 nFibMin = 0x0069;   // von 105 WinWord 95
5388                 nFibMax = 0x0069;   // bis 105 WinWord 95
5389                 break;
5390             case 8:
5391                 nFibMin = 0x006A;   // von 106 WinWord 97
5392                 nFibMax = 0x00c1;   // bis 193 WinWord 97 (?)
5393                 break;
5394             default:
5395                 nFibMin = 0;            // Programm-Fehler!
5396                 nFibMax = 0;
5397                 nFib    = 1;
5398                 ASSERT( !this, "Es wurde vergessen, nVersion zu kodieren!" );
5399                 break;
5400         }
5401         if ( (nFib < nFibMin) || (nFib > nFibMax) )
5402         {
5403             nFibError = ERR_SWG_READ_ERROR; // Error melden
5404             return;                         // und hopp raus!
5405         }
5406     }
5407 
5408     ww::WordVersion eVer = GetFIBVersion();
5409 
5410     // Hilfs-Varis fuer Ver67:
5411     sal_Int16 pnChpFirst_Ver67=0;
5412     sal_Int16 pnPapFirst_Ver67=0;
5413     sal_Int16 cpnBteChp_Ver67=0;
5414     sal_Int16 cpnBtePap_Ver67=0;
5415 
5416     // und auf gehts: FIB einlesen
5417     rSt >> lid;
5418     rSt >> pnNext;
5419     rSt >> aBits1;
5420     rSt >> aBits2;
5421     rSt >> nFibBack;
5422     rSt >> nHash;
5423     rSt >> nKey;
5424     rSt >> envr;
5425     rSt >> aVer8Bits1;      // unter Ver67  nur leeres Reservefeld
5426                             // Inhalt von aVer8Bits1
5427                             //
5428                             // sal_uInt8 fMac              :1;
5429                             // sal_uInt8 fEmptySpecial     :1;
5430                             // sal_uInt8 fLoadOverridePage :1;
5431                             // sal_uInt8 fFuturesavedUndo  :1;
5432                             // sal_uInt8 fWord97Saved      :1;
5433                             // sal_uInt8 :3;
5434     rSt >> chse;
5435     rSt >> chseTables;
5436     rSt >> fcMin;
5437     rSt >> fcMac;
5438 
5439 // Einschub fuer WW8 *****************************************************
5440     if (IsEightPlus(eVer))
5441     {
5442         rSt >> csw;
5443 
5444         // Marke: "rgsw"  Beginning of the array of shorts
5445         rSt >> wMagicCreated;
5446         rSt >> wMagicRevised;
5447         rSt >> wMagicCreatedPrivate;
5448         rSt >> wMagicRevisedPrivate;
5449         rSt.SeekRel( 9 * sizeof( sal_Int16 ) );
5450 
5451         /*
5452         // dies sind die 9 unused Felder:
5453         && (bVer67 || WW8ReadINT16(  rSt, pnFbpChpFirst_W6          ))  // 1
5454         && (bVer67 || WW8ReadINT16(  rSt, pnChpFirst_W6                 ))  // 2
5455         && (bVer67 || WW8ReadINT16(  rSt, cpnBteChp_W6                  ))  // 3
5456         && (bVer67 || WW8ReadINT16(  rSt, pnFbpPapFirst_W6          ))  // 4
5457         && (bVer67 || WW8ReadINT16(  rSt, pnPapFirst_W6                 ))  // 5
5458         && (bVer67 || WW8ReadINT16(  rSt, cpnBtePap_W6                  ))  // 6
5459         && (bVer67 || WW8ReadINT16(  rSt, pnFbpLvcFirst_W6          ))  // 7
5460         && (bVer67 || WW8ReadINT16(  rSt, pnLvcFirst_W6                 ))  // 8
5461         && (bVer67 || WW8ReadINT16(  rSt, cpnBteLvc_W6                  ))  // 9
5462         */
5463         rSt >> lidFE;
5464         rSt >> clw;
5465     }
5466 
5467 // Ende des Einschubs fuer WW8 *******************************************
5468 
5469         // Marke: "rglw"  Beginning of the array of longs
5470     rSt >> cbMac;
5471 
5472         // 2 Longs uebergehen, da unwichtiger Quatsch
5473     rSt.SeekRel( 2 * sizeof( sal_Int32) );
5474 
5475         // weitere 2 Longs nur bei Ver67 ueberspringen
5476     if (IsSevenMinus(eVer))
5477         rSt.SeekRel( 2 * sizeof( sal_Int32) );
5478 
5479     rSt >> ccpText;
5480     rSt >> ccpFtn;
5481     rSt >> ccpHdr;
5482     rSt >> ccpMcr;
5483     rSt >> ccpAtn;
5484     rSt >> ccpEdn;
5485     rSt >> ccpTxbx;
5486     rSt >> ccpHdrTxbx;
5487 
5488         // weiteres Long nur bei Ver67 ueberspringen
5489     if (IsSevenMinus(eVer))
5490         rSt.SeekRel( 1 * sizeof( sal_Int32) );
5491     else
5492     {
5493 // Einschub fuer WW8 *****************************************************
5494         rSt >> pnFbpChpFirst;
5495         rSt >> pnChpFirst;
5496         rSt >> cpnBteChp;
5497         rSt >> pnFbpPapFirst;
5498         rSt >> pnPapFirst;
5499         rSt >> cpnBtePap;
5500         rSt >> pnFbpLvcFirst;
5501         rSt >> pnLvcFirst;
5502         rSt >> cpnBteLvc;
5503         rSt >> fcIslandFirst;
5504         rSt >> fcIslandLim;
5505         rSt >> cfclcb;
5506     }
5507 
5508 // Ende des Einschubs fuer WW8 *******************************************
5509 
5510     // Marke: "rgfclcb" Beginning of array of FC/LCB pairs.
5511     rSt >> fcStshfOrig;
5512     lcbStshfOrig = Readcb(rSt, eVer);
5513     rSt >> fcStshf;
5514     lcbStshf = Readcb(rSt, eVer);
5515     rSt >> fcPlcffndRef;
5516     lcbPlcffndRef = Readcb(rSt, eVer);
5517     rSt >> fcPlcffndTxt;
5518     lcbPlcffndTxt = Readcb(rSt, eVer);
5519     rSt >> fcPlcfandRef;
5520     lcbPlcfandRef = Readcb(rSt, eVer);
5521     rSt >> fcPlcfandTxt;
5522     lcbPlcfandTxt = Readcb(rSt, eVer);
5523     rSt >> fcPlcfsed;
5524     lcbPlcfsed = Readcb(rSt, eVer);
5525     rSt >> fcPlcfpad;
5526     lcbPlcfpad = Readcb(rSt, eVer);
5527     rSt >> fcPlcfphe;
5528     lcbPlcfphe = Readcb(rSt, eVer);
5529     rSt >> fcSttbfglsy;
5530     lcbSttbfglsy = Readcb(rSt, eVer);
5531     rSt >> fcPlcfglsy;
5532     lcbPlcfglsy = Readcb(rSt, eVer);
5533     rSt >> fcPlcfhdd;
5534     lcbPlcfhdd = Readcb(rSt, eVer);
5535     rSt >> fcPlcfbteChpx;
5536     lcbPlcfbteChpx = Readcb(rSt, eVer);
5537     rSt >> fcPlcfbtePapx;
5538     lcbPlcfbtePapx = Readcb(rSt, eVer);
5539     rSt >> fcPlcfsea;
5540     lcbPlcfsea = Readcb(rSt, eVer);
5541     rSt >> fcSttbfffn;
5542     lcbSttbfffn = Readcb(rSt, eVer);
5543     rSt >> fcPlcffldMom;
5544     lcbPlcffldMom = Readcb(rSt, eVer);
5545     rSt >> fcPlcffldHdr;
5546     lcbPlcffldHdr = Readcb(rSt, eVer);
5547     rSt >> fcPlcffldFtn;
5548     lcbPlcffldFtn = Readcb(rSt, eVer);
5549     rSt >> fcPlcffldAtn;
5550     lcbPlcffldAtn = Readcb(rSt, eVer);
5551     rSt >> fcPlcffldMcr;
5552     lcbPlcffldMcr = Readcb(rSt, eVer);
5553     rSt >> fcSttbfbkmk;
5554     lcbSttbfbkmk = Readcb(rSt, eVer);
5555     rSt >> fcPlcfbkf;
5556     lcbPlcfbkf = Readcb(rSt, eVer);
5557     rSt >> fcPlcfbkl;
5558     lcbPlcfbkl = Readcb(rSt, eVer);
5559     rSt >> fcCmds;
5560     lcbCmds = Readcb(rSt, eVer);
5561     rSt >> fcPlcfmcr;
5562     lcbPlcfmcr = Readcb(rSt, eVer);
5563     rSt >> fcSttbfmcr;
5564     lcbSttbfmcr = Readcb(rSt, eVer);
5565     rSt >> fcPrDrvr;
5566     lcbPrDrvr = Readcb(rSt, eVer);
5567     rSt >> fcPrEnvPort;
5568     lcbPrEnvPort = Readcb(rSt, eVer);
5569     rSt >> fcPrEnvLand;
5570     lcbPrEnvLand = Readcb(rSt, eVer);
5571     rSt >> fcWss;
5572     lcbWss = Readcb(rSt, eVer);
5573     rSt >> fcDop;
5574     lcbDop = Readcb(rSt, eVer);
5575     rSt >> fcSttbfAssoc;
5576     lcbSttbfAssoc = Readcb(rSt, eVer);
5577     rSt >> fcClx;
5578     lcbClx = Readcb(rSt, eVer);
5579     rSt >> fcPlcfpgdFtn;
5580     lcbPlcfpgdFtn = Readcb(rSt, eVer);
5581     rSt >> fcAutosaveSource;
5582     lcbAutosaveSource = Readcb(rSt, eVer);
5583     rSt >> fcGrpStAtnOwners;
5584     lcbGrpStAtnOwners = Readcb(rSt, eVer);
5585     rSt >> fcSttbfAtnbkmk;
5586     lcbSttbfAtnbkmk = Readcb(rSt, eVer);
5587 
5588     // weiteres short nur bei Ver67 ueberspringen
5589     if (IsSevenMinus(eVer))
5590     {
5591         rSt.SeekRel( 1*sizeof( sal_Int16) );
5592 
5593         // folgende 4 Shorts existieren nur bei Ver67;
5594         rSt >> pnChpFirst_Ver67;
5595         rSt >> pnPapFirst_Ver67;
5596         rSt >> cpnBteChp_Ver67;
5597         rSt >> cpnBtePap_Ver67;
5598     }
5599 
5600     if (eVer > ww::eWW2)
5601     {
5602         rSt >> fcPlcfdoaMom;
5603         rSt >> lcbPlcfdoaMom;
5604         rSt >> fcPlcfdoaHdr;
5605         rSt >> lcbPlcfdoaHdr;
5606         rSt >> fcPlcfspaMom;
5607         rSt >> lcbPlcfspaMom;
5608         rSt >> fcPlcfspaHdr;
5609         rSt >> lcbPlcfspaHdr;
5610 
5611         rSt >> fcPlcfAtnbkf;
5612         rSt >> lcbPlcfAtnbkf;
5613         rSt >> fcPlcfAtnbkl;
5614         rSt >> lcbPlcfAtnbkl;
5615         rSt >> fcPms;
5616         rSt >> lcbPMS;
5617         rSt >> fcFormFldSttbf;
5618         rSt >> lcbFormFldSttbf;
5619         rSt >> fcPlcfendRef;
5620         rSt >> lcbPlcfendRef;
5621         rSt >> fcPlcfendTxt;
5622         rSt >> lcbPlcfendTxt;
5623         rSt >> fcPlcffldEdn;
5624         rSt >> lcbPlcffldEdn;
5625         rSt >> fcPlcfpgdEdn;
5626         rSt >> lcbPlcfpgdEdn;
5627         rSt >> fcDggInfo;
5628         rSt >> lcbDggInfo;
5629         rSt >> fcSttbfRMark;
5630         rSt >> lcbSttbfRMark;
5631         rSt >> fcSttbfCaption;
5632         rSt >> lcbSttbfCaption;
5633         rSt >> fcSttbAutoCaption;
5634         rSt >> lcbSttbAutoCaption;
5635         rSt >> fcPlcfwkb;
5636         rSt >> lcbPlcfwkb;
5637         rSt >> fcPlcfspl;
5638         rSt >> lcbPlcfspl;
5639         rSt >> fcPlcftxbxTxt;
5640         rSt >> lcbPlcftxbxTxt;
5641         rSt >> fcPlcffldTxbx;
5642         rSt >> lcbPlcffldTxbx;
5643         rSt >> fcPlcfHdrtxbxTxt;
5644         rSt >> lcbPlcfHdrtxbxTxt;
5645         rSt >> fcPlcffldHdrTxbx;
5646         rSt >> lcbPlcffldHdrTxbx;
5647         rSt >> fcStwUser;
5648         rSt >> lcbStwUser;
5649         rSt >> fcSttbttmbd;
5650         rSt >> lcbSttbttmbd;
5651     }
5652 
5653     if( 0 == rSt.GetError() )
5654     {
5655         // Bit-Flags setzen
5656         fDot        =   aBits1 & 0x01       ;
5657         fGlsy       = ( aBits1 & 0x02 ) >> 1;
5658         fComplex    = ( aBits1 & 0x04 ) >> 2;
5659         fHasPic     = ( aBits1 & 0x08 ) >> 3;
5660         cQuickSaves = ( aBits1 & 0xf0 ) >> 4;
5661         fEncrypted  =   aBits2 & 0x01       ;
5662         fWhichTblStm= ( aBits2 & 0x02 ) >> 1;
5663         fReadOnlyRecommended = (aBits2 & 0x4) >> 2;
5664         fWriteReservation = (aBits2 & 0x8) >> 3;
5665         fExtChar    = ( aBits2 & 0x10 ) >> 4;
5666         // dummy    = ( aBits2 & 0x20 ) >> 5;
5667         fFarEast    = ( aBits2 & 0x40 ) >> 6; // #i90932#
5668         // dummy    = ( aBits2 & 0x80 ) >> 7;
5669 
5670         /*
5671             ggfs. Ziel-Varaiblen, aus xxx_Ver67 fuellen
5672             oder Flags setzen
5673         */
5674         if (IsSevenMinus(eVer))
5675         {
5676             pnChpFirst = pnChpFirst_Ver67;
5677             pnPapFirst = pnPapFirst_Ver67;
5678             cpnBteChp = cpnBteChp_Ver67;
5679             cpnBtePap = cpnBtePap_Ver67;
5680         }
5681         else if (IsEightPlus(eVer))
5682         {
5683           fMac              =   aVer8Bits1  & 0x01           ;
5684           fEmptySpecial     = ( aVer8Bits1  & 0x02 ) >> 1;
5685           fLoadOverridePage = ( aVer8Bits1  & 0x04 ) >> 2;
5686           fFuturesavedUndo  = ( aVer8Bits1  & 0x08 ) >> 3;
5687           fWord97Saved      = ( aVer8Bits1  & 0x10 ) >> 4;
5688           fWord2000Saved    = ( aVer8Bits1  & 0x20 ) >> 5;
5689 
5690             /*
5691                 speziell fuer WW8:
5692                 ermittle die Werte fuer PLCF LST und PLF LFO
5693                 und PLCF fuer TextBox-Break-Deskriptoren
5694             */
5695             long nOldPos = rSt.Tell();
5696 
5697 			rSt.Seek( 0x02da );
5698 			rSt >> fcSttbFnm;
5699 			rSt >> lcbSttbFnm;
5700             rSt >> fcPlcfLst;
5701             rSt >> lcbPlcfLst;
5702             rSt >> fcPlfLfo;
5703             rSt >> lcbPlfLfo;
5704             rSt >> fcPlcftxbxBkd;
5705             rSt >> lcbPlcftxbxBkd;
5706             rSt >> fcPlcfHdrtxbxBkd;
5707             rSt >> lcbPlcfHdrtxbxBkd;
5708             if( 0 != rSt.GetError() )
5709             {
5710                 nFibError = ERR_SWG_READ_ERROR;
5711             }
5712 
5713             rSt.Seek( 0x372 );          // fcSttbListNames
5714             rSt >> fcSttbListNames;
5715             rSt >> lcbSttbListNames;
5716 
5717             if (cfclcb > 93)
5718             {
5719                 rSt.Seek( 0x382 );          // MagicTables
5720                 rSt >> fcPlcfTch;
5721                 rSt >> lcbPlcfTch;
5722             }
5723 
5724             if (cfclcb > 113)
5725             {
5726                 rSt.Seek( 0x41A );          // new ATRD
5727                 rSt >> fcAtrdExtra;
5728                 rSt >> lcbAtrdExtra;
5729             }
5730 
5731             if( 0 != rSt.GetError() )
5732                 nFibError = ERR_SWG_READ_ERROR;
5733 
5734             rSt.Seek( 0x5bc );          // Actual nFib introduced in Word 2003
5735             rSt >> nFib_actual;
5736 
5737             rSt.Seek( nOldPos );
5738         }
5739     }
5740     else
5741     {
5742         nFibError = ERR_SWG_READ_ERROR;     // Error melden
5743     }
5744 }
5745 
5746 
5747 WW8Fib::WW8Fib(sal_uInt8 nVer)
5748 {
5749     memset(this, 0, sizeof(*this));
5750     nVersion = nVer;
5751     if (8 == nVer)
5752     {
5753         fcMin = 0x800;
5754         wIdent = 0xa5ec;
5755         nFib = 0x0101;
5756         nFibBack = 0xbf;
5757         nProduct = 0x204D;
5758 
5759         csw = 0x0e;     // muss das sein ???
5760         cfclcb = 0x88;  //      -""-
5761         clw = 0x16;     //      -""-
5762         pnFbpChpFirst = pnFbpPapFirst = pnFbpLvcFirst = 0x000fffff;
5763         fExtChar = true;
5764         fWord97Saved = fWord2000Saved = true;
5765 
5766         // diese Flags muessen nicht gesetzt werden; koennen aber.
5767         //  wMagicCreated = wMagicRevised = 0x6a62;
5768         //  wMagicCreatedPrivate = wMagicRevisedPrivate = 0xb3b2;
5769         //
5770 
5771         wMagicCreated = 0x6143;
5772         wMagicRevised = 0x6C6F;
5773         wMagicCreatedPrivate = 0x6E61;
5774         wMagicRevisedPrivate = 0x3038;
5775     }
5776     else
5777     {
5778         fcMin = 0x300;
5779         wIdent = 0xa5dc;
5780         nFib = nFibBack = 0x65;
5781         nProduct = 0xc02d;
5782     }
5783 
5784     // --> #i90932#
5785     lid = 0x409; // LANGUAGE_ENGLISH_US
5786 
5787     LanguageType nLang = Application::GetSettings().GetLanguage();
5788     switch( nLang )
5789     {
5790         case LANGUAGE_CHINESE:
5791         case LANGUAGE_CHINESE_SIMPLIFIED:
5792         case LANGUAGE_CHINESE_HONGKONG:
5793         case LANGUAGE_CHINESE_SINGAPORE:
5794         case LANGUAGE_CHINESE_MACAU:
5795         case LANGUAGE_CHINESE_TRADITIONAL:
5796         case LANGUAGE_KOREAN:
5797         case LANGUAGE_KOREAN_JOHAB:
5798         case LANGUAGE_JAPANESE:
5799             lidFE = nLang;
5800             fFarEast = true;
5801             break;
5802         default:
5803             lidFE = lid;
5804             fFarEast = false;
5805             break;
5806     };
5807     // <-- #i90932#
5808 }
5809 
5810 bool WW8Fib::WriteHeader(SvStream& rStrm)
5811 {
5812 	bool bVer8 = 8 == nVersion;
5813 
5814 	size_t nUnencryptedHdr = bVer8 ? 0x44 : 0x24;
5815 	sal_uInt8 *pDataPtr = new sal_uInt8[ nUnencryptedHdr ];
5816     sal_uInt8 *pData = pDataPtr;
5817 	memset( pData, 0, nUnencryptedHdr );
5818 
5819 	sal_uLong nPos = rStrm.Tell();
5820 	cbMac = rStrm.Seek( STREAM_SEEK_TO_END );
5821 	rStrm.Seek( nPos );
5822 
5823 	Set_UInt16( pData, wIdent );
5824 	Set_UInt16( pData, nFib );
5825 	Set_UInt16( pData, nProduct );
5826 	Set_UInt16( pData, lid );
5827 	Set_UInt16( pData, pnNext );
5828 
5829 	sal_uInt16 nBits16 = 0;
5830 	if( fDot ) 			nBits16 |= 0x0001;
5831 	if( fGlsy) 			nBits16 |= 0x0002;
5832 	if( fComplex )		nBits16 |= 0x0004;
5833 	if( fHasPic ) 		nBits16 |= 0x0008;
5834 	nBits16 |= (0xf0 & ( cQuickSaves << 4 ));
5835 	if( fEncrypted ) 	nBits16 |= 0x0100;
5836 	if( fWhichTblStm ) 	nBits16 |= 0x0200;
5837 
5838     if (fReadOnlyRecommended)
5839         nBits16 |= 0x0400;
5840     if (fWriteReservation)
5841         nBits16 |= 0x0800;
5842 
5843 	if( fExtChar ) 		nBits16 |= 0x1000;
5844 	if( fFarEast )      nBits16 |= 0x4000;  // #i90932#
5845 	if( fObfuscated )	nBits16 |= 0x8000;
5846 	Set_UInt16( pData, nBits16 );
5847 
5848 	Set_UInt16( pData, nFibBack );
5849 	Set_UInt16( pData, nHash );
5850 	Set_UInt16( pData, nKey );
5851 	Set_UInt8( pData, envr );
5852 
5853 	sal_uInt8 nBits8 = 0;
5854 	if( bVer8 )
5855 	{
5856 		if( fMac ) 					nBits8 |= 0x0001;
5857 		if( fEmptySpecial ) 		nBits8 |= 0x0002;
5858 		if( fLoadOverridePage )		nBits8 |= 0x0004;
5859 		if( fFuturesavedUndo ) 		nBits8 |= 0x0008;
5860 		if( fWord97Saved ) 			nBits8 |= 0x0010;
5861         if( fWord2000Saved )        nBits8 |= 0x0020;
5862 	}
5863 	// unter Ver67 these are only reserved
5864 	Set_UInt8( pData, nBits8  );
5865 
5866 	Set_UInt16( pData, chse );
5867 	Set_UInt16( pData, chseTables );
5868 	Set_UInt32( pData, fcMin );
5869 	Set_UInt32( pData, fcMac );
5870 
5871 // Einschub fuer WW8 *****************************************************
5872 
5873 	// Marke: "rgsw"  Beginning of the array of shorts
5874 	if( bVer8 )
5875 	{
5876 		Set_UInt16( pData, csw );
5877 		Set_UInt16( pData, wMagicCreated );
5878 		Set_UInt16( pData, wMagicRevised );
5879 		Set_UInt16( pData, wMagicCreatedPrivate );
5880 		Set_UInt16( pData, wMagicRevisedPrivate );
5881 		pData += 9 * sizeof( sal_Int16 );
5882 		Set_UInt16( pData, lidFE );
5883 		Set_UInt16( pData, clw );
5884 	}
5885 
5886 // Ende des Einschubs fuer WW8 *******************************************
5887 
5888 	// Marke: "rglw"  Beginning of the array of longs
5889 	Set_UInt32( pData, cbMac );
5890 
5891 	rStrm.Write( pDataPtr, nUnencryptedHdr );
5892 	delete[] pDataPtr;
5893 	return 0 == rStrm.GetError();
5894 }
5895 
5896 bool WW8Fib::Write(SvStream& rStrm)
5897 {
5898 	bool bVer8 = 8 == nVersion;
5899 
5900 	WriteHeader( rStrm );
5901 
5902 	size_t nUnencryptedHdr = bVer8 ? 0x44 : 0x24;
5903 
5904     sal_uInt8 *pDataPtr = new sal_uInt8[ fcMin - nUnencryptedHdr ];
5905     sal_uInt8 *pData = pDataPtr;
5906 	memset( pData, 0, fcMin - nUnencryptedHdr );
5907 
5908     sal_uLong nPos = rStrm.Tell();
5909     cbMac = rStrm.Seek( STREAM_SEEK_TO_END );
5910     rStrm.Seek( nPos );
5911 
5912     // 2 Longs uebergehen, da unwichtiger Quatsch
5913     pData += 2 * sizeof( sal_Int32);
5914 
5915     // weitere 2 Longs nur bei Ver67 ueberspringen
5916     if( !bVer8 )
5917         pData += 2 * sizeof( sal_Int32);
5918 
5919     Set_UInt32( pData, ccpText );
5920     Set_UInt32( pData, ccpFtn );
5921     Set_UInt32( pData, ccpHdr );
5922     Set_UInt32( pData, ccpMcr );
5923     Set_UInt32( pData, ccpAtn );
5924     Set_UInt32( pData, ccpEdn );
5925     Set_UInt32( pData, ccpTxbx );
5926     Set_UInt32( pData, ccpHdrTxbx );
5927 
5928         // weiteres Long nur bei Ver67 ueberspringen
5929     if( !bVer8 )
5930         pData += 1 * sizeof( sal_Int32);
5931 
5932 // Einschub fuer WW8 *****************************************************
5933     if( bVer8 )
5934     {
5935         Set_UInt32( pData, pnFbpChpFirst );
5936         Set_UInt32( pData, pnChpFirst );
5937         Set_UInt32( pData, cpnBteChp );
5938         Set_UInt32( pData, pnFbpPapFirst );
5939         Set_UInt32( pData, pnPapFirst );
5940         Set_UInt32( pData, cpnBtePap );
5941         Set_UInt32( pData, pnFbpLvcFirst );
5942         Set_UInt32( pData, pnLvcFirst );
5943         Set_UInt32( pData, cpnBteLvc );
5944         Set_UInt32( pData, fcIslandFirst );
5945         Set_UInt32( pData, fcIslandLim );
5946         Set_UInt16( pData, cfclcb );
5947     }
5948 // Ende des Einschubs fuer WW8 *******************************************
5949 
5950     // Marke: "rgfclcb" Beginning of array of FC/LCB pairs.
5951     Set_UInt32( pData, fcStshfOrig );
5952     Set_UInt32( pData, lcbStshfOrig );
5953     Set_UInt32( pData, fcStshf );
5954     Set_UInt32( pData, lcbStshf );
5955     Set_UInt32( pData, fcPlcffndRef );
5956     Set_UInt32( pData, lcbPlcffndRef );
5957     Set_UInt32( pData, fcPlcffndTxt );
5958     Set_UInt32( pData, lcbPlcffndTxt );
5959     Set_UInt32( pData, fcPlcfandRef );
5960     Set_UInt32( pData, lcbPlcfandRef );
5961     Set_UInt32( pData, fcPlcfandTxt );
5962     Set_UInt32( pData, lcbPlcfandTxt );
5963     Set_UInt32( pData, fcPlcfsed );
5964     Set_UInt32( pData, lcbPlcfsed );
5965     Set_UInt32( pData, fcPlcfpad );
5966     Set_UInt32( pData, lcbPlcfpad );
5967     Set_UInt32( pData, fcPlcfphe );
5968     Set_UInt32( pData, lcbPlcfphe );
5969     Set_UInt32( pData, fcSttbfglsy );
5970     Set_UInt32( pData, lcbSttbfglsy );
5971     Set_UInt32( pData, fcPlcfglsy );
5972     Set_UInt32( pData, lcbPlcfglsy );
5973     Set_UInt32( pData, fcPlcfhdd );
5974     Set_UInt32( pData, lcbPlcfhdd );
5975     Set_UInt32( pData, fcPlcfbteChpx );
5976     Set_UInt32( pData, lcbPlcfbteChpx );
5977     Set_UInt32( pData, fcPlcfbtePapx );
5978     Set_UInt32( pData, lcbPlcfbtePapx );
5979     Set_UInt32( pData, fcPlcfsea );
5980     Set_UInt32( pData, lcbPlcfsea );
5981     Set_UInt32( pData, fcSttbfffn );
5982     Set_UInt32( pData, lcbSttbfffn );
5983     Set_UInt32( pData, fcPlcffldMom );
5984     Set_UInt32( pData, lcbPlcffldMom );
5985     Set_UInt32( pData, fcPlcffldHdr );
5986     Set_UInt32( pData, lcbPlcffldHdr );
5987     Set_UInt32( pData, fcPlcffldFtn );
5988     Set_UInt32( pData, lcbPlcffldFtn );
5989     Set_UInt32( pData, fcPlcffldAtn );
5990     Set_UInt32( pData, lcbPlcffldAtn );
5991     Set_UInt32( pData, fcPlcffldMcr );
5992     Set_UInt32( pData, lcbPlcffldMcr );
5993     Set_UInt32( pData, fcSttbfbkmk );
5994     Set_UInt32( pData, lcbSttbfbkmk );
5995     Set_UInt32( pData, fcPlcfbkf );
5996     Set_UInt32( pData, lcbPlcfbkf );
5997     Set_UInt32( pData, fcPlcfbkl );
5998     Set_UInt32( pData, lcbPlcfbkl );
5999     Set_UInt32( pData, fcCmds );
6000     Set_UInt32( pData, lcbCmds );
6001     Set_UInt32( pData, fcPlcfmcr );
6002     Set_UInt32( pData, lcbPlcfmcr );
6003     Set_UInt32( pData, fcSttbfmcr );
6004     Set_UInt32( pData, lcbSttbfmcr );
6005     Set_UInt32( pData, fcPrDrvr );
6006     Set_UInt32( pData, lcbPrDrvr );
6007     Set_UInt32( pData, fcPrEnvPort );
6008     Set_UInt32( pData, lcbPrEnvPort );
6009     Set_UInt32( pData, fcPrEnvLand );
6010     Set_UInt32( pData, lcbPrEnvLand );
6011     Set_UInt32( pData, fcWss );
6012     Set_UInt32( pData, lcbWss );
6013     Set_UInt32( pData, fcDop );
6014     Set_UInt32( pData, lcbDop );
6015     Set_UInt32( pData, fcSttbfAssoc );
6016     Set_UInt32( pData, lcbSttbfAssoc );
6017     Set_UInt32( pData, fcClx );
6018     Set_UInt32( pData, lcbClx );
6019     Set_UInt32( pData, fcPlcfpgdFtn );
6020     Set_UInt32( pData, lcbPlcfpgdFtn );
6021     Set_UInt32( pData, fcAutosaveSource );
6022     Set_UInt32( pData, lcbAutosaveSource );
6023     Set_UInt32( pData, fcGrpStAtnOwners );
6024     Set_UInt32( pData, lcbGrpStAtnOwners );
6025     Set_UInt32( pData, fcSttbfAtnbkmk );
6026     Set_UInt32( pData, lcbSttbfAtnbkmk );
6027 
6028     // weiteres short nur bei Ver67 ueberspringen
6029     if( !bVer8 )
6030     {
6031         pData += 1*sizeof( sal_Int16);
6032         Set_UInt16( pData, (sal_uInt16)pnChpFirst );
6033         Set_UInt16( pData, (sal_uInt16)pnPapFirst );
6034         Set_UInt16( pData, (sal_uInt16)cpnBteChp );
6035         Set_UInt16( pData, (sal_uInt16)cpnBtePap );
6036     }
6037 
6038     Set_UInt32( pData, fcPlcfdoaMom ); // nur bei Ver67, in Ver8 unused
6039     Set_UInt32( pData, lcbPlcfdoaMom ); // nur bei Ver67, in Ver8 unused
6040     Set_UInt32( pData, fcPlcfdoaHdr ); // nur bei Ver67, in Ver8 unused
6041     Set_UInt32( pData, lcbPlcfdoaHdr ); // nur bei Ver67, in Ver8 unused
6042 
6043     Set_UInt32( pData, fcPlcfspaMom ); // in Ver67 leere Reserve
6044     Set_UInt32( pData, lcbPlcfspaMom ); // in Ver67 leere Reserve
6045     Set_UInt32( pData, fcPlcfspaHdr ); // in Ver67 leere Reserve
6046     Set_UInt32( pData, lcbPlcfspaHdr ); // in Ver67 leere Reserve
6047 
6048     Set_UInt32( pData, fcPlcfAtnbkf );
6049     Set_UInt32( pData, lcbPlcfAtnbkf );
6050     Set_UInt32( pData, fcPlcfAtnbkl );
6051     Set_UInt32( pData, lcbPlcfAtnbkl );
6052     Set_UInt32( pData, fcPms );
6053     Set_UInt32( pData, lcbPMS );
6054     Set_UInt32( pData, fcFormFldSttbf );
6055     Set_UInt32( pData, lcbFormFldSttbf );
6056     Set_UInt32( pData, fcPlcfendRef );
6057     Set_UInt32( pData, lcbPlcfendRef );
6058     Set_UInt32( pData, fcPlcfendTxt );
6059     Set_UInt32( pData, lcbPlcfendTxt );
6060     Set_UInt32( pData, fcPlcffldEdn );
6061     Set_UInt32( pData, lcbPlcffldEdn );
6062     Set_UInt32( pData, fcPlcfpgdEdn );
6063     Set_UInt32( pData, lcbPlcfpgdEdn );
6064     Set_UInt32( pData, fcDggInfo ); // in Ver67 leere Reserve
6065     Set_UInt32( pData, lcbDggInfo ); // in Ver67 leere Reserve
6066     Set_UInt32( pData, fcSttbfRMark );
6067     Set_UInt32( pData, lcbSttbfRMark );
6068     Set_UInt32( pData, fcSttbfCaption );
6069     Set_UInt32( pData, lcbSttbfCaption );
6070     Set_UInt32( pData, fcSttbAutoCaption );
6071     Set_UInt32( pData, lcbSttbAutoCaption );
6072     Set_UInt32( pData, fcPlcfwkb );
6073     Set_UInt32( pData, lcbPlcfwkb );
6074     Set_UInt32( pData, fcPlcfspl ); // in Ver67 leere Reserve
6075     Set_UInt32( pData, lcbPlcfspl ); // in Ver67 leere Reserve
6076     Set_UInt32( pData, fcPlcftxbxTxt );
6077     Set_UInt32( pData, lcbPlcftxbxTxt );
6078     Set_UInt32( pData, fcPlcffldTxbx );
6079     Set_UInt32( pData, lcbPlcffldTxbx );
6080     Set_UInt32( pData, fcPlcfHdrtxbxTxt );
6081     Set_UInt32( pData, lcbPlcfHdrtxbxTxt );
6082     Set_UInt32( pData, fcPlcffldHdrTxbx );
6083     Set_UInt32( pData, lcbPlcffldHdrTxbx );
6084 
6085     if( bVer8 )
6086     {
6087         pData += 0x2da - 0x27a;         // Pos + Offset (fcPlcfLst - fcStwUser)
6088 		Set_UInt32( pData, fcSttbFnm);
6089 		Set_UInt32( pData, lcbSttbFnm);
6090         Set_UInt32( pData, fcPlcfLst );
6091         Set_UInt32( pData, lcbPlcfLst );
6092         Set_UInt32( pData, fcPlfLfo );
6093         Set_UInt32( pData, lcbPlfLfo );
6094         Set_UInt32( pData, fcPlcftxbxBkd );
6095         Set_UInt32( pData, lcbPlcftxbxBkd );
6096         Set_UInt32( pData, fcPlcfHdrtxbxBkd );
6097         Set_UInt32( pData, lcbPlcfHdrtxbxBkd );
6098 
6099         pData += 0x372 - 0x302; // Pos + Offset (fcSttbListNames - fcDocUndo)
6100         Set_UInt32( pData, fcSttbListNames );
6101         Set_UInt32( pData, lcbSttbListNames );
6102 
6103         pData += 0x382 - 0x37A;
6104         Set_UInt32( pData, fcPlcfTch );
6105         Set_UInt32( pData, lcbPlcfTch );
6106 
6107         pData += 0x3FA - 0x38A;
6108         Set_UInt16( pData, (sal_uInt16)0x0002);
6109         Set_UInt16( pData, (sal_uInt16)0x00D9);
6110 
6111         pData += 0x41A - 0x3FE;
6112         Set_UInt32( pData, fcAtrdExtra );
6113         Set_UInt32( pData, lcbAtrdExtra );
6114 
6115         pData += 0x4DA - 0x422;
6116         Set_UInt32( pData, fcHplxsdr );
6117         Set_UInt32( pData, 0);
6118     }
6119 
6120 	rStrm.Write( pDataPtr, fcMin - nUnencryptedHdr );
6121 	delete[] pDataPtr;
6122 	return 0 == rStrm.GetError();
6123 }
6124 
6125 rtl_TextEncoding WW8Fib::GetFIBCharset(sal_uInt16 chs)
6126 {
6127     ASSERT(chs <= 0x100, "overflowed winword charset set");
6128     rtl_TextEncoding eCharSet =
6129         (0x0100 == chs)
6130         ? RTL_TEXTENCODING_APPLE_ROMAN
6131         : rtl_getTextEncodingFromWindowsCharset( static_cast<sal_uInt8>(chs) );
6132     return eCharSet;
6133 }
6134 
6135 WW8Style::WW8Style(SvStream& rStream, WW8Fib& rFibPara)
6136     : rFib(rFibPara), rSt(rStream), cstd(0), cbSTDBaseInFile(0),
6137     stiMaxWhenSaved(0), istdMaxFixedWhenSaved(0), nVerBuiltInNamesWhenSaved(0),
6138     ftcAsci(0), ftcFE(0), ftcOther(0), ftcBi(0)
6139 {
6140     nStyleStart = rFib.fcStshf;
6141     nStyleLen = rFib.lcbStshf;
6142 
6143     rSt.Seek(nStyleStart);
6144 
6145     sal_uInt16 cbStshi = 0; //  2 bytes size of the following STSHI structure
6146 
6147     if (rFib.GetFIBVersion() <= ww::eWW2)
6148     {
6149         cbStshi = 0;
6150         cstd = 256;
6151     }
6152     else if (rFib.nFib < 67) // old Version ? (need to find this again to fix)
6153         cbStshi = 4;    // -> Laengenfeld fehlt
6154     else    // neue Version:
6155         // lies die Laenge der in der Datei gespeicherten Struktur
6156         rSt >> cbStshi;
6157 
6158     sal_uInt16 nRead = cbStshi;
6159     do
6160     {
6161         sal_uInt16 a16Bit;
6162 
6163         if(  2 > nRead ) break;
6164         rSt >> cstd;
6165 
6166         if(  4 > nRead ) break;
6167         rSt >> cbSTDBaseInFile;
6168 
6169         if(  6 > nRead ) break;
6170         rSt >> a16Bit;
6171         fStdStylenamesWritten = a16Bit & 0x0001;
6172 
6173         if(  8 > nRead ) break;
6174         rSt >> stiMaxWhenSaved;
6175 
6176         if( 10 > nRead ) break;
6177         rSt >> istdMaxFixedWhenSaved;
6178 
6179         if( 12 > nRead ) break;
6180         rSt >> nVerBuiltInNamesWhenSaved;
6181 
6182         if( 14 > nRead ) break;
6183         rSt >> ftcAsci;
6184 
6185         if( 16 > nRead ) break;
6186         rSt >> ftcFE;
6187 
6188         if ( 18 > nRead ) break;
6189         rSt >> ftcOther;
6190 
6191         ftcBi = ftcOther;
6192 
6193         if ( 20 > nRead ) break;
6194         rSt >> ftcBi;
6195 
6196         // ggfs. den Rest ueberlesen
6197         if( 20 < nRead )
6198             rSt.SeekRel( nRead-20 );
6199     }
6200     while( !this ); // Trick: obiger Block wird genau einmal durchlaufen
6201                     //   und kann vorzeitig per "break" verlassen werden.
6202 
6203     if( 0 != rSt.GetError() )
6204     {
6205         // wie denn nun den Error melden?
6206     }
6207 }
6208 
6209 // Read1STDFixed() liest ein Style ein. Wenn der Style vollstaendig vorhanden
6210 // ist, d.h. kein leerer Slot, dann wird Speicher alloziert und ein Pointer auf
6211 // die ( evtl. mit Nullen aufgefuellten ) STD geliefert. Ist es ein leerer
6212 // Slot, dann wird ein Nullpointer zurueckgeliefert.
6213 WW8_STD* WW8Style::Read1STDFixed( short& rSkip, short* pcbStd )
6214 {
6215     WW8_STD* pStd = 0;
6216 
6217     sal_uInt16 cbStd;
6218     rSt >> cbStd;   // lies Laenge
6219 
6220     sal_uInt16 nRead = cbSTDBaseInFile;
6221     if( cbStd >= cbSTDBaseInFile )
6222     {
6223         // Fixed part vollst. vorhanden
6224 
6225         // read fixed part of STD
6226         pStd = new WW8_STD;
6227         memset( pStd, 0, sizeof( *pStd ) );
6228 
6229         do
6230         {
6231             sal_uInt16 a16Bit;
6232 
6233             if( 2 > nRead ) break;
6234             rSt >> a16Bit;
6235             pStd->sti          =        a16Bit & 0x0fff  ;
6236             pStd->fScratch     = 0 != ( a16Bit & 0x1000 );
6237             pStd->fInvalHeight = 0 != ( a16Bit & 0x2000 );
6238             pStd->fHasUpe      = 0 != ( a16Bit & 0x4000 );
6239             pStd->fMassCopy    = 0 != ( a16Bit & 0x8000 );
6240 
6241             if( 4 > nRead ) break;
6242             rSt >> a16Bit;
6243             pStd->sgc      =   a16Bit & 0x000f       ;
6244             pStd->istdBase = ( a16Bit & 0xfff0 ) >> 4;
6245 
6246             if( 6 > nRead ) break;
6247             rSt >> a16Bit;
6248             pStd->cupx     =   a16Bit & 0x000f       ;
6249             pStd->istdNext = ( a16Bit & 0xfff0 ) >> 4;
6250 
6251             if( 8 > nRead ) break;
6252             rSt >> pStd->bchUpe;
6253 
6254             // ab Ver8 sollten diese beiden Felder dazukommen:
6255             if(10 > nRead ) break;
6256             rSt >> a16Bit;
6257             pStd->fAutoRedef =   a16Bit & 0x0001       ;
6258             pStd->fHidden    = ( a16Bit & 0x0002 ) >> 1;
6259 
6260             // man kann nie wissen: vorsichtshalber ueberlesen
6261             // wir eventuelle Fuellsel, die noch zum BASE-Part gehoeren...
6262             if( 10 < nRead )
6263                 rSt.SeekRel( nRead-10 );
6264         }
6265         while( !this ); // Trick: obiger Block wird genau einmal durchlaufen
6266                         //   und kann vorzeitig per "break" verlassen werden.
6267 
6268         if( (0 != rSt.GetError()) || !nRead )
6269             DELETEZ( pStd );        // per NULL den Error melden
6270 
6271       rSkip = cbStd - cbSTDBaseInFile;
6272     }
6273     else
6274     {           // Fixed part zu kurz
6275         if( cbStd )
6276             rSt.SeekRel( cbStd );           // ueberlies Reste
6277         rSkip = 0;
6278     }
6279     if( pcbStd )
6280         *pcbStd = cbStd;
6281     return pStd;
6282 }
6283 
6284 WW8_STD* WW8Style::Read1Style( short& rSkip, String* pString, short* pcbStd )
6285 {
6286     // Attention: MacWord-Documents have their Stylenames
6287     // always in ANSI, even if eStructCharSet == CHARSET_MAC !!
6288 
6289     WW8_STD* pStd = Read1STDFixed( rSkip, pcbStd );         // lese STD
6290 
6291     // String gewuenscht ?
6292     if( pString )
6293     {   // echter Style ?
6294         if ( pStd )
6295         {
6296             switch( rFib.nVersion )
6297             {
6298                 case 6:
6299                 case 7:
6300                     // lies Pascal-String
6301                     *pString = WW8ReadPString( rSt, RTL_TEXTENCODING_MS_1252 );
6302                     // leading len and trailing zero --> 2
6303                     rSkip -= 2+ pString->Len();
6304                     break;
6305                 case 8:
6306                     // handle Unicode-String with leading length short and
6307                     // trailing zero
6308                     if (ww8String::TestBeltAndBraces(rSt))
6309                     {
6310                         *pString = WW8Read_xstz(rSt, 0, true);
6311                         rSkip -= (pString->Len() + 2) * 2;
6312                     }
6313                     else
6314                     {
6315                         /*
6316                         #i8114#
6317                         This is supposed to be impossible, its just supposed
6318                         to be 16 bit count followed by the string and ending
6319                         in a 0 short. But "Lotus SmartSuite Product: Word Pro"
6320                         is creating invalid style names in ww7- format. So we
6321                         use the belt and braces of the ms strings to see if
6322                         they are not corrupt. If they are then we try them as
6323                         8bit ones
6324                         */
6325                         *pString = WW8ReadPString(rSt,RTL_TEXTENCODING_MS_1252);
6326                         // leading len and trailing zero --> 2
6327                         rSkip -= 2+ pString->Len();
6328                     }
6329                     break;
6330                 default:
6331                     ASSERT(!this, "Es wurde vergessen, nVersion zu kodieren!");
6332                     break;
6333             }
6334         }
6335         else
6336             *pString = aEmptyStr;   // Kann keinen Namen liefern
6337     }
6338     return pStd;
6339 }
6340 
6341 
6342 //-----------------------------------------
6343 
6344 
6345 struct WW8_FFN_Ver6 : public WW8_FFN_BASE
6346 {
6347     // ab Ver6
6348     sal_Char szFfn[65]; // 0x6 bzw. 0x40 ab Ver8 zero terminated string that
6349                         // records name of font.
6350                         // Maximal size of szFfn is 65 characters.
6351                         // Vorsicht: Dieses Array kann auch kleiner sein!!!
6352                         // Possibly followed by a second sz which records the
6353                         // name of an alternate font to use if the first named
6354                         // font does not exist on this system.
6355 };
6356 struct WW8_FFN_Ver8 : public WW8_FFN_BASE
6357 {
6358     // ab Ver8 sind folgende beiden Felder eingeschoben,
6359     // werden von uns ignoriert.
6360     sal_Char panose[ 10 ];  //  0x6   PANOSE
6361     sal_Char fs[ 24     ];  //  0x10  FONTSIGNATURE
6362 
6363     // ab Ver8 als Unicode
6364     sal_uInt16 szFfn[65];   // 0x6 bzw. 0x40 ab Ver8 zero terminated string that
6365                         // records name of font.
6366                         // Maximal size of szFfn is 65 characters.
6367                         // Vorsicht: Dieses Array kann auch kleiner sein!!!
6368                         // Possibly followed by a second sz which records the
6369                         // name of an alternate font to use if the first named
6370                         // font does not exist on this system.
6371 };
6372 
6373 // #i43762# check font name for illegal characters
6374 void lcl_checkFontname( String& sString )
6375 {
6376     // for efficiency, we'd like to use String methods as far as possible.
6377     // Hence, we will:
6378     // 1) convert all invalid chars to \u0001
6379     // 2) then erase all \u0001 chars (if any were found), and
6380     // 3) erase leading/trailing ';', in case a font name was
6381     //    completely removed
6382 
6383     // convert all invalid chars to \u0001
6384     sal_Unicode* pBuffer = sString.GetBufferAccess();
6385     xub_StrLen nLen = sString.Len();
6386     bool bFound = false;
6387     for( xub_StrLen n = 0; n < nLen; n++ )
6388     {
6389         if( pBuffer[n] < sal_Unicode( 0x20 ) )
6390         {
6391             pBuffer[n] = sal_Unicode( 1 );
6392             bFound = true;
6393         }
6394     }
6395     sString.ReleaseBufferAccess();
6396 
6397     // if anything was found, remove \u0001 + leading/trailing ';'
6398     if( bFound )
6399     {
6400         sString.EraseAllChars( sal_Unicode( 1 ) );
6401         sString.EraseLeadingAndTrailingChars( sal_Unicode( ';' ) );
6402     }
6403 }
6404 
6405 WW8Fonts::WW8Fonts( SvStream& rSt, WW8Fib& rFib )
6406     : pFontA(0), nMax(0)
6407 {
6408     // Attention: MacWord-Documents have their Fontnames
6409     // always in ANSI, even if eStructCharSet == CHARSET_MAC !!
6410     if( rFib.lcbSttbfffn <= 2 )
6411     {
6412         ASSERT( !this, "Fonttabelle kaputt! (rFib.lcbSttbfffn < 2)" );
6413         pFontA = 0;
6414         nMax = 0;
6415         return;
6416     }
6417 
6418     rSt.Seek( rFib.fcSttbfffn );
6419 
6420     sal_Int32 nFFn = rFib.lcbSttbfffn - 2;
6421 
6422     // allocate Font Array
6423     sal_uInt8* pA   = new sal_uInt8[ nFFn ];
6424     memset(pA, 0, nFFn);
6425     WW8_FFN* p = (WW8_FFN*)pA;
6426 
6427     ww::WordVersion eVersion = rFib.GetFIBVersion();
6428 
6429     if( eVersion >= ww::eWW8 )
6430     {
6431         // bVer8: read the count of strings in nMax
6432         rSt >> nMax;
6433     }
6434 
6435     // Ver8:  skip undefined uint16
6436     // Ver67: skip the herein stored total byte of structure
6437     //        - we already got that information in rFib.lcbSttbfffn
6438     rSt.SeekRel( 2 );
6439 
6440     // read all font information
6441     nFFn = rSt.Read( pA, nFFn );
6442 
6443     if( eVersion < ww::eWW8 )
6444     {
6445         // try to figure out how many fonts are defined here
6446         nMax = 0;
6447         long nLeft = nFFn;
6448         for(;;)
6449         {
6450             short nNextSiz;
6451 
6452             nNextSiz = p->cbFfnM1 + 1;
6453             if( nNextSiz > nLeft )
6454                 break;
6455             nMax++;
6456             nLeft -= nNextSiz;
6457             if( nLeft < 1 )     // can we read the given ammount of bytes ?
6458                 break;
6459             // increase p by nNextSiz Bytes
6460             p = (WW8_FFN *)( ( (sal_uInt8*)p ) + nNextSiz );
6461         }
6462     }
6463 
6464     if( nMax )
6465     {
6466         // allocate Index Array
6467         pFontA = new WW8_FFN[ nMax ];
6468         p = pFontA;
6469 
6470 	if( eVersion <= ww::eWW2 )
6471 	{
6472             WW8_FFN_BASE* pVer2 = (WW8_FFN_BASE*)pA;
6473             for(sal_uInt16 i=0; i<nMax; ++i, ++p)
6474             {
6475                 p->cbFfnM1   = pVer2->cbFfnM1;
6476 
6477                 p->prg       =  0;
6478                 p->fTrueType = 0;
6479                 p->ff        = 0;
6480 
6481                 p->wWeight   = ( *(((sal_uInt8*)pVer2) + 1) );
6482                 p->chs   = ( *(((sal_uInt8*)pVer2) + 2) );
6483         	/*
6484                  #i8726# 7- seems to encode the name in the same encoding as
6485                  the font, e.g load the doc in 97 and save to see the unicode
6486                  ver of the asian fontnames in that example to confirm.
6487                 */
6488                 rtl_TextEncoding eEnc = WW8Fib::GetFIBCharset(p->chs);
6489                 if ((eEnc == RTL_TEXTENCODING_SYMBOL) || (eEnc == RTL_TEXTENCODING_DONTKNOW))
6490                     eEnc = RTL_TEXTENCODING_MS_1252;
6491 
6492                 p->sFontname = String ( (((const sal_Char*)pVer2) + 1 + 2), eEnc);
6493                 pVer2 = (WW8_FFN_BASE*)( ((sal_uInt8*)pVer2) + pVer2->cbFfnM1 + 1 );
6494             }
6495 	}
6496         else if( eVersion < ww::eWW8 )
6497         {
6498             WW8_FFN_Ver6* pVer6 = (WW8_FFN_Ver6*)pA;
6499             sal_uInt8 c2;
6500             for(sal_uInt16 i=0; i<nMax; ++i, ++p)
6501             {
6502                 p->cbFfnM1   = pVer6->cbFfnM1;
6503                 c2           = *(((sal_uInt8*)pVer6) + 1);
6504 
6505                 p->prg       =  c2 & 0x02;
6506                 p->fTrueType = (c2 & 0x04) >> 2;
6507                 // ein Reserve-Bit ueberspringen
6508                 p->ff        = (c2 & 0x70) >> 4;
6509 
6510                 p->wWeight   = SVBT16ToShort( *(SVBT16*)&pVer6->wWeight );
6511                 p->chs       = pVer6->chs;
6512                 p->ibszAlt   = pVer6->ibszAlt;
6513                 /*
6514                  #i8726# 7- seems to encode the name in the same encoding as
6515                  the font, e.g load the doc in 97 and save to see the unicode
6516                  ver of the asian fontnames in that example to confirm.
6517                  */
6518                 rtl_TextEncoding eEnc = WW8Fib::GetFIBCharset(p->chs);
6519                 if ((eEnc == RTL_TEXTENCODING_SYMBOL) || (eEnc == RTL_TEXTENCODING_DONTKNOW))
6520                     eEnc = RTL_TEXTENCODING_MS_1252;
6521                 p->sFontname = String(pVer6->szFfn, eEnc);
6522                 if (p->ibszAlt)
6523                 {
6524                     p->sFontname.Append(';');
6525                     p->sFontname += String(pVer6->szFfn+p->ibszAlt, eEnc);
6526                 }
6527                 else
6528                 {
6529                     //#i18369# if its a symbol font set Symbol as fallback
6530                     if (
6531                          RTL_TEXTENCODING_SYMBOL == WW8Fib::GetFIBCharset(p->chs)
6532                          && !p->sFontname.EqualsAscii("Symbol")
6533                        )
6534                     {
6535                         p->sFontname.APPEND_CONST_ASC(";Symbol");
6536                     }
6537                 }
6538                 pVer6 = (WW8_FFN_Ver6*)( ((sal_uInt8*)pVer6) + pVer6->cbFfnM1 + 1 );
6539             }
6540         }
6541         else
6542         {
6543             WW8_FFN_Ver8* pVer8 = (WW8_FFN_Ver8*)pA;
6544             sal_uInt8 c2;
6545             for(sal_uInt16 i=0; i<nMax; ++i, ++p)
6546             {
6547                 p->cbFfnM1   = pVer8->cbFfnM1;
6548                 c2           = *(((sal_uInt8*)pVer8) + 1);
6549 
6550                 p->prg       =  c2 & 0x02;
6551                 p->fTrueType = (c2 & 0x04) >> 2;
6552                 // ein Reserve-Bit ueberspringen
6553                 p->ff        = (c2 & 0x70) >> 4;
6554 
6555                 p->wWeight   = SVBT16ToShort( *(SVBT16*)&pVer8->wWeight );
6556                 p->chs       = pVer8->chs;
6557                 p->ibszAlt   = pVer8->ibszAlt;
6558 
6559 #ifdef __WW8_NEEDS_COPY
6560                 {
6561                     sal_uInt8 nLen = 0x28;
6562                     sal_uInt8 nLength = sizeof( pVer8->szFfn ) / sizeof( SVBT16 );
6563                     nLength = std::min( nLength, sal_uInt8( pVer8->cbFfnM1+1 ) );
6564                     for( sal_uInt16* pTmp = pVer8->szFfn;
6565                         nLen < nLength; ++pTmp, nLen+=2 )
6566                     {
6567                         *pTmp = SVBT16ToShort( *(SVBT16*)pTmp );
6568                     }
6569                 }
6570 #endif // defined __WW8_NEEDS_COPY
6571 
6572                 p->sFontname = pVer8->szFfn;
6573                 if (p->ibszAlt)
6574                 {
6575                     p->sFontname.Append(';');
6576                     p->sFontname.Append(pVer8->szFfn+p->ibszAlt);
6577                 }
6578 
6579                 // #i43762# check font name for illegal characters
6580                 lcl_checkFontname( p->sFontname );
6581 
6582                 // Zeiger auf Ursprungsarray einen Font nach hinten setzen
6583                 pVer8 = (WW8_FFN_Ver8*)( ((sal_uInt8*)pVer8) + pVer8->cbFfnM1 + 1 );
6584             }
6585         }
6586     }
6587     delete[] pA;
6588 }
6589 
6590 const WW8_FFN* WW8Fonts::GetFont( sal_uInt16 nNum ) const
6591 {
6592     if( !pFontA || nNum >= nMax )
6593         return 0;
6594 
6595     return &pFontA[ nNum ];
6596 }
6597 
6598 
6599 
6600 //-----------------------------------------
6601 
6602 
6603 // Suche zu einem Header / Footer den Index in der WW-Liste von Headern / Footern
6604 //
6605 // Pferdefuesse bei WinWord6 und -7:
6606 // 1) Am Anfang des Einlesens muss WWPLCF_HdFt mit Fib und Dop konstruiert werden
6607 // 2) Der Haupttext muss sequentiell ueber alle Sections gelesen werden
6608 // 3) Fuer jedes vorkommende Header / Footer - Attribut des Haupttextes
6609 //  ( Darf pro Section maximal eins sein ) muss UpdateIndex() genau einmal
6610 //  mit dem Parameter des Attributes gerufen werden. Dieser Aufruf muss *nach*
6611 //  dem letzten Aufruf von GetTextPos() passieren.
6612 // 4) GetTextPos() darf mit genau einem der obenstehen WW_... aufgerufen werden
6613 //   ( nicht verodern ! )
6614 // -> dann liefert GetTextPos() vielleicht auch ein richtiges Ergebnis
6615 
6616 WW8PLCF_HdFt::WW8PLCF_HdFt( SvStream* pSt, WW8Fib& rFib, WW8Dop& rDop )
6617     : aPLCF( pSt, rFib.fcPlcfhdd , rFib.lcbPlcfhdd , 0 )
6618 {
6619     nIdxOffset = 0;
6620 
6621      /*
6622       cmc 23/02/2000: This dop.grpfIhdt has a bit set for each special
6623       footnote *and endnote!!* seperator,continuation seperator, and
6624       continuation notice entry, the documentation does not mention the
6625       endnote seperators, the documentation also gets the index numbers
6626       backwards when specifiying which bits to test. The bottom six bits
6627       of this value must be tested and skipped over. Each section's
6628       grpfIhdt is then tested for the existence of the appropiate headers
6629       and footers, at the end of each section the nIdxOffset must be updated
6630       to point to the beginning of the next section's group of headers and
6631       footers in this PLCF, UpdateIndex does that task.
6632       */
6633     for( sal_uInt8 nI = 0x1; nI <= 0x20; nI <<= 1 )
6634         if( nI & rDop.grpfIhdt )                // Bit gesetzt ?
6635             nIdxOffset++;
6636 
6637     nTextOfs = rFib.ccpText + rFib.ccpFtn;  // Groesse des Haupttextes
6638                                             // und der Fussnoten
6639 }
6640 
6641 bool WW8PLCF_HdFt::GetTextPos(sal_uInt8 grpfIhdt, sal_uInt8 nWhich, WW8_CP& rStart,
6642     long& rLen)
6643 {
6644     sal_uInt8 nI = 0x01;
6645     short nIdx = nIdxOffset;
6646     while (true)
6647     {
6648         if( nI & nWhich )
6649             break;                      // found
6650         if( grpfIhdt & nI )
6651             nIdx++;                     // uninteresting Header / Footer
6652         nI <<= 1;                       // text next bit
6653         if( nI > 0x20 )
6654             return false;               // not found
6655     }
6656                                         // nIdx ist HdFt-Index
6657     WW8_CP nEnd;
6658     void* pData;
6659 
6660     aPLCF.SetIdx( nIdx );               // Lookup suitable CP
6661     aPLCF.Get( rStart, nEnd, pData );
6662     rLen = nEnd - rStart;
6663     aPLCF++;
6664 
6665     return true;
6666 }
6667 
6668 bool WW8PLCF_HdFt::GetTextPosExact(short nIdx, WW8_CP& rStart, long& rLen)
6669 {
6670     WW8_CP nEnd;
6671     void* pData;
6672 
6673     aPLCF.SetIdx( nIdx );               // Lookup suitable CP
6674     aPLCF.Get( rStart, nEnd, pData );
6675     rLen = nEnd - rStart;
6676     return true;
6677 }
6678 
6679 void WW8PLCF_HdFt::UpdateIndex( sal_uInt8 grpfIhdt )
6680 {
6681     // Caution: Description is not correct
6682     for( sal_uInt8 nI = 0x01; nI <= 0x20; nI <<= 1 )
6683         if( nI & grpfIhdt )
6684             nIdxOffset++;
6685 }
6686 
6687 //-----------------------------------------
6688 //          WW8Dop
6689 //-----------------------------------------
6690 
6691 WW8Dop::WW8Dop(SvStream& rSt, sal_Int16 nFib, sal_Int32 nPos, sal_uInt32 nSize) : bUseThaiLineBreakingRules(false)
6692 {
6693     memset( &nDataStart, 0, (&nDataEnd - &nDataStart) );
6694     fDontUseHTMLAutoSpacing = true; //default
6695     fAcetateShowAtn = true; //default
6696     const sal_uInt32 nMaxDopSize = 0x268;
6697     sal_uInt8* pDataPtr = new sal_uInt8[ nMaxDopSize ];
6698     sal_uInt8* pData = pDataPtr;
6699 
6700     sal_uInt32 nRead = nMaxDopSize < nSize ? nMaxDopSize : nSize;
6701     rSt.Seek( nPos );
6702     if (2 > nSize || nRead != rSt.Read(pData, nRead))
6703         nDopError = ERR_SWG_READ_ERROR;     // Error melden
6704     else
6705     {
6706         if (nMaxDopSize > nRead)
6707             memset( pData + nRead, 0, nMaxDopSize - nRead );
6708 
6709         // dann mal die Daten auswerten
6710         sal_uInt32 a32Bit;
6711         sal_uInt16 a16Bit;
6712         sal_uInt8   a8Bit;
6713 
6714         a16Bit = Get_UShort( pData );        // 0 0x00
6715         fFacingPages        = 0 != ( a16Bit  &  0x0001 )     ;
6716         fWidowControl       = 0 != ( a16Bit  &  0x0002 )     ;
6717         fPMHMainDoc         = 0 != ( a16Bit  &  0x0004 )     ;
6718         grfSuppression      =      ( a16Bit  &  0x0018 ) >> 3;
6719         fpc                 =      ( a16Bit  &  0x0060 ) >> 5;
6720         grpfIhdt            =      ( a16Bit  &  0xff00 ) >> 8;
6721 
6722         a16Bit = Get_UShort( pData );        // 2 0x02
6723         rncFtn              =   a16Bit  &  0x0003        ;
6724         nFtn                = ( a16Bit  & ~0x0003 ) >> 2 ;
6725 
6726         a8Bit = Get_Byte( pData );           // 4 0x04
6727         fOutlineDirtySave      = 0 != ( a8Bit  &  0x01   );
6728 
6729         a8Bit = Get_Byte( pData );           // 5 0x05
6730         fOnlyMacPics           = 0 != ( a8Bit  &  0x01   );
6731         fOnlyWinPics           = 0 != ( a8Bit  &  0x02   );
6732         fLabelDoc              = 0 != ( a8Bit  &  0x04   );
6733         fHyphCapitals          = 0 != ( a8Bit  &  0x08   );
6734         fAutoHyphen            = 0 != ( a8Bit  &  0x10   );
6735         fFormNoFields          = 0 != ( a8Bit  &  0x20   );
6736         fLinkStyles            = 0 != ( a8Bit  &  0x40   );
6737         fRevMarking            = 0 != ( a8Bit  &  0x80   );
6738 
6739         a8Bit = Get_Byte( pData );           // 6 0x06
6740         fBackup                = 0 != ( a8Bit  &  0x01   );
6741         fExactCWords           = 0 != ( a8Bit  &  0x02   );
6742         fPagHidden             = 0 != ( a8Bit  &  0x04   );
6743         fPagResults            = 0 != ( a8Bit  &  0x08   );
6744         fLockAtn               = 0 != ( a8Bit  &  0x10   );
6745         fMirrorMargins         = 0 != ( a8Bit  &  0x20   );
6746         fReadOnlyRecommended   = 0 != ( a8Bit  &  0x40   );
6747         fDfltTrueType          = 0 != ( a8Bit  &  0x80   );
6748 
6749         a8Bit = Get_Byte( pData );           // 7 0x07
6750         fPagSuppressTopSpacing = 0 != ( a8Bit  &  0x01   );
6751         fProtEnabled           = 0 != ( a8Bit  &  0x02   );
6752         fDispFormFldSel        = 0 != ( a8Bit  &  0x04   );
6753         fRMView                = 0 != ( a8Bit  &  0x08   );
6754         fRMPrint               = 0 != ( a8Bit  &  0x10   );
6755         fWriteReservation      = 0 != ( a8Bit  &  0x20   );
6756         fLockRev               = 0 != ( a8Bit  &  0x40   );
6757         fEmbedFonts            = 0 != ( a8Bit  &  0x80   );
6758 
6759 
6760         a8Bit = Get_Byte( pData );           // 8 0x08
6761         copts_fNoTabForInd           = 0 != ( a8Bit  &  0x01   );
6762         copts_fNoSpaceRaiseLower     = 0 != ( a8Bit  &  0x02   );
6763         copts_fSupressSpbfAfterPgBrk = 0 != ( a8Bit  &  0x04   );
6764         copts_fWrapTrailSpaces       = 0 != ( a8Bit  &  0x08   );
6765         copts_fMapPrintTextColor     = 0 != ( a8Bit  &  0x10   );
6766         copts_fNoColumnBalance       = 0 != ( a8Bit  &  0x20   );
6767         copts_fConvMailMergeEsc      = 0 != ( a8Bit  &  0x40   );
6768         copts_fSupressTopSpacing     = 0 != ( a8Bit  &  0x80   );
6769 
6770         a8Bit = Get_Byte( pData );           // 9 0x09
6771         copts_fOrigWordTableRules    = 0 != ( a8Bit  &  0x01   );
6772         copts_fTransparentMetafiles  = 0 != ( a8Bit  &  0x02   );
6773         copts_fShowBreaksInFrames    = 0 != ( a8Bit  &  0x04   );
6774         copts_fSwapBordersFacingPgs  = 0 != ( a8Bit  &  0x08   );
6775         copts_fExpShRtn              = 0 != ( a8Bit  &  0x20   );  // #i56856#
6776 
6777         dxaTab = Get_Short( pData );         // 10 0x0a
6778         wSpare = Get_UShort( pData );        // 12 0x0c
6779         dxaHotZ = Get_UShort( pData );       // 14 0x0e
6780         cConsecHypLim = Get_UShort( pData ); // 16 0x10
6781         wSpare2 = Get_UShort( pData );       // 18 0x12
6782         dttmCreated = Get_Long( pData );     // 20 0x14
6783         dttmRevised = Get_Long( pData );     // 24 0x18
6784         dttmLastPrint = Get_Long( pData );   // 28 0x1c
6785         nRevision = Get_Short( pData );      // 32 0x20
6786         tmEdited = Get_Long( pData );        // 34 0x22
6787         cWords = Get_Long( pData );          // 38 0x26
6788         cCh = Get_Long( pData );             // 42 0x2a
6789         cPg = Get_Short( pData );            // 46 0x2e
6790         cParas = Get_Long( pData );          // 48 0x30
6791 
6792         a16Bit = Get_UShort( pData );        // 52 0x34
6793         rncEdn =   a16Bit &  0x0003       ;
6794         nEdn   = ( a16Bit & ~0x0003 ) >> 2;
6795 
6796         a16Bit = Get_UShort( pData );        // 54 0x36
6797         epc            =   a16Bit &  0x0003       ;
6798         nfcFtnRef      = ( a16Bit &  0x003c ) >> 2;
6799         nfcEdnRef      = ( a16Bit &  0x03c0 ) >> 6;
6800         fPrintFormData = 0 != ( a16Bit &  0x0400 );
6801         fSaveFormData  = 0 != ( a16Bit &  0x0800 );
6802         fShadeFormData = 0 != ( a16Bit &  0x1000 );
6803         fWCFtnEdn      = 0 != ( a16Bit &  0x8000 );
6804 
6805         cLines = Get_Long( pData );          // 56 0x38
6806         cWordsFtnEnd = Get_Long( pData );    // 60 0x3c
6807         cChFtnEdn = Get_Long( pData );       // 64 0x40
6808         cPgFtnEdn = Get_Short( pData );      // 68 0x44
6809         cParasFtnEdn = Get_Long( pData );    // 70 0x46
6810         cLinesFtnEdn = Get_Long( pData );    // 74 0x4a
6811         lKeyProtDoc = Get_Long( pData );     // 78 0x4e
6812 
6813         a16Bit = Get_UShort( pData );        // 82 0x52
6814         wvkSaved    =   a16Bit & 0x0007        ;
6815         wScaleSaved = ( a16Bit & 0x0ff8 ) >> 3 ;
6816         zkSaved     = ( a16Bit & 0x3000 ) >> 12;
6817         fRotateFontW6 = ( a16Bit & 0x4000 ) >> 14;
6818         iGutterPos = ( a16Bit &  0x8000 ) >> 15;
6819         /*
6820             bei nFib >= 103 gehts weiter:
6821         */
6822         if (nFib >= 103) // Word 6/32bit, 95, 97, 2000, 2002, 2003, 2007
6823         {
6824             a32Bit = Get_ULong( pData );     // 84 0x54
6825             SetCompatabilityOptions(a32Bit);
6826         }
6827 
6828         //#i22436#, for all WW7- documents
6829         if (nFib <= 104) // Word 95
6830             fUsePrinterMetrics = 1;
6831 
6832         /*
6833             bei nFib > 105 gehts weiter:
6834         */
6835         if (nFib > 105) // Word 97, 2000, 2002, 2003, 2007
6836         {
6837             adt = Get_Short( pData );            // 88 0x58
6838 
6839             doptypography.ReadFromMem(pData);    // 90 0x5a
6840 
6841             memcpy( &dogrid, pData, sizeof( WW8_DOGRID )); // 400 0x190
6842             pData += sizeof( WW8_DOGRID );
6843 
6844             a16Bit = Get_UShort( pData );        // 410 0x19a
6845             // die untersten 9 Bit sind uninteressant
6846             fHtmlDoc                = ( a16Bit &  0x0200 ) >>  9 ;
6847             fSnapBorder             = ( a16Bit &  0x0800 ) >> 11 ;
6848             fIncludeHeader          = ( a16Bit &  0x1000 ) >> 12 ;
6849             fIncludeFooter          = ( a16Bit &  0x2000 ) >> 13 ;
6850             fForcePageSizePag       = ( a16Bit &  0x4000 ) >> 14 ;
6851             fMinFontSizePag         = ( a16Bit &  0x8000 ) >> 15 ;
6852 
6853             a16Bit = Get_UShort( pData );        // 412 0x19c
6854             fHaveVersions   = 0 != ( a16Bit  &  0x0001 );
6855             fAutoVersion    = 0 != ( a16Bit  &  0x0002 );
6856 
6857             pData += 12;                         // 414 0x19e
6858 
6859             cChWS = Get_Long( pData );           // 426 0x1aa
6860             cChWSFtnEdn = Get_Long( pData );     // 430 0x1ae
6861             grfDocEvents = Get_Long( pData );    // 434 0x1b2
6862 
6863             pData += 4+30+8;  // 438 0x1b6; 442 0x1ba; 472 0x1d8; 476 0x1dc
6864 
6865             cDBC = Get_Long( pData );            // 480 0x1e0
6866             cDBCFtnEdn = Get_Long( pData );      // 484 0x1e4
6867 
6868             pData += 1 * sizeof( sal_Int32);         // 488 0x1e8
6869 
6870             nfcFtnRef = Get_Short( pData );      // 492 0x1ec
6871             nfcEdnRef = Get_Short( pData );      // 494 0x1ee
6872             hpsZoonFontPag = Get_Short( pData ); // 496 0x1f0
6873             dywDispPag = Get_Short( pData );     // 498 0x1f2
6874 
6875             if (nRead >= 516)
6876             {
6877                 //500 -> 508, Appear to be repeated here in 2000+
6878                 pData += 8;                      // 500 0x1f4
6879                 a32Bit = Get_Long( pData );      // 508 0x1fc
6880                 SetCompatabilityOptions(a32Bit);
6881                 a32Bit = Get_Long( pData );      // 512 0x200
6882 
6883 				// i#78591#
6884                 // fDontUseHTMLAutoSpacing = (a32Bit & 0x4) >> 2;
6885 				SetCompatabilityOptions2(a32Bit);
6886             }
6887             if (nRead >= 550)
6888             {
6889                 pData += 32;
6890                 a16Bit = Get_UShort( pData );
6891                 fDoNotEmbedSystemFont = ( a16Bit &  0x0001 );
6892                 fWordCompat = ( a16Bit &  0x0002 ) >> 1;
6893                 fLiveRecover = ( a16Bit &  0x0004 ) >> 2;
6894                 fEmbedFactoids = ( a16Bit &  0x0008 ) >> 3;
6895                 fFactoidXML = ( a16Bit &  0x00010 ) >> 4;
6896                 fFactoidAllDone = ( a16Bit &  0x0020 ) >> 5;
6897                 fFolioPrint = ( a16Bit &  0x0040 ) >> 6;
6898                 fReverseFolio = ( a16Bit &  0x0080 ) >> 7;
6899                 iTextLineEnding = ( a16Bit &  0x0700 ) >> 8;
6900                 fHideFcc = ( a16Bit &  0x0800 ) >> 11;
6901                 fAcetateShowMarkup = ( a16Bit &  0x1000 ) >> 12;
6902                 fAcetateShowAtn = ( a16Bit &  0x2000 ) >> 13;
6903                 fAcetateShowInsDel = ( a16Bit &  0x4000 ) >> 14;
6904                 fAcetateShowProps = ( a16Bit &  0x8000 ) >> 15;
6905             }
6906             if (nRead >= 600)
6907             {
6908                 pData += 48;
6909                 a16Bit = Get_Short(pData);
6910                 fUseBackGroundInAllmodes = (a16Bit & 0x0080) >> 7;
6911             }
6912         }
6913     }
6914     delete[] pDataPtr;
6915 }
6916 
6917 WW8Dop::WW8Dop() : bUseThaiLineBreakingRules(false)
6918 {
6919     // first set everything to a default of 0
6920     memset( &nDataStart, 0, (&nDataEnd - &nDataStart) );
6921 
6922     fWidowControl = 1;
6923     fpc = 1;
6924     nFtn = 1;
6925     fOutlineDirtySave = 1;
6926     fHyphCapitals = 1;
6927     fBackup = 1;
6928     fPagHidden = 1;
6929     fPagResults = 1;
6930     fDfltTrueType = 1;
6931 
6932     /*
6933     Writer acts like this all the time at the moment, ideally we need an
6934     option for these two as well to import word docs that are not like
6935     this by default
6936     */
6937     fNoLeading = 1;
6938     fUsePrinterMetrics = 1;
6939 
6940     fRMView = 1;
6941     fRMPrint = 1;
6942     dxaTab = 0x2d0;
6943     dxaHotZ = 0x168;
6944     nRevision = 1;
6945     nEdn = 1;
6946 
6947     epc = 3;
6948     nfcEdnRef = 2;
6949     fShadeFormData = 1;
6950 
6951     wvkSaved = 2;
6952     wScaleSaved = 100;
6953     zkSaved = 0;
6954 
6955     lvl = 9;
6956     fIncludeHeader = 1;
6957     fIncludeFooter = 1;
6958 
6959     cChWS = /**!!**/ 0;
6960     cChWSFtnEdn = /**!!**/ 0;
6961 
6962     cDBC = /**!!**/ 0;
6963     cDBCFtnEdn = /**!!**/ 0;
6964 
6965     fAcetateShowAtn = true;
6966 }
6967 
6968 void WW8Dop::SetCompatabilityOptions(sal_uInt32 a32Bit)
6969 {
6970     fNoTabForInd                = ( a32Bit &  0x00000001 )       ;
6971     fNoSpaceRaiseLower          = ( a32Bit &  0x00000002 ) >>  1 ;
6972     fSupressSpbfAfterPageBreak  = ( a32Bit &  0x00000004 ) >>  2 ;
6973     fWrapTrailSpaces            = ( a32Bit &  0x00000008 ) >>  3 ;
6974     fMapPrintTextColor          = ( a32Bit &  0x00000010 ) >>  4 ;
6975     fNoColumnBalance            = ( a32Bit &  0x00000020 ) >>  5 ;
6976     fConvMailMergeEsc           = ( a32Bit &  0x00000040 ) >>  6 ;
6977     fSupressTopSpacing          = ( a32Bit &  0x00000080 ) >>  7 ;
6978     fOrigWordTableRules         = ( a32Bit &  0x00000100 ) >>  8 ;
6979     fTransparentMetafiles       = ( a32Bit &  0x00000200 ) >>  9 ;
6980     fShowBreaksInFrames         = ( a32Bit &  0x00000400 ) >> 10 ;
6981     fSwapBordersFacingPgs       = ( a32Bit &  0x00000800 ) >> 11 ;
6982     fCompatabilityOptions_Unknown1_13       = ( a32Bit &  0x00001000 ) >> 12 ;
6983     fExpShRtn                   = ( a32Bit &  0x00002000 ) >> 13 ; // #i56856#
6984     fCompatabilityOptions_Unknown1_15       = ( a32Bit &  0x00004000 ) >> 14 ;
6985     fCompatabilityOptions_Unknown1_16       = ( a32Bit &  0x00008000 ) >> 15 ;
6986     fSuppressTopSpacingMac5     = ( a32Bit &  0x00010000 ) >> 16 ;
6987     fTruncDxaExpand             = ( a32Bit &  0x00020000 ) >> 17 ;
6988     fPrintBodyBeforeHdr         = ( a32Bit &  0x00040000 ) >> 18 ;
6989     fNoLeading                  = ( a32Bit &  0x00080000 ) >> 19 ;
6990     fCompatabilityOptions_Unknown1_21       = ( a32Bit &  0x00100000 ) >> 20 ;
6991     fMWSmallCaps                = ( a32Bit &  0x00200000 ) >> 21 ;
6992     fCompatabilityOptions_Unknown1_23       = ( a32Bit &  0x00400000 ) >> 22 ;
6993     fCompatabilityOptions_Unknown1_24       = ( a32Bit &  0x00800800 ) >> 23 ;
6994     fCompatabilityOptions_Unknown1_25       = ( a32Bit &  0x01000000 ) >> 24 ;
6995     fCompatabilityOptions_Unknown1_26       = ( a32Bit &  0x02000000 ) >> 25 ;
6996     fCompatabilityOptions_Unknown1_27       = ( a32Bit &  0x04000000 ) >> 26 ;
6997     fCompatabilityOptions_Unknown1_28       = ( a32Bit &  0x08000000 ) >> 27 ;
6998     fCompatabilityOptions_Unknown1_29       = ( a32Bit &  0x10000000 ) >> 28 ;
6999     fCompatabilityOptions_Unknown1_30       = ( a32Bit &  0x20000000 ) >> 29 ;
7000     fCompatabilityOptions_Unknown1_31       = ( a32Bit &  0x40000000 ) >> 30 ;
7001 
7002     fUsePrinterMetrics          = ( a32Bit &  0x80000000 ) >> 31 ;
7003 }
7004 
7005 sal_uInt32 WW8Dop::GetCompatabilityOptions() const
7006 {
7007     sal_uInt32 a32Bit = 0;
7008     if (fNoTabForInd)                   a32Bit |= 0x00000001;
7009     if (fNoSpaceRaiseLower)             a32Bit |= 0x00000002;
7010     if (fSupressSpbfAfterPageBreak)     a32Bit |= 0x00000004;
7011     if (fWrapTrailSpaces)               a32Bit |= 0x00000008;
7012     if (fMapPrintTextColor)             a32Bit |= 0x00000010;
7013     if (fNoColumnBalance)               a32Bit |= 0x00000020;
7014     if (fConvMailMergeEsc)              a32Bit |= 0x00000040;
7015     if (fSupressTopSpacing)             a32Bit |= 0x00000080;
7016     if (fOrigWordTableRules)            a32Bit |= 0x00000100;
7017     if (fTransparentMetafiles)          a32Bit |= 0x00000200;
7018     if (fShowBreaksInFrames)            a32Bit |= 0x00000400;
7019     if (fSwapBordersFacingPgs)          a32Bit |= 0x00000800;
7020     if (fCompatabilityOptions_Unknown1_13)          a32Bit |= 0x00001000;
7021     if (fExpShRtn)                      a32Bit |= 0x00002000; // #i56856#
7022     if (fCompatabilityOptions_Unknown1_15)          a32Bit |= 0x00004000;
7023     if (fCompatabilityOptions_Unknown1_16)          a32Bit |= 0x00008000;
7024     if (fSuppressTopSpacingMac5)        a32Bit |= 0x00010000;
7025     if (fTruncDxaExpand)                a32Bit |= 0x00020000;
7026     if (fPrintBodyBeforeHdr)            a32Bit |= 0x00040000;
7027     if (fNoLeading)                     a32Bit |= 0x00080000;
7028     if (fCompatabilityOptions_Unknown1_21)          a32Bit |= 0x00100000;
7029     if (fMWSmallCaps)                   a32Bit |= 0x00200000;
7030     if (fCompatabilityOptions_Unknown1_23)          a32Bit |= 0x00400000;
7031     if (fCompatabilityOptions_Unknown1_24)          a32Bit |= 0x00800000;
7032     if (fCompatabilityOptions_Unknown1_25)          a32Bit |= 0x01000000;
7033     if (fCompatabilityOptions_Unknown1_26)          a32Bit |= 0x02000000;
7034     if (fCompatabilityOptions_Unknown1_27)          a32Bit |= 0x04000000;
7035     if (fCompatabilityOptions_Unknown1_28)          a32Bit |= 0x08000000;
7036     if (fCompatabilityOptions_Unknown1_29)          a32Bit |= 0x10000000;
7037     if (fCompatabilityOptions_Unknown1_30)          a32Bit |= 0x20000000;
7038     if (fCompatabilityOptions_Unknown1_31)          a32Bit |= 0x40000000;
7039     if (fUsePrinterMetrics)             a32Bit |= 0x80000000;
7040     return a32Bit;
7041 }
7042 
7043 // i#78591#
7044 void WW8Dop::SetCompatabilityOptions2(sal_uInt32 a32Bit)
7045 {
7046 	fCompatabilityOptions_Unknown2_1 						= ( a32Bit &  0x00000001 );
7047     fCompatabilityOptions_Unknown2_2						= ( a32Bit &  0x00000002 ) >>  1 ;
7048     fDontUseHTMLAutoSpacing		= ( a32Bit &  0x00000004 ) >>  2 ;
7049 	fCompatabilityOptions_Unknown2_4					= ( a32Bit &  0x00000008 ) >>  3 ;
7050    	fCompatabilityOptions_Unknown2_5					= ( a32Bit &  0x00000010 ) >>  4 ;
7051    	fCompatabilityOptions_Unknown2_6					= ( a32Bit &  0x00000020 ) >>  5 ;
7052    	fCompatabilityOptions_Unknown2_7					= ( a32Bit &  0x00000040 ) >>  6 ;
7053    	fCompatabilityOptions_Unknown2_8					= ( a32Bit &  0x00000080 ) >>  7 ;
7054    	fCompatabilityOptions_Unknown2_9					= ( a32Bit &  0x00000100 ) >>  8 ;
7055    	fCompatabilityOptions_Unknown2_10					= ( a32Bit &  0x00000200 ) >>  9 ;
7056    	fCompatabilityOptions_Unknown2_11					= ( a32Bit &  0x00000400 ) >> 10 ;
7057    	fCompatabilityOptions_Unknown2_12					= ( a32Bit &  0x00000800 ) >> 11 ;
7058 	fCompatabilityOptions_Unknown2_13					= ( a32Bit &  0x00001000 ) >> 12 ;
7059 	fCompatabilityOptions_Unknown2_14					= ( a32Bit &  0x00002000 ) >> 13 ;
7060 	fCompatabilityOptions_Unknown2_15					= ( a32Bit &  0x00004000 ) >> 14 ;
7061 	fCompatabilityOptions_Unknown2_16					= ( a32Bit &  0x00008000 ) >> 15 ;
7062    	fCompatabilityOptions_Unknown2_17					= ( a32Bit &  0x00010000 ) >> 16 ;
7063    	fCompatabilityOptions_Unknown2_18					= ( a32Bit &  0x00020000 ) >> 17 ;
7064    	fCompatabilityOptions_Unknown2_19					= ( a32Bit &  0x00040000 ) >> 18 ;
7065    	fCompatabilityOptions_Unknown2_20					= ( a32Bit &  0x00080000 ) >> 19 ;
7066 	fCompatabilityOptions_Unknown2_21					= ( a32Bit &  0x00100000 ) >> 20 ;
7067    	fCompatabilityOptions_Unknown2_22					= ( a32Bit &  0x00200000 ) >> 21 ;
7068 	fCompatabilityOptions_Unknown2_23					= ( a32Bit &  0x00400000 ) >> 22 ;
7069 	fCompatabilityOptions_Unknown2_24					= ( a32Bit &  0x00800800 ) >> 23 ;
7070 	fCompatabilityOptions_Unknown2_25					= ( a32Bit &  0x01000800 ) >> 24 ;
7071 	fCompatabilityOptions_Unknown2_26					= ( a32Bit &  0x02000800 ) >> 25 ;
7072 	fCompatabilityOptions_Unknown2_27					= ( a32Bit &  0x04000800 ) >> 26 ;
7073 	fCompatabilityOptions_Unknown2_28					= ( a32Bit &  0x08000800 ) >> 27 ;
7074 	fCompatabilityOptions_Unknown2_29					= ( a32Bit &  0x10000800 ) >> 28 ;
7075 	fCompatabilityOptions_Unknown2_30					= ( a32Bit &  0x20000800 ) >> 29 ;
7076 	fCompatabilityOptions_Unknown2_31					= ( a32Bit &  0x40000800 ) >> 30 ;
7077    	fCompatabilityOptions_Unknown2_32					= ( a32Bit &  0x80000000 ) >> 31 ;
7078 }
7079 
7080 sal_uInt32 WW8Dop::GetCompatabilityOptions2() const
7081 {
7082     sal_uInt32 a32Bit = 0;
7083     if (fCompatabilityOptions_Unknown2_1)			a32Bit |= 0x00000001;
7084     if (fCompatabilityOptions_Unknown2_2)           a32Bit |= 0x00000002;
7085     if (fDontUseHTMLAutoSpacing)     a32Bit |= 0x00000004;
7086     if (fCompatabilityOptions_Unknown2_4)           a32Bit |= 0x00000008;
7087     if (fCompatabilityOptions_Unknown2_5)           a32Bit |= 0x00000010;
7088     if (fCompatabilityOptions_Unknown2_6)           a32Bit |= 0x00000020;
7089     if (fCompatabilityOptions_Unknown2_7)           a32Bit |= 0x00000040;
7090     if (fCompatabilityOptions_Unknown2_8)           a32Bit |= 0x00000080;
7091     if (fCompatabilityOptions_Unknown2_9)           a32Bit |= 0x00000100;
7092     if (fCompatabilityOptions_Unknown2_10)          a32Bit |= 0x00000200;
7093     if (fCompatabilityOptions_Unknown2_11)          a32Bit |= 0x00000400;
7094     if (fCompatabilityOptions_Unknown2_12)          a32Bit |= 0x00000800;
7095     if (fCompatabilityOptions_Unknown2_13)          a32Bit |= 0x00001000;
7096 	//#i42909# set thai "line breaking rules" compatibility option
7097 	// pflin, wonder whether bUseThaiLineBreakingRules is correct
7098 	// when importing word document.
7099     if (bUseThaiLineBreakingRules)          a32Bit |= 0x00002000;
7100 	else if (fCompatabilityOptions_Unknown2_14) 		a32Bit |= 0x00002000;
7101     if (fCompatabilityOptions_Unknown2_15)          a32Bit |= 0x00004000;
7102     if (fCompatabilityOptions_Unknown2_16)          a32Bit |= 0x00008000;
7103     if (fCompatabilityOptions_Unknown2_17)        	a32Bit |= 0x00010000;
7104     if (fCompatabilityOptions_Unknown2_18)          a32Bit |= 0x00020000;
7105     if (fCompatabilityOptions_Unknown2_19)          a32Bit |= 0x00040000;
7106     if (fCompatabilityOptions_Unknown2_20)          a32Bit |= 0x00080000;
7107     if (fCompatabilityOptions_Unknown2_21)          a32Bit |= 0x00100000;
7108     if (fCompatabilityOptions_Unknown2_22)          a32Bit |= 0x00200000;
7109     if (fCompatabilityOptions_Unknown2_23)          a32Bit |= 0x00400000;
7110     if (fCompatabilityOptions_Unknown2_24)          a32Bit |= 0x00800000;
7111     if (fCompatabilityOptions_Unknown2_25)          a32Bit |= 0x01000000;
7112     if (fCompatabilityOptions_Unknown2_26)          a32Bit |= 0x02000000;
7113     if (fCompatabilityOptions_Unknown2_27)          a32Bit |= 0x04000000;
7114     if (fCompatabilityOptions_Unknown2_28)          a32Bit |= 0x08000000;
7115     if (fCompatabilityOptions_Unknown2_29)          a32Bit |= 0x10000000;
7116     if (fCompatabilityOptions_Unknown2_30)          a32Bit |= 0x20000000;
7117     if (fCompatabilityOptions_Unknown2_31)          a32Bit |= 0x40000000;
7118     if (fCompatabilityOptions_Unknown2_32)          a32Bit |= 0x80000000;
7119     return a32Bit;
7120 }
7121 
7122 bool WW8Dop::Write(SvStream& rStrm, WW8Fib& rFib) const
7123 {
7124     const int nMaxDopLen = 610;
7125     sal_uInt32 nLen = 8 == rFib.nVersion ? nMaxDopLen : 84;
7126     rFib.fcDop =  rStrm.Tell();
7127     rFib.lcbDop = nLen;
7128 
7129     sal_uInt8 aData[ nMaxDopLen ];
7130     memset( aData, 0, nMaxDopLen );
7131     sal_uInt8* pData = aData;
7132 
7133     // dann mal die Daten auswerten
7134     sal_uInt16 a16Bit;
7135     sal_uInt8   a8Bit;
7136 
7137     a16Bit = 0;                         // 0 0x00
7138     if (fFacingPages)
7139         a16Bit |= 0x0001;
7140     if (fWidowControl)
7141         a16Bit |= 0x0002;
7142     if (fPMHMainDoc)
7143         a16Bit |= 0x0004;
7144     a16Bit |= ( 0x0018 & (grfSuppression << 3));
7145     a16Bit |= ( 0x0060 & (fpc << 5));
7146     a16Bit |= ( 0xff00 & (grpfIhdt << 8));
7147     Set_UInt16( pData, a16Bit );
7148 
7149     a16Bit = 0;                         // 2 0x02
7150     a16Bit |= ( 0x0003 & rncFtn );
7151     a16Bit |= ( ~0x0003 & (nFtn << 2));
7152     Set_UInt16( pData, a16Bit );
7153 
7154     a8Bit = 0;                          // 4 0x04
7155     if( fOutlineDirtySave ) a8Bit |= 0x01;
7156     Set_UInt8( pData, a8Bit );
7157 
7158     a8Bit = 0;                          // 5 0x05
7159     if( fOnlyMacPics )  a8Bit |= 0x01;
7160     if( fOnlyWinPics )  a8Bit |= 0x02;
7161     if( fLabelDoc )     a8Bit |= 0x04;
7162     if( fHyphCapitals ) a8Bit |= 0x08;
7163     if( fAutoHyphen )   a8Bit |= 0x10;
7164     if( fFormNoFields ) a8Bit |= 0x20;
7165     if( fLinkStyles )   a8Bit |= 0x40;
7166     if( fRevMarking )   a8Bit |= 0x80;
7167     Set_UInt8( pData, a8Bit );
7168 
7169     a8Bit = 0;                          // 6 0x06
7170     if( fBackup )               a8Bit |= 0x01;
7171     if( fExactCWords )          a8Bit |= 0x02;
7172     if( fPagHidden )            a8Bit |= 0x04;
7173     if( fPagResults )           a8Bit |= 0x08;
7174     if( fLockAtn )              a8Bit |= 0x10;
7175     if( fMirrorMargins )        a8Bit |= 0x20;
7176     if( fReadOnlyRecommended )  a8Bit |= 0x40;
7177     if( fDfltTrueType )         a8Bit |= 0x80;
7178     Set_UInt8( pData, a8Bit );
7179 
7180     a8Bit = 0;                          // 7 0x07
7181     if( fPagSuppressTopSpacing )    a8Bit |= 0x01;
7182     if( fProtEnabled )              a8Bit |= 0x02;
7183     if( fDispFormFldSel )           a8Bit |= 0x04;
7184     if( fRMView )                   a8Bit |= 0x08;
7185     if( fRMPrint )                  a8Bit |= 0x10;
7186     if( fWriteReservation )         a8Bit |= 0x20;
7187     if( fLockRev )                  a8Bit |= 0x40;
7188     if( fEmbedFonts )               a8Bit |= 0x80;
7189     Set_UInt8( pData, a8Bit );
7190 
7191 
7192     a8Bit = 0;                          // 8 0x08
7193     if( copts_fNoTabForInd )            a8Bit |= 0x01;
7194     if( copts_fNoSpaceRaiseLower )      a8Bit |= 0x02;
7195     if( copts_fSupressSpbfAfterPgBrk )  a8Bit |= 0x04;
7196     if( copts_fWrapTrailSpaces )        a8Bit |= 0x08;
7197     if( copts_fMapPrintTextColor )      a8Bit |= 0x10;
7198     if( copts_fNoColumnBalance )        a8Bit |= 0x20;
7199     if( copts_fConvMailMergeEsc )       a8Bit |= 0x40;
7200     if( copts_fSupressTopSpacing )      a8Bit |= 0x80;
7201     Set_UInt8( pData, a8Bit );
7202 
7203     a8Bit = 0;                          // 9 0x09
7204     if( copts_fOrigWordTableRules )     a8Bit |= 0x01;
7205     if( copts_fTransparentMetafiles )   a8Bit |= 0x02;
7206     if( copts_fShowBreaksInFrames )     a8Bit |= 0x04;
7207     if( copts_fSwapBordersFacingPgs )   a8Bit |= 0x08;
7208     if( copts_fExpShRtn )               a8Bit |= 0x20;  // #i56856#
7209     Set_UInt8( pData, a8Bit );
7210 
7211     Set_UInt16( pData, dxaTab );        // 10 0x0a
7212     Set_UInt16( pData, wSpare );        // 12 0x0c
7213     Set_UInt16( pData, dxaHotZ );       // 14 0x0e
7214     Set_UInt16( pData, cConsecHypLim ); // 16 0x10
7215     Set_UInt16( pData, wSpare2 );       // 18 0x12
7216     Set_UInt32( pData, dttmCreated );   // 20 0x14
7217     Set_UInt32( pData, dttmRevised );   // 24 0x18
7218     Set_UInt32( pData, dttmLastPrint ); // 28 0x1c
7219     Set_UInt16( pData, nRevision );     // 32 0x20
7220     Set_UInt32( pData, tmEdited );      // 34 0x22
7221     Set_UInt32( pData, cWords );        // 38 0x26
7222     Set_UInt32( pData, cCh );           // 42 0x2a
7223     Set_UInt16( pData, cPg );           // 46 0x2e
7224     Set_UInt32( pData, cParas );        // 48 0x30
7225 
7226     a16Bit = 0;                         // 52 0x34
7227     a16Bit |= ( 0x0003 & rncEdn );
7228     a16Bit |= (~0x0003 & ( nEdn << 2));
7229     Set_UInt16( pData, a16Bit );
7230 
7231     a16Bit = 0;                         // 54 0x36
7232     a16Bit |= (0x0003 & epc );
7233     a16Bit |= (0x003c & (nfcFtnRef << 2));
7234     a16Bit |= (0x03c0 & (nfcEdnRef << 6));
7235     if( fPrintFormData )    a16Bit |= 0x0400;
7236     if( fSaveFormData )     a16Bit |= 0x0800;
7237     if( fShadeFormData )    a16Bit |= 0x1000;
7238     if( fWCFtnEdn )         a16Bit |= 0x8000;
7239     Set_UInt16( pData, a16Bit );
7240 
7241     Set_UInt32( pData, cLines );        // 56 0x38
7242     Set_UInt32( pData, cWordsFtnEnd );  // 60 0x3c
7243     Set_UInt32( pData, cChFtnEdn );     // 64 0x40
7244     Set_UInt16( pData, cPgFtnEdn );     // 68 0x44
7245     Set_UInt32( pData, cParasFtnEdn );  // 70 0x46
7246     Set_UInt32( pData, cLinesFtnEdn );  // 74 0x4a
7247     Set_UInt32( pData, lKeyProtDoc );   // 78 0x4e
7248 
7249     a16Bit = 0;                         // 82 0x52
7250     if (wvkSaved)
7251         a16Bit |= 0x0007;
7252     a16Bit |= (0x0ff8 & (wScaleSaved << 3));
7253     a16Bit |= (0x3000 & (zkSaved << 12));
7254     Set_UInt16( pData, a16Bit );
7255 
7256     if( 8 == rFib.nVersion )
7257     {
7258         Set_UInt32(pData, GetCompatabilityOptions());  // 84 0x54
7259 
7260         Set_UInt16( pData, adt );                      // 88 0x58
7261 
7262         doptypography.WriteToMem(pData);               // 400 0x190
7263 
7264         memcpy( pData, &dogrid, sizeof( WW8_DOGRID ));
7265         pData += sizeof( WW8_DOGRID );
7266 
7267         a16Bit = 0x12;      // lvl auf 9 setzen        // 410 0x19a
7268         if( fHtmlDoc )          a16Bit |= 0x0200;
7269         if( fSnapBorder )       a16Bit |= 0x0800;
7270         if( fIncludeHeader )    a16Bit |= 0x1000;
7271         if( fIncludeFooter )    a16Bit |= 0x2000;
7272         if( fForcePageSizePag ) a16Bit |= 0x4000;
7273         if( fMinFontSizePag )   a16Bit |= 0x8000;
7274         Set_UInt16( pData, a16Bit );
7275 
7276         a16Bit = 0;                                    // 412 0x19c
7277         if( fHaveVersions ) a16Bit |= 0x0001;
7278         if( fAutoVersion )  a16Bit |= 0x0002;
7279         Set_UInt16( pData, a16Bit );
7280 
7281         pData += 12;                                   // 414 0x19e
7282 
7283         Set_UInt32( pData, cChWS );                    // 426 0x1aa
7284         Set_UInt32( pData, cChWSFtnEdn );              // 430 0x1ae
7285         Set_UInt32( pData, grfDocEvents );             // 434 0x1b2
7286 
7287         pData += 4+30+8;  // 438 0x1b6; 442 0x1ba; 472 0x1d8; 476 0x1dc
7288 
7289         Set_UInt32( pData, cDBC );                     // 480 0x1e0
7290         Set_UInt32( pData, cDBCFtnEdn );               // 484 0x1e4
7291 
7292         pData += 1 * sizeof( sal_Int32);                   // 488 0x1e8
7293 
7294         Set_UInt16( pData, nfcFtnRef );                // 492 0x1ec
7295         Set_UInt16( pData, nfcEdnRef );                // 494 0x1ee
7296         Set_UInt16( pData, hpsZoonFontPag );           // 496 0x1f0
7297         Set_UInt16( pData, dywDispPag );               // 498 0x1f2
7298 
7299         //500 -> 508, Appear to be repeated here in 2000+
7300         pData += 8;
7301         Set_UInt32(pData, GetCompatabilityOptions());
7302 		Set_UInt32(pData, GetCompatabilityOptions2());
7303         pData += 32;
7304 
7305         a16Bit = 0;
7306         if (fAcetateShowMarkup)
7307             a16Bit |= 0x1000;
7308         //Word XP at least requires fAcetateShowMarkup to honour fAcetateShowAtn
7309         if (fAcetateShowAtn)
7310         {
7311             a16Bit |= 0x1000;
7312             a16Bit |= 0x2000;
7313         }
7314         Set_UInt16(pData, a16Bit);
7315 
7316         pData += 48;
7317         a16Bit = 0x0080;
7318         Set_UInt16(pData, a16Bit);
7319     }
7320     rStrm.Write( aData, nLen );
7321     return 0 == rStrm.GetError();
7322 }
7323 
7324 void WW8DopTypography::ReadFromMem(sal_uInt8 *&pData)
7325 {
7326     sal_uInt16 a16Bit = Get_UShort(pData);
7327     fKerningPunct = (a16Bit & 0x0001);
7328     iJustification = (a16Bit & 0x0006) >>  1;
7329     iLevelOfKinsoku = (a16Bit & 0x0018) >>  3;
7330     f2on1 = (a16Bit & 0x0020) >>  5;
7331     reserved1 = (a16Bit & 0x03C0) >>  6;
7332     reserved2 = (a16Bit & 0xFC00) >>  10;
7333 
7334     cchFollowingPunct = Get_Short(pData);
7335     cchLeadingPunct = Get_Short(pData);
7336 
7337     sal_Int16 i;
7338     for (i=0; i < nMaxFollowing; ++i)
7339         rgxchFPunct[i] = Get_Short(pData);
7340     for (i=0; i < nMaxLeading; ++i)
7341         rgxchLPunct[i] = Get_Short(pData);
7342 
7343     if (cchFollowingPunct >= 0 && cchFollowingPunct < nMaxFollowing)
7344         rgxchFPunct[cchFollowingPunct]=0;
7345     else
7346         rgxchFPunct[nMaxFollowing - 1]=0;
7347 
7348     if (cchLeadingPunct >= 0 && cchLeadingPunct < nMaxLeading)
7349         rgxchLPunct[cchLeadingPunct]=0;
7350     else
7351         rgxchLPunct[nMaxLeading - 1]=0;
7352 
7353 }
7354 
7355 void WW8DopTypography::WriteToMem(sal_uInt8 *&pData) const
7356 {
7357     sal_uInt16 a16Bit = fKerningPunct;
7358     a16Bit |= (iJustification << 1) & 0x0006;
7359     a16Bit |= (iLevelOfKinsoku << 3) & 0x0018;
7360     a16Bit |= (f2on1 << 5) & 0x002;
7361     a16Bit |= (reserved1 << 6) & 0x03C0;
7362     a16Bit |= (reserved2 << 10) & 0xFC00;
7363     Set_UInt16(pData,a16Bit);
7364 
7365     Set_UInt16(pData,cchFollowingPunct);
7366     Set_UInt16(pData,cchLeadingPunct);
7367 
7368     sal_Int16 i;
7369     for (i=0; i < nMaxFollowing; ++i)
7370         Set_UInt16(pData,rgxchFPunct[i]);
7371     for (i=0; i < nMaxLeading; ++i)
7372         Set_UInt16(pData,rgxchLPunct[i]);
7373 }
7374 
7375 sal_uInt16 WW8DopTypography::GetConvertedLang() const
7376 {
7377     sal_uInt16 nLang;
7378     //I have assumed peoples republic/taiwan == simplified/traditional
7379 
7380     //This isn't a documented issue, so we might have it all wrong,
7381     //i.e. i.e. whats with the powers of two ?
7382 
7383     /*
7384     #84082#
7385     One example of 3 for reserved1 which was really Japanese, perhaps last bit
7386     is for some other use ?, or redundant. If more examples trigger the assert
7387     we might be able to figure it out.
7388     */
7389     switch(reserved1 & 0xE)
7390     {
7391         case 2:     //Japan
7392             nLang = LANGUAGE_JAPANESE;
7393             break;
7394         case 4:     //Chinese (Peoples Republic)
7395             nLang = LANGUAGE_CHINESE_SIMPLIFIED;
7396             break;
7397         case 6:     //Korean
7398             nLang = LANGUAGE_KOREAN;
7399             break;
7400         case 8:     //Chinese (Taiwan)
7401             nLang = LANGUAGE_CHINESE_TRADITIONAL;
7402             break;
7403         default:
7404             ASSERT(!this, "Unknown MS Asian Typography language, report");
7405             nLang = LANGUAGE_CHINESE;
7406             break;
7407         case 0:
7408             //And here we have the possibility that it says 2, but its really
7409             //a bug and only japanese level 2 has been selected after a custom
7410             //version was chosen on last save!
7411             nLang = LANGUAGE_JAPANESE;
7412             break;
7413     }
7414     return nLang;
7415 }
7416 
7417 //-----------------------------------------
7418 //              Sprms
7419 //-----------------------------------------
7420 sal_uInt16 wwSprmParser::GetSprmTailLen(sal_uInt16 nId, const sal_uInt8* pSprm)
7421     const
7422 {
7423     SprmInfo aSprm = GetSprmInfo(nId);
7424     sal_uInt16 nL = 0;                      // number of Bytes to read
7425 
7426     //sprmPChgTabs
7427     switch( nId )
7428     {
7429         case 23:
7430         case 0xC615:
7431             if( pSprm[1 + mnDelta] != 255 )
7432                 nL = static_cast< sal_uInt16 >(pSprm[1 + mnDelta] + aSprm.nLen);
7433             else
7434             {
7435                 sal_uInt8 nDel = pSprm[2 + mnDelta];
7436                 sal_uInt8 nIns = pSprm[3 + mnDelta + 4 * nDel];
7437 
7438                 nL = 2 + 4 * nDel + 3 * nIns;
7439             }
7440             break;
7441         case 0xD608:
7442             nL = SVBT16ToShort( &pSprm[1 + mnDelta] );
7443             break;
7444         default:
7445             switch (aSprm.nVari)
7446             {
7447                 case L_FIX:
7448                     nL = aSprm.nLen;        // Excl. Token
7449                     break;
7450                 case L_VAR:
7451                     // Variable 1-Byte Length?
7452                     // Excl. Token + Var-Lengthbyte
7453                     nL = static_cast< sal_uInt16 >(pSprm[1 + mnDelta] + aSprm.nLen);
7454                     break;
7455                 case L_VAR2:
7456                     // Variable 2-Byte Length?
7457                     // Excl. Token + Var-Lengthbyte
7458                     nL = static_cast< sal_uInt16 >(SVBT16ToShort( &pSprm[1 + mnDelta] ) + aSprm.nLen - 1);
7459                     break;
7460                 default:
7461                     ASSERT(!this, "Unknown sprm varient");
7462                     break;
7463             }
7464             break;
7465     }
7466     return nL;
7467 }
7468 
7469 // one or two bytes at the beginning at the sprm id
7470 sal_uInt16 wwSprmParser::GetSprmId(const sal_uInt8* pSp) const
7471 {
7472     ASSERT_RET_ON_FAIL(pSp, "Why GetSprmId with pSp of 0", 0);
7473 
7474     sal_uInt16 nId = 0;
7475 
7476     if (ww::IsSevenMinus(meVersion))
7477     {
7478         nId = *pSp;
7479         if (0x0100 < nId)
7480             nId = 0;
7481     }
7482     else
7483     {
7484         nId = SVBT16ToShort(pSp);
7485         if (0x0800 > nId)
7486             nId = 0;
7487     }
7488 
7489     return nId;
7490 }
7491 
7492 // with tokens and length byte
7493 sal_uInt16 wwSprmParser::GetSprmSize(sal_uInt16 nId, const sal_uInt8* pSprm) const
7494 {
7495     return GetSprmTailLen(nId, pSprm) + 1 + mnDelta + SprmDataOfs(nId);
7496 }
7497 
7498 sal_uInt8 wwSprmParser::SprmDataOfs(sal_uInt16 nId) const
7499 {
7500     return GetSprmInfo(nId).nVari;
7501 }
7502 
7503 sal_uInt16 wwSprmParser::DistanceToData(sal_uInt16 nId) const
7504 {
7505     return 1 + mnDelta + SprmDataOfs(nId);
7506 }
7507 
7508 SEPr::SEPr() :
7509     bkc(2), fTitlePage(0), fAutoPgn(0), nfcPgn(0), fUnlocked(0), cnsPgn(0),
7510     fPgnRestart(0), fEndNote(1), lnc(0), grpfIhdt(0), nLnnMod(0), dxaLnn(0),
7511     dxaPgn(720), dyaPgn(720), fLBetween(0), vjc(0), dmBinFirst(0),
7512     dmBinOther(0), dmPaperReq(0), fPropRMark(0), ibstPropRMark(0),
7513     dttmPropRMark(0), dxtCharSpace(0), dyaLinePitch(0), clm(0), reserved1(0),
7514     dmOrientPage(0), iHeadingPgn(0), pgnStart(1), lnnMin(0), wTextFlow(0),
7515     reserved2(0), pgbApplyTo(0), pgbPageDepth(0), pgbOffsetFrom(0),
7516     xaPage(lLetterWidth), yaPage(lLetterHeight), xaPageNUp(lLetterWidth), yaPageNUp(lLetterHeight),
7517     dxaLeft(1800), dxaRight(1800), dyaTop(1440), dyaBottom(1440), dzaGutter(0),
7518     dyaHdrTop(720), dyaHdrBottom(720), ccolM1(0), fEvenlySpaced(1),
7519     reserved3(0), fBiDi(0), fFacingCol(0), fRTLGutter(0), fRTLAlignment(0),
7520     dxaColumns(720), dxaColumnWidth(0), dmOrientFirst(0), fLayout(0),
7521     reserved4(0)
7522 {
7523     memset(rgdxaColumnWidthSpacing, 0, sizeof(rgdxaColumnWidthSpacing));
7524 }
7525 
7526 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
7527