Ejemplo n.º 1
0
        private (bool isChecked, NameToken stateName) GetCheckedState(DictionaryToken fieldDictionary, bool inheritsValue)
        {
            var isChecked = false;

            if (!fieldDictionary.TryGetOptionalTokenDirect(NameToken.V, tokenScanner, out NameToken valueToken))
            {
                if (fieldDictionary.TryGetOptionalTokenDirect(NameToken.As, tokenScanner, out NameToken appearanceStateName) &&
                    fieldDictionary.TryGetOptionalTokenDirect(NameToken.Ap, tokenScanner, out DictionaryToken _))
                {
                    // Issue #267 - Use the set appearance instead, this might not work for 3 state checkboxes.
                    isChecked = !string.Equals(
                        appearanceStateName.Data,
                        NameToken.Off,
                        StringComparison.OrdinalIgnoreCase);
                    valueToken = appearanceStateName;
                    return(isChecked, valueToken);
                }
                valueToken = NameToken.Off;
            }
            else if (inheritsValue && fieldDictionary.TryGet(NameToken.As, tokenScanner, out NameToken appearanceStateName))
            {
                // The parent field's V entry holds a name object corresponding to the
                // appearance state of whichever child field is currently in the on state.
                isChecked  = appearanceStateName.Equals(valueToken);
                valueToken = appearanceStateName;
            }
            else
            {
                isChecked = !string.Equals(valueToken.Data, NameToken.Off, StringComparison.OrdinalIgnoreCase);
            }

            return(isChecked, valueToken);
        }
Ejemplo n.º 2
0
        private AcroFieldBase GetTextField(DictionaryToken fieldDictionary, NameToken fieldType, uint fieldFlags, AcroFieldCommonInformation information)
        {
            var textFlags = (AcroTextFieldFlags)fieldFlags;

            var textValue = default(string);

            if (fieldDictionary.TryGet(NameToken.V, out var textValueToken))
            {
                if (DirectObjectFinder.TryGet(textValueToken, tokenScanner, out StringToken valueStringToken))
                {
                    textValue = valueStringToken.Data;
                }
                else if (DirectObjectFinder.TryGet(textValueToken, tokenScanner, out HexToken valueHexToken))
                {
                    textValue = valueHexToken.Data;
                }
                else if (DirectObjectFinder.TryGet(textValueToken, tokenScanner, out StreamToken valueStreamToken))
                {
                    textValue = OtherEncodings.BytesAsLatin1String(valueStreamToken.Decode(filterProvider).ToArray());
                }
            }

            var maxLength = default(int?);

            if (fieldDictionary.TryGetOptionalTokenDirect(NameToken.MaxLen, tokenScanner, out NumericToken maxLenToken))
            {
                maxLength = maxLenToken.Int;
            }

            var field = new AcroTextField(fieldDictionary, fieldType, textFlags, information, textValue, maxLength);

            return(field);
        }
Ejemplo n.º 3
0
        public static bool TryGetOptionalStringDirect(this DictionaryToken token, NameToken name, IPdfTokenScanner scanner, out string result)
        {
            result = default(string);
            if (token.TryGetOptionalTokenDirect(name, scanner, out StringToken stringToken))
            {
                result = stringToken.Data;
                return(true);
            }

            if (token.TryGetOptionalTokenDirect(name, scanner, out HexToken hexToken))
            {
                result = hexToken.Data;
                return(true);
            }

            return(false);
        }
