14

Any tools to convert C code into Java code? I am interested in converting this code into Java:

***************************************************************************/
/*
** UNECM - Decoder for ECM (Error Code Modeler) format.
** Version 1.0
** Copyright (C) 2002 Neill Corlett
**
** 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.
*/
/***************************************************************************/
/*
** Portability notes:
**
** - Assumes a 32-bit or higher integer size
** - No assumptions about byte order
** - No assumptions about struct packing
** - No unaligned memory access
*/
/***************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/***************************************************************************/

void banner(void) {
  fprintf(stderr,
    "UNECM - Decoder for Error Code Modeler format v1.0\n"
    "Copyright (C) 2002 Neill Corlett\n\n"
  );
}

/***************************************************************************/

/* Data types */
#define ecc_uint8 unsigned char
#define ecc_uint16 unsigned short
#define ecc_uint32 unsigned

/* LUTs used for computing ECC/EDC */
static ecc_uint8 ecc_f_lut[256];
static ecc_uint8 ecc_b_lut[256];
static ecc_uint32 edc_lut[256];

/* Init routine */
static void eccedc_init(void) {
  ecc_uint32 i, j, edc;
  for(i = 0; i < 256; i++) {
    j = (i << 1) ^ (i & 0x80 ? 0x11D : 0);
    ecc_f_lut[i] = j;
    ecc_b_lut[i ^ j] = i;
    edc = i;
    for(j = 0; j < 8; j++) edc = (edc >> 1) ^ (edc & 1 ? 0xD8018001 : 0);
    edc_lut[i] = edc;
  }
}

/***************************************************************************/
/*
** Compute EDC for a block
*/
ecc_uint32 edc_partial_computeblock(
        ecc_uint32  edc,
  const ecc_uint8  *src,
        ecc_uint16  size
) {
  while(size--) edc = (edc >> 8) ^ edc_lut[(edc ^ (*src++)) & 0xFF];
  return edc;
}

void edc_computeblock(
  const ecc_uint8  *src,
        ecc_uint16  size,
        ecc_uint8  *dest
) {
  ecc_uint32 edc = edc_partial_computeblock(0, src, size);
  dest[0] = (edc >>  0) & 0xFF;
  dest[1] = (edc >>  8) & 0xFF;
  dest[2] = (edc >> 16) & 0xFF;
  dest[3] = (edc >> 24) & 0xFF;
}

/***************************************************************************/
/*
** Compute ECC for a block (can do either P or Q)
*/
static void ecc_computeblock(
  ecc_uint8 *src,
  ecc_uint32 major_count,
  ecc_uint32 minor_count,
  ecc_uint32 major_mult,
  ecc_uint32 minor_inc,
  ecc_uint8 *dest
) {
  ecc_uint32 size = major_count * minor_count;
  ecc_uint32 major, minor;
  for(major = 0; major < major_count; major++) {
    ecc_uint32 index = (major >> 1) * major_mult + (major & 1);
    ecc_uint8 ecc_a = 0;
    ecc_uint8 ecc_b = 0;
    for(minor = 0; minor < minor_count; minor++) {
      ecc_uint8 temp = src[index];
      index += minor_inc;
      if(index >= size) index -= size;
      ecc_a ^= temp;
      ecc_b ^= temp;
      ecc_a = ecc_f_lut[ecc_a];
    }
    ecc_a = ecc_b_lut[ecc_f_lut[ecc_a] ^ ecc_b];
    dest[major              ] = ecc_a;
    dest[major + major_count] = ecc_a ^ ecc_b;
  }
}

/*
** Generate ECC P and Q codes for a block
*/
static void ecc_generate(
  ecc_uint8 *sector,
  int        zeroaddress
) {
  ecc_uint8 address[4], i;
  /* Save the address and zero it out */
  if(zeroaddress) for(i = 0; i < 4; i++) {
    address[i] = sector[12 + i];
    sector[12 + i] = 0;
  }
  /* Compute ECC P code */
  ecc_computeblock(sector + 0xC, 86, 24,  2, 86, sector + 0x81C);
  /* Compute ECC Q code */
  ecc_computeblock(sector + 0xC, 52, 43, 86, 88, sector + 0x8C8);
  /* Restore the address */
  if(zeroaddress) for(i = 0; i < 4; i++) sector[12 + i] = address[i];
}

/***************************************************************************/
/*
** Generate ECC/EDC information for a sector (must be 2352 = 0x930 bytes)
** Returns 0 on success
*/
void eccedc_generate(ecc_uint8 *sector, int type) {
  ecc_uint32 i;
  switch(type) {
  case 1: /* Mode 1 */
    /* Compute EDC */
    edc_computeblock(sector + 0x00, 0x810, sector + 0x810);
    /* Write out zero bytes */
    for(i = 0; i < 8; i++) sector[0x814 + i] = 0;
    /* Generate ECC P/Q codes */
    ecc_generate(sector, 0);
    break;
  case 2: /* Mode 2 form 1 */
    /* Compute EDC */
    edc_computeblock(sector + 0x10, 0x808, sector + 0x818);
    /* Generate ECC P/Q codes */
    ecc_generate(sector, 1);
    break;
  case 3: /* Mode 2 form 2 */
    /* Compute EDC */
    edc_computeblock(sector + 0x10, 0x91C, sector + 0x92C);
    break;
  }
}

/***************************************************************************/

unsigned mycounter;
unsigned mycounter_total;

void resetcounter(unsigned total) {
  mycounter = 0;
  mycounter_total = total;
}

void setcounter(unsigned n) {
  if((n >> 20) != (mycounter >> 20)) {
    unsigned a = (n+64)/128;
    unsigned d = (mycounter_total+64)/128;
    if(!d) d = 1;
    fprintf(stderr, "Decoding (%02d%%)\r", (100*a) / d);
  }
  mycounter = n;
}

