gs -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile=out.pdf in-*.pdf pdfmarks
Where out.pdf is the generated PDF, in- * .pdf are the input PDFs, and pdfmarks is a text file with contents like:
[/Title (Title Page) /Page 1 /OUT pdfmark [/Title (Table of Contents) /Page 3 /OUT pdfmark ...
Nice and easy.
For nested levels, use the /Count attribute. For example:
[/Count 3 /Title (Chapter 1) /Page 1 /OUT pdfmark [/Count -2 /Title (Section 1.1) /Page 2 /OUT pdfmark [/Title (Section 1.1.1) /Page 3 /OUT pdfmark [/Title (Section 1.1.2) /Page 4 /OUT pdfmark [/Count -1 /Title (Section 1.2) /Page 5 /OUT pdfmark [/Title (Section 1.2.1) /Page 6 /OUT pdfmark [/Title (Section 1.3) /Page 7 /OUT pdfmark
The argument to /Count gives the number of immediately subordinate bookmarks. The sign of the argument sets the default display (negative for closed, positive for open).