Showing posts with label programowanie. Show all posts
Showing posts with label programowanie. Show all posts

Monday, July 6, 2009

How to create valid file name?

During development of OOo2GD I met some non-trivial problem.
In Google Docs you may use almost all characters in title of document, but you cannot use all those characters in file name. This means that when user wants to download document to local machine you need sometimes to convert title to file name.... And of course we want to make sure that file name will be as much similar to document title as it is possible.

I thought about two possible ways, first by creating smallest common caharset for all operating systems [or rather file systems]. Second by narrowing available charset in steps.
I choose 2nd way, and decided that first I will try to remove only ":", if it will not help I will try to remove some bigger set of characters, and if it will not help too I will keep only latin letters and digits.

Here is code which I'm using :-)
public static String findAvailableFileName(String destFileURI) {
String destFileName = destFileURI.substring(0,destFileURI.lastIndexOf("."));
String destFileExt = destFileURI.substring(destFileURI.lastIndexOf(".")+1);
int count = 1;
File f;
while ((f=new File(destFileURI)).exists()) {
destFileURI=destFileName+"("+(count++)+")"+"."+destFileExt;
}
String fName = f.getName();
String fPath = f.getParent();
// Now we need to check if given file name is valid for file system, and if it isn't we need to convert it to valid form
if (!(testIfFileNameIsValid(destFileURI))) {
List forbiddenCharsPatterns = new ArrayList();
forbiddenCharsPatterns.add("[:]+"); // Mac OS, but it looks that also Windows XP
forbiddenCharsPatterns.add("[\\*\"/\\\\\\[\\]\\:\\;\\|\\=\\,]+"); // Windows
forbiddenCharsPatterns.add("[^\\w\\d\\.]+"); // last chance... only latin letters and digits
for (String pattern:forbiddenCharsPatterns) {
String nameToTest = fName;
nameToTest = nameToTest.replaceAll(pattern, "_");
destFileURI=fPath+"/"+nameToTest;
count=1;
destFileName = destFileURI.substring(0,destFileURI.lastIndexOf("."));
destFileExt = destFileURI.substring(destFileURI.lastIndexOf(".")+1);
while ((f=new File(destFileURI)).exists()) {
destFileURI=destFileName+"("+(count++)+")"+"."+destFileExt;
}
if (testIfFileNameIsValid(destFileURI)) break;
}
}
return destFileURI;
}

private static boolean testIfFileNameIsValid(String destFileURI) {
boolean valid = false;
try {
File candidate = new File(destFileURI);
String canonicalPath = candidate.getCanonicalPath();
boolean b = candidate.createNewFile();
if (b) {
candidate.delete();
}
valid = true;
} catch (IOException ioEx) { }
return valid;
}

Here nicer form of sources ;-)

Because whole operation in code above is performed on file path in first step I remove all / and \...

Additionally this code returns "first free" file name. So if you are trying to save file "test.odt" to directory where file with this name exists, this code will test first if "test.odt" is available, if not it will try "test(1).odt", next "test(2).odt" and so on.

Feel free to comment :-)


Similar postsbeta
How many i 1+1 in Java? ;-)
The Secret Life of String ;-)
Recursion is evil ;-)
Abuse of Booleans ;-)
How we may use Google Earth Plugin? :-)

Monday, March 24, 2008

Abuse of Booleans ;-)

Today next chapter of abusing Java internals with using of reflections ;-)
In previous chapters we discussed problems: How many is 1+1 in Java and The Secret Life of String.

Two of well known facts about Boolean in Java are:
Boolean.valueOf(true) value is true
Boolean.valueOf(false) value is false

But how we will shown, not always ;p
import java.lang.reflect.Field;
public class HackBool {
static void fixBooleans() throws Exception {
Class boolClass = Boolean.class;
Field field = boolClass.getDeclaredField("value");
field.setAccessible(true);
field.setBoolean(Boolean.TRUE, false);
field.setBoolean(Boolean.FALSE, true);
}

public static void main(String[] args) throws Exception {
System.out.println("Boolean.valueOf("+true+")="+Boolean.valueOf(true));
System.out.println("Boolean.valueOf("+false+")="+Boolean.valueOf(false));
fixBooleans();
System.out.println("Boolean.valueOf("+true+")="+Boolean.valueOf(true));
System.out.println("Boolean.valueOf("+false+")="+Boolean.valueOf(false));
}
}


When we will try to execute this code we will see:

Boolean.valueOf(true)=true
Boolean.valueOf(false)=false
Boolean.valueOf(true)=false
Boolean.valueOf(false)=true


Two first lines looks good, but what with two last? ;-)

