1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
25 #include <boost/noncopyable.hpp>
26 #include <rtl/instance.hxx>
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
58 m_nMagic
= INETHIST_MAGIC_HEAD
;
74 void initialize (sal_uInt16 nLru
, sal_uInt32 nHash
= 0)
83 bool operator== (sal_uInt32 nHash
) const
85 return (m_nHash
== nHash
);
87 bool operator< (sal_uInt32 nHash
) const
89 return (m_nHash
< nHash
);
103 void initialize (sal_uInt16 nThis
, sal_uInt32 nHash
= 0)
114 hash_entry m_pHash
[INETHIST_SIZE_LIMIT
];
115 lru_entry m_pList
[INETHIST_SIZE_LIMIT
];
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
;
157 INetURLHistory_Impl();
158 ~INetURLHistory_Impl();
162 void putUrl (const OUString
&rUrl
);
163 bool queryUrl (const OUString
&rUrl
);
166 INetURLHistory_Impl::INetURLHistory_Impl()
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
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
)
200 if (m_pHash
[m
] < nHash
)
208 void INetURLHistory_Impl::move (sal_uInt16 nSI
, sal_uInt16 nDI
)
210 hash_entry e
= m_pHash
[nSI
];
217 (nDI
- nSI
) * sizeof(hash_entry
));
225 (nSI
- nDI
) * sizeof(hash_entry
));
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
))
237 sal_uInt16 nMRU
= m_pHash
[k
].m_nLru
;
238 if (nMRU
!= m_aHead
.m_nNext
)
242 backlink (m_aHead
.m_nNext
, nMRU
);
245 m_aHead
.m_nNext
= m_pList
[m_aHead
.m_nNext
].m_nPrev
;
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
))
257 nLRU
= m_pHash
[nSI
].m_nLru
;
259 backlink (m_aHead
.m_nNext
, nLRU
);
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));
269 if (!(m_pHash
[nDI
] < h
))
274 if (m_pHash
[nDI
] < h
)
279 m_pList
[m_aHead
.m_nNext
].m_nHash
= m_pHash
[nSI
].m_nHash
= h
;
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
))
301 * INetURLHistory::StaticInstance implementation.
303 INetURLHistory
* INetURLHistory::StaticInstance::operator ()()
305 static INetURLHistory g_aInstance
;
309 INetURLHistory::INetURLHistory() : m_pImpl (new INetURLHistory_Impl())
313 INetURLHistory::~INetURLHistory()
321 INetURLHistory
* INetURLHistory::GetOrCreate()
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
);
341 case INetProtocol::Ftp
:
343 rUrl
.SetPort (INETHIST_DEF_FTP_PORT
);
346 case INetProtocol::Http
:
348 rUrl
.SetPort (INETHIST_DEF_HTTP_PORT
);
349 if (!rUrl
.HasURLPath())
350 rUrl
.SetURLPath("/");
353 case INetProtocol::Https
:
355 rUrl
.SetPort (INETHIST_DEF_HTTPS_PORT
);
356 if (!rUrl
.HasURLPath())
357 rUrl
.SetURLPath("/");
365 void INetURLHistory::PutUrl_Impl (const INetURLObject
&rUrl
)
367 DBG_ASSERT (m_pImpl
, "PutUrl_Impl(): no Implementation");
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");
392 INetURLObject
aHistUrl (rUrl
);
393 NormalizeUrl_Impl (aHistUrl
);
395 return m_pImpl
->queryUrl (aHistUrl
.GetMainURL(INetURLObject::NO_DECODE
));
401 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */