Source code: com/flexstor/flexdbserver/services/asset/iptc/IPTCParser.java
1 /*
2 * IPTCParser.java
3 *
4 * Copyright $Date: 2003/08/11 02:22:34 $ FLEXSTOR.net Inc.
5 *
6 * This work is licensed for use and distribution under license terms found at
7 * http://www.flexstor.org/license.html
8 *
9 */
10
11 package com.flexstor.flexdbserver.services.asset.iptc;
12
13 import java.util.Hashtable;
14
15 /**
16 *
17 * @author bparks
18 * @version initial
19 */
20 public class IPTCParser extends Object {
21
22 protected Hashtable hDataSets = null;
23
24
25 /** Creates new IPTCParser */
26 public IPTCParser() {
27 hDataSets = new Hashtable();
28 }
29
30
31 protected boolean parseIPTCdata( byte [] abIPTCrecord ) {
32 // loop through the byte array and get the data out of it
33 int nArrayIndex = 0;
34 byte bTagMarker = -1;
35 int nByteCount = -1;
36 String sDataSetID = null;
37 String sDataSetValue = null;
38
39 while ( nArrayIndex < abIPTCrecord.length ) {
40
41 bTagMarker = abIPTCrecord[nArrayIndex];
42 // increment the array index after reading the tag marker
43 nArrayIndex++;
44
45 // The end of the buffer may contain padded 0's which will give a tag marker
46 // error when there really isn't one. Just ignore them.
47 if ( bTagMarker == 0)
48 {
49 continue;
50 }
51
52 // If the tag marker is not 0x1c, this is not valid IPTC-NAA record data
53 if( bTagMarker != 0x1c ) {
54 BGPError( "IPTC tag marker not valid" );
55 return false;
56
57 } else {
58
59 // convert the next two bytes (the Record Number and DataSet Number) to
60 // the format "RR:DDD" The document titled "IPTC-NAA Information
61 // Interchange Model Version 4" document has these numbers in decimal so
62 // it will be easier to read if we use decimal here too.
63 sDataSetID = new String( Integer.toString( abIPTCrecord[nArrayIndex] ) + ":" +
64 Integer.toString( abIPTCrecord[nArrayIndex+1] ) );
65 // increment the array index after reading those two bytes
66 nArrayIndex+=2;
67
68 // Obtain the length of the data field. TODO: There is some special handling
69 // that needs to happen if the length of the data field is greater than
70 // 32767 octets. This is documented on page 15 of the IPTC-NAA IIMV4 doc.
71 nByteCount = hexBytesToInt( abIPTCrecord, nArrayIndex, 2 );
72 // increment the array index after reading those two bytes
73 nArrayIndex+=2;
74
75 // The next nByteCount bytes are what make up our data field value.
76 sDataSetValue = new String( abIPTCrecord, nArrayIndex, nByteCount );
77 //BGPDebug( "DataSetValue is [" + sDataSetValue + "]" );
78 // Increment the array index after reading the data set's data field
79 nArrayIndex+=nByteCount;
80
81 // Place the sDataSetID key and the sDataSetValue into our hashtable.
82 // There are some DataSets which can be repeated throughout our data.
83 // For those cases, just append a comma and the additional value
84 if ( hDataSets.get( sDataSetID ) == null ) {
85 // If it doesn't exist in our hashtable, create it.
86 hDataSets.put( sDataSetID, sDataSetValue );
87 } else {
88 // If it does exist, append a comma and the additional value
89 String sNewValue = null;
90 sNewValue = new String( ((String)hDataSets.get( sDataSetID )) +
91 ", " + sDataSetValue );
92 // and store it back in the hashtable
93 hDataSets.put( sDataSetID, sNewValue );
94 }
95
96 }
97
98 } // end of while loop
99 return true;
100
101 } // end of parseIPTCdata method
102
103 /** This method converts part of an array of bytes into an integer value.
104 * (For our purposes, we will not exceed four bytes.)
105 * @param abHexBytes The array of bytes. Some of which we will convert to an int.
106 * @param nStartPos The start of our byte value that will be converted.
107 * @param nLength The number of bytes that will be converted
108 * @return Returns an int value of the specifiec portion of our byte array.
109 * (i.e. {0x1C, 0x2B} would be converted to 7211)
110 */
111 protected int hexBytesToInt (byte abHexBytes[], int nStartPos, int nLength) {
112
113 // The soon-to-be-computed value of the byte array.
114 int nBytesValue = 0;
115
116 // The number of bits that need to get shifted is equal to one less than the
117 // number of bytes times eight. (i.e. 0x01, 0xC2 : the first byte 0x01 needs
118 // to be shifted 8 bits to the left before it is added to the second byte 0xC2.
119 int nBitShifter = ( (nLength - 1) * 8 );
120
121 // process each of the bytes in turn.
122 for ( int i=0; i < nLength; i++ ) {
123 //BGPDebug( "byte " + i + " is " + abHexBytes[ nStartPos+i ] +
124 // ", and nBitShifter is " + nBitShifter);
125 // arithmatic is always performed at least at 32-bit precision. This has the
126 // side effect of un-signing our signed byte before we bitshift.
127 nBytesValue |= (( abHexBytes[ nStartPos+i ] & 0x000000ff ) << nBitShifter );
128 // Each byte we process, we need to adjust the distance the bits are shifted.
129 nBitShifter = nBitShifter - 8;
130 }
131 return nBytesValue;
132 }
133
134
135 /** Quick (and easily changeable) way of printing an error.
136 * @param sErrorMsg The error string to print
137 */
138 protected void BGPError (String sErrorMsg) {
139 System.out.println (sErrorMsg);
140 }
141
142
143 /** Quick (and easily changeable) way of printing a debug statement.
144 * @param sDebugMsg The debug string to print.
145 */
146 protected void BGPDebug (String sDebugMsg) {
147 System.out.println ("{DEBUG: " + sDebugMsg + "}");
148 }
149
150 }