/* * Created on 21-Jun-2004 * Created by Paul Gardner * Copyright (C) 2004, 2005, 2006 Aelitis, All Rights Reserved. * * 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 2 * 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * AELITIS, SAS au capital de 46,603.30 euros * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France. * */ package com.frostwire.torrent; import java.io.File; import java.io.UnsupportedEncodingException; /** * @author parg * */ final class LocaleUtilDecoderFallback implements LocaleUtilDecoder { public static String NAME = "Fallback"; private static volatile int max_ok_name_length = 64; private static volatile boolean max_ok_name_length_determined; // don't change these, it'll stuff up people with torrents that are using the // fallback encoding private static final String VALID_CHARS = "abcdefghijklmnopqrstuvwxyz1234567890_-."; private int index; protected LocaleUtilDecoderFallback(int _index) { index = _index; } public String getName() { return (NAME); } public int getIndex() { return (index); } public String tryDecode(byte[] bytes, boolean lax) { return (decode(bytes)); } public String decodeString(byte[] bytes) throws UnsupportedEncodingException { return (decode(bytes)); } protected String decode(byte[] data) { if (data == null) { return (null); } StringBuffer res = new StringBuffer(data.length * 2); for (int i = 0; i < data.length; i++) { byte c = data[i]; if (VALID_CHARS.indexOf(Character.toLowerCase((char) c)) != -1) { res.append((char) c); } else { res.append("_"); res.append(ByteFormatter.nicePrint(c)); } } // more often that not these decoded values are used for filenames. Windows has a limit // of 250 (ish) chars, so we do something sensible with longer values int len = res.length(); if (len > max_ok_name_length) { // could be a file system out there that supports arbitarily long names, so // we can't pre-calculate the max if ((!max_ok_name_length_determined) && fileLengthOK(len)) { // this length is ok, bump up the known limit max_ok_name_length = len; } else { // won't fit if (!max_ok_name_length_determined) { for (int i = max_ok_name_length + 16; i < len; i += 16) { if (fileLengthOK(i)) { max_ok_name_length = i; } else { break; } } max_ok_name_length_determined = true; } // try and preserve extension String extension = null; int pos = res.lastIndexOf("."); if (pos != -1) { // include the "." extension = res.substring(pos); if (extension.length() == 1 || extension.length() > 4) { extension = null; } } // replace the end of the string with a hash value to ensure uniqueness byte[] hash = new SHA1Hasher().calculateHash(data); String hash_str = ByteFormatter.nicePrint(hash, true); res = new StringBuffer(res.substring(0, max_ok_name_length - hash_str.length() - (extension == null ? 0 : extension.length()))); res.append(hash_str); if (extension != null) { res.append(extension); } } } return (res.toString()); } protected boolean fileLengthOK(int len) { StringBuffer n = new StringBuffer(len); for (int i = 0; i < len; i++) { n.append("A"); } try { File f = File.createTempFile(n.toString(), ""); f.delete(); return (true); } catch (Throwable e) { return (false); } } }