int unecmify(
  FILE *in,
  FILE *out
) {
  unsigned checkedc = 0;
  unsigned char sector[2352];
  unsigned type;
  unsigned num;
  fseek(in, 0, SEEK_END);
  resetcounter(ftell(in));
  fseek(in, 0, SEEK_SET);
  if(
    (fgetc(in) != 'E') ||
    (fgetc(in) != 'C') ||
    (fgetc(in) != 'M') ||
    (fgetc(in) != 0x00)
  ) {
    fprintf(stderr, "Header not found!\n");
    goto corrupt;
  }
  for(;;) {
    int c = fgetc(in);
    int bits = 5;
    if(c == EOF) goto uneof;
    type = c & 3;
    num = (c >> 2) & 0x1F;
    while(c & 0x80) {
      c = fgetc(in);
      if(c == EOF) goto uneof;
      num |= ((unsigned)(c & 0x7F)) << bits;
      bits += 7;
    }
    if(num == 0xFFFFFFFF) break;
    num++;
    if(num >= 0x80000000) goto corrupt;
    if(!type) {
      while(num) {
        int b = num;
        if(b > 2352) b = 2352;
        if(fread(sector, 1, b, in) != b) goto uneof;
        checkedc = edc_partial_computeblock(checkedc, sector, b);
        fwrite(sector, 1, b, out);
        num -= b;
        setcounter(ftell(in));
      }
    } else {
      while(num--) {
        memset(sector, 0, sizeof(sector));
        memset(sector + 1, 0xFF, 10);
        switch(type) {
        case 1:
          sector[0x0F] = 0x01;
          if(fread(sector + 0x00C, 1, 0x003, in) != 0x003) goto uneof;
          if(fread(sector + 0x010, 1, 0x800, in) != 0x800) goto uneof;
          eccedc_generate(sector, 1);
          checkedc = edc_partial_computeblock(checkedc, sector, 2352);
          fwrite(sector, 2352, 1, out);
          setcounter(ftell(in));
          break;
        case 2:
          sector[0x0F] = 0x02;
          if(fread(sector + 0x014, 1, 0x804, in) != 0x804) goto uneof;
          sector[0x10] = sector[0x14];
          sector[0x11] = sector[0x15];
          sector[0x12] = sector[0x16];
          sector[0x13] = sector[0x17];
          eccedc_generate(sector, 2);
          checkedc = edc_partial_computeblock(checkedc, sector + 0x10, 2336);
          fwrite(sector + 0x10, 2336, 1, out);
          setcounter(ftell(in));
          break;
        case 3:
          sector[0x0F] = 0x02;
          if(fread(sector + 0x014, 1, 0x918, in) != 0x918) goto uneof;
          sector[0x10] = sector[0x14];
          sector[0x11] = sector[0x15];
          sector[0x12] = sector[0x16];
          sector[0x13] = sector[0x17];
          eccedc_generate(sector, 3);
          checkedc = edc_partial_computeblock(checkedc, sector + 0x10, 2336);
          fwrite(sector + 0x10, 2336, 1, out);
          setcounter(ftell(in));
          break;
        }
      }
    }
  }
  if(fread(sector, 1, 4, in) != 4) goto uneof;
  fprintf(stderr, "Decoded %ld bytes -> %ld bytes\n", ftell(in), ftell(out));
  if(
    (sector[0] != ((checkedc >>  0) & 0xFF)) ||
    (sector[1] != ((checkedc >>  8) & 0xFF)) ||
    (sector[2] != ((checkedc >> 16) & 0xFF)) ||
    (sector[3] != ((checkedc >> 24) & 0xFF))
  ) {
    fprintf(stderr, "EDC error (%08X, should be %02X%02X%02X%02X)\n",
      checkedc,
      sector[3],
      sector[2],
      sector[1],
      sector[0]
    );
    goto corrupt;
  }
  fprintf(stderr, "Done; file is OK\n");
  return 0;
uneof:
  fprintf(stderr, "Unexpected EOF!\n");
corrupt:
  fprintf(stderr, "Corrupt ECM file!\n");
  return 1;
}

/***************************************************************************/

int main(int argc, char **argv) {
  FILE *fin, *fout;
  char *infilename;
  char *outfilename;
  banner();
  /*
  ** Initialize the ECC/EDC tables
  */
  eccedc_init();
  /*
  ** Check command line
  */
  if((argc != 2) && (argc != 3)) {
    fprintf(stderr, "usage: %s ecmfile [outputfile]\n", argv[0]);
    return 1;
  }
  /*
  ** Verify that the input filename is valid
  */
  infilename = argv[1];
  if(strlen(infilename) < 5) {
    fprintf(stderr, "filename '%s' is too short\n", infilename);
    return 1;
  }
  if(strcasecmp(infilename + strlen(infilename) - 4, ".ecm")) {
    fprintf(stderr, "filename must end in .ecm\n");
    return 1;
  }
  /*
  ** Figure out what the output filename should be
  */
  if(argc == 3) {
    outfilename = argv[2];
  } else {
    outfilename = malloc(strlen(infilename) - 3);
    if(!outfilename) abort();
    memcpy(outfilename, infilename, strlen(infilename) - 4);
    outfilename[strlen(infilename) - 4] = 0;
  }
  fprintf(stderr, "Decoding %s to %s.\n", infilename, outfilename);
  /*
  ** Open both files
  */
  fin = fopen(infilename, "rb");
  if(!fin) {
    perror(infilename);
    return 1;
  }
  fout = fopen(outfilename, "wb");
  if(!fout) {
    perror(outfilename);
    fclose(fin);
    return 1;
  }
  /*
  ** Decode
  */
  unecmify(fin, fout);
  /*
  ** Close everything
  */
  fclose(fout);
  fclose(fin);
  return 0;
}
Aymon Fournier
  • 4,323
  • 12
  • 42
  • 59

7 Answers7

17

Your best bet is to rewrite the code.

Any automated conversion would, at best, yield poor-quality and unmaintainable code.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • Plus if there is a working "convertor", we are all unemployed. One clever guy made a proof this is not possible. All the convertors suck! – lzap Feb 28 '12 at 09:05
  • 3
    @lzap Who proved that it is not possible? (Also, there are a few programming languages that can be converted to a wide variety of programming languages, including Haxe (which was designed with the intention of being compilable into as many other languages as possible), so it's not necessarily true that "all converters suck".) – Anderson Green Feb 10 '13 at 04:30
  • His name is Alan Turing dude :-) – lzap Feb 13 '13 at 20:37
  • 6
    @Izap - if you are referring to the Halting problem, this is not the Halting problem. Dude. The Halting theorem says that there is no program that will tell you in a finite amount of time whether an arbitrary other program + input will terminate or not. It has nothing to do with the feasibility of program translation. – Stephen C Feb 20 '13 at 03:31
  • 17
    @lzap it is perfectly possible for a computer given a program to create an equivalent program in another language. That concept is called a compiler. – Thorbjørn Ravn Andersen Aug 02 '13 at 22:07
13

The C view of the world does not mix well with the Java view of the world. If you really want to compile to a form executable by Java, have a look at NestedVM - http://nestedvm.ibex.org/ - which is a cross compiler compiling to a MIPS-dialect which can then easily be "run" in Java either through interpretation or by conversion to actual bytecode reflecting the original MIPS-instructions.

I would recommend getting a Java version of the code.

Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347
10

There used to be tools called Ephedra, Convert2Java and C2J++. But they didn't really work and are no longer available. This leaves three companies offering automatic C to Java translation in the range of unusable, helpful and good:

  1. Novosoft, C2J: The created Java code needs serious manual work. C2J creates somewhat unreadable code (to have very limited pointer support) and has no support for unsigned types/goto statements/native libraries/macros/comments/...
  2. Tangible Software Solutions, C++2Java: The created Java code needs quite some manual work. C++2Java has no support for pointers/unsigned types/goto statements/native libraries/macros/... (Sachin Bhansali posted the translation of the unecm C code above)
  3. mtSystems, Coot: Creates functionally equivalent code (by having full support for pointers, function pointers, unsigned types, goto statements, native libraries, ...) and readable code (keeps macros/comments, renames identifiers, applies various optimizations, ...).

Here the created class from mtSystems (unaltered):

import static ch.mtsystems.coot.String8.cs8;
import static ch.mtsystems.coot.String8.nnc;

import ch.mtsystems.coot.String8;

import java.io.IOException;
import java.io.RandomAccessFile;

public class Unecm {
    public static void banner() {
        System.err.println("UNECM - Decoder for Error Code Modeler format v1.0\nCopyright (C) 2002 Neill Corlett\n");
    }

    /**
     * LUTs used for computing ECC/EDC
     */
    private static byte[] eccFLut_U = new byte[256];

    private static byte[] eccBLut_U = new byte[256];

    private static int[] edcLut_U = new int[256];

    /**
     * Init routine
     */
    private static void eccedcInit() {
        int j_U, edc_U;
        for(int i_U = 0; Integer.compareUnsigned(i_U, 256) < 0; i_U++) {
            j_U = i_U << 1 ^ ((i_U & 0x80) != 0 ? 0x11D : 0);
            eccFLut_U[i_U] = (byte)j_U;
            eccBLut_U[i_U ^ j_U] = (byte)i_U;
            edc_U = i_U;
            for(j_U = 0; Integer.compareUnsigned(j_U, 8) < 0; j_U++) {
                edc_U = edc_U >>> 1 ^ ((edc_U & 1) != 0 ? 0xD8018001 : 0);
            }
            edcLut_U[i_U] = edc_U;
        }
    }

    /**
     * Compute EDC for a block
     */
    public static int edcPartialComputeblock_U(int edc_U, String8 src_U, short size_U) {
        while(size_U-- != 0) {
            edc_U = edc_U >>> 8 ^ edcLut_U[(edc_U ^ Byte.toUnsignedInt((src_U = nnc(src_U).shift(1)).get(-1))) & 0xFF];
        }
        return edc_U;
    }

    public static void edcComputeblock(String8 src_U, short size_U, String8 dest_U) {
        int edc_U = edcPartialComputeblock_U(0, src_U, size_U);
        dest_U.set(0, (byte)(edc_U >>> 0 & 0xFF));
        dest_U.set(1, (byte)(edc_U >>> 8 & 0xFF));
        dest_U.set(2, (byte)(edc_U >>> 16 & 0xFF));
        dest_U.set(3, (byte)(edc_U >>> 24 & 0xFF));
    }

    /**
     * Compute ECC for a block (can do either P or Q)
     */
    private static void eccComputeblock(String8 src_U, int majorCount_U, int minorCount_U, int majorMult_U, int minorInc_U, String8 dest_U) {
        int size_U = majorCount_U * minorCount_U;
        for(int major_U = 0; Integer.compareUnsigned(major_U, majorCount_U) < 0; major_U++) {
            int index_U = (major_U >>> 1) * majorMult_U + (major_U & 1);
            byte eccA_U = 0;
            byte eccB_U = 0;
            for(int minor_U = 0; Integer.compareUnsigned(minor_U, minorCount_U) < 0; minor_U++) {
                byte temp_U = src_U.get(index_U);
                index_U += minorInc_U;
                if(Integer.compareUnsigned(index_U, size_U) >= 0) {
                    index_U -= size_U;
                }
                eccA_U = (byte)(Byte.toUnsignedInt(eccA_U) ^ Byte.toUnsignedInt(temp_U));
                eccB_U = (byte)(Byte.toUnsignedInt(eccB_U) ^ Byte.toUnsignedInt(temp_U));
                eccA_U = eccFLut_U[Byte.toUnsignedInt(eccA_U)];
            }
            eccA_U = eccBLut_U[Byte.toUnsignedInt(eccFLut_U[Byte.toUnsignedInt(eccA_U)]) ^ Byte.toUnsignedInt(eccB_U)];
            dest_U.set(major_U, eccA_U);
            dest_U.set(major_U + majorCount_U, (byte)(Byte.toUnsignedInt(eccA_U) ^ Byte.toUnsignedInt(eccB_U)));
        }
    }

    /**
     * Generate ECC P and Q codes for a block
     */
    private static void eccGenerate(String8 sector_U, int zeroaddress) {
        byte[] address_U = new byte[4];
        /* Save the address and zero it out */
        if(zeroaddress != 0) {
            for(byte i_U = 0; Byte.toUnsignedInt(i_U) < 4; i_U++) {
                address_U[Byte.toUnsignedInt(i_U)] = sector_U.get(12 + Byte.toUnsignedInt(i_U));
                sector_U.set(12 + Byte.toUnsignedInt(i_U), (byte)0);
            }
        }
        /* Compute ECC P code */
        eccComputeblock(nnc(sector_U).shift(0xC), 86, 24, 2, 86, nnc(sector_U).shift(0x81C));
        /* Compute ECC Q code */
        eccComputeblock(nnc(sector_U).shift(0xC), 52, 43, 86, 88, nnc(sector_U).shift(0x8C8));
        /* Restore the address */
        if(zeroaddress != 0) {
            for(byte i_U = 0; Byte.toUnsignedInt(i_U) < 4; i_U++) {
                sector_U.set(12 + Byte.toUnsignedInt(i_U), address_U[Byte.toUnsignedInt(i_U)]);
            }
        }
    }

    /**
     * Generate ECC/EDC information for a sector (must be 2352 = 0x930 bytes)
     * Returns 0 on success
     */
    public static void eccedcGenerate(String8 sector_U, int type) {
        switch(type) {
        case 1: /* Mode 1 */
            /* Compute EDC */
            edcComputeblock(nnc(sector_U).shift(0x00), (short)0x810, nnc(sector_U).shift(0x810));
            /* Write out zero bytes */
            for(int i_U = 0; Integer.compareUnsigned(i_U, 8) < 0; i_U++) {
                sector_U.set(0x814 + i_U, (byte)0);
            }
            /* Generate ECC P/Q codes */
            eccGenerate(sector_U, 0);
            break;
        case 2: /* Mode 2 form 1 */
            /* Compute EDC */
            edcComputeblock(nnc(sector_U).shift(0x10), (short)0x808, nnc(sector_U).shift(0x818));
            /* Generate ECC P/Q codes */
            eccGenerate(sector_U, 1);
            break;
        case 3: /* Mode 2 form 2 */
            /* Compute EDC */
            edcComputeblock(nnc(sector_U).shift(0x10), (short)0x91C, nnc(sector_U).shift(0x92C));
            break;
        }
    }

    public static int mycounter_U;

    public static int mycounterTotal_U;

    public static void resetcounter(int total_U) {
        mycounter_U = 0;
        mycounterTotal_U = total_U;
    }

    public static void setcounter(int n_U) {
        if(n_U >>> 20 != mycounter_U >>> 20) {
            int a_U = Integer.divideUnsigned(n_U + 64, 128);
            int d_U = Integer.divideUnsigned(mycounterTotal_U + 64, 128);
            if(d_U == 0) {
                d_U = 1;
            }
            System.err.printf("Decoding (%02d%%)\r", Integer.divideUnsigned(100 * a_U, d_U));
        }
        mycounter_U = n_U;
    }

    public static int unecmify(RandomAccessFile in, RandomAccessFile out) throws IOException {
        final int posUneof = 1, posCorrupt = 2;
        positionLoop:
        for(int pos = 0; true;) switch(pos) {
        default:
            int checkedc_U = 0;
            String8 sector_U = new String8(2_352);
            int type_U;
            int num_U;
            in.seek(in.length());
            resetcounter((int)in.getFilePointer());
            in.seek(0);
            if(in.read() != 'E' || in.read() != 'C' || in.read() != 'M' || in.read() != 0x00) {
                System.err.println("Header not found!");
                pos = posCorrupt;
                continue positionLoop;
            }
            for(;;) {
                int c = in.read();
                int bits = 5;
                if(c == -1) {
                    pos = posUneof;
                    continue positionLoop;
                }
                type_U = c & 3;
                num_U = c >> 2 & 0x1F;
                while((c & 0x80) != 0) {
                    c = in.read();
                    if(c == -1) {
                        pos = posUneof;
                        continue positionLoop;
                    }
                    num_U |= (c & 0x7F) << bits;
                    bits += 7;
                }
                if(num_U == 0xFFFFFFFF) {
                    break;
                }
                num_U++;
                if(Integer.compareUnsigned(num_U, 0x80000000) >= 0) {
                    pos = posCorrupt;
                    continue positionLoop;
                }
                if(type_U == 0) {
                    while(num_U != 0) {
                        int b = num_U;
                        if(b > 2_352) {
                            b = 2_352;
                        }
                        byte[] tmpBuf = new byte[b];
                        int readCount = Math.max(in.read(tmpBuf), 0);
                        sector_U.copyFrom(tmpBuf, readCount);
                        if(readCount != b) {
                            pos = posUneof;
                            continue positionLoop;
                        }
                        checkedc_U = edcPartialComputeblock_U(checkedc_U, sector_U, (short)b);
                        byte[] tmpBuf2 = new byte[b];
                        sector_U.copyTo(tmpBuf2);
                        out.write(tmpBuf2);
                        num_U -= b;
                        setcounter((int)in.getFilePointer());
                    }
                } else {
                    while(num_U-- != 0) {
                        sector_U.fill(0, sector_U.size(), (byte)0);
                        sector_U.shift(1).fill(0, 10, (byte)0xFF);
                        switch(type_U) {
                        case 1:
                            sector_U.set(0x0F, (byte)0x01);
                            byte[] tmpBuf = new byte[0x003];
                            int readCount = Math.max(in.read(tmpBuf), 0);
                            nnc(sector_U.shift(0x00C)).copyFrom(tmpBuf, readCount);
                            if(readCount != 0x003) {
                                pos = posUneof;
                                continue positionLoop;
                            }
                            byte[] tmpBuf2 = new byte[0x800];
                            int readCount2 = Math.max(in.read(tmpBuf2), 0);
                            nnc(sector_U.shift(0x010)).copyFrom(tmpBuf2, readCount2);
                            if(readCount2 != 0x800) {
                                pos = posUneof;
                                continue positionLoop;
                            }
                            eccedcGenerate(sector_U, 1);
                            checkedc_U = edcPartialComputeblock_U(checkedc_U, sector_U, (short)2_352);
                            byte[] tmpBuf3 = new byte[2_352];
                            sector_U.copyTo(tmpBuf3);
                            out.write(tmpBuf3);
                            setcounter((int)in.getFilePointer());
                            break;
                        case 2:
                            sector_U.set(0x0F, (byte)0x02);
                            byte[] tmpBuf4 = new byte[0x804];
                            int readCount3 = Math.max(in.read(tmpBuf4), 0);
                            nnc(sector_U.shift(0x014)).copyFrom(tmpBuf4, readCount3);
                            if(readCount3 != 0x804) {
                                pos = posUneof;
                                continue positionLoop;
                            }
                            sector_U.set(0x10, sector_U.get(0x14));
                            sector_U.set(0x11, sector_U.get(0x15));
                            sector_U.set(0x12, sector_U.get(0x16));
                            sector_U.set(0x13, sector_U.get(0x17));
                            eccedcGenerate(sector_U, 2);
                            checkedc_U = edcPartialComputeblock_U(checkedc_U, sector_U.shift(0x10), (short)2_336);
                            byte[] tmpBuf5 = new byte[2_336];
                            sector_U.shift(0x10).copyTo(tmpBuf5);
                            out.write(tmpBuf5);
                            setcounter((int)in.getFilePointer());
                            break;
                        case 3:
                            sector_U.set(0x0F, (byte)0x02);
                            byte[] tmpBuf6 = new byte[0x918];
                            int readCount4 = Math.max(in.read(tmpBuf6), 0);
                            nnc(sector_U.shift(0x014)).copyFrom(tmpBuf6, readCount4);
                            if(readCount4 != 0x918) {
                                pos = posUneof;
                                continue positionLoop;
                            }
                            sector_U.set(0x10, sector_U.get(0x14));
                            sector_U.set(0x11, sector_U.get(0x15));
                            sector_U.set(0x12, sector_U.get(0x16));
                            sector_U.set(0x13, sector_U.get(0x17));
                            eccedcGenerate(sector_U, 3);
                            checkedc_U = edcPartialComputeblock_U(checkedc_U, sector_U.shift(0x10), (short)2_336);
                            byte[] tmpBuf7 = new byte[2_336];
                            sector_U.shift(0x10).copyTo(tmpBuf7);
                            out.write(tmpBuf7);
                            setcounter((int)in.getFilePointer());
                            break;
                        }
                    }
                }
            }
            byte[] tmpBuf = new byte[4];
            int readCount = Math.max(in.read(tmpBuf), 0);
            sector_U.copyFrom(tmpBuf, readCount);
            if(readCount != 4) {
                pos = posUneof;
                continue positionLoop;
            }
            System.err.println("Decoded " + in.getFilePointer() + " bytes -> " + out.getFilePointer() + " bytes");
            if(Byte.toUnsignedInt(sector_U.get(0)) != (checkedc_U >>> 0 & 0xFF) || Byte.toUnsignedInt(sector_U.get(1)) != (checkedc_U >>> 8 & 0xFF) || Byte.toUnsignedInt(sector_U.get(2)) != (checkedc_U >>> 16 & 0xFF) || Byte.toUnsignedInt(sector_U.get(3)) != (checkedc_U >>> 24 & 0xFF)) {
                System.err.printf("EDC error (%08X, should be %02X%02X%02X%02X)\n", checkedc_U, Byte.toUnsignedInt(sector_U.get(3)), Byte.toUnsignedInt(sector_U.get(2)), Byte.toUnsignedInt(sector_U.get(1)), Byte.toUnsignedInt(sector_U.get(0)));
                pos = posCorrupt;
                continue positionLoop;
            }
            System.err.println("Done; file is OK");
            return 0;
        case posUneof:
            System.err.println("Unexpected EOF!");
        case posCorrupt:
            System.err.println("Corrupt ECM file!");
            return 1;
        }
    }

