OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/utility/importer/edge_database_reader_win.h" | |
6 | |
7 #include <windows.h> | |
8 | |
9 #include <vector> | |
10 | |
11 namespace { | |
12 | |
13 // This is an arbitary size chosen for the database error message buffer. | |
14 const size_t kErrorMessageSize = 1024; | |
15 // This is the page size of the Edge data. It's unlikely to change. | |
16 const JET_API_PTR kEdgeDatabasePageSize = 8192; | |
17 // This is the code page value for a Unicode (UCS-2) column. | |
18 const unsigned short kJetUnicodeCodePage = 1200; | |
19 | |
20 template <typename T> | |
21 bool ValidateAndConvertValueGeneric(const JET_COLTYP match_column_type, | |
22 const JET_COLTYP column_type, | |
23 const std::vector<uint8_t>& column_data, | |
24 T* value) { | |
25 if ((column_type == match_column_type) && (column_data.size() == sizeof(T))) { | |
26 memcpy(value, &column_data[0], sizeof(T)); | |
27 return true; | |
28 } | |
29 return false; | |
30 } | |
31 | |
32 bool ValidateAndConvertValue(const JET_COLTYP column_type, | |
33 const std::vector<uint8_t>& column_data, | |
34 bool* value) { | |
35 if ((column_type == JET_coltypBit) && (column_data.size() == 1)) { | |
36 *value = (column_data[0] & 1) == 1; | |
37 return true; | |
38 } | |
39 return false; | |
40 } | |
41 | |
42 bool ValidateAndConvertValue(const JET_COLTYP column_type, | |
43 const std::vector<uint8_t>& column_data, | |
44 base::string16* value) { | |
45 if ((column_type == JET_coltypLongText) && | |
46 ((column_data.size() % sizeof(base::char16)) == 0)) { | |
47 base::string16& value_ref = *value; | |
48 size_t char_length = column_data.size() / sizeof(base::char16); | |
49 value_ref.resize(char_length); | |
50 memcpy(&value_ref[0], &column_data[0], column_data.size()); | |
51 // Remove any trailing NUL characters. | |
52 while (char_length > 0) { | |
53 if (value_ref[char_length - 1]) | |
54 break; | |
55 char_length--; | |
56 } | |
57 value_ref.resize(char_length); | |
58 return true; | |
59 } | |
60 return false; | |
61 } | |
62 | |
63 bool ValidateAndConvertValue(const JET_COLTYP column_type, | |
64 const std::vector<uint8_t>& column_data, | |
65 GUID* value) { | |
66 return ValidateAndConvertValueGeneric(JET_coltypGUID, column_type, | |
67 column_data, value); | |
68 } | |
69 | |
70 bool ValidateAndConvertValue(const JET_COLTYP column_type, | |
71 const std::vector<uint8_t>& column_data, | |
72 int32_t* value) { | |
73 return ValidateAndConvertValueGeneric(JET_coltypLong, column_type, | |
74 column_data, value); | |
75 } | |
76 | |
77 bool ValidateAndConvertValue(const JET_COLTYP column_type, | |
78 const std::vector<uint8_t>& column_data, | |
79 int64_t* value) { | |
80 return ValidateAndConvertValueGeneric(JET_coltypLongLong, column_type, | |
81 column_data, value); | |
82 } | |
83 | |
84 bool ValidateAndConvertValue(const JET_COLTYP column_type, | |
85 const std::vector<uint8_t>& column_data, | |
86 FILETIME* value) { | |
87 return ValidateAndConvertValueGeneric(JET_coltypLongLong, column_type, | |
88 column_data, value); | |
89 } | |
90 | |
91 bool ValidateAndConvertValue(const JET_COLTYP column_type, | |
92 const std::vector<uint8_t>& column_data, | |
93 uint32_t* value) { | |
94 return ValidateAndConvertValueGeneric(JET_coltypUnsignedLong, column_type, | |
95 column_data, value); | |
96 } | |
97 | |
98 } // namespace | |
99 | |
100 base::string16 EdgeErrorObject::GetErrorMessage() const { | |
101 WCHAR error_message[kErrorMessageSize] = {}; | |
102 JET_API_PTR err = last_error_; | |
103 JET_ERR result = JetGetSystemParameter(JET_instanceNil, JET_sesidNil, | |
104 JET_paramErrorToString, &err, | |
105 error_message, sizeof(error_message)); | |
106 if (result != JET_errSuccess) | |
107 return L""; | |
108 | |
109 return error_message; | |
110 } | |
111 | |
112 bool EdgeErrorObject::SetLastError(JET_ERR error) { | |
113 last_error_ = error; | |
114 return error == JET_errSuccess; | |
115 } | |
116 | |
117 EdgeDatabaseTableEnumerator::EdgeDatabaseTableEnumerator( | |
118 const base::string16& table_name, | |
119 JET_SESID session_id, | |
120 JET_TABLEID table_id) | |
121 : table_id_(table_id), table_name_(table_name), session_id_(session_id) {} | |
122 | |
123 EdgeDatabaseTableEnumerator::~EdgeDatabaseTableEnumerator() { | |
124 if (table_id_ != JET_tableidNil) | |
125 JetCloseTable(session_id_, table_id_); | |
126 } | |
127 | |
128 bool EdgeDatabaseTableEnumerator::Reset() { | |
129 return SetLastError(JetMove(session_id_, table_id_, JET_MoveFirst, 0)); | |
130 } | |
131 | |
132 bool EdgeDatabaseTableEnumerator::Next() { | |
133 return SetLastError(JetMove(session_id_, table_id_, JET_MoveNext, 0)); | |
134 } | |
135 | |
136 template <typename T> | |
137 bool EdgeDatabaseTableEnumerator::RetrieveColumn( | |
138 const base::string16& column_name, | |
139 T* value) { | |
140 const JET_COLUMNBASE& column_base = GetColumnByName(column_name); | |
141 if (column_base.cbMax == 0) { | |
142 SetLastError(JET_errColumnNotFound); | |
143 return false; | |
144 } | |
145 if (column_base.coltyp == JET_coltypLongText && | |
146 column_base.cp != kJetUnicodeCodePage) { | |
147 SetLastError(JET_errInvalidColumnType); | |
148 return false; | |
149 } | |
150 std::vector<uint8_t> column_data(column_base.cbMax); | |
151 unsigned long actual_size = 0; | |
152 JET_ERR err = JetRetrieveColumn(session_id_, table_id_, column_base.columnid, | |
153 &column_data[0], column_data.size(), | |
154 &actual_size, 0, nullptr); | |
155 SetLastError(err); | |
156 if (err != JET_errSuccess && err != JET_wrnColumnNull) { | |
157 return false; | |
158 } | |
159 | |
160 if (err == JET_errSuccess) { | |
161 column_data.resize(actual_size); | |
162 if (!ValidateAndConvertValue(column_base.coltyp, column_data, value)) { | |
163 SetLastError(JET_errInvalidColumnType); | |
ananta
2015/12/02 21:33:11
Should there be a trace error here?
forshaw
2015/12/02 21:56:11
I expect if this fails then the entire import woul
| |
164 return false; | |
165 } | |
166 } else { | |
167 *value = T(); | |
168 } | |
169 | |
170 return true; | |
171 } | |
172 | |
173 // Explicitly instantiate implementations of RetrieveColumn for various types. | |
174 template bool EdgeDatabaseTableEnumerator::RetrieveColumn(const base::string16&, | |
175 bool*); | |
176 template bool EdgeDatabaseTableEnumerator::RetrieveColumn(const base::string16&, | |
177 FILETIME*); | |
178 template bool EdgeDatabaseTableEnumerator::RetrieveColumn(const base::string16&, | |
179 GUID*); | |
180 template bool EdgeDatabaseTableEnumerator::RetrieveColumn(const base::string16&, | |
181 int32_t*); | |
182 template bool EdgeDatabaseTableEnumerator::RetrieveColumn(const base::string16&, | |
183 int64_t*); | |
184 template bool EdgeDatabaseTableEnumerator::RetrieveColumn(const base::string16&, | |
185 base::string16*); | |
186 template bool EdgeDatabaseTableEnumerator::RetrieveColumn(const base::string16&, | |
187 uint32_t*); | |
188 | |
189 const JET_COLUMNBASE& EdgeDatabaseTableEnumerator::GetColumnByName( | |
190 const base::string16& column_name) { | |
191 auto found_col = columns_by_name_.find(column_name); | |
192 if (found_col == columns_by_name_.end()) { | |
193 JET_COLUMNBASE column_base = {}; | |
194 column_base.cbStruct = sizeof(JET_COLUMNBASE); | |
195 if (!SetLastError(JetGetTableColumnInfo( | |
196 session_id_, table_id_, column_name.c_str(), &column_base, | |
197 sizeof(column_base), JET_ColInfoBase))) { | |
198 // 0 indicates an invalid column. | |
199 column_base.cbMax = 0; | |
200 } | |
201 columns_by_name_[column_name] = column_base; | |
202 found_col = columns_by_name_.find(column_name); | |
203 } | |
204 return found_col->second; | |
205 } | |
206 | |
207 EdgeDatabaseReader::~EdgeDatabaseReader() { | |
208 // We don't need to collect other ID handles, terminating instance | |
209 // is enough to shut the entire session down. | |
210 if (instance_id_ != JET_instanceNil) | |
211 JetTerm(instance_id_); | |
212 } | |
213 | |
214 bool EdgeDatabaseReader::OpenDatabase(const base::string16& database_file) { | |
215 if (IsOpen()) { | |
216 SetLastError(JET_errOneDatabasePerSession); | |
217 return false; | |
218 } | |
219 if (!SetLastError(JetSetSystemParameter(nullptr, JET_sesidNil, | |
220 JET_paramDatabasePageSize, | |
221 kEdgeDatabasePageSize, nullptr))) | |
222 return false; | |
223 if (!SetLastError(JetCreateInstance(&instance_id_, L"EdgeDataImporter"))) | |
224 return false; | |
225 if (!SetLastError(JetSetSystemParameter(&instance_id_, JET_sesidNil, | |
226 JET_paramRecovery, 0, L"Off"))) | |
227 return false; | |
228 if (!SetLastError(JetInit(&instance_id_))) | |
229 return false; | |
230 if (!SetLastError( | |
231 JetBeginSession(instance_id_, &session_id_, nullptr, nullptr))) | |
232 return false; | |
233 if (!SetLastError(JetAttachDatabase2(session_id_, database_file.c_str(), 0, | |
234 JET_bitDbReadOnly))) | |
235 return false; | |
236 if (!SetLastError(JetOpenDatabase(session_id_, database_file.c_str(), nullptr, | |
237 &db_id_, JET_bitDbReadOnly))) | |
238 return false; | |
239 return true; | |
240 } | |
241 | |
242 scoped_ptr<EdgeDatabaseTableEnumerator> EdgeDatabaseReader::OpenTableEnumerator( | |
243 const base::string16& table_name) { | |
244 JET_TABLEID table_id; | |
245 | |
246 if (!IsOpen()) { | |
247 SetLastError(JET_errDatabaseNotFound); | |
248 return nullptr; | |
249 } | |
250 | |
251 if (!SetLastError(JetOpenTable(session_id_, db_id_, table_name.c_str(), | |
252 nullptr, 0, JET_bitTableReadOnly, &table_id))) | |
253 return nullptr; | |
254 | |
255 return make_scoped_ptr( | |
256 new EdgeDatabaseTableEnumerator(table_name, session_id_, table_id)); | |
257 } | |
OLD | NEW |