1 /* This file is part of the wvWare 2 project
2    Copyright (C) 2001-2003 Werner Trobin <trobin@kde.org>
3    Copyright (C) 2010-2011 Matus Uzak <matus.uzak@ixonos.com>
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the Library GNU General Public
7    version 2 of the License, or (at your option) version 3 or,
8    at the discretion of KDE e.V (which shall act as a proxy as in
9    section 14 of the GPLv3), any later version..
10 
11    This library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15 
16    You should have received a copy of the GNU Library General Public License
17    along with this library; see the file COPYING.LIB.  If not, write to
18    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19    Boston, MA 02110-1301, USA.
20 */
21 
22 #include "word97_helper.h"
23 #include "word95_helper.h"
24 #include "word97_generated.h"
25 #include "word95_generated.h"
26 #include "convert.h"
27 #include "olestream.h"
28 #include "styles.h"
29 #include "paragraphproperties.h"
30 
31 #include <string.h> // memcpy
32 #include <algorithm>
33 #include <functional> // std::bind2nd for gcc 2.9x
34 #include <cstdlib>
35 
36 #include "wvlog.h"
37 
38 namespace wvWare
39 {
40 
41 namespace Word97
42 {
43 
44 // The fts enumeration specifies how the preferred width for a table, table
45 // indent, table cell, cell margin, or cell spacing is defined.  MS-DOC, p.362
46 typedef enum
47 {
48     ftsNil     = 0x00, //the size is undefined and must be ignored
49     ftsAuto    = 0x01, //no preferred width is specified
50     ftsPercent = 0x02, //preferred width is measured in units of 1/50 of a percent
51     ftsDxa     = 0x03, //absolute width measured in twips
52     ftsDxaSys  = 0x13  //absolute width measured in twips
53 } FTS;
54 
55 // Make use of the grfbrc enumeration in decision to which cell sides the cell
56 // margin or cell spacing applies to.
57 typedef enum
58 {
59     fbrcTop    = 0x01,
60     fbrcLeft   = 0x02,
61     fbrcBottom = 0x04,
62     fbrcRight  = 0x08
63 } GRFBRC;
64 
65 namespace SPRM
66 {
67 
68 struct opcodeBits
69 {
70     U16 ispmd:9;
71     U16 fSpec:1;
72     U16 sgc:3;
73     U16 spra:3;
74 };
75 
76 // Apart from all the SPRMs in the documentation I added some from the OOo code.
77 // Additionally there are some xyzFake entries, which are used to get Word 6 sprms
78 // through the same code :-}
79 typedef enum
80 {
81     sprmNoop = 0x0000,
82     sprmCFRMarkDel = 0x0800,
83     sprmCFRMark = 0x0801,
84     sprmCFFldVanish = 0x0802,
85     sprmCFData = 0x0806,
86     sprmCFOle2 = 0x080A,
87     sprmCFBold = 0x0835,
88     sprmCFItalic = 0x0836,
89     sprmCFStrike = 0x0837,
90     sprmCFOutline = 0x0838,
91     sprmCFShadow = 0x0839,
92     sprmCFSmallCaps = 0x083A,
93     sprmCFCaps = 0x083B,
94     sprmCFVanish = 0x083C,
95     sprmCFImprint = 0x0854,
96     sprmCFSpec = 0x0855,
97     sprmCFObj = 0x0856,
98     sprmCFEmboss = 0x0858,
99     sprmCFBiDi = 0x085A,
100     sprmCFDiacColor = 0x085B,
101     sprmCFBoldBi = 0x085C,
102     sprmCFItalicBi = 0x085D,
103     sprmCFUsePgsuSettings = 0x0868,
104     sprmCUndocumented1 = 0x875,
105     sprmPJc = 0x2403,
106     sprmPJcFE = 0x2461, // Undocumented. According to OOo it's the asian equivalent to sprmPJc
107     sprmPFSideBySide = 0x2404,
108     sprmPFKeep = 0x2405,
109     sprmPFKeepFollow = 0x2406,
110     sprmPFPageBreakBefore = 0x2407,
111     sprmPBrcl = 0x2408,
112     sprmPBrcp = 0x2409,
113     sprmPFNoLineNumb = 0x240C,
114     sprmPFInTable = 0x2416,
115     sprmPFTtp = 0x2417,
116     sprmPWr = 0x2423,
117     sprmPFNoAutoHyph = 0x242A,
118     sprmPFLocked = 0x2430,
119     sprmPFWidowControl = 0x2431,
120     sprmPFKinsoku = 0x2433,
121     sprmPFWordWrap = 0x2434,
122     sprmPFOverflowPunct = 0x2435,
123     sprmPFTopLinePunct = 0x2436,
124     sprmPFAutoSpaceDE = 0x2437,
125     sprmPFAutoSpaceDN = 0x2438,
126     sprmPISnapBaseLine = 0x243B,
127     sprmPFBiDi = 0x2441,
128     sprmPFNumRMIns = 0x2443,
129     sprmPCrLf = 0x2444,
130     sprmPFUsePgsuSettings = 0x2447,
131     sprmPFAdjustRight = 0x2448,
132     sprmPFInnerTableCell = 0x244B,
133     sprmPFInnerTtp = 0x244C,
134     sprmPFDyaBeforeAuto = 0x245B,
135     sprmPFDyaAfterAuto = 0x245C,
136     sprmPNLvlAnmFake = 0x25FF, // Fake entry!
137     sprmPIncLvl = 0x2602,
138     sprmPIlvl = 0x260A,
139     sprmPPc = 0x261B,
140     sprmPOutLvl = 0x2640,
141     sprmCSfxText = 0x2859,
142     sprmCIdctHint = 0x286F,
143     sprmCHighlight = 0x2A0C,
144     sprmCFFtcAsciSymb = 0x2A10,
145     sprmCDefault = 0x2A32,
146     sprmCPlain = 0x2A33,
147     sprmCKcd = 0x2A34,
148     sprmCKul = 0x2A3E,
149     sprmCIco = 0x2A42,
150     sprmCHpsInc = 0x2A44,
151     sprmCHpsPosAdj = 0x2A46,
152     sprmCIss = 0x2A48,
153     sprmCFDStrike = 0x2A53,
154     sprmPicBrcl = 0x2E00,
155     sprmScnsPgn = 0x3000,
156     sprmSiHeadingPgn = 0x3001,
157     sprmSFEvenlySpaced = 0x3005,
158     sprmSFProtected = 0x3006,
159     sprmSBkc = 0x3009,
160     sprmSFTitlePage = 0x300A,
161     sprmSFAutoPgn = 0x300D,
162     sprmSNfcPgn = 0x300E,
163     sprmSFPgnRestart = 0x3011,
164     sprmSFEndnote = 0x3012,
165     sprmSLnc = 0x3013,
166     sprmSGprfIhdt = 0x3014, //MS Word 6.0, header/footer related group of bit flags
167     sprmSLBetween = 0x3019,
168     sprmSVjc = 0x301A,
169     sprmSBOrientation = 0x301D,
170     sprmSBCustomize = 0x301E,
171     sprmSFBiDi = 0x3228,
172     sprmSFFacingCol = 0x3229,
173     sprmSFRTLGutter = 0x322A,
174     sprmTFCantSplit = 0x3403,
175     sprmTTableHeader = 0x3404,
176     sprmTPc = 0x360D,
177     sprmTUndocumented1 = 0x3615,
178     sprmPWHeightAbs = 0x442B,
179     sprmPDcs = 0x442C,
180     sprmPShd80 = 0x442D,
181     sprmPWAlignFont = 0x4439,
182     sprmPFrameTextFlow = 0x443A,
183     sprmPIstd = 0x4600,
184     sprmPIlfo = 0x460B,
185     sprmPNest = 0x4610,
186     sprmPBrcTop10 = 0x461C,
187     sprmPBrcLeft10 = 0x461D,
188     sprmPBrcBottom10 = 0x461E,
189     sprmPBrcRight10 = 0x461F,
190     sprmPBrcBetween10 = 0x4620,
191     sprmPBrcBar10 = 0x4621,
192     sprmPDxaFromText10 = 0x4622,
193     sprmCIbstRMark = 0x4804,
194     sprmCIdslRMark = 0x4807,
195     sprmCIdCharType = 0x480B,
196     sprmCHpsPos = 0x4845,
197     sprmCHpsKern = 0x484B,
198     sprmCYsri = 0x484E,
199     sprmCCharScale = 0x4852,
200     sprmCLidBi = 0x485F,
201     sprmCIbstRMarkDel = 0x4863,
202     sprmCShd80 = 0x4866,
203     sprmCIdslRMarkDel = 0x4867,
204     sprmCCpg = 0x486B,
205     sprmCRgLid0 = 0x486D,
206     sprmCRgLid1 = 0x486E,
207     sprmCRgLidUndocumented1 = 0x4873, // According to OOo it's equal to sprmCRgLid0
208     sprmCUndocumented2 = 0x4874,
209     sprmCPbiGrf = 0x4888,
210     sprmCIstd = 0x4A30,
211     sprmCFtcDefault = 0x4A3D,
212     sprmCLid = 0x4A41,
213     sprmCHps = 0x4A43,
214     sprmCHpsMul = 0x4A4D,
215     sprmCRgFtc0 = 0x4A4F,
216     sprmCRgFtc1 = 0x4A50,
217     sprmCRgFtc2 = 0x4A51,
218     sprmCFtcBi = 0x4A5E,
219     sprmCIcoBi = 0x4A60,
220     sprmCHpsBi = 0x4A61,
221     sprmSDmBinFirst = 0x5007,
222     sprmSDmBinOther = 0x5008,
223     sprmSCcolumns = 0x500B,
224     sprmSNLnnMod = 0x5015,
225     sprmSLnnMin = 0x501B,
226     sprmSPgnStart = 0x501C,
227     sprmSDmPaperReq = 0x5026,
228     sprmSClm = 0x5032,
229     sprmSNfcFtnRef = 0x5040,
230     sprmSNfcEdnRef = 0x5042,
231     sprmSTextFlow = 0x5033,
232     sprmSPgbProp = 0x522F,
233     sprmTJc = 0x5400,
234     sprmTFBiDi = 0x560B,
235     sprmTDelete = 0x5622,
236     sprmTMerge = 0x5624,
237     sprmTSplit = 0x5625,
238     sprmTUndocumented2 = 0x5664,
239     sprmPDyaLine = 0x6412,
240     sprmPBrcTop = 0x6424,
241     sprmPBrcLeft = 0x6425,
242     sprmPBrcBottom = 0x6426,
243     sprmPBrcRight = 0x6427,
244     sprmPBrcBetween = 0x6428,
245     sprmPTableProps = 0x646b,
246     sprmPBrcBar = 0x6629,
247     sprmPHugePapx = 0x6645,
248     sprmPHugePapx2 = 0x6646,
249     sprmPItap = 0x6649,
250     sprmPDtap = 0x664A,
251     sprmCDttmRMark = 0x6805,
252     sprmCObjLocation = 0x680E,
253     sprmCRsidProp = 0x6815,
254     sprmCDttmRMarkDel = 0x6864,
255     sprmCBrc = 0x6865,
256     sprmCCv = 0x6870,
257     sprmCCvUl = 0x6877,
258     sprmCPbiIBullet = 0x6887,
259     sprmCPicLocation = 0x6A03,
260     sprmCSymbol = 0x6A09,
261     sprmPicBrcTop = 0x6C02,
262     sprmPicBrcLeft = 0x6C03,
263     sprmPicBrcBottom = 0x6C04,
264     sprmPicBrcRight = 0x6C05,
265     sprmSBrcTop = 0x702B,
266     sprmSBrcLeft = 0x702C,
267     sprmSBrcBottom = 0x702D,
268     sprmSBrcRight = 0x702E,
269     sprmSDxtCharSpace = 0x7030,
270     sprmTTlp = 0x740A,
271     sprmTHTMLProps = 0x740C,
272     sprmTInsert = 0x7621,
273     sprmTDxaCol = 0x7623,
274     sprmTSetShd = 0x7627,
275     sprmTSetShdOdd = 0x7628,
276     sprmTTextFlow = 0x7629,
277     sprmPDxaRight = 0x840E,
278     sprmPDxaRightFE = 0x845D, // Undocumented. According to OOo it's the asian equivalent to sprmPDxaRight
279     sprmPDxaLeft = 0x840F,
280     sprmPDxaLeftFE = 0x845E, // Undocumented. According to OOo it's the asian equivalent to sprmPDxaLeft
281     sprmPDxaLeft1 = 0x8411,
282     sprmPDxaLeft1FE = 0x8460, // Undocumented. According to OOo it's the asian equivalent to sprmPDxaLeft1
283     sprmPDxaAbs = 0x8418,
284     sprmPDyaAbs = 0x8419,
285     sprmPDxaWidth = 0x841A,
286     sprmPDyaFromText = 0x842E,
287     sprmPDxaFromText = 0x842F,
288     sprmCDxaSpace = 0x8840,
289     sprmSDxaColumns = 0x900C,
290     sprmSDxaLnn = 0x9016,
291     sprmSDyaTop = 0x9023,
292     sprmSDyaBottom = 0x9024,
293     sprmSDyaLinePitch = 0x9031,
294     sprmTDyaRowHeight = 0x9407,
295     sprmTDxaFromText = 0x9410,
296     sprmTDyaFromText = 0x9411,
297     sprmTDxaFromTextRight = 0x941E,
298     sprmTDyaFromTextBottom = 0x941F,
299     sprmTDxaAbs = 0x940E,
300     sprmTDyaAbs = 0x940F,
301     sprmTDxaLeft = 0x9601,
302     sprmTDxaGapHalf = 0x9602,
303     sprmPDyaBefore = 0xA413,
304     sprmPDyaAfter = 0xA414,
305     sprmSDyaPgn = 0xB00F,
306     sprmSDxaPgn = 0xB010,
307     sprmSDyaHdrTop = 0xB017,
308     sprmSDyaHdrBottom = 0xB018,
309     sprmSXaPage = 0xB01F,
310     sprmSYaPage = 0xB020,
311     sprmSDxaLeft = 0xB021,
312     sprmSDxaRight = 0xB022,
313     sprmSDzaGutter = 0xB025,
314     sprmPIstdPermute = 0xC601,
315     sprmPChgTabsPapx = 0xC60D,
316     sprmPChgTabs = 0xC615,
317     sprmPRuler = 0xC632,
318     sprmPAnld = 0xC63E,
319     sprmPPropRMark = 0xC63F,
320     sprmPNumRM = 0xC645,
321     sprmPShd = 0xC64D,
322     sprmPUndocumented1 = 0xC64E,
323     sprmPUndocumented2 = 0xC64F,
324     sprmPUndocumented3 = 0xC650,
325     sprmPUndocumented4 = 0xC651,
326     sprmCIstdPermute = 0xCA31,
327     sprmCMajority = 0xCA47,
328     sprmCHpsNew50 = 0xCA49,
329     sprmCHpsInc1 = 0xCA4A,
330     sprmCMajority50 = 0xCA4C,
331     sprmCPropRMark = 0xCA57,
332     sprmCDispFldRMark = 0xCA62,
333     sprmCShd = 0xCA71,
334     sprmCFELayout = 0xCA78,
335     sprmPicScale = 0xCE01,
336     sprmSOlstAnm = 0xD202,
337     sprmSPropRMark = 0xD227,
338     sprmTTableBorders80 = 0xD605,
339     sprmTDefTable10 = 0xD606,
340     sprmTDefTable = 0xD608,
341     sprmTDefTableShd80 = 0xD609,
342     sprmTDefTableShd = 0xD612,
343     sprmTTableBorders = 0xD613,
344     sprmTDefTableShd2nd = 0xD616,
345     sprmTDefTableShd3rd = 0xD60C,
346     sprmTBrcTopCv = 0xD61A,
347     sprmTBrcLeftCv = 0xD61B,
348     sprmTBrcBottomCv = 0xD61C,
349     sprmTBrcRightCv = 0xD61D,
350     sprmTSetBrc80 = 0xD620,
351     sprmTSetBrc10 = 0xD626,
352     sprmTDiagLine = 0xD62A,
353     sprmTVertMerge = 0xD62B,
354     sprmTVertAlign = 0xD62C,
355     sprmTSetBrc = 0xD62F,
356     sprmTCellPadding = 0xD632,
357     sprmTCellSpacingDefault = 0xD633,
358     sprmTCellPaddingDefault = 0xD634,
359     sprmTSetShdTable = 0xD660,
360     sprmTCellBrcType = 0xD662,
361     sprmCChs = 0xEA08,
362     sprmCSizePos = 0xEA3F,
363     sprmSDxaColWidth = 0xF203,
364     sprmSDxaColSpacing = 0xF204,
365     sprmTUndocumented10 = 0xF614,
366     sprmTUndocumented11 = 0xF617,
367     sprmTUndocumented12 = 0xF618,
368     sprmTWidthIndent = 0xF661
369 } opcodes;
370 
371 // The length of the SPRM parameter
determineParameterLength(U16 sprm,const U8 * in,WordVersion version)372 U16 determineParameterLength( U16 sprm, const U8* in, WordVersion version )
373 {
374     if ( version == Word8 ) {
375         static const char operandSizes[ 8 ] = { 1, 1, 2, 4, 2, 2, 0, 3 };
376 
377         int index = ( sprm & 0xE000 ) >> 13;
378         if ( operandSizes[ index ] != 0 ) {
379 #ifdef WV2_DEBUG_SPRMS
380             wvlog << "==> Size of the sprm argument:" << (U16) operandSizes[index] << endl;
381             wvlog << "sgc:" << (U16) ((sprm & 0x1C00) >> 10);
382 #endif
383             return operandSizes[ index ];
384         }
385         else {
386 #ifdef WV2_DEBUG_SPRMS
387             wvlog << "==> Variable size of the sprm argument:";
388 #endif
389             // Get length of variable size operand.
390             switch ( sprm ) {
391                 case sprmTDefTable10:
392                 case sprmTDefTable:
393                     return readU16( in ) + 1;
394                     break;
395                 case sprmPChgTabs:
396                     if ( *in == 255 ) {
397                         U8 itbdDelMax = in[ 1 ];
398                         U8 itbdAddMax = in[ 1 + itbdDelMax * 4 ];
399                         return 1 + itbdDelMax * 4 + itbdAddMax * 3;
400                     }
401                     else
402                         return *in + 1;
403                     break;
404                 default:
405                     return *in + 1;
406                     break;
407             }
408         }
409     }
410     else { // Word67
411         if ( sprm > 255 )
412             wvlog << "Error: Trying to get the length of a flaky SPRM (" << sprm << ", 0x" << hex
413                   << sprm << dec << ") via the Word 95 method!" << endl;
414         return Word95::SPRM::determineParameterLength( static_cast<U8>( sprm ), in );
415     }
416 }
417 
418 // Apply a <T> grpprl of a given size ("count" bytes long)
419 // This template function might be a bit sick, but it helps to
420 // avoid duplicated code, so what ;)
421 template<class T>
apply(T * const t,S16 (T::* applySPRM)(const U8 *,const Style *,const StyleSheet *,OLEStreamReader *,WordVersion),const U8 * grpprl,U16 count,const Style * style,const StyleSheet * styleSheet,OLEStreamReader * dataStream,WordVersion version)422 void apply(T* const t,
423            S16 ( T::* applySPRM ) ( const U8*, const Style*, const StyleSheet*, OLEStreamReader*, WordVersion ),
424            const U8* grpprl, U16 count, const Style* style, const StyleSheet* styleSheet,
425            OLEStreamReader* dataStream, WordVersion version )
426 {
427     if ( !grpprl )
428         return;
429 
430     // We are using an integer here, that we can detect situations where
431     // we read beyond the limit due to a buggy spec/impl.
432     // The plain U16 would overflow and we'd be trapped in a loop.
433     int safeCount = count;
434 
435     // walk through the grpprl, applying one sprm after the other
436     while ( safeCount > 1 ) {
437         S16 result = ( t->*applySPRM )( grpprl, style, styleSheet, dataStream, version );
438         if ( result == -1 ) {
439             U16 sprm;
440             if ( version == Word8 ) {
441                 sprm = readU16( grpprl );
442                 grpprl += 2;
443 #ifdef WV2_DEBUG_SPRMS
444                 wvlog << "Seems like that's a different SPRM (0x" << hex << sprm << dec << ")... skipping" << endl;
445 #endif
446             }
447             else {
448                 sprm = *grpprl++;
449 #ifdef WV2_DEBUG_SPRMS
450                 wvlog << "Seems like that's a different SPRM (" << sprm << ")... skipping" << endl;
451 #endif
452             }
453 
454             U16 len = determineParameterLength( sprm, grpprl, version );
455             grpprl += len;
456             safeCount -= len + ( version == Word8 ? 2 : 1 );
457         }
458         else {
459             grpprl += result;
460             safeCount -= result;
461         }
462     }
463     if ( safeCount < 0 )
464         wvlog << "Warning: We read past the end of the grpprl, buggy spec?" << endl;
465 }
466 
unzippedOpCode(U8 isprm)467 U16 unzippedOpCode( U8 isprm )
468 {
469     // Note: Changed sprmCFStrikeRM to sprmCFStrike and sprmPPnbrRMarkNot to sprmNoop
470     static const U16 lut[] = {
471         sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmPIncLvl, sprmPJc, sprmPFSideBySide,
472         sprmPFKeep, sprmPFKeepFollow, sprmPFPageBreakBefore, sprmPBrcl, sprmPBrcp,
473         sprmPIlvl, sprmNoop, sprmPFNoLineNumb, sprmNoop, sprmNoop, sprmNoop, sprmNoop,
474         sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmPFInTable, sprmPFTtp,
475         sprmNoop, sprmNoop, sprmNoop, sprmPPc, sprmNoop, sprmNoop, sprmNoop, sprmNoop,
476         sprmNoop, sprmNoop, sprmNoop, sprmPWr, sprmNoop, sprmNoop, sprmNoop, sprmNoop,
477         sprmNoop, sprmNoop, sprmPFNoAutoHyph, sprmNoop, sprmNoop, sprmNoop, sprmNoop,
478         sprmNoop, sprmPFLocked, sprmPFWidowControl, sprmNoop, sprmPFKinsoku, sprmPFWordWrap,
479         sprmPFOverflowPunct, sprmPFTopLinePunct, sprmPFAutoSpaceDE, sprmPFAutoSpaceDN,
480         sprmNoop, sprmNoop, sprmPISnapBaseLine, sprmNoop, sprmNoop, sprmNoop, sprmCFStrike,
481         sprmCFRMark, sprmCFFldVanish, sprmNoop, sprmNoop, sprmNoop, sprmCFData,
482         sprmNoop, sprmNoop, sprmNoop, sprmCFOle2, sprmNoop, sprmCHighlight, sprmCFEmboss,
483         sprmCSfxText, sprmNoop, sprmNoop, sprmNoop, sprmCPlain, sprmNoop, sprmCFBold,
484         sprmCFItalic, sprmCFStrike, sprmCFOutline, sprmCFShadow, sprmCFSmallCaps,
485         sprmCFCaps, sprmCFVanish, sprmNoop, sprmCKul, sprmNoop, sprmNoop, sprmNoop,
486         sprmCIco, sprmNoop, sprmCHpsInc, sprmNoop, sprmCHpsPosAdj, sprmNoop, sprmCIss,
487         sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop,
488         sprmNoop, sprmNoop, sprmCFDStrike, sprmCFImprint, sprmCFSpec, sprmCFObj,
489         sprmPicBrcl, sprmPOutLvl, sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop,
490         sprmNoop };
491 
492     return lut[ isprm ];
493 }
494 
495 /**
496  * Converts a Word 6/7 SPRM to a Word 8 one.
497  */
word6toWord8(U8 sprm)498 U16 word6toWord8( U8 sprm )
499 {
500     static const U16 lut[] = {
501         sprmNoop, sprmNoop, sprmPIstd, sprmPIstdPermute, sprmPIncLvl,
502         sprmPJc, sprmPFSideBySide, sprmPFKeep, sprmPFKeepFollow, sprmPFPageBreakBefore,
503         sprmPBrcl, sprmPBrcp, sprmPAnld, sprmPNLvlAnmFake, sprmPFNoLineNumb,
504         sprmPChgTabsPapx, sprmPDxaRight, sprmPDxaLeft, sprmPNest, sprmPDxaLeft1,
505         sprmPDyaLine, sprmPDyaBefore, sprmPDyaAfter, sprmPChgTabs, sprmPFInTable,
506         sprmPFTtp, sprmPDxaAbs, sprmPDyaAbs, sprmPDxaWidth, sprmPPc,
507         sprmPBrcTop10, sprmPBrcLeft10, sprmPBrcBottom10, sprmPBrcRight10, sprmPBrcBetween10,
508         sprmPBrcBar10, sprmPDxaFromText10, sprmPWr, sprmPBrcTop, sprmPBrcLeft,
509         sprmPBrcBottom, sprmPBrcRight, sprmPBrcBetween, sprmPBrcBar, sprmPFNoAutoHyph,
510         sprmPWHeightAbs, sprmPDcs, sprmPShd80, sprmPDyaFromText, sprmPDxaFromText,
511         sprmPFLocked, sprmPFWidowControl, sprmPRuler, sprmNoop, sprmNoop,
512         sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop,
513         sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop,
514         sprmCFRMarkDel, sprmCFRMark, sprmCFFldVanish, sprmCPicLocation, sprmCIbstRMark,
515         sprmCDttmRMark, sprmCFData, sprmCIdslRMark, sprmCChs, sprmCSymbol,
516         sprmCFOle2, sprmNoop, sprmNoop, sprmNoop, sprmNoop,
517         sprmCIstd, sprmCIstdPermute, sprmCDefault, sprmCPlain, sprmNoop,
518         sprmCFBold, sprmCFItalic, sprmCFStrike, sprmCFOutline, sprmCFShadow,
519         sprmCFSmallCaps, sprmCFCaps, sprmCFVanish, sprmCFtcDefault, sprmCKul,
520         sprmCSizePos, sprmCDxaSpace, sprmCLid, sprmCIco, sprmCHps,
521         sprmCHpsInc, sprmCHpsPos, sprmCHpsPosAdj, sprmCMajority, sprmCIss,
522         sprmCHpsNew50, sprmCHpsInc1, sprmCHpsKern, sprmCMajority50, sprmCHpsMul,
523         sprmCYsri, sprmNoop, sprmNoop, sprmNoop, sprmNoop,
524         sprmNoop, sprmNoop, sprmCFSpec, sprmCFObj, sprmPicBrcl,
525         sprmPicScale, sprmPicBrcTop, sprmPicBrcLeft, sprmPicBrcBottom, sprmPicBrcRight,
526         sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop,
527         sprmNoop, sprmScnsPgn, sprmSiHeadingPgn, sprmSOlstAnm, sprmNoop,
528         sprmNoop, sprmSDxaColWidth, sprmSDxaColSpacing, sprmSFEvenlySpaced, sprmSFProtected,
529         sprmSDmBinFirst, sprmSDmBinOther, sprmSBkc, sprmSFTitlePage, sprmSCcolumns,
530         sprmSDxaColumns, sprmSFAutoPgn, sprmSNfcPgn, sprmSDyaPgn, sprmSDxaPgn,
531         sprmSFPgnRestart, sprmSFEndnote, sprmSLnc, sprmSGprfIhdt, sprmSNLnnMod,
532         sprmSDxaLnn, sprmSDyaHdrTop, sprmSDyaHdrBottom, sprmSLBetween, sprmSVjc,
533         sprmSLnnMin, sprmSPgnStart, sprmSBOrientation, sprmSBCustomize, sprmSXaPage,
534         sprmSYaPage, sprmSDxaLeft, sprmSDxaRight, sprmSDyaTop, sprmSDyaBottom,
535         sprmSDzaGutter, sprmSDmPaperReq, sprmNoop, sprmNoop, sprmNoop,
536         sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop,
537         sprmNoop, sprmNoop, sprmTJc, sprmTDxaLeft, sprmTDxaGapHalf,
538         sprmTFCantSplit, sprmTTableHeader, sprmTTableBorders80, sprmTDefTable10, sprmTDyaRowHeight,
539         sprmTDefTable, sprmTDefTableShd80, sprmTTlp, sprmTSetBrc80, sprmTInsert,
540         sprmTDelete, sprmTDxaCol, sprmTMerge, sprmTSplit, sprmTSetBrc10,
541         sprmTSetShd };
542 
543     U16 s;
544     if ( sprm > 200 )
545         s = sprmNoop;
546     else
547         s = lut[ sprm ];
548     if ( s == sprmNoop )
549         wvlog << "Warning: Got a Word 6 " << static_cast<int>( sprm ) << " and return a noop!" << endl;
550     return s;
551 }
552 
553 } // namespace SPRM
554 
555 
initPAPFromStyle(const U8 * exceptions,const StyleSheet * styleSheet,OLEStreamReader * dataStream,WordVersion version)556 ParagraphProperties* initPAPFromStyle( const U8* exceptions, const StyleSheet* styleSheet, OLEStreamReader* dataStream, WordVersion version )
557 {
558     ParagraphProperties* properties = 0;
559     if ( exceptions == 0 ) {
560         if ( !styleSheet ) {
561             wvlog << "Warning: Couldn't read from the stylesheet." << endl;
562             return new ParagraphProperties();
563         }
564         const Style* normal = styleSheet->styleByID( 0 );  // stiNormal == 0x0000
565         if ( normal ) {
566             properties = new ParagraphProperties( normal->paragraphProperties() );
567         } else {
568             properties = new ParagraphProperties();
569         }
570     } else {
571         int cb = static_cast<int>( *exceptions++ ) << 1;  // Count of words (x2) -> count of bytes
572         if ( cb == 0 ) {                    // odd PAPX -> skip the padding byte
573             cb = static_cast<int>( *exceptions++ ) << 1;
574             cb -= 2;
575         } else {
576             cb -= version == Word8 ? 3 : 2;  // Don't ask me, why Word 6/7 only needs -2 bytes
577         }
578 
579         U16 tmpIstd = readU16( exceptions );
580         exceptions += 2;
581 
582         const Style* style = 0;
583         if ( styleSheet ) {
584             style = styleSheet->styleByIndex( tmpIstd );
585             if ( style ) {
586                 properties = new ParagraphProperties( style->paragraphProperties() );
587             } else {
588                 wvlog << "Warning: Couldn't read from the style, just applying the PAPX." << endl;
589                 properties = new ParagraphProperties();
590             }
591         } else {
592             wvlog << "Warning: Couldn't read from the stylesheet, just applying the PAPX." << endl;
593             properties = new ParagraphProperties();
594         }
595 
596         properties->pap().istd = tmpIstd;
597 
598         cb = cb < 0 ? 0 : cb;  // safety :-}
599         // Note: The caller also has to override the PHE from this
600         // PAP with the PHE stored in the BX
601         properties->pap().apply( exceptions, cb, style, styleSheet, dataStream, version );
602     }
603     return properties;
604 }
605 
initTAP(const U8 * exceptions,OLEStreamReader * dataStream,WordVersion version)606 Word97::TAP* initTAP( const U8* exceptions, OLEStreamReader* dataStream, WordVersion version )
607 {
608     Word97::TAP* tap = new Word97::TAP;
609 
610     if ( exceptions == 0 )
611         return tap;
612 
613     int cb = static_cast<int>( *exceptions++ ) << 1;  // Count of words (x2) -> count of bytes
614     if ( cb == 0 ) {                    // odd PAPX -> skip the padding byte
615         cb = static_cast<int>( *exceptions++ ) << 1;
616         cb -= 2;
617     }
618     else
619         cb -= 3;
620 
621     exceptions += 2; // skip the istd
622     cb = cb < 0 ? 0 : cb;  // safety :-}
623     tap->apply( exceptions, cb, 0, 0, dataStream, version ); // we don't need a style(sheet), do we?
624 
625 
626     return tap;
627 }
628 
629 
630 // Apply a PAP grpprl of a given size ("count" bytes long)
apply(const U8 * grpprl,U16 count,const Style * style,const StyleSheet * styleSheet,OLEStreamReader * dataStream,WordVersion version)631 void PAP::apply( const U8* grpprl, U16 count, const Style* style, const StyleSheet* styleSheet,
632                  OLEStreamReader* dataStream, WordVersion version )
633 {
634     // A PAP grpprl might contain TAP sprms, we just skip them
635     SPRM::apply<PAP>( this, &PAP::applyPAPSPRM, grpprl, count, style, styleSheet, dataStream, version );
636 }
637 
icoToCOLORREF(U16 ico)638     U32 icoToCOLORREF(U16 ico)
639     {
640         //TODO: Do not place the fAuto byte in front!  The MS-ODRAW
641         //OfficeArtCOLORREF is an equivalent and has the byte properly at the
642         //end.  Oooo, it's confusing ...
643 
644         switch(ico)
645         {
646             case 0: //default and we choose black as most paper is white
647                 return 0xFF000000;
648             case 1://black
649                 return 0x00000000;
650             case 2://blue
651                 return 0x000000FF;
652             case 3://cyan
653                 return 0x0000FFFF;
654             case 4://green
655                 return 0x00008000;
656             case 5://magenta
657                 return 0x00FF00FF;
658             case 6://red
659                 return 0x00FF0000;
660             case 7://yellow
661                 return 0x00FFFF00;
662             case 8://white
663                 return 0x00FFFFFF;
664             case 9://dark blue
665                 return 0x0000008B;
666             case 10://dark cyan
667                 return 0x00008B8B;
668             case 11://dark green
669                 return 0x00006400;
670             case 12://dark magenta
671                 return 0x008B008B;
672             case 13://dark red
673                 return 0x008B0000;
674             case 14://dark yellow
675                 return 0x00808000;
676             case 15://dark gray
677                 return 0x00A9A9A9;
678             case 16://light gray
679                 return 0x00D3D3D3;
680 
681             default:
682                 return 0x000000;
683         }
684     }
685 
686 // Helper methods for the more complex sprms
687 namespace
688 {
689     /**
690      * Adds the tabs of the sprmPChgTabs* sprms.  Pass a pointer to the
691      * itbdAddMax and the vector.
692      *
693      * @return the number of tabs added
694      */
695     typedef std::vector<Word97::TabDescriptor> TabDescVector;
addTabs(const U8 * ptr,TabDescVector & rgdxaTab)696     U8 addTabs( const U8* ptr, TabDescVector& rgdxaTab )
697     {
698 //         wvlog << "Before adding the tabs: " << (int)rgdxaTab.size() << endl;
699         // Remember where the end was
700         const TabDescVector::size_type oldSize = rgdxaTab.size();
701         // Now append the new ones, we'll then sort the vector using
702         // inplace_merge
703         const U8 itbdAddMax = *ptr++;
704         //wvlog << "                           itbdAddMax=" << (int)itbdAddMax << endl;
705         for ( U8 i = 0 ; i < itbdAddMax ; ++i ) {
706             // #### We should probably add a proper constructor to
707             // #### TabDescriptor (Werner)
708             TabDescriptor descr;
709             descr.dxaTab = readS16( ptr + sizeof( S16 ) * i );
710 //             wvlog << "                           dxaPos=" << descr.dxaTab << endl;
711             descr.tbd = TBD( readU8( ptr + sizeof( S16 ) * itbdAddMax + i ) );
712             rgdxaTab.push_back( descr );
713         }
714         if ( oldSize != 0 && itbdAddMax ) {
715             TabDescVector::iterator middle = rgdxaTab.begin();
716             middle += oldSize;
717             std::inplace_merge( rgdxaTab.begin(), middle, rgdxaTab.end() );
718         }
719         TabDescVector::iterator uend = std::unique( rgdxaTab.begin(), rgdxaTab.end() );
720         if ( uend != rgdxaTab.end() ) {
721             rgdxaTab.erase( uend, rgdxaTab.end() );
722         }
723 //         wvlog << "After applying sprmPChgTabs(Papx) : " << (int)rgdxaTab.size() << endl;
724         return itbdAddMax;
725     }
726 
727     // A zone where tabstops are forbidden, needed for sprmPChgTabs
728     struct Zone
729     {
ZonewvWare::Word97::__anonb78b3c460411::Zone730         Zone( const U8* ptr, U8 index, U8 itbdDelMax )
731         {
732             m_center = readS16( ptr + index * sizeof( S16 ) );
733             // A negative value doesn't make sense here, right? Hmmm
734             m_plusMinus = std::abs( (int)( readS16( ptr + itbdDelMax * sizeof( S16 ) + index * sizeof( S16 ) ) ) );
735         }
736 
containswvWare::Word97::__anonb78b3c460411::Zone737         bool contains( S16 position ) const { return m_center - m_plusMinus <= position && m_center + m_plusMinus >= position; }
738 
739         S16 m_center;
740         S16 m_plusMinus;
741     };
742 
743     struct InZone : public std::binary_function<TabDescriptor, Zone, bool>
744     {
operator ()wvWare::Word97::__anonb78b3c460411::InZone745         bool operator()(const TabDescriptor &tab, const Zone& zone) const { return zone.contains( tab.dxaTab ); }
746     };
747 
getSPRM(const U8 ** ptr,WordVersion version,U16 & sprmLength)748     U16 getSPRM( const U8** ptr, WordVersion version, U16& sprmLength )
749     {
750         U16 sprm;
751         if ( version == Word8 ) {
752             sprm = readU16( *ptr );
753             ( *ptr ) += 2;
754             sprmLength = SPRM::determineParameterLength( sprm, *ptr, version ) + 2;
755         }
756         else {
757             sprm = **ptr;
758             ++( *ptr );
759             sprmLength = SPRM::determineParameterLength( sprm, *ptr, version ) + 1;
760             sprm = SPRM::word6toWord8( sprm );  // "fix" it for the Word 8 switch statements below
761         }
762         return sprm;
763     }
764 
readBRC(BRC & brc,const U8 * ptr,WordVersion version)765     void readBRC( BRC& brc, const U8* ptr, WordVersion version )
766     {
767         if ( version == Word8 )
768             brc.readPtr( ptr );
769         else
770             brc = toWord97( Word95::BRC( ptr ) );
771     }
772 } //anonymous namespace
773 
774 // Returns -1 if this wasn't a PAP sprm and it returns the length
775 // of the applied sprm if it was successful
applyPAPSPRM(const U8 * ptr,const Style * style,const StyleSheet * styleSheet,OLEStreamReader * dataStream,WordVersion version)776 S16 PAP::applyPAPSPRM( const U8* ptr, const Style* style, const StyleSheet* styleSheet, OLEStreamReader* dataStream, WordVersion version )
777 {
778     U16 sprmLength;
779     const U16 sprm( getSPRM( &ptr, version, sprmLength ) );
780 #ifdef WV2_DEBUG_SPRMS
781     wvlog << "got a sprm: 0x" << hex << sprm << dec << endl;
782 #endif
783 
784     // Is it a PAP sprm?
785     if ( ( ( sprm & 0x1C00 ) >> 10 ) != 1 ) {
786 #ifdef WV2_DEBUG_SPRMS
787         wvlog << "Warning: You're trying to apply a non PAP sprm to a PAP. Not necessarily bad." << endl;
788 #endif
789         return -1;  // tell the caller to try with something else (e.g. applying a TAP)...
790     }
791     // which one? ;)
792     switch ( sprm ) {
793         case SPRM::sprmNoop:
794             wvlog << "Huh? Found a sprmNoop..." << endl;
795             break;
796         case SPRM::sprmPIstd:
797             istd = readU16( ptr );
798             break;
799         case SPRM::sprmPIstdPermute:
800         {
801             const U8* myPtr = ptr + 3; // cch, fLongg, fSpare
802             const U16 istdFirst = readU16( myPtr );
803             myPtr += 2;
804             const U16 istdLast = readU16( myPtr );
805             myPtr += 2;
806             if ( istd > istdFirst && istd <= istdLast )
807                 istd = myPtr[ istd - istdFirst ];
808             break;
809         }
810         case SPRM::sprmPIncLvl:
811             // Applies only to list styles, note: SPEC defect, there's no stc anymore
812             if ( istd >= 1 && istd <= 9 ) {
813                 istd += static_cast<S8>( *ptr );
814                 lvl += static_cast<S8>( *ptr );
815             }
816             break;
817         case SPRM::sprmPJc:
818         case SPRM::sprmPJcFE: // asian version, according to OOo (fall-through intended)
819             jc = *ptr;
820             break;
821         case SPRM::sprmPFSideBySide:
822             fSideBySide = *ptr == 1;
823             break;
824         case SPRM::sprmPFKeep:
825             fKeep = *ptr == 1;
826             break;
827         case SPRM::sprmPFKeepFollow:
828             fKeepFollow = *ptr == 1;
829             break;
830         case SPRM::sprmPFPageBreakBefore:
831             fPageBreakBefore = *ptr == 1;
832             break;
833         case SPRM::sprmPBrcl:
834             brcl = *ptr;
835             break;
836         case SPRM::sprmPBrcp:
837             brcp = *ptr;
838             break;
839         case SPRM::sprmPIlvl:
840             ilvl = *ptr;
841             break;
842         case SPRM::sprmPIlfo:
843             ilfo = readS16( ptr );
844             break;
845         case SPRM::sprmPFNoLineNumb:
846             fNoLnn = *ptr == 1;
847             break;
848         case SPRM::sprmPChgTabsPapx:
849         {
850             const U8* myPtr = ptr;
851             U8 cch = *myPtr++;
852             U8 itbdDelMax = *myPtr++;
853             std::vector<Word97::TabDescriptor>::iterator tabIt = rgdxaTab.begin();
854             //wvlog << "Applying sprmPChgTabsPapx. itbdDelMax=" << (int)itbdDelMax << endl;
855             // First the 'to be deleted' array
856             for ( U8 i = 0 ; i < itbdDelMax ; ++i )
857             {
858                 TabDescriptor testDescr;
859                 testDescr.dxaTab = readS16( myPtr );
860                 myPtr += 2;
861                 // Look for this one, starting at last position (they are sorted)
862                 tabIt = std::find( tabIt, rgdxaTab.end(), testDescr );
863                 if ( tabIt != rgdxaTab.end() )
864                 {
865                     tabIt = rgdxaTab.erase( tabIt );
866                 }
867             }
868             U8 itbdAddMax = addTabs( myPtr, rgdxaTab );
869             itbdMac = rgdxaTab.size();
870 
871             if ( cch != 1 + 2 * itbdDelMax + 1 + 3 * itbdAddMax ) {
872                 wvlog << "Offset problem in sprmPChgTabsPapx. cch=" << static_cast<int>( cch ) <<
873                          "data size=" << 1 + 2 * itbdDelMax + 1 + 3 * itbdAddMax << endl;
874             }
875 #ifdef WV2_DEBUG_SPRMS
876             wvlog << "After applying sprmPChgTabsPapx : " << (int)rgdxaTab.size() << endl;
877             for (uint i = 0; i < rgdxaTab.size(); i++) {
878                 wvlog << "rgdxaTab[" << i << "].dxaTab" << rgdxaTab[i].dxaTab;
879             }
880 #endif
881             break;
882         }
883         case SPRM::sprmPDxaRight:
884         case SPRM::sprmPDxaRightFE: // asian version, according to OOo (fall-through intended)
885             dxaRight = readS16( ptr );
886             break;
887         case SPRM::sprmPDxaLeft:
888         case SPRM::sprmPDxaLeftFE: // asian version, according to OOo (fall-through intended)
889             dxaLeft = readS16( ptr );
890 #ifdef WV2_DEBUG_SPRMS
891             wvlog << "dxaLeft:" << dxaLeft;
892 #endif
893             break;
894         case SPRM::sprmPNest:
895             dxaLeft += readS16( ptr );
896             dxaLeft = dxaLeft < 0 ? 0 : dxaLeft;
897             break;
898         case SPRM::sprmPDxaLeft1:
899         case SPRM::sprmPDxaLeft1FE: // asian version, according to OOo (fall-through intended)
900             dxaLeft1 = readS16( ptr );
901 #ifdef WV2_DEBUG_SPRMS
902             wvlog << "dxaLeft1:" << dxaLeft1;
903 #endif
904             break;
905         case SPRM::sprmPDyaLine:
906             lspd.dyaLine = readS16( ptr );
907             lspd.fMultLinespace = readS16( ptr + 2 );
908             break;
909         case SPRM::sprmPDyaBefore:
910             dyaBefore = readU16( ptr );
911             break;
912         case SPRM::sprmPDyaAfter:
913             dyaAfter = readU16( ptr );
914             break;
915         case SPRM::sprmPChgTabs:
916         {
917             const U8* myPtr = ptr;
918             const U8 cch = *myPtr++;
919             const U8 itbdDelMax = *myPtr++;
920             // Remove the tabs within the deletion zones
921             std::vector<TabDescriptor>::iterator newEnd = rgdxaTab.end();
922             for ( U8 i = 0; i < itbdDelMax; ++i ) {
923                 newEnd = std::remove_if ( rgdxaTab.begin(), newEnd,
924                                           std::bind2nd( InZone(), Zone( myPtr, i, itbdDelMax ) ) );
925             }
926             rgdxaTab.erase( newEnd, rgdxaTab.end() ); // really get rid of them
927             myPtr += itbdDelMax * 4;
928 
929             U8 itbdAddMax = addTabs( myPtr, rgdxaTab );
930             itbdMac = rgdxaTab.size();
931 
932             if ( cch != 255 && cch != 1 + 4 * itbdDelMax + 1 + 3 * itbdAddMax ) {
933                 wvlog << "Offset problem in sprmPChgTabs. cch=" << static_cast<int>( cch ) <<
934                          "data size=" << 1 + 4 * itbdDelMax + 1 + 3 * itbdAddMax << endl;
935             }
936 #ifdef WV2_DEBUG_SPRMS
937             wvlog << "After applying sprmPChgTabs : " << (int)rgdxaTab.size() << endl;
938             for (uint i = 0; i < rgdxaTab.size(); i++) {
939                 wvlog << "rgdxaTab[" << i << "].dxaTab" << rgdxaTab[i].dxaTab;
940             }
941 #endif
942             break;
943         }
944         case SPRM::sprmPDxaAbs:
945             dxaAbs = readS16( ptr );
946             break;
947         case SPRM::sprmPDyaAbs:
948             dyaAbs = readS16( ptr );
949             break;
950         case SPRM::sprmPDxaWidth:
951             dxaWidth = readS16( ptr );
952             break;
953         case SPRM::sprmPPc:
954         {
955             pcVert = ( *ptr & 0x30 ) >> 4;
956             pcHorz = ( *ptr & 0xC0 ) >> 6;
957             break;
958         }
959         case SPRM::sprmPBrcTop10:
960             wvlog << "Warning: sprmPBrcTop10 doesn't make sense for Word 8" << endl;
961             break;
962         case SPRM::sprmPBrcLeft10:
963             wvlog << "Warning: sprmPBrcLeft10 doesn't make sense for Word 8" << endl;
964             break;
965         case SPRM::sprmPBrcBottom10:
966             wvlog << "Warning: sprmPBrcBottom10 doesn't make sense for Word 8" << endl;
967             break;
968         case SPRM::sprmPBrcRight10:
969             wvlog << "Warning: sprmPBrcRight10 doesn't make sense for Word 8" << endl;
970             break;
971         case SPRM::sprmPBrcBetween10:
972             wvlog << "Warning: sprmPBrcBetween10 doesn't make sense for Word 8" << endl;
973             break;
974         case SPRM::sprmPBrcBar10:
975             wvlog << "Warning: sprmPBrcBar10 doesn't make sense for Word 8" << endl;
976             break;
977         case SPRM::sprmPDxaFromText10:
978             wvlog << "Warning: sprmPDxaFromText10 doesn't make sense for Word 8" << endl;
979             break;
980         case SPRM::sprmPWr:
981             wr = *ptr;
982             break;
983         case SPRM::sprmPBrcTop:
984             readBRC( brcTop, ptr, version );
985             break;
986         case SPRM::sprmPBrcLeft:
987             readBRC( brcLeft, ptr, version );
988             break;
989         case SPRM::sprmPBrcBottom:
990             readBRC( brcBottom, ptr, version );
991             break;
992         case SPRM::sprmPBrcRight:
993             readBRC( brcRight, ptr, version );
994             break;
995         case SPRM::sprmPBrcBetween:
996             readBRC( brcBetween, ptr, version );
997             break;
998         case SPRM::sprmPBrcBar:
999             readBRC( brcBar, ptr, version );
1000             break;
1001         case SPRM::sprmPFNoAutoHyph:
1002             fNoAutoHyph = *ptr == 1;
1003             break;
1004         case SPRM::sprmPWHeightAbs:
1005         {
1006             U16 heightAbsTmp = readU16( ptr );
1007             dyaHeight = ( heightAbsTmp & 0xfffe );
1008             break;
1009         }
1010         case SPRM::sprmPDcs:
1011             dcs.readPtr( ptr );
1012             break;
1013         case SPRM::sprmPShd80:
1014             shd.readPtr( ptr );
1015             break;
1016         case SPRM::sprmPShd:
1017             shd.readSHDOperandPtr( ptr );       // and read the SHDOperand structure into SHD
1018             break;
1019         case SPRM::sprmPDyaFromText:
1020             dyaFromText = readS16( ptr );
1021             break;
1022         case SPRM::sprmPDxaFromText:
1023             dxaFromText = readS16( ptr );
1024             break;
1025         case SPRM::sprmPFLocked:
1026             fLocked = *ptr == 1;
1027             break;
1028         case SPRM::sprmPFWidowControl:
1029             fWidowControl = *ptr == 1;
1030             break;
1031         case SPRM::sprmPRuler:
1032             wvlog << "Warning: sprmPRuler not implemented" << endl;
1033             break;
1034         case SPRM::sprmPFKinsoku:
1035             fKinsoku = *ptr == 1;
1036             break;
1037         case SPRM::sprmPFWordWrap:
1038             fWordWrap = *ptr == 1;
1039             break;
1040         case SPRM::sprmPFOverflowPunct:
1041             fOverflowPunct = *ptr == 1;
1042             break;
1043         case SPRM::sprmPFTopLinePunct:
1044             fTopLinePunct = *ptr == 1;
1045             break;
1046         case SPRM::sprmPFAutoSpaceDE:
1047             fAutoSpaceDE = *ptr == 1;
1048             break;
1049         case SPRM::sprmPFAutoSpaceDN:
1050             fAutoSpaceDN = *ptr == 1;
1051             break;
1052         case SPRM::sprmPWAlignFont:
1053             wAlignFont = readU16( ptr );
1054             break;
1055         case SPRM::sprmPFrameTextFlow:
1056             wvlog << "Warning: sprmPFrameTextFlow not implemented" << endl;
1057             break;
1058         case SPRM::sprmPISnapBaseLine:
1059             wvlog << "Warning: sprmPISnapBaseLine is obsolete" << endl;
1060             break;
1061         case SPRM::sprmPAnld:
1062             if ( version == Word8 )
1063                 anld.readPtr( ptr + 1 ); // variable length, skip length byte
1064             else
1065                 anld = toWord97( Word95::ANLD( ptr + 1 ) );
1066             break;
1067         case SPRM::sprmPPropRMark:
1068             fPropRMark = *( ptr + 1 );
1069             ibstPropRMark = readS16( ptr + 2 );
1070             dttmPropRMark.readPtr( ptr + 4 );
1071             break;
1072         case SPRM::sprmPOutLvl:
1073             lvl = readS8( ptr );
1074             break;
1075         case SPRM::sprmPFBiDi:
1076             fBiDi = readS8( ptr );
1077             break;
1078         case SPRM::sprmPFNumRMIns:
1079             fNumRMIns = *ptr == 1;
1080             break;
1081         case SPRM::sprmPCrLf:
1082             fCrLf = *ptr;
1083             break;
1084         case SPRM::sprmPNumRM:
1085             numrm.readPtr( ptr + 1 );
1086             break;
1087         case SPRM::sprmPHugePapx:
1088         case SPRM::sprmPHugePapx2:
1089         {
1090             if ( dataStream ) {
1091                 dataStream->push();
1092                 dataStream->seek( readU32( ptr ), WV2_SEEK_SET );
1093                 const U16 count( dataStream->readU16() );
1094                 U8* grpprl = new U8[ count ];
1095                 dataStream->read( grpprl, count );
1096                 dataStream->pop();
1097 
1098                 apply( grpprl, count, style, styleSheet, dataStream, version );
1099                 delete [] grpprl;
1100             }
1101             else
1102                 wvlog << "Error: sprmPHugePapx found, but no data stream!" << endl;
1103             break;
1104         }
1105         case SPRM::sprmPFUsePgsuSettings:
1106             fUsePgsuSettings = *ptr == 1;
1107             break;
1108         case SPRM::sprmPFAdjustRight:
1109             fAdjustRight = *ptr == 1;
1110             break;
1111         case SPRM::sprmPNLvlAnmFake:
1112             nLvlAnm = *ptr;
1113             break;
1114         case SPRM::sprmPFDyaBeforeAuto:
1115             dyaBeforeAuto = *ptr == 1;
1116             break;
1117         case SPRM::sprmPFDyaAfterAuto:
1118             dyaAfterAuto = *ptr == 1;
1119             break;
1120         //START - table related SPRMs
1121         case SPRM::sprmPFInTable:
1122             fInTable = *ptr == 1;
1123             break;
1124         case SPRM::sprmPFTtp:
1125             fTtp = *ptr == 1;
1126             break;
1127         case SPRM::sprmPItap:
1128             itap = readU32( ptr );
1129             break;
1130         case SPRM::sprmPDtap:
1131             dtap = readS32( ptr );
1132             break;
1133         case SPRM::sprmPFInnerTableCell:
1134             fInnerTableCell = *ptr == 1;
1135             break;
1136         case SPRM::sprmPFInnerTtp:
1137             fInnerTtp = *ptr == 1;
1138             break;
1139         //END - table related SPRMs
1140         case SPRM::sprmPUndocumented1:
1141         case SPRM::sprmPUndocumented2:
1142         case SPRM::sprmPUndocumented3:
1143         case SPRM::sprmPUndocumented4:
1144             break;
1145         default:
1146             wvlog << "Huh? None of the defined sprms matches 0x" << hex << sprm << dec << "... trying to skip anyway" << endl;
1147             break;
1148     }
1149     return static_cast<S16>( sprmLength );  // length of the SPRM
1150 }
1151 
1152 // Apply a CHP grpprl of a given size ("count" bytes long)
apply(const U8 * grpprl,U16 count,const Style * paragraphStyle,const StyleSheet * styleSheet,OLEStreamReader * dataStream,WordVersion version)1153 void CHP::apply( const U8* grpprl, U16 count, const Style* paragraphStyle, const StyleSheet* styleSheet,
1154                  OLEStreamReader* dataStream, WordVersion version )
1155 {
1156     // There should be only CHP sprms in the grpprl we get
1157     SPRM::apply<CHP>( this, &CHP::applyCHPSPRM, grpprl, count, paragraphStyle, styleSheet, dataStream, version );
1158 }
1159 
applyExceptions(const U8 * exceptions,const Style * paragraphStyle,const StyleSheet * styleSheet,OLEStreamReader * dataStream,WordVersion version)1160 void CHP::applyExceptions( const U8* exceptions, const Style* paragraphStyle, const StyleSheet* styleSheet,
1161                            OLEStreamReader* dataStream, WordVersion version )
1162 {
1163     if ( exceptions == 0 )
1164         return;
1165     U8 cb = *exceptions;
1166     ++exceptions;
1167     apply( exceptions, cb, paragraphStyle, styleSheet, dataStream, version );
1168 }
1169 
1170 // Helper functions for more complex sprms
1171 namespace
1172 {
determineCHP(U16 istd,const Style * paragraphStyle,const StyleSheet * styleSheet)1173     const Word97::CHP* determineCHP( U16 istd, const Style* paragraphStyle, const StyleSheet* styleSheet )
1174     {
1175         const Word97::CHP* chp( 0 );
1176         if ( istd == 10 && paragraphStyle ) {
1177             chp = &paragraphStyle->chp();
1178         }
1179         else if ( istd != 10 && styleSheet ) {
1180             const Style* style( styleSheet->styleByIndex( istd ) );
1181             chp = ((style != 0) && (style->type() == sgcChp)) ? &style->chp() : 0;
1182         }
1183         else {
1184             wvlog << "Warning: sprmCFxyz couldn't find a style" << endl;
1185         }
1186         return chp;
1187     }
1188 }
1189 
1190 // Returns -1 if this wasn't a CHP sprm and it returns the length
1191 // of the applied sprm if it was successful
applyCHPSPRM(const U8 * ptr,const Style * paragraphStyle,const StyleSheet * styleSheet,OLEStreamReader * dataStream,WordVersion version)1192 S16 CHP::applyCHPSPRM( const U8* ptr, const Style* paragraphStyle, const StyleSheet* styleSheet, OLEStreamReader* dataStream, WordVersion version )
1193 {
1194     U16 sprmLength;
1195     const U16 sprm( getSPRM( &ptr, version, sprmLength ) );
1196 #ifdef WV2_DEBUG_SPRMS
1197     wvlog << "got a sprm: 0x" << hex << sprm << dec << endl;
1198 #endif
1199 
1200     // Is it a CHP sprm?
1201     if ( ( ( sprm & 0x1C00 ) >> 10 ) != 2 ) {
1202 #ifdef WV2_DEBUG_SPRMS
1203         wvlog << "Warning: You're trying to apply a non CHP sprm to a CHP. Not necessarily bad." << endl;
1204 #endif
1205         return -1;
1206     }
1207     // which one? ;)
1208     switch ( sprm ) {
1209         case SPRM::sprmNoop:
1210             wvlog << "Huh? Found a sprmNoop..." << endl;
1211             break;
1212         case SPRM::sprmCFRMarkDel:
1213             fRMarkDel = *ptr == 1;
1214             break;
1215         case SPRM::sprmCFRMark:
1216             fRMark = *ptr == 1;
1217             break;
1218         case SPRM::sprmCFFldVanish:
1219             fFldVanish = *ptr == 1;
1220             break;
1221         case SPRM::sprmCPicLocation:
1222             fSpec = 1;
1223             fcPic_fcObj_lTagObj = readS32( ptr + ( version == Word8 ? 0 : 1 ) );
1224             break;
1225         case SPRM::sprmCIbstRMark:
1226             ibstRMark = readS16( ptr );
1227             break;
1228         case SPRM::sprmCDttmRMark:
1229             dttmRMark.readPtr( ptr );
1230             break;
1231         case SPRM::sprmCFData:
1232             fData = *ptr == 1;
1233             break;
1234         case SPRM::sprmCIdslRMark:
1235             idslRMReason = readS16( ptr );
1236             break;
1237         case SPRM::sprmCChs:
1238             fChsDiff = *ptr == 1;
1239             chse = readU16( ptr + 1 );
1240             break;
1241         case SPRM::sprmCSymbol:
1242             if ( version == Word8 ) {
1243                 ftcSym = readS16( ptr );
1244                 xchSym = readS16( ptr + 2 );
1245             } else {
1246                 // First the length byte...
1247                 ftcSym = readS16( ptr + 1 );
1248                 xchSym = *( ptr + 3 );
1249             }
1250 #ifdef WV2_DEBUG_SPRMS
1251             wvlog << "sprmCSymbol: ftcSym=" << ftcSym << " xchSym=" << xchSym << endl;
1252 #endif
1253             fSpec = 1;
1254             break;
1255         case SPRM::sprmCFOle2:
1256             fOle2 = *ptr == 1;
1257             break;
1258         case SPRM::sprmCIdCharType:
1259             wvlog << "Warning: sprmCIdCharType doesn't make sense for Word 8" << endl;
1260             break;
1261         case SPRM::sprmCHighlight:
1262             icoHighlight = *ptr;
1263             fHighlight = icoHighlight != 0 ? 1 : 0;
1264             break;
1265         case SPRM::sprmCObjLocation:
1266             fcPic_fcObj_lTagObj = readU32( ptr );
1267             break;
1268         case SPRM::sprmCFFtcAsciSymb:
1269             fFtcAsciSym = *ptr == 1;
1270             break;
1271         case SPRM::sprmCIstd:
1272         {
1273             wvlog << "######################## old character style = " << istd << endl;
1274             istd = readS16( ptr );
1275             if ( styleSheet ) {
1276                 wvlog << "Trying to change the character style to " << istd << endl;
1277                 const Style* style = styleSheet->styleByIndex( istd );
1278                 if ( style && style->type() == sgcChp ) {
1279                     wvlog << "got a character style!" << endl;
1280                     const UPECHPX& upechpx( style->upechpx() );
1281                     apply( upechpx.grpprl, upechpx.cb, paragraphStyle, styleSheet, dataStream, version );
1282                 } else {
1283                     wvlog << "Warning: Couldn't find the character style with istd " << istd << endl;
1284                 }
1285             } else {
1286                 wvlog << "Warning: Tried to change the character style, but the stylesheet was 0" << endl;
1287             }
1288             break;
1289         }
1290         case SPRM::sprmCIstdPermute:
1291         {
1292             const U8* myPtr = ptr + 3; // cch, fLongg, fSpare
1293             const U16 istdFirst = readU16( myPtr );
1294             myPtr += 2;
1295             const U16 istdLast = readU16( myPtr );
1296             myPtr += 2;
1297             if ( istd > istdFirst && istd <= istdLast ) {
1298                 istd = myPtr[ istd - istdFirst ];
1299             }
1300             break;
1301         }
1302         case SPRM::sprmCDefault:
1303             fBold = false;
1304             fItalic = false;
1305             fOutline = false;
1306             fStrike = false;
1307             fShadow = false;
1308             fSmallCaps = false;
1309             fCaps = false;
1310             fVanish = false;
1311             kul = 0;
1312             cv = 0;
1313             break;
1314         case SPRM::sprmCPlain:
1315         {
1316             bool fSpecBackup = fSpec;
1317             if ( paragraphStyle ) {
1318                 *this = paragraphStyle->chp();
1319             }
1320             fSpec = fSpecBackup;
1321             break;
1322         }
1323         case SPRM::sprmCKcd:
1324             kcd = *ptr;
1325             break;
1326         case SPRM::sprmCFBold:
1327 #ifdef WV2_DEBUG_SPRMS
1328             wvlog << "sprmCFBold operand: 0x" << hex << *ptr << "| istd: 0x" << hex << istd <<
1329                      "| paragraphStyle:" << paragraphStyle;
1330 #endif
1331             if ( *ptr < 128 ) {
1332                 fBold = *ptr == 1;
1333             } else if ( *ptr == 128 && paragraphStyle ) {
1334                 fBold = paragraphStyle->chp().fBold;
1335             } else if ( *ptr == 129 && paragraphStyle ) {
1336                 fBold = !( paragraphStyle->chp().fBold );
1337             } else {
1338                 wvlog << "Warning: sprmCFBold couldn't find a style" << endl;
1339                 fBold = !fBold;
1340             }
1341             break;
1342         case SPRM::sprmCFItalic:
1343             if ( *ptr < 128 ) {
1344                 fItalic = *ptr == 1;
1345             } else if ( *ptr == 128 && paragraphStyle ) {
1346                 fItalic = paragraphStyle->chp().fItalic;
1347             } else if ( *ptr == 129 && paragraphStyle ) {
1348                 fItalic = !( paragraphStyle->chp().fItalic );
1349             } else {
1350                 wvlog << "Warning: sprmCFItalic couldn't find a style" << endl;
1351                 fItalic = !fItalic;
1352             }
1353             break;
1354         case SPRM::sprmCFStrike:
1355 #ifdef WV2_DEBUG_SPRMS
1356             wvlog << "sprmCFStrike -- fStrike = " << static_cast<int>( fStrike ) << " *ptr = " << static_cast<int>( *ptr ) << endl;
1357 #endif
1358             if ( *ptr < 128 ) {
1359                 fStrike = *ptr == 1;
1360             } else if ( *ptr == 128 && paragraphStyle ) {
1361                 fStrike = paragraphStyle->chp().fStrike;
1362             } else if ( *ptr == 129 && paragraphStyle ) {
1363                 fStrike = !( paragraphStyle->chp().fStrike );
1364             } else {
1365                 wvlog << "Warning: sprmCFStrike couldn't find a style" << endl;
1366                 fStrike = !fStrike;
1367             }
1368 #ifdef WV2_DEBUG_SPRMS
1369             wvlog << "sprmCFStrike -- fStrike (changed) = " << static_cast<int>( fStrike ) << endl;
1370 #endif
1371             break;
1372         case SPRM::sprmCFOutline:
1373             if ( *ptr < 128 ) {
1374                 fOutline = *ptr == 1;
1375             } else if ( *ptr == 128 && paragraphStyle ) {
1376                 fOutline = paragraphStyle->chp().fOutline;
1377             } else if ( *ptr == 129 && paragraphStyle ) {
1378                 fOutline = !( paragraphStyle->chp().fOutline );
1379             } else {
1380                 wvlog << "Warning: sprmCFOutline couldn't find a style" << endl;
1381                 fOutline = !fOutline;
1382             }
1383             break;
1384         case SPRM::sprmCFShadow:
1385             if ( *ptr < 128 ) {
1386                 fShadow = *ptr == 1;
1387             } else if ( *ptr == 128 && paragraphStyle ) {
1388                 fShadow = paragraphStyle->chp().fShadow;
1389             } else if ( *ptr == 129 && paragraphStyle ) {
1390                 fShadow = !( paragraphStyle->chp().fShadow );
1391             } else {
1392                 wvlog << "Warning: sprmCFShadow couldn't find a style" << endl;
1393                 fShadow = !fShadow;
1394             }
1395             break;
1396         case SPRM::sprmCFSmallCaps:
1397             if ( *ptr < 128 ) {
1398                 fSmallCaps = *ptr == 1;
1399             } else if ( *ptr == 128 && paragraphStyle ) {
1400                 fSmallCaps = paragraphStyle->chp().fSmallCaps;
1401             } else if ( *ptr == 129 && paragraphStyle ) {
1402                 fSmallCaps = !( paragraphStyle->chp().fSmallCaps );
1403             } else {
1404                 wvlog << "Warning: sprmCFSmallCaps couldn't find a style" << endl;
1405                 fSmallCaps = !fSmallCaps;
1406             }
1407             break;
1408         case SPRM::sprmCFCaps:
1409             if ( *ptr < 128 ) {
1410                 fCaps = *ptr == 1;
1411             } else if ( *ptr == 128 && paragraphStyle ) {
1412                 fCaps = paragraphStyle->chp().fCaps;
1413             } else if ( *ptr == 129 && paragraphStyle ) {
1414                 fCaps = !( paragraphStyle->chp().fCaps );
1415             } else {
1416                 wvlog << "Warning: sprmCFCaps couldn't find a style" << endl;
1417                 fCaps = !fCaps;
1418             }
1419             break;
1420         case SPRM::sprmCFVanish:
1421             if ( *ptr < 128 ) {
1422                 fVanish = *ptr == 1;
1423             } else if ( *ptr == 128 && paragraphStyle ) {
1424                 fVanish = paragraphStyle->chp().fVanish;
1425             } else if ( *ptr == 129 && paragraphStyle ) {
1426                 fVanish = !( paragraphStyle->chp().fVanish );
1427             } else {
1428                 wvlog << "Warning: sprmCFVanish couldn't find a style" << endl;
1429                 fVanish = !fVanish;
1430             }
1431             break;
1432         case SPRM::sprmCFtcDefault:
1433             // We are abusing this SPRM for Word 6 purposes (sprmCFtc, 93)
1434             //wvlog << "Error: sprmCFtcDefault only used internally in MS Word" << endl;
1435             ftcAscii = ftcFE = ftcOther = ftc = readS16( ptr );
1436             break;
1437         case SPRM::sprmCKul:
1438             kul = *ptr;
1439             break;
1440         case SPRM::sprmCSizePos:
1441             // The hps sprms would be quite hard to implement in a sane way
1442             wvlog << "Warning: sprmCSizePos not implemented" << endl;
1443             break;
1444         case SPRM::sprmCDxaSpace:
1445             dxaSpace = readS16( ptr );
1446             break;
1447         case SPRM::sprmCLid:
1448             // We are abusing this SPRM for Word 6 purposes (sprmCLid, 97)
1449             lidDefault = lidFE = lid = readU16( ptr );
1450             //wvlog << "Error: sprmCLid only used internally in MS Word" << endl;
1451             break;
1452         case SPRM::sprmCIco: {
1453             U16 ico = *ptr;
1454             cv=Word97::icoToCOLORREF(ico);
1455             break;
1456         }
1457         case SPRM::sprmCCv: {
1458             U8 r,g,b,k;
1459 
1460             r=readU8(ptr);
1461             ptr+=sizeof(U8);
1462             g=readU8(ptr);
1463             ptr+=sizeof(U8);
1464             b=readU8(ptr);
1465             ptr+=sizeof(U8);
1466             k=readU8(ptr);
1467             ptr+=sizeof(U8);
1468             cv=(k<<24)|(r<<16)|(g<<8)|(b);
1469             break;
1470         }
1471         case SPRM::sprmCCvUl: {
1472             U8 r,g,b,k;
1473 
1474             r=readU8(ptr);
1475             ptr+=sizeof(U8);
1476             g=readU8(ptr);
1477             ptr+=sizeof(U8);
1478             b=readU8(ptr);
1479             ptr+=sizeof(U8);
1480             k=readU8(ptr);
1481             ptr+=sizeof(U8);
1482             cvUl=(k<<24)|(r<<16)|(g<<8)|(b);
1483             break;
1484         }
1485         case SPRM::sprmCHps:
1486             hps = readU16( ptr );
1487             break;
1488         case SPRM::sprmCHpsInc:
1489             // The hps sprms would be quite hard to implement in a sane way
1490             wvlog << "Warning: sprmCHpsInc not implemented" << endl;
1491             break;
1492         case SPRM::sprmCHpsPos:
1493             hpsPos = readS16( ptr );
1494             break;
1495         case SPRM::sprmCHpsPosAdj:
1496             // The hps sprms would be quite hard to implement in a sane way
1497             wvlog << "Warning: sprmCHpsPosAdj not implemented" << endl;
1498             break;
1499         case SPRM::sprmCMajority:
1500         case SPRM::sprmCMajority50: // same as sprmCMajority
1501         {
1502             CHP tmpChp;
1503             tmpChp.ftc = 4; // the rest is default, looks a bit strange
1504             tmpChp.apply( ptr + 1, *ptr, paragraphStyle, styleSheet, dataStream, version );
1505             if ( paragraphStyle ) {
1506                 const CHP& pstyle( paragraphStyle->chp() );
1507                 if ( tmpChp.fBold == fBold )
1508                     fBold = pstyle.fBold;
1509                 if ( tmpChp.fItalic == fItalic )
1510                     fItalic = pstyle.fItalic;
1511                 if ( tmpChp.fStrike == fStrike )
1512                     fStrike = pstyle.fStrike;
1513                 if ( tmpChp.fOutline == fOutline )
1514                     fOutline = pstyle.fOutline;
1515                 if ( tmpChp.fShadow == fShadow )
1516                     fShadow = pstyle.fShadow;
1517                 if ( tmpChp.fSmallCaps == fSmallCaps )
1518                     fSmallCaps = pstyle.fSmallCaps;
1519                 if ( tmpChp.fCaps == fCaps )
1520                     fCaps = pstyle.fCaps;
1521                 if ( tmpChp.ftc == ftc )
1522                     ftc = pstyle.ftc;
1523                 if ( tmpChp.hps == hps )
1524                     hps = pstyle.hps;
1525                 if ( tmpChp.hpsPos == hpsPos )
1526                     hpsPos = pstyle.hpsPos;
1527                 if ( tmpChp.kul == kul )
1528                     kul = pstyle.kul;
1529                 if ( tmpChp.dxaSpace == dxaSpace ) // qpsSpace???
1530                     dxaSpace = pstyle.dxaSpace;
1531                 if ( tmpChp.cv == cv )
1532                     cv = pstyle.cv;
1533             }
1534             else
1535                 wvlog << "Warning: sprmCMajority couldn't find a style" << endl;
1536             break;
1537         }
1538         case SPRM::sprmCIss:
1539             iss = *ptr;
1540             break;
1541         case SPRM::sprmCHpsNew50:
1542             if ( *ptr != 2 )
1543                 wvlog << "Warning: sprmCHpsNew50 has a different length than 2" << endl;
1544             else
1545                 hps = readU16( ptr + 1 );
1546             break;
1547         case SPRM::sprmCHpsInc1:
1548             // The hps sprms would be quite hard to implement in a sane way
1549             wvlog << "Warning: sprmCHpsInc1 not implemented" << endl;
1550             break;
1551         case SPRM::sprmCHpsKern:
1552             hpsKern = readU16( ptr );
1553             break;
1554         case SPRM::sprmCHpsMul:
1555             hps = static_cast<int>( static_cast<double>( hps ) * ( 1.0 + static_cast<double>( readS16( ptr ) ) / 100.0 ) );
1556             break;
1557         case SPRM::sprmCYsri:
1558             // Undocumented, no idea if that's implemented correctly
1559             ysr = *ptr;
1560             chYsr = *( ptr + 1 );
1561             break;
1562         case SPRM::sprmCRgFtc0:
1563             ftcAscii = readS16( ptr );
1564             break;
1565         case SPRM::sprmCRgFtc1:
1566             ftcFE = readS16( ptr );
1567             break;
1568         case SPRM::sprmCRgFtc2:
1569             ftcOther = readS16( ptr );
1570             break;
1571         case SPRM::sprmCCharScale:
1572             wCharScale = readU16( ptr ); // undocumented, but should be okay
1573             break;
1574         case SPRM::sprmCFDStrike:
1575             if ( *ptr < 128 ) {
1576                 fDStrike = *ptr == 1;
1577             } else if ( *ptr == 128 && paragraphStyle ) {
1578                 fDStrike = paragraphStyle->chp().fDStrike;
1579             } else if ( *ptr == 129 && paragraphStyle ) {
1580                 fDStrike = !( paragraphStyle->chp().fDStrike );
1581             } else {
1582                 wvlog << "Warning: sprmCFDStrike couldn't find a style" << endl;
1583                 fDStrike = !fDStrike;
1584             }
1585             break;
1586         case SPRM::sprmCFImprint:
1587             if ( *ptr < 128 ) {
1588                 fImprint = *ptr == 1;
1589             } else if ( *ptr == 128 && paragraphStyle ) {
1590                 fImprint = paragraphStyle->chp().fImprint;
1591             } else if ( *ptr == 129 && paragraphStyle ) {
1592                 fImprint = !( paragraphStyle->chp().fImprint );
1593             } else {
1594                 wvlog << "Warning: sprmCFImprint couldn't find a style" << endl;
1595                 fImprint = !fImprint;
1596             }
1597             break;
1598         case SPRM::sprmCFSpec:
1599             if ( *ptr < 128 ) {
1600                 fSpec = *ptr == 1;
1601             } else if ( *ptr == 128 && paragraphStyle ) {
1602                 fSpec = paragraphStyle->chp().fSpec;
1603             } else if ( *ptr == 129 && paragraphStyle ) {
1604                 fSpec = !( paragraphStyle->chp().fSpec );
1605             } else {
1606                 wvlog << "Warning: sprmCFSpec couldn't find a style" << endl;
1607                 fSpec = !fSpec;
1608             }
1609             break;
1610         case SPRM::sprmCFObj:
1611             fObj = *ptr == 1;
1612             break;
1613         case SPRM::sprmCPropRMark:
1614             if ( *ptr != 7 ) {
1615                 wvlog << "Error: sprmCPropRMark has an unexpected size" << endl;
1616             }
1617             fPropMark = *( ptr + 1 ) == 1;
1618             ibstPropRMark = readS16( ptr + 2 );
1619             dttmPropRMark.readPtr( ptr + 4 );
1620             break;
1621         case SPRM::sprmCFEmboss:
1622             if ( *ptr < 128 ) {
1623                 fEmboss = *ptr == 1;
1624             } else if ( *ptr == 128 && paragraphStyle ) {
1625                 fEmboss = paragraphStyle->chp().fEmboss;
1626             } else if ( *ptr == 129 && paragraphStyle ) {
1627                 fEmboss = !( paragraphStyle->chp().fEmboss );
1628             } else {
1629                 wvlog << "Warning: sprmCFEmboss couldn't find a style" << endl;
1630                 fEmboss = !fEmboss;
1631             }
1632             break;
1633         case SPRM::sprmCSfxText:
1634             sfxtText = *ptr;
1635             break;
1636         // All the BiDi flags below aren't documented. The question is whether we should
1637         // add some BiDi versions of e.g. fBold and interpret these sprms here like plain
1638         // sprmCFBold. For now I just ignore them, as the only user of wv2 is Words, and
1639         // Words is intelligent enough to support BiDi "the right way." (Werner)
1640         case SPRM::sprmCFBiDi:
1641             // ###### Undocumented
1642             //wvlog << "Warning: sprmCFBiDi not implemented" << endl;
1643             break;
1644         case SPRM::sprmCFDiacColor:
1645             // ###### Undocumented
1646             //wvlog << "Warning: sprmCFDiacColor not implemented" << endl;
1647             break;
1648         case SPRM::sprmCFBoldBi:
1649             // ###### Undocumented
1650             //wvlog << "Warning: sprmCFBoldBi not implemented" << endl;
1651             break;
1652         case SPRM::sprmCFItalicBi:
1653             // ###### Undocumented
1654             //wvlog << "Warning: sprmCFItalicBi not implemented" << endl;
1655             break;
1656         case SPRM::sprmCFtcBi:
1657             // ###### Undocumented
1658             //wvlog << "Warning: sprmCFtcBi not implemented" << endl;
1659             break;
1660         case SPRM::sprmCLidBi:
1661             // OOo does something with that flag.
1662             wvlog << "Warning: sprmCLidBi not implemented (no documentation available)" << endl;
1663             break;
1664         case SPRM::sprmCIcoBi:
1665             // ###### Undocumented
1666             //wvlog << "Warning: sprmCIcoBi not implemented" << endl;
1667             break;
1668         case SPRM::sprmCHpsBi:
1669             // OOo does something with that flag.
1670             wvlog << "Warning: sprmCHpsBi not implemented (no documentation available)" << endl;
1671             break;
1672         case SPRM::sprmCDispFldRMark:
1673         {
1674             if ( *ptr != 39 ) {
1675                 wvlog << "Warning: sprmCDispFldRMark has a different length than 39" << endl;
1676             } else {
1677                 fDispFldRMark = *( ptr + 1 ) == 1;
1678                 ibstDispFldRMark = readS16( ptr + 2 );
1679                 dttmPropRMark.readPtr( ptr + 4 );
1680                 for ( int i = 0; i < 16; ++i )
1681                     xstDispFldRMark[ i ] = readU16( ptr + 8 + i * sizeof( U16 ) );
1682             }
1683             break;
1684         }
1685         case SPRM::sprmCIbstRMarkDel:
1686             ibstRMarkDel = readS16( ptr );
1687             break;
1688         case SPRM::sprmCDttmRMarkDel:
1689             dttmRMarkDel.readPtr( ptr );
1690             break;
1691         case SPRM::sprmCBrc:
1692             readBRC( brc, ptr, version );
1693             break;
1694         case SPRM::sprmCShd:
1695             ptr++;
1696             shd.read90Ptr( ptr );
1697             break;
1698         case SPRM::sprmCShd80:
1699             shd.readPtr( ptr );
1700             break;
1701         case SPRM::sprmCIdslRMarkDel:
1702             idslRMReasonDel = readS16( ptr );
1703             break;
1704         case SPRM::sprmCFUsePgsuSettings:
1705             if ( *ptr < 128 ) {
1706                 fUsePgsuSettings = *ptr == 1;
1707             } else if ( *ptr == 128 && paragraphStyle ) {
1708                 fUsePgsuSettings = paragraphStyle->chp().fUsePgsuSettings;
1709             } else if ( *ptr == 129 && paragraphStyle ) {
1710                 fUsePgsuSettings = !( paragraphStyle->chp().fUsePgsuSettings );
1711             } else {
1712                 wvlog << "Warning: sprmCFSpec couldn't find a style" << endl;
1713                 fUsePgsuSettings = !fUsePgsuSettings;
1714             }
1715             break;
1716         case SPRM::sprmCCpg:
1717             // Undocumented, no idea what this variable is for. I changed it to chse in
1718             // the spec as it made more sense. (Werner)
1719             //wvlog << "Warning: sprmCCpg not implemented" << endl;
1720             break;
1721         case SPRM::sprmCRgLid0:
1722         case SPRM::sprmCRgLidUndocumented1: // according to OOo a dup. of sprmCRgLid0
1723             lidDefault = readU16( ptr );
1724             break;
1725         case SPRM::sprmCRgLid1:
1726             lidFE = readU16( ptr );
1727             break;
1728         case SPRM::sprmCIdctHint:
1729             idct = *ptr;
1730             break;
1731         // Fall-through intended
1732         case SPRM::sprmCUndocumented1:
1733         case SPRM::sprmCUndocumented2:
1734             break;  // They are not documented but they are skipped correctly
1735         case SPRM::sprmCFELayout:
1736         {
1737             //skipping cb
1738             U16 ufel = readU16( ptr + sizeof(U8) );
1739             fTNY = ufel;
1740             //skip to compress;
1741             ufel >>= 12;
1742             fTNYCompress = ufel;
1743             break;
1744         }
1745         case SPRM::sprmCPbiIBullet:
1746             picBulletCP = readU16( ptr );
1747             wvlog << "=> picBulletCP:" << picBulletCP;
1748             break;
1749         case SPRM::sprmCPbiGrf:
1750             fPicBullet = (*ptr & 0x01);
1751             fNoAutoSize = (*ptr & 0x02) >> 1;
1752             wvlog << "=> fPicBullet:" << fPicBullet << "| fNoAutoSize:" << fNoAutoSize << "| check:" << *ptr;
1753             break;
1754         default:
1755             wvlog << "Huh? None of the defined sprms matches 0x" << hex << sprm << dec << "... trying to skip anyway" << endl;
1756             break;
1757     }
1758     return static_cast<S16>( sprmLength );  // length of the SPRM
1759 }
1760 
1761 
1762 // Apply a PICF grpprl of a given size ("count" bytes long)
apply(const U8 * grpprl,U16 count,const Style * style,const StyleSheet * styleSheet,OLEStreamReader * dataStream,WordVersion version)1763 void PICF::apply( const U8* grpprl, U16 count, const Style* style, const StyleSheet* styleSheet,
1764                   OLEStreamReader* dataStream, WordVersion version )
1765 {
1766     // There should be only PICF sprms in the grpprl we get
1767     SPRM::apply<PICF>( this, &PICF::applyPICFSPRM, grpprl, count, style, styleSheet, dataStream, version );
1768 }
1769 
applyExceptions(const U8 *,const StyleSheet *,OLEStreamReader *,WordVersion)1770 void PICF::applyExceptions(const U8* /*exceptions*/, const StyleSheet* /*stylesheet*/, OLEStreamReader* /*dataStream*/, WordVersion /*version*/ )
1771 {
1772     // ### CHECK: Do we need that at all?
1773 }
1774 
1775 // Returns -1 if this wasn't a PICF sprm and it returns the length
1776 // of the applied sprm if it was successful
applyPICFSPRM(const U8 * ptr,const Style *,const StyleSheet *,OLEStreamReader *,WordVersion version)1777 S16 PICF::applyPICFSPRM( const U8* ptr, const Style* /*style*/, const StyleSheet* /*styleSheet*/,
1778                          OLEStreamReader* /*dataStream*/, WordVersion version )
1779 {
1780     U16 sprmLength;
1781     const U16 sprm( getSPRM( &ptr, version, sprmLength ) );
1782 
1783     // Is it a PICF sprm?
1784     if ( ( ( sprm & 0x1C00 ) >> 10 ) != 3 ) {
1785         wvlog << "Warning: You're trying to apply a non PICF sprm to a PICF." << endl;
1786         return -1;
1787     }
1788     // which one? ;)
1789     switch ( sprm ) {
1790         case SPRM::sprmNoop:
1791             wvlog << "Huh? Found a sprmNoop..." << endl;
1792             break;
1793         case SPRM::sprmPicBrcl:
1794             brcl = *ptr;
1795             break;
1796         case SPRM::sprmPicScale:
1797             if ( *ptr != 12 )
1798                 wvlog << "Warning: sprmPicScale has a different size (" << static_cast<int>( *ptr )
1799                       << ") than expected (12)." << endl;
1800             mx = readU16( ptr + 1 );
1801             my = readU16( ptr + 3 );
1802             dxaCropLeft = readU16( ptr + 5 );
1803             dyaCropTop = readU16( ptr + 7 );
1804             dxaCropRight = readU16( ptr + 9 );
1805             dyaCropBottom = readU16( ptr + 11 );
1806             break;
1807         case SPRM::sprmPicBrcTop:
1808             readBRC( brcTop, ptr, version );
1809             break;
1810         case SPRM::sprmPicBrcLeft:
1811             readBRC( brcLeft, ptr, version );
1812             break;
1813         case SPRM::sprmPicBrcBottom:
1814             readBRC( brcBottom, ptr, version );
1815             break;
1816         case SPRM::sprmPicBrcRight:
1817             readBRC( brcRight, ptr, version );
1818             break;
1819         default:
1820             wvlog << "Huh? None of the defined sprms matches 0x" << hex << sprm << dec << "... trying to skip anyway" << endl;
1821             break;
1822     }
1823     return static_cast<S16>( sprmLength );  // length of the SPRM
1824 }
1825 
1826 
1827 // Apply a SEP grpprl of a given size ("count" bytes long)
apply(const U8 * grpprl,U16 count,const Style * style,const StyleSheet * styleSheet,OLEStreamReader * dataStream,WordVersion version)1828 void SEP::apply( const U8* grpprl, U16 count, const Style* style, const StyleSheet* styleSheet,
1829                  OLEStreamReader* dataStream, WordVersion version )
1830 {
1831     // There should be only SEP sprms in the grpprl we get
1832     SPRM::apply<SEP>( this, &SEP::applySEPSPRM, grpprl, count, style, styleSheet, dataStream, version );
1833 }
1834 
applyExceptions(const U8 * exceptions,const StyleSheet * styleSheet,OLEStreamReader * dataStream,WordVersion version)1835 void SEP::applyExceptions( const U8* exceptions, const StyleSheet* styleSheet, OLEStreamReader* dataStream, WordVersion version )
1836 {
1837     if ( exceptions == 0 )
1838         return;
1839     U16 cb = readU16( exceptions );
1840     exceptions += 2;
1841     apply( exceptions, cb, 0, styleSheet, dataStream, version );
1842 }
1843 
1844 // Returns -1 if this wasn't a SEP sprm and it returns the length
1845 // of the applied sprm if it was successful
applySEPSPRM(const U8 * ptr,const Style *,const StyleSheet *,OLEStreamReader *,WordVersion version)1846 S16 SEP::applySEPSPRM( const U8* ptr, const Style* /*style*/, const StyleSheet* /*styleSheet*/, OLEStreamReader* /*dataStream*/, WordVersion version )
1847 {
1848     U16 sprmLength;
1849     const U16 sprm( getSPRM( &ptr, version, sprmLength ) );
1850 
1851     // Is it a SEP sprm?
1852     if ( ( ( sprm & 0x1C00 ) >> 10 ) != 4 ) {
1853         wvlog << "Warning: You're trying to apply a non SEP sprm to a SEP." << endl;
1854         return -1;
1855     }
1856     // which one? ;)
1857     switch ( sprm ) {
1858         case SPRM::sprmNoop:
1859             wvlog << "Huh? Found a sprmNoop..." << endl;
1860             break;
1861         case SPRM::sprmScnsPgn:
1862             cnsPgn = *ptr;
1863             break;
1864         case SPRM::sprmSiHeadingPgn:
1865             iHeadingPgn = *ptr;
1866             break;
1867         case SPRM::sprmSOlstAnm:
1868             if ( version == Word8 )
1869                 olstAnm.readPtr( ptr + 1 ); // variable length, skip length byte
1870             else
1871                 olstAnm = toWord97( Word95::OLST( ptr + 1 ) );
1872             break;
1873         case SPRM::sprmSDxaColWidth:
1874             wvlog << "Warning: sprmSDxaColWidth not implemented" << endl;
1875             break;
1876         case SPRM::sprmSDxaColSpacing:
1877             wvlog << "Warning: sprmSDxaColSpacing not implemented" << endl;
1878             break;
1879         case SPRM::sprmSFEvenlySpaced:
1880             fEvenlySpaced = *ptr == 1;
1881             break;
1882         case SPRM::sprmSFProtected:
1883             fUnlocked = *ptr == 1;
1884             break;
1885         case SPRM::sprmSDmBinFirst:
1886             dmBinFirst = readU16( ptr );
1887             break;
1888         case SPRM::sprmSDmBinOther:
1889             dmBinOther = readU16( ptr );
1890             break;
1891         case SPRM::sprmSBkc:
1892             bkc = *ptr;
1893             break;
1894         case SPRM::sprmSFTitlePage:
1895             fTitlePage = *ptr == 1;
1896             break;
1897         case SPRM::sprmSCcolumns:
1898             ccolM1 = readS16( ptr );
1899             break;
1900         case SPRM::sprmSDxaColumns:
1901             dxaColumns = readS16( ptr );
1902             break;
1903         case SPRM::sprmSFAutoPgn:
1904             fAutoPgn = *ptr == 1;
1905             break;
1906         case SPRM::sprmSNfcPgn:
1907             nfcPgn = *ptr;
1908             break;
1909         case SPRM::sprmSDyaPgn:
1910             dyaPgn = readS16( ptr );
1911             break;
1912         case SPRM::sprmSDxaPgn:
1913             dxaPgn = readS16( ptr );
1914             break;
1915         case SPRM::sprmSFPgnRestart:
1916             fPgnRestart = *ptr == 1;
1917             break;
1918         case SPRM::sprmSFEndnote:
1919             fEndNote = *ptr == 1;
1920             break;
1921         case SPRM::sprmSLnc:
1922             lnc = *ptr;
1923             break;
1924         case SPRM::sprmSGprfIhdt:
1925             grpfIhdt = *ptr;
1926             break;
1927         case SPRM::sprmSNLnnMod:
1928             nLnnMod = readU16( ptr );
1929             break;
1930         case SPRM::sprmSDxaLnn:
1931             dxaLnn = readS16( ptr );
1932             break;
1933         case SPRM::sprmSDyaHdrTop:
1934             dyaHdrTop = readU16( ptr );
1935             break;
1936         case SPRM::sprmSDyaHdrBottom:
1937             dyaHdrBottom = readU16( ptr );
1938             break;
1939         case SPRM::sprmSLBetween:
1940             fLBetween = *ptr == 1;
1941             break;
1942         case SPRM::sprmSVjc:
1943             vjc = *ptr;
1944             break;
1945         case SPRM::sprmSLnnMin:
1946             lnnMin = readS16( ptr );
1947             break;
1948         case SPRM::sprmSPgnStart:
1949             pgnStart = readU16( ptr );
1950             break;
1951         case SPRM::sprmSBOrientation:
1952             dmOrientPage = *ptr;
1953             break;
1954         case SPRM::sprmSBCustomize:
1955             wvlog << "Warning: sprmSBCustomize not implemented" << endl;
1956             break;
1957         case SPRM::sprmSXaPage:
1958             xaPage = readU16( ptr );
1959             break;
1960         case SPRM::sprmSYaPage:
1961             yaPage = readU16( ptr );
1962             break;
1963         case SPRM::sprmSDxaLeft:
1964             dxaLeft = readU16( ptr );
1965             break;
1966         case SPRM::sprmSDxaRight:
1967             dxaRight = readU16( ptr );
1968             break;
1969         case SPRM::sprmSDyaTop:
1970             dyaTop = readS16( ptr );
1971             break;
1972         case SPRM::sprmSDyaBottom:
1973             dyaBottom = readS16( ptr );
1974             break;
1975         case SPRM::sprmSDzaGutter:
1976             dzaGutter = readU16( ptr );
1977             break;
1978         case SPRM::sprmSDmPaperReq:
1979             dmPaperReq = readU16( ptr );
1980             break;
1981         case SPRM::sprmSPropRMark:
1982             fPropRMark = *( ptr + 1 );
1983             ibstPropRMark = readS16( ptr + 2 );
1984             dttmPropRMark.readPtr( ptr + 4 );
1985             break;
1986         case SPRM::sprmSFBiDi:
1987             wvlog << "Warning: sprmSFBiDi not implemented" << endl;
1988             break;
1989         case SPRM::sprmSFFacingCol:
1990             wvlog << "Warning: sprmSFFacingCol not implemented" << endl;
1991             break;
1992         case SPRM::sprmSFRTLGutter:
1993             wvlog << "Warning: sprmSFRTLGutter not implemented" << endl;
1994             break;
1995         case SPRM::sprmSBrcTop:
1996             readBRC( brcTop, ptr, version );
1997             break;
1998         case SPRM::sprmSBrcLeft:
1999             readBRC( brcLeft, ptr, version );
2000             break;
2001         case SPRM::sprmSBrcBottom:
2002             readBRC( brcBottom, ptr, version );
2003             break;
2004         case SPRM::sprmSBrcRight:
2005             readBRC( brcRight, ptr, version );
2006             break;
2007         case SPRM::sprmSPgbProp:
2008         {
2009             U16 pgbProp = readU16( ptr );
2010             pgbApplyTo = pgbProp;
2011             pgbProp >>= 3;
2012             pgbPageDepth = pgbProp;
2013             pgbProp >>= 2;
2014             pgbOffsetFrom = pgbProp;
2015             pgbProp >>= 3;
2016             unused74_8 = pgbProp;
2017             break;
2018         }
2019         case SPRM::sprmSDxtCharSpace:
2020             dxtCharSpace = readS32( ptr );
2021             break;
2022         case SPRM::sprmSDyaLinePitch:
2023             dyaLinePitch = readS32( ptr );
2024             break;
2025         case SPRM::sprmSClm:
2026             clm = readU16( ptr );
2027             break;
2028         case SPRM::sprmSNfcFtnRef:
2029             nfcFtnRef = readU16( ptr );
2030             break;
2031         case SPRM::sprmSNfcEdnRef:
2032             nfcEdnRef = readU16( ptr );
2033             break;
2034         case SPRM::sprmSTextFlow:
2035             wTextFlow = readU16( ptr );
2036             break;
2037         default:
2038             wvlog << "Huh? None of the defined sprms matches 0x" << hex << sprm << dec << "... trying to skip anyway" << endl;
2039             break;
2040     }
2041     return static_cast<S16>( sprmLength );  // length of the SPRM
2042 }
2043 
2044 
2045 // Apply a TAP grpprl (or at least the TAP properties of a PAP/TAP grpprl)
2046 // of a given size ("count" bytes long)
apply(const U8 * grpprl,U16 count,const Style * style,const StyleSheet * styleSheet,OLEStreamReader * dataStream,WordVersion version)2047 void TAP::apply( const U8* grpprl, U16 count, const Style* style, const StyleSheet* styleSheet,
2048                  OLEStreamReader* dataStream, WordVersion version )
2049 {
2050     // There should be mostly TAP sprms in the grpprl we get, and we
2051     // have to ignore the remaining PAP sprms, just what the template does
2052     SPRM::apply<TAP>( this, &TAP::applyTAPSPRM, grpprl, count, style, styleSheet, dataStream, version );
2053 }
2054 
applyExceptions(const U8 *,const StyleSheet *,OLEStreamReader *,WordVersion)2055 void TAP::applyExceptions( const U8* /*exceptions*/, const StyleSheet* /*stylesheet*/, OLEStreamReader* /*dataStream*/, WordVersion /*version*/ )
2056 {
2057     // ### TODO -- is that needed at all?
2058 }
2059 
2060 namespace
2061 {
cropIndices(U8 & itcFirst,U8 & itcLim,U8 size)2062     void cropIndices( U8& itcFirst, U8& itcLim, U8 size )
2063     {
2064         if ( itcFirst >= size ) {
2065             wvlog << "Warning: itcFirst out of bounds" << endl;
2066             itcFirst = size - 1;
2067         }
2068         if ( itcLim > size ) {
2069             wvlog << "Warning: itcLim out of bounds" << endl;
2070             itcLim = size;
2071         }
2072     }
2073 }
2074 
2075 // Returns -1 if this wasn't a TAP sprm and it returns the length
2076 // of the applied sprm if it was successful
applyTAPSPRM(const U8 * ptr,const Style * style,const StyleSheet * styleSheet,OLEStreamReader * dataStream,WordVersion version)2077 S16 TAP::applyTAPSPRM( const U8* ptr, const Style* style, const StyleSheet* styleSheet, OLEStreamReader* dataStream, WordVersion version )
2078 {
2079     U16 sprmLength;
2080     const U16 sprm( getSPRM( &ptr, version, sprmLength ) );
2081 
2082 #ifdef WV2_DEBUG_SPRMS
2083     wvlog << "sprm: 0x" << hex << sprm << dec << endl;
2084     wvlog << "sprmLength: " << sprmLength << endl;
2085 #endif
2086     // Is it a TAP sprm? Not really an error if it's none, as all TAP sprms
2087     // live inside PAP grpprls
2088     if ( ( ( sprm & 0x1C00 ) >> 10 ) != 5 &&
2089          (sprm != SPRM::sprmPHugePapx) &&
2090          (sprm != SPRM::sprmPHugePapx2) &&
2091          (sprm != SPRM::sprmPTableProps) )
2092     {
2093 #ifdef WV2_DEBUG_SPRMS
2094         wvlog << "Warning: You're trying to apply a non TAP sprm to a TAP. Not necessarily bad."
2095               << endl;
2096 #endif
2097         return -1;
2098     }
2099     // which one? ;)
2100     switch ( sprm ) {
2101     case SPRM::sprmNoop:
2102         wvlog << "Huh? Found a sprmNoop..." << endl;
2103         break;
2104     case SPRM::sprmTJc:
2105         jc = readS16( ptr );
2106         break;
2107     case SPRM::sprmTDxaLeft:
2108     {
2109         //NOTE: no recalculation of the horizontal origin, use rgdxaCenter[0]
2110 
2111 //         const S16 dxaNew = readS16( ptr ) - ( rgdxaCenter[ 0 ] + dxaGapHalf );
2112 //         std::transform( rgdxaCenter.begin(), rgdxaCenter.end(), rgdxaCenter.begin(),
2113 //                         std::bind1st( std::plus<S16>(), dxaNew ) );
2114 
2115         dxaLeft = readS16( ptr );
2116 #ifdef WV2_DEBUG_SPRMS
2117         wvlog << "dxaLeft: " << dxaLeft << endl;
2118 #endif
2119         break;
2120     }
2121     case SPRM::sprmTDxaGapHalf:
2122     {
2123         //NOTE: no recalculation of the horizontal origin, use rgdxaCenter[0]
2124 
2125 //         const S16 dxaGapHalfNew = readS16( ptr );
2126 //         if ( !rgdxaCenter.empty() ) {
2127 //             rgdxaCenter[ 0 ] += dxaGapHalf - dxaGapHalfNew;
2128 //         }
2129 
2130     dxaGapHalf = readS16( ptr );
2131 #ifdef WV2_DEBUG_SPRMS
2132         wvlog << "dxaGapHalf: " << dxaGapHalf << endl;
2133 #endif
2134         break;
2135     }
2136     case SPRM::sprmTFCantSplit:
2137         fCantSplit = *ptr == 1;
2138         break;
2139     case SPRM::sprmTTableHeader:
2140         fTableHeader = *ptr == 1;
2141         break;
2142     case SPRM::sprmTTableBorders80:
2143     {
2144         const U8 inc = version == Word8 ? Word97::BRC::sizeOf97 : Word95::BRC::sizeOf;
2145         for ( int i = 0; i < 6; ++i )
2146         {
2147             // skip the leading size byte
2148             readBRC( rgbrcTable[ i ], ptr + 1 + i * inc, version );
2149         }
2150         break;
2151     }
2152     case SPRM::sprmTTableBorders:
2153     {
2154         const U8 inc = version == Word8 ? Word97::BRC::sizeOf : Word95::BRC::sizeOf;
2155         for ( int i = 0; i < 6; ++i )
2156             // skip the leading size byte
2157             rgbrcTable[ i ].read90Ptr( ptr + 1 + i * inc );
2158         break;
2159     }
2160     case SPRM::sprmTDefTable10:
2161         wvlog << "Warning: sprmTDefTable10 is obsolete" << endl;
2162         break;
2163     case SPRM::sprmTDyaRowHeight:
2164         dyaRowHeight = readS16( ptr );
2165         break;
2166     case SPRM::sprmTDefTable:
2167     {
2168         if ( itcMac != 0 ) {
2169             wvlog << "Bug: Assumption about sprmTDefTable not true" << endl;
2170             break;
2171         }
2172         int remainingLength = readU16( ptr ) - 1;
2173         itcMac = *( ptr + 2 );
2174 
2175         remainingLength -= 2 * ( itcMac + 1 );
2176         if ( remainingLength < 0 ) {
2177             wvlog << "Bug: Not even enough space for the dxas!" << endl;
2178             break;
2179         }
2180         const U8* myPtr = ptr + 3;
2181         const U8* myLim = ptr + 3 + 2 * ( itcMac + 1 );
2182         while ( myPtr < myLim ) {
2183             rgdxaCenter.push_back( readS16( myPtr ) );
2184             myPtr += 2;
2185         }
2186 #ifdef WV2_DEBUG_SPRMS
2187         wvlog << "rgdxaCenter[0]: " << rgdxaCenter[0] << endl;
2188 #endif
2189         const int tcSize = version == Word8 ? Word97::TC::sizeOf : Word95::TC::sizeOf;
2190         myLim = myPtr + ( remainingLength / tcSize ) * tcSize;
2191         while ( myPtr < myLim ) {
2192             if ( version == Word8 ) {
2193                 rgtc.push_back( TC( myPtr ) );
2194             }
2195             else {
2196                 rgtc.push_back( toWord97( Word95::TC( myPtr ) ) );
2197             }
2198             myPtr += tcSize;
2199         }
2200         if ( rgtc.size() < static_cast<std::vector<S16>::size_type>( itcMac ) ) {
2201             rgtc.insert( rgtc.end(), itcMac - rgtc.size(), TC() );
2202         }
2203         //default shading
2204         rgshd.insert( rgshd.begin(), itcMac, SHD() );
2205         break;
2206     }
2207     case SPRM::sprmTDefTableShd80:
2208     {
2209         const U8* myPtr = ptr + 1;
2210         const U8* myLim = ptr + 1 + *ptr;
2211         rgshd.clear();
2212         while ( myPtr < myLim ) {
2213             rgshd.push_back( SHD( myPtr ) );
2214             myPtr += SHD::sizeOf;
2215         }
2216         if ( rgshd.size() < static_cast<std::vector<S16>::size_type>( itcMac ) ) {
2217             rgshd.insert( rgshd.end(), itcMac - rgshd.size(), SHD() );
2218         }
2219         break;
2220     }
2221     case SPRM::sprmTDefTableShd:
2222     {
2223         const U8* myPtr = ptr + 1;
2224         const U8* myLim = ptr + 1 + *ptr;
2225         rgshd.clear();
2226         while ( myPtr < myLim ) {
2227             SHD shd;
2228             shd.read90Ptr(myPtr);
2229             rgshd.push_back( shd );
2230             myPtr += SHD::sizeOf;
2231         }
2232         if ( rgshd.size() < static_cast<std::vector<S16>::size_type>( itcMac ) ) {
2233             rgshd.insert( rgshd.end(), itcMac - rgshd.size(), SHD() );
2234         }
2235         break;
2236     }
2237     case SPRM::sprmTDefTableShd2nd:
2238     {
2239         wvlog << "Warning: sprmTDefTableShd2nd not implemented" << endl;
2240         break;
2241     }
2242     case SPRM::sprmTDefTableShd3rd:
2243     {
2244         wvlog << "Warning: sprmTDefTableShd3rd not implemented" << endl;
2245         break;
2246     }
2247     case SPRM::sprmTTlp:
2248         tlp.readPtr( ptr );
2249         break;
2250     case SPRM::sprmTFBiDi:
2251         fBiDi = readU16( ptr );
2252         break;
2253     case SPRM::sprmTPc:
2254     {
2255         pcVert = ( *ptr & 0x30 ) >> 4;
2256         pcHorz = ( *ptr & 0xC0 ) >> 6;
2257         break;
2258     }
2259     case SPRM::sprmTDxaFromText:
2260         dxaFromText = readU16( ptr );
2261         textWrap = 1;
2262         break;
2263     case SPRM::sprmTDyaFromText:
2264         dyaFromText = readU16( ptr );
2265         textWrap = 1;
2266         break;
2267     case SPRM::sprmTDxaFromTextRight:
2268         dxaFromTextRight = readU16( ptr );
2269         textWrap = 1;
2270         break;
2271     case SPRM::sprmTDyaFromTextBottom:
2272         dyaFromTextBottom = readU16( ptr );
2273         textWrap = 1;
2274         break;
2275     case SPRM::sprmTDxaAbs:
2276         dxaAbs = readS16( ptr );
2277         break;
2278     case SPRM::sprmTDyaAbs:
2279         dyaAbs = readS16( ptr );
2280         break;
2281     case SPRM::sprmTHTMLProps:
2282         wvlog << "Warning: sprmTHTMLProps not implemented" << endl;
2283         break;
2284     case SPRM::sprmTSetBrc80:
2285     {
2286         const U8* myPtr( version == Word8 ? ptr + 1 : ptr );  // variable size byte for Word 8!
2287         U8 itcFirst = *myPtr;
2288         U8 itcLim = *( myPtr + 1 );
2289         cropIndices( itcFirst, itcLim, rgtc.size() );
2290         const U8 flags = *( myPtr + 2 );
2291         BRC brc;
2292         readBRC( brc, myPtr + 3, version );
2293 
2294         for ( ; itcFirst < itcLim; ++itcFirst ) {
2295             if ( flags & 0x01 )
2296                 rgtc[ itcFirst ].brcTop = brc;
2297             if ( flags & 0x02 )
2298                 rgtc[ itcFirst ].brcLeft = brc;
2299             if ( flags & 0x04 )
2300                 rgtc[ itcFirst ].brcBottom = brc;
2301             if ( flags & 0x08 )
2302                 rgtc[ itcFirst ].brcRight = brc;
2303         }
2304         break;
2305     }
2306     case SPRM::sprmTInsert:
2307     {
2308         //NOTE: don't process before sprmTDefTable
2309     if ( itcMac == 0 ) {
2310             wvlog << "Bug: Assumption about sprmTDefTable not true" << endl;
2311             break;
2312         }
2313     // Sanity check
2314         if ( static_cast<std::vector<S16>::size_type>( itcMac ) + 1 != rgdxaCenter.size() ) {
2315             wvlog << "Bug: Somehow itcMac and the rgdxaCenter.size() aren't in sync anymore!" << endl;
2316             itcMac = rgdxaCenter.size() - 1;
2317         }
2318 
2319         const U8 itcFirst = *ptr;
2320         const U8 ctc = *( ptr + 1 );
2321         const U16 dxaCol = readU16( ptr + 2 );
2322 
2323         if ( itcMac < itcFirst ) {
2324             // Shaky, no idea why we would have to subtract ctc here?  The
2325             // implementation below is a guess from me, but it looks like this
2326             // never happens in real documents.
2327             wvlog << "Warning: sprmTInsert: Debug me ########################################" << endl;
2328 
2329             S16 runningDxaCol = 0;
2330             if ( !rgdxaCenter.empty() ) {
2331                 runningDxaCol = rgdxaCenter.back();
2332             }
2333 
2334             for ( ; itcMac < itcFirst; ++itcMac ) {
2335                 // If the index is bigger than our current array we just fill
2336                 // the hole with dummy cells (dxaCol wide, default TC) as
2337                 // suggested in the documentation
2338                 runningDxaCol += dxaCol;
2339                 rgdxaCenter.push_back( runningDxaCol );
2340                 rgtc.push_back( TC() );
2341             }
2342         } else {
2343             S16 runningDxaCol;
2344             if ( itcFirst > 0 ) {
2345                 runningDxaCol = rgdxaCenter[ itcFirst - 1 ] + dxaCol;
2346             }
2347             // preserve the position of the table row
2348             else {
2349                 runningDxaCol = rgdxaCenter[ 0 ];
2350             }
2351             for ( int i = 0; i < ctc; ++i ) {
2352                 std::vector<S16>::iterator dxaIt = rgdxaCenter.begin() + itcFirst + i;
2353                 rgdxaCenter.insert( dxaIt, runningDxaCol );
2354                 runningDxaCol += dxaCol;
2355             }
2356 
2357             rgtc.insert( rgtc.begin() + itcFirst, ctc, TC() );
2358             rgshd.insert( rgshd.begin() + itcFirst, ctc, SHD() );
2359             itcMac += ctc;
2360 
2361             // Adjust all successive items (+= ctc * dxaCol)
2362             std::transform( rgdxaCenter.begin() + itcFirst + ctc, rgdxaCenter.end(),
2363                             rgdxaCenter.begin() + itcFirst + ctc,
2364                             std::bind1st( std::plus<S16>(), ctc * dxaCol ) );
2365         }
2366         break;
2367     }
2368     case SPRM::sprmTDelete:
2369     {
2370         U8 itcFirst = *ptr;
2371         U8 itcLim = *( ptr + 1 );
2372         cropIndices( itcFirst, itcLim, rgdxaCenter.size() );
2373 
2374         rgdxaCenter.erase( rgdxaCenter.begin() + itcFirst, rgdxaCenter.begin() + itcLim );
2375         rgtc.erase( rgtc.begin() + itcFirst, rgtc.begin() + itcLim );
2376         rgshd.erase( rgshd.begin() + itcFirst, rgshd.begin() + itcLim );
2377 
2378         itcMac -= itcLim - itcFirst;
2379         break;
2380     }
2381     case SPRM::sprmTDxaCol:
2382     {
2383         //NOTE: don't process before sprmTDefTable
2384     if ( itcMac == 0 ) {
2385             wvlog << "Bug: Assumption about sprmTDefTable not true" << endl;
2386             break;
2387         }
2388 
2389         U8 itcFirst = *ptr;
2390         U8 itcLim = *( ptr + 1 );
2391         const S16 dxaCol = readS16( ptr + 2 );
2392 
2393         cropIndices( itcFirst, itcLim, rgdxaCenter.size() );
2394         S16 shift = 0;
2395         for ( ; itcFirst < itcLim; ++itcFirst ) {
2396             shift += rgdxaCenter[ itcFirst + 1 ] - rgdxaCenter[ itcFirst ] - dxaCol;
2397             rgdxaCenter[ itcFirst + 1 ] = rgdxaCenter[ itcFirst ] + dxaCol;
2398         }
2399         // Adjust all the following columns
2400         ++itcFirst;
2401         std::transform( rgdxaCenter.begin() + itcFirst, rgdxaCenter.end(),
2402                         rgdxaCenter.begin() + itcFirst,
2403                         std::bind2nd( std::minus<S16>(), shift ) );
2404         break;
2405     }
2406     case SPRM::sprmTMerge:
2407     {
2408         wvlog << "Debug me (sprmTMerge) #########################################################" << endl;
2409         U8 itcFirst = *ptr;
2410         U8 itcLim = *( ptr + 1 );
2411         cropIndices( itcFirst, itcLim, rgtc.size() );
2412 
2413         rgtc[ itcFirst++ ].fFirstMerged = 1;
2414         for ( ; itcFirst < itcLim; ++itcFirst ) {
2415             rgtc[ itcFirst ].fMerged = 1;
2416         }
2417         break;
2418     }
2419     case SPRM::sprmTSplit:
2420     {
2421         wvlog << "Debug me (sprmTSplit) #########################################################" << endl;
2422         U8 itcFirst = *ptr;
2423         U8 itcLim = *( ptr + 1 );
2424         cropIndices( itcFirst, itcLim, rgtc.size() );
2425 
2426         std::vector<TC>::iterator it = rgtc.begin() + itcFirst;
2427         std::vector<TC>::const_iterator end = rgtc.begin() + itcLim;
2428         for ( ; it != end; ++it ) {
2429             ( *it ).fFirstMerged = 0;
2430             ( *it ).fMerged = 0;
2431         }
2432         break;
2433     }
2434     case SPRM::sprmTSetBrc10:
2435         wvlog << "Warning: sprmTSetBrc10 doesn't make sense for Word97 structures" << endl;
2436         break;
2437     case SPRM::sprmTSetShd:
2438     {
2439         U8 itcFirst = *ptr;
2440         U8 itcLim = *( ptr + 1 );
2441         cropIndices( itcFirst, itcLim, rgshd.size() );
2442         const SHD shd( ptr + 2 );
2443 
2444         std::fill_n( rgshd.begin() + itcFirst, itcLim - itcFirst, shd );
2445         break;
2446     }
2447     case SPRM::sprmTSetShdOdd:
2448     {
2449         U8 itcFirst = *ptr;
2450         U8 itcLim = *( ptr + 1 );
2451         cropIndices( itcFirst, itcLim, rgshd.size() );
2452         const SHD shd( ptr + 2 );
2453 
2454         for ( ; itcFirst < itcLim; ++itcFirst ) {
2455             if ( itcFirst & 0x01 ) {
2456                 rgshd[ itcFirst ] = shd;
2457             }
2458         }
2459         break;
2460     }
2461     case SPRM::sprmTTextFlow:
2462         wvlog << "Warning: sprmTTextFlow is undocumented. Please send this document to trobin@kde.org." << endl;
2463         break;
2464     case SPRM::sprmTDiagLine:
2465         wvlog << "Warning: sprmTDiagLine is undocumented. Please send this document to trobin@kde.org." << endl;
2466         break;
2467     case SPRM::sprmTVertMerge:
2468     {
2469         const U8 index = *ptr;
2470         const U8 flags = *( ptr + 1 );
2471         if ( index < rgtc.size() ) {
2472             rgtc[ index ].fVertMerge = flags;
2473             rgtc[ index ].fVertRestart = ( flags & 0x02 ) >> 1;
2474         }
2475         else {
2476             wvlog << "Warning: sprmTVertMerge: Out of bounds access" << endl;
2477         }
2478         break;
2479     }
2480     case SPRM::sprmTVertAlign:
2481     {
2482         U8 itcFirst = *ptr;
2483         U8 itcLim = *( ptr + 1 );
2484         cropIndices( itcFirst, itcLim, rgtc.size() );
2485         const U8 vertAlign = *( ptr + 2 );
2486 
2487         for ( ; itcFirst < itcLim; ++itcFirst ) {
2488             rgtc[ itcFirst ].vertAlign = vertAlign;
2489         }
2490         break;
2491     }
2492     case SPRM::sprmTSetBrc:
2493     {
2494         // variable size byte for Word 8!
2495         const U8* myPtr( version == Word8 ? ptr + 1 : ptr );
2496         U8 itcFirst = *myPtr;
2497         U8 itcLim = *( myPtr + 1 );
2498         cropIndices( itcFirst, itcLim, rgtc.size() );
2499         const U8 flags = *( myPtr + 2 );
2500         BRC brc;
2501         brc.read90Ptr(myPtr + 3 );
2502 
2503         for ( ; itcFirst < itcLim; ++itcFirst ) {
2504             if ( flags & 0x01 ) {
2505                 rgtc[ itcFirst ].brcTop = brc;
2506             }
2507             if ( flags & 0x02 ) {
2508                 rgtc[ itcFirst ].brcLeft = brc;
2509             }
2510             if ( flags & 0x04 ) {
2511                 rgtc[ itcFirst ].brcBottom = brc;
2512             }
2513             if ( flags & 0x08 ) {
2514                 rgtc[ itcFirst ].brcRight = brc;
2515             }
2516             if ( flags & 0x10 ) {
2517                 rgtc[ itcFirst ].brcTL2BR = brc;
2518             }
2519             if ( flags & 0x20 ) {
2520                 rgtc[ itcFirst ].brcTR2BL = brc;
2521             }
2522         }
2523         break;
2524     }
2525     case SPRM::sprmTBrcTopCv:
2526     {
2527         // variable size byte for Word 8!
2528         const U8* myPtr( version == Word8 ? ptr + 1 : ptr );
2529         for (uint i=0 ; i < 64 && i < rgtc.size(); ++i ) {
2530             rgtc[ i ].brcTop.cv = ((*(myPtr + i*4))<<16)  | ((*(myPtr + 1 + i*4))<<8) | (*(myPtr + 2 + i*4)) ;
2531         }
2532         break;
2533     }
2534     case SPRM::sprmTBrcLeftCv:
2535     {
2536         // variable size byte for Word 8!
2537         const U8* myPtr( version == Word8 ? ptr + 1 : ptr );
2538         for (uint i=0 ; i < 64 && i < rgtc.size(); ++i ) {
2539             rgtc[ i ].brcLeft.cv = ((*(myPtr + i*4))<<16)  | ((*(myPtr + 1 + i*4))<<8) | (*(myPtr + 2 + i*4)) ;
2540         }
2541         break;
2542     }
2543     case SPRM::sprmTBrcRightCv:
2544     {
2545         // variable size byte for Word 8!
2546         const U8* myPtr( version == Word8 ? ptr + 1 : ptr );
2547         for (uint i=0 ; i < 64 && i < rgtc.size(); ++i ) {
2548             rgtc[ i ].brcRight.cv = ((*(myPtr + i*4))<<16)  | ((*(myPtr + 1 + i*4))<<8) | (*(myPtr + 2 + i*4)) ;
2549         }
2550         break;
2551     }
2552     case SPRM::sprmTBrcBottomCv:
2553     {
2554         // variable size byte for Word 8!
2555         const U8* myPtr( version == Word8 ? ptr + 1 : ptr );
2556         for (uint i=0 ; i < 64 && i < rgtc.size(); ++i ) {
2557             rgtc[ i ].brcBottom.cv = ((*(myPtr + i*4))<<16)  | ((*(myPtr + 1 + i*4))<<8) | (*(myPtr + 2 + i*4)) ;
2558         }
2559         break;
2560     }
2561     case SPRM::sprmTCellPadding:
2562         wvlog << "Warning: sprmTCellPadding not implemented" << endl;
2563 //         if ( *ptr == 6 ) {
2564 //             const U8 itcFirst( *( ptr + 1 ) );
2565 //             for ( int i = 0; i < 6; ++i )
2566 //                 wvlog << "    byte " << i << ": " << hex << ( int )*( ptr + i ) << dec << endl;
2567 //         }
2568 //         else {
2569 //             wvlog << "Warning: sprmTCellPadding with unusual length=" <<
2570 //                   static_cast<int>( *ptr ) << endl;
2571 //         }
2572         break;
2573     case SPRM::sprmTCellSpacingDefault:
2574        wvlog << "Warning: sprmTCellSpacingDefault not implemented" << endl;
2575        break;
2576     case SPRM::sprmTCellPaddingDefault:
2577         if ( *ptr == 6 ) {
2578 
2579             U8 itcFirst = *( ptr + 1 );
2580             U8 itcLim = *( ptr + 2 );
2581             U8 grfbrc = *( ptr + 3 );
2582             U8 ftsWidth = *( ptr + 4 );
2583             const U16 wWidth = readU16( ptr + 5 );
2584 
2585             if ( (itcFirst != 0) || (itcLim != 1) ) {
2586                 wvlog << "Warning: wrong itcFirst or itcLim value";
2587             }
2588 
2589             switch (ftsWidth) {
2590             case Word97::ftsNil:
2591                 wvlog << "Note: wWidth is not used and must be zero";
2592                 break;
2593             case Word97::ftsAuto:
2594             case Word97::ftsPercent:
2595             case Word97::ftsDxaSys:
2596                 wvlog << "Note: this value of ftsWidth is not allowed";
2597                 break;
2598             default:
2599                 if (grfbrc == (Word97::fbrcLeft | Word97::fbrcRight)) {
2600                     padHorz = wWidth;
2601                 }
2602                 else if (grfbrc == (Word97::fbrcTop | Word97::fbrcBottom)) {
2603                     padVert = wWidth;
2604                 }
2605                 else {
2606                     padHorz = wWidth;
2607                     padVert = wWidth;
2608                 }
2609                 break;
2610             }
2611         } else {
2612             wvlog << "Warning: sprmTCellPaddingDefault with unusual length=" <<
2613                   static_cast<int>( *ptr ) << endl;
2614         }
2615         break;
2616     case SPRM::sprmTUndocumented1:
2617     case SPRM::sprmTUndocumented2:
2618         wvlog << "Warning: undocumented SPRM";
2619         break;
2620     case SPRM::sprmTSetShdTable:
2621         wvlog << "Warning: sprmTSetShdTable not implemented" << endl;
2622         break;
2623     case SPRM::sprmTUndocumented10:
2624     case SPRM::sprmTUndocumented11:
2625     case SPRM::sprmTUndocumented12:
2626         wvlog << "Warning: undocumented SPRM";
2627         break;
2628     case SPRM::sprmTWidthIndent:
2629     {
2630         //MS-DOC, page 362 of 609
2631         const U8 ftsWidth = *ptr;
2632         const S16 wWidth = readS16( ptr + 1 );
2633 
2634         switch (ftsWidth) {
2635         case Word97::ftsNil:
2636         case Word97::ftsAuto:
2637             wvlog << "Note: wWidth is not used and must be zero";
2638             break;
2639         case Word97::ftsPercent:
2640             wvlog << "Note: this value of ftsWidth is not allowed";
2641             break;
2642         default:
2643             widthIndent = wWidth;
2644             break;
2645         }
2646         break;
2647     }
2648     // These are needed in case there are table properties inside the huge papx
2649     case SPRM::sprmPHugePapx:
2650     case SPRM::sprmPHugePapx2:
2651     case SPRM::sprmPTableProps:
2652     {
2653         wvlog << "--> Parsing PrcData" << endl;
2654         if ( dataStream ) {
2655             dataStream->push();
2656             dataStream->seek( readU32( ptr ), WV2_SEEK_SET );
2657 
2658             const U16 count( dataStream->readU16() );
2659             U8* grpprl = new U8[ count ];
2660 
2661             dataStream->read( grpprl, count );
2662             dataStream->pop();
2663 
2664             apply( grpprl, count, style, styleSheet, dataStream, version );
2665             delete [] grpprl;
2666         }
2667         else {
2668             wvlog << "Error: no data stream!" << endl;
2669         }
2670         wvlog << "<-- PrcData parsed successfully" << endl;
2671         break;
2672     }
2673     default:
2674         wvlog << "Huh? None of the defined sprms matches 0x" << hex << sprm << dec << "... trying to skip anyway" << endl;
2675         break;
2676     }
2677     return static_cast<S16>( sprmLength );  // length of the SPRM
2678 }
2679 
2680 
2681 // Creates a PRM2 from a plain PRM
toPRM2() const2682 PRM2 PRM::toPRM2() const
2683 {
2684     PRM2 prm;
2685     prm.fComplex = fComplex;
2686     prm.igrpprl = ( val << 7 ) | isprm;
2687     return prm;
2688 }
2689 
2690 } // namespace Word97
2691 } // namespace wvWare
2692