2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is Places.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Google Inc.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2006
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Brian Ryner <bryner@brianryner.com> (original author)
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
2007-08-15 08:50:22 -07:00
|
|
|
#include "nsMorkReader.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsNavHistory.h"
|
|
|
|
#include "mozStorageHelper.h"
|
|
|
|
#include "prprf.h"
|
|
|
|
#include "nsNetUtil.h"
|
|
|
|
#include "nsTArray.h"
|
|
|
|
|
|
|
|
// Columns for entry (non-meta) history rows
|
|
|
|
enum {
|
|
|
|
kURLColumn,
|
|
|
|
kNameColumn,
|
|
|
|
kVisitCountColumn,
|
|
|
|
kHiddenColumn,
|
|
|
|
kTypedColumn,
|
|
|
|
kLastVisitColumn,
|
2009-01-13 02:48:25 -08:00
|
|
|
kFirstVisitColumn,
|
2007-03-22 10:30:00 -07:00
|
|
|
kColumnCount // keep me last
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char * const gColumnNames[] = {
|
2009-01-13 02:48:25 -08:00
|
|
|
"URL", "Name", "VisitCount", "Hidden", "Typed", "LastVisitDate", "FirstVisitDate"
|
2007-03-22 10:30:00 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
struct TableReadClosure
|
|
|
|
{
|
|
|
|
TableReadClosure(nsMorkReader *aReader, nsNavHistory *aHistory)
|
|
|
|
: reader(aReader), history(aHistory), swapBytes(PR_FALSE),
|
|
|
|
byteOrderColumn(-1)
|
|
|
|
{
|
|
|
|
for (PRUint32 i = 0; i < kColumnCount; ++i) {
|
|
|
|
columnIndexes[i] = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Backpointers to the reader and history we're operating on
|
|
|
|
const nsMorkReader *reader;
|
|
|
|
nsNavHistory *history;
|
|
|
|
|
|
|
|
// Whether we need to swap bytes (file format is other-endian)
|
|
|
|
PRBool swapBytes;
|
|
|
|
|
|
|
|
// Indexes of the columns that we care about
|
|
|
|
PRInt32 columnIndexes[kColumnCount];
|
|
|
|
PRInt32 byteOrderColumn;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Reverses the high and low bytes in a PRUnichar buffer.
|
|
|
|
// This is used if the file format has a different endianness from the
|
|
|
|
// current architecture.
|
|
|
|
static void
|
|
|
|
SwapBytes(PRUnichar *buffer)
|
|
|
|
{
|
|
|
|
for (PRUnichar *b = buffer; *b; ++b) {
|
|
|
|
PRUnichar c = *b;
|
|
|
|
*b = (c << 8) | ((c >> 8) & 0xff);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-15 08:50:22 -07:00
|
|
|
// Enumerator callback to add a table row to history
|
2008-10-10 08:04:34 -07:00
|
|
|
static PLDHashOperator
|
2007-08-15 08:50:22 -07:00
|
|
|
AddToHistoryCB(const nsCSubstring &aRowID,
|
|
|
|
const nsTArray<nsCString> *aValues,
|
|
|
|
void *aData)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-07-08 00:08:04 -07:00
|
|
|
TableReadClosure *data = static_cast<TableReadClosure*>(aData);
|
2007-03-22 10:30:00 -07:00
|
|
|
const nsMorkReader *reader = data->reader;
|
|
|
|
nsCString values[kColumnCount];
|
|
|
|
const PRInt32 *columnIndexes = data->columnIndexes;
|
|
|
|
|
|
|
|
for (PRInt32 i = 0; i < kColumnCount; ++i) {
|
|
|
|
if (columnIndexes[i] != -1) {
|
|
|
|
values[i] = (*aValues)[columnIndexes[i]];
|
|
|
|
reader->NormalizeValue(values[i]);
|
2007-11-20 10:23:38 -08:00
|
|
|
if (i == kHiddenColumn && values[i].EqualsLiteral("1"))
|
|
|
|
return PL_DHASH_NEXT; // Do not import hidden records.
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-20 10:23:38 -08:00
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
NS_NewURI(getter_AddRefs(uri), values[kURLColumn]);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-11-20 10:23:38 -08:00
|
|
|
if (uri) {
|
|
|
|
// title is really a UTF-16 string at this point
|
|
|
|
nsCString &titleC = values[kNameColumn];
|
|
|
|
|
|
|
|
PRUint32 titleLength;
|
|
|
|
const char *titleBytes;
|
|
|
|
if (titleC.IsEmpty()) {
|
|
|
|
titleBytes = "\0";
|
|
|
|
titleLength = 0;
|
|
|
|
} else {
|
|
|
|
titleLength = titleC.Length() / 2;
|
|
|
|
|
|
|
|
// add an extra null byte onto the end, so that the buffer ends
|
|
|
|
// with a complete unicode null character.
|
|
|
|
titleC.Append('\0');
|
|
|
|
|
|
|
|
// Swap the bytes in the unicode characters if necessary.
|
|
|
|
if (data->swapBytes) {
|
|
|
|
SwapBytes(reinterpret_cast<PRUnichar*>(titleC.BeginWriting()));
|
|
|
|
}
|
|
|
|
titleBytes = titleC.get();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-11-20 10:23:38 -08:00
|
|
|
const PRUnichar *title = reinterpret_cast<const PRUnichar*>(titleBytes);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-11-20 10:23:38 -08:00
|
|
|
PRInt32 err;
|
2009-01-13 02:48:25 -08:00
|
|
|
PRInt32 visitCount = values[kVisitCountColumn].ToInteger(&err);
|
|
|
|
if (err != 0 || visitCount == 0) {
|
|
|
|
visitCount = 1;
|
2007-11-20 10:23:38 -08:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-01-13 02:48:25 -08:00
|
|
|
PRTime lastVisitDate;
|
|
|
|
if (PR_sscanf(values[kLastVisitColumn].get(), "%lld", &lastVisitDate) != 1) {
|
|
|
|
lastVisitDate = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRTime firstVisitDate;
|
|
|
|
if (PR_sscanf(values[kFirstVisitColumn].get(), "%lld", &firstVisitDate) != 1) {
|
|
|
|
firstVisitDate = -1;
|
2007-11-20 10:23:38 -08:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
PRBool isTyped = values[kTypedColumn].EqualsLiteral("1");
|
|
|
|
PRInt32 transition = isTyped ?
|
|
|
|
(PRInt32) nsINavHistoryService::TRANSITION_TYPED
|
|
|
|
: (PRInt32) nsINavHistoryService::TRANSITION_LINK;
|
|
|
|
nsNavHistory *history = data->history;
|
|
|
|
|
2008-03-19 12:30:49 -07:00
|
|
|
nsAutoString titleStr;
|
|
|
|
if (titleLength)
|
|
|
|
titleStr = nsDependentString(title, titleLength);
|
|
|
|
else
|
|
|
|
titleStr.SetIsVoid(PR_TRUE);
|
2009-01-13 02:48:25 -08:00
|
|
|
|
|
|
|
history->AddPageWithVisits(uri, titleStr, visitCount, transition,
|
|
|
|
firstVisitDate, lastVisitDate);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
2007-08-15 08:50:22 -07:00
|
|
|
// nsNavHistory::ImportHistory
|
|
|
|
//
|
2007-03-22 10:30:00 -07:00
|
|
|
// ImportHistory is the main entry point to the importer.
|
|
|
|
// It sets up the file stream and loops over the lines in the file to
|
|
|
|
// parse them, then adds the resulting row set to history.
|
2007-08-15 08:50:22 -07:00
|
|
|
//
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
2007-08-15 08:50:22 -07:00
|
|
|
nsNavHistory::ImportHistory(nsIFile* aFile)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-05-12 08:11:53 -07:00
|
|
|
NS_ENSURE_ARG(aFile);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Check that the file exists before we try to open it
|
|
|
|
PRBool exists;
|
|
|
|
aFile->Exists(&exists);
|
|
|
|
if (!exists) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read in the mork file
|
|
|
|
nsMorkReader reader;
|
|
|
|
nsresult rv = reader.Init();
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = reader.Read(aFile);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// Gather up the column ids so we don't need to find them on each row
|
2007-08-15 08:50:22 -07:00
|
|
|
TableReadClosure data(&reader, this);
|
2007-03-22 10:30:00 -07:00
|
|
|
const nsTArray<nsMorkReader::MorkColumn> &columns = reader.GetColumns();
|
|
|
|
for (PRUint32 i = 0; i < columns.Length(); ++i) {
|
|
|
|
const nsCSubstring &name = columns[i].name;
|
|
|
|
for (PRUint32 j = 0; j < kColumnCount; ++j) {
|
|
|
|
if (name.Equals(gColumnNames[j])) {
|
|
|
|
data.columnIndexes[j] = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (name.EqualsLiteral("ByteOrder")) {
|
|
|
|
data.byteOrderColumn = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determine the byte order from the table's meta-row.
|
|
|
|
const nsTArray<nsCString> *metaRow = reader.GetMetaRow();
|
|
|
|
if (metaRow && data.byteOrderColumn != -1) {
|
|
|
|
const nsCString &byteOrder = (*metaRow)[data.byteOrderColumn];
|
|
|
|
if (!byteOrder.IsVoid()) {
|
|
|
|
// Note whether the file uses a non-native byte ordering.
|
|
|
|
// If it does, we'll have to swap bytes for PRUnichar values.
|
|
|
|
// "BE" and "LE" are the only recognized values, anything
|
|
|
|
// else is garbage and the file will be treated as native-endian
|
|
|
|
// (no swapping).
|
|
|
|
nsCAutoString byteOrderValue(byteOrder);
|
|
|
|
reader.NormalizeValue(byteOrderValue);
|
|
|
|
#ifdef IS_LITTLE_ENDIAN
|
|
|
|
data.swapBytes = byteOrderValue.EqualsLiteral("BE");
|
|
|
|
#else
|
|
|
|
data.swapBytes = byteOrderValue.EqualsLiteral("LE");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now add the results to history
|
2007-11-20 15:27:41 -08:00
|
|
|
// Note: Duplicates are handled by Places internally, no need to filter them
|
|
|
|
// out before importing.
|
2007-08-15 08:50:22 -07:00
|
|
|
mozIStorageConnection *conn = GetStorageConnection();
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_TRUE(conn, NS_ERROR_NOT_INITIALIZED);
|
|
|
|
mozStorageTransaction transaction(conn, PR_FALSE);
|
|
|
|
|
|
|
|
reader.EnumerateRows(AddToHistoryCB, &data);
|
|
|
|
|
|
|
|
return transaction.Commit();
|
|
|
|
}
|