Cleanup after dicttool

Arrange for temporary files to be deleted.
Also, add a security on stack overflows.

Change-Id: I9da2ebefb06409a71b235243ea835ce10d6a9b81
main
Jean Chalard 2012-10-30 19:54:34 +09:00
parent ee0b5488b5
commit a8058d169d
3 changed files with 19 additions and 7 deletions

View File

@ -50,6 +50,8 @@ public final class BinaryDictOffdeviceUtils {
public final static String COMPRESSION = "compressed"; public final static String COMPRESSION = "compressed";
public final static String ENCRYPTION = "encrypted"; public final static String ENCRYPTION = "encrypted";
private final static int MAX_DECODE_DEPTH = 8;
public static class DecoderChainSpec { public static class DecoderChainSpec {
ArrayList<String> mDecoderSpec = new ArrayList<String>(); ArrayList<String> mDecoderSpec = new ArrayList<String>();
File mFile; File mFile;
@ -85,12 +87,17 @@ public final class BinaryDictOffdeviceUtils {
* If this is not a binary dictionary, the method returns null. * If this is not a binary dictionary, the method returns null.
*/ */
public static DecoderChainSpec getRawBinaryDictionaryOrNull(final File src) { public static DecoderChainSpec getRawBinaryDictionaryOrNull(final File src) {
return getRawBinaryDictionaryOrNullInternal(new DecoderChainSpec(), src); return getRawBinaryDictionaryOrNullInternal(new DecoderChainSpec(), src, 0);
} }
private static DecoderChainSpec getRawBinaryDictionaryOrNullInternal( private static DecoderChainSpec getRawBinaryDictionaryOrNullInternal(
final DecoderChainSpec spec, final File src) { final DecoderChainSpec spec, final File src, final int depth) {
// TODO: arrange for the intermediary files to be deleted // Unfortunately the decoding scheme we use can consider any data to be encrypted
// and will product some output, meaning it's not possible to reliably detect encrypted
// data. Thus, some non-dictionary files (especially small) ones may successfully decrypt
// over and over, ending in a stack overflow. Hence we limit the depth at which we try
// decoding the file.
if (depth > MAX_DECODE_DEPTH) return null;
if (BinaryDictInputOutput.isBinaryDictionary(src)) { if (BinaryDictInputOutput.isBinaryDictionary(src)) {
spec.mFile = src; spec.mFile = src;
return spec; return spec;
@ -99,7 +106,7 @@ public final class BinaryDictOffdeviceUtils {
final File uncompressedFile = tryGetUncompressedFile(src); final File uncompressedFile = tryGetUncompressedFile(src);
if (null != uncompressedFile) { if (null != uncompressedFile) {
final DecoderChainSpec newSpec = final DecoderChainSpec newSpec =
getRawBinaryDictionaryOrNullInternal(spec, uncompressedFile); getRawBinaryDictionaryOrNullInternal(spec, uncompressedFile, depth + 1);
if (null == newSpec) return null; if (null == newSpec) return null;
return newSpec.addStep(COMPRESSION); return newSpec.addStep(COMPRESSION);
} }
@ -107,7 +114,7 @@ public final class BinaryDictOffdeviceUtils {
final File decryptedFile = tryGetDecryptedFile(src); final File decryptedFile = tryGetDecryptedFile(src);
if (null != decryptedFile) { if (null != decryptedFile) {
final DecoderChainSpec newSpec = final DecoderChainSpec newSpec =
getRawBinaryDictionaryOrNullInternal(spec, decryptedFile); getRawBinaryDictionaryOrNullInternal(spec, decryptedFile, depth + 1);
if (null == newSpec) return null; if (null == newSpec) return null;
return newSpec.addStep(ENCRYPTION); return newSpec.addStep(ENCRYPTION);
} }
@ -122,6 +129,7 @@ public final class BinaryDictOffdeviceUtils {
private static File tryGetUncompressedFile(final File src) { private static File tryGetUncompressedFile(final File src) {
try { try {
final File dst = File.createTempFile(PREFIX, SUFFIX); final File dst = File.createTempFile(PREFIX, SUFFIX);
dst.deleteOnExit();
final FileOutputStream dstStream = new FileOutputStream(dst); final FileOutputStream dstStream = new FileOutputStream(dst);
copy(Compress.getUncompressedStream(new BufferedInputStream(new FileInputStream(src))), copy(Compress.getUncompressedStream(new BufferedInputStream(new FileInputStream(src))),
new BufferedOutputStream(dstStream)); // #copy() closes the streams new BufferedOutputStream(dstStream)); // #copy() closes the streams
@ -140,12 +148,13 @@ public final class BinaryDictOffdeviceUtils {
private static File tryGetDecryptedFile(final File src) { private static File tryGetDecryptedFile(final File src) {
try { try {
final File dst = File.createTempFile(PREFIX, SUFFIX); final File dst = File.createTempFile(PREFIX, SUFFIX);
dst.deleteOnExit();
final FileOutputStream dstStream = new FileOutputStream(dst); final FileOutputStream dstStream = new FileOutputStream(dst);
copy(Crypt.getDecryptedStream(new BufferedInputStream(new FileInputStream(src))), copy(Crypt.getDecryptedStream(new BufferedInputStream(new FileInputStream(src))),
dstStream); // #copy() closes the streams dstStream); // #copy() closes the streams
return dst; return dst;
} catch (IOException e) { } catch (IOException e) {
// Could not uncompress the file: presumably the file is simply not a compressed file // Could not decrypt the file: presumably the file is simply not a crypted file
return null; return null;
} }
} }

View File

@ -32,7 +32,7 @@ public class Info extends Dicttool.Command {
@Override @Override
public String getHelp() { public String getHelp() {
return COMMAND + "<filename>: prints various information about a dictionary file"; return COMMAND + " <filename>: prints various information about a dictionary file";
} }
private static void showInfo(final FusionDictionary dict) { private static void showInfo(final FusionDictionary dict) {

View File

@ -54,6 +54,7 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase {
dict.add("fool", 1, null, false /* isNotAWord */); dict.add("fool", 1, null, false /* isNotAWord */);
final File dst = File.createTempFile("testGetRawDict", ".tmp"); final File dst = File.createTempFile("testGetRawDict", ".tmp");
dst.deleteOnExit();
final OutputStream out = Compress.getCompressedStream( final OutputStream out = Compress.getCompressedStream(
Compress.getCompressedStream( Compress.getCompressedStream(
Compress.getCompressedStream( Compress.getCompressedStream(
@ -81,6 +82,7 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase {
public void testGetRawDictFails() throws IOException { public void testGetRawDictFails() throws IOException {
// Randomly create some 4k file containing garbage // Randomly create some 4k file containing garbage
final File dst = File.createTempFile("testGetRawDict", ".tmp"); final File dst = File.createTempFile("testGetRawDict", ".tmp");
dst.deleteOnExit();
final OutputStream out = new BufferedOutputStream(new FileOutputStream(dst)); final OutputStream out = new BufferedOutputStream(new FileOutputStream(dst));
for (int i = 0; i < 1024; ++i) { for (int i = 0; i < 1024; ++i) {
out.write(0x12345678); out.write(0x12345678);
@ -92,6 +94,7 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase {
BinaryDictOffdeviceUtils.getRawBinaryDictionaryOrNull(dst)); BinaryDictOffdeviceUtils.getRawBinaryDictionaryOrNull(dst));
final File gzDst = File.createTempFile("testGetRawDict", ".tmp"); final File gzDst = File.createTempFile("testGetRawDict", ".tmp");
gzDst.deleteOnExit();
final OutputStream gzOut = final OutputStream gzOut =
Compress.getCompressedStream(new BufferedOutputStream(new FileOutputStream(gzDst))); Compress.getCompressedStream(new BufferedOutputStream(new FileOutputStream(gzDst)));
for (int i = 0; i < 1024; ++i) { for (int i = 0; i < 1024; ++i) {