ColdFusion Builder has been my weapon of choice for writing CFML since it has been in beta and free. Now it's at version 1.0.0, and Adobe has decided to charge $299 for it, I think I'll be going back to CFEclipse.
Shouldn't Adobe be trying to build it's user base by giving CFBuilder away for free? Even Microsoft has got in on the act with it's Express tools.
I also find it quite a poor show that Adobe has taken an Open Source project, Eclipse, added very little to it, re-branded it and is trying to charge the CF developer community, who are inexplicably loyal to Adobe, $299 a pop for it.
So just for shits and giggles here is how you might crack CFBuilder to continue using it for free.
You will need:-
-
ColdFusion Builder Trial
-
JD-GUI Java Decompiler
-
7-Zip
If you installed CFBuilder in the default location, the class files we need to modify are in:
C:\Program Files\Adobe\Adobe ColdFusion Builder\plugins\com.adobe.ide.coldfusion.common_1.0.0.271911.jar
Start the decompiler and open the above JAR file. The class we need to edit is:
com.adobe.ide.coldfusion.common.util.TestUtil.class
Navigate to the TestUtil class, the JD decompiler produces the following code:
TestUtil.java
package com.adobe.ide.coldfusion.common.util;
import com.adobe.ide.amt.Activator;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.TimerTask;
import org.eclipse.core.runtime.Platform;
import org.eclipse.swt.widgets.Display;
public class TestUtil
{
private Calendar _expDate = null;
private Calendar _installDate = null;
private int _evalDays = 30;
private boolean _expired = false;
private File _hiddenFile = null;
private static final long MAGIC = -889275714L;
private String _code = null;
private boolean isBeta = true;
private static final TestUtil instance = new TestUtil();
private boolean isCheckDone = false;
private boolean isValidLicense = false;
private static final Object lockObject = new Object();
private boolean cfbStartupPluginLoaded = false;
public static final Object getLockObject() {
return lockObject;
}
public static TestUtil getInstance() {
return instance;
}
private TestUtil()
{
Timer timer = new Timer();
TimerHelper timerTask = new TimerHelper(null);
timer.schedule(timerTask, 150000L);
this._expDate = Calendar.getInstance();
this._expDate.set(2010, 2, 30);
checkExpired();
}
static Long encodeDate(long time) {
return Long.valueOf(0xCAFEBABE ^ (time >>> 32 | time << 32));
}
private void setCode() {
Calendar now = Calendar.getInstance();
this._code = encodeDate(now.getTime().getTime()).toString();
}
private void checkExpired() {
if (!this.isBeta) {
this._expired = false;
return;
}
setHiddenFile();
if (!hiddenFileExists()) {
createFileIfNeeded();
}
setHiddenProps();
if (!checkHiddenFile())
this._expired = true;
}
private void createFileIfNeeded()
{
Process p = null;
setCode();
try {
PrintWriter out = new PrintWriter(
new BufferedWriter(new OutputStreamWriter(new FileOutputStream(this._hiddenFile))));
out.println(this._code);
out.close();
if (!File.separator.equalsIgnoreCase("\\")) {
break label99;
}
String command = "attrib +H " + this._hiddenFile.getPath();
p = Runtime.getRuntime().exec(command);
label99: p.waitFor();
}
catch (Exception localException) {
}
finally {
if (p != null)
p.destroy();
}
}
private int getDaysDiffFromHiddenFile()
{
int _installYear = this._installDate.get(1);
int _expYear = this._expDate.get(1);
int yearDiff = _expYear - _installYear;
return this._expDate.get(6) -
this._installDate.get(6) + 365 * yearDiff;
}
private void emptyHiddenFile() {
Process p = null;
try {
this._hiddenFile.delete();
this._hiddenFile.createNewFile();
if (!File.separator.equalsIgnoreCase("\\")) {
break label66;
}
String command = "attrib +H " + this._hiddenFile.getPath();
p = Runtime.getRuntime().exec(command);
label66: p.waitFor();
}
catch (Exception localException) {
}
finally {
if (p != null)
p.destroy();
}
}
private boolean checkHiddenFile()
{
this._installDate = Calendar.getInstance();
if (!isEmpty(this._code)) {
this._installDate.setTime(decodeDate(Long.parseLong(this._code)));
this._evalDays = getDaysDiffFromHiddenFile();
if (getEvalDaysLeftForBeta() <= 0L) {
this._expired = true;
}
return true;
}
return false;
}
private void checkSystemDate() {
this._evalDays = getDaysDiffFromBeta();
if (this._evalDays <= 0)
this._expired = true;
}
private boolean hiddenFileExists()
{
return this._hiddenFile.exists();
}
private boolean isEmpty(String s)
{
return (s == null) || (s.length() == 0);
}
static final Date decodeDate(long code) {
Date d = null;
if (code != 0L) {
code = 0xCAFEBABE ^ code;
long time = code << 32 | code >>> 32;
d = new Date(time);
}
return d;
}
private void setHiddenProps() {
try {
BufferedReader br = new BufferedReader(new FileReader(this._hiddenFile));
String line = br.readLine();
if (!isEmpty(line)) {
this._code = line;
}
br.close();
}
catch (Exception localException) {
}
}
private void setHiddenFile() {
if (File.separator.equalsIgnoreCase("\\"))
{
String _hiddenfilename = getSystemDrive() + "\\.tolb3755.bin";
this._hiddenFile = new File(_hiddenfilename);
} else {
String _hiddenfilename = getUnixHome() + "/.tolb3755.bin";
this._hiddenFile = new File(_hiddenfilename);
}
}
private String getEnv(String envvar)
{
Map variables = System.getenv();
String value = "";
for (Map.Entry entry : variables.entrySet()) {
String name = (String)entry.getKey();
value = (String)entry.getValue();
if (name.equalsIgnoreCase(envvar.toUpperCase())) {
break;
}
}
return value;
}
private String getUnixHome()
{
return getEnv("HOME");
}
private String getSystemDrive() {
return getEnv("SYSTEMDRIVE");
}
private int getDaysDiffFromBeta()
{
Calendar now = Calendar.getInstance();
now.setTime(new Date());
int _nowYear = now.get(1);
int _expYear = this._expDate.get(1);
int yearDiff = _expYear - _nowYear;
int daysLeft = this._expDate.get(6) -
now.get(6) + 365 * yearDiff;
return daysLeft;
}
public long getEvalDaysLeftForBeta()
{
int daysLeft = getDaysDiffFromBeta();
if (daysLeft < 0)
daysLeft = 0;
return daysLeft;
}
public boolean isExpired() {
return this._expired;
}
public boolean isValidAtStartup()
{
return isValidHelper(true);
}
public boolean isValid() {
return isValidHelper(false);
}
public boolean isValidHelper(boolean calledFromStartup) {
synchronized (getLockObject()) {
if (this.isCheckDone) {
return this.isValidLicense;
}
}
return validate(calledFromStartup);
}
private boolean validate(boolean calledFromStartup)
{
if (!calledFromStartup)
{
return true;
}
synchronized (getLockObject())
{
try {
if (this.isCheckDone)
break label56;
this.cfbStartupPluginLoaded = true;
Activator.AMT_Initialize();
int iProductActionIndicator = Activator.AMT_ObtainLicense(
"ColdFusionBuilder_Base", 1, 0);
label56: if (iProductActionIndicator > 1)
this.isValidLicense = false;
else {
this.isValidLicense = true;
}
}
catch (Throwable localThrowable)
{
this.isValidLicense = false;
} finally {
this.isCheckDone = true;
}
return this.isValidLicense;
}
}
private class TimerHelper extends TimerTask
{
private TimerHelper()
{
}
public void run()
{
try
{
if (TestUtil.this.cfbStartupPluginLoaded) {
break label58;
}
Runnable task = new Runnable()
{
public void run()
{
TestUtil.this.isValidHelper(true);
}
};
if (Platform.getOS().equalsIgnoreCase("macosx"))
{
Display.getDefault().syncExec(task);
}
else
{
Display display1 = new Display();
display1.syncExec(task);
label58: display1.dispose();
}
}
catch (Throwable localThrowable)
{
}
finally
{
TestUtil.this.isCheckDone = true;
}
}
}
}
What we want to do is remove any validation logic and always return values indicating the the license is valid. After a bit of editing, your new TestUtil.java
should look something like:
TestUtil.java
package com.adobe.ide.coldfusion.common.util;
import java.util.Date;
public class TestUtil {
private static final TestUtil instance = new TestUtil();
private static final Object lockObject = new Object();
public static final Object getLockObject() {
return lockObject;
}
public static TestUtil getInstance() {
return instance;
}
private TestUtil() {
}
static Long encodeDate(long time) {
return Long.valueOf(0xCAFEBABE ^ (time >>> 32 | time << 32));
}
static final Date decodeDate(long code) {
Date d = null;
if (code != 0L) {
code = 0xCAFEBABE ^ code;
long time = code << 32 | code >>> 32;
d = new Date(time);
}
return d;
}
public long getEvalDaysLeftForBeta() {
return 1;
}
public boolean isExpired() {
return false;
}
public boolean isValidAtStartup() {
return true;
}
public boolean isValid() {
return true;
}
public boolean isValidHelper(boolean calledFromStartup) {
return true;
}
}
Recompile this class, and using 7-Zip, replace the old class in:
C:\Program Files\Adobe\Adobe ColdFusion Builder\plugins\com.adobe.ide.coldfusion.common_1.0.0.271911.jar
with the one you just compiled.
Now just start ColdFusion Builder and the registration screen should not appear.
As always with this type of thing, I won't be held responsible for anyone actually doing this, it's naughty and you might get a telling off, so don't do it. Either pay for CFBuilder or go download CFEclipse for free.