Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / libs / locale / opencataloga.c
bloba74cc96839e1ccbf421d1233de9162ba9180bf3a
1 /*
2 Copyright © 1995-2008, The AROS Development Team. All rights reserved.
3 $Id$
4 */
5 #define AROS_ALMOST_COMPATIBLE
7 #include <exec/types.h>
8 #include <exec/memory.h>
9 #include <exec/lists.h>
10 #include <proto/exec.h>
11 #include <proto/dos.h>
12 #include <libraries/iffparse.h>
13 #include <proto/iffparse.h>
14 #include <proto/utility.h>
15 #include <string.h>
16 #include "locale_intern.h"
18 #include <aros/debug.h>
20 #define DEBUG_OPENCATALOG(x) ;
22 struct header
24 unsigned char id[4];
25 unsigned char len[4];
28 /*****************************************************************************
30 NAME */
31 #include <proto/locale.h>
33 AROS_LH3(struct Catalog *, OpenCatalogA,
35 /* SYNOPSIS */
36 AROS_LHA(const struct Locale *, locale, A0),
37 AROS_LHA(CONST_STRPTR, name, A1),
38 AROS_LHA(const struct TagItem *, tags, A2),
40 /* LOCATION */
41 struct LocaleBase *, LocaleBase, 25, Locale)
43 /* FUNCTION
45 INPUTS
47 RESULT
49 NOTES
51 EXAMPLE
53 BUGS
55 SEE ALSO
57 INTERNALS
59 *****************************************************************************/
61 AROS_LIBFUNC_INIT
63 struct Locale * def_locale = NULL;
64 struct IntCatalog * catalog = NULL;
65 char * language;
66 char * app_language;
67 char * specific_language;
68 struct Process * MyProcess;
69 #define FILENAMESIZE 256
71 char filename[FILENAMESIZE];
72 char buf[100];
73 LONG chars;
74 ULONG version;
75 ULONG catversion,catrevision;
76 WORD pref_language;
77 UWORD i;
79 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: locale 0x%lx name <%s> Tags 0x%lx localebase 0x%lx\n",
80 locale,
81 name,
82 tags,
83 LocaleBase));
85 SetIoErr(0);
87 if (!locale)
89 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: no locale\n"));
90 locale = def_locale = OpenLocale(NULL);
91 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: def_locale 0x%lx\n",
92 def_locale));
95 if (!locale)
97 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: nolocale..done\n"));
98 return NULL;
101 MyProcess=(struct Process *)FindTask(NULL);
103 specific_language = (char *)GetTagData(OC_Language, (IPTR)0, tags);
105 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: specific lang 0x%lx\n",specific_language));
106 if (specific_language)
108 language = specific_language;
109 pref_language = -1;
110 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: language 0x%lx\n",language));
112 else
114 language = locale->loc_PrefLanguages[0];
115 pref_language = 0;
116 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: language 0x%lx\n",language));
119 if (language == NULL)
121 if (def_locale) CloseLocale(def_locale);
122 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: nolanguage..done\n"));
123 return NULL;
127 ** Check whether the built in language of the application matches
128 ** the language of the default locale. If it matches, then I
129 ** don't need to load anything.
132 app_language = "english";
133 app_language = (char *)GetTagData(OC_BuiltInLanguage,
134 (IPTR)app_language,
135 tags);
137 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: app_language 0x%lx\n",
138 app_language));
140 if (NULL != app_language && 0 == strcmp(app_language, language))
142 if (def_locale) CloseLocale(def_locale);
143 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: failure..done\n"));
144 return NULL;
147 version = GetTagData(OC_Version,
149 tags);
151 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: version %ld\n",version));
153 if (NULL != name)
155 struct IFFHandle * iff = NULL;
158 ** The wanted catalog might be in the list of catalogs that are
159 ** already loaded. So check that list first.
162 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: CatalogLock 0x%lx\n",
163 &IntLB(LocaleBase)->lb_CatalogLock));
165 ObtainSemaphore(&IntLB(LocaleBase)->lb_CatalogLock);
167 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: search cached Catalog\n"));
169 ForeachNode(&IntLB(LocaleBase)->lb_CatalogList, catalog)
171 if (catalog->ic_Name &&
172 0 == strcmp(catalog->ic_Name, name) &&
173 catalog->ic_Catalog.cat_Language &&
174 0 == strcmp(catalog->ic_Catalog.cat_Language, language))
176 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: found Catalog 0x%lx\n",catalog));
177 catalog->ic_UseCount++;
178 ReleaseSemaphore(&IntLB(LocaleBase)->lb_CatalogLock);
180 if (def_locale)
182 CloseLocale(def_locale);
185 SetIoErr(ERROR_ACTION_NOT_KNOWN);
187 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: return Catalog 0x%lx\n",catalog));
188 return (struct Catalog *)catalog;
191 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: found none\n"));
193 ReleaseSemaphore(&IntLB(LocaleBase)->lb_CatalogLock);
196 /* Clear error condition before we start. */
197 SetIoErr(0);
199 iff = AllocIFF();
201 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: iff 0x%lx\n",iff));
202 if (NULL == iff)
204 if (def_locale) CloseLocale(def_locale);
205 SetIoErr(ERROR_NO_FREE_STORE);
207 return NULL;
210 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: pref_language %ld language 0x%lx\n",
211 pref_language,
212 language));
214 while ((pref_language < 10) && language)
216 if (app_language && (strcmp(language, app_language) == 0))
218 FreeIFF(iff);
219 if (def_locale) CloseLocale(def_locale);
220 SetIoErr(0);
221 return NULL;
224 if ((MyProcess->pr_HomeDir) != NULL)
226 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: HomeDir !=NULL..try progdir\n"));
227 strcpy(filename, "PROGDIR:Catalogs");
228 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: filename <%s>\n",filename));
229 AddPart(filename, language, FILENAMESIZE);
230 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: filename <%s>\n",filename));
231 AddPart(filename, name , FILENAMESIZE);
233 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: filename <%s>\n",filename));
234 iff->iff_Stream = (IPTR)Open(filename, MODE_OLDFILE);
235 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: iffstream 0x%lx\n",
236 iff->iff_Stream));
238 if (iff->iff_Stream) break;
240 #ifdef __MORPHOS__
241 strcpy(filename, "MOSSYS:LOCALE/Catalogs");
243 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: filename <%s>\n",filename));
244 AddPart(filename, language, FILENAMESIZE);
245 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: filename <%s>\n",filename));
246 AddPart(filename, name , FILENAMESIZE);
248 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: try filename <%s>\n",filename));
250 { APTR oldwinptr=MyProcess->pr_WindowPtr;
251 MyProcess->pr_WindowPtr=(APTR)-1;
252 iff->iff_Stream = (IPTR)Open(filename, MODE_OLDFILE);
253 MyProcess->pr_WindowPtr=oldwinptr;
256 if (iff->iff_Stream) break;
257 #endif
258 strcpy(filename, "LOCALE:Catalogs");
260 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: filename <%s>\n",filename));
261 AddPart(filename, language, FILENAMESIZE);
262 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: filename <%s>\n",filename));
263 AddPart(filename, name , FILENAMESIZE);
265 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: try filename <%s>\n",filename));
267 iff->iff_Stream = (IPTR)Open(filename, MODE_OLDFILE);
268 if (iff->iff_Stream) break;
270 pref_language++;
271 language = locale->loc_PrefLanguages[pref_language];
274 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: language 0x%lx\n",language));
276 /* I no longer need the locale. So close it if we opened it */
278 if (def_locale)
280 CloseLocale(def_locale);
281 def_locale = NULL;
284 #undef FILENAMESIZE
286 if (iff->iff_Stream == 0)
288 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: end..nostream\n"));
289 FreeIFF(iff);
290 SetIoErr(ERROR_OBJECT_NOT_FOUND);
291 return NULL;
294 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: catalog name <%s>\n",name));
295 catalog = AllocVec(sizeof(struct IntCatalog) + strlen(name) + 1, MEMF_CLEAR | MEMF_PUBLIC);
296 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: catalog 0x%lx\n",catalog));
297 if (NULL == catalog)
299 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: end..no catalog\n"));
300 Close((BPTR)iff->iff_Stream);
301 FreeIFF(iff);
302 SetIoErr(ERROR_NO_FREE_STORE);
303 return NULL;
306 catalog->ic_UseCount = 1;
307 catalog->ic_Catalog.cat_Language = catalog->ic_LanguageName;
308 strcpy(catalog->ic_Name, name);
310 InitIFFasDOS(iff);
312 if (!OpenIFF(iff, IFFF_READ))
314 while (1)
316 LONG error = ParseIFF(iff, IFFPARSE_STEP);
318 if (IFFERR_EOF == error)
320 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: parsed catalog\n"));
321 /* Did everything go fine? */
323 if (!(catalog->ic_LanguageName[0]))
325 /* No ID_LANG chunk found. So setup languagename ourselves.
326 Hmm ... maybe this should be done anyway always. Because
327 if the catalog file *does* contain an ID_LANG chunk then
328 this should be the same as "language" anyway. And if it
329 is not, then maybe OpenCatalogA() should fail :-\ */
331 strcpy(catalog->ic_LanguageName, language);
334 /* Connect this catalog to the list of catalogs */
335 ObtainSemaphore (&IntLB(LocaleBase)->lb_CatalogLock);
336 AddHead((struct List *)&IntLB(LocaleBase)->lb_CatalogList,
337 &catalog->ic_Catalog.cat_Link);
338 ReleaseSemaphore(&IntLB(LocaleBase)->lb_CatalogLock);
340 CloseIFF(iff);
341 Close((BPTR)iff->iff_Stream);
342 FreeIFF(iff);
344 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: return catalog 0x%lx\n",catalog));
346 return &catalog->ic_Catalog;
349 if (IFFERR_EOC == error) /* end of chunk */
350 continue;
352 if (0 == error)
354 struct ContextNode * top = CurrentChunk(iff);
356 switch (top->cn_ID)
358 case ID_FORM:
359 break;
361 case ID_FVER:
363 if (top->cn_Size > 100) break; /*max 100 bytes*/
365 error = ReadChunkBytes(iff, buf, top->cn_Size);
366 if (error == top->cn_Size)
368 error = 0;
370 else
372 break;
375 buf[99] = 0;
377 /*Ok now we want to get the version and the revision.
378 They are separated by a blank space*/
380 i = 0;
381 while (buf[i] && (buf[i] != ' '))
382 i++;
383 while (buf[i] && (buf[i] == ' '))
384 i++;
385 while (buf[i] && (buf[i] != ' '))
386 i++;
388 if (buf[i])
390 if ((chars = StrToLong(&buf[i],(LONG *)&catversion)) < 0)
391 break;
393 i += chars;
394 if (buf[i++])
396 if (StrToLong(&buf[i],(LONG *)&catrevision) < 0)
397 break;
400 catalog->ic_Catalog.cat_Version = catversion;
401 catalog->ic_Catalog.cat_Revision = catrevision;
403 if (version && (catversion != version))
405 error = RETURN_ERROR;
408 break;
412 case ID_LANG:
413 /* The IntCatalog structure has only 30 bytes reserved for
414 the language name. So make sure the chunk is not bigger. */
416 if (top->cn_Size > 30) break;
418 error = ReadChunkBytes(iff, catalog->ic_LanguageName, top->cn_Size);
419 if (error == top->cn_Size)
421 error = 0;
423 break;
425 case ID_CSET:
426 if (top->cn_Size != sizeof(struct CodeSet)) break;
427 if (top->cn_Size == ReadChunkBytes(iff,
428 &catalog->ic_CodeSet,
429 top->cn_Size))
431 /* Who cares: codeset is not used at the moment */
433 break;
435 case ID_STRS:
436 if (!(catalog->ic_StringChunk = AllocVec(top->cn_Size, MEMF_PUBLIC | MEMF_CLEAR)))
438 error = ERROR_NO_FREE_STORE;
439 SetIoErr(error);
440 break;
443 error = ReadChunkBytes(iff, catalog->ic_StringChunk, top->cn_Size);
444 if (error == top->cn_Size)
446 error = 0;
448 else
450 break;
453 /* Count the number of strings */
456 UBYTE *buffer = catalog->ic_StringChunk;
457 LONG c = 0, strlen;
459 catalog->ic_NumStrings = 0;
461 while(c < top->cn_Size)
463 catalog->ic_NumStrings++;
465 strlen = (buffer[4] << 24) +
466 (buffer[5] << 16) +
467 (buffer[6] << 8) +
468 (buffer[7]);
470 strlen = 8 + strlen + (strlen & 1);
471 if (strlen & 3) strlen += 4 - (strlen & 3);
473 c += strlen; buffer += strlen;
478 if (catalog->ic_NumStrings == 0) break; /* Paranoia? */
480 if (!(catalog->ic_CatStrings = AllocVec(catalog->ic_NumStrings * sizeof(struct CatStr), MEMF_PUBLIC | MEMF_CLEAR)))
482 error = ERROR_NO_FREE_STORE;
483 SetIoErr(error);
484 break;
487 /* Fill out catalog->ic_CatStrings array */
490 UBYTE *buffer = catalog->ic_StringChunk;
491 ULONG i, strlen, id, previd = 0;
492 BOOL inorder = TRUE;
494 for(i = 0; i < catalog->ic_NumStrings; i++)
496 id = (buffer[0] << 24) +
497 (buffer[1] << 16) +
498 (buffer[2] << 8) +
499 (buffer[3]);
501 strlen = (buffer[4] << 24) +
502 (buffer[5] << 16) +
503 (buffer[6] << 8) +
504 (buffer[7]);
506 catalog->ic_CatStrings[i].cs_String = &buffer[8];
507 catalog->ic_CatStrings[i].cs_Id = id;
509 //kprintf("Catalog String #%d id=%d string=\"%s\"\n", i, id, catalog->ic_CatStrings[i].cs_String);
511 strlen = 8 + strlen + (strlen & 1);
512 if (strlen & 3) strlen += 4 - (strlen & 3);
514 if (id < previd) inorder = FALSE;
516 buffer += strlen;
517 previd = id;
520 if (inorder) catalog->ic_Flags |= ICF_INORDER;
522 break;
524 } /* switch (top->cn_ID) */
526 } /* if (0 == error) */
528 if (error)
530 dispose_catalog(catalog, LocaleBase);
532 ** An error with the file occurred
534 break;
537 } /* while (1) */
539 CloseIFF(iff);
541 } /* if (!OpenIFF(iff, IFFF_READ)) */
544 Close((BPTR)iff->iff_Stream);
545 FreeIFF(iff);
546 FreeVec(catalog);
548 } /* if (NULL != name) */
550 if (def_locale) CloseLocale(def_locale);
552 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: catalog not loaded\n"));
553 return NULL;
555 AROS_LIBFUNC_EXIT
557 } /* OpenCatalogA */