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
This commit is contained in:
eccles 2004-01-20 23:20:44 +00:00
parent 6dd9291512
commit 31e10cd7d3
3 changed files with 161 additions and 131 deletions

View file

@ -409,196 +409,227 @@ int CEXEBuild::GenerateLangTables() {
} }
} }
// Add language tables into their datablock // Add all installer language strings
int j, l, cnt, tabsset; int j, l, tabsset;
struct langstring* lang_strings; struct langstring* lang_strings;
TinyGrowBuf *string_ptrs = new TinyGrowBuf[num_lang_tables];
i = num_lang_tables; tabsset = 1;
while (i--) { while (tabsset)
build_langtables.add(&lt[i].lang_id, sizeof(LANGID)); {
build_langtables.add(&lt[i].dlg_offset, sizeof(int)); tabsset = 0;
for (i = num_lang_tables; i--; )
{ {
int rtl = lt[i].nlf.m_bRTL ? 1 : 0; // Fill in default values for all used language strings that we can
build_langtables.add(&rtl, sizeof(int)); FillLanguageTable(&lt[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; // For all current language strings
unsigned int oldlen = build_langtables.getlen(); lang_strings = build_langstrings.sort_index(&l);
for (j = 0; j < l; j++)
cnt = 0; {
tabsset = 1; // Is this language string used (in the installer)?
if (lang_strings[j].index >= 0)
// write langstrings {
while (tabsset) { // For each language
FillLanguageTable(&lt[i]); for (i = num_lang_tables; i--; )
{
int lastcnt = cnt; // Get the current string pointer
cnt = 0; int *ptr = (int *)string_ptrs[i].get() + lang_strings[j].index;
tabsset = 0; // Not already set?
if (!*ptr)
lang_strings = build_langstrings.sort_index(&l); {
// Get the language string and its name
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]) {
const char *str = lt[i].lang_strings->get(lang_strings[j].sn); 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); 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] != '^') if (lsn[0] != '^')
warning("LangString \"%s\" is not set in language table of language %d", lsn, lt[i].lang_id); 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]; char fn[1024];
sprintf(fn, "LangString %s", lsn); sprintf(fn, "LangString %s", lsn);
curfilename = fn; curfilename = fn;
linecnt = lt[i].lang_id; linecnt = lt[i].lang_id;
*ptr = add_string(str, lang_strings[j].process, lt[i].nlf.m_uCodePage);
tab = add_string(str, lang_strings[j].process, lt[i].nlf.m_uCodePage);
tabsset++;
curfilename = 0; 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
for (i = num_lang_tables; i--; )
// optimize langstrings and check for recursion {
TinyGrowBuf rec; TinyGrowBuf rec;
for (j = 0; j < build_langstring_num; j++) { int *lst = (int *)string_ptrs[i].get();
while (lst[j] < 0) { for (j = 0; j < build_langstring_num; j++)
for (int k = 0; (unsigned int)k < rec.getlen() / sizeof(int); k++) { {
if (((int*)rec.get())[k] == lst[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)"; const char *name = "(unnamed)";
for (k = 0; k < l; k++) { for (l = 0; l < build_langstring_num; l++)
if (lang_strings[k].index == j) { if (lang_strings[l].index == j)
name = build_langstrings.offset2name(lang_strings[k].name); name = build_langstrings.offset2name(lang_strings[l].name);
}
}
ERROR_MSG("Error: LangString %s is recursive!\n", name); ERROR_MSG("Error: LangString %s is recursive!\n", name);
delete [] string_ptrs;
return PS_ERROR; return PS_ERROR;
} }
} }
// Add this reference to the list
rec.add(&lst[j], sizeof(int)); rec.add(&lst[j], sizeof(int));
// and dereference it
lst[j] = lst[-lst[j] - 1]; lst[j] = lst[-lst[j] - 1];
} }
rec.resize(0); rec.resize(0);
} }
} }
// Add language tables into their datablock
for (i = num_lang_tables; i--; )
{
build_langtables.add(&lt[i].lang_id, sizeof(LANGID));
build_langtables.add(&lt[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.blocks[NB_LANGTABLES].num = num_lang_tables;
build_header.langtable_size = build_langtables.getlen() / num_lang_tables; build_header.langtable_size = build_langtables.getlen() / num_lang_tables;
#ifdef NSIS_CONFIG_UNINSTALL_SUPPORT #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
// Now do it all again, this time for the uninstaller
set_uninstall_mode(1); set_uninstall_mode(1);
i = num_lang_tables; tabsset = 1;
while (i--) { while (tabsset)
ubuild_langtables.add(&lt[i].lang_id, sizeof(LANGID)); {
ubuild_langtables.add(&lt[i].dlg_offset, sizeof(int)); tabsset = 0;
for (i = num_lang_tables; i--; )
{ {
int rtl = lt[i].nlf.m_bRTL ? 1 : 0; // Fill in default values for all used language strings that we can
ubuild_langtables.add(&rtl, sizeof(int)); FillLanguageTable(&lt[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; // For all current language strings
unsigned int oldlen = ubuild_langtables.getlen(); lang_strings = build_langstrings.sort_uindex(&l);
for (j = 0; j < l; j++)
cnt = 0; {
tabsset = 1; // Is this language string used (in the uninstaller)?
if (lang_strings[j].uindex >= 0)
// write langstrings {
while (tabsset) { // For each language
FillLanguageTable(&lt[i]); for (i = num_lang_tables; i--; )
{
int lastcnt = cnt; // Get the current string pointer
cnt = 0; int *ptr = (int *)string_ptrs[i].get() + lang_strings[j].uindex;
tabsset = 0; // Not already set?
if (!*ptr)
lang_strings = build_langstrings.sort_uindex(&l); {
// Get the language string and its name
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]) {
const char *str = lt[i].lang_strings->get(lang_strings[j].sn); 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); 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] != '^') if (lsn[0] != '^')
warning("LangString \"%s\" is not set in language table of language %d", lsn, lt[i].lang_id); 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]; char fn[1024];
sprintf(fn, "LangString %s", lsn); sprintf(fn, "LangString %s", lsn);
curfilename = fn; curfilename = fn;
linecnt = lt[i].lang_id; linecnt = lt[i].lang_id;
*ptr = add_string(str, lang_strings[j].process, lt[i].nlf.m_uCodePage);
tab = add_string(str, lang_strings[j].process, lt[i].nlf.m_uCodePage);
tabsset++;
curfilename = 0; 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
for (i = num_lang_tables; i--; )
// optimize langstrings and check for recursion {
TinyGrowBuf rec; TinyGrowBuf rec;
for (j = 0; j < ubuild_langstring_num; j++) { int *lst = (int *)string_ptrs[i].get();
while (lst[j] < 0) { for (j = 0; j < ubuild_langstring_num; j++)
for (int k = 0; (unsigned int)k < rec.getlen() / sizeof(int); k++) { {
if (((int*)rec.get())[k] == lst[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)"; const char *name = "(unnamed)";
for (k = 0; k < l; k++) { for (l = 0; l < ubuild_langstring_num; l++)
if (lang_strings[k].uindex == j) { if (lang_strings[l].uindex == j)
name = build_langstrings.offset2name(lang_strings[k].name); name = build_langstrings.offset2name(lang_strings[l].name);
}
}
ERROR_MSG("Error: LangString %s is recursive!\n", name); ERROR_MSG("Error: LangString %s is recursive!\n", name);
delete [] string_ptrs;
return PS_ERROR; return PS_ERROR;
} }
} }
// Add this reference to the list
rec.add(&lst[j], sizeof(int)); rec.add(&lst[j], sizeof(int));
// and dereference it
lst[j] = lst[-lst[j] - 1]; lst[j] = lst[-lst[j] - 1];
} }
rec.resize(0); rec.resize(0);
} }
} }
// Add language tables into their datablock
for (i = num_lang_tables; i--; )
{
ubuild_langtables.add(&lt[i].lang_id, sizeof(LANGID));
ubuild_langtables.add(&lt[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.blocks[NB_LANGTABLES].num = num_lang_tables;
build_uninst.langtable_size = ubuild_langtables.getlen() / num_lang_tables; build_uninst.langtable_size = ubuild_langtables.getlen() / num_lang_tables;
set_uninstall_mode(0); set_uninstall_mode(0);
#endif #endif
SCRIPT_MSG("Done!\n"); SCRIPT_MSG("Done!\n");
delete [] string_ptrs;
return PS_OK; return PS_OK;
} }
@ -809,7 +840,7 @@ LanguageTable * CEXEBuild::LoadLangFile(char *filename) {
// skip virtual strings // skip virtual strings
if (!NLFStrings[i].szDefault) if (!NLFStrings[i].szDefault)
continue; continue;
// Fill in for missing strings // Fill in for missing strings
// 0 will mean default will be used from NLFStrings // 0 will mean default will be used from NLFStrings
switch (i) { switch (i) {
@ -914,4 +945,4 @@ void CEXEBuild::DeleteLangTable(LanguageTable *table) {
if (table->nlf.m_szStrings[i]) if (table->nlf.m_szStrings[i])
free(table->nlf.m_szStrings[i]); free(table->nlf.m_szStrings[i]);
} }
} }

View file

@ -76,7 +76,7 @@ class LangStringList : public SortedStringListND<struct langstring>
const char *pos2name(int pos) const char *pos2name(int pos)
{ {
struct langstring *data=(struct langstring *)gr.get(); struct langstring *data=(struct langstring *)gr.get();
if ((unsigned int)pos > (gr.getlen() / sizeof(struct langstring))) if ((unsigned int)pos > (gr.getlen() / sizeof(struct langstring)))
return 0; return 0;
@ -167,9 +167,9 @@ class StringsArray
resize(idx+1); resize(idx+1);
int old = ((int*)offsets.get())[idx]; int old = ((int*)offsets.get())[idx];
((int*)offsets.get())[idx] = strings.add(str, strlen(str) + 1); ((int*)offsets.get())[idx] = strings.add(str, strlen(str) + 1);
return old; return old;
} }
@ -300,8 +300,6 @@ struct LanguageTable {
int dlg_offset; int dlg_offset;
GrowBuf *strlist;
StringsArray *lang_strings; StringsArray *lang_strings;
NLF nlf; NLF nlf;

View file

@ -3,7 +3,7 @@
#include <stdlib.h> // for gcc #include <stdlib.h> // for gcc
class IGrowBuf class IGrowBuf
{ {
public: public:
virtual int add(const void *data, int len)=0; 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; } 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; if (len<=0) return 0;
resize(m_used+len); resize(m_used+len);
memcpy((char*)m_s+m_used-len,data,len); memcpy((char*)m_s+m_used-len,data,len);
return m_used-len; return m_used-len;
} }
@ -56,7 +56,7 @@ class GrowBuf : public IGrowBuf
{ {
extern FILE *g_output; extern FILE *g_output;
extern int g_display_errors; 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); fprintf(g_output,"\nack! realloc(%d) failed, trying malloc(%d)!\n",m_alloc,newlen);
fflush(g_output); fflush(g_output);
@ -66,7 +66,7 @@ class GrowBuf : public IGrowBuf
if (!n) if (!n)
{ {
extern void quit(); 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); fprintf(g_output,"\nInternal compiler error #12345: GrowBuf realloc/malloc(%d) failed.\n",m_alloc);
fflush(g_output); fflush(g_output);
@ -77,8 +77,9 @@ class GrowBuf : public IGrowBuf
free(m_s); free(m_s);
} }
m_s=n; 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 if (!m_used && m_alloc > 2*m_bs) // only free if you resize to 0 and we're > 64k
{ {
m_alloc=0; m_alloc=0;
@ -132,7 +133,7 @@ public:
{ {
return offs; return offs;
} }
if (case_sensitive==2 && if (case_sensitive==2 &&
strlen(str) < strlen(s+offs) && // check for end of string strlen(str) < strlen(s+offs) && // check for end of string
!strcmp(s+offs+strlen(s+offs)-strlen(str),str)) !strcmp(s+offs+strlen(s+offs)-strlen(str),str))
{ {
@ -212,7 +213,7 @@ class SortedStringList
extern FILE *g_output; extern FILE *g_output;
extern int g_display_errors; extern int g_display_errors;
extern void quit(); 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); fprintf(g_output,"\nInternal compiler error #12345: GrowBuf realloc/malloc(%d) failed.\n",strlen(name)+1);
fflush(g_output); fflush(g_output);
@ -250,7 +251,7 @@ class SortedStringList
else ll=nextpos+1; else ll=nextpos+1;
nextpos=(ul+ll)/2; nextpos=(ul+ll)/2;
} }
return returnbestpos ? nextpos : -1; 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); int pos=find(name,-1,case_sensitive,1,&where);
if (pos==-1) return alwaysreturnpos ? where : -1; if (pos==-1) return alwaysreturnpos ? where : -1;
newstruct.name=strings.add(name,strlen(name)+1); newstruct.name=strings.add(name,strlen(name)+1);
gr.add(&newstruct,sizeof(T)); gr.add(&newstruct,sizeof(T));
T *s=(T*)gr.get(); T *s=(T*)gr.get();
memmove(s+pos+1,s+pos,gr.getlen()-((pos+1)*sizeof(T))); 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; else ll=nextpos+1;
nextpos=(ul+ll)/2; nextpos=(ul+ll)/2;
} }
return returnbestpos ? nextpos : -1; return returnbestpos ? nextpos : -1;
} }
@ -388,7 +389,7 @@ class DefineList : public SortedStringList<struct define>
extern FILE *g_output; extern FILE *g_output;
extern int g_display_errors; extern int g_display_errors;
extern void quit(); 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); fprintf(g_output,"\nInternal compiler error #12345: GrowBuf realloc/malloc(%d) failed.\n",strlen(value)+1);
fflush(g_output); fflush(g_output);