gpt4 book ai didi

java - 使用 Java 创建 gettext 二进制 MO 文件

转载 作者:行者123 更新时间:2023-12-02 07:59:07 25 4
gpt4 key购买 nike

我尝试创建一个实用程序来解析 gettext po 文件并生成二进制 mo 文件。解析器很简单(我的公司不使用模糊、复数等东西,只是 msgid/msgstr),但生成器不起作用。

这里是the description of the mo file ,这里是the original generator source (它是C),还找到了一个php脚本(https://github.com/josscrowcroft/php.mo/blob/master/php-mo.php)。

我的代码:

public void writeFile(String filename, Map<String, String> polines) throws FileNotFoundException, IOException {

DataOutputStream os = new DataOutputStream(new FileOutputStream(filename));
HashMap<String, String> bvc = new HashMap<String, String>();
TreeMap<String, String> hash = new TreeMap(bvc);
hash.putAll(polines);


StringBuilder ids = new StringBuilder();
StringBuilder strings = new StringBuilder();
ArrayList<ArrayList> offsets = new ArrayList<ArrayList>();
ArrayList<Integer> key_offsets = new ArrayList<Integer>();
ArrayList<Integer> value_offsets = new ArrayList<Integer>();
ArrayList<Integer> temp_offsets = new ArrayList<Integer>();

for (Map.Entry<String, String> entry : hash.entrySet()) {
String id = entry.getKey();
String str = entry.getValue();

ArrayList<Integer> offsetsItems = new ArrayList<Integer>();
offsetsItems.add(ids.length());
offsetsItems.add(id.length());
offsetsItems.add(strings.length());
offsetsItems.add(str.length());
offsets.add((ArrayList) offsetsItems.clone());

ids.append(id).append('\0');
strings.append(str).append('\0');
}
Integer key_start = 7 * 4 + hash.size() * 4 * 4;
Integer value_start = key_start + ids.length();

Iterator e = offsets.iterator();
while (e.hasNext()) {
ArrayList<Integer> offEl = (ArrayList<Integer>) e.next();
key_offsets.add(offEl.get(1));
key_offsets.add(offEl.get(0) + key_start);
value_offsets.add(offEl.get(3));
value_offsets.add(offEl.get(2) + value_start);
}

temp_offsets.addAll(key_offsets);
temp_offsets.addAll(value_offsets);


os.writeByte(0xde);
os.writeByte(0x12);
os.writeByte(0x04);
os.writeByte(0x95);

os.writeByte(0x00);
os.writeInt(hash.size() & 0xff);
os.writeInt((7 * 4) & 0xff);
os.writeInt((7 * 4 + hash.size() * 8) & 0xff);
os.writeInt(0x00000000);
os.writeInt(key_start & 0xff);

Iterator offi = temp_offsets.iterator();
while (offi.hasNext()) {
Integer off = (Integer) offi.next();
os.writeInt(off & 0xff);
}
os.writeUTF(ids.toString());
os.writeUTF(strings.toString());

os.close();
}

os.writeInt(key_start);看起来不错,与原始工具生成的mo文件的差异是在这些字节之后开始的。

怎么了? (除了我可怕的英语......)

最佳答案

在将您的实现与文档进行比较时,我注意到两件事:

  1. 紧随魔数(Magic Number)之后的修订版应该是一个 int。 这似乎有效,可能是因为 writeByte 输出一些填充。不过,使用 writeInt 会更清晰。
  2. writeInt 调用中的 & 0xFF 部分可能是错误的。需要此操作将有符号字节转换为其无符号整数值,对于正整数则不需要。

要解析 po 文件,您还可以查看 zanata/tennera project on github .

编辑: writeUTF call 也是有问题的,因为它使用两个字节长度作为输出前缀,并使用 javas 修改的 utf 编码来破坏 '\0' 字节。您可以将其替换为:

os.write(ids.toString().getBytes("utf-8"));
os.write(strings.toString().getBytes("utf-8"));

另一个编辑:我不能放弃这段代码,关于字符与 utf8 字节中的字符串长度以及在 big-endian instead of little endian 中写入的 DataOutputStream 还存在其他问题。 。我认为以下代码应该可以工作,不同之处在于 msgfmt 生成的文件包含一个可选的哈希表以加快访问速度:

public static void writeInt(OutputStream os, int i) throws IOException {
os.write((i) & 0xFF);
os.write((i >>> 8) & 0xFF);
os.write((i >>> 16) & 0xFF);
os.write((i >>> 24) & 0xFF);
}

public static void writeFile(String filename, TreeMap<String, String> polines) throws IOException {
OutputStream os = new BufferedOutputStream(new FileOutputStream(filename));
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int size = polines.size();
int[] indices = new int[size*2];
int[] lengths = new int[size*2];
int idx = 0;
// write the strings and translations to a byte array and remember offsets and length in bytes
for (String key : polines.keySet()) {
byte[] utf = key.getBytes("utf-8");
indices[idx] = bos.size();
lengths[idx] = utf.length;
bos.write(utf);
bos.write(0);
idx++;
}
for (String val : polines.values()) {
byte[] utf = val.getBytes("utf-8");
indices[idx] = bos.size();
lengths[idx] = utf.length;
bos.write(utf);
bos.write(0);
idx++;
}

try {
int headerLength = 7*4;
int tableLength = size*2*2*4;
writeInt(os, 0x950412DE); // magic
writeInt(os, 0); // file format revision
writeInt(os, size); //number of strings
writeInt(os, headerLength); // offset of table with original strings
writeInt(os, headerLength + tableLength/2); // offset of table with translation strings
writeInt(os, 0); // size of hashing table
writeInt(os, headerLength + tableLength); // offset of hashing table, not used since length is 0

for (int i=0; i<size*2; i++) {
writeInt(os, lengths[i]);
writeInt(os, headerLength + tableLength + indices[i]);
}

// copy keys and translations
bos.writeTo(os);

} finally {
os.close();
}
}

关于java - 使用 Java 创建 gettext 二进制 MO 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9159934/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com