Update ooo320-m1
[ooovba.git] / shell / source / tools / lngconvex / lngconvex.cxx
blobe5fa02155f172ec1307b529a2aed103185ccb6da
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: lngconvex.cxx,v $
10 * $Revision: 1.18 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_shell.hxx"
34 #if OSL_DEBUG_LEVEL == 0
35 #ifndef NDEBUG
36 #define NDEBUG
37 #endif
38 #endif
40 #include <tools/presys.h>
41 #if defined _MSC_VER
42 #pragma warning(push, 1)
43 #endif
44 #include <windows.h>
45 #if defined _MSC_VER
46 #pragma warning(pop)
47 #endif
48 #include <tools/postsys.h>
50 #define VCL_NEED_BASETSD
52 #include "cmdline.hxx"
54 #include "osl/thread.h"
55 #include "osl/process.h"
56 #include "osl/file.hxx"
58 #include "tools/config.hxx"
59 #include "i18npool/mslangid.hxx"
61 #include <iostream>
62 #include <fstream>
63 #include <assert.h>
64 #include <map>
65 #include <sstream>
66 #include <iterator>
67 #include <algorithm>
69 namespace /* private */
72 using rtl::OUString;
73 using rtl::OString;
75 //###########################################
76 void ShowUsage()
78 std::cout << "Usage: -ulf ulf_file -rc rc_output_file -rct rc_template_file -rch rch_file -rcf rcf_file" << std::endl;
79 std::cout << "-ulf Name of the ulf file" << std::endl;
80 std::cout << "-rc Name of the resulting resource file" << std::endl;
81 std::cout << "-rct Name of the resource template file" << std::endl;
82 std::cout << "-rch Name of the resource file header" << std::endl;
83 std::cout << "-rcf Name of the resource file footer" << std::endl;
86 //###########################################
87 inline OUString OStringToOUString(const OString& str)
88 { return rtl::OStringToOUString(str, osl_getThreadTextEncoding()); }
90 //###########################################
91 inline OString OUStringToOString(const OUString& str)
92 { return rtl::OUStringToOString(str, osl_getThreadTextEncoding()); }
94 //###########################################
95 /** Get the directory where the module
96 is located as system directory, the
97 returned directory has a trailing '\' */
98 OUString get_module_path()
100 OUString cwd_url;
101 OUString module_path;
102 if (osl_Process_E_None == osl_getProcessWorkingDir(&cwd_url.pData))
103 osl::FileBase::getSystemPathFromFileURL(cwd_url, module_path);
105 return module_path;
108 //###########################################
109 /** Make the absolute directory of a base and
110 a relative directory, if the relative
111 directory is absolute the the relative
112 directory will be returned unchanged.
113 Base and relative directory should be
114 system paths the returned directory is
115 a system path too */
116 OUString get_absolute_path(
117 const OUString& BaseDir, const OUString& RelDir)
119 OUString base_url;
120 OUString rel_url;
122 osl::FileBase::getFileURLFromSystemPath(BaseDir, base_url);
123 osl::FileBase::getFileURLFromSystemPath(RelDir, rel_url);
125 OUString abs_url;
126 osl::FileBase::getAbsoluteFileURL(base_url, rel_url, abs_url);
128 OUString abs_sys_path;
129 osl::FileBase::getSystemPathFromFileURL(abs_url, abs_sys_path);
131 return abs_sys_path;
134 //###########################################
135 OString get_absolute_file_path(const std::string& file_name)
137 OUString fp = get_absolute_path(
138 get_module_path(), OStringToOUString(file_name.c_str()));
139 return OUStringToOString(fp);
142 //###########################################
143 /** A helper class, enables stream exceptions
144 on construction, restors the old exception
145 state on destruction */
146 class StreamExceptionsEnabler
148 public:
149 explicit StreamExceptionsEnabler(
150 std::ios& iostrm,
151 std::ios::iostate NewIos = std::ios::failbit | std::ios::badbit) :
152 m_IoStrm(iostrm),
153 m_OldIos(m_IoStrm.exceptions())
155 m_IoStrm.exceptions(NewIos);
158 ~StreamExceptionsEnabler()
160 m_IoStrm.exceptions(m_OldIos);
162 private:
163 std::ios& m_IoStrm;
164 std::ios::iostate m_OldIos;
167 typedef std::vector<std::string> string_container_t;
169 //###########################################
170 class iso_lang_identifier
172 public:
173 iso_lang_identifier() {};
175 iso_lang_identifier(const OString& str) :
176 lang_(str)
177 { init(); }
179 iso_lang_identifier(const std::string& str) :
180 lang_(str.c_str())
181 { init(); }
183 OString language() const
184 { return lang_; }
186 OString country() const
187 { return country_; }
189 OString make_OString() const
190 { return lang_ + "-" + country_; }
192 std::string make_std_string() const
194 OString tmp(lang_ + "-" + country_);
195 return tmp.getStr();
198 private:
199 void init()
201 sal_Int32 idx = lang_.indexOf("-");
203 if (idx > -1)
205 country_ = lang_.copy(idx + 1);
206 lang_ = lang_.copy(0, idx);
210 private:
211 OString lang_;
212 OString country_;
215 //###########################################
216 /** Convert a OUString to the MS resource
217 file format string e.g.
218 OUString -> L"\x1A00\x2200\x3400" */
219 std::string make_winrc_unicode_string(const OUString& str)
221 std::ostringstream oss;
222 oss << "L\"";
224 size_t length = str.getLength();
225 const sal_Unicode* pchr = str.getStr();
227 for (size_t i = 0; i < length; i++)
228 oss << "\\x" << std::hex << (int)*pchr++;
230 oss << "\"";
231 return oss.str();
234 //###########################################
235 std::string make_winrc_unicode_string(const std::string& str)
237 return make_winrc_unicode_string(
238 OUString::createFromAscii(str.c_str()));
241 //################################################
242 /** A replacement table contains pairs of
243 placeholders and the appropriate substitute */
244 class Substitutor
246 private:
247 typedef std::map<std::string, std::string> replacement_table_t;
248 typedef std::map<std::string, replacement_table_t*> iso_lang_replacement_table_t;
250 public:
251 typedef iso_lang_replacement_table_t::iterator iterator;
252 typedef iso_lang_replacement_table_t::const_iterator const_iterator;
254 iterator begin()
255 { return iso_lang_replacement_table_.begin(); }
257 iterator end()
258 { return iso_lang_replacement_table_.end(); }
260 public:
262 Substitutor() {};
264 ~Substitutor()
266 iso_lang_replacement_table_t::iterator iter_end = iso_lang_replacement_table_.end();
267 iso_lang_replacement_table_t::iterator iter = iso_lang_replacement_table_.begin();
269 for( /* no init */; iter != iter_end; ++iter)
270 delete iter->second;
272 iso_lang_replacement_table_.clear();
275 void set_language(const iso_lang_identifier& iso_lang)
277 active_iso_lang_ = iso_lang;
280 // If Text is a placeholder substitute it with
281 //its substitute else leave it unchanged
282 void substitute(std::string& Text)
284 replacement_table_t* prt = get_replacement_table(active_iso_lang_.make_std_string());
285 assert(prt);
286 replacement_table_t::iterator iter = prt->find(Text);
287 if (iter != prt->end())
288 Text = iter->second;
291 void add_substitution(
292 const std::string& Placeholder, const std::string& Substitute)
294 replacement_table_t* prt = get_replacement_table(active_iso_lang_.make_std_string());
295 assert(prt);
296 prt->insert(std::make_pair(Placeholder, Substitute));
300 private:
301 // Return the replacement table for the iso lang id
302 // create a new one if not already present
303 replacement_table_t* get_replacement_table(const std::string& iso_lang)
305 iso_lang_replacement_table_t::iterator iter =
306 iso_lang_replacement_table_.find(iso_lang);
308 replacement_table_t* prt = NULL;
310 if (iso_lang_replacement_table_.end() == iter)
312 prt = new replacement_table_t();
313 iso_lang_replacement_table_.insert(std::make_pair(iso_lang, prt));
315 else
317 prt = iter->second;
319 return prt;
322 private:
323 iso_lang_replacement_table_t iso_lang_replacement_table_;
324 iso_lang_identifier active_iso_lang_;
327 //###########################################
328 void add_group_entries(
329 Config& aConfig,
330 const ByteString& GroupName,
331 Substitutor& Substitutor)
333 assert(aConfig.HasGroup(GroupName));
335 aConfig.SetGroup(GroupName);
336 size_t key_count = aConfig.GetKeyCount();
338 for (size_t i = 0; i < key_count; i++)
340 ByteString iso_lang = aConfig.GetKeyName(sal::static_int_cast<USHORT>(i));
341 ByteString key_value_utf8 = aConfig.ReadKey(sal::static_int_cast<USHORT>(i));
343 Substitutor.set_language(iso_lang_identifier(iso_lang));
345 key_value_utf8.EraseLeadingAndTrailingChars('\"');
347 OUString key_value_utf16 =
348 rtl::OStringToOUString(key_value_utf8, RTL_TEXTENCODING_UTF8);
350 Substitutor.add_substitution(
351 GroupName.GetBuffer(), make_winrc_unicode_string(key_value_utf16));
355 //###########################################
356 void read_ulf_file(const std::string& FileName, Substitutor& Substitutor)
358 // work-around for #i32420#
360 // as the Config class is currently not able to deal correctly with
361 // UTF8 files starting with a byte-order-mark we create a copy of the
362 // original file without the byte-order-mark
363 rtl::OUString tmpfile_url;
364 osl_createTempFile(NULL, NULL, &tmpfile_url.pData);
366 rtl::OUString tmpfile_sys;
367 osl::FileBase::getSystemPathFromFileURL(tmpfile_url, tmpfile_sys);
369 std::ifstream in(FileName.c_str());
370 std::ofstream out(OUStringToOString(tmpfile_sys).getStr());
374 StreamExceptionsEnabler sexc_out(out);
375 StreamExceptionsEnabler sexc_in(in);
377 //skip the byte-order-mark 0xEF 0xBB 0xBF, identifying UTF8 files
378 unsigned char BOM[3] = {0xEF, 0xBB, 0xBF};
379 char buff[3];
380 in.read(&buff[0], 3);
382 if (memcmp(buff, BOM, 3) != 0)
383 in.seekg(0);
385 std::string line;
386 while (std::getline(in, line))
387 out << line << std::endl;
389 catch (const std::ios::failure&)
391 if (!in.eof())
392 throw;
395 //Config config(OStringToOUString(FileName.c_str()).getStr());
397 // end work-around for #i32420#
399 Config config(tmpfile_url.getStr());
400 size_t grpcnt = config.GetGroupCount();
401 for (size_t i = 0; i < grpcnt; i++)
402 add_group_entries(config, config.GetGroupName(sal::static_int_cast<USHORT>(i)), Substitutor);
405 //###########################################
406 void read_file(
407 const std::string& fname,
408 string_container_t& string_container)
410 std::ifstream file(fname.c_str());
411 StreamExceptionsEnabler sexc(file);
415 std::string line;
416 while (std::getline(file, line))
417 string_container.push_back(line);
419 catch(const std::ios::failure&)
421 if (!file.eof())
422 throw;
426 //###########################################
427 /** A simple helper function that appens the
428 content of one file to another one */
429 void concatenate_files(std::ostream& os, std::istream& is)
431 StreamExceptionsEnabler os_sexc(os);
432 StreamExceptionsEnabler is_sexc(is);
436 std::string line;
437 while (std::getline(is, line))
438 os << line << std::endl;
440 catch(const std::ios::failure&)
442 if (!is.eof())
443 throw;
447 //###########################################
448 bool is_placeholder(const std::string& str)
450 return ((str.length() > 1) &&
451 ('%' == str[0]) &&
452 ('%' == str[str.length() - 1]));
455 //###########################################
456 void start_language_section(
457 std::ostream_iterator<std::string>& ostream_iter, const iso_lang_identifier& iso_lang)
459 ostream_iter = std::string();
461 std::string lang_section("LANGUAGE ");
463 LanguageType ltype = MsLangId::convertIsoNamesToLanguage(iso_lang.language(), iso_lang.country());
465 char buff[10];
466 int primLangID = PRIMARYLANGID(ltype);
467 int subLangID = SUBLANGID(ltype);
468 // Our resources are normaly not sub language dependant.
469 // Esp. for spanish we don't want to distinguish between trad.
470 // and internatinal sorting ( which leads to two different sub languages )
471 // Setting the sub language to neutral allows us to use one
472 // stringlist for all spanish variants ( see #123126# )
473 if ( ( primLangID == LANG_SPANISH ) &&
474 ( subLangID == SUBLANG_SPANISH ) )
475 subLangID = SUBLANG_NEUTRAL;
477 _itoa(primLangID, buff, 16);
478 lang_section += std::string("0x") + std::string(buff);
480 lang_section += std::string(" , ");
482 _itoa(subLangID, buff, 16);
484 lang_section += std::string("0x") + std::string(buff);
485 ostream_iter = lang_section;
488 //###########################################
489 /** Iterate all languages in the substitutor,
490 replace the all placeholder and append the
491 result to the output file */
492 void inflate_rc_template_to_file(
493 std::ostream& os, const string_container_t& rctmpl, Substitutor& substitutor)
495 StreamExceptionsEnabler sexc(os);
497 Substitutor::const_iterator iter = substitutor.begin();
498 Substitutor::const_iterator iter_end = substitutor.end();
500 std::ostream_iterator<std::string> oi(os, "\n");
502 for ( /**/ ;iter != iter_end; ++iter)
504 substitutor.set_language(iso_lang_identifier(iter->first));
506 string_container_t::const_iterator rct_iter = rctmpl.begin();
507 string_container_t::const_iterator rct_iter_end = rctmpl.end();
509 if (!rctmpl.empty())
510 start_language_section(oi, iter->first);
512 for ( /**/ ;rct_iter != rct_iter_end; ++rct_iter)
514 std::istringstream iss(*rct_iter);
515 std::string line;
517 while (iss)
519 std::string token;
520 iss >> token;
521 substitutor.substitute(token);
523 // #110274# HACK for partially merged
524 // *.lng files where some strings have
525 // a particular language that others
526 // don't have in order to keep the
527 // build
528 if (is_placeholder(token))
529 token = make_winrc_unicode_string(token);
531 line += token;
532 line += " ";
534 oi = line;
539 } // namespace /* private */
541 //####################################################
542 /* MAIN
543 The file names provided via command line should be
544 absolute or relative to the directory of this module.
546 Algo:
547 1. read the ulf file and initialize the substitutor
548 2. read the resource template file
549 3. create the output file and append the header
550 4. inflate the resource template to the output file
551 for every language using the substitutor
552 5. append the footer
554 #define MAKE_ABSOLUTE(s) (get_absolute_file_path((s)).getStr())
555 #define ULF_FILE(c) MAKE_ABSOLUTE((c).get_arg("-ulf"))
556 #define RC_TEMPLATE(c) MAKE_ABSOLUTE((c).get_arg("-rct"))
557 #define RC_FILE(c) MAKE_ABSOLUTE((c).get_arg("-rc"))
558 #define RC_HEADER(c) MAKE_ABSOLUTE((c).get_arg("-rch"))
559 #define RC_FOOTER(c) MAKE_ABSOLUTE((c).get_arg("-rcf"))
561 int main(int argc, char* argv[])
565 CommandLine cmdline(argc, argv);
567 Substitutor substitutor;
568 read_ulf_file(ULF_FILE(cmdline), substitutor);
570 string_container_t rc_tmpl;
571 read_file(RC_TEMPLATE(cmdline), rc_tmpl);
573 std::ofstream rc_file(RC_FILE(cmdline));
574 std::ifstream in_header(RC_HEADER(cmdline));
575 concatenate_files(rc_file, in_header);
577 inflate_rc_template_to_file(rc_file, rc_tmpl, substitutor);
579 std::ifstream in_footer(RC_FOOTER(cmdline));
580 concatenate_files(rc_file, in_footer);
582 catch(const std::ios::failure& ex)
584 std::cout << ex.what() << std::endl;
586 catch(std::exception& ex)
588 std::cout << ex.what() << std::endl;
589 ShowUsage();
591 catch(...)
593 std::cout << "Unexpected error..." << std::endl;
595 return 0;