1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* libwps
3 * Version: MPL 2.0 / LGPLv2.1+
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * Major Contributor(s):
10 * Copyright (C) 2002 William Lachance (william.lachance@sympatico.ca)
11 * Copyright (C) 2002-2004 Marc Maurer (uwog@uwog.net)
12 *
13 * For minor contributions see the git repository.
14 *
15 * Alternatively, the contents of this file may be used under the terms
16 * of the GNU Lesser General Public License Version 2.1 or later
17 * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
18 * applicable instead of those above.
19 *
20 * For further information visit http://libwps.sourceforge.net
21 */
22
23 #include <string.h>
24
25 #include "libwps_internal.h"
26
27 #include "WPSHeader.h"
28
29 using namespace libwps;
30
WPSHeader(RVNGInputStreamPtr & input,RVNGInputStreamPtr & fileInput,uint8_t majorVersion,WPSKind kind)31 WPSHeader::WPSHeader(RVNGInputStreamPtr &input, RVNGInputStreamPtr &fileInput, uint8_t majorVersion, WPSKind kind) :
32 m_input(input), m_fileInput(fileInput), m_majorVersion(majorVersion), m_kind(kind)
33 {
34 }
35
~WPSHeader()36 WPSHeader::~WPSHeader()
37 {
38 }
39
40
41 /**
42 * So far, we have identified three categories of Works documents.
43 *
44 * Works documents versions 3 and later use a MS OLE container, so we detect
45 * their type by checking for OLE stream names. Works version 2 is like
46 * Works 3 without OLE, so those two types use the same parser.
47 *
48 */
constructHeader(RVNGInputStreamPtr & input)49 WPSHeader *WPSHeader::constructHeader(RVNGInputStreamPtr &input)
50 {
51 WPS_DEBUG_MSG(("WPSHeader::constructHeader()\n"));
52
53 if (!input->isStructured())
54 {
55 input->seek(0, librevenge::RVNG_SEEK_SET);
56 uint8_t firstOffset = libwps::readU8(input);
57 uint8_t secondOffset = libwps::readU8(input);
58
59 if (firstOffset < 6 && secondOffset == 0xFE)
60 {
61 WPS_DEBUG_MSG(("Microsoft Works v2 format detected\n"));
62 return new WPSHeader(input, input, 2);
63 }
64 // works1 dos file begin by 2054
65 if ((firstOffset == 0xFF || firstOffset == 0x20) && secondOffset==0x54)
66 {
67 WPS_DEBUG_MSG(("Microsoft Works wks database\n"));
68 return new WPSHeader(input, input, 1, WPS_DATABASE);
69 }
70 if ((firstOffset == 0xFF || firstOffset == 00) && secondOffset == 0x0 &&
71 libwps::readU16(input) == 2 && libwps::readU16(input) == 0x0404)
72 {
73 WPS_DEBUG_MSG(("Microsoft Works wks detected\n"));
74 return new WPSHeader(input, input, 2, WPS_SPREADSHEET);
75 }
76
77 return 0;
78 }
79
80 RVNGInputStreamPtr document_mn0(input->getSubStreamByName("MN0"));
81 if (document_mn0)
82 {
83 // can be a mac or a pc document
84 // each must contains a MM Ole which begins by 0x444e: Mac or 0x4e44: PC
85 RVNGInputStreamPtr document_mm(input->getSubStreamByName("MM"));
86 if (document_mm && libwps::readU16(document_mm) == 0x4e44)
87 {
88 WPS_DEBUG_MSG(("Microsoft Works Mac v4 format detected\n"));
89 return 0;
90 }
91 // now, look if this is a database document
92 uint16_t fileMagic=libwps::readU16(document_mn0);
93 if (fileMagic == 0x54FF)
94 {
95 WPS_DEBUG_MSG(("Microsoft Works Database format detected\n"));
96 return new WPSHeader(document_mn0, input, 4, WPS_DATABASE);
97 }
98 WPS_DEBUG_MSG(("Microsoft Works v4 format detected\n"));
99 return new WPSHeader(document_mn0, input, 4);
100 }
101
102 RVNGInputStreamPtr document_contents(input->getSubStreamByName("CONTENTS"));
103 if (document_contents)
104 {
105 /* check the Works 2000/7/8 format magic */
106 document_contents->seek(0, librevenge::RVNG_SEEK_SET);
107
108 char fileMagic[8];
109 for (int i=0; i<7 && !document_contents->isEnd(); i++)
110 fileMagic[i] = char(libwps::readU8(document_contents.get()));
111 fileMagic[7] = '\0';
112
113 /* Works 7/8 */
114 if (0 == strcmp(fileMagic, "CHNKWKS"))
115 {
116 WPS_DEBUG_MSG(("Microsoft Works v8 (maybe 7) format detected\n"));
117 return new WPSHeader(document_contents, input, 8);
118 }
119
120 /* Works 2000 */
121 if (0 == strcmp(fileMagic, "CHNKINK"))
122 {
123 return new WPSHeader(document_contents, input, 5);
124 }
125 }
126
127 return NULL;
128 }
129 /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */
130