Converting a Midlet to a COD file for OTA installation

February 14, 2008 on 12:01 pm | In RIM / Blackberry, Uncategorized |

God, RIM sucks. Thought I’d mention that. I hate Blackberries with passion. Really.

Now, if you are converting a Midlet to a COD file, you will need to use the infamous rapc tool provided with the RIM JDE ( in the bin directory if you are looking for it ) . Now, along with issues with multiple versions, bugs and what have you, one big pain is if you want the RIM version of the JAD file created for OTA installation, rapc doesn’t give you all the parameters if you use the -midlet paramater. If you DON’T use it, you get a nice JAD but the COD will not work.

So, to get around this, I created a small app to extract the RIM specfic information from the COD file generated by rapc.

Generated the COD using

rapc import="%jde%\lib\net_rim_api.jar" codename=%jar% -midlet jad=%jar%.jad %jar%.jar

where %jde% is your JDE path, %jar% is the name of your module.

Extract JAD information from a COD file

To run:

java -jar cod2jad.jar {cod file} {module name}

This will dump the extra information to stdout, so you can just append it to your JAD file with >>, ie

java -jar cod2jad.jar path.cod myapp >> path.jad

Remember, once you have done this, open the COD file in winzip ( or whatever ) and extract the seperate elements to your webserver. Once note, if you COD is only made of one module, this will probably fail ( sorry ).

Oh, and if you are using Netbeans components, and/or getting verification errors, try turning down your obfusication level in your project - rapc hates the splash screen and wait screen when obfusicated for some reason. The other option is to try including the net_rim_api.jar in your project ( but don’t include in the package ).

And even nicer of me, here is the source code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package com.magnetmobile.tools.rim;
 
/**
 *
 * @author Sime when drunk ... yay drunk code
 */
import java.io.*;
import java.util.*;
import java.util.jar.*;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
 
public class Cod2Jad {
 
    public static void main(String args[])throws NoSuchAlgorithmException {
 
        FileInputStream fis = null;
        try {
            int count = 0;
            if (args.length != 2) {
                System.out.println("usage: {path to COD} {Module name}");
                System.exit(-1);
            }
            Hashtable htSizes = new Hashtable();
            Hashtable htJarContents = new Hashtable();
            fis = new FileInputStream(args[0]);
 
 
            BufferedInputStream bis = new BufferedInputStream(fis);
            ZipInputStream zis = new ZipInputStream(bis);
            ZipEntry ze = null;
            while ((ze = zis.getNextEntry()) != null) {
                if (ze.isDirectory()) {
                    continue;
                }
 
                int size = (int) ze.getSize();
                // -1 means unknown size.
                if (size == -1) {
                    size = ((Integer) htSizes.get(ze.getName())).intValue();
                }
                byte[] b = new byte[(int) size];
                int rb = 0;
                int chunk = 0;
                while (((int) size - rb) > 0) {
                    chunk = zis.read(b, rb, (int) size - rb);
                    if (chunk == -1) {
                        break;
                    }
                    rb += chunk;
                }
                htJarContents.put(ze.getName(), b);
                process(ze, count, b);
                count++;
            }
 
            System.out.println("RIM-COD-Module-Name:" + args[1]);
            System.out.println("RIM-COD-Module-Dependencies: net_rim_cldc");
            System.out.println("RIM-COD-Creation-Time: 1202924527");
 
            zis.close();
            bis.close();
            fis.close();
        } catch (IOException ex) {
            System.out.println("Could not access file "+args[0]);
            System.exit(-1);
        } finally {
            try {
                fis.close();
            } catch (IOException ex) {
                Logger.getLogger(Cod2Jad.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
 
    private static void process(Object obj, int count,byte[] data) throws NoSuchAlgorithmException,
UnsupportedEncodingException {
        ZipEntry entry = (ZipEntry) obj;
        String name = entry.getName();
        long size = entry.getSize();
        long compressedSize = entry.getCompressedSize();
 
        String output = "RIM-COD-URL" + (count > 0 ? ("-" + count) : "") + ": " + name;
        System.out.println(output);
 
        output = "RIM-COD-Size" + (count > 0 ? ("-" + count) : "") + ": " + compressedSize;
        System.out.println(output);
 
        output = "RIM-COD-SHA1" + (count > 0 ? ("-" + count) : "") + ": ";
        output +=  SHA1(data, true);
        System.out.println(output);
    }
 
    private static String convertToHex(byte[] data, boolean spaced) {
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i <
                data.length; i++) {
            int halfbyte = (data[i] >>> 4) & 0x0F;
            int two_halfs = 0;
            do {
                if ((0 <= halfbyte) && (halfbyte <= 9)) {
                    buf.append((char) ('0' + halfbyte));
                } else {
                    buf.append((char) ('a' + (halfbyte - 10)));
                }
 
                halfbyte = data[i] & 0x0F;
            } while (two_halfs++ < 1);
 
            if (spaced) {
                buf.append(' ');
            }
        }
 
        return buf.toString();
    }
 
    public static String SHA1(byte[] data, boolean spaced)
            throws NoSuchAlgorithmException, UnsupportedEncodingException {
        MessageDigest md;
        md =
                MessageDigest.getInstance("SHA-1");
        byte[] sha1hash = new byte[40];
        md.update(data, 0, data.length);
        sha1hash =
                md.digest();
        return convertToHex(sha1hash, spaced);
    }
}
[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Google] [StumbleUpon]

3 Comments »

RSS feed for comments on this post.

  1. Holy crap, this was useful, thanks!

    Just one question: should the properties RIM-COD-URL, RIM-COD-URL-1 etc. in the .jad file contain the whole url (starting with http://mysite.com …) or just the .cod file name?

    Csaba

    Comment by Csaba — April 27, 2008 #

  2. It doesn’t seem to matter as much in the RIM version as it may do on some J2ME devices - either way you could edit the above code to add it as a parameter.

    To be honest, I repass JAD files on my server on the way out using PHP to automatically resolve / append the URLS …

    Comment by Sime — May 3, 2008 #

  3. Your blog is interesting!

    Keep up the good work!

    Comment by AlexM — August 17, 2008 #

Leave a comment

XHTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Powered by WordPress with Pool theme design by Borja Fernandez.
Entries and comments feeds. Valid XHTML and CSS. ^Top^