Chromium Code Reviews| 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 |