facf0c92e0
Red Bear OS is a full fork. All sources must be available from git clone with zero network access. Removed gitignore rules that excluded fetched source trees under recipes/*/source/, local/recipes/kde/*/source/, local/recipes/qt/*/source/, and vendor source trees. Build artifacts (target/, build/, source.tar, *.o, *.so) remain excluded. 127291 files added — kernel, relibc, base, bootloader, pkgar, all KDE/Qt frameworks, mesa, wayland, DRM drivers, and every other recipe source.
242 lines
9.5 KiB
C#
242 lines
9.5 KiB
C#
/* GNU gettext for C#
|
|
* Copyright (C) 2003-2004, 2007 Free Software Foundation, Inc.
|
|
* Written by Bruno Haible <bruno@clisp.org>, 2003.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*
|
|
* This program dumps a GettextResourceSet subclass (in a satellite assembly)
|
|
* or a .resources file as a PO file.
|
|
*/
|
|
|
|
using System; /* Object, String, Type, Console, Exception */
|
|
using System.Reflection; /* Assembly, MethodInfo, ConstructorInfo */
|
|
using System.Collections; /* Hashtable, DictionaryEntry */
|
|
using System.IO; /* BufferedStream, StreamWriter, TextWriter, FileNotFoundException, Path */
|
|
using System.Text; /* StringBuilder, UTF8Encoding */
|
|
using System.Resources; /* ResourceReader */
|
|
using GNU.Gettext; /* GettextResourceSet */
|
|
|
|
namespace GNU.Gettext {
|
|
public class DumpResource {
|
|
private TextWriter Out;
|
|
private void DumpString (String str) {
|
|
int n = str.Length;
|
|
Out.Write('"');
|
|
for (int i = 0; i < n; i++) {
|
|
char c = str[i];
|
|
if (c == 0x0008) {
|
|
Out.Write('\\'); Out.Write('b');
|
|
} else if (c == 0x000c) {
|
|
Out.Write('\\'); Out.Write('f');
|
|
} else if (c == 0x000a) {
|
|
Out.Write('\\'); Out.Write('n');
|
|
} else if (c == 0x000d) {
|
|
Out.Write('\\'); Out.Write('r');
|
|
} else if (c == 0x0009) {
|
|
Out.Write('\\'); Out.Write('t');
|
|
} else if (c == '\\' || c == '"') {
|
|
Out.Write('\\'); Out.Write(c);
|
|
} else
|
|
Out.Write(c);
|
|
}
|
|
Out.Write('"');
|
|
}
|
|
private void DumpMessage (String msgid, String msgid_plural, Object msgstr) {
|
|
int separatorPos = msgid.IndexOf('\u0004');
|
|
if (separatorPos >= 0) {
|
|
String msgctxt = msgid.Substring(0,separatorPos);
|
|
msgid = msgid.Substring(separatorPos+1);
|
|
Out.Write("msgctxt "); DumpString(msgctxt);
|
|
}
|
|
Out.Write("msgid "); DumpString(msgid); Out.Write('\n');
|
|
if (msgid_plural != null) {
|
|
Out.Write("msgid_plural "); DumpString(msgid_plural); Out.Write('\n');
|
|
for (int i = 0; i < (msgstr as String[]).Length; i++) {
|
|
Out.Write("msgstr[" + i + "] ");
|
|
DumpString((msgstr as String[])[i]);
|
|
Out.Write('\n');
|
|
}
|
|
} else {
|
|
Out.Write("msgstr "); DumpString(msgstr as String); Out.Write('\n');
|
|
}
|
|
Out.Write('\n');
|
|
}
|
|
|
|
// ---------------- Dumping a GettextResourceSet ----------------
|
|
|
|
private void Dump (GettextResourceSet catalog) {
|
|
MethodInfo pluralMethod =
|
|
catalog.GetType().GetMethod("GetMsgidPluralTable", Type.EmptyTypes);
|
|
// Search for the header entry.
|
|
{
|
|
Object header_entry = catalog.GetObject("");
|
|
// If there is no header entry, fake one.
|
|
// FIXME: This is not needed; right after po_lex_charset_init set
|
|
// the PO charset to UTF-8.
|
|
if (header_entry == null)
|
|
header_entry = "Content-Type: text/plain; charset=UTF-8\n";
|
|
DumpMessage("", null, header_entry);
|
|
}
|
|
// Now the other messages.
|
|
{
|
|
Hashtable plural = null;
|
|
if (pluralMethod != null)
|
|
plural = pluralMethod.Invoke(catalog, new Object[0]) as Hashtable;
|
|
foreach (String key in catalog.Keys)
|
|
if (!"".Equals(key)) {
|
|
Object value = catalog.GetObject(key);
|
|
String key_plural =
|
|
(plural != null && value is String[] ? plural[key] as String : null);
|
|
DumpMessage(key, key_plural, value);
|
|
}
|
|
}
|
|
}
|
|
// Essentially taken from class GettextResourceManager.
|
|
private static Assembly GetSatelliteAssembly (String baseDirectory, String resourceName, String cultureName) {
|
|
String satelliteExpectedLocation =
|
|
baseDirectory
|
|
+ Path.DirectorySeparatorChar + cultureName
|
|
+ Path.DirectorySeparatorChar + resourceName + ".resources.dll";
|
|
return Assembly.LoadFrom(satelliteExpectedLocation);
|
|
}
|
|
// Taken from class GettextResourceManager.
|
|
private static String ConstructClassName (String resourceName) {
|
|
// We could just return an arbitrary fixed class name, like "Messages",
|
|
// assuming that every assembly will only ever contain one
|
|
// GettextResourceSet subclass, but this assumption would break the day
|
|
// we want to support multi-domain PO files in the same format...
|
|
bool valid = (resourceName.Length > 0);
|
|
for (int i = 0; valid && i < resourceName.Length; i++) {
|
|
char c = resourceName[i];
|
|
if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c == '_')
|
|
|| (i > 0 && c >= '0' && c <= '9')))
|
|
valid = false;
|
|
}
|
|
if (valid)
|
|
return resourceName;
|
|
else {
|
|
// Use hexadecimal escapes, using the underscore as escape character.
|
|
String hexdigit = "0123456789abcdef";
|
|
StringBuilder b = new StringBuilder();
|
|
b.Append("__UESCAPED__");
|
|
for (int i = 0; i < resourceName.Length; i++) {
|
|
char c = resourceName[i];
|
|
if (c >= 0xd800 && c < 0xdc00
|
|
&& i+1 < resourceName.Length
|
|
&& resourceName[i+1] >= 0xdc00 && resourceName[i+1] < 0xe000) {
|
|
// Combine two UTF-16 words to a character.
|
|
char c2 = resourceName[i+1];
|
|
int uc = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
|
|
b.Append('_');
|
|
b.Append('U');
|
|
b.Append(hexdigit[(uc >> 28) & 0x0f]);
|
|
b.Append(hexdigit[(uc >> 24) & 0x0f]);
|
|
b.Append(hexdigit[(uc >> 20) & 0x0f]);
|
|
b.Append(hexdigit[(uc >> 16) & 0x0f]);
|
|
b.Append(hexdigit[(uc >> 12) & 0x0f]);
|
|
b.Append(hexdigit[(uc >> 8) & 0x0f]);
|
|
b.Append(hexdigit[(uc >> 4) & 0x0f]);
|
|
b.Append(hexdigit[uc & 0x0f]);
|
|
i++;
|
|
} else if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
|
|
|| (c >= '0' && c <= '9'))) {
|
|
int uc = c;
|
|
b.Append('_');
|
|
b.Append('u');
|
|
b.Append(hexdigit[(uc >> 12) & 0x0f]);
|
|
b.Append(hexdigit[(uc >> 8) & 0x0f]);
|
|
b.Append(hexdigit[(uc >> 4) & 0x0f]);
|
|
b.Append(hexdigit[uc & 0x0f]);
|
|
} else
|
|
b.Append(c);
|
|
}
|
|
return b.ToString();
|
|
}
|
|
}
|
|
// Essentially taken from class GettextResourceManager.
|
|
private static GettextResourceSet InstantiateResourceSet (Assembly satelliteAssembly, String resourceName, String cultureName) {
|
|
Type clazz = satelliteAssembly.GetType(ConstructClassName(resourceName)+"_"+cultureName.Replace('-','_'));
|
|
ConstructorInfo constructor = clazz.GetConstructor(Type.EmptyTypes);
|
|
return constructor.Invoke(null) as GettextResourceSet;
|
|
}
|
|
public DumpResource (String baseDirectory, String resourceName, String cultureName) {
|
|
// We are only interested in the messages belonging to the locale
|
|
// itself, not in the inherited messages. Therefore we instantiate just
|
|
// the GettextResourceSet, not a GettextResourceManager.
|
|
Assembly satelliteAssembly =
|
|
GetSatelliteAssembly(baseDirectory, resourceName, cultureName);
|
|
GettextResourceSet catalog =
|
|
InstantiateResourceSet(satelliteAssembly, resourceName, cultureName);
|
|
BufferedStream stream = new BufferedStream(Console.OpenStandardOutput());
|
|
Out = new StreamWriter(stream, new UTF8Encoding());
|
|
Dump(catalog);
|
|
Out.Close();
|
|
stream.Close();
|
|
}
|
|
|
|
// ----------------- Dumping a .resources file ------------------
|
|
|
|
public DumpResource (String filename) {
|
|
BufferedStream stream = new BufferedStream(Console.OpenStandardOutput());
|
|
Out = new StreamWriter(stream, new UTF8Encoding());
|
|
ResourceReader rr;
|
|
if (filename.Equals("-")) {
|
|
BufferedStream input = new BufferedStream(Console.OpenStandardInput());
|
|
// A temporary output stream is needed because ResourceReader expects
|
|
// to be able to seek in the Stream.
|
|
byte[] contents;
|
|
{
|
|
MemoryStream tmpstream = new MemoryStream();
|
|
byte[] buf = new byte[1024];
|
|
for (;;) {
|
|
int n = input.Read(buf, 0, 1024);
|
|
if (n == 0)
|
|
break;
|
|
tmpstream.Write(buf, 0, n);
|
|
}
|
|
contents = tmpstream.ToArray();
|
|
tmpstream.Close();
|
|
}
|
|
MemoryStream tmpinput = new MemoryStream(contents);
|
|
rr = new ResourceReader(tmpinput);
|
|
} else {
|
|
rr = new ResourceReader(filename);
|
|
}
|
|
foreach (DictionaryEntry entry in rr) // uses rr.GetEnumerator()
|
|
DumpMessage(entry.Key as String, null, entry.Value as String);
|
|
rr.Close();
|
|
Out.Close();
|
|
stream.Close();
|
|
}
|
|
|
|
// --------------------------------------------------------------
|
|
|
|
public static int Main (String[] args) {
|
|
try {
|
|
if (args.Length > 1)
|
|
new DumpResource(args[0], args[1], args[2]);
|
|
else
|
|
new DumpResource(args[0]);
|
|
} catch (Exception e) {
|
|
Console.Error.WriteLine(e);
|
|
Console.Error.WriteLine(e.StackTrace);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
}
|