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