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>
26 #include <tools/debug.hxx>
27 #include <tools/urlobj.hxx>
30 * INetURLHistory internals.
32 #define INETHIST_DEF_FTP_PORT 21
33 #define INETHIST_DEF_HTTP_PORT 80
34 #define INETHIST_DEF_HTTPS_PORT 443
36 #define INETHIST_SIZE_LIMIT 1024
37 #define INETHIST_MAGIC_HEAD 0x484D4849UL
39 class INetURLHistory_Impl
52 m_nMagic
= INETHIST_MAGIC_HEAD
;
66 void initialize (sal_uInt16 nLru
)
74 bool operator== (sal_uInt32 nHash
) const
76 return (m_nHash
== nHash
);
78 bool operator< (sal_uInt32 nHash
) const
80 return (m_nHash
< nHash
);
94 void initialize (sal_uInt16 nThis
)
105 hash_entry m_pHash
[INETHIST_SIZE_LIMIT
];
106 lru_entry m_pList
[INETHIST_SIZE_LIMIT
];
112 static sal_uInt16
capacity()
114 return sal_uInt16(INETHIST_SIZE_LIMIT
);
117 static sal_uInt32
crc32 (OUString
const & rData
)
119 return rtl_crc32 (0, rData
.getStr(), rData
.getLength() * sizeof(sal_Unicode
));
122 sal_uInt16
find (sal_uInt32 nHash
) const;
124 void move (sal_uInt16 nSI
, sal_uInt16 nDI
);
126 void backlink (sal_uInt16 nThis
, sal_uInt16 nTail
)
128 lru_entry
&rThis
= m_pList
[nThis
];
129 lru_entry
&rTail
= m_pList
[nTail
];
131 rTail
.m_nNext
= nThis
;
132 rTail
.m_nPrev
= rThis
.m_nPrev
;
133 rThis
.m_nPrev
= nTail
;
134 m_pList
[rTail
.m_nPrev
].m_nNext
= nTail
;
137 void unlink (sal_uInt16 nThis
)
139 lru_entry
&rThis
= m_pList
[nThis
];
141 m_pList
[rThis
.m_nPrev
].m_nNext
= rThis
.m_nNext
;
142 m_pList
[rThis
.m_nNext
].m_nPrev
= rThis
.m_nPrev
;
143 rThis
.m_nNext
= nThis
;
144 rThis
.m_nPrev
= nThis
;
148 INetURLHistory_Impl();
149 INetURLHistory_Impl(const INetURLHistory_Impl
&) = delete;
150 INetURLHistory_Impl
& operator=(const INetURLHistory_Impl
&) = delete;
154 void putUrl (const OUString
&rUrl
);
155 bool queryUrl (const OUString
&rUrl
) const;
158 INetURLHistory_Impl::INetURLHistory_Impl()
163 void INetURLHistory_Impl::initialize()
165 m_aHead
.initialize();
167 sal_uInt16 i
, n
= capacity();
168 for (i
= 0; i
< n
; i
++)
169 m_pHash
[i
].initialize(i
);
170 for (i
= 0; i
< n
; i
++)
171 m_pList
[i
].initialize(i
);
172 for (i
= 1; i
< n
; i
++)
173 backlink (m_aHead
.m_nNext
, i
);
176 sal_uInt16
INetURLHistory_Impl::find (sal_uInt32 nHash
) const
179 sal_uInt16 r
= capacity() - 1;
180 sal_uInt16 c
= capacity();
182 while ((l
< r
) && (r
< c
))
184 sal_uInt16 m
= ((l
+ r
) / 2) & 0xFFFF;
185 if (m_pHash
[m
] == nHash
)
188 if (m_pHash
[m
] < nHash
)
196 void INetURLHistory_Impl::move (sal_uInt16 nSI
, sal_uInt16 nDI
)
198 hash_entry e
= m_pHash
[nSI
];
205 (nDI
- nSI
) * sizeof(hash_entry
));
213 (nSI
- nDI
) * sizeof(hash_entry
));
218 void INetURLHistory_Impl::putUrl (const OUString
&rUrl
)
220 sal_uInt32 h
= crc32 (rUrl
);
221 sal_uInt16 k
= find (h
);
222 if ((k
< capacity()) && (m_pHash
[k
] == h
))
225 sal_uInt16 nMRU
= m_pHash
[k
].m_nLru
;
226 if (nMRU
!= m_aHead
.m_nNext
)
230 backlink (m_aHead
.m_nNext
, nMRU
);
233 m_aHead
.m_nNext
= m_pList
[m_aHead
.m_nNext
].m_nPrev
;
238 // Cache miss. Obtain least recently used.
239 sal_uInt16 nLRU
= m_pList
[m_aHead
.m_nNext
].m_nPrev
;
241 sal_uInt16 nSI
= find (m_pList
[nLRU
].m_nHash
);
242 if (nLRU
!= m_pHash
[nSI
].m_nLru
)
245 nLRU
= m_pHash
[nSI
].m_nLru
;
247 backlink (m_aHead
.m_nNext
, nLRU
);
251 m_aHead
.m_nNext
= m_pList
[m_aHead
.m_nNext
].m_nPrev
;
253 // Check source and destination.
254 sal_uInt16 nDI
= std::min (k
, sal_uInt16(capacity() - 1));
255 if (nSI
< nDI
&& !(m_pHash
[nDI
] < h
))
257 if (nDI
< nSI
&& m_pHash
[nDI
] < h
)
261 m_pList
[m_aHead
.m_nNext
].m_nHash
= m_pHash
[nSI
].m_nHash
= h
;
266 bool INetURLHistory_Impl::queryUrl (const OUString
&rUrl
) const
268 sal_uInt32 h
= crc32 (rUrl
);
269 sal_uInt16 k
= find (h
);
271 return (k
< capacity()) && (m_pHash
[k
] == h
);
274 INetURLHistory::INetURLHistory() : m_pImpl (new INetURLHistory_Impl())
278 INetURLHistory::~INetURLHistory()
285 INetURLHistory
* INetURLHistory::GetOrCreate()
287 static INetURLHistory instance
;
291 void INetURLHistory::NormalizeUrl_Impl (INetURLObject
&rUrl
)
293 switch (rUrl
.GetProtocol())
295 case INetProtocol::File
:
296 if (!INetURLObject::IsCaseSensitive())
298 OUString
aPath (rUrl
.GetURLPath(INetURLObject::DecodeMechanism::NONE
).toAsciiLowerCase());
299 rUrl
.SetURLPath (aPath
, INetURLObject::EncodeMechanism::NotCanonical
);
303 case INetProtocol::Ftp
:
305 rUrl
.SetPort (INETHIST_DEF_FTP_PORT
);
308 case INetProtocol::Http
:
310 rUrl
.SetPort (INETHIST_DEF_HTTP_PORT
);
311 if (!rUrl
.HasURLPath())
312 rUrl
.SetURLPath(u
"/");
315 case INetProtocol::Https
:
317 rUrl
.SetPort (INETHIST_DEF_HTTPS_PORT
);
318 if (!rUrl
.HasURLPath())
319 rUrl
.SetURLPath(u
"/");
327 void INetURLHistory::PutUrl_Impl (const INetURLObject
&rUrl
)
329 DBG_ASSERT (m_pImpl
, "PutUrl_Impl(): no Implementation");
333 INetURLObject
aHistUrl (rUrl
);
334 NormalizeUrl_Impl (aHistUrl
);
336 m_pImpl
->putUrl (aHistUrl
.GetMainURL(INetURLObject::DecodeMechanism::NONE
));
337 Broadcast (INetURLHistoryHint (&rUrl
));
339 if (aHistUrl
.HasMark())
341 aHistUrl
.SetURL (aHistUrl
.GetURLNoMark(INetURLObject::DecodeMechanism::NONE
),
342 INetURLObject::EncodeMechanism::NotCanonical
);
344 m_pImpl
->putUrl (aHistUrl
.GetMainURL(INetURLObject::DecodeMechanism::NONE
));
345 Broadcast (INetURLHistoryHint (&aHistUrl
));
349 bool INetURLHistory::QueryUrl(std::u16string_view rUrl
) const
351 INetProtocol eProto
= INetURLObject::CompareProtocolScheme (rUrl
);
352 if (!QueryProtocol (eProto
))
354 return QueryUrl_Impl( INetURLObject(rUrl
) );
358 bool INetURLHistory::QueryUrl_Impl (INetURLObject rUrl
) const
360 DBG_ASSERT (m_pImpl
, "QueryUrl_Impl(): no Implementation");
363 NormalizeUrl_Impl (rUrl
);
365 return m_pImpl
->queryUrl (rUrl
.GetMainURL(INetURLObject::DecodeMechanism::NONE
));
371 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */