using System; using System.Collections.Generic; using System.IO; using System.Text; using CLR; using iTextSharp.text.pdf; namespace PDFPatcher.Model { static class PdfModelHelper { internal static T Locate(this PdfDictionary source, params object[] path) where T : PdfObject { PdfObject s = source; if (s == null) { return null; } PdfName n; foreach (var item in path) { n = item as PdfName; if (s == null) { return null; } if (n != null) { if (s.Type != PdfObject.DICTIONARY && s.Type != PdfObject.STREAM) { return null; } s = ((PdfDictionary)s).GetDirectObject(n); continue; } if (item is not int) { throw new ArgumentException("参数类型必须为 Int32 或 PdfName"); } int i = (int)item; if (s.Type != PdfObject.ARRAY) { return null; } s = ((PdfArray)s).GetDirectObject(i); } return s as T; } internal static T Locate(this PdfDictionary source, params PdfName[] path) where T : PdfObject { return source.Locate(true, path); } internal static T Locate(this PdfDictionary source, bool resolveRef, params PdfName[] path) where T : PdfObject { PdfObject o = null; foreach (var item in path) { if (source == null) { return null; } o = resolveRef ? source.GetDirectObject(item) : source.Get(item); source = o as PdfDictionary; } return o as T; } internal static T Locate(this PdfArray source, int index) where T : PdfObject { return source.Locate(true, index); } internal static T Locate(this PdfArray source, bool resolveRef, int index) where T : PdfObject { if (source == null) { return null; } return (resolveRef ? source.GetDirectObject(index) : source[index]) as T; } internal static T CastAs(this PdfIndirectReference pdfRef) where T : PdfObject { return PdfReader.GetPdfObject(pdfRef) as T; } internal static float ValueAsFloat(this PdfObject obj) { return obj is PdfNumber n ? n.FloatValue : 0; } internal static float ValueAsInt(this PdfObject obj) { return obj is PdfNumber n ? n.IntValue : 0; } internal static bool ValueIs(this PdfNumber obj, double value) { return obj != null && obj.DoubleValue == value; } internal static bool ValueIs(this PdfBoolean obj, bool value) { return obj != null && obj.BooleanValue == value; } internal static bool ValueIs(this PdfObject obj, PdfName value) { return value.Equals(obj); } internal static int TryGetInt32(this PdfDictionary source, PdfName key, int defaultValue) { var w = source.GetAsNumber(key); return w?.IntValue ?? defaultValue; } internal static bool TryGetBoolean(this PdfDictionary source, PdfName key, bool defaultValue) { var b = source.GetAsBoolean(key); return b?.BooleanValue ?? defaultValue; } internal static string Decode(this PdfString text, Encoding encoding) { if (text == null) { return String.Empty; } var bytes = text.GetBytes(); using (var ms = new MemoryStream(bytes)) { if (encoding == null) { if (bytes.Length >= 2 && Op.Cast(ref bytes[0]).CeqAny(0xFFFE, 0xFEFF)) { // bytes 以 0xFEFF 或 0xFFFE 开头 using (var r = new StreamReader(ms, true)) { return r.ReadToEnd(); } } else { return PdfEncodings.ConvertToString(bytes, PdfObject.TEXT_PDFDOCENCODING); } } else { // 跳过字节顺序标记 if (bytes.Length >= 2 && Op.Cast(ref bytes[0]).CeqAny(0xFFFE, 0xFEFF)) { // bytes 以 0xFEFF 或 0xFFFE 开头 ms.Position += 2; } else if (bytes.Length >= 3 && bytes[0] == 0xef && bytes[1] == 0xbb && bytes[2] == 0xbf) { ms.Position += 3; } else if (bytes.Length >= 4 && Op.Cast(ref bytes[0]) == 0xFFFE0000) { // bytes 以 0000FEFF 开头 ms.Position += 4; } using (var r = new StreamReader(ms, encoding)) { return r.ReadToEnd(); } } } } internal static PdfString ToPdfString(this string text) { if (String.IsNullOrEmpty(text)) { return new PdfString(); } bool u = false; foreach (var c in text) { if (c > 127) { u = true; break; } } return u ? new PdfString(text, PdfObject.TEXT_UNICODE) : new PdfString(text); } internal static IEnumerable GetReferencedResources(PdfDictionary source, Predicate predicate, HashSet refDedup) { foreach (var item in source) { if (item.Value is PdfIndirectReference r && refDedup.Add(r) && PdfReader.GetPdfObjectRelease(r) is PdfDictionary o) { if (predicate(o)) { yield return new ResourceReference(r, item.Key, o); } foreach (var f in GetReferencedResources(o, predicate, refDedup)) { yield return f; } } else if (item.Value is PdfDictionary d) { foreach (var f in GetReferencedResources(d, predicate, refDedup)) { yield return f; } } } } } }