1/*
2 * Copyright (C) 2009 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "HistoryPropertyList.h"
28
29#include "HistoryItem.h"
30#include <wtf/StringExtras.h>
31
32namespace WebCore {
33
34static const int currentFileVersion = 1;
35
36HistoryPropertyListWriter::HistoryPropertyListWriter()
37    : m_dailyVisitCountsKey("D")
38    , m_displayTitleKey("displayTitle")
39    , m_lastVisitWasFailureKey("lastVisitWasFailure")
40    , m_lastVisitWasHTTPNonGetKey("lastVisitWasHTTPNonGet")
41    , m_lastVisitedDateKey("lastVisitedDate")
42    , m_redirectURLsKey("redirectURLs")
43    , m_titleKey("title")
44    , m_urlKey("")
45    , m_visitCountKey("visitCount")
46    , m_weeklyVisitCountsKey("W")
47    , m_buffer(0)
48{
49}
50
51UInt8* HistoryPropertyListWriter::buffer(size_t size)
52{
53    ASSERT(!m_buffer);
54    m_buffer = static_cast<UInt8*>(CFAllocatorAllocate(0, size, 0));
55    m_bufferSize = size;
56    return m_buffer;
57}
58
59RetainPtr<CFDataRef> HistoryPropertyListWriter::releaseData()
60{
61    UInt8* buffer = m_buffer;
62    if (!buffer)
63        return 0;
64    m_buffer = 0;
65    RetainPtr<CFDataRef> data(AdoptCF, CFDataCreateWithBytesNoCopy(0, buffer, m_bufferSize, 0));
66    if (!data) {
67        CFAllocatorDeallocate(0, buffer);
68        return 0;
69    }
70    return data;
71}
72
73void HistoryPropertyListWriter::writeObjects(BinaryPropertyListObjectStream& stream)
74{
75    size_t outerDictionaryStart = stream.writeDictionaryStart();
76
77    stream.writeString("WebHistoryFileVersion");
78    stream.writeString("WebHistoryDates");
79
80    stream.writeInteger(currentFileVersion);
81    size_t outerDateArrayStart = stream.writeArrayStart();
82    writeHistoryItems(stream);
83    stream.writeArrayEnd(outerDateArrayStart);
84
85    stream.writeDictionaryEnd(outerDictionaryStart);
86}
87
88void HistoryPropertyListWriter::writeHistoryItem(BinaryPropertyListObjectStream& stream, HistoryItem* item)
89{
90    size_t itemDictionaryStart = stream.writeDictionaryStart();
91
92    const String& title = item->title();
93    const String& displayTitle = item->alternateTitle();
94    double lastVisitedDate = item->lastVisitedTime();
95    int visitCount = item->visitCount();
96    Vector<String>* redirectURLs = item->redirectURLs();
97    const Vector<int>& dailyVisitCounts = item->dailyVisitCounts();
98    const Vector<int>& weeklyVisitCounts = item->weeklyVisitCounts();
99
100    // keys
101    stream.writeString(m_urlKey);
102    if (!title.isEmpty())
103        stream.writeString(m_titleKey);
104    if (!displayTitle.isEmpty())
105        stream.writeString(m_displayTitleKey);
106    if (lastVisitedDate)
107        stream.writeString(m_lastVisitedDateKey);
108    if (visitCount)
109        stream.writeString(m_visitCountKey);
110    if (item->lastVisitWasFailure())
111        stream.writeString(m_lastVisitWasFailureKey);
112    if (item->lastVisitWasHTTPNonGet())
113        stream.writeString(m_lastVisitWasHTTPNonGetKey);
114    if (redirectURLs)
115        stream.writeString(m_redirectURLsKey);
116    if (!dailyVisitCounts.isEmpty())
117        stream.writeString(m_dailyVisitCountsKey);
118    if (!weeklyVisitCounts.isEmpty())
119        stream.writeString(m_weeklyVisitCountsKey);
120
121    // values
122    stream.writeUniqueString(item->urlString());
123    if (!title.isEmpty())
124        stream.writeString(title);
125    if (!displayTitle.isEmpty())
126        stream.writeString(displayTitle);
127    if (lastVisitedDate) {
128        char buffer[32];
129        snprintf(buffer, sizeof(buffer), "%.1lf", lastVisitedDate);
130        stream.writeUniqueString(buffer);
131    }
132    if (visitCount)
133        stream.writeInteger(visitCount);
134    if (item->lastVisitWasFailure())
135        stream.writeBooleanTrue();
136    if (item->lastVisitWasHTTPNonGet()) {
137        ASSERT(item->urlString().startsWith("http:", false) || item->urlString().startsWith("https:", false));
138        stream.writeBooleanTrue();
139    }
140    if (redirectURLs) {
141        size_t redirectArrayStart = stream.writeArrayStart();
142        size_t size = redirectURLs->size();
143        ASSERT(size);
144        for (size_t i = 0; i < size; ++i)
145            stream.writeUniqueString(redirectURLs->at(i));
146        stream.writeArrayEnd(redirectArrayStart);
147    }
148    if (size_t size = dailyVisitCounts.size())
149        stream.writeIntegerArray(dailyVisitCounts.data(), size);
150    if (size_t size = weeklyVisitCounts.size())
151        stream.writeIntegerArray(weeklyVisitCounts.data(), size);
152
153    stream.writeDictionaryEnd(itemDictionaryStart);
154}
155
156}
157