shell32: Implement SHGetNewLinkInfo[AW].
[wine] / dlls / wineps.drv / glyphlist.c
1 /*******************************************************************************
2  *
3  *      Functions and data structures used to maintain a single list of glyph
4  *      names.  The list is sorted alphabetically and each name appears only
5  *      once.  After all font information has been read, the 'index' field of
6  *      each GLYPHNAME structure is initialized, so future sorts/searches can
7  *      be done without comparing strings.
8  *
9  * Copyright 2001 Ian Pilcher
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25
26 #include <string.h>
27 #include "psdrv.h"
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
31
32 #define GLYPHLIST_ALLOCSIZE     1024
33
34 static GLYPHNAME    **glyphList = NULL;
35 static INT          glyphListSize = 0;
36 static BOOL         glyphNamesIndexed = TRUE;
37
38 /*******************************************************************************
39  *      PSDRV_GlyphListInit
40  *
41  *  Allocates initial block of memory for the glyph list and copies pointers to
42  *  the AGL glyph names into it; returns 0 on success, 1 on failure
43  *
44  */
45 INT PSDRV_GlyphListInit(void)
46 {
47     INT i;
48
49     /*
50      *  Compute the smallest multiple of GLYPHLIST_ALLOCSIZE that is
51      *  greater than or equal to PSDRV_AGLGlyphNamesSize
52      *
53      */
54     glyphListSize = PSDRV_AGLGlyphNamesSize;
55     i = ((glyphListSize + GLYPHLIST_ALLOCSIZE - 1) / GLYPHLIST_ALLOCSIZE) *
56             GLYPHLIST_ALLOCSIZE;
57
58     TRACE("glyphList will initially hold %i glyph names\n", i);
59
60     glyphList = HeapAlloc(PSDRV_Heap, 0, i * sizeof(GLYPHNAME *));
61     if (glyphList == NULL) return 1;
62
63     for (i = 0; i < glyphListSize; ++i)
64         glyphList[i] = PSDRV_AGLGlyphNames + i;
65
66     return 0;
67 }
68
69 /*******************************************************************************
70  *      GlyphListInsert
71  *
72  *  Inserts a copy of the  glyph name into the list at the index, growing the
73  *  list if necessary; returns index on success (-1 on failure)
74  *
75  */
76 static inline INT GlyphListInsert(LPCSTR szName, INT index)
77 {
78     GLYPHNAME *g;
79
80     g = HeapAlloc(PSDRV_Heap, 0, sizeof(GLYPHNAME) + strlen(szName) + 1);
81     if (g == NULL) return -1;
82
83     g->index = -1;
84     g->sz = (LPSTR)(g + 1);
85     strcpy((LPSTR)g->sz, szName);
86
87     if (glyphListSize % GLYPHLIST_ALLOCSIZE == 0)       /* grow the list? */
88     {
89         GLYPHNAME   **newGlyphList;
90
91         newGlyphList = HeapReAlloc(PSDRV_Heap, 0, glyphList,
92                 (glyphListSize + GLYPHLIST_ALLOCSIZE) * sizeof(GLYPHNAME *));
93         if (newGlyphList == NULL)
94         {
95             HeapFree(PSDRV_Heap, 0, g);
96             return -1;
97         }
98
99         glyphList = newGlyphList;
100
101         TRACE("glyphList will now hold %i glyph names\n",
102                 glyphListSize + GLYPHLIST_ALLOCSIZE);
103     }
104
105     if (index < glyphListSize)
106     {
107         memmove(glyphList + (index + 1), glyphList + index,
108                 (glyphListSize - index) * sizeof(GLYPHNAME *));
109     }
110
111     glyphList[index] = g;
112     ++glyphListSize;
113     glyphNamesIndexed = FALSE;
114
115 #if 0
116     TRACE("Added '%s' at glyphList[%i] (glyphListSize now %i)\n",
117             glyphList[index]->sz, index, glyphListSize);
118 #endif
119     return index;
120 }
121
122 /*******************************************************************************
123  *      GlyphListSearch
124  *
125  *  Searches the specified portion of the list for the glyph name and inserts it
126  *  in the list if necessary; returns the index at which the name (now) resides
127  *  (-1 if unable to insert it)
128  *
129  */
130 static INT GlyphListSearch(LPCSTR szName, INT loIndex, INT hiIndex)
131 {
132     INT midIndex, cmpResult;
133
134     while (1)
135     {
136         if (loIndex > hiIndex)
137             return GlyphListInsert(szName, loIndex);
138
139         midIndex = (loIndex + hiIndex) >> 1;
140
141         cmpResult = strcmp(szName, glyphList[midIndex]->sz);
142
143         if (cmpResult == 0)
144         {
145 #if 0
146             TRACE("Found '%s' at glyphList[%i]\n", glyphList[midIndex]->sz,
147                     midIndex);
148 #endif
149             return midIndex;
150         }
151
152         if (cmpResult < 0)
153             hiIndex = midIndex - 1;
154         else
155             loIndex = midIndex + 1;
156     }
157 }
158
159 /*******************************************************************************
160  *      PSDRV_GlyphName
161  *
162  *  Searches the glyph name list for the provided name, adds it to the list if
163  *  necessary, and returns a pointer to it (NULL if unable to add it)
164  *
165  */
166 const GLYPHNAME *PSDRV_GlyphName(LPCSTR szName)
167 {
168     INT index;
169
170     index = GlyphListSearch(szName, 0, glyphListSize - 1);
171     if (index < 0)
172         return NULL;
173
174     return glyphList[index];
175 }
176
177 /*******************************************************************************
178  *      PSDRV_IndexGlyphList
179  *
180  *  Initializes index member of all GLYPHNAME structures
181  *
182  */
183 VOID PSDRV_IndexGlyphList(void)
184 {
185     INT i;
186
187     if (glyphNamesIndexed)
188         return;
189
190     TRACE("%i glyph names:\n", glyphListSize);
191
192     for (i = 0; i < glyphListSize; ++i)
193     {
194         glyphList[i]->index = i;
195 #if 0
196         TRACE("  glyphList[%i] -> '%s'\n", i, glyphList[i]->sz);
197 #endif
198     }
199
200     glyphNamesIndexed = TRUE;
201 }