    public static void main(String[] args) throws IOException {
        RandomAccessFile fin, fout;
        String8 infilename;
        String8 outfilename;
        banner();
        /*
         ** Initialize the ECC/EDC tables
         */
        eccedcInit();
        /*
         ** Check command line
         */
        if(args.length != 1 && args.length != 2) {
            System.err.println("usage: " + Unecm.class.getSimpleName() + " ecmfile [outputfile]");
            System.exit(1);
        }
        /*
         ** Verify that the input filename is valid
         */
        infilename = cs8(args[0]);
        if(Integer.compareUnsigned(infilename.length(), 5) < 0) {
            System.err.println("filename '" + infilename + "' is too short");
            System.exit(1);
        }
        if(!nnc(infilename).shift(infilename.length() - 4).equalsIgnoreCase(".ecm")) {
            System.err.println("filename must end in .ecm");
            System.exit(1);
        }
        /*
         ** Figure out what the output filename should be
         */
        if(args.length == 2) {
            outfilename = cs8(args[1]);
        } else {
            outfilename = new String8(true, infilename.length() - 3);
            nnc(outfilename).copyFrom(infilename, infilename.length() - 4);
            outfilename.set(infilename.length() - 4, (byte)0);
        }
        System.err.println("Decoding " + infilename + " to " + outfilename + ".");
        /*
         ** Open both files
         */
        try {
            fin = new RandomAccessFile(infilename.toString(), "r");
        } catch(IOException ex) {
            fin = null;
            ex.printStackTrace();
            System.exit(1);
        }
        try {
            fout = new RandomAccessFile(outfilename.toString(), "rw");
            fout.setLength(0);
        } catch(IOException ex) {
            fout = null;
            ex.printStackTrace();
            fin.close();
            System.exit(1);
        }
        /*
         ** Decode
         */
        unecmify(fin, fout);
        /*
         ** Close everything
         */
        fout.close();
        fin.close();
    }
}
user3669782
  • 797
  • 8
  • 6
5

Have you considered using JNI instead of bothering doing the translation from C to Java?