Ejemplo n.º 4
0
        private AcroFieldBase GetChoiceField(DictionaryToken fieldDictionary, NameToken fieldType,
                                             uint fieldFlags,
                                             AcroFieldCommonInformation information,
                                             int?pageNumber,
                                             PdfRectangle?bounds)
        {
            var selectedOptions = EmptyArray <string> .Instance;

            if (fieldDictionary.TryGet(NameToken.V, out var valueToken))
            {
                if (DirectObjectFinder.TryGet(valueToken, tokenScanner, out StringToken valueString))
                {
                    selectedOptions = new[] { valueString.Data };
                }
                else if (DirectObjectFinder.TryGet(valueToken, tokenScanner, out HexToken valueHex))
                {
                    selectedOptions = new[] { valueHex.Data };
                }
                else if (DirectObjectFinder.TryGet(valueToken, tokenScanner, out ArrayToken valueArray))
                {
                    selectedOptions = new string[valueArray.Length];
                    for (var i = 0; i < valueArray.Length; i++)
                    {
                        var valueOptToken = valueArray.Data[i];

                        if (DirectObjectFinder.TryGet(valueOptToken, tokenScanner, out StringToken valueOptString))
                        {
                            selectedOptions[i] = valueOptString.Data;
                        }
                        else if (DirectObjectFinder.TryGet(valueOptToken, tokenScanner, out HexToken valueOptHex))
                        {
                            selectedOptions[i] = valueOptHex.Data;
                        }
                    }
                }
            }

            var selectedIndices = default(int[]);

            if (fieldDictionary.TryGetOptionalTokenDirect(NameToken.I, tokenScanner, out ArrayToken indicesArray))
            {
                selectedIndices = new int[indicesArray.Length];
                for (var i = 0; i < indicesArray.Data.Count; i++)
                {
                    var token        = indicesArray.Data[i];
                    var numericToken = DirectObjectFinder.Get <NumericToken>(token, tokenScanner);
                    selectedIndices[i] = numericToken.Int;
                }
            }

            var options = new List <AcroChoiceOption>();

            if (fieldDictionary.TryGetOptionalTokenDirect(NameToken.Opt, tokenScanner, out ArrayToken optionsArrayToken))
            {
                for (var i = 0; i < optionsArrayToken.Data.Count; i++)
                {
                    var optionToken = optionsArrayToken.Data[i];
                    if (DirectObjectFinder.TryGet(optionToken, tokenScanner, out StringToken optionStringToken))
                    {
                        var name       = optionStringToken.Data;
                        var isSelected = IsChoiceSelected(selectedOptions, selectedIndices, i, name);
                        options.Add(new AcroChoiceOption(i, isSelected, optionStringToken.Data));
                    }
                    else if (DirectObjectFinder.TryGet(optionToken, tokenScanner, out HexToken optionHexToken))
                    {
                        var name       = optionHexToken.Data;
                        var isSelected = IsChoiceSelected(selectedOptions, selectedIndices, i, name);
                        options.Add(new AcroChoiceOption(i, isSelected, optionHexToken.Data));
                    }
                    else if (DirectObjectFinder.TryGet(optionToken, tokenScanner, out ArrayToken optionArrayToken))
                    {
                        if (optionArrayToken.Length != 2)
                        {
                            throw new PdfDocumentFormatException($"An option array containing array elements should contain 2 strings, instead got: {optionArrayToken}.");
                        }

                        string exportValue;
                        if (DirectObjectFinder.TryGet(optionArrayToken.Data[0], tokenScanner, out StringToken exportValueStringToken))
                        {
                            exportValue = exportValueStringToken.Data;
                        }
                        else if (DirectObjectFinder.TryGet(optionArrayToken.Data[0], tokenScanner, out HexToken exportValueHexToken))
                        {
                            exportValue = exportValueHexToken.Data;
                        }
                        else
                        {
                            throw new PdfDocumentFormatException($"An option array array element's first value should be the export value string, instead got: {optionArrayToken.Data[0]}.");
                        }

                        string name;
                        if (DirectObjectFinder.TryGet(optionArrayToken.Data[1], tokenScanner, out StringToken nameStringToken))
                        {
                            name = nameStringToken.Data;
                        }
                        else if (DirectObjectFinder.TryGet(optionArrayToken.Data[1], tokenScanner, out HexToken nameHexToken))
                        {
                            name = nameHexToken.Data;
                        }
                        else
                        {
                            throw new PdfDocumentFormatException($"An option array array element's second value should be the option name string, instead got: {optionArrayToken.Data[1]}.");
                        }

                        var isSelected = IsChoiceSelected(selectedOptions, selectedIndices, i, name);
                        options.Add(new AcroChoiceOption(i, isSelected, name, exportValue));
                    }
                    else
                    {
                        throw new PdfDocumentFormatException($"An option array should contain either strings or 2 element arrays, instead got: {optionToken}.");
                    }
                }
            }

            var choiceFlags = (AcroChoiceFieldFlags)fieldFlags;

            if (choiceFlags.HasFlag(AcroChoiceFieldFlags.Combo))
            {
                var field = new AcroComboBoxField(fieldDictionary, fieldType, choiceFlags, information,
                                                  options,
                                                  selectedOptions,
                                                  selectedIndices,
                                                  pageNumber,
                                                  bounds);
                return(field);
            }

            var topIndex = default(int?);

            if (fieldDictionary.TryGetOptionalTokenDirect(NameToken.Ti, tokenScanner, out NumericToken topIndexToken))
            {
                topIndex = topIndexToken.Int;
            }

            return(new AcroListBoxField(fieldDictionary, fieldType, choiceFlags, information,
                                        options,
                                        selectedOptions,
                                        selectedIndices,
                                        topIndex,
                                        pageNumber,
                                        bounds));
        }
Ejemplo n.º 5
0
        private AcroFieldBase GetAcroField(DictionaryToken fieldDictionary, Catalog catalog,
                                           IReadOnlyList <DictionaryToken> parentDictionaries)
        {
            var(combinedFieldDictionary, inheritsValue) = CreateInheritedDictionary(fieldDictionary, parentDictionaries);

            fieldDictionary = combinedFieldDictionary;

            fieldDictionary.TryGet(NameToken.Ft, tokenScanner, out NameToken fieldType);
            fieldDictionary.TryGet(NameToken.Ff, tokenScanner, out NumericToken fieldFlagsToken);

            var kids = new List <(bool hasParent, DictionaryToken dictionary)>();

            if (fieldDictionary.TryGetOptionalTokenDirect(NameToken.Kids, tokenScanner, out ArrayToken kidsToken))
            {
                foreach (var kid in kidsToken.Data)
                {
                    if (!(kid is IndirectReferenceToken kidReferenceToken))
                    {
                        throw new PdfDocumentFormatException($"AcroForm kids should only contain indirect reference, instead got: {kid}.");
                    }

                    var kidObject = tokenScanner.Get(kidReferenceToken.Data);

                    if (kidObject.Data is DictionaryToken kidDictionaryToken)
                    {
                        var hasParent = kidDictionaryToken.TryGet(NameToken.Parent, out IndirectReferenceToken _);
                        kids.Add((hasParent, kidDictionaryToken));
                    }
                    else
                    {
                        throw new PdfDocumentFormatException($"Unexpected type of kid in AcroForm field. Expected dictionary but got: {kidObject.Data}.");
                    }
                }
            }

            fieldDictionary.TryGetOptionalStringDirect(NameToken.T, tokenScanner, out var partialFieldName);
            fieldDictionary.TryGetOptionalStringDirect(NameToken.Tu, tokenScanner, out var alternateFieldName);
            fieldDictionary.TryGetOptionalStringDirect(NameToken.Tm, tokenScanner, out var mappingName);
            fieldDictionary.TryGet(NameToken.Parent, out IndirectReferenceToken parentReferenceToken);
            var information = new AcroFieldCommonInformation(parentReferenceToken?.Data, partialFieldName, alternateFieldName, mappingName);

            int?pageNumber = null;

            if (fieldDictionary.TryGet(NameToken.P, tokenScanner, out IndirectReferenceToken pageReference))
            {
                pageNumber = catalog.GetPageByReference(pageReference.Data)?.PageNumber;
            }

            PdfRectangle?bounds = null;

            if (fieldDictionary.TryGet(NameToken.Rect, tokenScanner, out ArrayToken rectArray) && rectArray.Length == 4)
            {
                bounds = rectArray.ToRectangle(tokenScanner);
            }

            var newParentDictionaries = new List <DictionaryToken>(parentDictionaries)
            {
                fieldDictionary
            };

            var children = new List <AcroFieldBase>(kids.Count);

            foreach (var kid in kids)
            {
                if (!kid.hasParent)
                {
                    // Is a widget annotation dictionary.
                    continue;
                }

                children.Add(GetAcroField(kid.dictionary, catalog, newParentDictionaries));
            }

            var fieldFlags = (uint)(fieldFlagsToken?.Long ?? 0);

            AcroFieldBase result;

            if (fieldType == null)
            {
                result = new AcroNonTerminalField(fieldDictionary, "Non-Terminal Field", fieldFlags, information, AcroFieldType.Unknown, children);
            }
            else if (fieldType == NameToken.Btn)
            {
                var buttonFlags = (AcroButtonFieldFlags)fieldFlags;

                if (buttonFlags.HasFlag(AcroButtonFieldFlags.Radio))
                {
                    if (children.Count > 0)
                    {
                        result = new AcroRadioButtonsField(fieldDictionary, fieldType, buttonFlags, information,
                                                           children);
                    }
                    else
                    {
                        var(isChecked, valueToken) = GetCheckedState(fieldDictionary, inheritsValue);

                        var field = new AcroRadioButtonField(fieldDictionary, fieldType, buttonFlags, information,
                                                             pageNumber,
                                                             bounds,
                                                             valueToken,
                                                             isChecked);

                        result = field;
                    }
                }
                else if (buttonFlags.HasFlag(AcroButtonFieldFlags.PushButton))
                {
                    var field = new AcroPushButtonField(fieldDictionary, fieldType, buttonFlags, information,
                                                        pageNumber,
                                                        bounds);
                    result = field;
                }
                else
                {
                    if (children.Count > 0)
                    {
                        result = new AcroCheckboxesField(fieldDictionary, fieldType, buttonFlags, information,
                                                         children);
                    }
                    else
                    {
                        var(isChecked, valueToken) = GetCheckedState(fieldDictionary, inheritsValue);
                        var field = new AcroCheckboxField(fieldDictionary, fieldType, buttonFlags, information,
                                                          valueToken,
                                                          isChecked,
                                                          pageNumber,
                                                          bounds);

                        result = field;
                    }
                }
            }
            else if (fieldType == NameToken.Tx)
            {
                result = GetTextField(fieldDictionary, fieldType, fieldFlags, information, pageNumber, bounds);
            }
            else if (fieldType == NameToken.Ch)
            {
                result = GetChoiceField(fieldDictionary, fieldType, fieldFlags, information,
                                        pageNumber,
                                        bounds);
            }
            else if (fieldType == NameToken.Sig)
            {
                var field = new AcroSignatureField(fieldDictionary, fieldType, fieldFlags, information,
                                                   pageNumber,
                                                   bounds);
                result = field;
            }
            else
            {
                throw new PdfDocumentFormatException($"Unexpected type for field in AcroForm: {fieldType}.");
            }

            return(result);
        }
