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 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 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 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 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 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