All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mdbtools.libmdb.Table Maven / Gradle / Ivy

Go to download

Java API to handle Microsoft MDB format (Access). Used by Bio-Formats for Zeiss LSM metadata in MDB files.

There is a newer version: 5.3.3
Show newest version
/*
 * #%L
 * Fork of MDB Tools (Java port).
 * %%
 * Copyright (C) 2008 - 2016 Open Microscopy Environment:
 *   - Board of Regents of the University of Wisconsin-Madison
 *   - Glencoe Software, Inc.
 *   - University of Dundee
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as 
 * published by the Free Software Foundation, either version 2.1 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 Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public 
 * License along with this program.  If not, see
 * .
 * #L%
 */

package mdbtools.libmdb;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;

public class Table
{
  public static MdbTableDef mdb_read_table(MdbCatalogEntry entry)
    throws IOException
  {
    MdbTableDef table = null;
    MdbHandle mdb = entry.mdb;
    MdbFormatConstants fmt = mdb.fmt;
    int len;
    int rownum, row_start, row_end;

//    System.out.println("start of mdb_read_table");

    table = mem.mdb_alloc_tabledef(entry);

    file.mdb_read_pg(mdb, entry.table_pg);
    len = file.mdb_get_int16(mdb,8);

    table.num_rows = file.mdb_get_int32(mdb, fmt.tab_num_rows_offset);
    table.num_cols = file.mdb_get_int16(mdb, fmt.tab_num_cols_offset);
    table.num_idxs = file.mdb_get_int32(mdb, fmt.tab_num_idxs_offset);
    table.num_real_idxs = file.mdb_get_int32(mdb, fmt.tab_num_ridxs_offset);

    /* grab a copy of the usage map */
    rownum = mdb.pg_buf[fmt.tab_usage_map_offset];
//System.out.println("tab_usage_map_offset: " + fmt.tab_usage_map_offset);
//System.out.println("====alt offset: " + file.mdb_get_int24(mdb, fmt.tab_usage_map_offset + 1));
    file.mdb_read_alt_pg(mdb, file.mdb_get_int24(mdb, fmt.tab_usage_map_offset + 1));
    file.mdb_swap_pgbuf(mdb);
//int offset = ((fmt.row_count_offset + 2) + (rownum*2));
//System.out.println("====: offset: " + offset);
//System.out.println("[offset]: " + file.unsign(mdb.pg_buf[offset]));
//System.out.println("[offset+1]: " + file.unsign(mdb.pg_buf[offset+1]));
    row_start = file.mdb_get_int16(mdb, (fmt.row_count_offset + 2) + (rownum*2));
    row_end = Data.mdb_find_end_of_row(mdb, rownum);
    table.map_sz = row_end - row_start + 1;
    table.usage_map = new byte[table.map_sz];
//    System.out.println("==== row start: " + row_start);
//    System.out.println("====: " + mdb.pg_buf[row_start]);
    System.arraycopy(mdb.pg_buf,row_start,table.usage_map,0,table.map_sz);
    /* swap back */
    file.mdb_swap_pgbuf(mdb);
    table.first_data_pg = file.mdb_get_int16(mdb, fmt.tab_first_dpg_offset);

//System.out.println("end of mdb_read_table");
    return table;
  }

