/src/libwpd/src/lib/WP42Heuristics.cpp
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ |
2 | | /* libwpd |
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) 2003 William Lachance (wrlach@gmail.com) |
11 | | * Copyright (C) 2003 Marc Maurer (uwog@uwog.net) |
12 | | * Copyright (C) 2006 Fridrich Strba (fridrich.strba@bluewin.ch) |
13 | | * |
14 | | * For minor contributions see the git repository. |
15 | | * |
16 | | * Alternatively, the contents of this file may be used under the terms |
17 | | * of the GNU Lesser General Public License Version 2.1 or later |
18 | | * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are |
19 | | * applicable instead of those above. |
20 | | * |
21 | | * For further information visit http://libwpd.sourceforge.net |
22 | | */ |
23 | | |
24 | | /* "This product is not manufactured, approved, or supported by |
25 | | * Corel Corporation or Corel Corporation Limited." |
26 | | */ |
27 | | |
28 | | #include "WP42Heuristics.h" |
29 | | |
30 | | #include <memory> |
31 | | |
32 | | #include "WP42FileStructure.h" |
33 | | #include "libwpd_internal.h" |
34 | | |
35 | | using namespace libwpd; |
36 | | |
37 | 0 | WPDPasswordMatch WP42Heuristics::verifyPassword(librevenge::RVNGInputStream *input, const char *password) try |
38 | 0 | { |
39 | 0 | if (!password) |
40 | 0 | return WPD_PASSWORD_MATCH_DONTKNOW; |
41 | | |
42 | 0 | input->seek(0, librevenge::RVNG_SEEK_SET); |
43 | |
|
44 | 0 | if (readU8(input, nullptr) == 0xFE && readU8(input, nullptr) == 0xFF && |
45 | 0 | readU8(input, nullptr) == 0x61 && readU8(input, nullptr) == 0x61) |
46 | 0 | { |
47 | 0 | WPXEncryption encryption(password, 6); |
48 | 0 | if (readU16(input, nullptr) == encryption.getCheckSum()) |
49 | 0 | return WPD_PASSWORD_MATCH_OK; |
50 | 0 | else |
51 | 0 | return WPD_PASSWORD_MATCH_NONE; |
52 | 0 | } |
53 | 0 | else |
54 | 0 | return WPD_PASSWORD_MATCH_DONTKNOW; |
55 | 0 | } |
56 | 0 | catch (...) |
57 | 0 | { |
58 | 0 | return WPD_PASSWORD_MATCH_DONTKNOW; |
59 | 0 | } |
60 | | |
61 | 0 | WPDConfidence WP42Heuristics::isWP42FileFormat(librevenge::RVNGInputStream *input, const char *password) try |
62 | 0 | { |
63 | 0 | input->seek(0, librevenge::RVNG_SEEK_SET); |
64 | 0 | std::unique_ptr<WPXEncryption> encryption; |
65 | 0 | if (readU8(input, nullptr) == 0xFE && readU8(input, nullptr) == 0xFF && |
66 | 0 | readU8(input, nullptr) == 0x61 && readU8(input, nullptr) == 0x61) |
67 | 0 | { |
68 | 0 | if (password) |
69 | 0 | { |
70 | 0 | encryption.reset(new WPXEncryption(password, 6)); |
71 | 0 | if (readU16(input, nullptr) != encryption->getCheckSum()) |
72 | 0 | return WPD_CONFIDENCE_SUPPORTED_ENCRYPTION; |
73 | 0 | } |
74 | 0 | else |
75 | 0 | { |
76 | 0 | if (readU16(input,nullptr) != 0x0000) |
77 | 0 | return WPD_CONFIDENCE_SUPPORTED_ENCRYPTION; |
78 | 0 | } |
79 | 0 | } |
80 | | |
81 | 0 | input->seek(0, librevenge::RVNG_SEEK_SET); |
82 | 0 | if (password && encryption) |
83 | 0 | input->seek(6, librevenge::RVNG_SEEK_SET); |
84 | |
|
85 | 0 | int functionGroupCount = 0; |
86 | 0 | bool invalidUTF8 = false; |
87 | |
|
88 | 0 | WPD_DEBUG_MSG(("WP42Heuristics::isWP42FileFormat()\n")); |
89 | |
|
90 | 0 | while (!input->isEnd()) |
91 | 0 | { |
92 | 0 | unsigned char readVal = readU8(input, encryption.get()); |
93 | |
|
94 | 0 | WPD_DEBUG_MSG(("WP42Heuristics, Offset 0x%.8x, value 0x%.2x\n", (unsigned int)(input->tell() - 1), readVal)); |
95 | |
|
96 | 0 | if (readVal < (unsigned char)0x20) |
97 | 0 | { |
98 | | // line breaks et al, skip |
99 | 0 | } |
100 | 0 | else if (readVal >= (unsigned char)0x20 && readVal <= (unsigned char)0x7F) |
101 | 0 | { |
102 | | // normal ASCII characters, skip |
103 | 0 | } |
104 | 0 | else if (readVal >= (unsigned char)0x80 && readVal <= (unsigned char)0xBF) |
105 | 0 | { |
106 | | // single character function codes, skip |
107 | 0 | functionGroupCount++; |
108 | 0 | } |
109 | 0 | else if (readVal >= (unsigned char)0xFF) |
110 | 0 | { |
111 | | // special codes that should not be found as separate functions |
112 | 0 | return WPD_CONFIDENCE_NONE; |
113 | 0 | } |
114 | 0 | else |
115 | 0 | { |
116 | | // multi character function group |
117 | |
|
118 | 0 | if (!invalidUTF8 && isValidUtf8(input, encryption.get())) |
119 | 0 | { |
120 | 0 | WPD_DEBUG_MSG(("WP42Heuristics validUTF8\n")); |
121 | 0 | continue; |
122 | 0 | } |
123 | 0 | else |
124 | 0 | { |
125 | 0 | WPD_DEBUG_MSG(("WP42Heuristics invalidUTF8\n")); |
126 | 0 | invalidUTF8 = true; |
127 | 0 | } |
128 | | |
129 | | // check that the size constrains are valid, and that every group_member |
130 | | // is properly closed at the right place |
131 | | |
132 | 0 | if (WP42_FUNCTION_GROUP_SIZE[readVal-0xC0] == -1) |
133 | 0 | { |
134 | | // variable length function group |
135 | | |
136 | | // skip over all the bytes in the group, and scan for the closing gate |
137 | 0 | unsigned char readNextVal = 0; |
138 | 0 | while (!input->isEnd()) |
139 | 0 | { |
140 | 0 | readNextVal = readU8(input, encryption.get()); |
141 | 0 | if (readNextVal == readVal) |
142 | 0 | break; |
143 | 0 | } |
144 | | |
145 | | // when passed the complete file, we don't allow for open groups when we've reached EOF |
146 | 0 | if ((readNextVal == 0) || (input->isEnd() && (readNextVal != readVal))) |
147 | 0 | return WPD_CONFIDENCE_NONE; |
148 | | |
149 | 0 | functionGroupCount++; |
150 | 0 | } |
151 | 0 | else |
152 | 0 | { |
153 | | // fixed length function group |
154 | | |
155 | | // seek to the position where the closing gate should be |
156 | 0 | int res = input->seek(WP42_FUNCTION_GROUP_SIZE[readVal-0xC0]-2, librevenge::RVNG_SEEK_CUR); |
157 | | // when passed the complete file, we should be able to do that |
158 | 0 | if (res) |
159 | 0 | return WPD_CONFIDENCE_NONE; |
160 | | |
161 | | // read the closing gate |
162 | 0 | unsigned char readNextVal = readU8(input, encryption.get()); |
163 | 0 | if (readNextVal != readVal) |
164 | 0 | return WPD_CONFIDENCE_NONE; |
165 | | |
166 | 0 | functionGroupCount++; |
167 | 0 | } |
168 | 0 | } |
169 | 0 | } |
170 | | |
171 | | /* When we get here, the document is in a format that we *could* import properly. |
172 | | However, if we didn't entcounter a single WP4.2 function group) we need to be more carefull: |
173 | | this would be the case when passed a plaintext file for example, which libwpd is not |
174 | | supposed to handle. */ |
175 | 0 | if (!invalidUTF8) |
176 | 0 | return WPD_CONFIDENCE_NONE; |
177 | 0 | if (!functionGroupCount && !encryption) |
178 | 0 | return WPD_CONFIDENCE_NONE; |
179 | | |
180 | 0 | return WPD_CONFIDENCE_EXCELLENT; |
181 | 0 | } |
182 | 0 | catch (...) |
183 | 0 | { |
184 | 0 | return WPD_CONFIDENCE_NONE; |
185 | 0 | } |
186 | | |
187 | | /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */ |