Chromium Code Reviews| 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)); |
| +} |