  public static ArrayList mdb_read_columns(MdbTableDef table)
    throws IOException
  {
    MdbHandle mdb = table.entry.mdb;
    MdbFormatConstants fmt = mdb.fmt;
    MdbColumn col, pcol;
    int len, i,j;
    byte low_byte, high_byte;
    int cur_col, cur_name;
    int name_sz;
    LinkedList  slist = new LinkedList();
    Holder pm = new Holder();

    table.columns = new ArrayList();

    cur_col = fmt.tab_cols_start_offset +
              (table.num_real_idxs * fmt.tab_ridx_entry_size);

    /* new code based on patch submitted by Tim Nelson 2000.09.27 */

    /*
    ** column attributes
    */
    for (i = 0 ;i < table.num_cols;i++)
    {
      col = new MdbColumn();
      col.col_num = mdb.pg_buf[cur_col + fmt.col_num_offset];

      pm.i = cur_col;
      read_pg_if(mdb, pm, 0);
      cur_col = pm.i;

      col.col_type = mdb.pg_buf[cur_col];

      if (col.col_type == Constants.MDB_NUMERIC)
      {
        col.col_prec = mdb.pg_buf[cur_col + 11];
        col.col_scale = mdb.pg_buf[cur_col + 12];
      }

      pm.i = cur_col;
      read_pg_if(mdb, pm, 13);
      cur_col = pm.i;
      col.is_fixed = (mdb.pg_buf[cur_col + fmt.col_fixed_offset] & 0x01) != 0 ? true : false;
      if (col.col_type != Constants.MDB_BOOL)
      {
        pm.i = cur_col;
        read_pg_if(mdb, pm, 17);
        cur_col = pm.i;

        low_byte = mdb.pg_buf[cur_col + fmt.col_size_offset];

        pm.i = cur_col;
        read_pg_if(mdb, pm, 18);
        cur_col = pm.i;

        high_byte = mdb.pg_buf[cur_col + fmt.col_size_offset + 1];
        col.col_size += file.unsign(high_byte) * 256 + file.unsign(low_byte);
//        col.col_size += file.unsign(low_byte) * 256 + file.unsign(high_byte);
      }
      else
        col.col_size=0;

      pcol = col;
//      pcol = (MdbColumn)col.clone();
//      System.out.println("add pcol: col_size: "+pcol.col_size);
//      slist = g_slist_insert_sorted(slist,pcol,(GCompareFunc)mdb_col_comparer);
      slist.add(pcol);  // +++ crs +++ just add will sort the whole thing later
      cur_col += fmt.tab_col_entry_size;
    }

    // +++ crs +++ sort the list === this is done so as to not
    // have to compare during the insert - how does java do that anyway?
    Collections.sort(slist,new Comparator()
      {
        public int compare(Object o1, Object o2)
        {
          MdbColumn a = (MdbColumn)o1;
          MdbColumn b = (MdbColumn)o2;

          if (a.col_num > b.col_num)
            return 1;
          else if (a.col_num < b.col_num)
            return -1;
          else
            return 0;
        }

        public boolean equals(Object obj)
        {
          throw new RuntimeException("equals is not implemented");
        }
      });

    cur_name = cur_col;

    /*
    ** column names
    */
    for (i = 0;i < table.num_cols;i++)
    {
      /* fetch the column */
      pcol = (MdbColumn)slist.get(i);

      /* we have reached the end of page */
      pm.i = cur_col;
      read_pg_if(mdb, pm, 0);
      cur_col = pm.i;

      name_sz = mdb.pg_buf[cur_name];

      if (macros.IS_JET4(mdb))
      {
//        if (cur_name < 0)
//          System.out.println("hi");
        /* FIX ME - for now just skip the high order byte */
        cur_name += 2;
        /* determine amount of name on this page */
        len = ((cur_name + name_sz) > fmt.pg_size) ?
        fmt.pg_size - cur_name :
        name_sz;

        /** @todo +++CRS+++ since the name is unicode and java is unicode
         *        support the unicode instead of stripping it
         */
        char[] name = new char[Constants.MDB_MAX_OBJ_NAME+1];
        int nameIndex = 0;
        /* strip high order (second) byte from unicode string */
        for (j = 0; j < len;j += 2)
          name[nameIndex++] = (char)mdb.pg_buf[cur_name + j];
        /* name wrapped over page */
        if (len < name_sz)
        {
//          /* read the next pg */
//          file.mdb_read_pg(mdb, file.mdb_get_int32(mdb,4));
//          cur_name = 8 - (fmt.pg_size - cur_name);
//          if (len % 2 != 0)
//            cur_name++;
//          /* get the rest of the name */
//          for (j = 0;j < (name_sz - len);j++)
//          {
//            if (cur_name < 0)
//              System.out.println("hi");
//            name[nameIndex++] = (char)mdb.pg_buf[cur_name+j];
//          }

                        file.mdb_read_pg(mdb, file.mdb_get_int32(mdb,4));
                        cur_name = 8 - (fmt.pg_size - cur_name);
                        /* get the rest of the name */
                        for (j=len;j fmt.pg_size) ? fmt.pg_size - cur_name : name_sz;

        if (len > 0)
        {
          pcol.name = new String(mdb.pg_buf,cur_name+1,len);
//            memcpy(pcol->name, &mdb->pg_buf[cur_name+1], len);
        }
        else
          pcol.name = "";
        /* name wrapped over page */
        if (len < name_sz)
        {
          /* read the next pg */
          file.mdb_read_pg(mdb, file.mdb_get_int32(mdb,4));
          cur_name = 8 - (fmt.pg_size - cur_name);
          /* get the rest of the name */
          int strlen = name_sz - len;
          if (cur_name < 0) cur_name = 0;
          if (strlen < 0) strlen = 0;
          if (strlen + cur_name >= mdb.pg_buf.length) {
            strlen = mdb.pg_buf.length - cur_name;
          }
          pcol.name += new String(mdb.pg_buf,cur_name,strlen);
//          memcpy(&pcol.name[len], &mdb->pg_buf[cur_name], name_sz - len);
        }
//        pcol->name[name_sz]='\0';

        cur_name += name_sz + 1;
      }
      else
      {
        throw new RuntimeException("Unknown MDB version");
      }
    }

    /* turn this list into an array */
    for (i = 0;i < table.num_cols;i++)
    {
      pcol = (MdbColumn)slist.get(i);
      table.columns.add(pcol);
    }

    table.index_start = cur_name;
    return table.columns;
  }

  /*
  ** read the next page if offset is > pg_size
  ** return true if page was read
  */
  private static int read_pg_if(MdbHandle mdb, Holder cur_pos, int offset)
    throws IOException
  {
    if (cur_pos.i + offset >= mdb.fmt.pg_size)
    {
      file.mdb_read_pg(mdb, file.mdb_get_int32(mdb,4));
      cur_pos.i = 8 - (mdb.fmt.pg_size - cur_pos.i);
      return 1;
    }
    return 0;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy