From 31e10cd7d3dcb3ac09013a05a45840fc6de03048 Mon Sep 17 00:00:00 2001 From: eccles Date: Tue, 20 Jan 2004 23:20:44 +0000 Subject: [PATCH] Installer would crash with certain combinations of language files when certain language strings were not referenced in all languages. git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@3404 212acab6-be3b-0410-9dea-997c60f758d6 --- Source/lang.cpp | 257 ++++++++++++++++++++++++++--------------------- Source/lang.h | 8 +- Source/strlist.h | 27 ++--- 3 files changed, 161 insertions(+), 131 deletions(-) diff --git a/Source/lang.cpp b/Source/lang.cpp index 84f7e126..c9a8b8f5 100644 --- a/Source/lang.cpp +++ b/Source/lang.cpp @@ -409,196 +409,227 @@ int CEXEBuild::GenerateLangTables() { } } - // Add language tables into their datablock - int j, l, cnt, tabsset; + // Add all installer language strings + int j, l, tabsset; struct langstring* lang_strings; + TinyGrowBuf *string_ptrs = new TinyGrowBuf[num_lang_tables]; - i = num_lang_tables; - while (i--) { - build_langtables.add(<[i].lang_id, sizeof(LANGID)); - build_langtables.add(<[i].dlg_offset, sizeof(int)); + tabsset = 1; + while (tabsset) + { + tabsset = 0; + for (i = num_lang_tables; i--; ) { - int rtl = lt[i].nlf.m_bRTL ? 1 : 0; - build_langtables.add(&rtl, sizeof(int)); + // Fill in default values for all used language strings that we can + FillLanguageTable(<[i]); + // Make sure the string lists are large enough + string_ptrs[i].set_zeroing(1); + string_ptrs[i].resize(build_langstring_num * sizeof(int)); } - int *lst = NULL; - unsigned int oldlen = build_langtables.getlen(); - - cnt = 0; - tabsset = 1; - - // write langstrings - while (tabsset) { - FillLanguageTable(<[i]); - - int lastcnt = cnt; - cnt = 0; - tabsset = 0; - - lang_strings = build_langstrings.sort_index(&l); - - for (j = 0; j < l; j++) { - lst = (int *)((char *)build_langtables.get() + oldlen); - if (lang_strings[j].index >= 0) { - if (cnt >= lastcnt || !lst[lang_strings[j].index]) { + // For all current language strings + lang_strings = build_langstrings.sort_index(&l); + for (j = 0; j < l; j++) + { + // Is this language string used (in the installer)? + if (lang_strings[j].index >= 0) + { + // For each language + for (i = num_lang_tables; i--; ) + { + // Get the current string pointer + int *ptr = (int *)string_ptrs[i].get() + lang_strings[j].index; + // Not already set? + if (!*ptr) + { + // Get the language string and its name const char *str = lt[i].lang_strings->get(lang_strings[j].sn); - int tab = 0; - const char *lsn = build_langstrings.offset2name(lang_strings[j].name); - - if (!str || !*str) { + if (!str || !*str) + { + // No string is defined; give a warning (for user strings only) if (lsn[0] != '^') warning("LangString \"%s\" is not set in language table of language %d", lsn, lt[i].lang_id); } - else { + else + { + // Add the language string to the string data block char fn[1024]; sprintf(fn, "LangString %s", lsn); curfilename = fn; linecnt = lt[i].lang_id; - - tab = add_string(str, lang_strings[j].process, lt[i].nlf.m_uCodePage); - tabsset++; - + *ptr = add_string(str, lang_strings[j].process, lt[i].nlf.m_uCodePage); curfilename = 0; + // Indicate that we should check again for any newly referenced language strings + tabsset++; } - - if (cnt < lastcnt) - lst[lang_strings[j].index] = tab; - else - build_langtables.add(&tab, sizeof(int)); } - - cnt++; } } } + } - lst = (int *)((char *)build_langtables.get() + oldlen); - - // optimize langstrings and check for recursion + // Optimize langstrings and check for recursion + for (i = num_lang_tables; i--; ) + { TinyGrowBuf rec; - for (j = 0; j < build_langstring_num; j++) { - while (lst[j] < 0) { - for (int k = 0; (unsigned int)k < rec.getlen() / sizeof(int); k++) { - if (((int*)rec.get())[k] == lst[j]) { + int *lst = (int *)string_ptrs[i].get(); + for (j = 0; j < build_langstring_num; j++) + { + // Does this string reference another language string directly? + while (lst[j] < 0) + { + // Search through list of language string references + for (l = 0; (unsigned int)l < rec.getlen() / sizeof(int); l++) + { + if (((int*)rec.get())[l] == lst[j]) + { + // We have the index of a recursive language string; now find the name const char *name = "(unnamed)"; - for (k = 0; k < l; k++) { - if (lang_strings[k].index == j) { - name = build_langstrings.offset2name(lang_strings[k].name); - } - } + for (l = 0; l < build_langstring_num; l++) + if (lang_strings[l].index == j) + name = build_langstrings.offset2name(lang_strings[l].name); ERROR_MSG("Error: LangString %s is recursive!\n", name); + delete [] string_ptrs; return PS_ERROR; } } + // Add this reference to the list rec.add(&lst[j], sizeof(int)); + // and dereference it lst[j] = lst[-lst[j] - 1]; } rec.resize(0); } } + // Add language tables into their datablock + for (i = num_lang_tables; i--; ) + { + build_langtables.add(<[i].lang_id, sizeof(LANGID)); + build_langtables.add(<[i].dlg_offset, sizeof(int)); + int rtl = lt[i].nlf.m_bRTL ? 1 : 0; + build_langtables.add(&rtl, sizeof(int)); + build_langtables.add(string_ptrs[i].get(), string_ptrs[i].getlen()); + string_ptrs[i].resize(0); + } + build_header.blocks[NB_LANGTABLES].num = num_lang_tables; build_header.langtable_size = build_langtables.getlen() / num_lang_tables; #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT + // Now do it all again, this time for the uninstaller set_uninstall_mode(1); - i = num_lang_tables; - while (i--) { - ubuild_langtables.add(<[i].lang_id, sizeof(LANGID)); - ubuild_langtables.add(<[i].dlg_offset, sizeof(int)); + tabsset = 1; + while (tabsset) + { + tabsset = 0; + for (i = num_lang_tables; i--; ) { - int rtl = lt[i].nlf.m_bRTL ? 1 : 0; - ubuild_langtables.add(&rtl, sizeof(int)); + // Fill in default values for all used language strings that we can + FillLanguageTable(<[i]); + // Make sure the string lists are large enough + string_ptrs[i].set_zeroing(1); + string_ptrs[i].resize(ubuild_langstring_num * sizeof(int)); } - int *lst = NULL; - unsigned int oldlen = ubuild_langtables.getlen(); - - cnt = 0; - tabsset = 1; - - // write langstrings - while (tabsset) { - FillLanguageTable(<[i]); - - int lastcnt = cnt; - cnt = 0; - tabsset = 0; - - lang_strings = build_langstrings.sort_uindex(&l); - - for (j = 0; j < l; j++) { - lst = (int *)((char *)ubuild_langtables.get() + oldlen); - if (lang_strings[j].uindex >= 0) { - if (cnt >= lastcnt || !lst[lang_strings[j].uindex]) { + // For all current language strings + lang_strings = build_langstrings.sort_uindex(&l); + for (j = 0; j < l; j++) + { + // Is this language string used (in the uninstaller)? + if (lang_strings[j].uindex >= 0) + { + // For each language + for (i = num_lang_tables; i--; ) + { + // Get the current string pointer + int *ptr = (int *)string_ptrs[i].get() + lang_strings[j].uindex; + // Not already set? + if (!*ptr) + { + // Get the language string and its name const char *str = lt[i].lang_strings->get(lang_strings[j].sn); - int tab = 0; - const char *lsn = build_langstrings.offset2name(lang_strings[j].name); - - if (!str || !*str) { + if (!str || !*str) + { + // No string is defined; give a warning (for user strings only) if (lsn[0] != '^') warning("LangString \"%s\" is not set in language table of language %d", lsn, lt[i].lang_id); } - else { + else + { + // Add the language string to the string data block char fn[1024]; sprintf(fn, "LangString %s", lsn); curfilename = fn; linecnt = lt[i].lang_id; - - tab = add_string(str, lang_strings[j].process, lt[i].nlf.m_uCodePage); - tabsset++; - + *ptr = add_string(str, lang_strings[j].process, lt[i].nlf.m_uCodePage); curfilename = 0; + // Indicate that we should check again for any newly referenced language strings + tabsset++; } - - if (cnt < lastcnt) - lst[lang_strings[j].uindex] = tab; - else - ubuild_langtables.add(&tab, sizeof(int)); } - - cnt++; } } } + } - lst = (int *)((char *)ubuild_langtables.get() + oldlen); - - // optimize langstrings and check for recursion + // Optimize langstrings and check for recursion + for (i = num_lang_tables; i--; ) + { TinyGrowBuf rec; - for (j = 0; j < ubuild_langstring_num; j++) { - while (lst[j] < 0) { - for (int k = 0; (unsigned int)k < rec.getlen() / sizeof(int); k++) { - if (((int*)rec.get())[k] == lst[j]) { + int *lst = (int *)string_ptrs[i].get(); + for (j = 0; j < ubuild_langstring_num; j++) + { + // Does this string reference another language string directly? + while (lst[j] < 0) + { + // Search through list of language string references + for (l = 0; (unsigned int)l < rec.getlen() / sizeof(int); l++) + { + if (((int*)rec.get())[l] == lst[j]) + { + // We have the index of a recursive language string; now find the name const char *name = "(unnamed)"; - for (k = 0; k < l; k++) { - if (lang_strings[k].uindex == j) { - name = build_langstrings.offset2name(lang_strings[k].name); - } - } + for (l = 0; l < ubuild_langstring_num; l++) + if (lang_strings[l].uindex == j) + name = build_langstrings.offset2name(lang_strings[l].name); ERROR_MSG("Error: LangString %s is recursive!\n", name); + delete [] string_ptrs; return PS_ERROR; } } + // Add this reference to the list rec.add(&lst[j], sizeof(int)); + // and dereference it lst[j] = lst[-lst[j] - 1]; } rec.resize(0); } } + // Add language tables into their datablock + for (i = num_lang_tables; i--; ) + { + ubuild_langtables.add(<[i].lang_id, sizeof(LANGID)); + ubuild_langtables.add(<[i].dlg_offset, sizeof(int)); + int rtl = lt[i].nlf.m_bRTL ? 1 : 0; + ubuild_langtables.add(&rtl, sizeof(int)); + ubuild_langtables.add(string_ptrs[i].get(), string_ptrs[i].getlen()); + string_ptrs[i].resize(0); + } + build_uninst.blocks[NB_LANGTABLES].num = num_lang_tables; build_uninst.langtable_size = ubuild_langtables.getlen() / num_lang_tables; set_uninstall_mode(0); #endif - + SCRIPT_MSG("Done!\n"); + delete [] string_ptrs; return PS_OK; } @@ -809,7 +840,7 @@ LanguageTable * CEXEBuild::LoadLangFile(char *filename) { // skip virtual strings if (!NLFStrings[i].szDefault) continue; - + // Fill in for missing strings // 0 will mean default will be used from NLFStrings switch (i) { @@ -914,4 +945,4 @@ void CEXEBuild::DeleteLangTable(LanguageTable *table) { if (table->nlf.m_szStrings[i]) free(table->nlf.m_szStrings[i]); } -} \ No newline at end of file +} diff --git a/Source/lang.h b/Source/lang.h index 7ea5bc8a..db5d4394 100644 --- a/Source/lang.h +++ b/Source/lang.h @@ -76,7 +76,7 @@ class LangStringList : public SortedStringListND const char *pos2name(int pos) { struct langstring *data=(struct langstring *)gr.get(); - + if ((unsigned int)pos > (gr.getlen() / sizeof(struct langstring))) return 0; @@ -167,9 +167,9 @@ class StringsArray resize(idx+1); int old = ((int*)offsets.get())[idx]; - + ((int*)offsets.get())[idx] = strings.add(str, strlen(str) + 1); - + return old; } @@ -300,8 +300,6 @@ struct LanguageTable { int dlg_offset; - GrowBuf *strlist; - StringsArray *lang_strings; NLF nlf; diff --git a/Source/strlist.h b/Source/strlist.h index f663e423..478835d5 100644 --- a/Source/strlist.h +++ b/Source/strlist.h @@ -3,7 +3,7 @@ #include // for gcc -class IGrowBuf +class IGrowBuf { public: virtual int add(const void *data, int len)=0; @@ -34,10 +34,10 @@ class GrowBuf : public IGrowBuf void set_zeroing(int zero) { m_zero=zero; } - int add(const void *data, int len) - { + int add(const void *data, int len) + { if (len<=0) return 0; - resize(m_used+len); + resize(m_used+len); memcpy((char*)m_s+m_used-len,data,len); return m_used-len; } @@ -56,7 +56,7 @@ class GrowBuf : public IGrowBuf { extern FILE *g_output; extern int g_display_errors; - if (g_display_errors) + if (g_display_errors) { fprintf(g_output,"\nack! realloc(%d) failed, trying malloc(%d)!\n",m_alloc,newlen); fflush(g_output); @@ -66,7 +66,7 @@ class GrowBuf : public IGrowBuf if (!n) { extern void quit(); - if (g_display_errors) + if (g_display_errors) { fprintf(g_output,"\nInternal compiler error #12345: GrowBuf realloc/malloc(%d) failed.\n",m_alloc); fflush(g_output); @@ -77,8 +77,9 @@ class GrowBuf : public IGrowBuf free(m_s); } m_s=n; - if (m_zero) memset((char*)m_s+ou,0,m_alloc-ou); } + if (m_zero && m_used > ou) + memset((char*)m_s + ou, 0, m_used - ou); if (!m_used && m_alloc > 2*m_bs) // only free if you resize to 0 and we're > 64k { m_alloc=0; @@ -132,7 +133,7 @@ public: { return offs; } - if (case_sensitive==2 && + if (case_sensitive==2 && strlen(str) < strlen(s+offs) && // check for end of string !strcmp(s+offs+strlen(s+offs)-strlen(str),str)) { @@ -212,7 +213,7 @@ class SortedStringList extern FILE *g_output; extern int g_display_errors; extern void quit(); - if (g_display_errors) + if (g_display_errors) { fprintf(g_output,"\nInternal compiler error #12345: GrowBuf realloc/malloc(%d) failed.\n",strlen(name)+1); fflush(g_output); @@ -250,7 +251,7 @@ class SortedStringList else ll=nextpos+1; nextpos=(ul+ll)/2; } - + return returnbestpos ? nextpos : -1; } @@ -296,7 +297,7 @@ class SortedStringListND // no delete - can be placed in GrowBuf int pos=find(name,-1,case_sensitive,1,&where); if (pos==-1) return alwaysreturnpos ? where : -1; newstruct.name=strings.add(name,strlen(name)+1); - + gr.add(&newstruct,sizeof(T)); T *s=(T*)gr.get(); memmove(s+pos+1,s+pos,gr.getlen()-((pos+1)*sizeof(T))); @@ -345,7 +346,7 @@ class SortedStringListND // no delete - can be placed in GrowBuf else ll=nextpos+1; nextpos=(ul+ll)/2; } - + return returnbestpos ? nextpos : -1; } @@ -388,7 +389,7 @@ class DefineList : public SortedStringList extern FILE *g_output; extern int g_display_errors; extern void quit(); - if (g_display_errors) + if (g_display_errors) { fprintf(g_output,"\nInternal compiler error #12345: GrowBuf realloc/malloc(%d) failed.\n",strlen(value)+1); fflush(g_output);