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

net.sf.mpxj.mpp.CustomFieldValueReader9 Maven / Gradle / Ivy

Go to download

Library that provides facilities to allow project information to be manipulated in Java and .Net. Supports a range of data formats: Microsoft Project Exchange (MPX), Microsoft Project (MPP,MPT), Microsoft Project Data Interchange (MSPDI XML), Microsoft Project Database (MPD), Planner (XML), Primavera (PM XML, XER, and database), Asta Powerproject (PP, MDB), Asta Easyplan (PP), Phoenix Project Manager (PPX), FastTrack Schedule (FTS), and the Standard Data Exchange Format (SDEF).

There is a newer version: 13.8.0
Show newest version
/*
 * file:       CustomFieldValueReader12.java
 * author:     Jon Iles
 * copyright:  (c) Packwood Software 2015
 * date:       28/04/2015
 */

/*
 * This library 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 library 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 Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 */

package net.sf.mpxj.mpp;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import net.sf.mpxj.CustomField;
import net.sf.mpxj.CustomFieldContainer;
import net.sf.mpxj.CustomFieldLookupTable;
import net.sf.mpxj.DataType;
import net.sf.mpxj.Duration;
import net.sf.mpxj.FieldType;
import net.sf.mpxj.ProjectProperties;
import net.sf.mpxj.TimeUnit;
import net.sf.mpxj.common.FieldTypeHelper;

/**
 * MPP9 custom field value reader.
 */
public class CustomFieldValueReader9
{
   /**
    * Constructor.
    *
    * @param properties MPXJ project properties
    * @param projectProps MPP project properties
    * @param container cusotm field container
    */
   public CustomFieldValueReader9(ProjectProperties properties, Props projectProps, CustomFieldContainer container)
   {
      m_properties = properties;
      m_projectProps = projectProps;
      m_container = container;
   }

   /**
    * Reads custom field values and populates container.
    */
   public void process()
   {
      byte[] data = m_projectProps.getByteArray(Props.TASK_FIELD_ATTRIBUTES);
      if (data != null)
      {
         int index = 0;
         int offset = 0;
         // First the length
         int length = MPPUtility.getInt(data, offset);
         offset += 4;
         // Then the number of custom value lists
         int numberOfValueLists = MPPUtility.getInt(data, offset);
         offset += 4;

         // Then the value lists themselves
         FieldType field;
         int valueListOffset = 0;
         while (index < numberOfValueLists && offset < length)
         {
            // Each item consists of the Field ID (4 bytes) and the offset to the value list (4 bytes)

            // Get the Field
            field = FieldTypeHelper.getInstance(MPPUtility.getInt(data, offset));
            offset += 4;

            // Get the value list offset
            valueListOffset = MPPUtility.getInt(data, offset);
            offset += 4;
            // Read the value list itself
            if (valueListOffset < data.length)
            {
               int tempOffset = valueListOffset;
               tempOffset += 8;
               // Get the data offset
               int dataOffset = MPPUtility.getInt(data, tempOffset) + valueListOffset;
               tempOffset += 4;
               // Get the end of the data offset
               int endDataOffset = MPPUtility.getInt(data, tempOffset) + valueListOffset;
               tempOffset += 4;
               // Get the end of the description
               int endDescriptionOffset = MPPUtility.getInt(data, tempOffset) + valueListOffset;

               // Get the values themselves
               int valuesLength = endDataOffset - dataOffset;
               byte[] values = new byte[valuesLength];
               MPPUtility.getByteArray(data, dataOffset, valuesLength, values, 0);

               // Get the descriptions
               int descriptionsLength = endDescriptionOffset - endDataOffset;
               byte[] descriptions = new byte[descriptionsLength];
               MPPUtility.getByteArray(data, endDataOffset, descriptionsLength, descriptions, 0);

               populateContainer(field, values, descriptions);
            }
            index++;
         }
      }
   }

   /**
    * Populate the container, converting raw data into Java types.
    *
    * @param field custom field to which these values belong
    * @param values raw value data
    * @param descriptions raw description data
    */
   private void populateContainer(FieldType field, byte[] values, byte[] descriptions)
   {
      CustomField config = m_container.getCustomField(field);
      CustomFieldLookupTable table = config.getLookupTable();

      List descriptionList = convertType(DataType.STRING, descriptions);
      List valueList = convertType(field.getDataType(), values);
      for (int index = 0; index < descriptionList.size(); index++)
      {
         CustomFieldValueItem item = new CustomFieldValueItem(Integer.valueOf(0));
         item.setDescription((String) descriptionList.get(index));
         if (index < valueList.size())
         {
            item.setValue(valueList.get(index));
         }
         table.add(item);
      }
   }

   /**
    * Convert raw data into Java types.
    *
    * @param type data type
    * @param data raw data
    * @return list of Java object
    */
   private List convertType(DataType type, byte[] data)
   {
      List result = new ArrayList();
      int index = 0;

      while (index < data.length)
      {
         switch (type)
         {
            case STRING:
            {
               String value = MPPUtility.getUnicodeString(data, index);
               result.add(value);
               index += ((value.length() + 1) * 2);
               break;
            }

            case CURRENCY:
            {
               Double value = Double.valueOf(MPPUtility.getDouble(data, index) / 100);
               result.add(value);
               index += 8;
               break;
            }

            case NUMERIC:
            {
               Double value = Double.valueOf(MPPUtility.getDouble(data, index));
               result.add(value);
               index += 8;
               break;
            }

            case DATE:
            {
               Date value = MPPUtility.getTimestamp(data, index);
               result.add(value);
               index += 4;
               break;

            }

            case DURATION:
            {
               TimeUnit units = MPPUtility.getDurationTimeUnits(MPPUtility.getShort(data, index + 4), m_properties.getDefaultDurationUnits());
               Duration value = MPPUtility.getAdjustedDuration(m_properties, MPPUtility.getInt(data, index), units);
               result.add(value);
               index += 6;
               break;
            }

            case BOOLEAN:
            {
               Boolean value = Boolean.valueOf(MPPUtility.getShort(data, index) == 1);
               result.add(value);
               index += 2;
               break;
            }

            default:
            {
               index = data.length;
               break;
            }
         }
      }

      return result;
   }

   private final ProjectProperties m_properties;
   private final Props m_projectProps;
   private final CustomFieldContainer m_container;
}