1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: lngconvex.cxx,v $
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
40 #include <tools/presys.h>
42 #pragma warning(push, 1)
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"
69 namespace /* private */
75 //###########################################
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()
101 OUString module_path
;
102 if (osl_Process_E_None
== osl_getProcessWorkingDir(&cwd_url
.pData
))
103 osl::FileBase::getSystemPathFromFileURL(cwd_url
, 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
116 OUString
get_absolute_path(
117 const OUString
& BaseDir
, const OUString
& RelDir
)
122 osl::FileBase::getFileURLFromSystemPath(BaseDir
, base_url
);
123 osl::FileBase::getFileURLFromSystemPath(RelDir
, rel_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
);
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
149 explicit StreamExceptionsEnabler(
151 std::ios::iostate NewIos
= std::ios::failbit
| std::ios::badbit
) :
153 m_OldIos(m_IoStrm
.exceptions())
155 m_IoStrm
.exceptions(NewIos
);
158 ~StreamExceptionsEnabler()
160 m_IoStrm
.exceptions(m_OldIos
);
164 std::ios::iostate m_OldIos
;
167 typedef std::vector
<std::string
> string_container_t
;
169 //###########################################
170 class iso_lang_identifier
173 iso_lang_identifier() {};
175 iso_lang_identifier(const OString
& str
) :
179 iso_lang_identifier(const std::string
& str
) :
183 OString
language() const
186 OString
country() const
189 OString
make_OString() const
190 { return lang_
+ "-" + country_
; }
192 std::string
make_std_string() const
194 OString
tmp(lang_
+ "-" + country_
);
201 sal_Int32 idx
= lang_
.indexOf("-");
205 country_
= lang_
.copy(idx
+ 1);
206 lang_
= lang_
.copy(0, idx
);
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
;
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
++;
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 */
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
;
251 typedef iso_lang_replacement_table_t::iterator iterator
;
252 typedef iso_lang_replacement_table_t::const_iterator const_iterator
;
255 { return iso_lang_replacement_table_
.begin(); }
258 { return iso_lang_replacement_table_
.end(); }
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
)
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());
286 replacement_table_t::iterator iter
= prt
->find(Text
);
287 if (iter
!= prt
->end())
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());
296 prt
->insert(std::make_pair(Placeholder
, Substitute
));
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
));
323 iso_lang_replacement_table_t iso_lang_replacement_table_
;
324 iso_lang_identifier active_iso_lang_
;
327 //###########################################
328 void add_group_entries(
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};
380 in
.read(&buff
[0], 3);
382 if (memcmp(buff
, BOM
, 3) != 0)
386 while (std::getline(in
, line
))
387 out
<< line
<< std::endl
;
389 catch (const std::ios::failure
&)
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 //###########################################
407 const std::string
& fname
,
408 string_container_t
& string_container
)
410 std::ifstream
file(fname
.c_str());
411 StreamExceptionsEnabler
sexc(file
);
416 while (std::getline(file
, line
))
417 string_container
.push_back(line
);
419 catch(const std::ios::failure
&)
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
);
437 while (std::getline(is
, line
))
438 os
<< line
<< std::endl
;
440 catch(const std::ios::failure
&)
447 //###########################################
448 bool is_placeholder(const std::string
& str
)
450 return ((str
.length() > 1) &&
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());
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();
510 start_language_section(oi
, iter
->first
);
512 for ( /**/ ;rct_iter
!= rct_iter_end
; ++rct_iter
)
514 std::istringstream
iss(*rct_iter
);
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
528 if (is_placeholder(token
))
529 token
= make_winrc_unicode_string(token
);
539 } // namespace /* private */
541 //####################################################
543 The file names provided via command line should be
544 absolute or relative to the directory of this module.
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
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
;
593 std::cout
<< "Unexpected error..." << std::endl
;