diff options
Diffstat (limited to 'chrome/utility/importer/edge_database_reader_win.cc')
-rw-r--r-- | chrome/utility/importer/edge_database_reader_win.cc | 257 |
1 files changed, 257 insertions, 0 deletions
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 0000000..58f4b20 --- /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); + 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)); +} |