FileBasedConfig supports UTF-8 byte order marker
Change-Id: I1f5dc07182dbf6bba2a9f4807fdd25b475da4ead
This commit is contained in:
parent
4b3c0f8aba
commit
8f706db56a
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Copyright (C) 2012, Marc Strapetz
|
||||
* and other copyright owners as documented in the project's IP log.
|
||||
*
|
||||
* This program and the accompanying materials are made available
|
||||
* under the terms of the Eclipse Distribution License v1.0 which
|
||||
* accompanies this distribution, is reproduced below, and is
|
||||
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* - Neither the name of the Eclipse Foundation, Inc. nor the
|
||||
* names of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.eclipse.jgit.storage.file;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
import org.eclipse.jgit.util.FS;
|
||||
import org.eclipse.jgit.util.FileUtils;
|
||||
import org.eclipse.jgit.util.IO;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class FileBasedConfigTest {
|
||||
|
||||
private static final String USER = "user";
|
||||
|
||||
private static final String NAME = "name";
|
||||
|
||||
private static final String ALICE = "Alice";
|
||||
|
||||
private static final String BOB = "Bob";
|
||||
|
||||
private static final String CONTENT1 = "[" + USER + "]\n\t" + NAME + " = "
|
||||
+ ALICE + "\n";
|
||||
|
||||
private static final String CONTENT2 = "[" + USER + "]\n\t" + NAME + " = "
|
||||
+ BOB + "\n";
|
||||
|
||||
private final File trash = new File(new File("target"), "trash");
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
FileUtils.delete(trash, FileUtils.RECURSIVE | FileUtils.SKIP_MISSING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSystemEncoding() throws IOException, ConfigInvalidException {
|
||||
final File file = createFile(CONTENT1.getBytes());
|
||||
final FileBasedConfig config = new FileBasedConfig(file, FS.DETECTED);
|
||||
config.load();
|
||||
assertEquals(ALICE, config.getString(USER, null, NAME));
|
||||
|
||||
config.setString(USER, null, NAME, BOB);
|
||||
config.save();
|
||||
assertArrayEquals(CONTENT2.getBytes(), IO.readFully(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUTF8withoutBOM() throws IOException, ConfigInvalidException {
|
||||
final File file = createFile(CONTENT1.getBytes("UTF-8"));
|
||||
final FileBasedConfig config = new FileBasedConfig(file, FS.DETECTED);
|
||||
config.load();
|
||||
assertEquals(ALICE, config.getString(USER, null, NAME));
|
||||
|
||||
config.setString(USER, null, NAME, BOB);
|
||||
config.save();
|
||||
assertArrayEquals(CONTENT2.getBytes(), IO.readFully(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUTF8withBOM() throws IOException, ConfigInvalidException {
|
||||
final ByteArrayOutputStream bos1 = new ByteArrayOutputStream();
|
||||
bos1.write(0xEF);
|
||||
bos1.write(0xBB);
|
||||
bos1.write(0xBF);
|
||||
bos1.write(CONTENT1.getBytes("UTF-8"));
|
||||
|
||||
final File file = createFile(bos1.toByteArray());
|
||||
final FileBasedConfig config = new FileBasedConfig(file, FS.DETECTED);
|
||||
config.load();
|
||||
assertEquals(ALICE, config.getString(USER, null, NAME));
|
||||
|
||||
config.setString(USER, null, NAME, BOB);
|
||||
config.save();
|
||||
|
||||
final ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
|
||||
bos2.write(0xEF);
|
||||
bos2.write(0xBB);
|
||||
bos2.write(0xBF);
|
||||
bos2.write(CONTENT2.getBytes("UTF-8"));
|
||||
assertArrayEquals(bos2.toByteArray(), IO.readFully(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLeadingWhitespaces() throws IOException, ConfigInvalidException {
|
||||
final ByteArrayOutputStream bos1 = new ByteArrayOutputStream();
|
||||
bos1.write(" \n\t".getBytes());
|
||||
bos1.write(CONTENT1.getBytes());
|
||||
|
||||
final File file = createFile(bos1.toByteArray());
|
||||
final FileBasedConfig config = new FileBasedConfig(file, FS.DETECTED);
|
||||
config.load();
|
||||
assertEquals(ALICE, config.getString(USER, null, NAME));
|
||||
|
||||
config.setString(USER, null, NAME, BOB);
|
||||
config.save();
|
||||
|
||||
final ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
|
||||
bos2.write(" \n\t".getBytes());
|
||||
bos2.write(CONTENT2.getBytes());
|
||||
assertArrayEquals(bos2.toByteArray(), IO.readFully(file));
|
||||
}
|
||||
|
||||
private File createFile(byte[] content) throws IOException {
|
||||
trash.mkdirs();
|
||||
File f = File.createTempFile(getClass().getName(), null, trash);
|
||||
FileOutputStream os = new FileOutputStream(f, true);
|
||||
try {
|
||||
os.write(content);
|
||||
} finally {
|
||||
os.close();
|
||||
}
|
||||
return f;
|
||||
}
|
||||
}
|
|
@ -49,6 +49,7 @@
|
|||
|
||||
package org.eclipse.jgit.storage.file;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
@ -70,8 +71,13 @@
|
|||
*/
|
||||
public class FileBasedConfig extends StoredConfig {
|
||||
private final File configFile;
|
||||
|
||||
private final FS fs;
|
||||
|
||||
private boolean utf8Bom;
|
||||
|
||||
private volatile FileSnapshot snapshot;
|
||||
|
||||
private volatile ObjectId hash;
|
||||
|
||||
/**
|
||||
|
@ -141,7 +147,16 @@ public void load() throws IOException, ConfigInvalidException {
|
|||
else
|
||||
snapshot = newSnapshot;
|
||||
} else {
|
||||
fromText(RawParseUtils.decode(in));
|
||||
final String decoded;
|
||||
if (in.length >= 3 && in[0] == (byte) 0xEF
|
||||
&& in[1] == (byte) 0xBB && in[2] == (byte) 0xBF) {
|
||||
decoded = RawParseUtils.decode(RawParseUtils.UTF8_CHARSET,
|
||||
in, 3, in.length);
|
||||
utf8Bom = true;
|
||||
} else {
|
||||
decoded = RawParseUtils.decode(in);
|
||||
}
|
||||
fromText(decoded);
|
||||
snapshot = newSnapshot;
|
||||
hash = newHash;
|
||||
}
|
||||
|
@ -170,7 +185,19 @@ public void load() throws IOException, ConfigInvalidException {
|
|||
* the file could not be written.
|
||||
*/
|
||||
public void save() throws IOException {
|
||||
final byte[] out = Constants.encode(toText());
|
||||
final byte[] out;
|
||||
final String text = toText();
|
||||
if (utf8Bom) {
|
||||
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
bos.write(0xEF);
|
||||
bos.write(0xBB);
|
||||
bos.write(0xBF);
|
||||
bos.write(text.getBytes(RawParseUtils.UTF8_CHARSET));
|
||||
out = bos.toByteArray();
|
||||
} else {
|
||||
out = Constants.encode(text);
|
||||
}
|
||||
|
||||
final LockFile lf = new LockFile(getFile(), fs);
|
||||
if (!lf.lock())
|
||||
throw new LockFailedException(getFile());
|
||||
|
|
|
@ -65,6 +65,11 @@
|
|||
|
||||
/** Handy utility functions to parse raw object contents. */
|
||||
public final class RawParseUtils {
|
||||
/**
|
||||
* UTF-8 charset constant.
|
||||
*/
|
||||
public static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
|
||||
|
||||
private static final byte[] digits10;
|
||||
|
||||
private static final byte[] digits16;
|
||||
|
|
Loading…
Reference in New Issue