Index: chrome/utility/importer/edge_database_reader_win.cc |
diff --git a/chrome/utility/importer/edge_database_reader_win.cc b/chrome/utility/importer/edge_database_reader_win.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..58f4b2024d4f349124b17195fff168d43ea65406 |
--- /dev/null |
+++ b/chrome/utility/importer/edge_database_reader_win.cc |
@@ -0,0 +1,257 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/utility/importer/edge_database_reader_win.h" |
+ |
+#include <windows.h> |
+ |
+#include <vector> |
+ |
+namespace { |
+ |
+// This is an arbitary size chosen for the database error message buffer. |
+const size_t kErrorMessageSize = 1024; |
+// This is the page size of the Edge data. It's unlikely to change. |
+const JET_API_PTR kEdgeDatabasePageSize = 8192; |
+// This is the code page value for a Unicode (UCS-2) column. |
+const unsigned short kJetUnicodeCodePage = 1200; |
+ |
+template <typename T> |
+bool ValidateAndConvertValueGeneric(const JET_COLTYP match_column_type, |
+ const JET_COLTYP column_type, |
+ const std::vector<uint8_t>& column_data, |
+ T* value) { |
+ if ((column_type == match_column_type) && (column_data.size() == sizeof(T))) { |
+ memcpy(value, &column_data[0], sizeof(T)); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool ValidateAndConvertValue(const JET_COLTYP column_type, |
+ const std::vector<uint8_t>& column_data, |
+ bool* value) { |
+ if ((column_type == JET_coltypBit) && (column_data.size() == 1)) { |
+ *value = (column_data[0] & 1) == 1; |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool ValidateAndConvertValue(const JET_COLTYP column_type, |
+ const std::vector<uint8_t>& column_data, |
+ base::string16* value) { |
+ if ((column_type == JET_coltypLongText) && |
+ ((column_data.size() % sizeof(base::char16)) == 0)) { |
+ base::string16& value_ref = *value; |
+ size_t char_length = column_data.size() / sizeof(base::char16); |
+ value_ref.resize(char_length); |
+ memcpy(&value_ref[0], &column_data[0], column_data.size()); |
+ // Remove any trailing NUL characters. |
+ while (char_length > 0) { |
+ if (value_ref[char_length - 1]) |
+ break; |
+ char_length--; |
+ } |
+ value_ref.resize(char_length); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool ValidateAndConvertValue(const JET_COLTYP column_type, |
+ const std::vector<uint8_t>& column_data, |
+ GUID* value) { |
+ return ValidateAndConvertValueGeneric(JET_coltypGUID, column_type, |
+ column_data, value); |
+} |
+ |
+bool ValidateAndConvertValue(const JET_COLTYP column_type, |
+ const std::vector<uint8_t>& column_data, |
+ int32_t* value) { |
+ return ValidateAndConvertValueGeneric(JET_coltypLong, column_type, |
+ column_data, value); |
+} |
+ |
+bool ValidateAndConvertValue(const JET_COLTYP column_type, |
+ const std::vector<uint8_t>& column_data, |
+ int64_t* value) { |
+ return ValidateAndConvertValueGeneric(JET_coltypLongLong, column_type, |
+ column_data, value); |
+} |
+ |
+bool ValidateAndConvertValue(const JET_COLTYP column_type, |
+ const std::vector<uint8_t>& column_data, |
+ FILETIME* value) { |
+ return ValidateAndConvertValueGeneric(JET_coltypLongLong, column_type, |
+ column_data, value); |
+} |
+ |
+bool ValidateAndConvertValue(const JET_COLTYP column_type, |
+ const std::vector<uint8_t>& column_data, |
+ uint32_t* value) { |
+ return ValidateAndConvertValueGeneric(JET_coltypUnsignedLong, column_type, |
+ column_data, value); |
+} |
+ |
+} // namespace |
+ |
+base::string16 EdgeErrorObject::GetErrorMessage() const { |
+ WCHAR error_message[kErrorMessageSize] = {}; |
+ JET_API_PTR err = last_error_; |
+ JET_ERR result = JetGetSystemParameter(JET_instanceNil, JET_sesidNil, |
+ JET_paramErrorToString, &err, |
+ error_message, sizeof(error_message)); |
+ if (result != JET_errSuccess) |
+ return L""; |
+ |
+ return error_message; |
+} |
+ |
+bool EdgeErrorObject::SetLastError(JET_ERR error) { |
+ last_error_ = error; |
+ return error == JET_errSuccess; |
+} |
+ |
+EdgeDatabaseTableEnumerator::EdgeDatabaseTableEnumerator( |
+ const base::string16& table_name, |
+ JET_SESID session_id, |
+ JET_TABLEID table_id) |
+ : table_id_(table_id), table_name_(table_name), session_id_(session_id) {} |
+ |
+EdgeDatabaseTableEnumerator::~EdgeDatabaseTableEnumerator() { |
+ if (table_id_ != JET_tableidNil) |
+ JetCloseTable(session_id_, table_id_); |
+} |
+ |
+bool EdgeDatabaseTableEnumerator::Reset() { |
+ return SetLastError(JetMove(session_id_, table_id_, JET_MoveFirst, 0)); |
+} |
+ |
+bool EdgeDatabaseTableEnumerator::Next() { |
+ return SetLastError(JetMove(session_id_, table_id_, JET_MoveNext, 0)); |
+} |
+ |
+template <typename T> |
+bool EdgeDatabaseTableEnumerator::RetrieveColumn( |
+ const base::string16& column_name, |
+ T* value) { |
+ const JET_COLUMNBASE& column_base = GetColumnByName(column_name); |
+ if (column_base.cbMax == 0) { |
+ SetLastError(JET_errColumnNotFound); |
+ return false; |
+ } |
+ if (column_base.coltyp == JET_coltypLongText && |
+ column_base.cp != kJetUnicodeCodePage) { |
+ SetLastError(JET_errInvalidColumnType); |
+ return false; |
+ } |
+ std::vector<uint8_t> column_data(column_base.cbMax); |
+ unsigned long actual_size = 0; |
+ JET_ERR err = JetRetrieveColumn(session_id_, table_id_, column_base.columnid, |
+ &column_data[0], column_data.size(), |
+ &actual_size, 0, nullptr); |
+ SetLastError(err); |
+ if (err != JET_errSuccess && err != JET_wrnColumnNull) { |
+ return false; |
+ } |
+ |
+ if (err == JET_errSuccess) { |
+ column_data.resize(actual_size); |
+ if (!ValidateAndConvertValue(column_base.coltyp, column_data, value)) { |
+ 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
|
+ return false; |
+ } |
+ } else { |
+ *value = T(); |
+ } |
+ |
+ return true; |
+} |
+ |
+// Explicitly instantiate implementations of RetrieveColumn for various types. |
+template bool EdgeDatabaseTableEnumerator::RetrieveColumn(const base::string16&, |
+ bool*); |
+template bool EdgeDatabaseTableEnumerator::RetrieveColumn(const base::string16&, |
+ FILETIME*); |
+template bool EdgeDatabaseTableEnumerator::RetrieveColumn(const base::string16&, |
+ GUID*); |
+template bool EdgeDatabaseTableEnumerator::RetrieveColumn(const base::string16&, |
+ int32_t*); |
+template bool EdgeDatabaseTableEnumerator::RetrieveColumn(const base::string16&, |
+ int64_t*); |
+template bool EdgeDatabaseTableEnumerator::RetrieveColumn(const base::string16&, |
+ base::string16*); |
+template bool EdgeDatabaseTableEnumerator::RetrieveColumn(const base::string16&, |
+ uint32_t*); |
+ |
+const JET_COLUMNBASE& EdgeDatabaseTableEnumerator::GetColumnByName( |
+ const base::string16& column_name) { |
+ auto found_col = columns_by_name_.find(column_name); |
+ if (found_col == columns_by_name_.end()) { |
+ JET_COLUMNBASE column_base = {}; |
+ column_base.cbStruct = sizeof(JET_COLUMNBASE); |
+ if (!SetLastError(JetGetTableColumnInfo( |
+ session_id_, table_id_, column_name.c_str(), &column_base, |
+ sizeof(column_base), JET_ColInfoBase))) { |
+ // 0 indicates an invalid column. |
+ column_base.cbMax = 0; |
+ } |
+ columns_by_name_[column_name] = column_base; |
+ found_col = columns_by_name_.find(column_name); |
+ } |
+ return found_col->second; |
+} |
+ |
+EdgeDatabaseReader::~EdgeDatabaseReader() { |
+ // We don't need to collect other ID handles, terminating instance |
+ // is enough to shut the entire session down. |
+ if (instance_id_ != JET_instanceNil) |
+ JetTerm(instance_id_); |
+} |
+ |
+bool EdgeDatabaseReader::OpenDatabase(const base::string16& database_file) { |
+ if (IsOpen()) { |
+ SetLastError(JET_errOneDatabasePerSession); |
+ return false; |
+ } |
+ if (!SetLastError(JetSetSystemParameter(nullptr, JET_sesidNil, |
+ JET_paramDatabasePageSize, |
+ kEdgeDatabasePageSize, nullptr))) |
+ return false; |
+ if (!SetLastError(JetCreateInstance(&instance_id_, L"EdgeDataImporter"))) |
+ return false; |
+ if (!SetLastError(JetSetSystemParameter(&instance_id_, JET_sesidNil, |
+ JET_paramRecovery, 0, L"Off"))) |
+ return false; |
+ if (!SetLastError(JetInit(&instance_id_))) |
+ return false; |
+ if (!SetLastError( |
+ JetBeginSession(instance_id_, &session_id_, nullptr, nullptr))) |
+ return false; |
+ if (!SetLastError(JetAttachDatabase2(session_id_, database_file.c_str(), 0, |
+ JET_bitDbReadOnly))) |
+ return false; |
+ if (!SetLastError(JetOpenDatabase(session_id_, database_file.c_str(), nullptr, |
+ &db_id_, JET_bitDbReadOnly))) |
+ return false; |
+ return true; |
+} |
+ |
+scoped_ptr<EdgeDatabaseTableEnumerator> EdgeDatabaseReader::OpenTableEnumerator( |
+ const base::string16& table_name) { |
+ JET_TABLEID table_id; |
+ |
+ if (!IsOpen()) { |
+ SetLastError(JET_errDatabaseNotFound); |
+ return nullptr; |
+ } |
+ |
+ if (!SetLastError(JetOpenTable(session_id_, db_id_, table_name.c_str(), |
+ nullptr, 0, JET_bitTableReadOnly, &table_id))) |
+ return nullptr; |
+ |
+ return make_scoped_ptr( |
+ new EdgeDatabaseTableEnumerator(table_name, session_id_, table_id)); |
+} |