And what we will see after change of this code to this version:
import java.lang.reflect.Field;
public class HackBool {
static void fixBooleans() throws Exception {
Class boolClass = Boolean.class;
Field field = boolClass.getDeclaredField("value");
field.setAccessible(true);
field.setBoolean(Boolean.TRUE, false);
field.setBoolean(Boolean.FALSE, true);
}

public static void main(String[] args) throws Exception {
fixBooleans();
Boolean b = true;
if (b) System.out.println("TRUE :-)");
else System.out.println("FALSE :-(");
}
}

Correct answer is:
FALSE :-(

Why? Answer is easy, Boolean have two fields TRUE and FALSE, in fixBooleans() we changed values stored in variable value, for now when JVM tries to obtain value of TRUE it gets our change value false. That's whole secret ;-)

I will try to write next time something more interesting.

Similar postsbeta
How many i 1+1 in Java? ;-)
The Secret Life of String ;-)
How to create valid file name?
Recursion is evil ;-)
How to get negative number from size() in LinkedList in Java? ;-)

Sunday, March 16, 2008

How many i 1+1 in Java? ;-)

Last time we spoke about immutability of String in Java, today lets talk about adding Integers ;-)

Lets check how many is 1+1 in Java...

For first try we will use this code:
public class Integers { 
public static void main(String[] args) throws Exception{
Integer i1 = 1;
Integer i2 = 1;
System.out.println(i1+"+"+i2+"="+(Integer)(i1+i2));
}
}

After compile and run we will see on the screen:

1+1=2

It was easy :-)

But to our next try we will add some additional code....

import java.lang.reflect.Field;
public class Integers {
public static void main(String[] args) throws Exception {
Integer i1 = 1;
Integer i2 = 1;
System.out.println(i1+"+"+i2+"="+(Integer)(i1+i2));
fixIntegers();
System.out.println(i1+"+"+i2+"="+(Integer)(i1+i2));

}

static void fixIntegers() throws Exception {
Class integerClass = Integer.class;
Field value = integerClass.getDeclaredField("value");
value.setAccessible(true);
value.setInt(Integer.valueOf(2), 3);
}

}


And now strange things happens....

After we compile and run we can see....

1+1=2
1+1=3

How it's possible? ;-)

Here short explanation ;-)
Method fixIntegers() changes value of int stored as "int representation" in some Integer... This some Integer is rather important ;-) In Sun Java was decided that conversion of some numbers [actually from -128 to 127] is rather often, so why to make this conversion so often? More reasonable will be to keep somewhere array of those Integers and when it will be needed use one of those objects. Method fixIntegers() first gets Integer object for int value of 2, and using reflections it changes value from 2 to 3 :-)
Next "magic" things are in line where we made second addition, we adds 1 to 1, and of course we got as a result 2, but we also wants to convert it to Integer, instead conversion we have here usage of value from "pool", we take this object :-) But because we wants to print String representation of this value method toString() of our object is called... and toString() looks to private variable value and finds in this place... 3 :-)
And it's whole secret ;-)

Similar postsbeta
Abuse of Booleans ;-)
The Secret Life of String ;-)
How to get negative number from size() in LinkedList in Java? ;-)
How to create valid file name?
Recursion is evil ;-)

Thursday, March 6, 2008

The Secret Life of String ;-)

/mad scientist mode on

They always said "String is immutable - you cannot change its value without changing reference!"

But what They will say when I will use this code?
import java.lang.reflect.Field;

public class StringModificator {
public static void trueModificator(String str)
throws Exception {
Field valueField = str.getClass().getDeclaredField("value");
valueField.setAccessible(true);
char[] value = (char[])valueField.get(str);
char[] reversed = new char[value.length];
for (int idx=0; idx<value.length; idx++) {
reversed[idx]=value[value.length-idx-1];
}
for (int idx=0; idx<value.length; idx++) {
value[idx]=reversed[idx];
}
}

public static void falseModificator(String str) {
str="toster";
}

public static void main(String[] args) throws Exception {
String str = "it's a test";
String subStr = str.substring(3);
// prints "it's a test"
System.out.println(str);
System.out.println(subStr);

falseModificator(str);
// Still prints "it's a test"
System.out.println(str);
System.out.println(subStr);

trueModificator(str);
// But whats now? ;-)
System.out.println(str);
System.out.println(subStr);
}
}

So this whole String isn't so immutable as They said!!!

/mad scientist mode off

Similar postsbeta
Abuse of Booleans ;-)
How many i 1+1 in Java? ;-)
How to create valid file name?
Recursion is evil ;-)
How to get negative number from size() in LinkedList in Java? ;-)