Ejemplo n.º 6
0
        public IFont Generate(DictionaryToken dictionary, bool isLenientParsing)
        {
            if (!dictionary.TryGetOptionalTokenDirect(NameToken.FirstChar, pdfScanner, out NumericToken firstCharacterToken) ||
                !dictionary.TryGet <IToken>(NameToken.FontDescriptor, pdfScanner, out _) ||
                !dictionary.TryGet(NameToken.Widths, out IToken _))
            {
                if (!dictionary.TryGetOptionalTokenDirect(NameToken.BaseFont, pdfScanner, out NameToken baseFont))
                {
                    throw new InvalidFontFormatException($"The provided TrueType font dictionary did not contain a /FirstChar or a /BaseFont entry: {dictionary}.");
                }

                // Can use the AFM descriptor despite not being Type 1!
                var standard14Font = Standard14.GetAdobeFontMetrics(baseFont.Data);

                if (standard14Font == null)
                {
                    throw new InvalidFontFormatException($"The provided TrueType font dictionary did not have a /FirstChar and did not match a Standard 14 font: {dictionary}.");
                }

                var fileSystemFont = systemFontFinder.GetTrueTypeFont(baseFont.Data);

                var thisEncoding = encodingReader.Read(dictionary, isLenientParsing);

                if (thisEncoding == null)
                {
                    thisEncoding = new AdobeFontMetricsEncoding(standard14Font);
                }

                int?     firstChar      = null;
                double[] widthsOverride = null;

                if (dictionary.TryGet(NameToken.FirstChar, pdfScanner, out firstCharacterToken))
                {
                    firstChar = firstCharacterToken.Int;
                }

                if (dictionary.TryGet(NameToken.Widths, pdfScanner, out ArrayToken widthsArray))
                {
                    widthsOverride = widthsArray.Data.OfType <NumericToken>()
                                     .Select(x => x.Double).ToArray();
                }

                return(new TrueTypeStandard14FallbackSimpleFont(baseFont, standard14Font, thisEncoding, fileSystemFont,
                                                                new TrueTypeStandard14FallbackSimpleFont.MetricOverrides(firstChar, widthsOverride)));
            }

            var firstCharacter = firstCharacterToken.Int;

            var widths = FontDictionaryAccessHelper.GetWidths(pdfScanner, dictionary, isLenientParsing);

            var descriptor = FontDictionaryAccessHelper.GetFontDescriptor(pdfScanner, fontDescriptorFactory, dictionary, isLenientParsing);

            var font = ParseTrueTypeFont(descriptor, out var actualHandler);

            if (font == null && actualHandler != null)
            {
                return(actualHandler.Generate(dictionary, isLenientParsing));
            }

            var name = FontDictionaryAccessHelper.GetName(pdfScanner, dictionary, descriptor, isLenientParsing);

            CMap toUnicodeCMap = null;

            if (dictionary.TryGet(NameToken.ToUnicode, out var toUnicodeObj))
            {
                var toUnicode = DirectObjectFinder.Get <StreamToken>(toUnicodeObj, pdfScanner);

                var decodedUnicodeCMap = toUnicode.Decode(filterProvider);

                if (decodedUnicodeCMap != null)
                {
                    toUnicodeCMap = CMapCache.Parse(new ByteArrayInputBytes(decodedUnicodeCMap), isLenientParsing);
                }
            }

            Encoding encoding = encodingReader.Read(dictionary, isLenientParsing, descriptor);

            if (encoding == null && font?.TableRegister?.CMapTable != null &&
                font.TableRegister.PostScriptTable?.GlyphNames != null)
            {
                var postscript = font.TableRegister.PostScriptTable;

                // Synthesize an encoding
                var fakeEncoding = new Dictionary <int, string>();
                for (var i = 0; i < 256; i++)
                {
                    if (font.TableRegister.CMapTable.TryGetGlyphIndex(i, out var index))
                    {
                        string glyphName;
                        if (index >= 0 && index < postscript.GlyphNames.Count)
                        {
                            glyphName = postscript.GlyphNames[index];
                        }
                        else
                        {
                            glyphName = index.ToString();
                        }

                        fakeEncoding[i] = glyphName;
                    }
                }

                encoding = new BuiltInEncoding(fakeEncoding);
            }

            return(new TrueTypeSimpleFont(name, descriptor, toUnicodeCMap, encoding, font, firstCharacter, widths));
        }
Ejemplo n.º 7
0
        public static EncryptionDictionary Read(DictionaryToken encryptionDictionary, IPdfTokenScanner tokenScanner)
        {
            if (encryptionDictionary == null)
            {
                throw new ArgumentNullException(nameof(encryptionDictionary));
            }

            var filter = encryptionDictionary.Get <NameToken>(NameToken.Filter, tokenScanner);

            var code = EncryptionAlgorithmCode.Unrecognized;

            if (encryptionDictionary.TryGetOptionalTokenDirect(NameToken.V, tokenScanner, out NumericToken vNum))
            {
                code = (EncryptionAlgorithmCode)vNum.Int;
            }

            var length = default(int?);

            if (encryptionDictionary.TryGetOptionalTokenDirect(NameToken.Length, tokenScanner, out NumericToken lengthToken))
            {
                length = lengthToken.Int;
            }

            var revision = default(int);

            if (encryptionDictionary.TryGetOptionalTokenDirect(NameToken.R, tokenScanner, out NumericToken revisionToken))
            {
                revision = revisionToken.Int;
            }

            byte[] ownerBytes = null;
            if (encryptionDictionary.TryGet(NameToken.O, out IToken ownerToken))
            {
                if (ownerToken is StringToken ownerString)
                {
                    ownerBytes = OtherEncodings.StringAsLatin1Bytes(ownerString.Data);
                }
                else if (ownerToken is HexToken ownerHex)
                {
                    ownerBytes = ownerHex.Bytes.ToArray();
                }
            }

            byte[] userBytes = null;
            if (encryptionDictionary.TryGet(NameToken.U, out IToken userToken))
            {
                if (userToken is StringToken userString)
                {
                    userBytes = OtherEncodings.StringAsLatin1Bytes(userString.Data);
                }
                else if (userToken is HexToken userHex)
                {
                    userBytes = userHex.Bytes.ToArray();
                }
            }

            var access = default(UserAccessPermissions);

            if (encryptionDictionary.TryGetOptionalTokenDirect(NameToken.P, tokenScanner, out NumericToken accessToken))
            {
                access = (UserAccessPermissions)accessToken.Int;
            }

            byte[] userEncryptionBytes = null, ownerEncryptionBytes = null;
            if (revision >= 5)
            {
                ownerEncryptionBytes = GetEncryptionBytesOrDefault(encryptionDictionary, tokenScanner, false);
                userEncryptionBytes  = GetEncryptionBytesOrDefault(encryptionDictionary, tokenScanner, true);
            }

            encryptionDictionary.TryGetOptionalTokenDirect(NameToken.EncryptMetaData, tokenScanner, out BooleanToken encryptMetadata);

            return(new EncryptionDictionary(filter.Data, code, length, revision, ownerBytes, userBytes,
                                            ownerEncryptionBytes,
                                            userEncryptionBytes,
                                            access,
                                            encryptionDictionary,
                                            encryptMetadata?.Data ?? true));
        }
Ejemplo n.º 8
0
        private AcroFieldBase GetAcroField(DictionaryToken fieldDictionary, Catalog catalog)
        {
            fieldDictionary.TryGet(NameToken.Ft, out NameToken fieldType);
            fieldDictionary.TryGet(NameToken.Ff, out NumericToken fieldFlagsToken);

            var kids = new List <DictionaryToken>();

            if (fieldDictionary.TryGetOptionalTokenDirect(NameToken.Kids, tokenScanner, out ArrayToken kidsToken))
            {
                foreach (var kid in kidsToken.Data)
                {
                    if (!(kid is IndirectReferenceToken kidReferenceToken))
                    {
                        throw new PdfDocumentFormatException($"AcroForm kids should only contain indirect reference, instead got: {kid}.");
                    }

                    var kidObject = tokenScanner.Get(kidReferenceToken.Data);

                    if (kidObject.Data is DictionaryToken kidDictionaryToken)
                    {
                        kids.Add(kidDictionaryToken);
                    }
                    else
                    {
                        throw new PdfDocumentFormatException($"Unexpected type of kid in AcroForm field. Expected dictionary but got: {kidObject.Data}.");
                    }
                }
            }

            fieldDictionary.TryGetOptionalStringDirect(NameToken.T, tokenScanner, out var partialFieldName);
            fieldDictionary.TryGetOptionalStringDirect(NameToken.Tu, tokenScanner, out var alternateFieldName);
            fieldDictionary.TryGetOptionalStringDirect(NameToken.Tm, tokenScanner, out var mappingName);
            fieldDictionary.TryGet(NameToken.Parent, out IndirectReferenceToken parentReferenceToken);
            var information = new AcroFieldCommonInformation(parentReferenceToken?.Data, partialFieldName, alternateFieldName, mappingName);

            int?pageNumber = null;

            if (fieldDictionary.TryGet(NameToken.P, tokenScanner, out IndirectReferenceToken pageReference))
            {
                pageNumber = catalog.GetPageByReference(pageReference.Data)?.PageNumber;
            }

            PdfRectangle?bounds = null;

            if (fieldDictionary.TryGet(NameToken.Rect, tokenScanner, out ArrayToken rectArray) && rectArray.Length == 4)
            {
                bounds = rectArray.ToRectangle();
            }

            var fieldFlags = (uint)(fieldFlagsToken?.Long ?? 0);

            AcroFieldBase result;

            if (fieldType == null)
            {
                var children = new List <AcroFieldBase>();
                foreach (var kid in kids)
                {
                    var kidField = GetAcroField(kid, catalog);
                    children.Add(kidField);
                }

                result = new AcroNonTerminalField(fieldDictionary, "Non-Terminal Field", fieldFlags, information, children);
            }
            else if (fieldType == NameToken.Btn)
            {
                var buttonFlags = (AcroButtonFieldFlags)fieldFlags;

                if (buttonFlags.HasFlag(AcroButtonFieldFlags.Radio))
                {
                    var field = new AcroRadioButtonsField(fieldDictionary, fieldType, buttonFlags, information,
                                                          pageNumber,
                                                          bounds);
                    result = field;
                }
                else if (buttonFlags.HasFlag(AcroButtonFieldFlags.PushButton))
                {
                    var field = new AcroPushButtonField(fieldDictionary, fieldType, buttonFlags, information,
                                                        pageNumber,
                                                        bounds);
                    result = field;
                }
                else
                {
                    var isChecked = false;
                    if (!fieldDictionary.TryGetOptionalTokenDirect(NameToken.V, tokenScanner, out NameToken valueToken))
                    {
                        valueToken = NameToken.Off;
                    }
                    else
                    {
                        isChecked = !string.Equals(valueToken.Data, NameToken.Off, StringComparison.OrdinalIgnoreCase);
                    }

                    var field = new AcroCheckboxField(fieldDictionary, fieldType, buttonFlags, information,
                                                      valueToken,
                                                      isChecked,
                                                      pageNumber,
                                                      bounds);

                    result = field;
                }
            }
            else if (fieldType == NameToken.Tx)
            {
                result = GetTextField(fieldDictionary, fieldType, fieldFlags, information, pageNumber, bounds);
            }
            else if (fieldType == NameToken.Ch)
            {
                result = GetChoiceField(fieldDictionary, fieldType, fieldFlags, information,
                                        pageNumber,
                                        bounds);
            }
            else if (fieldType == NameToken.Sig)
            {
                var field = new AcroSignatureField(fieldDictionary, fieldType, fieldFlags, information,
                                                   pageNumber,
                                                   bounds);
                result = field;
            }
            else
            {
                throw new PdfDocumentFormatException($"Unexpected type for field in AcroForm: {fieldType}.");
            }

            return(result);
        }
