PageRenderTime 43ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/ITextSharp.Silverlight/iTextSharp/text/pdf/FdfWriter.cs

#
C# | 345 lines | 222 code | 21 blank | 102 comment | 45 complexity | a8fba3eb12877a2f507ebfe448934619 MD5 | raw file
  1. using System;
  2. using System.util;
  3. using System.IO;
  4. using System.Collections.Generic;
  5. /*
  6. * This file is part of the iText project.
  7. * Copyright (c) 1998-2009 1T3XT BVBA
  8. * Authors: Bruno Lowagie, Paulo Soares, et al.
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU Affero General Public License version 3
  12. * as published by the Free Software Foundation with the addition of the
  13. * following permission added to Section 15 as permitted in Section 7(a):
  14. * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT,
  15. * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
  16. *
  17. * This program is distributed in the hope that it will be useful, but
  18. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  19. * or FITNESS FOR A PARTICULAR PURPOSE.
  20. * See the GNU Affero General Public License for more details.
  21. * You should have received a copy of the GNU Affero General Public License
  22. * along with this program; if not, see http://www.gnu.org/licenses or write to
  23. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  24. * Boston, MA, 02110-1301 USA, or download the license from the following URL:
  25. * http://itextpdf.com/terms-of-use/
  26. *
  27. * The interactive user interfaces in modified source and object code versions
  28. * of this program must display Appropriate Legal Notices, as required under
  29. * Section 5 of the GNU Affero General Public License.
  30. *
  31. * In accordance with Section 7(b) of the GNU Affero General Public License,
  32. * you must retain the producer line in every PDF that is created or manipulated
  33. * using iText.
  34. *
  35. * You can be released from the requirements of the license by purchasing
  36. * a commercial license. Buying such a license is mandatory as soon as you
  37. * develop commercial activities involving the iText software without
  38. * disclosing the source code of your own applications.
  39. * These activities include: offering paid services to customers as an ASP,
  40. * serving PDFs on the fly in a web application, shipping iText with a closed
  41. * source product.
  42. *
  43. * For more information, please contact iText Software Corp. at this
  44. * address: sales@itextpdf.com
  45. */
  46. namespace iTextSharp.text.pdf {
  47. /** Writes an FDF form.
  48. * @author Paulo Soares
  49. */
  50. public class FdfWriter {
  51. private static readonly byte[] HEADER_FDF = DocWriter.GetISOBytes("%FDF-1.4\n%\u00e2\u00e3\u00cf\u00d3\n");
  52. Dictionary<String, Object> fields = new Dictionary<string,object>();
  53. /** The PDF file associated with the FDF. */
  54. private String file;
  55. /** Creates a new FdfWriter. */
  56. public FdfWriter() {
  57. }
  58. /** Writes the content to a stream.
  59. * @param os the stream
  60. * @throws DocumentException on error
  61. * @throws IOException on error
  62. */
  63. public void WriteTo(Stream os) {
  64. Wrt wrt = new Wrt(os, this);
  65. wrt.WriteTo();
  66. }
  67. internal bool SetField(String field, PdfObject value) {
  68. Dictionary<String, Object> map = fields;
  69. StringTokenizer tk = new StringTokenizer(field, ".");
  70. if (!tk.HasMoreTokens())
  71. return false;
  72. while (true) {
  73. String s = tk.NextToken();
  74. Object obj;
  75. map.TryGetValue(s, out obj);
  76. if (tk.HasMoreTokens()) {
  77. if (obj == null) {
  78. obj = new Dictionary<String, Object>();
  79. map[s] = obj;
  80. map = (Dictionary<string,object>)obj;
  81. continue;
  82. }
  83. else if (obj is Dictionary<String, Object>)
  84. map = (Dictionary<String, Object>)obj;
  85. else
  86. return false;
  87. }
  88. else {
  89. if (!(obj is Dictionary<String, Object>)) {
  90. map[s] = value;
  91. return true;
  92. }
  93. else
  94. return false;
  95. }
  96. }
  97. }
  98. internal void IterateFields(Dictionary<String, Object> values, Dictionary<String, Object> map, String name) {
  99. foreach (KeyValuePair<String, Object> entry in map) {
  100. String s = entry.Key;
  101. Object obj = entry.Value;
  102. if (obj is Dictionary<String, Object>)
  103. IterateFields(values, (Dictionary<String, Object>)obj, name + "." + s);
  104. else
  105. values[(name + "." + s).Substring(1)] = obj;
  106. }
  107. }
  108. /** Removes the field value.
  109. * @param field the field name
  110. * @return <CODE>true</CODE> if the field was found and removed,
  111. * <CODE>false</CODE> otherwise
  112. */
  113. public bool RemoveField(String field) {
  114. Dictionary<String, Object> map = fields;
  115. StringTokenizer tk = new StringTokenizer(field, ".");
  116. if (!tk.HasMoreTokens())
  117. return false;
  118. List<object> hist = new List<object>();
  119. while (true) {
  120. String s = tk.NextToken();
  121. Object obj;
  122. map.TryGetValue(s, out obj);
  123. if (obj == null)
  124. return false;
  125. hist.Add(map);
  126. hist.Add(s);
  127. if (tk.HasMoreTokens()) {
  128. if (obj is Dictionary<String, Object>)
  129. map = (Dictionary<String, Object>)obj;
  130. else
  131. return false;
  132. }
  133. else {
  134. if (obj is Dictionary<String, Object>)
  135. return false;
  136. else
  137. break;
  138. }
  139. }
  140. for (int k = hist.Count - 2; k >= 0; k -= 2) {
  141. map = (Dictionary<String, Object>)hist[k];
  142. String s = (String)hist[k + 1];
  143. map.Remove(s);
  144. if (map.Count > 0)
  145. break;
  146. }
  147. return true;
  148. }
  149. /** Gets all the fields. The map is keyed by the fully qualified
  150. * field name and the values are <CODE>PdfObject</CODE>.
  151. * @return a map with all the fields
  152. */
  153. public Dictionary<String, Object> GetFields() {
  154. Dictionary<String, Object> values = new Dictionary<String, Object>();
  155. IterateFields(values, fields, "");
  156. return values;
  157. }
  158. /** Gets the field value.
  159. * @param field the field name
  160. * @return the field value or <CODE>null</CODE> if not found
  161. */
  162. public String GetField(String field) {
  163. Dictionary<String, Object> map = fields;
  164. StringTokenizer tk = new StringTokenizer(field, ".");
  165. if (!tk.HasMoreTokens())
  166. return null;
  167. while (true) {
  168. String s = tk.NextToken();
  169. Object obj;
  170. map.TryGetValue(s, out obj);
  171. if (obj == null)
  172. return null;
  173. if (tk.HasMoreTokens()) {
  174. if (obj is Dictionary<String, Object>)
  175. map = (Dictionary<String, Object>)obj;
  176. else
  177. return null;
  178. }
  179. else {
  180. if (obj is Dictionary<String, Object>)
  181. return null;
  182. else {
  183. if (((PdfObject)obj).IsString())
  184. return ((PdfString)obj).ToUnicodeString();
  185. else
  186. return PdfName.DecodeName(obj.ToString());
  187. }
  188. }
  189. }
  190. }
  191. /** Sets the field value as a name.
  192. * @param field the fully qualified field name
  193. * @param value the value
  194. * @return <CODE>true</CODE> if the value was inserted,
  195. * <CODE>false</CODE> if the name is incompatible with
  196. * an existing field
  197. */
  198. public bool SetFieldAsName(String field, String value) {
  199. return SetField(field, new PdfName(value));
  200. }
  201. /** Sets the field value as a string.
  202. * @param field the fully qualified field name
  203. * @param value the value
  204. * @return <CODE>true</CODE> if the value was inserted,
  205. * <CODE>false</CODE> if the name is incompatible with
  206. * an existing field
  207. */
  208. public bool SetFieldAsString(String field, String value) {
  209. return SetField(field, new PdfString(value, PdfObject.TEXT_UNICODE));
  210. }
  211. /**
  212. * Sets the field value as a <CODE>PDFAction</CODE>.
  213. * For example, this method allows setting a form submit button action using {@link PdfAction#createSubmitForm(String, Object[], int)}.
  214. * This method creates an <CODE>A</CODE> entry for the specified field in the underlying FDF file.
  215. * Method contributed by Philippe Laflamme (plaflamme)
  216. * @param field the fully qualified field name
  217. * @param action the field's action
  218. * @return <CODE>true</CODE> if the value was inserted,
  219. * <CODE>false</CODE> if the name is incompatible with
  220. * an existing field
  221. * @since 2.1.5
  222. */
  223. public bool SetFieldAsAction(String field, PdfAction action) {
  224. return SetField(field, action);
  225. }
  226. /** Sets all the fields from this <CODE>FdfReader</CODE>
  227. * @param fdf the <CODE>FdfReader</CODE>
  228. */
  229. public void SetFields(FdfReader fdf) {
  230. Dictionary<String, PdfDictionary> map = fdf.Fields;
  231. foreach (KeyValuePair<string,PdfDictionary> entry in map) {
  232. String key = entry.Key;
  233. PdfDictionary dic = entry.Value;
  234. PdfObject v = dic.Get(PdfName.V);
  235. if (v != null) {
  236. SetField(key, v);
  237. }
  238. v = dic.Get(PdfName.A); // (plaflamme)
  239. if (v != null) {
  240. SetField(key, v);
  241. }
  242. }
  243. }
  244. /** Sets all the fields from this <CODE>PdfReader</CODE>
  245. * @param pdf the <CODE>PdfReader</CODE>
  246. */
  247. public void SetFields(PdfReader pdf) {
  248. SetFields(pdf.AcroFields);
  249. }
  250. /** Sets all the fields from this <CODE>AcroFields</CODE>
  251. * @param acro the <CODE>AcroFields</CODE>
  252. */
  253. public void SetFields(AcroFields af) {
  254. foreach (KeyValuePair<string,AcroFields.Item> entry in af.Fields) {
  255. String fn = entry.Key;
  256. AcroFields.Item item = entry.Value;
  257. PdfDictionary dic = item.GetMerged(0);
  258. PdfObject v = PdfReader.GetPdfObjectRelease(dic.Get(PdfName.V));
  259. if (v == null)
  260. continue;
  261. PdfObject ft = PdfReader.GetPdfObjectRelease(dic.Get(PdfName.FT));
  262. if (ft == null || PdfName.SIG.Equals(ft))
  263. continue;
  264. SetField(fn, v);
  265. }
  266. }
  267. /** Gets the PDF file name associated with the FDF.
  268. * @return the PDF file name associated with the FDF
  269. */
  270. public String File {
  271. get {
  272. return this.file;
  273. }
  274. set {
  275. file = value;
  276. }
  277. }
  278. internal class Wrt : PdfWriter {
  279. private FdfWriter fdf;
  280. internal Wrt(Stream os, FdfWriter fdf) : base(new PdfDocument(), os) {
  281. this.fdf = fdf;
  282. this.os.Write(HEADER_FDF, 0, HEADER_FDF.Length);
  283. body = new PdfBody(this);
  284. }
  285. internal void WriteTo() {
  286. PdfDictionary dic = new PdfDictionary();
  287. dic.Put(PdfName.FIELDS, Calculate(fdf.fields));
  288. if (fdf.file != null)
  289. dic.Put(PdfName.F, new PdfString(fdf.file, PdfObject.TEXT_UNICODE));
  290. PdfDictionary fd = new PdfDictionary();
  291. fd.Put(PdfName.FDF, dic);
  292. PdfIndirectReference refi = AddToBody(fd).IndirectReference;
  293. byte[] b = GetISOBytes("trailer\n");
  294. os.Write(b, 0, b.Length);
  295. PdfDictionary trailer = new PdfDictionary();
  296. trailer.Put(PdfName.ROOT, refi);
  297. trailer.ToPdf(null, os);
  298. b = GetISOBytes("\n%%EOF\n");
  299. os.Write(b, 0, b.Length);
  300. os.Close();
  301. }
  302. internal PdfArray Calculate(Dictionary<String, Object> map) {
  303. PdfArray ar = new PdfArray();
  304. foreach (KeyValuePair<String, Object> entry in map) {
  305. String key = entry.Key;
  306. Object v = entry.Value;
  307. PdfDictionary dic = new PdfDictionary();
  308. dic.Put(PdfName.T, new PdfString(key, PdfObject.TEXT_UNICODE));
  309. if (v is Dictionary<String, Object>) {
  310. dic.Put(PdfName.KIDS, Calculate((Dictionary<String, Object>)v));
  311. }
  312. else if (v is PdfAction) { // (plaflamme)
  313. dic.Put(PdfName.A, (PdfAction)v);
  314. }
  315. else {
  316. dic.Put(PdfName.V, (PdfObject)v);
  317. }
  318. ar.Add(dic);
  319. }
  320. return ar;
  321. }
  322. }
  323. }
  324. }