You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UnparsedStructuredField.java 9.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.afp.parser;
  19. import java.io.ByteArrayInputStream;
  20. import java.io.ByteArrayOutputStream;
  21. import java.io.DataInputStream;
  22. import java.io.IOException;
  23. import java.io.OutputStream;
  24. import java.text.DecimalFormat;
  25. /**
  26. * Represents an unparsed (generic) AFP structured field.
  27. */
  28. public final class UnparsedStructuredField {
  29. private final Introducer introducer;
  30. private final byte[] extData;
  31. private final byte[] data;
  32. /**
  33. *
  34. * @param Structured field introducer
  35. * @param data Structured field data
  36. * @param extData Structured field extension data
  37. */
  38. UnparsedStructuredField(Introducer introducer,
  39. byte[] data, byte[] extData) {
  40. this.introducer = introducer;
  41. this.data = data;
  42. if (extData != null) {
  43. this.extData = extData;
  44. } else {
  45. this.extData = null;
  46. }
  47. }
  48. @Override
  49. public String toString() {
  50. StringBuffer sb = new StringBuffer("Structured Field: ");
  51. sb.append(Integer.toHexString(getSfTypeID()).toUpperCase());
  52. sb.append(", len=");
  53. sb.append(new DecimalFormat("00000").format(getSfLength()));
  54. sb.append(" ").append(getTypeCodeAsString());
  55. sb.append(" ").append(getCategoryCodeAsString());
  56. if (isSfiExtensionPresent()) {
  57. sb.append(", SFI extension present");
  58. }
  59. if (isSfiSegmentedData()) {
  60. sb.append(", segmented data");
  61. }
  62. if (isSfiPaddingPresent()) {
  63. sb.append(", with padding");
  64. }
  65. return sb.toString();
  66. }
  67. /**
  68. * Returns type code function name for this field.
  69. * @return the type code function name
  70. */
  71. private String getTypeCodeAsString() {
  72. switch (getSfTypeCode() & 0xFF) {
  73. case 0xA0: return "Attribute";
  74. case 0xA2: return "CopyCount";
  75. case 0xA6: return "Descriptor";
  76. case 0xA7: return "Control";
  77. case 0xA8: return "Begin";
  78. case 0xA9: return "End";
  79. case 0xAB: return "Map";
  80. case 0xAC: return "Position";
  81. case 0xAD: return "Process";
  82. case 0xAF: return "Include";
  83. case 0xB0: return "Table";
  84. case 0xB1: return "Migration";
  85. case 0xB2: return "Variable";
  86. case 0xB4: return "Link";
  87. case 0xEE: return "Data";
  88. default: return "Unknown:" + Integer.toHexString(getSfTypeCode()).toUpperCase();
  89. }
  90. }
  91. /**
  92. * Returns category code function name for this field.
  93. * @return the category code function name
  94. */
  95. private String getCategoryCodeAsString() {
  96. switch (getSfCategoryCode() & 0xFF) {
  97. case 0x5F: return "Page Segment";
  98. case 0x6B: return "Object Area";
  99. case 0x77: return "Color Attribute Table";
  100. case 0x7B: return "IM Image";
  101. case 0x88: return "Medium";
  102. case 0x89: return "Font";
  103. case 0x8A: return "Coded Font";
  104. case 0x90: return "Process Element";
  105. case 0x92: return "Object Container";
  106. case 0x9B: return "Presentation Text";
  107. case 0xA7: return "Index";
  108. case 0xA8: return "Document";
  109. case 0xAD: return "Page Group";
  110. case 0xAF: return "Page";
  111. case 0xBB: return "Graphics";
  112. case 0xC3: return "Data Resource";
  113. case 0xC4: return "Document Environment Group (DEG)";
  114. case 0xC6: return "Resource Group";
  115. case 0xC7: return "Object Environment Group (OEG)";
  116. case 0xC9: return "Active Environment Group (AEG)";
  117. case 0xCC: return "Medium Map";
  118. case 0xCD: return "Form Map";
  119. case 0xCE: return "Name Resource";
  120. case 0xD8: return "Page Overlay";
  121. case 0xD9: return "Resource Environment Group (REG)";
  122. case 0xDF: return "Overlay";
  123. case 0xEA: return "Data Supression";
  124. case 0xEB: return "Bar Code";
  125. case 0xEE: return "No Operation";
  126. case 0xFB: return "Image";
  127. default: return "Unknown:" + Integer.toHexString(getSfTypeCode()).toUpperCase();
  128. }
  129. }
  130. /**
  131. * Returns the structured field's length.
  132. * @return the field length
  133. */
  134. public short getSfLength() {
  135. return introducer.length;
  136. }
  137. /**
  138. * Returns the structured field's identifier.
  139. * @return the field identifier
  140. */
  141. public int getSfTypeID() {
  142. return ((getSfClassCode() & 0xFF) << 16)
  143. | ((getSfTypeCode() & 0xFF) << 8)
  144. | (getSfCategoryCode() & 0xFF);
  145. }
  146. /**
  147. * Returns the structured field's class code.
  148. * @return the field class code
  149. */
  150. public byte getSfClassCode() {
  151. return introducer.classCode;
  152. }
  153. /**
  154. * Returns the structured field's type code.
  155. * @return the type code
  156. */
  157. public byte getSfTypeCode() {
  158. return introducer.typeCode;
  159. }
  160. /**
  161. * Returns the structured field's category code.
  162. * @return the sfCategoryCode
  163. */
  164. public byte getSfCategoryCode() {
  165. return introducer.categoryCode;
  166. }
  167. /**
  168. * Indicates whether an field introducer extension is present.
  169. * @return true if an field introducer extension is present
  170. */
  171. public boolean isSfiExtensionPresent() {
  172. return introducer.extensionPresent && (this.extData != null);
  173. }
  174. /**
  175. * Indicates whether segmented data is present.
  176. * @return true if the data is segmented
  177. */
  178. public boolean isSfiSegmentedData() {
  179. return introducer.segmentedData;
  180. }
  181. /**
  182. * Indicates whether the data is padded.
  183. * @return true if the data is padded
  184. */
  185. public boolean isSfiPaddingPresent() {
  186. return introducer.paddingPresent;
  187. }
  188. /**
  189. * Returns the length of the extension if present.
  190. * @return the length of the extension (or 0 if no extension is present)
  191. */
  192. public short getExtLength() {
  193. return (extData != null) ? (short)(extData.length + 1) : 0;
  194. }
  195. /**
  196. * Returns the extension data if present.
  197. * @return the extension data (or null if no extension is present)
  198. */
  199. byte[] getExtData() {
  200. if (this.extData == null) {
  201. return new byte[0];
  202. }
  203. byte[] rtn = new byte[this.extData.length];
  204. System.arraycopy(this.extData, 0, rtn, 0, rtn.length);
  205. return rtn;
  206. }
  207. /**
  208. * Returns the structured field's payload.
  209. * @return the field's data
  210. */
  211. public byte[] getData() {
  212. if (this.data == null) {
  213. return new byte[0];
  214. }
  215. byte[] rtn = new byte[this.data.length];
  216. System.arraycopy(this.data, 0, rtn, 0, rtn.length);
  217. return rtn;
  218. }
  219. //For unit testing
  220. byte[] getIntroducerData() {
  221. return introducer.getIntroducerData();
  222. }
  223. /**
  224. * Returns the complete structured field as a byte array.
  225. * @return the complete field data
  226. */
  227. public byte[] getCompleteFieldAsBytes() {
  228. ByteArrayOutputStream baos = new ByteArrayOutputStream(getSfLength());
  229. try {
  230. writeTo(baos);
  231. } catch (IOException ioe) {
  232. //nop
  233. }
  234. return baos.toByteArray();
  235. }
  236. /**
  237. * Writes this structured field to the given {@link OutputStream}.
  238. * @param out the output stream
  239. * @throws IOException if an I/O error occurs
  240. */
  241. public void writeTo(OutputStream out) throws IOException {
  242. out.write(introducer.introducerData);
  243. if (isSfiExtensionPresent()) {
  244. out.write(this.extData.length + 1);
  245. out.write(this.extData);
  246. }
  247. out.write(this.data);
  248. }
  249. static final class Introducer {
  250. private final short length;
  251. private final byte classCode;
  252. private final byte typeCode;
  253. private final byte categoryCode;
  254. private final boolean extensionPresent;
  255. private final boolean segmentedData;
  256. private final boolean paddingPresent;
  257. private final byte[] introducerData;
  258. Introducer(byte[] introducerData) throws IOException {
  259. this.introducerData = introducerData;
  260. // Parse the introducer; the 8 bytes have already been read from the stream just
  261. // before, so we parse the introducer from the byte array
  262. DataInputStream iis = new DataInputStream(
  263. new ByteArrayInputStream(introducerData));
  264. length = iis.readShort();
  265. classCode = iis.readByte();
  266. typeCode = iis.readByte();
  267. categoryCode = iis.readByte();
  268. //Flags
  269. byte f = iis.readByte();
  270. extensionPresent = (f & 0x01) != 0;
  271. segmentedData = (f & 0x04) != 0;
  272. paddingPresent = (f & 0x10) != 0;
  273. }
  274. public short getLength() {
  275. return length;
  276. }
  277. public byte getClassCode() {
  278. return classCode;
  279. }
  280. public byte getTypeCode() {
  281. return typeCode;
  282. }
  283. public byte getCategoryCode() {
  284. return categoryCode;
  285. }
  286. public boolean isExtensionPresent() {
  287. return extensionPresent;
  288. }
  289. public boolean isSegmentedData() {
  290. return segmentedData;
  291. }
  292. public boolean isPaddingPresent() {
  293. return paddingPresent;
  294. }
  295. public byte[] getIntroducerData() {
  296. byte[] rtn = new byte[introducerData.length];
  297. System.arraycopy(introducerData, 0, rtn, 0, rtn.length);
  298. return rtn;
  299. }
  300. }
  301. }