fdfToArray function

Bob Sneidar bobsneidar at iotecdigital.com
Thu Oct 25 18:44:45 EDT 2018


Hi all. 

Anyone interested in getting data from, or putting data into an Acrobat Fillable Form will appreciate this. It parses an FDF file into an LC array. I have a companion function that takes an array (formatted properly of course) and creates an fdf file that a PDF form can use to populate itself (if configured to do so). This version can parse the data created by exporting from Adobe Acrobat, or the file produced by pdftk (which contains spaces and linefeeds for some unknown reason). There is no reason it shouldn't work with *any* properly formatted fdf file. 

Enjoy:

function fdfToArray2 theFDFSource, theMode
   if theMode = "data" then
      -- create a temporary source file for the fdf data
      setDefaultFolder
      put the defaultfolder & "/" & "temp/FDF_Data.fdf" into theFDFFile
      open file theFDFFile for binary write
      write theFDFSource to file theFDFFile
      close file theFDFFile
      put theFDFFile into theFDFSource
   end if
   
   open file theFdfSource for binary read
   read from file theFdfSource until eof -- we will parse with LC
   close file theFdfSource
   put it into tFileData
   
   -- get the header
   put offset("<", tFileData) -1 into tHeaderEnd
   put char 1 to tHeaderEnd of tFileData into aFDFData ["header"]
   delete char 1 to tHeaderEnd of tFileData
   
   -- get the PDF filename (if any)
   -- note the filename must be present for a fillable form to auto-fill from the fdf file
   put offset("/f(", tFileData) into tFilenameFieldStart
   
   if tFilenameFieldStart >0 then
      put offset(")", tFileData) into tFilenameFieldEnd
      put char tFilenameFieldStart +3 to tFilenameFieldEnd -1 of tFileData into aFDFData ["filename"]
   else
      put empty into aFDFData ["filename"]
   end if
   
   -- extract the field data
   put offset("/Fields", tFileData) into tFieldStartPos
   if tFieldStartPos = 0 then return empty -- no field data
   put offSet("<<", tFileData, tFieldStartPos) + tFieldStartPos into tFieldStartPos
   put offset("endobj", tFileData) into tFieldEndPos
   put char tFieldStartPos to tFieldEndPos -1 of tFileData into tFieldData
   
   -- check for ID tag
   put offset("/ID[", tFieldData) into tIDStartPos
   
   if tIDStartPos > 0 then
      put offset("]", tFieldData, tIDStartPos) into tIDEndPos
      put char tIDStartPos +5 to tIDStartPos + tIDEndPos -2 of tFieldData into aFDFData ["ID"]
      delete char tIDStartPos to tIDStartPos + tIDEndPos of tFieldData
   else
      put empty into aFDFData ["ID"]
   end if
   
   -- check for end of file tag
   put offset("/UF(", tFieldData) into tEndFileTagStartPos
   
   if tEndFileTagStartPos >0 then
      put offset(")", tFieldData, tEndFileTagStartPos) into tEndFileTagEndPos
      delete char tEndFileTagStartPos -1 to -1 of tFieldData
   end if
   
   -- get the footer
   put offset("endObj", tFileData) into tFooterStartPos
   put char tFooterStartPos to -1 of tFileData into aFDFData ["footer"]
   delete char tFooterStartPos to -1 of tFileData
   
   -- clean up the field data
   replace "\" & cr with empty in tFieldData
   replace numToChar(10) with empty in tFieldData
   replace "/T " with "/T" in tFieldData
   replace "/V " with "/V" in tFieldData
   replace "/Kids [" with "/Kids[" in tFieldData
   replace ">> <<"  with ">><<" in tFieldData
   replace "<<>>" with empty in tFieldData
   replace ">>>>" with ">>" in tFieldData
   
   -- Parse fillable control data
   -- table objects first (kids)
   put 0 into tPointer
   
   repeat
      put offset("/Kids[", tFieldData) into tKidsStartPos
      if tKidsStartPos = 0 then exit repeat
      put offset("]", tFieldData, tKidsStartPos) + tKidsStartPos into tKidsEndPos
      put char tKidsStartPos +6 to tKidsEndPos -1 of tFieldData into tKids
      put offset("/T(", tFieldData, tKidsEndPos) + tKidsEndPos into tLabelStartPos
      put offset(")", tFieldData, tLabelStartPos) + tLabelStartPos into tLabelEndPos
      put char tLabelStartPos +3 to tLabelEndPos-1 of tFieldData into tLabel
      delete char tKidsStartPos to tLabelEndPos of tFieldData
      
      -- kids loop
      repeat
         put offset("<<", tKids) into tThisKidStartPos
         put offset(">>", tKids) into tThisKidEndPos
         if tThisKidEndPos = 0 then exit repeat
         put char tThisKidStartPos to tThisKidEndPos +2 of tKids into tThisKid
         delete char 1 to tThisKidEndPos +1 of tKids
         
         -- parse this kid
         put offset("/T", tThisKid) into tElementStartPos
         put offset("(", tThisKid, tElementStartPos) + tElementStartPos into tElementStartPos
         put offset(")", tThisKid, tElementStartPos) + tElementStartPos into tElementEndPos
         put char tElementStartPos +1 to tElementEndPos -1 of tThisKid into tElement
         put offset("/V", tThisKid) into tValueStartPos
         put offset("(", tThisKid, tValueStartPos) + tValueStartPos into tValueStartPos
         put offset(")", tThisKid, tValueStartPos) + tValueStartPos into tValueEndPos
         put char tValueStartPos +1 to tValueEndPos -1 of tThisKid into tValue
         put tValue into aFDFData ["fields"] [tLabel] [tElement]
      end repeat
   end repeat
   
   -- other form objects loop
   replace "<<>>" with empty in tFieldData
   
   repeat
      put offset("<<", tFieldData) into tFieldStartPos
      if tFieldStartPos = 0 then exit repeat
      put offset(">>", tFieldData) into tFieldEndPos
      put char 3 to tFieldEndPos -1 of tFieldData into tThisField
      delete char 1 to tFieldEndPos +1 of tFieldData
      put offset("/T(", tThisField) +2 into tElementStartPos
      put offset(")", tThisField, tElementStartPos) + tElementStartPos into tElementEndPos
      put char tElementStartPos +1 to tElementEndPos -1 of tThisField into tElement
      put offset("/V(", tThisField) +2 into tValueStartPos
      put offset(")", tThisField, tValueStartPos) + tValueStartPos into tValueEndPos
      put char tValueStartPos +1 to tValueEndPos -1 of tThisField into tValue
      put tValue into aFDFData ["fields"] [tElement]
   end repeat
   
   if theMode = "data" then
      -- delete temporary file
      delete file theFDFFile
   end if
   
   return aFDFData   
end fdfToArray2



More information about the use-livecode mailing list