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 <rtl/instance.hxx>
27 #include <osl/getglobalmutex.hxx>
28 #include <tools/solar.h>
29 #include <tools/debug.hxx>
30 #include <tools/urlobj.hxx>
33 * INetURLHistory internals.
35 #define INETHIST_DEF_FTP_PORT 21
36 #define INETHIST_DEF_HTTP_PORT 80
37 #define INETHIST_DEF_HTTPS_PORT 443
39 #define INETHIST_SIZE_LIMIT 1024
40 #define INETHIST_MAGIC_HEAD 0x484D4849UL
42 class INetURLHistory_Impl
55 m_nMagic
= INETHIST_MAGIC_HEAD
;
69 void initialize (sal_uInt16 nLru
)
77 bool operator== (sal_uInt32 nHash
) const
79 return (m_nHash
== nHash
);
81 bool operator< (sal_uInt32 nHash
) const
83 return (m_nHash
< nHash
);
97 void initialize (sal_uInt16 nThis
)
108 hash_entry m_pHash
[INETHIST_SIZE_LIMIT
];
109 lru_entry m_pList
[INETHIST_SIZE_LIMIT
];
115 static sal_uInt16
capacity()
117 return sal_uInt16(INETHIST_SIZE_LIMIT
);
120 static sal_uInt32
crc32 (OUString
const & rData
)
122 return rtl_crc32 (0, rData
.getStr(), rData
.getLength() * sizeof(sal_Unicode
));
125 sal_uInt16
find (sal_uInt32 nHash
) const;
127 void move (sal_uInt16 nSI
, sal_uInt16 nDI
);
129 void backlink (sal_uInt16 nThis
, sal_uInt16 nTail
)
131 lru_entry
&rThis
= m_pList
[nThis
];
132 lru_entry
&rTail
= m_pList
[nTail
];
134 rTail
.m_nNext
= nThis
;
135 rTail
.m_nPrev
= rThis
.m_nPrev
;
136 rThis
.m_nPrev
= nTail
;
137 m_pList
[rTail
.m_nPrev
].m_nNext
= nTail
;
140 void unlink (sal_uInt16 nThis
)
142 lru_entry
&rThis
= m_pList
[nThis
];
144 m_pList
[rThis
.m_nPrev
].m_nNext
= rThis
.m_nNext
;
145 m_pList
[rThis
.m_nNext
].m_nPrev
= rThis
.m_nPrev
;
146 rThis
.m_nNext
= nThis
;
147 rThis
.m_nPrev
= nThis
;
151 INetURLHistory_Impl();
152 INetURLHistory_Impl(const INetURLHistory_Impl
&) = delete;
153 INetURLHistory_Impl
& operator=(const INetURLHistory_Impl
&) = delete;
157 void putUrl (const OUString
&rUrl
);
158 bool queryUrl (const OUString
&rUrl
) const;
161 INetURLHistory_Impl::INetURLHistory_Impl()
166 void INetURLHistory_Impl::initialize()
168 m_aHead
.initialize();
170 sal_uInt16 i
, n
= capacity();
171 for (i
= 0; i
< n
; i
++)
172 m_pHash
[i
].initialize(i
);
173 for (i
= 0; i
< n
; i
++)
174 m_pList
[i
].initialize(i
);
175 for (i
= 1; i
< n
; i
++)
176 backlink (m_aHead
.m_nNext
, i
);
179 sal_uInt16
INetURLHistory_Impl::find (sal_uInt32 nHash
) const
182 sal_uInt16 r
= capacity() - 1;
183 sal_uInt16 c
= capacity();
185 while ((l
< r
) && (r
< c
))
187 sal_uInt16 m
= (l
+ r
) / 2;
188 if (m_pHash
[m
] == nHash
)
191 if (m_pHash
[m
] < nHash
)
199 void INetURLHistory_Impl::move (sal_uInt16 nSI
, sal_uInt16 nDI
)
201 hash_entry e
= m_pHash
[nSI
];
208 (nDI
- nSI
) * sizeof(hash_entry
));
216 (nSI
- nDI
) * sizeof(hash_entry
));
221 void INetURLHistory_Impl::putUrl (const OUString
&rUrl
)
223 sal_uInt32 h
= crc32 (rUrl
);
224 sal_uInt16 k
= find (h
);
225 if ((k
< capacity()) && (m_pHash
[k
] == h
))
228 sal_uInt16 nMRU
= m_pHash
[k
].m_nLru
;
229 if (nMRU
!= m_aHead
.m_nNext
)
233 backlink (m_aHead
.m_nNext
, nMRU
);
236 m_aHead
.m_nNext
= m_pList
[m_aHead
.m_nNext
].m_nPrev
;
241 // Cache miss. Obtain least recently used.
242 sal_uInt16 nLRU
= m_pList
[m_aHead
.m_nNext
].m_nPrev
;
244 sal_uInt16 nSI
= find (m_pList
[nLRU
].m_nHash
);
245 if (nLRU
!= m_pHash
[nSI
].m_nLru
)
248 nLRU
= m_pHash
[nSI
].m_nLru
;
250 backlink (m_aHead
.m_nNext
, nLRU
);
254 m_aHead
.m_nNext
= m_pList
[m_aHead
.m_nNext
].m_nPrev
;
256 // Check source and destination.
257 sal_uInt16 nDI
= std::min (k
, sal_uInt16(capacity() - 1));
260 if (!(m_pHash
[nDI
] < h
))
265 if (m_pHash
[nDI
] < h
)
270 m_pList
[m_aHead
.m_nNext
].m_nHash
= m_pHash
[nSI
].m_nHash
= h
;
275 bool INetURLHistory_Impl::queryUrl (const OUString
&rUrl
) const
277 sal_uInt32 h
= crc32 (rUrl
);
278 sal_uInt16 k
= find (h
);
280 return (k
< capacity()) && (m_pHash
[k
] == h
);
284 * INetURLHistory::StaticInstance implementation.
286 INetURLHistory
* INetURLHistory::StaticInstance::operator ()()
288 static INetURLHistory g_aInstance
;
292 INetURLHistory::INetURLHistory() : m_pImpl (new INetURLHistory_Impl())
296 INetURLHistory::~INetURLHistory()
303 INetURLHistory
* INetURLHistory::GetOrCreate()
306 INetURLHistory
, StaticInstance
,
307 osl::MutexGuard
, osl::GetGlobalMutex
>::create (
308 StaticInstance(), osl::GetGlobalMutex());
311 void INetURLHistory::NormalizeUrl_Impl (INetURLObject
&rUrl
)
313 switch (rUrl
.GetProtocol())
315 case INetProtocol::File
:
316 if (!INetURLObject::IsCaseSensitive())
318 OUString
aPath (rUrl
.GetURLPath(INetURLObject::DecodeMechanism::NONE
).toAsciiLowerCase());
319 rUrl
.SetURLPath (aPath
, INetURLObject::EncodeMechanism::NotCanonical
);
323 case INetProtocol::Ftp
:
325 rUrl
.SetPort (INETHIST_DEF_FTP_PORT
);
328 case INetProtocol::Http
:
330 rUrl
.SetPort (INETHIST_DEF_HTTP_PORT
);
331 if (!rUrl
.HasURLPath())
332 rUrl
.SetURLPath("/");
335 case INetProtocol::Https
:
337 rUrl
.SetPort (INETHIST_DEF_HTTPS_PORT
);
338 if (!rUrl
.HasURLPath())
339 rUrl
.SetURLPath("/");
347 void INetURLHistory::PutUrl_Impl (const INetURLObject
&rUrl
)
349 DBG_ASSERT (m_pImpl
, "PutUrl_Impl(): no Implementation");
353 INetURLObject
aHistUrl (rUrl
);
354 NormalizeUrl_Impl (aHistUrl
);
356 m_pImpl
->putUrl (aHistUrl
.GetMainURL(INetURLObject::DecodeMechanism::NONE
));
357 Broadcast (INetURLHistoryHint (&rUrl
));
359 if (aHistUrl
.HasMark())
361 aHistUrl
.SetURL (aHistUrl
.GetURLNoMark(INetURLObject::DecodeMechanism::NONE
),
362 INetURLObject::EncodeMechanism::NotCanonical
);
364 m_pImpl
->putUrl (aHistUrl
.GetMainURL(INetURLObject::DecodeMechanism::NONE
));
365 Broadcast (INetURLHistoryHint (&aHistUrl
));
369 bool INetURLHistory::QueryUrl_Impl (const INetURLObject
&rUrl
)
371 DBG_ASSERT (m_pImpl
, "QueryUrl_Impl(): no Implementation");
374 INetURLObject
aHistUrl (rUrl
);
375 NormalizeUrl_Impl (aHistUrl
);
377 return m_pImpl
->queryUrl (aHistUrl
.GetMainURL(INetURLObject::DecodeMechanism::NONE
));
383 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */