Bug 451040 ? Passwords Manager Empty after convert to MozStorage. r=gavin
[wine-gecko.git] / toolkit / components / places / src / nsMorkHistoryImporter.cpp
blob5102b71141e437350c6d3a7ca2f7f4c014c192d9
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Places.
17 * The Initial Developer of the Original Code is
18 * Google Inc.
19 * Portions created by the Initial Developer are Copyright (C) 2006
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Brian Ryner <bryner@brianryner.com> (original author)
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsMorkReader.h"
40 #include "nsNavHistory.h"
41 #include "mozStorageHelper.h"
42 #include "prprf.h"
43 #include "nsNetUtil.h"
44 #include "nsTArray.h"
46 // Columns for entry (non-meta) history rows
47 enum {
48 kURLColumn,
49 kNameColumn,
50 kVisitCountColumn,
51 kHiddenColumn,
52 kTypedColumn,
53 kLastVisitColumn,
54 kColumnCount // keep me last
57 static const char * const gColumnNames[] = {
58 "URL", "Name", "VisitCount", "Hidden", "Typed", "LastVisitDate"
61 struct TableReadClosure
63 TableReadClosure(nsMorkReader *aReader, nsNavHistory *aHistory)
64 : reader(aReader), history(aHistory), swapBytes(PR_FALSE),
65 byteOrderColumn(-1)
67 for (PRUint32 i = 0; i < kColumnCount; ++i) {
68 columnIndexes[i] = -1;
72 // Backpointers to the reader and history we're operating on
73 const nsMorkReader *reader;
74 nsNavHistory *history;
76 // Whether we need to swap bytes (file format is other-endian)
77 PRBool swapBytes;
79 // Indexes of the columns that we care about
80 PRInt32 columnIndexes[kColumnCount];
81 PRInt32 byteOrderColumn;
84 // Reverses the high and low bytes in a PRUnichar buffer.
85 // This is used if the file format has a different endianness from the
86 // current architecture.
87 static void
88 SwapBytes(PRUnichar *buffer)
90 for (PRUnichar *b = buffer; *b; ++b) {
91 PRUnichar c = *b;
92 *b = (c << 8) | ((c >> 8) & 0xff);
96 // Enumerator callback to add a table row to history
97 static PLDHashOperator PR_CALLBACK
98 AddToHistoryCB(const nsCSubstring &aRowID,
99 const nsTArray<nsCString> *aValues,
100 void *aData)
102 TableReadClosure *data = static_cast<TableReadClosure*>(aData);
103 const nsMorkReader *reader = data->reader;
104 nsCString values[kColumnCount];
105 const PRInt32 *columnIndexes = data->columnIndexes;
107 for (PRInt32 i = 0; i < kColumnCount; ++i) {
108 if (columnIndexes[i] != -1) {
109 values[i] = (*aValues)[columnIndexes[i]];
110 reader->NormalizeValue(values[i]);
111 if (i == kHiddenColumn && values[i].EqualsLiteral("1"))
112 return PL_DHASH_NEXT; // Do not import hidden records.
116 nsCOMPtr<nsIURI> uri;
117 NS_NewURI(getter_AddRefs(uri), values[kURLColumn]);
119 if (uri) {
120 // title is really a UTF-16 string at this point
121 nsCString &titleC = values[kNameColumn];
123 PRUint32 titleLength;
124 const char *titleBytes;
125 if (titleC.IsEmpty()) {
126 titleBytes = "\0";
127 titleLength = 0;
128 } else {
129 titleLength = titleC.Length() / 2;
131 // add an extra null byte onto the end, so that the buffer ends
132 // with a complete unicode null character.
133 titleC.Append('\0');
135 // Swap the bytes in the unicode characters if necessary.
136 if (data->swapBytes) {
137 SwapBytes(reinterpret_cast<PRUnichar*>(titleC.BeginWriting()));
139 titleBytes = titleC.get();
142 const PRUnichar *title = reinterpret_cast<const PRUnichar*>(titleBytes);
144 PRInt32 err;
145 PRInt32 count = values[kVisitCountColumn].ToInteger(&err);
146 if (err != 0 || count == 0) {
147 count = 1;
150 PRTime date;
151 if (PR_sscanf(values[kLastVisitColumn].get(), "%lld", &date) != 1) {
152 date = -1;
155 PRBool isTyped = values[kTypedColumn].EqualsLiteral("1");
156 PRInt32 transition = isTyped ?
157 (PRInt32) nsINavHistoryService::TRANSITION_TYPED
158 : (PRInt32) nsINavHistoryService::TRANSITION_LINK;
159 nsNavHistory *history = data->history;
161 nsAutoString titleStr;
162 if (titleLength)
163 titleStr = nsDependentString(title, titleLength);
164 else
165 titleStr.SetIsVoid(PR_TRUE);
166 history->AddPageWithVisit(uri, titleStr,
167 PR_FALSE, isTyped, count, transition, date);
169 return PL_DHASH_NEXT;
172 // nsNavHistory::ImportHistory
174 // ImportHistory is the main entry point to the importer.
175 // It sets up the file stream and loops over the lines in the file to
176 // parse them, then adds the resulting row set to history.
178 NS_IMETHODIMP
179 nsNavHistory::ImportHistory(nsIFile* aFile)
181 NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
183 // Check that the file exists before we try to open it
184 PRBool exists;
185 aFile->Exists(&exists);
186 if (!exists) {
187 return NS_OK;
190 // Read in the mork file
191 nsMorkReader reader;
192 nsresult rv = reader.Init();
193 NS_ENSURE_SUCCESS(rv, rv);
195 rv = reader.Read(aFile);
196 NS_ENSURE_SUCCESS(rv, rv);
198 // Gather up the column ids so we don't need to find them on each row
199 TableReadClosure data(&reader, this);
200 const nsTArray<nsMorkReader::MorkColumn> &columns = reader.GetColumns();
201 for (PRUint32 i = 0; i < columns.Length(); ++i) {
202 const nsCSubstring &name = columns[i].name;
203 for (PRUint32 j = 0; j < kColumnCount; ++j) {
204 if (name.Equals(gColumnNames[j])) {
205 data.columnIndexes[j] = i;
206 break;
209 if (name.EqualsLiteral("ByteOrder")) {
210 data.byteOrderColumn = i;
214 // Determine the byte order from the table's meta-row.
215 const nsTArray<nsCString> *metaRow = reader.GetMetaRow();
216 if (metaRow && data.byteOrderColumn != -1) {
217 const nsCString &byteOrder = (*metaRow)[data.byteOrderColumn];
218 if (!byteOrder.IsVoid()) {
219 // Note whether the file uses a non-native byte ordering.
220 // If it does, we'll have to swap bytes for PRUnichar values.
221 // "BE" and "LE" are the only recognized values, anything
222 // else is garbage and the file will be treated as native-endian
223 // (no swapping).
224 nsCAutoString byteOrderValue(byteOrder);
225 reader.NormalizeValue(byteOrderValue);
226 #ifdef IS_LITTLE_ENDIAN
227 data.swapBytes = byteOrderValue.EqualsLiteral("BE");
228 #else
229 data.swapBytes = byteOrderValue.EqualsLiteral("LE");
230 #endif
234 // Now add the results to history
235 // Note: Duplicates are handled by Places internally, no need to filter them
236 // out before importing.
237 mozIStorageConnection *conn = GetStorageConnection();
238 NS_ENSURE_TRUE(conn, NS_ERROR_NOT_INITIALIZED);
239 mozStorageTransaction transaction(conn, PR_FALSE);
241 reader.EnumerateRows(AddToHistoryCB, &data);
243 return transaction.Commit();