Ejemplo n.º 9
0
        private AcroFieldBase GetAcroField(DictionaryToken fieldDictionary)
        {
            fieldDictionary.TryGet(NameToken.Ft, out NameToken fieldType);
            fieldDictionary.TryGet(NameToken.Ff, out NumericToken fieldFlagsToken);

            var kids = new List <DictionaryToken>();

            if (fieldDictionary.TryGetOptionalTokenDirect(NameToken.Kids, tokenScanner, out ArrayToken kidsToken))
            {
                foreach (var kid in kidsToken.Data)
                {
                    if (!(kid is IndirectReferenceToken kidReferenceToken))
                    {
                        throw new PdfDocumentFormatException($"AcroForm kids should only contain indirect reference, instead got: {kid}.");
                    }

                    var kidObject = tokenScanner.Get(kidReferenceToken.Data);

                    if (kidObject.Data is DictionaryToken kidDictionaryToken)
                    {
                        kids.Add(kidDictionaryToken);
                    }
                    else
                    {
                        throw new PdfDocumentFormatException($"Unexpected type of kid in AcroForm field. Expected dictionary but got: {kidObject.Data}.");
                    }
                }
            }

            fieldDictionary.TryGetOptionalStringDirect(NameToken.T, tokenScanner, out var partialFieldName);
            fieldDictionary.TryGetOptionalStringDirect(NameToken.Tu, tokenScanner, out var alternateFieldName);
            fieldDictionary.TryGetOptionalStringDirect(NameToken.Tm, tokenScanner, out var mappingName);
            fieldDictionary.TryGet(NameToken.Parent, out IndirectReferenceToken parentReferenceToken);
            var information = new AcroFieldCommonInformation(parentReferenceToken?.Data, partialFieldName, alternateFieldName, mappingName);


            var fieldFlags = (uint)(fieldFlagsToken?.Long ?? 0);

            AcroFieldBase result;

            if (fieldType == null)
            {
                var children = new List <AcroFieldBase>();
                foreach (var kid in kids)
                {
                    var kidField = GetAcroField(kid);
                    children.Add(kidField);
                }

                result = new NonTerminalAcroField(fieldDictionary, "Non-Terminal Field", fieldFlags, information, children);
            }
            else if (fieldType == NameToken.Btn)
            {
                var buttonFlags = (AcroButtonFieldFlags)fieldFlags;

                if (buttonFlags.HasFlag(AcroButtonFieldFlags.Radio))
                {
                    var field = new AcroRadioButtonsField(fieldDictionary, fieldType, buttonFlags, information);
                    result = field;
                }
                else if (buttonFlags.HasFlag(AcroButtonFieldFlags.PushButton))
                {
                    var field = new AcroPushButtonField(fieldDictionary, fieldType, buttonFlags, information);
                    result = field;
                }
                else
                {
                    if (!fieldDictionary.TryGetOptionalTokenDirect(NameToken.V, tokenScanner, out NameToken valueToken))
                    {
                        valueToken = NameToken.Off;
                    }

                    var field = new AcroCheckboxField(fieldDictionary, fieldType, buttonFlags, information, valueToken);
                    result = field;
                }
            }
            else if (fieldType == NameToken.Tx)
            {
                result = GetTextField(fieldDictionary, fieldType, fieldFlags, information);
            }
            else if (fieldType == NameToken.Ch)
            {
                result = GetChoiceField(fieldDictionary, fieldType, fieldFlags, information);
            }
            else if (fieldType == NameToken.Sig)
            {
                var field = new AcroSignatureField(fieldDictionary, fieldType, fieldFlags, information);
                result = field;
            }
            else
            {
                throw new PdfDocumentFormatException($"Unexpected type for field in AcroForm: {fieldType}.");
            }

            return(result);
        }