int CEXEBuild::GenerateLangTables() { int i; LanguageTable *lt = (LanguageTable*)lang_tables.get(); SCRIPT_MSG("Generating language tables... "); if ( #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT ubuild_langstring_num > MAX_CODED || #endif build_langstring_num > MAX_CODED ) { ERROR_MSG("\nError: too many LangStrings. Maximum allowed is %u.\n", MAX_CODED); return PS_ERROR; } // If we have no tables (user didn't set any string and didn't load any NLF) create the default one if (!lang_tables.getlen()) { LANGID lang = NSIS_DEFAULT_LANG; LanguageTable *table = GetLangTable(lang); if (!table) return PS_ERROR; lt = (LanguageTable*)lang_tables.get(); } // Apply default font if (*build_font) { try { init_res_editor(); #define ADD_FONT(id) { \ BYTE* dlg = res_editor->GetResource(RT_DIALOG, MAKEINTRESOURCE(id), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)); \ if (dlg) { \ CDialogTemplate td(dlg); \ free(dlg); \ td.SetFont(build_font, build_font_size); \ DWORD dwSize; \ dlg = td.Save(dwSize); \ res_editor->UpdateResource(RT_DIALOG, MAKEINTRESOURCE(id), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), dlg, dwSize); \ free(dlg); \ } \ } #ifdef NSIS_CONFIG_LICENSEPAGE ADD_FONT(IDD_LICENSE); ADD_FONT(IDD_LICENSE_FSRB); ADD_FONT(IDD_LICENSE_FSCB); #endif ADD_FONT(IDD_DIR); #ifdef NSIS_CONFIG_COMPONENTPAGE ADD_FONT(IDD_SELCOM); #endif ADD_FONT(IDD_INST); ADD_FONT(IDD_INSTFILES); #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT ADD_FONT(IDD_UNINST); #endif #ifdef NSIS_CONFIG_CRC_SUPPORT ADD_FONT(IDD_VERIFY); #endif #undef ADD_FONT } catch (exception& err) { ERROR_MSG("\nError while applying font: %s\n", err.what()); return PS_ERROR; } } // Fill tables with defaults (if needed) and with instruction strings // Create language specific resources (currently only dialogs with different fonts) int num_lang_tables = lang_tables.getlen() / sizeof(LanguageTable); // if there is one string table then there is no need for two sets of dialogs int cur_offset = num_lang_tables == 1 ? 0 : 100; for (i = 0; i < num_lang_tables; i++) { if ((lt[i].nlf.m_szFont && !*build_font) || lt[i].nlf.m_bRTL) { lt[i].dlg_offset = cur_offset; char *font = lt[i].nlf.m_szFont; if (*build_font) font = 0; try { init_res_editor(); #define ADD_FONT(id) { \ BYTE* dlg = res_editor->GetResource(RT_DIALOG, MAKEINTRESOURCE(id), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)); \ if (dlg) { \ CDialogTemplate td(dlg,lt[i].nlf.m_uCodePage); \ free(dlg); \ if (font) td.SetFont(font, lt[i].nlf.m_iFontSize); \ if (lt[i].nlf.m_bRTL) td.ConvertToRTL(); \ DWORD dwSize; \ dlg = td.Save(dwSize); \ res_editor->UpdateResource(RT_DIALOG, MAKEINTRESOURCE(id+cur_offset), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), dlg, dwSize); \ free(dlg); \ } \ } #ifdef NSIS_CONFIG_LICENSEPAGE ADD_FONT(IDD_LICENSE); ADD_FONT(IDD_LICENSE_FSRB); ADD_FONT(IDD_LICENSE_FSCB); #endif ADD_FONT(IDD_DIR); #ifdef NSIS_CONFIG_COMPONENTPAGE ADD_FONT(IDD_SELCOM); #endif ADD_FONT(IDD_INST); ADD_FONT(IDD_INSTFILES); #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT ADD_FONT(IDD_UNINST); #endif #ifdef NSIS_CONFIG_CRC_SUPPORT ADD_FONT(IDD_VERIFY); #endif #undef ADD_FONT } catch (exception& err) { ERROR_MSG("\nError while applying NLF font/RTL: %s\n", err.what()); return PS_ERROR; } cur_offset += 100; } } // Add all installer language strings int j, l, tabsset; struct langstring* lang_strings; TinyGrowBuf *string_ptrs = new TinyGrowBuf[num_lang_tables]; tabsset = 1; while (tabsset) { tabsset = 0; for (i = num_lang_tables; i--; ) { // 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)); } // 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); const char *lsn = build_langstrings.offset2name(lang_strings[j].name); 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 { // Add the language string to the string data block char fn[1024]; sprintf(fn, "LangString %s", lsn); curfilename = fn; linecnt = lt[i].lang_id; *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++; } } } } } } // Optimize langstrings and check for recursion for (i = num_lang_tables; i--; ) { TinyGrowBuf rec; 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 (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); tabsset = 1; while (tabsset) { tabsset = 0; for (i = num_lang_tables; i--; ) { // 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)); } // 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); const char *lsn = build_langstrings.offset2name(lang_strings[j].name); 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 { // Add the language string to the string data block char fn[1024]; sprintf(fn, "LangString %s", lsn); curfilename = fn; linecnt = lt[i].lang_id; *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++; } } } } } } // Optimize langstrings and check for recursion for (i = num_lang_tables; i--; ) { TinyGrowBuf rec; 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 (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; }
int CEXEBuild::WriteStringTables() { int i; SCRIPT_MSG("Generating language tables... "); // If we have no tables (user didn't set any string and didn't load any NLF) create the default one if (!string_tables.size()) { LANGID lang = 1033; StringTable *table = GetTable(lang); if (!table) return PS_ERROR; } // Fill tables with defaults (if needed) and with instruction strings int st_num = string_tables.size(); for (i = 0; i < st_num; i++) FillDefaultsIfNeeded(string_tables[i]); // check for missing LangStrings int userstrings_num = build_userlangstrings.getnum(); for (i = 0; i < userstrings_num; i++) { int counter = 0; for (int j = 0; j < st_num; j++) { counter += !((int*)string_tables[j]->user_strings.get())[i]; } if (counter) { int offset=build_userlangstrings.idx2pos(i); if (offset<0) continue; warning("LangString \"%s\" is not present in all language tables!", build_userlangstrings.get()+offset); } } int userustrings_num = ubuild_userlangstrings.getlen(); for (i = 0; i < userustrings_num; i++) { int counter = 0; for (int j = 0; j < st_num; j++) { counter += !((int*)string_tables[j]->user_ustrings.get())[i]; } if (counter) { int offset=ubuild_userlangstrings.idx2pos(i); if (offset<0) continue; warning("LangString \"%s\" is not present in all language tables!", ubuild_userlangstrings.get()+offset); } } // Add string tables into their datablock for (i = 0; i < st_num; i++) { build_langtables.add(&string_tables[i]->lang_id, sizeof(LANGID)); build_langtables.add(&string_tables[i]->common, sizeof(common_strings)); build_langtables.add(&string_tables[i]->installer, sizeof(installer_strings)); if (build_userlangstrings.getnum()) build_langtables.add(string_tables[i]->user_strings.get(), string_tables[i]->user_strings.getlen()); } build_header.common.language_tables_num = st_num; build_header.common.language_table_size = build_langtables.getlen() / st_num; for (i = 0; i < st_num; i++) { ubuild_langtables.add(&string_tables[i]->lang_id, sizeof(LANGID)); ubuild_langtables.add(&string_tables[i]->ucommon, sizeof(common_strings)); ubuild_langtables.add(&string_tables[i]->uninstall, sizeof(uninstall_strings)); if (ubuild_userlangstrings.getnum()) ubuild_langtables.add(string_tables[i]->user_ustrings.get(), string_tables[i]->user_ustrings.getlen()); } build_uninst.common.language_tables_num = st_num; build_uninst.common.language_table_size = ubuild_langtables.getlen() / st_num; SCRIPT_MSG("Done!\n"); return PS_OK; }
int CEXEBuild::GenerateLangTables() { int i; LanguageTable *lt = (LanguageTable*)lang_tables.get(); SCRIPT_MSG("Generating language tables... "); if ( #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT ubuild_langstring_num > MAX_CODED || #endif build_langstring_num > MAX_CODED ) { ERROR_MSG("\nError: too many LangStrings. Maximum allowed is %u.\n", MAX_CODED); return PS_ERROR; } // If we have no tables (user didn't set any string and didn't load any NLF) create the default one if (!lang_tables.getlen()) { LANGID lang = NSIS_DEFAULT_LANG; LanguageTable *table = GetLangTable(lang); if (!table) return PS_ERROR; lt = (LanguageTable*)lang_tables.get(); } // Apply default font if (*build_font) { try { init_res_editor(); #define ADD_FONT(id) { \ BYTE* dlg = res_editor->GetResource(RT_DIALOG, MAKEINTRESOURCE(id), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)); \ if (dlg) { \ CDialogTemplate td(dlg); \ free(dlg); \ td.SetFont(build_font, build_font_size); \ DWORD dwSize; \ dlg = td.Save(dwSize); \ res_editor->UpdateResource(RT_DIALOG, MAKEINTRESOURCE(id), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), dlg, dwSize); \ free(dlg); \ } \ } #ifdef NSIS_CONFIG_LICENSEPAGE ADD_FONT(IDD_LICENSE); ADD_FONT(IDD_LICENSE_FSRB); ADD_FONT(IDD_LICENSE_FSCB); #endif ADD_FONT(IDD_DIR); #ifdef NSIS_CONFIG_COMPONENTPAGE ADD_FONT(IDD_SELCOM); #endif ADD_FONT(IDD_INST); ADD_FONT(IDD_INSTFILES); #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT ADD_FONT(IDD_UNINST); #endif #ifdef NSIS_CONFIG_CRC_SUPPORT ADD_FONT(IDD_VERIFY); #endif #undef ADD_FONT } catch (exception& err) { ERROR_MSG("\nError while applying font: %s\n", err.what()); return PS_ERROR; } } // Fill tables with defaults (if needed) and with instruction strings // Create language specific resources (currently only dialogs with different fonts) int num_lang_tables = lang_tables.getlen() / sizeof(LanguageTable); // if there is one string table then there is no need for two sets of dialogs int cur_offset = num_lang_tables == 1 ? 0 : 100; for (i = 0; i < num_lang_tables; i++) { if ((lt[i].nlf.m_szFont && !*build_font) || lt[i].nlf.m_bRTL) { lt[i].dlg_offset = cur_offset; char *font = lt[i].nlf.m_szFont; if (*build_font) font = 0; try { init_res_editor(); #define ADD_FONT(id) { \ BYTE* dlg = res_editor->GetResource(RT_DIALOG, MAKEINTRESOURCE(id), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)); \ if (dlg) { \ CDialogTemplate td(dlg,lt[i].nlf.m_uCodePage); \ free(dlg); \ if (font) td.SetFont(font, lt[i].nlf.m_iFontSize); \ if (lt[i].nlf.m_bRTL) td.ConvertToRTL(); \ DWORD dwSize; \ dlg = td.Save(dwSize); \ res_editor->UpdateResource(RT_DIALOG, MAKEINTRESOURCE(id+cur_offset), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), dlg, dwSize); \ free(dlg); \ } \ } #ifdef NSIS_CONFIG_LICENSEPAGE ADD_FONT(IDD_LICENSE); ADD_FONT(IDD_LICENSE_FSRB); ADD_FONT(IDD_LICENSE_FSCB); #endif ADD_FONT(IDD_DIR); #ifdef NSIS_CONFIG_COMPONENTPAGE ADD_FONT(IDD_SELCOM); #endif ADD_FONT(IDD_INST); ADD_FONT(IDD_INSTFILES); #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT ADD_FONT(IDD_UNINST); #endif #ifdef NSIS_CONFIG_CRC_SUPPORT ADD_FONT(IDD_VERIFY); #endif #undef ADD_FONT } catch (exception& err) { ERROR_MSG("\nError while applying NLF font/RTL: %s\n", err.what()); return PS_ERROR; } cur_offset += 100; } } // Add language tables into their datablock int j, l, cnt, tabsset; struct langstring* lang_strings; i = num_lang_tables; while (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)); } 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]) { 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 (lsn[0] != '^') warning("LangString \"%s\" is not set in language table of language %d", lsn, lt[i].lang_id); } else { 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++; curfilename = 0; } 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 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]) { const char *name = "(unnamed)"; for (k = 0; k < l; k++) { if (lang_strings[k].index == j) { name = build_langstrings.offset2name(lang_strings[k].name); } } ERROR_MSG("Error: LangString %s is recursive!\n", name); return PS_ERROR; } } rec.add(&lst[j], sizeof(int)); lst[j] = lst[-lst[j] - 1]; } rec.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 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)); { int rtl = lt[i].nlf.m_bRTL ? 1 : 0; ubuild_langtables.add(&rtl, 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]) { 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 (lsn[0] != '^') warning("LangString \"%s\" is not set in language table of language %d", lsn, lt[i].lang_id); } else { 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++; curfilename = 0; } 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 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]) { const char *name = "(unnamed)"; for (k = 0; k < l; k++) { if (lang_strings[k].uindex == j) { name = build_langstrings.offset2name(lang_strings[k].name); } } ERROR_MSG("Error: LangString %s is recursive!\n", name); return PS_ERROR; } } rec.add(&lst[j], sizeof(int)); lst[j] = lst[-lst[j] - 1]; } rec.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"); return PS_OK; }