xref: /reactos/dll/shellext/fontext/CFontCache.cpp (revision 76dd2fcf)
1 /*
2  * PROJECT:     ReactOS Font Shell Extension
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     font list cache handling
5  * COPYRIGHT:   Copyright 2019,2020 Mark Jansen (mark.jansen@reactos.org)
6  */
7 
8 #include "precomp.h"
9 
10 WINE_DEFAULT_DEBUG_CHANNEL(fontext);
11 
12 CFontCache* g_FontCache = NULL;
13 
14 CFontInfo::CFontInfo(LPCWSTR name)
15     : m_Name(name)
16     , m_FileRead(false)
17 {
18 }
19 
20 const CStringW& CFontInfo::Name() const
21 {
22     return m_Name;
23 }
24 
25 const bool CFontInfo::Valid() const
26 {
27     return !m_Name.IsEmpty();
28 }
29 
30 const CStringW& CFontInfo::File()
31 {
32     if (!m_FileRead)
33     {
34         if (Valid())
35         {
36             // Read the filename stored in the registry.
37             // This can be either a filename or a full path
38             CRegKey key;
39             if (key.Open(FONT_HIVE, FONT_KEY, KEY_READ) == ERROR_SUCCESS)
40             {
41                 CStringW Value;
42                 DWORD dwAllocated = 128;
43                 LSTATUS Status;
44                 do
45                 {
46                     DWORD dwSize = dwAllocated;
47                     PWSTR Buffer = Value.GetBuffer(dwSize);
48                     Status = key.QueryStringValue(m_Name, Buffer, &dwSize);
49                     Value.ReleaseBuffer(dwSize);
50                     if (Status == ERROR_SUCCESS)
51                     {
52                         // Ensure we do not re-use the same string object, by passing it a PCWSTR
53                         m_File = Value.GetString();
54                         break;
55                     }
56                     dwAllocated += 128;
57                 } while (Status == ERROR_MORE_DATA);
58             }
59         }
60         m_FileRead = true;
61     }
62     return m_File;
63 }
64 
65 
66 
67 CFontCache::CFontCache()
68 {
69 }
70 
71 void CFontCache::SetFontDir(const LPCWSTR Path)
72 {
73     if (m_FontFolderPath.IsEmpty())
74         m_FontFolderPath = Path;
75 }
76 
77 size_t CFontCache::Size()
78 {
79     if (m_Fonts.GetCount() == 0u)
80         Read();
81 
82     return m_Fonts.GetCount();
83 }
84 
85 CStringW CFontCache::Name(size_t Index)
86 {
87     if (m_Fonts.GetCount() == 0u)
88         Read();
89 
90     if (Index >= m_Fonts.GetCount())
91         return CStringW();
92 
93     return m_Fonts[Index].Name();
94 }
95 
96 CStringW CFontCache::Filename(const FontPidlEntry* fontEntry, bool alwaysFullPath)
97 {
98     CStringW File;
99 
100     if (fontEntry->Index < m_Fonts.GetCount())
101     {
102         CFontInfo& info = m_Fonts[fontEntry->Index];
103 
104         if (info.Name().CompareNoCase(fontEntry->Name) == 0)
105             File = info.File();
106     }
107 
108     for (UINT n = 0; File.IsEmpty() && n < Size(); ++n)
109     {
110         if (m_Fonts[n].Name().CompareNoCase(fontEntry->Name) == 0)
111             File = m_Fonts[n].File();
112     }
113 
114     if (!File.IsEmpty() && alwaysFullPath)
115     {
116         // Ensure this is a full path
117         if (PathIsRelativeW(File))
118         {
119             File = m_FontFolderPath + File;
120         }
121     }
122 
123     return File;
124 }
125 
126 void CFontCache::Insert(CAtlList<CFontInfo>& fonts, const CStringW& KeyName)
127 {
128     POSITION it = fonts.GetHeadPosition();
129     while (it != NULL)
130     {
131         POSITION lastit = it;
132         const CFontInfo& info = fonts.GetNext(it);
133         if (info.Name().CompareNoCase(KeyName) >= 0)
134         {
135             fonts.InsertBefore(lastit, CFontInfo(KeyName));
136             return;
137         }
138     }
139     fonts.AddTail(CFontInfo(KeyName));
140 }
141 
142 void CFontCache::Read()
143 {
144     CAtlList<CFontInfo> fonts;
145     CRegKey key;
146 
147     // Enumerate all registered font names
148     if (key.Open(FONT_HIVE, FONT_KEY, KEY_READ) == ERROR_SUCCESS)
149     {
150         LSTATUS Status;
151         DWORD dwAllocated = 128;
152         DWORD ilIndex = 0;
153         CStringW KeyName;
154         do
155         {
156             DWORD dwSize = dwAllocated;
157             PWSTR Buffer = KeyName.GetBuffer(dwSize);
158             Status = RegEnumValueW(key.m_hKey, ilIndex, Buffer, &dwSize, NULL, NULL, NULL, NULL);
159             KeyName.ReleaseBuffer(dwSize);
160             if (Status == ERROR_SUCCESS)
161             {
162                 // Insert will create an ordered list
163                 Insert(fonts, KeyName);
164                 ilIndex++;
165                 continue;
166             }
167             if (Status == ERROR_NO_MORE_ITEMS)
168                 break;
169             else if (Status == ERROR_MORE_DATA)
170             {
171                 dwAllocated += 128;
172             }
173         } while (Status == ERROR_MORE_DATA || Status == ERROR_SUCCESS);
174     }
175 
176     // Move the fonts from a list to an array (for easy indexing)
177     m_Fonts.SetCount(fonts.GetCount());
178     size_t Index = 0;
179     POSITION it = fonts.GetHeadPosition();
180     while (it != NULL)
181     {
182         m_Fonts[Index] = fonts.GetNext(it);
183         Index++;
184     }
185 }
186 
187