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 = ¶graphStyle->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