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 "HistoryPropertyList.h" 27 28#include <WebCore/HistoryItem.h> 29#include <wtf/StringExtras.h> 30 31using namespace WebCore; 32 33static const int currentFileVersion = 1; 34 35HistoryPropertyListWriter::HistoryPropertyListWriter() 36 : m_dailyVisitCountsKey("D") 37 , m_displayTitleKey("displayTitle") 38 , m_lastVisitWasFailureKey("lastVisitWasFailure") 39 , m_lastVisitWasHTTPNonGetKey("lastVisitWasHTTPNonGet") 40 , m_lastVisitedDateKey("lastVisitedDate") 41 , m_redirectURLsKey("redirectURLs") 42 , m_titleKey("title") 43 , m_urlKey("") 44 , m_visitCountKey("visitCount") 45 , m_weeklyVisitCountsKey("W") 46 , m_buffer(0) 47{ 48} 49 50UInt8* HistoryPropertyListWriter::buffer(size_t size) 51{ 52 ASSERT(!m_buffer); 53 m_buffer = static_cast<UInt8*>(CFAllocatorAllocate(0, size, 0)); 54 m_bufferSize = size; 55 return m_buffer; 56} 57 58RetainPtr<CFDataRef> HistoryPropertyListWriter::releaseData() 59{ 60 UInt8* buffer = m_buffer; 61 if (!buffer) 62 return 0; 63 m_buffer = 0; 64 RetainPtr<CFDataRef> data = adoptCF(CFDataCreateWithBytesNoCopy(0, buffer, m_bufferSize, 0)); 65 if (!data) { 66 CFAllocatorDeallocate(0, buffer); 67 return 0; 68 } 69 return data; 70} 71 72void HistoryPropertyListWriter::writeObjects(BinaryPropertyListObjectStream& stream) 73{ 74 size_t outerDictionaryStart = stream.writeDictionaryStart(); 75 76 stream.writeString("WebHistoryFileVersion"); 77 stream.writeString("WebHistoryDates"); 78 79 stream.writeInteger(currentFileVersion); 80 size_t outerDateArrayStart = stream.writeArrayStart(); 81 writeHistoryItems(stream); 82 stream.writeArrayEnd(outerDateArrayStart); 83 84 stream.writeDictionaryEnd(outerDictionaryStart); 85} 86 87void HistoryPropertyListWriter::writeHistoryItem(BinaryPropertyListObjectStream& stream, HistoryItem* item) 88{ 89 size_t itemDictionaryStart = stream.writeDictionaryStart(); 90 91 const String& title = item->title(); 92 const String& displayTitle = item->alternateTitle(); 93 double lastVisitedDate = item->lastVisitedTime(); 94 int visitCount = item->visitCount(); 95 Vector<String>* redirectURLs = item->redirectURLs(); 96 const Vector<int>& dailyVisitCounts = item->dailyVisitCounts(); 97 const Vector<int>& weeklyVisitCounts = item->weeklyVisitCounts(); 98 99 // keys 100 stream.writeString(m_urlKey); 101 if (!title.isEmpty()) 102 stream.writeString(m_titleKey); 103 if (!displayTitle.isEmpty()) 104 stream.writeString(m_displayTitleKey); 105 if (lastVisitedDate) 106 stream.writeString(m_lastVisitedDateKey); 107 if (visitCount) 108 stream.writeString(m_visitCountKey); 109 if (item->lastVisitWasFailure()) 110 stream.writeString(m_lastVisitWasFailureKey); 111 if (item->lastVisitWasHTTPNonGet()) 112 stream.writeString(m_lastVisitWasHTTPNonGetKey); 113 if (redirectURLs) 114 stream.writeString(m_redirectURLsKey); 115 if (!dailyVisitCounts.isEmpty()) 116 stream.writeString(m_dailyVisitCountsKey); 117 if (!weeklyVisitCounts.isEmpty()) 118 stream.writeString(m_weeklyVisitCountsKey); 119 120 // values 121 stream.writeUniqueString(item->urlString()); 122 if (!title.isEmpty()) 123 stream.writeString(title); 124 if (!displayTitle.isEmpty()) 125 stream.writeString(displayTitle); 126 if (lastVisitedDate) { 127 char buffer[32]; 128 snprintf(buffer, sizeof(buffer), "%.1lf", lastVisitedDate); 129 stream.writeUniqueString(buffer); 130 } 131 if (visitCount) 132 stream.writeInteger(visitCount); 133 if (item->lastVisitWasFailure()) 134 stream.writeBooleanTrue(); 135 if (item->lastVisitWasHTTPNonGet()) { 136 ASSERT(item->urlString().startsWith("http:", false) || item->urlString().startsWith("https:", false)); 137 stream.writeBooleanTrue(); 138 } 139 if (redirectURLs) { 140 size_t redirectArrayStart = stream.writeArrayStart(); 141 size_t size = redirectURLs->size(); 142 ASSERT(size); 143 for (size_t i = 0; i < size; ++i) 144 stream.writeUniqueString(redirectURLs->at(i)); 145 stream.writeArrayEnd(redirectArrayStart); 146 } 147 if (size_t size = dailyVisitCounts.size()) 148 stream.writeIntegerArray(dailyVisitCounts.data(), size); 149 if (size_t size = weeklyVisitCounts.size()) 150 stream.writeIntegerArray(weeklyVisitCounts.data(), size); 151 152 stream.writeDictionaryEnd(itemDictionaryStart); 153} 154 155