3 * Copyright (C) 1998-2004 A.J. van Os; Released under GPL
6 * Deal with the OLE internals of a MS Word file
12 /* Private type for Property Set Storage entries */
13 typedef struct pps_entry_tag
{
24 /* Show that a PPS number or index should not be used */
25 #define PPS_NUMBER_INVALID 0xffffffffUL
28 /* Macro to make sure all such statements will be identical */
31 vDestroySmallBlockList();\
32 aulRootList = xfree(aulRootList);\
33 aulSbdList = xfree(aulSbdList);\
34 aulBbdList = xfree(aulBbdList);\
35 aulSBD = xfree(aulSBD);\
36 aulBBD = xfree(aulBBD);\
41 * ulReadLong - read four bytes from the given file and offset
44 ulReadLong(FILE *pFile
, ULONG ulOffset
)
50 if (!bReadBytes(aucBytes
, 4, ulOffset
, pFile
)) {
51 werr(1, "Read long 0x%lx not possible", ulOffset
);
53 return ulGetLong(0, aucBytes
);
54 } /* end of ulReadLong */
57 * vName2String - turn the name into a proper string.
60 vName2String(char *szName
, const UCHAR
*aucBytes
, size_t tNameSize
)
65 fail(aucBytes
== NULL
|| szName
== NULL
);
71 for (tIndex
= 0, pcChar
= szName
;
72 tIndex
< 2 * tNameSize
;
73 tIndex
+= 2, pcChar
++) {
74 *pcChar
= (char)aucBytes
[tIndex
];
76 szName
[tNameSize
- 1] = '\0';
77 } /* end of vName2String */
80 * tReadBlockIndices - read the Big/Small Block Depot indices
82 * Returns the number of indices read
85 tReadBlockIndices(FILE *pFile
, ULONG
*aulBlockDepot
,
86 size_t tMaxRec
, ULONG ulOffset
)
90 UCHAR aucBytes
[BIG_BLOCK_SIZE
];
92 fail(pFile
== NULL
|| aulBlockDepot
== NULL
);
95 /* Read a big block with BBD or SBD indices */
96 if (!bReadBytes(aucBytes
, BIG_BLOCK_SIZE
, ulOffset
, pFile
)) {
97 werr(0, "Reading big block from 0x%lx is not possible",
101 /* Split the big block into indices, an index is four bytes */
102 tDone
= min(tMaxRec
, (size_t)BIG_BLOCK_SIZE
/ 4);
103 for (iIndex
= 0; iIndex
< (int)tDone
; iIndex
++) {
104 aulBlockDepot
[iIndex
] = ulGetLong(4 * iIndex
, aucBytes
);
105 NO_DBG_DEC(aulBlockDepot
[iIndex
]);
108 } /* end of tReadBlockIndices */
111 * bGetBBD - get the Big Block Depot indices from the index-blocks
114 bGetBBD(FILE *pFile
, const ULONG
*aulDepot
, size_t tDepotLen
,
115 ULONG
*aulBBD
, size_t tBBDLen
)
121 fail(pFile
== NULL
|| aulDepot
== NULL
|| aulBBD
== NULL
);
126 for (iIndex
= 0; iIndex
< (int)tDepotLen
&& tToGo
!= 0; iIndex
++) {
127 ulBegin
= (aulDepot
[iIndex
] + 1) * BIG_BLOCK_SIZE
;
129 tDone
= tReadBlockIndices(pFile
, aulBBD
, tToGo
, ulBegin
);
138 } /* end of bGetBBD */
141 * bGetSBD - get the Small Block Depot indices from the index-blocks
144 bGetSBD(FILE *pFile
, const ULONG
*aulDepot
, size_t tDepotLen
,
145 ULONG
*aulSBD
, size_t tSBDLen
)
151 fail(pFile
== NULL
|| aulDepot
== NULL
|| aulSBD
== NULL
);
156 for (iIndex
= 0; iIndex
< (int)tDepotLen
&& tToGo
!= 0; iIndex
++) {
157 fail(aulDepot
[iIndex
] >= ULONG_MAX
/ BIG_BLOCK_SIZE
);
158 ulBegin
= (aulDepot
[iIndex
] + 1) * BIG_BLOCK_SIZE
;
160 tDone
= tReadBlockIndices(pFile
, aulSBD
, tToGo
, ulBegin
);
169 } /* end of bGetSBD */
172 * vComputePPSlevels - compute the levels of the Property Set Storage entries
175 vComputePPSlevels(pps_entry_type
*atPPSlist
, pps_entry_type
*pNode
,
176 int iLevel
, int iRecursionLevel
)
178 fail(atPPSlist
== NULL
|| pNode
== NULL
);
179 fail(iLevel
< 0 || iRecursionLevel
< 0);
181 if (iRecursionLevel
> 25) {
182 /* This removes the possibility of an infinite recursion */
183 DBG_DEC(iRecursionLevel
);
186 if (pNode
->iLevel
<= iLevel
) {
187 /* Avoid entering a loop */
189 DBG_DEC(pNode
->iLevel
);
193 pNode
->iLevel
= iLevel
;
195 if (pNode
->ulDir
!= PPS_NUMBER_INVALID
) {
196 vComputePPSlevels(atPPSlist
,
197 &atPPSlist
[pNode
->ulDir
],
199 iRecursionLevel
+ 1);
201 if (pNode
->ulNext
!= PPS_NUMBER_INVALID
) {
202 vComputePPSlevels(atPPSlist
,
203 &atPPSlist
[pNode
->ulNext
],
205 iRecursionLevel
+ 1);
207 if (pNode
->ulPrevious
!= PPS_NUMBER_INVALID
) {
208 vComputePPSlevels(atPPSlist
,
209 &atPPSlist
[pNode
->ulPrevious
],
211 iRecursionLevel
+ 1);
213 } /* end of vComputePPSlevels */
216 * bGetPPS - search the Property Set Storage for three sets
218 * Return TRUE if the WordDocument PPS is found
222 const ULONG
*aulRootList
, size_t tRootListLen
, pps_info_type
*pPPS
)
224 pps_entry_type
*atPPSlist
;
225 ULONG ulBegin
, ulOffset
, ulTmp
;
226 size_t tNbrOfPPS
, tNameSize
;
227 int iIndex
, iStartBlock
, iRootIndex
;
229 UCHAR aucBytes
[PROPERTY_SET_STORAGE_SIZE
];
231 fail(pFile
== NULL
|| aulRootList
== NULL
|| pPPS
== NULL
);
235 NO_DBG_DEC(tRootListLen
);
239 (void)memset(pPPS
, 0, sizeof(*pPPS
));
241 /* Read and store all the Property Set Storage entries */
243 tNbrOfPPS
= tRootListLen
* BIG_BLOCK_SIZE
/ PROPERTY_SET_STORAGE_SIZE
;
244 atPPSlist
= xcalloc(tNbrOfPPS
, sizeof(pps_entry_type
));
247 for (iIndex
= 0; iIndex
< (int)tNbrOfPPS
; iIndex
++) {
248 ulTmp
= (ULONG
)iIndex
* PROPERTY_SET_STORAGE_SIZE
;
249 iStartBlock
= (int)(ulTmp
/ BIG_BLOCK_SIZE
);
250 ulOffset
= ulTmp
% BIG_BLOCK_SIZE
;
251 ulBegin
= (aulRootList
[iStartBlock
] + 1) * BIG_BLOCK_SIZE
+
254 if (!bReadBytes(aucBytes
, PROPERTY_SET_STORAGE_SIZE
,
256 werr(0, "Reading PPS %d is not possible", iIndex
);
257 atPPSlist
= xfree(atPPSlist
);
260 tNameSize
= (size_t)usGetWord(0x40, aucBytes
);
261 tNameSize
= (tNameSize
+ 1) / 2;
262 vName2String(atPPSlist
[iIndex
].szName
, aucBytes
, tNameSize
);
263 atPPSlist
[iIndex
].ucType
= ucGetByte(0x42, aucBytes
);
264 if (atPPSlist
[iIndex
].ucType
== 5) {
267 atPPSlist
[iIndex
].ulPrevious
= ulGetLong(0x44, aucBytes
);
268 atPPSlist
[iIndex
].ulNext
= ulGetLong(0x48, aucBytes
);
269 atPPSlist
[iIndex
].ulDir
= ulGetLong(0x4c, aucBytes
);
270 atPPSlist
[iIndex
].ulSB
= ulGetLong(0x74, aucBytes
);
271 atPPSlist
[iIndex
].ulSize
= ulGetLong(0x78, aucBytes
);
272 atPPSlist
[iIndex
].iLevel
= INT_MAX
;
273 if ((atPPSlist
[iIndex
].ulPrevious
>= (ULONG
)tNbrOfPPS
&&
274 atPPSlist
[iIndex
].ulPrevious
!= PPS_NUMBER_INVALID
) ||
275 (atPPSlist
[iIndex
].ulNext
>= (ULONG
)tNbrOfPPS
&&
276 atPPSlist
[iIndex
].ulNext
!= PPS_NUMBER_INVALID
) ||
277 (atPPSlist
[iIndex
].ulDir
>= (ULONG
)tNbrOfPPS
&&
278 atPPSlist
[iIndex
].ulDir
!= PPS_NUMBER_INVALID
)) {
280 DBG_DEC(atPPSlist
[iIndex
].ulPrevious
);
281 DBG_DEC(atPPSlist
[iIndex
].ulNext
);
282 DBG_DEC(atPPSlist
[iIndex
].ulDir
);
284 werr(0, "The Property Set Storage is damaged");
285 atPPSlist
= xfree(atPPSlist
);
290 #if 0 /* defined(DEBUG) */
292 for (iIndex
= 0; iIndex
< (int)tNbrOfPPS
; iIndex
++) {
293 DBG_MSG(atPPSlist
[iIndex
].szName
);
294 DBG_HEX(atPPSlist
[iIndex
].ulDir
);
295 DBG_HEX(atPPSlist
[iIndex
].ulPrevious
);
296 DBG_HEX(atPPSlist
[iIndex
].ulNext
);
297 DBG_DEC(atPPSlist
[iIndex
].ulSB
);
298 DBG_HEX(atPPSlist
[iIndex
].ulSize
);
299 DBG_DEC(atPPSlist
[iIndex
].iLevel
);
303 /* Add level information to each entry */
304 vComputePPSlevels(atPPSlist
, &atPPSlist
[iRootIndex
], 0, 0);
306 /* Check the entries on level 1 for the required information */
308 for (iIndex
= 0; iIndex
< (int)tNbrOfPPS
; iIndex
++) {
309 #if 0 /* defined(DEBUG) */
310 DBG_MSG(atPPSlist
[iIndex
].szName
);
311 DBG_HEX(atPPSlist
[iIndex
].ulDir
);
312 DBG_HEX(atPPSlist
[iIndex
].ulPrevious
);
313 DBG_HEX(atPPSlist
[iIndex
].ulNext
);
314 DBG_DEC(atPPSlist
[iIndex
].ulSB
);
315 DBG_HEX(atPPSlist
[iIndex
].ulSize
);
316 DBG_DEC(atPPSlist
[iIndex
].iLevel
);
318 if (atPPSlist
[iIndex
].iLevel
!= 1 ||
319 atPPSlist
[iIndex
].ucType
!= 2 ||
320 atPPSlist
[iIndex
].szName
[0] == '\0' ||
321 atPPSlist
[iIndex
].ulSize
== 0) {
322 /* This entry can be ignored */
325 if (pPPS
->tWordDocument
.ulSize
== 0 &&
326 STREQ(atPPSlist
[iIndex
].szName
, "WordDocument")) {
327 pPPS
->tWordDocument
.ulSB
= atPPSlist
[iIndex
].ulSB
;
328 pPPS
->tWordDocument
.ulSize
= atPPSlist
[iIndex
].ulSize
;
330 } else if (pPPS
->tData
.ulSize
== 0 &&
331 STREQ(atPPSlist
[iIndex
].szName
, "Data")) {
332 pPPS
->tData
.ulSB
= atPPSlist
[iIndex
].ulSB
;
333 pPPS
->tData
.ulSize
= atPPSlist
[iIndex
].ulSize
;
334 } else if (pPPS
->t0Table
.ulSize
== 0 &&
335 STREQ(atPPSlist
[iIndex
].szName
, "0Table")) {
336 pPPS
->t0Table
.ulSB
= atPPSlist
[iIndex
].ulSB
;
337 pPPS
->t0Table
.ulSize
= atPPSlist
[iIndex
].ulSize
;
338 } else if (pPPS
->t1Table
.ulSize
== 0 &&
339 STREQ(atPPSlist
[iIndex
].szName
, "1Table")) {
340 pPPS
->t1Table
.ulSB
= atPPSlist
[iIndex
].ulSB
;
341 pPPS
->t1Table
.ulSize
= atPPSlist
[iIndex
].ulSize
;
342 } else if (pPPS
->tSummaryInfo
.ulSize
== 0 &&
343 STREQ(atPPSlist
[iIndex
].szName
,
344 "\005SummaryInformation")) {
345 pPPS
->tSummaryInfo
.ulSB
= atPPSlist
[iIndex
].ulSB
;
346 pPPS
->tSummaryInfo
.ulSize
= atPPSlist
[iIndex
].ulSize
;
347 } else if (pPPS
->tDocSummaryInfo
.ulSize
== 0 &&
348 STREQ(atPPSlist
[iIndex
].szName
,
349 "\005DocumentSummaryInformation")) {
350 pPPS
->tDocSummaryInfo
.ulSB
= atPPSlist
[iIndex
].ulSB
;
351 pPPS
->tDocSummaryInfo
.ulSize
= atPPSlist
[iIndex
].ulSize
;
352 } else if (STREQ(atPPSlist
[iIndex
].szName
, "Book") ||
353 STREQ(atPPSlist
[iIndex
].szName
, "Workbook")) {
358 /* Free the space for the Property Set Storage entries */
359 atPPSlist
= xfree(atPPSlist
);
361 /* Draw your conclusions */
367 werr(0, "Sorry, but this is an Excel spreadsheet");
369 werr(0, "This OLE file does not contain a Word document");
372 } /* end of bGetPPS */
375 * vGetBbdList - make a list of the places to find big blocks
378 vGetBbdList(FILE *pFile
, int iNbr
, ULONG
*aulBbdList
, ULONG ulOffset
)
384 fail(aulBbdList
== NULL
);
387 for (iIndex
= 0; iIndex
< iNbr
; iIndex
++) {
389 ulReadLong(pFile
, ulOffset
+ 4 * (ULONG
)iIndex
);
391 NO_DBG_HEX(aulBbdList
[iIndex
]);
393 } /* end of vGetBbdList */
396 * bGetDocumentText - make a list of the text blocks of a Word document
398 * Return TRUE when succesful, otherwise FALSE
401 bGetDocumentText(FILE *pFile
, const pps_info_type
*pPPS
,
402 const ULONG
*aulBBD
, size_t tBBDLen
,
403 const ULONG
*aulSBD
, size_t tSBDLen
,
404 const UCHAR
*aucHeader
, int iWordVersion
)
407 ULONG ulTextLen
, ulFootnoteLen
, ulEndnoteLen
;
408 ULONG ulHdrFtrLen
, ulMacroLen
, ulAnnotationLen
;
409 ULONG ulTextBoxLen
, ulHdrTextBoxLen
;
411 BOOL bFarEastWord
, bTemplate
, bFastSaved
, bEncrypted
, bSuccess
;
412 USHORT usIdent
, usDocStatus
;
414 fail(pFile
== NULL
|| pPPS
== NULL
);
415 fail(aulBBD
== NULL
);
416 fail(aulSBD
== NULL
);
418 DBG_MSG("bGetDocumentText");
420 /* Get the "magic number" from the header */
421 usIdent
= usGetWord(0x00, aucHeader
);
423 bFarEastWord
= usIdent
== 0x8098 || usIdent
== 0x8099 ||
424 usIdent
== 0xa697 || usIdent
== 0xa699;
425 /* Get the status flags from the header */
426 usDocStatus
= usGetWord(0x0a, aucHeader
);
427 DBG_HEX(usDocStatus
);
428 bTemplate
= (usDocStatus
& BIT(0)) != 0;
429 DBG_MSG_C(bTemplate
, "This document is a Template");
430 bFastSaved
= (usDocStatus
& BIT(2)) != 0;
431 uiQuickSaves
= (UINT
)(usDocStatus
& 0x00f0) >> 4;
432 DBG_MSG_C(bFastSaved
, "This document is Fast Saved");
433 DBG_DEC_C(bFastSaved
, uiQuickSaves
);
434 bEncrypted
= (usDocStatus
& BIT(8)) != 0;
436 werr(0, "Encrypted documents are not supported");
440 /* Get length information */
441 ulBeginOfText
= ulGetLong(0x18, aucHeader
);
442 DBG_HEX(ulBeginOfText
);
443 switch (iWordVersion
) {
446 ulTextLen
= ulGetLong(0x34, aucHeader
);
447 ulFootnoteLen
= ulGetLong(0x38, aucHeader
);
448 ulHdrFtrLen
= ulGetLong(0x3c, aucHeader
);
449 ulMacroLen
= ulGetLong(0x40, aucHeader
);
450 ulAnnotationLen
= ulGetLong(0x44, aucHeader
);
451 ulEndnoteLen
= ulGetLong(0x48, aucHeader
);
452 ulTextBoxLen
= ulGetLong(0x4c, aucHeader
);
453 ulHdrTextBoxLen
= ulGetLong(0x50, aucHeader
);
456 ulTextLen
= ulGetLong(0x4c, aucHeader
);
457 ulFootnoteLen
= ulGetLong(0x50, aucHeader
);
458 ulHdrFtrLen
= ulGetLong(0x54, aucHeader
);
459 ulMacroLen
= ulGetLong(0x58, aucHeader
);
460 ulAnnotationLen
= ulGetLong(0x5c, aucHeader
);
461 ulEndnoteLen
= ulGetLong(0x60, aucHeader
);
462 ulTextBoxLen
= ulGetLong(0x64, aucHeader
);
463 ulHdrTextBoxLen
= ulGetLong(0x68, aucHeader
);
466 werr(0, "This version of Word is not supported");
470 DBG_DEC(ulFootnoteLen
);
471 DBG_DEC(ulHdrFtrLen
);
473 DBG_DEC(ulAnnotationLen
);
474 DBG_DEC(ulEndnoteLen
);
475 DBG_DEC(ulTextBoxLen
);
476 DBG_DEC(ulHdrTextBoxLen
);
478 /* Make a list of the text blocks */
479 switch (iWordVersion
) {
483 bSuccess
= bGet6DocumentText(pFile
,
485 pPPS
->tWordDocument
.ulSB
,
489 bSuccess
= bAddTextBlocks(ulBeginOfText
,
493 ulMacroLen
+ ulAnnotationLen
+
495 ulTextBoxLen
+ ulHdrTextBoxLen
,
498 pPPS
->tWordDocument
.ulSB
,
503 bSuccess
= bGet8DocumentText(pFile
,
505 aulBBD
, tBBDLen
, aulSBD
, tSBDLen
,
509 werr(0, "This version of Word is not supported");
515 vSplitBlockList(pFile
,
524 !bFastSaved
&& iWordVersion
== 8);
526 vDestroyTextBlockList();
527 werr(0, "I can't find the text of this document");
530 } /* end of bGetDocumentText */
533 * vGetDocumentData - make a list of the data blocks of a Word document
536 vGetDocumentData(FILE *pFile
, const pps_info_type
*pPPS
,
537 const ULONG
*aulBBD
, size_t tBBDLen
,
538 const UCHAR
*aucHeader
, int iWordVersion
)
540 options_type tOptions
;
542 BOOL bFastSaved
, bHasImages
, bSuccess
;
547 fail(aulBBD
== NULL
);
549 /* Get the options */
550 vGetOptions(&tOptions
);
552 /* Get the status flags from the header */
553 usDocStatus
= usGetWord(0x0a, aucHeader
);
554 DBG_HEX(usDocStatus
);
555 bFastSaved
= (usDocStatus
& BIT(2)) != 0;
556 bHasImages
= (usDocStatus
& BIT(3)) != 0;
559 tOptions
.eConversionType
== conversion_text
||
560 tOptions
.eConversionType
== conversion_fmt_text
||
561 tOptions
.eConversionType
== conversion_xml
||
562 tOptions
.eImageLevel
== level_no_images
) {
564 * No images in the document or text-only output or
565 * no images wanted, so no data blocks will be needed
567 vDestroyDataBlockList();
571 /* Get length information */
572 ulBeginOfText
= ulGetLong(0x18, aucHeader
);
573 DBG_HEX(ulBeginOfText
);
575 /* Make a list of the data blocks */
576 switch (iWordVersion
) {
580 * The data blocks are in the text stream. The text stream
581 * is in "fast saved" format or "normal saved" format
584 bSuccess
= bGet6DocumentData(pFile
,
585 pPPS
->tWordDocument
.ulSB
,
589 bSuccess
= bAddDataBlocks(ulBeginOfText
,
591 pPPS
->tWordDocument
.ulSB
,
597 * The data blocks are in the data stream. The data stream
598 * is always in "normal saved" format
600 bSuccess
= bAddDataBlocks(0, (ULONG
)LONG_MAX
,
601 pPPS
->tData
.ulSB
, aulBBD
, tBBDLen
);
604 werr(0, "This version of Word is not supported");
610 vDestroyDataBlockList();
611 werr(0, "I can't find the data of this document");
613 } /* end of vGetDocumentData */
616 * iInitDocumentOLE - initialize an OLE document
618 * Returns the version of Word that made the document or -1
621 iInitDocumentOLE(FILE *pFile
, long lFilesize
)
623 pps_info_type PPS_info
;
624 ULONG
*aulBBD
, *aulSBD
;
625 ULONG
*aulRootList
, *aulBbdList
, *aulSbdList
;
626 ULONG ulBdbListStart
, ulAdditionalBBDlist
;
627 ULONG ulRootStartblock
, ulSbdStartblock
, ulSBLstartblock
;
628 ULONG ulStart
, ulTmp
;
630 size_t tBBDLen
, tSBDLen
, tNumBbdBlocks
, tRootListLen
;
631 int iWordVersion
, iIndex
, iToGo
;
633 USHORT usIdent
, usDocStatus
;
634 UCHAR aucHeader
[HEADER_SIZE
];
638 lMaxBlock
= lFilesize
/ BIG_BLOCK_SIZE
- 2;
643 tBBDLen
= (size_t)(lMaxBlock
+ 1);
644 tNumBbdBlocks
= (size_t)ulReadLong(pFile
, 0x2c);
645 DBG_DEC(tNumBbdBlocks
);
646 ulRootStartblock
= ulReadLong(pFile
, 0x30);
647 DBG_DEC(ulRootStartblock
);
648 ulSbdStartblock
= ulReadLong(pFile
, 0x3c);
649 DBG_DEC(ulSbdStartblock
);
650 ulAdditionalBBDlist
= ulReadLong(pFile
, 0x44);
651 DBG_HEX(ulAdditionalBBDlist
);
652 ulSBLstartblock
= ulReadLong(pFile
,
653 (ulRootStartblock
+ 1) * BIG_BLOCK_SIZE
+ 0x74);
654 DBG_DEC(ulSBLstartblock
);
655 tSBDLen
= (size_t)(ulReadLong(pFile
,
656 (ulRootStartblock
+ 1) * BIG_BLOCK_SIZE
+ 0x78) /
658 /* All to be xcalloc-ed pointers to NULL */
664 /* Big Block Depot */
665 aulBbdList
= xcalloc(tNumBbdBlocks
, sizeof(ULONG
));
666 aulBBD
= xcalloc(tBBDLen
, sizeof(ULONG
));
667 iToGo
= (int)tNumBbdBlocks
;
668 vGetBbdList(pFile
, min(iToGo
, 109), aulBbdList
, 0x4c);
671 while (ulAdditionalBBDlist
!= END_OF_CHAIN
&& iToGo
> 0) {
672 ulBdbListStart
= (ulAdditionalBBDlist
+ 1) * BIG_BLOCK_SIZE
;
673 vGetBbdList(pFile
, min(iToGo
, 127),
674 aulBbdList
+ ulStart
, ulBdbListStart
);
675 ulAdditionalBBDlist
= ulReadLong(pFile
,
676 ulBdbListStart
+ 4 * 127);
677 DBG_DEC(ulAdditionalBBDlist
);
678 DBG_HEX(ulAdditionalBBDlist
);
682 if (!bGetBBD(pFile
, aulBbdList
, tNumBbdBlocks
, aulBBD
, tBBDLen
)) {
686 aulBbdList
= xfree(aulBbdList
);
687 /* Small Block Depot */
688 aulSbdList
= xcalloc(tBBDLen
, sizeof(ULONG
));
689 aulSBD
= xcalloc(tSBDLen
, sizeof(ULONG
));
690 for (iIndex
= 0, ulTmp
= ulSbdStartblock
;
691 iIndex
< (int)tBBDLen
&& ulTmp
!= END_OF_CHAIN
;
692 iIndex
++, ulTmp
= aulBBD
[ulTmp
]) {
693 if (ulTmp
>= (ULONG
)tBBDLen
) {
696 werr(1, "The Big Block Depot is damaged");
698 aulSbdList
[iIndex
] = ulTmp
;
699 NO_DBG_HEX(aulSbdList
[iIndex
]);
701 if (!bGetSBD(pFile
, aulSbdList
, tBBDLen
, aulSBD
, tSBDLen
)) {
705 aulSbdList
= xfree(aulSbdList
);
707 for (tRootListLen
= 0, ulTmp
= ulRootStartblock
;
708 tRootListLen
< tBBDLen
&& ulTmp
!= END_OF_CHAIN
;
709 tRootListLen
++, ulTmp
= aulBBD
[ulTmp
]) {
710 if (ulTmp
>= (ULONG
)tBBDLen
) {
713 werr(1, "The Big Block Depot is damaged");
716 if (tRootListLen
== 0) {
717 werr(0, "No Rootlist found");
721 aulRootList
= xcalloc(tRootListLen
, sizeof(ULONG
));
722 for (iIndex
= 0, ulTmp
= ulRootStartblock
;
723 iIndex
< (int)tBBDLen
&& ulTmp
!= END_OF_CHAIN
;
724 iIndex
++, ulTmp
= aulBBD
[ulTmp
]) {
725 if (ulTmp
>= (ULONG
)tBBDLen
) {
728 werr(1, "The Big Block Depot is damaged");
730 aulRootList
[iIndex
] = ulTmp
;
731 NO_DBG_DEC(aulRootList
[iIndex
]);
733 fail(tRootListLen
!= (size_t)iIndex
);
734 bSuccess
= bGetPPS(pFile
, aulRootList
, tRootListLen
, &PPS_info
);
735 aulRootList
= xfree(aulRootList
);
740 /* Small block list */
741 if (!bCreateSmallBlockList(ulSBLstartblock
, aulBBD
, tBBDLen
)) {
746 if (PPS_info
.tWordDocument
.ulSize
< MIN_SIZE_FOR_BBD_USE
) {
747 DBG_DEC(PPS_info
.tWordDocument
.ulSize
);
749 werr(0, "I'm afraid the text stream of this file "
750 "is too small to handle.");
753 /* Read the headerblock */
754 if (!bReadBuffer(pFile
, PPS_info
.tWordDocument
.ulSB
,
755 aulBBD
, tBBDLen
, BIG_BLOCK_SIZE
,
756 aucHeader
, 0, HEADER_SIZE
)) {
760 usIdent
= usGetWord(0x00, aucHeader
);
762 fail(usIdent
!= 0x8098 && /* Word 7 for oriental languages */
763 usIdent
!= 0x8099 && /* Word 7 for oriental languages */
764 usIdent
!= 0xa5dc && /* Word 6 & 7 */
765 usIdent
!= 0xa5ec && /* Word 7 & 97 & 98 */
766 usIdent
!= 0xa697 && /* Word 7 for oriental languages */
767 usIdent
!= 0xa699); /* Word 7 for oriental languages */
768 iWordVersion
= iGetVersionNumber(aucHeader
);
769 if (iWordVersion
< 6) {
771 werr(0, "This file is from a version of Word before Word 6.");
775 /* Get the status flags from the header */
776 usDocStatus
= usGetWord(0x0a, aucHeader
);
777 if (usDocStatus
& BIT(9)) {
778 PPS_info
.tTable
= PPS_info
.t1Table
;
780 PPS_info
.tTable
= PPS_info
.t0Table
;
782 /* Clean the entries that should not be used */
783 memset(&PPS_info
.t0Table
, 0, sizeof(PPS_info
.t0Table
));
784 memset(&PPS_info
.t1Table
, 0, sizeof(PPS_info
.t1Table
));
786 bSuccess
= bGetDocumentText(pFile
, &PPS_info
,
787 aulBBD
, tBBDLen
, aulSBD
, tSBDLen
,
788 aucHeader
, iWordVersion
);
790 vGetDocumentData(pFile
, &PPS_info
,
791 aulBBD
, tBBDLen
, aucHeader
, iWordVersion
);
792 vGetPropertyInfo(pFile
, &PPS_info
,
793 aulBBD
, tBBDLen
, aulSBD
, tSBDLen
,
794 aucHeader
, iWordVersion
);
795 vSetDefaultTabWidth(pFile
, &PPS_info
,
796 aulBBD
, tBBDLen
, aulSBD
, tSBDLen
,
797 aucHeader
, iWordVersion
);
798 vGetNotesInfo(pFile
, &PPS_info
,
799 aulBBD
, tBBDLen
, aulSBD
, tSBDLen
,
800 aucHeader
, iWordVersion
);
803 return bSuccess
? iWordVersion
: -1;
804 } /* end of iInitDocumentOLE */