bump product version to 5.0.4.1
[LibreOffice.git] / svl / source / misc / inethist.cxx
blob68428ebda07390cc0c257663c63b98ae5609495d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svl/inethist.hxx>
22 #include <algorithm>
23 #include <string.h>
25 #include <boost/noncopyable.hpp>
26 #include <rtl/instance.hxx>
27 #include <rtl/crc.h>
28 #include <osl/diagnose.h>
29 #include <osl/getglobalmutex.hxx>
30 #include <tools/solar.h>
31 #include <tools/debug.hxx>
32 #include <tools/urlobj.hxx>
35 * INetURLHistory internals.
37 #define INETHIST_DEF_FTP_PORT 21
38 #define INETHIST_DEF_HTTP_PORT 80
39 #define INETHIST_DEF_HTTPS_PORT 443
41 #define INETHIST_SIZE_LIMIT 1024
42 #define INETHIST_MAGIC_HEAD 0x484D4849UL
44 class INetURLHistory_Impl: private boost::noncopyable
46 struct head_entry
48 /** Representation.
50 sal_uInt32 m_nMagic;
51 sal_uInt16 m_nNext;
52 sal_uInt16 m_nMBZ;
54 /** Initialization.
56 void initialize()
58 m_nMagic = INETHIST_MAGIC_HEAD;
59 m_nNext = 0;
60 m_nMBZ = 0;
64 struct hash_entry
66 /** Representation.
68 sal_uInt32 m_nHash;
69 sal_uInt16 m_nLru;
70 sal_uInt16 m_nMBZ;
72 /** Initialization.
74 void initialize (sal_uInt16 nLru, sal_uInt32 nHash = 0)
76 m_nHash = nHash;
77 m_nLru = nLru;
78 m_nMBZ = 0;
81 /** Comparison.
83 bool operator== (sal_uInt32 nHash) const
85 return (m_nHash == nHash);
87 bool operator< (sal_uInt32 nHash) const
89 return (m_nHash < nHash);
93 struct lru_entry
95 /** Representation.
97 sal_uInt32 m_nHash;
98 sal_uInt16 m_nNext;
99 sal_uInt16 m_nPrev;
101 /** Initialization.
103 void initialize (sal_uInt16 nThis, sal_uInt32 nHash = 0)
105 m_nHash = nHash;
106 m_nNext = nThis;
107 m_nPrev = nThis;
111 /** Representation.
113 head_entry m_aHead;
114 hash_entry m_pHash[INETHIST_SIZE_LIMIT];
115 lru_entry m_pList[INETHIST_SIZE_LIMIT];
117 /** Initialization.
119 void initialize();
121 static sal_uInt16 capacity()
123 return (sal_uInt16)(INETHIST_SIZE_LIMIT);
126 static sal_uInt32 crc32 (OUString const & rData)
128 return rtl_crc32 (0, rData.getStr(), rData.getLength() * sizeof(sal_Unicode));
131 sal_uInt16 find (sal_uInt32 nHash) const;
133 void move (sal_uInt16 nSI, sal_uInt16 nDI);
135 void backlink (sal_uInt16 nThis, sal_uInt16 nTail)
137 lru_entry &rThis = m_pList[nThis];
138 lru_entry &rTail = m_pList[nTail];
140 rTail.m_nNext = nThis;
141 rTail.m_nPrev = rThis.m_nPrev;
142 rThis.m_nPrev = nTail;
143 m_pList[rTail.m_nPrev].m_nNext = nTail;
146 void unlink (sal_uInt16 nThis)
148 lru_entry &rThis = m_pList[nThis];
150 m_pList[rThis.m_nPrev].m_nNext = rThis.m_nNext;
151 m_pList[rThis.m_nNext].m_nPrev = rThis.m_nPrev;
152 rThis.m_nNext = nThis;
153 rThis.m_nPrev = nThis;
156 public:
157 INetURLHistory_Impl();
158 ~INetURLHistory_Impl();
160 /** putUrl/queryUrl.
162 void putUrl (const OUString &rUrl);
163 bool queryUrl (const OUString &rUrl);
166 INetURLHistory_Impl::INetURLHistory_Impl()
168 initialize();
171 INetURLHistory_Impl::~INetURLHistory_Impl()
175 void INetURLHistory_Impl::initialize()
177 m_aHead.initialize();
179 sal_uInt16 i, n = capacity();
180 for (i = 0; i < n; i++)
181 m_pHash[i].initialize(i);
182 for (i = 0; i < n; i++)
183 m_pList[i].initialize(i);
184 for (i = 1; i < n; i++)
185 backlink (m_aHead.m_nNext, i);
188 sal_uInt16 INetURLHistory_Impl::find (sal_uInt32 nHash) const
190 sal_uInt16 l = 0;
191 sal_uInt16 r = capacity() - 1;
192 sal_uInt16 c = capacity();
194 while ((l < r) && (r < c))
196 sal_uInt16 m = (l + r) / 2;
197 if (m_pHash[m] == nHash)
198 return m;
200 if (m_pHash[m] < nHash)
201 l = m + 1;
202 else
203 r = m - 1;
205 return l;
208 void INetURLHistory_Impl::move (sal_uInt16 nSI, sal_uInt16 nDI)
210 hash_entry e = m_pHash[nSI];
211 if (nSI < nDI)
213 // shift left.
214 memmove (
215 &m_pHash[nSI ],
216 &m_pHash[nSI + 1],
217 (nDI - nSI) * sizeof(hash_entry));
219 if (nSI > nDI)
221 // shift right.
222 memmove (
223 &m_pHash[nDI + 1],
224 &m_pHash[nDI ],
225 (nSI - nDI) * sizeof(hash_entry));
227 m_pHash[nDI] = e;
230 void INetURLHistory_Impl::putUrl (const OUString &rUrl)
232 sal_uInt32 h = crc32 (rUrl);
233 sal_uInt16 k = find (h);
234 if ((k < capacity()) && (m_pHash[k] == h))
236 // Cache hit.
237 sal_uInt16 nMRU = m_pHash[k].m_nLru;
238 if (nMRU != m_aHead.m_nNext)
240 // Update LRU chain.
241 unlink (nMRU);
242 backlink (m_aHead.m_nNext, nMRU);
244 // Rotate LRU chain.
245 m_aHead.m_nNext = m_pList[m_aHead.m_nNext].m_nPrev;
248 else
250 // Cache miss. Obtain least recently used.
251 sal_uInt16 nLRU = m_pList[m_aHead.m_nNext].m_nPrev;
253 sal_uInt16 nSI = find (m_pList[nLRU].m_nHash);
254 if (!(nLRU == m_pHash[nSI].m_nLru))
256 // Update LRU chain.
257 nLRU = m_pHash[nSI].m_nLru;
258 unlink (nLRU);
259 backlink (m_aHead.m_nNext, nLRU);
262 // Rotate LRU chain.
263 m_aHead.m_nNext = m_pList[m_aHead.m_nNext].m_nPrev;
265 // Check source and destination.
266 sal_uInt16 nDI = std::min (k, sal_uInt16(capacity() - 1));
267 if (nSI < nDI)
269 if (!(m_pHash[nDI] < h))
270 nDI -= 1;
272 if (nDI < nSI)
274 if (m_pHash[nDI] < h)
275 nDI += 1;
278 // Assign data.
279 m_pList[m_aHead.m_nNext].m_nHash = m_pHash[nSI].m_nHash = h;
280 move (nSI, nDI);
284 bool INetURLHistory_Impl::queryUrl (const OUString &rUrl)
286 sal_uInt32 h = crc32 (rUrl);
287 sal_uInt16 k = find (h);
288 if ((k < capacity()) && (m_pHash[k] == h))
290 // Cache hit.
291 return true;
293 else
295 // Cache miss.
296 return false;
301 * INetURLHistory::StaticInstance implementation.
303 INetURLHistory * INetURLHistory::StaticInstance::operator ()()
305 static INetURLHistory g_aInstance;
306 return &g_aInstance;
309 INetURLHistory::INetURLHistory() : m_pImpl (new INetURLHistory_Impl())
313 INetURLHistory::~INetURLHistory()
315 DELETEZ (m_pImpl);
319 * GetOrCreate.
321 INetURLHistory* INetURLHistory::GetOrCreate()
323 return rtl_Instance<
324 INetURLHistory, StaticInstance,
325 osl::MutexGuard, osl::GetGlobalMutex >::create (
326 StaticInstance(), osl::GetGlobalMutex());
329 void INetURLHistory::NormalizeUrl_Impl (INetURLObject &rUrl)
331 switch (rUrl.GetProtocol())
333 case INetProtocol::File:
334 if (!INetURLObject::IsCaseSensitive())
336 OUString aPath (rUrl.GetURLPath(INetURLObject::NO_DECODE).toAsciiLowerCase());
337 rUrl.SetURLPath (aPath, INetURLObject::NOT_CANONIC);
339 break;
341 case INetProtocol::Ftp:
342 if (!rUrl.HasPort())
343 rUrl.SetPort (INETHIST_DEF_FTP_PORT);
344 break;
346 case INetProtocol::Http:
347 if (!rUrl.HasPort())
348 rUrl.SetPort (INETHIST_DEF_HTTP_PORT);
349 if (!rUrl.HasURLPath())
350 rUrl.SetURLPath("/");
351 break;
353 case INetProtocol::Https:
354 if (!rUrl.HasPort())
355 rUrl.SetPort (INETHIST_DEF_HTTPS_PORT);
356 if (!rUrl.HasURLPath())
357 rUrl.SetURLPath("/");
358 break;
360 default:
361 break;
365 void INetURLHistory::PutUrl_Impl (const INetURLObject &rUrl)
367 DBG_ASSERT (m_pImpl, "PutUrl_Impl(): no Implementation");
368 if (m_pImpl)
370 INetURLObject aHistUrl (rUrl);
371 NormalizeUrl_Impl (aHistUrl);
373 m_pImpl->putUrl (aHistUrl.GetMainURL(INetURLObject::NO_DECODE));
374 Broadcast (INetURLHistoryHint (&rUrl));
376 if (aHistUrl.HasMark())
378 aHistUrl.SetURL (aHistUrl.GetURLNoMark(INetURLObject::NO_DECODE),
379 INetURLObject::NOT_CANONIC);
381 m_pImpl->putUrl (aHistUrl.GetMainURL(INetURLObject::NO_DECODE));
382 Broadcast (INetURLHistoryHint (&aHistUrl));
387 bool INetURLHistory::QueryUrl_Impl (const INetURLObject &rUrl)
389 DBG_ASSERT (m_pImpl, "QueryUrl_Impl(): no Implementation");
390 if (m_pImpl)
392 INetURLObject aHistUrl (rUrl);
393 NormalizeUrl_Impl (aHistUrl);
395 return m_pImpl->queryUrl (aHistUrl.GetMainURL(INetURLObject::NO_DECODE));
397 return false;
401 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */