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
32 namespace WebCore {
33
34 static const int currentFileVersion = 1;
35
HistoryPropertyListWriter()36 HistoryPropertyListWriter::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
buffer(size_t size)51 UInt8* 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
releaseData()59 RetainPtr<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
writeObjects(BinaryPropertyListObjectStream & stream)73 void 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
writeHistoryItem(BinaryPropertyListObjectStream & stream,HistoryItem * item)88 void 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