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
15 * The Original Code is Places.
17 * The Initial Developer of the Original Code is
19 * Portions created by the Initial Developer are Copyright (C) 2006
20 * the Initial Developer. All Rights Reserved.
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"
43 #include "nsNetUtil.h"
46 // Columns for entry (non-meta) history rows
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
),
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)
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.
88 SwapBytes(PRUnichar
*buffer
)
90 for (PRUnichar
*b
= buffer
; *b
; ++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
,
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
]);
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()) {
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.
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
);
145 PRInt32 count
= values
[kVisitCountColumn
].ToInteger(&err
);
146 if (err
!= 0 || count
== 0) {
151 if (PR_sscanf(values
[kLastVisitColumn
].get(), "%lld", &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
;
163 titleStr
= nsDependentString(title
, titleLength
);
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.
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
185 aFile
->Exists(&exists
);
190 // Read in the mork file
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
;
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
224 nsCAutoString
byteOrderValue(byteOrder
);
225 reader
.NormalizeValue(byteOrderValue
);
226 #ifdef IS_LITTLE_ENDIAN
227 data
.swapBytes
= byteOrderValue
.EqualsLiteral("BE");
229 data
.swapBytes
= byteOrderValue
.EqualsLiteral("LE");
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();