package com.pdflib.cookbook.pcos.interactive; import java.io.File; import java.io.FileOutputStream; import java.io.PrintWriter; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import com.pdflib.IpCOS; import com.pdflib.cookbook.pcos.pcos_cookbook_example; /** * Dump package/portfolio properties. The properties are written to stdout * record-by-record. In addition they are written to a CSV file that can be * imported into spreadsheets. *
* Required software: pCOS interface 3 (pCOS 3.x, PDFlib+PDI/PPS 7.x, TET 2.2,
* PLOP 3.x)
* Required data: PDF document that is a package or a portfolio and that has
* package properties
*
* @version $Id: package_properties.java,v 1.13 2015/11/16 11:53:16 stm Exp $
*/
public class package_properties extends pcos_cookbook_example {
/**
* This is where the data files are. Adjust as necessary.
*/
private final static String SEARCH_PATH = "../input";
/**
* The field separator character used in the CSV file output.
*/
private final static char CSV_SEPARATOR_CHAR = ',';
public void example_code(IpCOS p, int doc) throws Exception {
String filename = p.pcos_get_string(doc, "filename");
System.out.println("File name: " + filename);
System.out.println();
/* Check whether the document represents a PDF package */
String colltype = p.pcos_get_string(doc, "type:/Root/Collection");
if (colltype.equals("dict")) {
String defaultdoc;
boolean has_folders = p.pcos_get_string(doc,
"type:/Root/Collection/Folders").equals("dict");
String doctype = has_folders ? "portfolio" : "package";
System.out.print("PDF " + doctype + ", default document: ");
/*
* Check the default document (may be different from container PDF);
* we currently don't check whether this name is actually present in
* the list of embedded files.
*/
if (p.pcos_get_string(doc, "type:/Root/Collection/D").equals(
"string")) {
defaultdoc = "'" + p.pcos_get_string(doc, "/Root/Collection/D")
+ "'";
}
else {
defaultdoc = "container PDF";
}
System.out.println(defaultdoc);
File input_file = new File(filename);
String basename = input_file.getName();
String csv_name = basename + ".csv";
System.out.println("Writing properties also to CSV file \""
+ csv_name + "\"");
PrintWriter csv_file = new PrintWriter(new FileOutputStream(
csv_name));
print_package_properties(p, doc, has_folders, csv_file);
csv_file.close();
}
else {
System.out.println("Input document is not a PDF package");
}
System.out.println();
}
/**
* Description of a CollectionField object (see "TABLE 8.8 Entries in a
* collection field dictionary" in the Adobe PDF Reference 1.7)
*/
private class collection_field {
/**
* A text field.
*/
public final static int TYPE_S = 0;
/**
* A date field.
*/
public final static int TYPE_D = 1;
/**
* A number field.
*/
public final static int TYPE_N = 2;
/**
* The field data is the file name of the embedded file stream.
*/
public final static int TYPE_F = 3;
/**
* The field data is the description of the embedded file stream.
*/
public final static int TYPE_DESC = 4;
/**
* The field data is the modification date of the embedded file stream.
*/
public final static int TYPE_MODDATE = 5;
/**
* The field data is the creation date of the embedded file stream.
*/
public final static int TYPE_CREATIONDATE = 6;
/**
* The field data is the creation date of the embedded file stream.
*/
public final static int TYPE_SIZE = 7;
/**
* The "Subtype" element of the dictionary, one of the above "TYPE_..."
* values.
*/
public int subtype;
/**
* The textual field name that is displayed to the user.
*/
public String display_name;
/**
* The relative order of the field name in the user interface.
*/
public int order;
/**
* The initial visibility of the field in the user interface.
*/
public boolean visibility;
/**
* Whether the field should be editable in the user interface.
*/
public boolean editable;
/**
* Constructor with default values.
*/
public collection_field() {
subtype = -1;
display_name = "";
order = -1;
visibility = true;
editable = false;
}
}
/**
* An array to map the above integer-encoded field types to human-readable
* strings.
*/
public static final String type_names[] = { "text", "date", "number",
"file name", "description", "modification date", "creation date",
"size" };
/**
* Description of a schema dictionary. The class has fixed collection_field
* members for the predefined file-related fields, and a Map that stores the
* custom fields under their name as the key.
*
*/
private class schema_dictionary {
/**
* The number of predefined fields.
*/
public static final int NUMBER_OF_PREDEFINED_FIELDS = 5;
public collection_field predef_f;
public collection_field predef_desc;
public collection_field predef_moddate;
public collection_field predef_creationdate;
public collection_field predef_size;
public Map custom_fields = new HashMap();
/**
* Default constructor that sets the predefined fields to defaults. If a
* schema dictionary is present, it will override the built-in defaults.
*/
public schema_dictionary() {
predef_f = new collection_field();
predef_f.display_name = "Name";
predef_f.editable = true;
predef_f.subtype = collection_field.TYPE_F;
predef_desc = new collection_field();
predef_desc.display_name = "Description";
predef_desc.editable = true;
predef_desc.subtype = collection_field.TYPE_DESC;
predef_moddate = new collection_field();
predef_moddate.display_name = "Modified Date";
predef_moddate.subtype = collection_field.TYPE_MODDATE;
predef_creationdate = new collection_field();
predef_creationdate.display_name = "Creation Date";
predef_creationdate.subtype = collection_field.TYPE_CREATIONDATE;
predef_size = new collection_field();
predef_size.display_name = "Size";
predef_size.subtype = collection_field.TYPE_SIZE;
}
}
/**
* Contains the information of a parsed collection schema dictionary.
*/
private schema_dictionary schema = new schema_dictionary();
/**
* Map of folder IDs to folder names (see "TABLE 8.6c Entries in a folder
* dictionary" in "Adobe Supplement to the ISO 32000 BaseVersion: 1.7
* ExtensionLevel: 3" document)
*
* Every folder in a portfolio has a unique ID. For being able to display a
* folder name for an item in a portfolio, the map is built once by
* analyzing the folder structure under "/Root/Collection/Folders".
*/
private HashMap folders = null;
/**
* Analyze the collection schema dictionary if present, and print out the
* properties of all packages.
*
* @param p
* The {@link IpCOS} object
* @param doc
* A valid document handle
* @param csv_file
* The {@link PrintWriter} object for producing the CSV file
*
* @throws Exception
*/
private void print_package_properties(IpCOS p, int doc, boolean has_folders,
PrintWriter csv_file) throws Exception {
analyze_schema(p, doc);
if (has_folders) {
analyze_folders(p, doc);
}
print_schema_properties();
print_schema_properties(csv_file);
print_properties(p, doc);
print_properties(csv_file, p, doc);
}
/**
* Parse the folder structure under the pCOS path "/Root/Collection/Folders"
* and save the mapping of folder IDs to folder names in the
* {@link #folders folders} member.
*
* @param p
* The {@link IpCOS} object
* @param doc
* A valid document handle
*
* @throws Exception
*/
private void analyze_folders(IpCOS p, int doc) throws Exception {
folders = new HashMap();
/*
* In order to avoid very long pCOS pathnames, we operate with pCOS
* object IDs here.
*/
int root_folder_id = (int) p.pcos_get_number(doc,
"pcosid:/Root/Collection/Folders");
walk_folder_tree(p, doc, root_folder_id, "");
}
/**
* Recursive method to walk the folder tree.
*
* @param p
* The {@link IpCOS} object
* @param doc
* A valid document handle
* @param node_id
* The pCOS object ID of the current folder node
* @param parent_folder_path
* The accumulated pathname for the parent folder
*
* @throws Exception
*/
private void walk_folder_tree(IpCOS p, int doc, int node_id,
String parent_folder_path) throws Exception {
boolean has_next = true;
while (has_next) {
/*
* Actually every folder dictionary should have a /Name entry, but
* we've seen documents where it is missing. For the root folder it
* is usually empty.
*/
String node_path = "objects[" + node_id + "]";
String node_name_path = node_path + "/Name";
String node_name = p.pcos_get_string(doc, "type:" + node_name_path)
.equals("string") ? p.pcos_get_string(doc, node_name_path) : "";
String node_id_path = node_path + "/ID";
int folder_id = (int) p.pcos_get_number(doc, node_id_path);
String separator = parent_folder_path.endsWith("/") ? "" : "/";
String current_path = parent_folder_path + separator + node_name;
folders.put(new Integer(folder_id), current_path);
System.out.println("folder id " + folder_id + " path "
+ current_path);
String child_path = node_path + "/Child";
if (p.pcos_get_string(doc, "type:" + child_path).equals("dict")) {
int child_node_id = (int) p.pcos_get_number(doc, "pcosid:"
+ child_path);
walk_folder_tree(p, doc, child_node_id, current_path);
}
String next_path = node_path + "/Next";
has_next = p.pcos_get_string(doc, "type:" + next_path).equals(
"dict");
if (has_next) {
node_id = (int) p.pcos_get_number(doc, "pcosid:" + next_path);
}
}
}
/**
* Read in a collection field dictionary. Analyze, whether it describes one
* of the predefined properties or a custom property, and save it in the
* {@link #schema} member.
*
* @param p
* The IpCOS object
* @param doc
* A valid document handle
* @param key
* The name of the entry in the collection schema dictionary
* @param value_path
* The pCOS path for the collection field dictionary
*
* @throws Exception
*/
private void read_collection_field(IpCOS p, int doc, String key,
String value_path) throws Exception {
collection_field field = new collection_field();
// The display name is mandatory.
field.display_name = p.pcos_get_string(doc, value_path + "/N");
// The relative order is optional.
String order_path = value_path + "/O";
String objtype = p.pcos_get_string(doc, "type:" + order_path);
if (objtype.equals("integer")) {
field.order = (int) p.pcos_get_number(doc, order_path);
}
// The visibility is optional.
String visibility_path = value_path + "/V";
objtype = p.pcos_get_string(doc, "type:" + visibility_path);
if (objtype.equals("boolean")) {
field.visibility = (int) p.pcos_get_number(doc, visibility_path) != 0;
}
// The editability is optional.
String editable_path = value_path + "/E";
objtype = p.pcos_get_string(doc, "type:" + editable_path);
if (objtype.equals("boolean")) {
field.editable = (int) p.pcos_get_number(doc, editable_path) != 0;
}
// The subtype is required.
String subtype = p.pcos_get_string(doc, value_path + "/Subtype");
if (subtype.equals("S")) {
field.subtype = collection_field.TYPE_S;
schema.custom_fields.put(key, field);
}
else if (subtype.equals("D")) {
field.subtype = collection_field.TYPE_D;
schema.custom_fields.put(key, field);
}
else if (subtype.equals("N")) {
field.subtype = collection_field.TYPE_N;
schema.custom_fields.put(key, field);
}
else if (subtype.equals("F")) {
field.subtype = collection_field.TYPE_F;
schema.predef_f = field;
}
else if (subtype.equals("Desc")) {
field.subtype = collection_field.TYPE_DESC;
schema.predef_desc = field;
}
else if (subtype.equals("ModDate")) {
field.subtype = collection_field.TYPE_MODDATE;
schema.predef_moddate = field;
}
else if (subtype.equals("CreationDate")) {
field.subtype = collection_field.TYPE_CREATIONDATE;
schema.predef_creationdate = field;
}
else if (subtype.equals("Size")) {
field.subtype = collection_field.TYPE_SIZE;
schema.predef_size = field;
}
}
/**
* Read in the collection schema dictionary.
*
* @param p
* The IpCOS object
* @param doc
* A valid document handle
*
* @throws Exception
*/
private void analyze_schema(IpCOS p, int doc) throws Exception {
String schema_path = "/Root/Collection/Schema";
String objtype = p.pcos_get_string(doc, "type:" + schema_path);
if (objtype.equals("dict")) {
int length = (int) p.pcos_get_number(doc, "length:" + schema_path);
for (int i = 0; i < length; i += 1) {
String schema_entry_path = schema_path + "[" + i + "]";
String key = p.pcos_get_string(doc, schema_entry_path + ".key");
String value_path = schema_entry_path + ".val";
objtype = p.pcos_get_string(doc, "type:" + value_path);
if (objtype.equals("dict")) {
read_collection_field(p, doc, key, value_path);
}
else if (key.equals("Type") && objtype.equals("name")) {
String dictionaryType = p.pcos_get_string(doc, value_path);
if (!dictionaryType.equals("CollectionSchema")) {
System.out.println("Illegal type \"" + dictionaryType
+ "\" for collection schema dictionary");
}
}
else {
System.out
.println("Illegal entry in collection schema dictionary "
+ "(key: " + key + ", objtype: " + objtype + ")");
}
}
}
else {
System.out.println("No collection schema dictionary present");
/*
* Try to detect Acrobat 9 Portfolios. At the time this pCOS
* Cookbook example was written, there was no documentation about
* the Portfolio implementation available, so this is done
* heuristically.
*/
String acrobat9_entries[] = { "Folder", "Color", "Navigator",
"Resources" };
boolean acrobat9_assumed = false;
for (int i = 0; i < acrobat9_entries.length && !acrobat9_assumed; i += 1) {
String path = "/Root/Collection/" + acrobat9_entries[i];
objtype = p.pcos_get_string(doc, "type:" + path);
acrobat9_assumed = objtype.equals("dict");
}
if (acrobat9_assumed) {
System.out.println("This looks like an Acrobat 9 Portfolio");
}
}
}
/**
* Print the collection schema. This is a description of all the properties
* that can be attached to the package members.
*
* @throws Exception
*/
private void print_schema_properties() throws Exception {
System.out.println();
System.out.println("Collection schema:");
int property_number = 1;
print_schema_property(property_number++, schema.predef_f, null);
print_schema_property(property_number++, schema.predef_desc, null);
print_schema_property(property_number++, schema.predef_moddate, null);
print_schema_property(property_number++, schema.predef_creationdate,
null);
print_schema_property(property_number++, schema.predef_size, null);
Set customFields = schema.custom_fields.entrySet();
Iterator i = customFields.iterator();
while (i.hasNext()) {
Map.Entry entry = (Map.Entry) i.next();
String key = (String) entry.getKey();
collection_field field_desc = (collection_field) entry.getValue();
print_schema_property(property_number++, field_desc, key);
}
}
/**
* Print the header section of the CSV file that describes the collection
* schema.
*
* @param csv_file
* The {@link PrintWriter} object for producing the CSV file
*/
private void print_schema_properties(PrintWriter csv_file) {
/*
* Add 1 for the first columns with the row description.
*/
int number_of_columns = schema_dictionary.NUMBER_OF_PREDEFINED_FIELDS
+ schema.custom_fields.size() + 1;
/*
* Add 1 for the folder name column if this is a portfolio.
*/
if (folders != null) {
number_of_columns += 1;
}
/*
* Array with the row descriptions for the schema header section.
*/
String row_descriptions[] = { "Field name", "Kind", "Type", "Order",
"Visibility", "Editable" };
/*
* Allocate a two-dimensional String array to make it simpler to write
* out the header section with the schema description.
*/
String schema_header[][] = new String[row_descriptions.length][number_of_columns];
/*
* Transfer row_names.
*/
int column_counter = 0;
for (int i = 0; i < row_descriptions.length; i += 1) {
schema_header[i][column_counter] = row_descriptions[i];
}
/*
* Transfer column for folder name if this is a portfolio.
*/
if (folders != null) {
column_counter += 1;
int row = 0;
schema_header[row++][column_counter] = "Folder";
schema_header[row++][column_counter] = "built-in";
schema_header[row++][column_counter] = "folder name";
schema_header[row++][column_counter] = "
* Files in the "EmbeddedFiles" name tree are linked via a special naming
* convention "<id>filename" to their folders. "id" is the folder id
* that is stored in the folder dictionary.
*
* @param p
* The IpCOS object
* @param doc
* A valid document handle
* @param file_path
* The pCOS path of the EmbeddedFiles entry
*
* @return the folder name
*
* @throws Exception
*/
private String get_folder_path(IpCOS p, int doc, String file_path)
throws Exception {
String folder_link = p.pcos_get_string(doc, file_path + ".key");
/*
* The first character must be the '<' character if the file is
* associated with a folder. The '>' must follow after at least one
* character.
*/
int lt_index = folder_link.indexOf('<');
int gt_index = folder_link.indexOf('>');
/*
* Extract the folder id. If a name does not conform to the rules, the
* file is treated as associated with the root folder.
*/
String folder = "/";
if (lt_index == 0 && gt_index >= 2) {
String folder_id_string = folder_link.substring(1, gt_index);
try {
Integer folder_id = new Integer(folder_id_string);
folder = (String) folders.get(folder_id);
}
catch (NumberFormatException e) {
// Invalid id number in the folder id string, assume root folder
}
}
return folder;
}
/**
* Print out a single property to the CSV file.
*
* @param csv_file
* The CSV file
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param number
* The relative number of the property
* @param file_path
* The pCOS path for the package member
* @param field
* The @{link collection_field} description of the field
* @param key
* The key in the "CI" dictionary for the package member
*
* @throws Exception
*/
private void print_property(PrintWriter csv_file, IpCOS p, int doc,
String file_path, collection_field field, String key)
throws Exception {
switch (field.subtype) {
case collection_field.TYPE_S:
csv_column(csv_file, get_text_field(p, doc, file_path, key));
break;
case collection_field.TYPE_D:
// we print dates as strings
csv_column(csv_file, get_text_field(p, doc, file_path, key));
break;
case collection_field.TYPE_N:
csv_column(csv_file, get_number_field(p, doc, file_path, key));
break;
case collection_field.TYPE_F:
csv_column(csv_file, get_filename(p, doc, file_path));
break;
case collection_field.TYPE_DESC:
csv_column(csv_file, get_description(p, doc, file_path));
break;
case collection_field.TYPE_MODDATE:
csv_column(csv_file, get_moddate(p, doc, file_path));
break;
case collection_field.TYPE_CREATIONDATE:
csv_column(csv_file, get_creationdate(p, doc, file_path));
break;
case collection_field.TYPE_SIZE:
csv_column(csv_file, get_size(p, doc, file_path));
break;
}
}
/**
* Print the properties for a single file to the CSV file.
*
* @param csv_file
* @param p
* The IpCOS object
* @param doc
* A valid document handle
* @param file_index
* The pCOS path for the EmbeddedFiles entry
* @throws Exception
*/
private void print_file_properties(PrintWriter csv_file, IpCOS p, int doc,
String file_path) throws Exception {
if (folders != null) {
csv_column(csv_file, get_folder_path(p, doc, file_path));
}
print_property(csv_file, p, doc, file_path, schema.predef_f, null);
print_property(csv_file, p, doc, file_path, schema.predef_desc, null);
print_property(csv_file, p, doc, file_path, schema.predef_moddate, null);
print_property(csv_file, p, doc, file_path, schema.predef_creationdate,
null);
print_property(csv_file, p, doc, file_path, schema.predef_size, null);
Set customFields = schema.custom_fields.entrySet();
Iterator i = customFields.iterator();
while (i.hasNext()) {
Map.Entry entry = (Map.Entry) i.next();
String key = (String) entry.getKey();
collection_field field_desc = (collection_field) entry.getValue();
print_property(csv_file, p, doc, file_path, field_desc, key);
}
}
/**
* Print out a single property.
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param number
* The relative number of the property
* @param file_path
* The pCOS path for the package member
* @param field
* The @{link collection_field} description of the field
* @param key
* The key in the "CI" dictionary for the package member
*
* @throws Exception
*/
private void print_property(IpCOS p, int doc, int number, String file_path,
collection_field field, String key) throws Exception {
print_formatted("Property number", "" + number);
String value = null;
switch (field.subtype) {
case collection_field.TYPE_S:
value = get_text_field(p, doc, file_path, key);
break;
case collection_field.TYPE_D:
// we print dates as strings
value = get_text_field(p, doc, file_path, key);
break;
case collection_field.TYPE_N:
value = get_number_field(p, doc, file_path, key);
break;
case collection_field.TYPE_F:
value = get_filename(p, doc, file_path);
break;
case collection_field.TYPE_DESC:
value = get_description(p, doc, file_path);
break;
case collection_field.TYPE_MODDATE:
value = get_moddate(p, doc, file_path);
break;
case collection_field.TYPE_CREATIONDATE:
value = get_creationdate(p, doc, file_path);
break;
case collection_field.TYPE_SIZE:
value = get_size(p, doc, file_path);
break;
}
print_formatted("Display name", field.display_name);
print_formatted("Value", value);
}
/**
* Get the size for a package member.
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param file_path
* The pCOS path for the package member
*
* @return The size of the package member in bytes as String
*
* @throws Exception
*/
private String get_size(IpCOS p, int doc, String file_path)
throws Exception {
String size_path = file_path + "/EF/F/Params/Size";
String retval = null;
String objtype = p.pcos_get_string(doc, "type:" + size_path);
if (objtype.equals("number")) {
retval = "" + (int) p.pcos_get_number(doc, size_path);
}
return retval;
}
/**
* Get the creation date of a package member.
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param file_path
* The pCOS path for the package member
*
* @return The creation date in PDF format as String
*
* @throws Exception
*/
private String get_creationdate(IpCOS p, int doc, String file_path)
throws Exception {
return get_date(p, doc, file_path + "/EF/F/Params/CreationDate");
}
/**
* Get the modification date of a package member.
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param file_path
* The pCOS path for the package member
*
* @return The modification date in PDF format as String
*
* @throws Exception
*/
private String get_moddate(IpCOS p, int doc, String file_path)
throws Exception {
return get_date(p, doc, file_path + "/EF/F/Params/ModDate");
}
/**
* Get the date from the given IpCOS path.
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param date_path
* The pCOS path for the desired date
*
* @return The date stored under the given pCOS path if it exists, otherwise
* null
*
* @throws Exception
*/
private String get_date(IpCOS p, int doc, String date_path)
throws Exception {
String retval = null;
String objtype = p.pcos_get_string(doc, "type:" + date_path);
if (objtype.equals("string")) {
retval = p.pcos_get_string(doc, date_path);
}
return retval;
}
/**
* Get the description of a package member.
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param file_path
* The pCOS path of the package member
*
* @return The description for the package member as String if it is
* available, othwise null
*
* @throws Exception
*/
private String get_description(IpCOS p, int doc, String file_path)
throws Exception {
String desc_path = file_path + "/Desc";
String retval = null;
String objtype = p.pcos_get_string(doc, "type:" + desc_path);
if (objtype.equals("string")) {
retval = p.pcos_get_string(doc, desc_path);
}
return retval;
}
/**
* Get the filename of a package member. Only the "UF" and "F" entries are
* examined.
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param file_path
* The pCOS path of the package member
*
* @return The filename of the package member if it exists, otherwise null
*
* @throws Exception
*/
private String get_filename(IpCOS p, int doc, String file_path)
throws Exception {
String fname_paths[] = { file_path + "/UF", file_path + "/F" };
String retval = null;
for (int i = 0; i < fname_paths.length && retval == null; i += 1) {
String objtype = p.pcos_get_string(doc, "type:" + fname_paths[i]);
if (objtype.equals("string")) {
retval = p.pcos_get_string(doc, fname_paths[i]);
}
}
return retval;
}
/**
* Get a custom number field.
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param file_path
* The pCOS path of the package member
* @param key
* The key of the custom field in the collection item dictionary
*
* @return The number as String if it is available, otherwise null
*
* @throws Exception
*/
private String get_number_field(IpCOS p, int doc, String file_path,
String key) throws Exception {
String result = null;
String collection_item_path = file_path + "/CI/" + key;
String objtype = p.pcos_get_string(doc, "type:" + collection_item_path);
if (objtype.equals("number")) {
result = "" + p.pcos_get_number(doc, collection_item_path);
}
else if (objtype.equals("dict")) {
/*
* A "collection subitem dictionary"
*/
String data = "";
String collection_subitem_data_path = collection_item_path + "/D";
objtype = p.pcos_get_string(doc, "type:"
+ collection_subitem_data_path);
if (objtype.equals("number")) {
data = ""
+ p.pcos_get_number(doc, collection_subitem_data_path);
}
String prefix = "";
String collection_subitem_prefix_path = collection_item_path + "/P";
objtype = p.pcos_get_string(doc, "type:"
+ collection_subitem_prefix_path);
if (objtype.equals("string")) {
prefix = p.pcos_get_string(doc, collection_subitem_prefix_path);
}
result = prefix + data;
}
return result;
}
/**
* Get a custom text field. This is also used for date fields.
*
* @param p
* An IpCOS object
* @param doc
* A valid document handle
* @param file_path
* The pCOS path of the package member
* @param key
* The key of the custom field in the collection item dictionary
*
* @return The text/date as String if it is available, otherwise null
*
* @throws Exception
*/
private String get_text_field(IpCOS p, int doc, String file_path, String key)
throws Exception {
String result = null;
String collection_item_path = file_path + "/CI/" + key;
String objtype = p.pcos_get_string(doc, "type:" + collection_item_path);
if (objtype.equals("string")) {
result = p.pcos_get_string(doc, collection_item_path);
}
else if (objtype.equals("dict")) {
/*
* A "collection subitem dictionary"
*/
String data = "";
String collection_subitem_data_path = collection_item_path + "/D";
objtype = p.pcos_get_string(doc, "type:"
+ collection_subitem_data_path);
if (objtype.equals("string")) {
data = p.pcos_get_string(doc, collection_subitem_data_path);
}
String prefix = "";
String collection_subitem_prefix_path = collection_item_path + "/P";
objtype = p.pcos_get_string(doc, "type:"
+ collection_subitem_prefix_path);
if (objtype.equals("string")) {
prefix = p.pcos_get_string(doc, collection_subitem_prefix_path);
}
result = prefix + data;
}
return result;
}
/**
* Constant for aligning all the labels in the output.
*/
private static final int DESC_WIDTH = 20;
/**
* Print label/value pairs, aligned using the {@link #DESC_WIDTH} constant.
*
* @param description
* The label
* @param value
* The value
*/
private void print_formatted(String description, String value) {
StringBuffer b = new StringBuffer();
for (int i = description.length(); i < DESC_WIDTH; i += 1) {
b.append(' ');
}
b.append(description);
b.append(": ");
b.append(value != null ? value : "