Catchwa
  • 5,845
  • 4
  • 31
  • 57
  • I have and I am intimidated. At first I tried to compile this for Android, and run it using exec(). I don't think that I compiled it correctly, but didn't know how to test it. Then I looked towards Android NDK and that is just as intimidating. But if you could give me some direction that would be great too. – Aymon Fournier Aug 13 '10 at 04:06
  • 9
    A better idea is to rewrite the C code in Java by hand. JNI introduces a whole stack of issues; e.g. portability, building, JVM stability, etc. – Stephen C Aug 13 '10 at 05:18
  • Are all the functions in the above code able o be translated into Java? – Aymon Fournier Aug 13 '10 at 15:21
  • 1
    @Aymon: Any turing-complete language (which both C and Java are) can represent anything that can be represented in any other turing-complete language. While the syntax and the approach might be different (even wildly different), there's nothing that you can do in terms of input-output in C or Java that you can't do in the other. – Adam Robinson Aug 14 '10 at 16:36
  • 3
    @Adam, but one may be much faster than the other - the Turing-stuff doesn't take time in consideration. – Thorbjørn Ravn Andersen May 18 '11 at 21:27
  • 1
    @Thorbjørn The OP (in his above comment) asked "Are all the functions in the above code able [t]o be translated into Java?", to which the answer is "yes" (as both are Turing-complete). He didn't ask about performance. – Adam Robinson May 19 '11 at 02:14
  • 2
    @Adam, answering with Turing-completeness is only relevant if the OP did not know this already, and then it is important to know the implications. Do you frankly think that performance is unimportant in a program doing bit manipulation to calculate error correcting codes? – Thorbjørn Ravn Andersen May 19 '11 at 05:41
  • 1
    @Thorbjørn As stated, the OP asked if it was possible. That is the question I answered. My comment was not intended to imply that performance was unimportant, though I'm not sure how you could get that from what I said. Given that this question has not had any activity in a year, let's drop this, shall we? – Adam Robinson May 19 '11 at 16:37
  • 1
    @adam, I am not saying that YOU do not think that performance is unimportant, but that if the OP doesn't know about Turing-completeness he probably doesn't know either that time is not considered important here, and that it should be mentioned too. Otherwise it is like saying "yes, you can write an Excel macro emulating a PlayStation 3 because they are Turing-equivalent.". – Thorbjørn Ravn Andersen May 20 '11 at 21:34
4

I used C++ to Java converter to convert above code. It wont be 100% correct but at least it gives fare idea as to what needs to be done.

public class GlobalMembersTest
{
    /*
    ** UNECM - Decoder for ECM (Error Code Modeler) format.
    ** Version 1.0
    ** Copyright (C) 2002 Neill Corlett
    **
    ** 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.
    */
    /***************************************************************************/
    /*
    ** Portability notes:
    **
    ** - Assumes a 32-bit or higher integer size
    ** - No assumptions about byte order
    ** - No assumptions about struct packing
    ** - No unaligned memory access
    */
    /***************************************************************************/
    /***************************************************************************/
    public static void banner()
    {
      fprintf(stderr, "UNECM - Decoder for Error Code Modeler format v1.0\n" + "Copyright (C) 2002 Neill Corlett\n\n");
    }

    /***************************************************************************/

    /* Data types */
    //C++ TO JAVA CONVERTER NOTE: The following #define macro was replaced in-line:
    ///#define ecc_uint8 unsigned char
    //C++ TO JAVA CONVERTER NOTE: The following #define macro was replaced in-line:
    ///#define ecc_uint16 unsigned short
    //C++ TO JAVA CONVERTER NOTE: The following #define macro was replaced in-line:
    ///#define ecc_uint32 unsigned

    /* LUTs used for computing ECC/EDC */
    public static byte[] ecc_f_lut = new byte[256];
    public static byte[] ecc_b_lut = new byte[256];
    public static int[] edc_lut = new int[256];

    /* Init routine */
    public static void eccedc_init()
    {
      int i;
      int j;
      int edc;
      for (i = 0; i < 256; i++)
      {
        j = (i << 1)  (i & 0x80 ? 0x11D : 0);
        ecc_f_lut[i] = j;
        ecc_b_lut[i ^ j] = i;
        edc = i;
        for (j = 0; j < 8; j++)
            edc = (edc >> 1) ^ (edc & 1 ? 0xD8018001 : 0);
        edc_lut[i] = edc;
      }
    }

    /***************************************************************************/
    /*
    ** Compute EDC for a block
    */
    public static int edc_partial_computeblock(int edc, String src, short size)
    {
      while (size--)
          edc = (edc >> 8) ^ edc_lut[(edc ^ (src++)) & 0xFF];
      return edc;
    }

    public static void edc_computeblock(String src, short size, byte[] dest)
    {
      int edc = GlobalMembersTest.edc_partial_computeblock(0, src, size);
      dest[0] = (edc >> 0) & 0xFF;
      dest[1] = (edc >> 8) & 0xFF;
      dest[2] = (edc >> 16) & 0xFF;
      dest[3] = (edc >> 24) & 0xFF;
    }

    /***************************************************************************/
    /*
    ** Compute ECC for a block (can do either P or Q)
    */
    public static void ecc_computeblock(byte[] src, int major_count, int minor_count, int major_mult, int minor_inc, byte[] dest)
    {
      int size = major_count * minor_count;
      int major;
      int minor;
      for (major = 0; major < major_count; major++)
      {
        int index = (major >> 1) * major_mult + (major & 1);
        byte ecc_a = 0;
        byte ecc_b = 0;
        for (minor = 0; minor < minor_count; minor++)
        {
          byte temp = src[index];
          index += minor_inc;
          if (index >= size)
              index -= size;
          ecc_a ^= temp;
          ecc_b ^= temp;
          ecc_a = ecc_f_lut[ecc_a];
        }
        ecc_a = ecc_b_lut[ecc_f_lut[ecc_a] ^ ecc_b];
        dest[major] = ecc_a;
        dest[major + major_count] = ecc_a ^ ecc_b;
      }
    }

    /*
    ** Generate ECC P and Q codes for a block
    */
    public static void ecc_generate(byte[] sector, int zeroaddress)
    {
      byte[] address = new byte[4];
      byte i;
      /* Save the address and zero it out */
      if (zeroaddress != 0)
          for (i = 0; i < 4; i++)
          {
        address[i] = sector[12 + i];
        sector[12 + i] = 0;
          }
      /* Compute ECC P code */
      GlobalMembersTest.ecc_computeblock(sector + 0xC, 86, 24, 2, 86, sector + 0x81C);
      /* Compute ECC Q code */
      GlobalMembersTest.ecc_computeblock(sector + 0xC, 52, 43, 86, 88, sector + 0x8C8);
      /* Restore the address */
      if (zeroaddress != 0)
          for (i = 0; i < 4; i++)
              sector[12 + i] = address[i];
    }

    /***************************************************************************/
    /*
    ** Generate ECC/EDC information for a sector (must be 2352 = 0x930 bytes)
    ** Returns 0 on success
    */
    public static void eccedc_generate(byte[] sector, int type)
    {
      int i;
      switch (type)
      {
      case 1: // Mode 1
        /* Compute EDC */
        GlobalMembersTest.edc_computeblock(sector + 0x00, 0x810, sector + 0x810);
        /* Write out zero bytes */
        for (i = 0; i < 8; i++)
            sector[0x814 + i] = 0;
        /* Generate ECC P/Q codes */
        GlobalMembersTest.ecc_generate(sector, 0);
        break;
      case 2: // Mode 2 form 1
        /* Compute EDC */
        GlobalMembersTest.edc_computeblock(sector + 0x10, 0x808, sector + 0x818);
        /* Generate ECC P/Q codes */
        GlobalMembersTest.ecc_generate(sector, 1);
        break;
      case 3: // Mode 2 form 2
        /* Compute EDC */
        GlobalMembersTest.edc_computeblock(sector + 0x10, 0x91C, sector + 0x92C);
        break;
      }
    }

    /***************************************************************************/

    public static int mycounter;
    public static int mycounter_total;

    public static void resetcounter(int total)
    {
      mycounter = 0;
      mycounter_total = total;
    }

    public static void setcounter(int n)
    {
      if ((n >> 20) != (mycounter >> 20))
      {
        int a = (n + 64) / 128;
        int d = (mycounter_total + 64) / 128;
        if (d == 0)
            d = 1;
        fprintf(stderr, "Decoding (%02d%%)\r", (100 * a) / d);
      }
      mycounter = n;
    }

    public static int unecmify(FILE in, FILE out)
    {
      int checkedc = 0;
      byte[] sector = new byte[2352];
      int type;
      int num;
      fseek(in, 0, SEEK_END);
      GlobalMembersTest.resetcounter(ftell(in));
      fseek(in, 0, SEEK_SET);
      if ((fgetc(in) != 'E') || (fgetc(in) != 'C') || (fgetc(in) != 'M') || (fgetc(in) != 0x00))
      {
        fprintf(stderr, "Header not found!\n");
//C++ TO JAVA CONVERTER TODO TASK: There are no gotos or labels in Java:
        goto corrupt;
      }
      for (;;)
      {
        int c = fgetc(in);
        int bits = 5;
        if (c == EOF)
//C++ TO JAVA CONVERTER TODO TASK: There are no gotos or labels in Java:
            goto uneof;
        type = c & 3;
        num = (c >> 2) & 0x1F;
        while (c & 0x80 != 0)
        {
          c = fgetc(in);
          if (c == EOF)
//C++ TO JAVA CONVERTER TODO TASK: There are no gotos or labels in Java:
              goto uneof;
          num |= ((int)(c & 0x7F)) << bits;
          bits += 7;
        }
        if (num == 0xFFFFFFFF)
            break;
        num++;
        if (num >= 0x80000000)
//C++ TO JAVA CONVERTER TODO TASK: There are no gotos or labels in Java:
            goto corrupt;
        if (type == 0)
        {
          while (num != 0)
          {
            int b = num;
            if (b > 2352)
                b = 2352;
            if (fread(sector, 1, b, in) != b)
//C++ TO JAVA CONVERTER TODO TASK: There are no gotos or labels in Java:
                goto uneof;
            checkedc = GlobalMembersTest.edc_partial_computeblock(checkedc, sector, b);
            fwrite(sector, 1, b, out);
            num -= b;
            GlobalMembersTest.setcounter(ftell(in));
          }
        }
        else
        {
          while (num--)
          {
//C++ TO JAVA CONVERTER TODO TASK: The memory management function 'memset' has no equivalent in Java:
//C++ TO JAVA CONVERTER TODO TASK: There is no Java equivalent to 'sizeof':
            memset(sector, 0, sizeof(sector));
//C++ TO JAVA CONVERTER TODO TASK: The memory management function 'memset' has no equivalent in Java:
            memset(sector + 1, 0xFF, 10);
            switch (type)
            {
            case 1:
              sector[0x0F] = 0x01;
              if (fread(sector + 0x00C, 1, 0x003, in) != 0x003)
//C++ TO JAVA CONVERTER TODO TASK: There are no gotos or labels in Java:
                  goto uneof;
              if (fread(sector + 0x010, 1, 0x800, in) != 0x800)
//C++ TO JAVA CONVERTER TODO TASK: There are no gotos or labels in Java:
                  goto uneof;
              GlobalMembersTest.eccedc_generate(sector, 1);
              checkedc = GlobalMembersTest.edc_partial_computeblock(checkedc, sector, 2352);
              fwrite(sector, 2352, 1, out);
              GlobalMembersTest.setcounter(ftell(in));
              break;
            case 2:
              sector[0x0F] = 0x02;
              if (fread(sector + 0x014, 1, 0x804, in) != 0x804)
//C++ TO JAVA CONVERTER TODO TASK: There are no gotos or labels in Java:
                  goto uneof;
              sector[0x10] = sector[0x14];
              sector[0x11] = sector[0x15];
              sector[0x12] = sector[0x16];
              sector[0x13] = sector[0x17];
              GlobalMembersTest.eccedc_generate(sector, 2);
              checkedc = GlobalMembersTest.edc_partial_computeblock(checkedc, sector + 0x10, 2336);
              fwrite(sector + 0x10, 2336, 1, out);
              GlobalMembersTest.setcounter(ftell(in));
              break;
            case 3:
              sector[0x0F] = 0x02;
              if (fread(sector + 0x014, 1, 0x918, in) != 0x918)
//C++ TO JAVA CONVERTER TODO TASK: There are no gotos or labels in Java:
                  goto uneof;
              sector[0x10] = sector[0x14];
              sector[0x11] = sector[0x15];
              sector[0x12] = sector[0x16];
              sector[0x13] = sector[0x17];
              GlobalMembersTest.eccedc_generate(sector, 3);
              checkedc = GlobalMembersTest.edc_partial_computeblock(checkedc, sector + 0x10, 2336);
              fwrite(sector + 0x10, 2336, 1, out);
              GlobalMembersTest.setcounter(ftell(in));
              break;
            }
          }
        }
      }
      if (fread(sector, 1, 4, in) != 4)
//C++ TO JAVA CONVERTER TODO TASK: There are no gotos or labels in Java:
          goto uneof;
      fprintf(stderr, "Decoded %ld bytes -> %ld bytes\n", ftell(in), ftell(out));
      if ((sector[0] != ((checkedc >> 0) & 0xFF)) || (sector[1] != ((checkedc >> 8) & 0xFF)) || (sector[2] != ((checkedc >> 16) & 0xFF)) || (sector[3] != ((checkedc >> 24) & 0xFF)))
      {
        fprintf(stderr, "EDC error (%08X, should be %02X%02X%02X%02X)\n", checkedc, sector[3], sector[2], sector[1], sector[0]);
//C++ TO JAVA CONVERTER TODO TASK: There are no gotos or labels in Java:
        goto corrupt;
      }
      fprintf(stderr, "Done; file is OK\n");
      return 0;
//C++ TO JAVA CONVERTER TODO TASK: There are no gotos or labels in Java:
    uneof:
      fprintf(stderr, "Unexpected EOF!\n");
//C++ TO JAVA CONVERTER TODO TASK: There are no gotos or labels in Java:
    corrupt:
      fprintf(stderr, "Corrupt ECM file!\n");
      return 1;
    }

    /***************************************************************************/

    public static int Main(int argc, String[] args)
    {
      FILE fin;
      FILE fout;
      String infilename;
      String outfilename;
      GlobalMembersTest.banner();
      /*
      ** Initialize the ECC/EDC tables
      */
      GlobalMembersTest.eccedc_init();
      /*
      ** Check command line
      */
      if ((argc != 2) && (argc != 3))
      {
        fprintf(stderr, "usage: %s ecmfile [outputfile]\n", args[0]);
        return 1;
      }
      /*
      ** Verify that the input filename is valid
      */
      infilename = args[1];
      if (infilename.length() < 5)
      {
        fprintf(stderr, "filename '%s' is too short\n", infilename);
        return 1;
      }
      if (strcasecmp(infilename + infilename.length() - 4, ".ecm"))
      {
        fprintf(stderr, "filename must end in .ecm\n");
        return 1;
      }
      /*
      ** Figure out what the output filename should be
      */
      if (argc == 3)
      {
        outfilename = args[2];
      }
      else
      {
//C++ TO JAVA CONVERTER TODO TASK: The memory management function 'malloc' has no equivalent in Java:
        outfilename = malloc(infilename.length() - 3);
        if (outfilename == null)
            abort();
//C++ TO JAVA CONVERTER TODO TASK: The memory management function 'memcpy' has no equivalent in Java:
        memcpy(outfilename, infilename, infilename.length() - 4);
        outfilename = outfilename.substring(0, infilename.length() - 4);
      }
      fprintf(stderr, "Decoding %s to %s.\n", infilename, outfilename);
      /*
      ** Open both files
      */
      fin = fopen(infilename, "rb");
      if (fin == null)
      {
        perror(infilename);
        return 1;
      }
      fout = fopen(outfilename, "wb");
      if (fout == null)
      {
        perror(outfilename);
        fclose(fin);
        return 1;
      }
      /*
      ** Decode
      */
      GlobalMembersTest.unecmify(fin, fout);
      /*
      ** Close everything
      */
      fclose(fout);
      fclose(fin);
    }
}
Sachin Bhansali
  • 1,372
  • 2
  • 9
  • 12
1

I realized I never posted my solution

In Android Activity:

Public class UnECMActivity extends Activity {
...

    static {
    System.loadLibrary("unecm");
}
private native int rununecm(String fileName);

In unecm.c add:

jint Java_com_romcessed_unecm_UnECMActivity_rununecm(JNIEnv* env, jobject javaThis, jstring fileName) {
  FILE *fin, *fout;
  jboolean *iscopy;
  char *infilename = (*env)->GetStringUTFChars(env, fileName, iscopy);
  char *outfilename;
  banner();
  eccedc_init();

  /*
  ** Verify that the input filename is valid
  */
  if(strlen(infilename) < 5) {
    fprintf(stderr, "filename '%s' is too short\n", infilename);
    return 1;
  }
  if(strcasecmp(infilename + strlen(infilename) - 4, ".ecm")) {
    fprintf(stderr, "filename must end in .ecm\n");
    return 1;
  }

  /*
  ** Figure out what the output filename should be
  */
    outfilename = malloc(strlen(infilename) - 3);
    if(!outfilename) abort();
    memcpy(outfilename, infilename, strlen(infilename) - 4);
    outfilename[strlen(infilename) - 4] = 0;

  fprintf(stderr, "Decoding %s to %s.\n", infilename, outfilename);
  /*
  ** Open both files
  */
  fin = fopen(infilename, "rb");
  if(!fin) {
    perror(infilename);
    return 1;
  }
  fout = fopen(outfilename, "wb");
  if(!fout) {
    perror(outfilename);
    fclose(fin);
    return 1;
  }
  /*
  ** Decode
  */
  unecmify(fin, fout);
  /*
  ** Close everything
  */
  fclose(fout);
  fclose(fin);
  return 0;
}
Aymon Fournier
  • 4,323
  • 12
  • 42
  • 59
1

The question is asking "any tool?", so here is a tool.
Please don't downvote just because you don't like tools.

I tried a C-to-Java conversion tool called "Novosoft C2J". Verdict:

  • Very buggy
  • Crashes often
  • Proprietary (even though it claims "Beta versions of C2J are under GNU license", source code is nowhere to be found)

I managed to convert a C file with few dependencies, but had to "pre-process" it by copy-pasting the content of header files to headers, because C2J won't let me select .h files for inclusion in a project.

Translated code is static, with strange "nextlevel()" and "prevlevel()" calls.
Some translated code needs manual work, for instance: UndefFcs.cisnan([...])

Conclusion: Buggy tool, but it might be the case that there is no better tool.

Nicolas Raoul
  • 58,567
  • 58
  • 222
  • 373